dpkg-statoverride.pl 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. #! /usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use POSIX;
  5. use POSIX qw(:errno_h :signal_h);
  6. my $admindir = "/var/lib/dpkg"; # This line modified by Makefile
  7. my $version = '1.3.0'; # This line modified by Makefile
  8. ($0) = $0 =~ m:.*/(.+):;
  9. my $dpkglibdir= "."; # This line modified by Makefile
  10. push (@INC, $dpkglibdir);
  11. require 'dpkg-gettext.pl';
  12. textdomain("dpkg");
  13. my $verbose = 1;
  14. my $doforce = 0;
  15. my $doupdate = 0;
  16. my $mode = "";
  17. my %owner;
  18. my %group;
  19. my %mode;
  20. sub version {
  21. printf _g("Debian %s version %s.\n"), $0, $version;
  22. printf _g("
  23. Copyright (C) 2000 Wichert Akkerman.");
  24. printf _g("
  25. This is free software; see the GNU General Public Licence version 2 or
  26. later for copying conditions. There is NO warranty.
  27. ");
  28. }
  29. sub usage {
  30. printf _g(
  31. "Usage: %s [<option> ...] <command>
  32. Commands:
  33. --add <owner> <group> <mode> <file>
  34. add a new entry into the database.
  35. --remove <file> remove file from the database.
  36. --list [<glob-pattern>] list current overrides in the database.
  37. Options:
  38. --admindir <directory> set the directory with the statoverride file.
  39. --update immediately update file permissions.
  40. --force force an action even if a sanity check fails.
  41. --quiet quiet operation, minimal output.
  42. --help show this help message.
  43. --version show the version.
  44. "), $0;
  45. }
  46. sub CheckModeConflict {
  47. return unless $mode;
  48. badusage(sprintf(_g("two commands specified: %s and --%s"), $_, $mode));
  49. }
  50. while (@ARGV) {
  51. $_=shift(@ARGV);
  52. last if m/^--$/;
  53. if (!m/^-/) {
  54. unshift(@ARGV,$_); last;
  55. } elsif (m/^--help$/) {
  56. &usage; exit(0);
  57. } elsif (m/^--version$/) {
  58. &version; exit(0);
  59. } elsif (m/^--update$/) {
  60. $doupdate=1;
  61. } elsif (m/^--quiet$/) {
  62. $verbose=0;
  63. } elsif (m/^--force$/) {
  64. $doforce=1;
  65. } elsif (m/^--admindir$/) {
  66. @ARGV || &badusage(sprintf(_g("--%s needs a <directory> argument"), "admindir"));
  67. $admindir= shift(@ARGV);
  68. } elsif (m/^--add$/) {
  69. &CheckModeConflict;
  70. $mode= 'add';
  71. } elsif (m/^--remove$/) {
  72. &CheckModeConflict;
  73. $mode= 'remove';
  74. } elsif (m/^--list$/) {
  75. &CheckModeConflict;
  76. $mode= 'list';
  77. } else {
  78. &badusage(sprintf(_g("unknown option \`%s'"), $_));
  79. }
  80. }
  81. my $dowrite = 0;
  82. my $exitcode = 0;
  83. &badusage(_g("no mode specified")) unless $mode;
  84. &ReadOverrides;
  85. if ($mode eq "add") {
  86. @ARGV==4 || &badusage(_g("--add needs four arguments"));
  87. my $user = $ARGV[0];
  88. my $uid = 0;
  89. my $gid = 0;
  90. if ($user =~ m/^#([0-9]+)$/) {
  91. $uid=$1;
  92. &badusage(sprintf(_g("illegal user %s"), $user)) if ($uid<0);
  93. } else {
  94. my ($name, $pw);
  95. (($name,$pw,$uid)=getpwnam($user)) || &badusage(sprintf(_g("non-existing user %s"), $user));
  96. }
  97. my $group = $ARGV[1];
  98. if ($group =~ m/^#([0-9]+)$/) {
  99. $gid=$1;
  100. &badusage(sprintf(_g("illegal group %s"), $group)) if ($gid<0);
  101. } else {
  102. my ($name, $pw);
  103. (($name,$pw,$gid)=getgrnam($group)) || &badusage(sprintf(_g("non-existing group %s"), $group));
  104. }
  105. my $mode = $ARGV[2];
  106. (($mode<0) or (oct($mode)>07777) or ($mode !~ m/\d+/)) && &badusage(sprintf(_g("illegal mode %s"), $mode));
  107. my $file = $ARGV[3];
  108. $file =~ m/\n/ && &badusage(_g("file may not contain newlines"));
  109. $file =~ s,/+$,, && print STDERR _g("stripping trailing /")."\n";
  110. if (defined $owner{$file}) {
  111. printf STDERR _g("An override for \"%s\" already exists, "), $file;
  112. if ($doforce) {
  113. print STDERR _g("but --force specified so will be ignored.")."\n";
  114. } else {
  115. print STDERR _g("aborting")."\n";
  116. exit(3);
  117. }
  118. }
  119. $owner{$file}=$user;
  120. $group{$file}=$group;
  121. $mode{$file}=$mode;
  122. $dowrite=1;
  123. if ($doupdate) {
  124. if (not -e $file) {
  125. printf STDERR _g("warning: --update given but %s does not exist")."\n", $file;
  126. } else {
  127. chown ($uid,$gid,$file) || warn sprintf(_g("failed to chown %s: %s"), $file, $!)."\n";
  128. chmod (oct($mode),$file) || warn sprintf(_g("failed to chmod %s: %s"), $file, $!)."\n";
  129. }
  130. }
  131. } elsif ($mode eq "remove") {
  132. @ARGV==1 || &badusage(sprintf(_g("--%s needs a single argument"), "remove"));
  133. my $file = $ARGV[0];
  134. $file =~ s,/+$,, && print STDERR _g("stripping trailing /")."\n";
  135. if (not defined $owner{$file}) {
  136. print STDERR _g("No override present.")."\n";
  137. exit(0) if ($doforce);
  138. exit(2);
  139. }
  140. delete $owner{$file};
  141. delete $group{$file};
  142. delete $mode{$file};
  143. $dowrite=1;
  144. print(STDERR _g("warning: --update is useless for --remove")."\n") if ($doupdate);
  145. } elsif ($mode eq "list") {
  146. my (@list, @ilist);
  147. @ilist= @ARGV ? @ARGV : ('*');
  148. while (defined($_=shift(@ilist))) {
  149. s/\W/\\$&/g;
  150. s/\\\?/./g;
  151. s/\\\*/.*/g;
  152. s,/+$,, && print STDERR _g("stripping trailing /")."\n";
  153. push(@list,"^$_\$");
  154. }
  155. my $pattern = join('|', @list);
  156. $exitcode=1;
  157. for my $file (keys %owner) {
  158. next unless ($file =~ m/$pattern/o);
  159. $exitcode=0;
  160. print "$owner{$file} $group{$file} $mode{$file} $file\n";
  161. }
  162. }
  163. &WriteOverrides if ($dowrite);
  164. exit($exitcode);
  165. sub ReadOverrides {
  166. open(SO,"$admindir/statoverride") || &quit(sprintf(_g("cannot open statoverride: %s"), $!));
  167. while (<SO>) {
  168. my ($owner,$group,$mode,$file);
  169. chomp;
  170. ($owner,$group,$mode,$file)=split(' ', $_, 4);
  171. die sprintf(_g("Multiple overrides for \"%s\", aborting"), $file)
  172. if defined $owner{$file};
  173. $owner{$file}=$owner;
  174. $group{$file}=$group;
  175. $mode{$file}=$mode;
  176. }
  177. close(SO);
  178. }
  179. sub WriteOverrides {
  180. my ($file);
  181. open(SO,">$admindir/statoverride-new") || &quit(sprintf(_g("cannot open new statoverride file: %s"), $!));
  182. foreach $file (keys %owner) {
  183. print SO "$owner{$file} $group{$file} $mode{$file} $file\n";
  184. }
  185. close(SO);
  186. chmod(0644, "$admindir/statoverride-new");
  187. unlink("$admindir/statoverride-old") ||
  188. $! == ENOENT || &quit(sprintf(_g("error removing statoverride-old: %s"), $!));
  189. link("$admindir/statoverride","$admindir/statoverride-old") ||
  190. $! == ENOENT || &quit(sprintf(_g("error creating new statoverride-old: %s"), $!));
  191. rename("$admindir/statoverride-new","$admindir/statoverride")
  192. || &quit(sprintf(_g("error installing new statoverride: %s"), $!));
  193. }
  194. sub quit
  195. {
  196. printf STDERR "%s: %s\n", $0, "@_";
  197. exit(2);
  198. }
  199. sub badusage
  200. {
  201. printf STDERR "%s: %s\n\n", $0, "@_";
  202. &usage;
  203. exit(2);
  204. }
  205. # vi: ts=8 sw=8 ai si cindent