dpkg-source.pl 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683
  1. #!/usr/bin/perl
  2. use POSIX;
  3. use POSIX qw(:errno_h :signal_h);
  4. $dpkglibdir= ".";
  5. $version= '1.3.0'; # This line modified by Makefile
  6. push(@INC,$dpkglibdir);
  7. require 'controllib.pl';
  8. sub usageversion {
  9. print STDERR
  10. "Debian GNU/Linux dpkg-source $version. Copyright (C) 1996
  11. Ian Jackson. This is free software; see the GNU General Public Licence
  12. version 2 or later for copying conditions. There is NO warranty.
  13. Usage:
  14. dpkg-source -x <filename>.dsc
  15. dpkg-source -b <directory> [<orig-directory>|\'\']
  16. Options: -c<controlfile> get control info from this file\n".
  17. "(for -b) -l<changelogfile> get per-version info from this file
  18. -F<changelogformat> force change log format
  19. -V<name>=<value> set a substitution variable
  20. -T<varlistfile> read variables here, not debian/substvars
  21. -D<field>=<value> override or add a .dsc field and value
  22. -U<field> remove a field
  23. -h print this message
  24. Relative filenames for -c and -l are interpreted starting at the
  25. source tree's top level directory. If <orig-directory> is omitted then
  26. it defaults to <directory>.orig if that exists or to \'\' (indicating a
  27. Debian-special package without a diff) if <directory>.orig doesn\`t.
  28. ";
  29. }
  30. $i=100;grep($fieldimps{$_}=$i--,
  31. qw(Source Version Binary Maintainer Architecture Standards-Version));
  32. while (@ARGV && $ARGV[0] =~ m/^-/) {
  33. $_=shift(@ARGV);
  34. if (m/^-b$/) {
  35. &setopmode('build');
  36. } elsif (m/^-x$/) {
  37. &setopmode('extract');
  38. } elsif (m/^-c/) {
  39. $controlfile= $';
  40. } elsif (m/^-l/) {
  41. $changelogfile= $';
  42. } elsif (m/^-F([0-9a-z]+)$/) {
  43. $changelogformat=$1;
  44. } elsif (m/^-D([^\=:]+)[=:]/) {
  45. $override{$1}= $';
  46. } elsif (m/^-U([^\=:]+)$/) {
  47. $remove{$1}= 1;
  48. } elsif (m/^-V(\w+)[=:]/) {
  49. $substvar{$1}= $';
  50. } elsif (m/^-T/) {
  51. $varlistfile= $';
  52. } elsif (m/^-h$/) {
  53. &usageversion; exit(0);
  54. } elsif (m/^--$/) {
  55. last;
  56. } else {
  57. &usageerr("unknown option $_");
  58. }
  59. }
  60. defined($opmode) || &usageerr("need -x or -b");
  61. if ($opmode eq 'build') {
  62. @ARGV || &usageerr("-b needs a directory");
  63. @ARGV<=2 || &usageerr("-b takes at most a directory and an orig directory");
  64. $dir= shift(@ARGV);
  65. $dir= "./$dir" unless $dir =~ m:^/:;
  66. stat($dir) || &error("cannot stat directory $dir: $!");
  67. -d $dir || &error("directory argument $dir is not a directory");
  68. $!=0; if (@ARGV) {
  69. $origdir= shift(@ARGV);
  70. if (length($origdir)) {
  71. stat($origdir) || &error("cannot find orig directory $origdir: $!");
  72. -d $origdir || &error("orig directory argument $origdir is not a directory");
  73. }
  74. } elsif (!stat("$dir.orig")) {
  75. $! == ENOENT || &error("cannot stat tentative orig dir $dir.orig: $!");
  76. $origdir= '';
  77. } elsif (-d _) {
  78. $origdir= "$dir.orig";
  79. } else {
  80. &error("tentative orig directory $dir.orig is not a directory");
  81. }
  82. $changelogfile= "$dir/debian/changelog" unless defined($changelogfile);
  83. $controlfile= "$dir/debian/control" unless defined($controlfile);
  84. &parsechangelog;
  85. &parsecontrolfile;
  86. $archspecific=0;
  87. for $_ (keys %fi) {
  88. $v= $fi{$_};
  89. if (s/^C //) {
  90. #print STDERR "G key >$_< value >$v<\n";
  91. if (m/^Source$/) { &setsourcepackage; }
  92. elsif (m/^Standards-Version$|^Maintainer$/) { $f{$_}= $v; }
  93. elsif (s/^X[BC]*S[BC]*-//i) { $f{$_}= $v; }
  94. elsif (m/^(Section|Priority|Files)$/ || m/^X[BC]+-/i) { }
  95. else { &unknown('general section of control info file'); }
  96. } elsif (s/^C(\d+) //) {
  97. #print STDERR "P key >$_< value >$v<\n";
  98. $i=$1; $p=$fi{"C$i Package"};
  99. push(@binarypackages,$p) unless $packageadded{$p}++;
  100. if (m/^Architecture$/) {
  101. #print STDERR "$p >$v< >".join(' ',@sourcearch)."<\n";
  102. if ($v eq 'any') {
  103. @sourcearch= ('any');
  104. } elsif ($v eq 'all') {
  105. if (!@sourcearch || $sourcearch[0] eq 'all') {
  106. @sourcearch= ('all');
  107. } else {
  108. @sourcearch= ('any');
  109. }
  110. } else {
  111. if (grep($sourcearch[0] eq $_, 'any','all')) {
  112. @sourcearch= ('any');
  113. } else {
  114. for $a (split(/\s+/,$v)) {
  115. &error("architecture $a only allowed on its own".
  116. " (list for package $p is \`$a')")
  117. if grep($a eq $_, 'any','all');
  118. push(@sourcearch,$a) unless $archadded{$a}++;
  119. }
  120. }
  121. }
  122. $f{'Architecture'}= join(' ',@sourcearch);
  123. } elsif (s/^X[BC]*S[BC]*-//i) {
  124. $f{$_}= $v;
  125. } elsif (m/^(Package|Essential|Pre-Depends|Depends|Provides)$/ ||
  126. m/^(Recommends|Suggests|Optional|Conflicts|Replaces)$/ ||
  127. m/^(Description|Section|Priority)$/ ||
  128. m/^X[CS]+-/i) {
  129. } else {
  130. &unknown("package's section of control info file");
  131. }
  132. } elsif (s/^L //) {
  133. #print STDERR "L key >$_< value >$v<\n";
  134. if (m/^Source$/) {
  135. &setsourcepackage;
  136. } elsif (m/^Version$/) {
  137. $f{$_}= $v;
  138. } elsif (s/^X[BS]*C[BS]*-//i) {
  139. $f{$_}= $v;
  140. } elsif (m/^(Maintainer|Changes|Urgency|Distribution|Date)$/ ||
  141. m/^X[BS]+-/i) {
  142. } else {
  143. &unknown("parsed version of changelog");
  144. }
  145. } else {
  146. &internerr("value from nowhere, with key >$_< and value >$v<");
  147. }
  148. }
  149. $f{'Binary'}= join(', ',@binarypackages);
  150. for $f (keys %override) { $f{&capit($f)}= $override{$f}; }
  151. for $f (qw(Version)) {
  152. defined($f{$f}) || &error("missing information for critical output field $f");
  153. }
  154. for $f (qw(Maintainer Architecture Standards-Version)) {
  155. defined($f{$f}) || &warn("missing information for output field $f");
  156. }
  157. defined($sourcepackage) || &error("unable to determine source package name !");
  158. $f{'Source'}= $sourcepackage;
  159. for $f (keys %remove) { delete $f{&capit($f)}; }
  160. $version= $f{'Version'}; $version =~ s/^\d+://;
  161. $basenamerev= $basename= $sourcepackage.'_'.$version;
  162. $basename =~ s/-[^_]+$//;
  163. $basedirname= $basename;
  164. #print STDERR ">$basedirname<\n";
  165. $basedirname =~ s/_/-/;
  166. #print STDERR ">$basedirname<\n";
  167. $dirbase= $dir; $dirbase =~ s,/?$,,; $dirbase =~ s,[^/]+$,,; $dirname= $&;
  168. if (length($origdir)) {
  169. $origdirbase= $origdir; $origdirbase =~ s,/?$,,;
  170. $origdirbase =~ s,[^/]+$,,; $origdirname= $&;
  171. $origdirname eq "$basedirname.orig" ||
  172. &warn(".orig directory name $origdirname is not package-origversion".
  173. " (wanted $basedirname.orig)");
  174. $tardirbase= $origdirbase; $tardirname= $origdirname;
  175. $tarname= "$basename.orig.tar.gz";
  176. } else {
  177. $tardirbase= $dirbase; $tardirname= $dirname;
  178. $tarname= "$basename.tar.gz";
  179. }
  180. print("$progname: building $sourcepackage in $tarname\n")
  181. || &syserr("write building tar message");
  182. &forkgzipwrite($tarname);
  183. defined($c2= fork) || &syserr("fork for tar");
  184. if (!$c2) {
  185. chdir($tardirbase) || &syserr("chdir to above (orig) source $tardirbase");
  186. open(STDOUT,">&GZIP") || &syserr("reopen gzip for tar");
  187. exec('tar','-cO','--',$tardirname); &syserr("exec tar");
  188. }
  189. close(GZIP);
  190. &reapgzip;
  191. $c2 == waitpid($c2,0) || &syserr("wait for tar");
  192. $? && !(WIFSIGNALED($c2) && WTERMSIG($c2) == SIGPIPE) && subprocerr("tar");
  193. addfile("$tarname");
  194. if (length($origdir)) {
  195. print("$progname: building $sourcepackage in $basenamerev.diff.gz\n")
  196. || &syserr("write building diff message");
  197. &forkgzipwrite("$basenamerev.diff.gz");
  198. defined($c2= open(FIND,"-|")) || &syserr("fork for find");
  199. if (!$c2) {
  200. chdir($dirname) || &syserr("chdir to $dirname for find");
  201. exec('find','.','-print0'); &syserr("exec find");
  202. }
  203. $/= "\0";
  204. file:
  205. while (defined($fn= <FIND>)) {
  206. $fn =~ s/\0$//; $fn =~ s,^\./,,;
  207. lstat("$dir/$fn") || &syserr("cannot stat file $dir/$fn");
  208. if (-l _) {
  209. $type{$fn}= 'symlink';
  210. &checktype('-l') || next;
  211. defined($n= readlink("$dir/$fn")) ||
  212. &syserr("cannot read link $dir/$fn");
  213. defined($n2= readlink("$origdir/$fn")) ||
  214. &syserr("cannot read orig link $origdir/$fn");
  215. $n eq $n2 || &unrepdiff2("symlink to $n2","symlink to $n");
  216. } elsif (-f _) {
  217. $type{$fn}= 'plain file';
  218. if (!lstat("$origdir/$fn")) {
  219. $! == ENOENT || &syserr("cannot stat orig file $origdir/$fn");
  220. $ofnread= '/dev/null';
  221. } elsif (-f _) {
  222. $ofnread= "$origdir/$fn";
  223. } else {
  224. &unrepdiff2("something else","plain file");
  225. next;
  226. }
  227. defined($c3= open(DIFFGEN,"-|")) || &syserr("fork for diff");
  228. if (!$c3) {
  229. exec('diff','-u',
  230. '-L',"$basedirname.orig/$fn",
  231. '-L',"$basedirname/$fn",
  232. '--',"$ofnread","$dir/$fn"); &syserr("exec diff");
  233. }
  234. $difflinefound= 0;
  235. $/= "\n";
  236. while (<DIFFGEN>) {
  237. if (m/^binary/i) {
  238. close(DIFFGEN); $/= "\0";
  239. &unrepdiff("binary file contents changed");
  240. next file;
  241. } elsif (m/^[-+\@ ]/) {
  242. $difflinefound=1;
  243. } else {
  244. s/\n$//;
  245. &internerr("unknown line from diff -u on $dirname/$fn: \`$_'");
  246. }
  247. print(GZIP $_) || &syserr("failed to write to gzip");
  248. }
  249. close(DIFFGEN); $/= "\0";
  250. if (WIFEXITED($?) && (($es=WEXITSTATUS($?))==0 || $es==1)) {
  251. if ($es==1 && !$difflinefound) {
  252. &unrepdiff("diff gave 1 but no diff lines found");
  253. }
  254. } else {
  255. subprocerr("diff on $dirname/$fn");
  256. }
  257. } elsif (-p _) {
  258. $type{$fn}= 'pipe';
  259. &checktype('-p');
  260. } elsif (-b _ || -c _ || -S _) {
  261. &unrepdiff("device or socket is not allowed");
  262. } elsif (-d _) {
  263. $type{$fn}= 'directory';
  264. } else {
  265. &unrepdiff("unknown file type ($!)");
  266. }
  267. }
  268. close(FIND); $? && subprocerr("find on $dirname");
  269. close(GZIP) || &syserr("finish write to gzip pipe");
  270. &reapgzip;
  271. defined($c2= open(FIND,"-|")) || &syserr("fork for 2nd find");
  272. if (!$c2) {
  273. chdir($origdirname) || &syserr("chdir to $origdirname for 2nd find");
  274. exec('find','.','-print0'); &syserr("exec 2nd find");
  275. }
  276. $/= "\0";
  277. while (defined($fn= <FIND>)) {
  278. $fn =~ s/\0$//; $fn =~ s,^\./,,;
  279. next if defined($type{$fn});
  280. lstat("$origdir/$fn") || &syserr("cannot check orig file $origdir/$fn");
  281. if (-f _) {
  282. &warn("ignoring deletion of file $fn");
  283. } elsif (-d _) {
  284. &warn("ignoring deletion of directory $fn");
  285. } elsif (-l _) {
  286. &warn("ignoring deletion of symlink $fn");
  287. } else {
  288. &unrepdiff2('not a file, directory or link','nonexistent');
  289. }
  290. }
  291. close(FIND); $? && subprocerr("find on $dirname");
  292. &addfile("$basenamerev.diff.gz");
  293. }
  294. print("$progname: building $sourcepackage in $basenamerev.dsc\n")
  295. || &syserr("write building message");
  296. open(STDOUT,"> $basenamerev.dsc") || &syserr("create $basenamerev.dsc");
  297. &outputclose;
  298. if ($ur) {
  299. print(STDERR "$progname: unrepresentable changes to source\n")
  300. || &syserr("write error msg: $!");
  301. exit(1);
  302. }
  303. exit(0);
  304. } else {
  305. @ARGV==1 || &usageerr("-x needs exactly one argument, the .dsc");
  306. $dsc= shift(@ARGV);
  307. $dsc= "./$dsc" unless $dsc =~ m:^/:;
  308. $dscdir= $dsc; $dscdir= "./$dscdir" unless $dsc =~ m,^/|^\./,;
  309. $dscdir =~ s,/[^/]+$,,;
  310. open(CDATA,"< $dsc") || &error("cannot open .dsc file $dsc: $!");
  311. &parsecdata('S',-1,"source control file $dsc");
  312. for $f (qw(Source Version Files)) {
  313. defined($fi{"S $f"}) ||
  314. &error("missing critical source control field $f");
  315. }
  316. $sourcepackage= $fi{'S Source'};
  317. $sourcepackage =~ m/[^-+.0-9a-z]/ &&
  318. &error("source package name contains illegal character \`$&'");
  319. $sourcepackage =~ m/^[0-9a-z]./ ||
  320. &error("source package name is too short or starts with non-alphanum");
  321. $version= $fi{'S Version'};
  322. $version =~ m/[^-+:.0-9a-zA-Z]/ &&
  323. &error("version number contains illegal character \`$&'");
  324. $version =~ s/^\d+://;
  325. if ($version =~ m/-([^-]+)$/) {
  326. $baseversion= $`; $revision= $1;
  327. } else {
  328. $baseversion= $version; $revision= '';
  329. }
  330. $files= $fi{'S Files'};
  331. for $file (split(/\n /,$files)) {
  332. next if $file eq '';
  333. $file =~ m/^([0-9a-f]{32})[ \t]+(\d+)[ \t]+([0-9a-zA-Z][-+:.,=0-9a-zA-Z_]+)$/
  334. || &error("Files field contains bad line \`$file'");
  335. ($md5sum{$3},$size{$3},$file) = ($1,$2,$3);
  336. &setfile(\$tarfile) if $file =~ m/\.tar\.gz$/;
  337. &setfile(\$difffile) if $file =~ m/\.diff\.gz$/;
  338. }
  339. $newdirectory= $sourcepackage.'-'.$baseversion;
  340. $expectprefix= $newdirectory; $expectprefix.= '.orig' if length($difffile);
  341. length($tarfile) || &error("no tarfile in Files field");
  342. checkstats($tarfile);
  343. checkstats($difffile) if length($difffile);
  344. &forkgzipread("$dscdir/$tarfile");
  345. defined($c2= open(CPIO,"-|")) || &syserr("fork for cpio");
  346. if (!$c2) {
  347. open(STDIN,"<&GZIP") || &syserr("reopen gzip for cpio");
  348. &cpiostderr;
  349. exec('cpio','-0t'); &syserr("exec cpio");
  350. }
  351. $/= "\0";
  352. close(GZIP);
  353. file:
  354. while (defined($fn= <CPIO>)) {
  355. $fn =~ s/\0$//; $pname= $fn; $pname =~ y/ -~/?/c;
  356. $fn =~ m/\n/ &&
  357. &error("tarfile contains object with newline in its name ($pname)");
  358. $slash= substr($fn,length($expectprefix),1);
  359. (($slash eq '/' || $slash eq '') &&
  360. substr($fn,0,length($expectprefix)) eq $expectprefix) ||
  361. &error("tarfile contains object ($pname) not in expected directory".
  362. " ($expectprefix)");
  363. $fn =~ m,/\.\./, &&
  364. &error("tarfile contains object with /../ in its name ($pname)");
  365. push(@filesinarchive,$fn);
  366. }
  367. close(CPIO); $? && subprocerr("cpio");
  368. $/= "\n";
  369. &reapgzip;
  370. &forkgzipread("$dscdir/$tarfile");
  371. defined($c2= open(TAR,"-|")) || &syserr("fork for tar -t");
  372. if (!$c2) {
  373. $ENV{'LANG'}= 'C';
  374. open(STDIN,"<&GZIP") || &syserr("reopen gzip for tar -t");
  375. exec('tar','-vvtf','-'); &syserr("exec tar -vvtf -");
  376. }
  377. close(GZIP);
  378. $efix= 0;
  379. file:
  380. while (length($_= <TAR>)) {
  381. s/\n$//;
  382. m,^(\S{10})\s, ||
  383. &error("tarfile contains unknown object listed by tar as \`$_'");
  384. $fn= $filesinarchive[$efix++]; $mode= $1;
  385. if ($mode =~ m/^l/) { $_ =~ s/ -\> .*//; }
  386. substr($_,length($_)-length($fn)-1) eq " $fn" ||
  387. &error("tarfile contains unexpected object listed by tar as \`$_',".
  388. " expected \`$fn'");
  389. $mode =~ s/^([-dpsl])// ||
  390. &error("tarfile contains object \`$fn' with unknown or forbidden type \`".
  391. substr($_,0,1)."'");
  392. $fn =~ m/\.dpkg-orig$/ &&
  393. &error("tarfile contains file with name ending .dpkg-orig");
  394. $type= $&;
  395. $mode =~ m/[sStT]/ && $type ne 'd' &&
  396. &error("tarfile contains setuid, setgid or sticky object \`$fn'");
  397. $fn eq "$expectprefix/debian" && $type ne 'd' &&
  398. &error("tarfile contains object `debian' that isn't a directory");
  399. $fn =~ s,/$,, if $type eq 'd';
  400. $dirname= $fn;
  401. $dirname =~ s,/[^/]+$,, && !defined($dirincluded{$dirname}) &&
  402. &error("tarfile contains object \`$fn' but its containing ".
  403. "directory \`$dirname' does not precede it");
  404. $dirincluded{$fn}= 1 if $type eq 'd';
  405. $notfileobject{$fn}= 1 if $type ne '-';
  406. }
  407. close(TAR); $? && subprocerr("tar -t");
  408. &reapgzip;
  409. if (length($difffile)) {
  410. if (!$dirincluded{"$expectprefix/debian"}) {
  411. $mkdebian=1; $dirincluded{"$expectprefix/debian"}= 1;
  412. }
  413. &forkgzipread("$dscdir/$difffile");
  414. $/="\n";
  415. while (length($_=<GZIP>)) {
  416. s/\n$// || &error("diff is missing trailing newline");
  417. if (m/^--- /) {
  418. $fn= $';
  419. substr($fn,0,length($expectprefix)+1) eq "$expectprefix/" ||
  420. &error("diff patches file ($fn) not in expected subdirectory");
  421. $fn =~ m/\.dpkg-orig$/ &&
  422. &error("diff patches file with name ending .dpkg-orig");
  423. $dirname= $fn;
  424. $dirname =~ s,/[^/]+$,, && defined($dirincluded{$dirname}) ||
  425. &error("diff patches file ($fn) whose directory does not appear".
  426. " in tarfile");
  427. defined($notfileobject{$fn}) &&
  428. &error("diff patches something which is not a plain file");
  429. $_= <GZIP>; s/\n$// ||
  430. &error("diff finishes in middle of ---/+++ (line $.)");
  431. $_ eq '+++ '.$newdirectory.substr($fn,length($expectprefix)) ||
  432. &error("line after --- for file $fn isn't as expected");
  433. $filepatched{$fn}++ && &error("diff patches file $fn twice");
  434. } elsif (!m/^[-+ \@]/) {
  435. &error("diff contains unknown line \`$_'");
  436. }
  437. }
  438. close(GZIP);
  439. &reapgzip;
  440. }
  441. print("$progname: extracting $sourcepackage in $newdirectory".
  442. ($difffile ? " and $expectprefix" : '')."\n")
  443. || &syserr("write extracting message");
  444. &erasedir($newdirectory);
  445. &erasedir("$newdirectory.orig");
  446. &extracttar;
  447. if (length($difffile)) {
  448. rename($expectprefix,$newdirectory) ||
  449. &syserr("failed to rename newly-extracted $expectprefix to $newdirectory");
  450. &extracttar;
  451. if ($mkdebian) {
  452. mkdir("$newdirectory/debian",0777) ||
  453. &syserr("failed to create $newdirectory/debian subdirectory");
  454. }
  455. &forkgzipread("$dscdir/$difffile");
  456. defined($c2= fork) || &syserr("fork for patch");
  457. if (!$c2) {
  458. open(STDIN,"<&GZIP") || &syserr("reopen gzip for patch");
  459. chdir($newdirectory) || &syserr("chdir to $newdirectory for patch");
  460. exec('patch','-s','-t','-F','0','-N','-p1','-u',
  461. '-V','never','-b','.dpkg-orig');
  462. &syserr("exec patch");
  463. }
  464. close(GZIP);
  465. $c2 == waitpid($c2,0) || &syserr("wait for patch");
  466. $? && subprocerr("patch");
  467. &reapgzip;
  468. for $fn (keys %filepatched) {
  469. $ftr= "$newdirectory/".substr($fn,length($expectprefix)+1).".dpkg-orig";
  470. unlink($ftr) || &syserr("remove patch backup file $ftr");
  471. }
  472. if (!(@s= lstat("$newdirectory/debian/rules"))) {
  473. $! == ENOENT || &syserr("cannot stat $newdirectory/debian/rules");
  474. &warn("$newdirectory/debian/rules does not exist");
  475. } elsif (-f _) {
  476. chmod($s[2] | 0111, "$newdirectory/debian/rules") ||
  477. &syserr("cannot make $newdirectory/debian/rules executable");
  478. } else {
  479. &warn("$newdirectory/debian/rules is not a plain file");
  480. }
  481. }
  482. $execmode= 0777 & ~umask;
  483. (@s= stat('.')) || &syserr("cannot stat \`.'");
  484. $dirmode= $execmode | ($s[2] & 02000);
  485. $plainmode= $execmode & ~0111;
  486. $fifomode= ($plainmode & 0222) | (($plainmode & 0222) << 1);
  487. for $fn (@filesinarchive) {
  488. $fn= substr($fn,length($expectprefix)+1);
  489. $fn= "$newdirectory/$fn";
  490. (@s= lstat($fn)) || &syserr("cannot stat extracted object \`$fn'");
  491. $mode= $s[2];
  492. if (-d _) {
  493. $newmode= $dirmode;
  494. } elsif (-f _) {
  495. $newmode= ($mode & 0111) ? $execmode : $plainmode;
  496. } elsif (-p _) {
  497. $newmode= $fifomode;
  498. } elsif (!-l _) {
  499. &internerr("unknown object \`$fn' after extract (mode ".
  500. sprintf("0%o",$mode).")");
  501. }
  502. next if ($mode & 07777) == $newmode;
  503. chmod($newmode,$fn) ||
  504. &syserr(sprintf("cannot change mode of \`%s' to 0%o from 0%o",
  505. $fn,$newmode,$mode));
  506. }
  507. exit(0);
  508. }
  509. sub checkstats {
  510. my ($f)= @_;
  511. my @s,$m;
  512. open(STDIN,"< $dscdir/$f") || &syserr("cannot read $dscdir/$f");
  513. (@s= stat(STDIN)) || &syserr("cannot fstat $dscdir/$f");
  514. $s[7] == $size{$f} || &error("file $f has size $s[7] instead of expected $size{$f}");
  515. $m= `md5sum`; $? && subprocerr("md5sum $f"); $m =~ s/\n$//;
  516. $m =~ m/^[0-9a-f]{32}$/ || &failure("md5sum of $f gave bad output \`$m'");
  517. $m eq $md5sum{$f} || &error("file $f has md5sum $m instead of expected $md5sum{$f}");
  518. open(STDIN,"</dev/null") || &syserr("reopen stdin from /dev/null");
  519. }
  520. sub erasedir {
  521. my ($dir) = @_;
  522. if (!lstat($dir)) {
  523. $! == ENOENT || &syserr("cannot stat output directory $dir (before removal)");
  524. } else {
  525. system 'rm','-r','--',$dir;
  526. $? && subprocerr("rm -r $dir");
  527. }
  528. }
  529. sub extracttar {
  530. &forkgzipread("$dscdir/$tarfile");
  531. defined($c2= fork) || &syserr("fork for cpio -i");
  532. if (!$c2) {
  533. open(STDIN,"<&GZIP") || &syserr("reopen gzip for cpio -i");
  534. &cpiostderr;
  535. exec('cpio','-Hustar','-im','--no-preserve-owner'); &syserr("exec cpio -i");
  536. }
  537. close(GZIP);
  538. $c2 == waitpid($c2,0) || &syserr("wait for cpio -i");
  539. $? && subprocerr("cpio -i");
  540. &reapgzip;
  541. }
  542. sub cpiostderr {
  543. open(STDERR,"| egrep -v '^[0-9]+ blocks\$' >&2") ||
  544. &syserr("reopen stderr for cpio to grep out blocks message");
  545. }
  546. sub setfile {
  547. my ($varref)= @_;
  548. &error("repeated file type - files ".$$varref." and $file") if length($$varref);
  549. $$varref= $file;
  550. }
  551. sub checktype {
  552. if (!lstat("$origdir/$fn")) {
  553. &unrepdiff2("nonexistent",$type{$fn});
  554. } else {
  555. $v= eval("$_[0] _ ? 2 : 1"); $v || &internerr("checktype $@ ($_[0])");
  556. return 1 if $v == 2;
  557. &unrepdiff2("something else",$type{$fn});
  558. }
  559. return 0;
  560. }
  561. sub setopmode {
  562. defined($opmode) && &usageerr("only one of -x or -b allowed, and only once");
  563. $opmode= $_[0];
  564. }
  565. sub unrepdiff {
  566. print(STDERR "$progname: cannot represent change to $fn: $_[0]\n")
  567. || &syserr("write syserr unrep");
  568. $ur++;
  569. }
  570. sub unrepdiff2 {
  571. print(STDERR "$progname: cannot represent change to $fn:\n".
  572. "$progname: new version is $_[1]\n".
  573. "$progname: old version is $_[0]\n")
  574. || &syserr("write syserr unrep");
  575. $ur++;
  576. }
  577. sub forkgzipwrite {
  578. #print STDERR "forkgzipwrite $_[0]\n";
  579. open(GZIPFILE,"> $_[0]") || &syserr("create file $_[0]");
  580. pipe(GZIPREAD,GZIP) || &syserr("pipe for gzip");
  581. defined($cgz= fork) || &syserr("fork for gzip");
  582. if (!$cgz) {
  583. open(STDIN,"<&GZIPREAD") || &syserr("reopen gzip pipe"); close(GZIPREAD);
  584. close(GZIP); open(STDOUT,">&GZIPFILE") || &syserr("reopen tar.gz");
  585. exec('gzip','-9'); &syserr("exec gzip");
  586. }
  587. close(GZIPREAD);
  588. $gzipsigpipeok= 0;
  589. }
  590. sub forkgzipread {
  591. #print STDERR "forkgzipread $_[0]\n";
  592. open(GZIPFILE,"< $_[0]") || &syserr("read file $_[0]");
  593. pipe(GZIP,GZIPWRITE) || &syserr("pipe for gunzip");
  594. defined($cgz= fork) || &syserr("fork for gunzip");
  595. if (!$cgz) {
  596. open(STDOUT,">&GZIPWRITE") || &syserr("reopen gunzip pipe"); close(GZIPWRITE);
  597. close(GZIP); open(STDIN,"<&GZIPFILE") || &syserr("reopen input file");
  598. exec('gunzip'); &syserr("exec gunzip");
  599. }
  600. close(GZIPWRITE);
  601. $gzipsigpipeok= 1;
  602. }
  603. sub reapgzip {
  604. #print STDERR "reapgzip $_[0]\n";
  605. $cgz == waitpid($cgz,0) || &syserr("wait for gzip");
  606. !$? || ($gzipsigpipeok && WIFSIGNALED($?) && WTERMSIG($?)==SIGPIPE) ||
  607. subprocerr("gzip");
  608. (@stat= stat(GZIPFILE)) || &syserr("cannot stat file after run gzip");
  609. $size= $stat[7];
  610. close(GZIPFILE);
  611. }
  612. sub addfile {
  613. my ($filename)= @_;
  614. my $md5sum= `md5sum <$filename`;
  615. $? && &subprocerr("md5sum $filename");
  616. $md5sum =~ s/^([0-9a-f]{32})\n$/$1/ ||
  617. die "$progname: failure: md5sum gave bogus output \`$_'\n";
  618. $f{'Files'}.= "\n $md5sum $size $filename";
  619. }