#!/usr/bin/perl =encoding UTF-8 =head1 NAME dh_usrlocal - migrate usr/local directories to maintainer scripts =cut use warnings; use strict; use Debian::Debhelper::Dh_Lib; use File::Find; use File::stat; our $VERSION = DH_BUILTIN_VERSION; =head1 SYNOPSIS B [S>] [B<-n>] =head1 DESCRIPTION B is a debhelper program that can be used for building packages that will provide a subdirectory in F when installed. It finds subdirectories of F in the package build directory, and removes them, replacing them with maintainer script snippets (unless B<-n> is used) to create the directories at install time, and remove them when the package is removed, in a manner compliant with Debian policy. These snippets are inserted into the maintainer scripts by B. See L for an explanation of debhelper maintainer script snippets. When the I field is not (effectively) I, the directories in F will have ownership root:staff and the mode will be 02775. These values have been chosen to comply with the recommendations of the Debian policy for directories in F. When I has an effective value of I, the owners, groups and permissions will be preserved with one exception. If the directory is owned by root:root, then ownership will be reset to root:staff and mode will be reset to 02775. This is useful, since that is the group and mode policy recommends for directories in F. =head1 OPTIONS =over 4 =item B<-n>, B<--no-scripts> Do not modify F/F scripts. =back =head1 NOTES Note that this command is not idempotent. L should be called between invocations of this command. Otherwise, it may cause multiple instances of the same text to be added to maintainer scripts. =head1 CONFORMS TO Debian policy, version 2.2 =cut init(); # PROMISE: DH NOOP WITHOUT tmp(usr/local) foreach my $package (@{$dh{DOPACKAGES}}) { my $tmp = tmpdir($package); if (-d "$tmp/usr/local") { my (@dirs, @justdirs); find({bydepth => 1, no_chdir => 1, wanted => sub { my $fn = $File::Find::name; if (-d $fn) { my $user = 'root'; my $group = 'staff'; my $mode = '02775'; if (should_use_root()) { my $stat = stat $fn; $user = getpwuid $stat->uid; $group = getgrgid $stat->gid; $mode = sprintf "%04lo", ($stat->mode & 07777); if ($stat->uid == 0 && $stat->gid == 0) { $group = 'staff'; $mode = '02775'; } } $fn =~ s!^\Q$tmp\E!!; return if $fn eq '/usr/local'; # @dirs is in parents-first order for dir creation... unshift @dirs, "$fn $mode $user $group"; # ...whereas @justdirs is depth-first for removal. push @justdirs, $fn; doit('rmdir', $_); } else { warning("$fn is not a directory"); } }}, "$tmp/usr/local"); doit('rmdir', "$tmp/usr/local"); my $bs = "\\"; # A single plain backslash my $ebs = $bs x 2; # Escape the backslash from the shell # This constructs the body of a 'sed' c\ expression which # is parsed by the shell in double-quotes my $dirs = join("$ebs\n", sort @dirs); pop @justdirs; # don't remove directories directly in /usr/local my $justdirs = join("$ebs\n", reverse sort @justdirs); if (! $dh{NOSCRIPTS}) { autoscript($package,"postinst", "postinst-usrlocal", "/#DIRS#/ c${ebs}\n${dirs}"); autoscript($package,"prerm", "prerm-usrlocal", "/#JUSTDIRS#/ c${ebs}\n${justdirs}") if length $justdirs; } } } =head1 SEE ALSO L This program is a part of debhelper. =head1 AUTHOR Andrew Stribblehill =cut