dpkg-source.pl 23 KB

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