dpkg-source.pl 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. #!/usr/bin/perl
  2. $dpkglibdir= ".";
  3. $version= '1.3.0'; # This line modified by Makefile
  4. $sourcestyle= 'X';
  5. use POSIX;
  6. use POSIX qw(:errno_h :signal_h);
  7. push(@INC,$dpkglibdir);
  8. require 'controllib.pl';
  9. sub usageversion {
  10. print STDERR
  11. "Debian GNU/Linux dpkg-source $version. Copyright (C) 1996
  12. Ian Jackson. This is free software; see the GNU General Public Licence
  13. version 2 or later for copying conditions. There is NO warranty.
  14. Usage: dpkg-source -x <filename>.dsc
  15. dpkg-source -b <directory> [<orig-directory>|<orig-targz>|\'\']
  16. Build options: -c<controlfile> get control info from this file
  17. -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. -sa auto select orig source (-sA is default)
  24. -sk use packed orig source (unpack & keep)
  25. -sp use packed orig source (unpack & remove)
  26. -su use unpacked orig source (pack & keep)
  27. -sr use unpacked orig source (pack & remove)
  28. -ss trust packed & unpacked orig src are same
  29. -sn there is no diff, do main tarfile only
  30. -sA,-sK,-sP,-sU,-sR like -sa,-sp,-sk,-su,-sr but may overwrite
  31. Extract options: -sp (default) leave orig source packed in current dir
  32. -sn do not copy original source to current dir
  33. -su unpack original source tree too
  34. General options: -h print this message
  35. ";
  36. }
  37. $i=100;grep($fieldimps{$_}=$i--,
  38. qw(Source Version Binary Maintainer Architecture Standards-Version));
  39. while (@ARGV && $ARGV[0] =~ m/^-/) {
  40. $_=shift(@ARGV);
  41. if (m/^-b$/) {
  42. &setopmode('build');
  43. } elsif (m/^-x$/) {
  44. &setopmode('extract');
  45. } elsif (m/^-s([akpursnAKPUR])$/) {
  46. $sourcestyle= $1;
  47. } elsif (m/^-c/) {
  48. $controlfile= $';
  49. } elsif (m/^-l/) {
  50. $changelogfile= $';
  51. } elsif (m/^-F([0-9a-z]+)$/) {
  52. $changelogformat=$1;
  53. } elsif (m/^-D([^\=:]+)[=:]/) {
  54. $override{$1}= $';
  55. } elsif (m/^-U([^\=:]+)$/) {
  56. $remove{$1}= 1;
  57. } elsif (m/^-V(\w[-:0-9A-Za-z]*)[=:]/) {
  58. $substvar{$1}= $';
  59. } elsif (m/^-T/) {
  60. $varlistfile= $';
  61. } elsif (m/^-h$/) {
  62. &usageversion; exit(0);
  63. } elsif (m/^--$/) {
  64. last;
  65. } else {
  66. &usageerr("unknown option $_");
  67. }
  68. }
  69. defined($opmode) || &usageerr("need -x or -b");
  70. if ($opmode eq 'build') {
  71. $sourcestyle =~ y/X/A/;
  72. $sourcestyle =~ m/[akpursnAKPUR]/ ||
  73. &usageerr("source handling style -s$sourcestyle not allowed with -b");
  74. @ARGV || &usageerr("-b needs a directory");
  75. @ARGV<=2 || &usageerr("-b takes at most a directory and an orig source argument");
  76. $dir= shift(@ARGV);
  77. $dir= "./$dir" unless $dir =~ m:^/:; $dir =~ s,/*$,,;
  78. stat($dir) || &error("cannot stat directory $dir: $!");
  79. -d $dir || &error("directory argument $dir is not a directory");
  80. $changelogfile= "$dir/debian/changelog" unless defined($changelogfile);
  81. $controlfile= "$dir/debian/control" unless defined($controlfile);
  82. &parsechangelog;
  83. &parsecontrolfile;
  84. $archspecific=0;
  85. for $_ (keys %fi) {
  86. $v= $fi{$_};
  87. if (s/^C //) {
  88. #print STDERR "G key >$_< value >$v<\n";
  89. if (m/^Source$/) { &setsourcepackage; }
  90. elsif (m/^Standards-Version$|^Maintainer$/) { $f{$_}= $v; }
  91. elsif (s/^X[BC]*S[BC]*-//i) { $f{$_}= $v; }
  92. elsif (m/^(Section|Priority|Files)$/ || m/^X[BC]+-/i) { }
  93. else { &unknown('general section of control info file'); }
  94. } elsif (s/^C(\d+) //) {
  95. #print STDERR "P key >$_< value >$v<\n";
  96. $i=$1; $p=$fi{"C$i Package"};
  97. push(@binarypackages,$p) unless $packageadded{$p}++;
  98. if (m/^Architecture$/) {
  99. #print STDERR "$p >$v< >".join(' ',@sourcearch)."<\n";
  100. if ($v eq 'any') {
  101. @sourcearch= ('any');
  102. } elsif ($v eq 'all') {
  103. if (!@sourcearch || $sourcearch[0] eq 'all') {
  104. @sourcearch= ('all');
  105. } else {
  106. @sourcearch= ('any');
  107. }
  108. } else {
  109. if (grep($sourcearch[0] eq $_, 'any','all')) {
  110. @sourcearch= ('any');
  111. } else {
  112. for $a (split(/\s+/,$v)) {
  113. &error("architecture $a only allowed on its own".
  114. " (list for package $p is \`$a')")
  115. if grep($a eq $_, 'any','all');
  116. push(@sourcearch,$a) unless $archadded{$a}++;
  117. }
  118. }
  119. }
  120. $f{'Architecture'}= join(' ',@sourcearch);
  121. } elsif (s/^X[BC]*S[BC]*-//i) {
  122. $f{$_}= $v;
  123. } elsif (m/^(Package|Essential|Pre-Depends|Depends|Provides)$/ ||
  124. m/^(Recommends|Suggests|Optional|Conflicts|Replaces)$/ ||
  125. m/^(Description|Section|Priority)$/ ||
  126. m/^X[CS]+-/i) {
  127. } else {
  128. &unknown("package's section of control info file");
  129. }
  130. } elsif (s/^L //) {
  131. #print STDERR "L key >$_< value >$v<\n";
  132. if (m/^Source$/) {
  133. &setsourcepackage;
  134. } elsif (m/^Version$/) {
  135. $f{$_}= $v;
  136. } elsif (s/^X[BS]*C[BS]*-//i) {
  137. $f{$_}= $v;
  138. } elsif (m/^(Maintainer|Changes|Urgency|Distribution|Date)$/ ||
  139. m/^X[BS]+-/i) {
  140. } else {
  141. &unknown("parsed version of changelog");
  142. }
  143. } else {
  144. &internerr("value from nowhere, with key >$_< and value >$v<");
  145. }
  146. }
  147. $f{'Binary'}= join(', ',@binarypackages);
  148. for $f (keys %override) { $f{&capit($f)}= $override{$f}; }
  149. for $f (qw(Version)) {
  150. defined($f{$f}) || &error("missing information for critical output field $f");
  151. }
  152. for $f (qw(Maintainer Architecture Standards-Version)) {
  153. defined($f{$f}) || &warn("missing information for output field $f");
  154. }
  155. defined($sourcepackage) || &error("unable to determine source package name !");
  156. $f{'Source'}= $sourcepackage;
  157. for $f (keys %remove) { delete $f{&capit($f)}; }
  158. $version= $f{'Version'};
  159. $version =~ s/^\d+://; $upstreamversion= $version; $upstreamversion =~ s/-[^-]*$//;
  160. $basenamerev= $sourcepackage.'_'.$version;
  161. $basename= $sourcepackage.'_'.$upstreamversion;
  162. $basedirname= $basename;
  163. #print STDERR ">$basedirname<\n";
  164. $basedirname =~ s/_/-/;
  165. #print STDERR ">$basedirname<\n";
  166. $origdir= "$dir.orig";
  167. $origtargz= "$basename.orig.tar.gz";
  168. if (@ARGV) {
  169. $origarg= shift(@ARGV);
  170. if (length($origarg)) {
  171. stat($origarg) || &error("cannot stat orig argument $origarg: $!");
  172. if (-d _) {
  173. $origdir= $origarg;
  174. $origdir= "./$origdir" unless $origdir =~ m,^/,; $origdir =~ s,/*$,,;
  175. $sourcestyle =~ y/aA/rR/;
  176. $sourcestyle =~ m/[ursURS]/ ||
  177. &error("orig argument is unpacked but source handling style".
  178. " -s$sourcestyle calls for packed (.orig.tar.gz)");
  179. } elsif (-f _) {
  180. $origtargz= $origarg;
  181. $sourcestyle =~ y/aA/pP/;
  182. $sourcestyle =~ m/[kpsKPS]/ ||
  183. &error("orig argument is packed but source handling style".
  184. " -s$sourcestyle calls for unpacked (.orig/)");
  185. } else {
  186. &error("orig argument $origarg is not a plain file or directory");
  187. }
  188. } else {
  189. $sourcestyle =~ y/aA/nn/;
  190. $sourcestyle =~ m/n/ ||
  191. &error("orig argument is empty (means no orig, no diff)".
  192. " but source handling style -s$sourcestyle wants something");
  193. }
  194. }
  195. if ($sourcestyle =~ m/[aA]/) {
  196. if (stat("$origtargz")) {
  197. -f _ || &error("packed orig \`$origtargz' exists but is not a plain file");
  198. $sourcestyle =~ y/aA/pP/;
  199. } elsif ($! != ENOENT) {
  200. &syserr("unable to stat putative packed orig \`$origtargz'");
  201. } elsif (stat("$origdir")) {
  202. -d _ || &error("unpacked orig \`$origdir' exists but is not a directory");
  203. $sourcestyle =~ y/aA/rR/;
  204. } elsif ($! != ENOENT) {
  205. &syserr("unable to stat putative unpacked orig \`$origdir'");
  206. } else {
  207. $sourcestyle =~ y/aA/nn/;
  208. }
  209. }
  210. $dirbase= $dir; $dirbase =~ s,/?$,,; $dirbase =~ s,[^/]+$,,; $dirname= $&;
  211. $dirname eq $basedirname || &warn("source directory \`$dir' is not <sourcepackage>".
  212. "-<upstreamversion> \`$basedirname'");
  213. if ($sourcestyle ne 'n') {
  214. $origdirbase= $origdir; $origdirbase =~ s,/?$,,;
  215. $origdirbase =~ s,[^/]+$,,; $origdirname= $&;
  216. $origdirname eq "$basedirname.orig" ||
  217. &warn(".orig directory name $origdirname is not <package>".
  218. "-<upstreamversion> (wanted $basedirname.orig)");
  219. $tardirbase= $origdirbase; $tardirname= $origdirname;
  220. $tarname= $origtargz;
  221. $tarname eq "$basename.orig.tar.gz" ||
  222. &warn(".orig.tar.gz name $tarname is not <package>_<upstreamversion>".
  223. ".orig.tar.gz (wanted $basename.orig.tar.gz)");
  224. } else {
  225. $tardirbase= $dirbase; $tardirname= $dirname;
  226. $tarname= "$basename.tar.gz";
  227. }
  228. #print STDERR ">$dir|$origdir|$origtargz|$sourcestyle<\n";
  229. if ($sourcestyle =~ m/[nurUR]/) {
  230. if (stat($tarname)) {
  231. $sourcestyle =~ m/[nUR]/ ||
  232. &error("tarfile \`$tarname' already exists, not overwriting,".
  233. " giving up; use -sU or -sR to override");
  234. } elsif ($! != ENOENT) {
  235. &syserr("unable to check for existence of \`$tarname'");
  236. }
  237. #print STDERR ">$tarname|$tardirbase|$tardirname<\n";
  238. print("$progname: building $sourcepackage in $tarname\n")
  239. || &syserr("write building tar message");
  240. &forkgzipwrite("$tarname.new");
  241. defined($c2= fork) || &syserr("fork for tar");
  242. if (!$c2) {
  243. chdir($tardirbase) || &syserr("chdir to above (orig) source $tardirbase");
  244. #system('pwd && ls');
  245. open(STDOUT,">&GZIP") || &syserr("reopen gzip for tar");
  246. # FIXME: put `--' argument back when tar is fixed
  247. exec('tar','-cf','-',$tardirname); &syserr("exec tar");
  248. }
  249. close(GZIP);
  250. &reapgzip;
  251. $c2 == waitpid($c2,0) || &syserr("wait for tar");
  252. $? && !(WIFSIGNALED($c2) && WTERMSIG($c2) == SIGPIPE) && subprocerr("tar");
  253. rename("$tarname.new",$tarname) ||
  254. &syserr("unable to rename \`$tarname.new' (newly created) to \`$tarname'");
  255. } else {
  256. print("$progname: building $sourcepackage using existing $tarname\n")
  257. || &syserr("write using existing tar message");
  258. }
  259. addfile("$tarname");
  260. if ($sourcestyle =~ m/[kpKP]/) {
  261. if (stat($origdir)) {
  262. $sourcestyle =~ m/[KP]/ ||
  263. &error("orig dir \`$origdir' already exists, not overwriting,".
  264. " giving up; use -sA, -sK or -sP to override");
  265. erasedir($origdir);
  266. } elsif ($! != ENOENT) {
  267. &syserr("unable to check for existence of orig dir \`$origdir'");
  268. }
  269. $expectprefix= $origdir; $expectprefix =~ s,^\./,,;
  270. checktarsane($origtargz,$expectprefix);
  271. mkdir("$origtargz.tmp-nest",0755) ||
  272. &syserr("unable to create \`$origdirtargz.tmp-nest'");
  273. extracttar($origtargz,"$origtargz.tmp-nest");
  274. rename("$origtargz.tmp-nest/$expectprefix",$expectprefix) ||
  275. &syserr("unable to rename \`$origtargz.tmp-nest/$expectprefix' to ".
  276. "\`$expectprefix'");
  277. rmdir("$origtargz.tmp-nest") ||
  278. &syserr("unable to remove \`$origdirtargz.tmp-nest'");
  279. }
  280. if ($sourcestyle =~ m/[kpursKPUR]/) {
  281. print("$progname: building $sourcepackage in $basenamerev.diff.gz\n")
  282. || &syserr("write building diff message");
  283. &forkgzipwrite("$basenamerev.diff.gz");
  284. defined($c2= open(FIND,"-|")) || &syserr("fork for find");
  285. if (!$c2) {
  286. chdir($dir) || &syserr("chdir to $dir for find");
  287. exec('find','.','-print0'); &syserr("exec find");
  288. }
  289. $/= "\0";
  290. file:
  291. while (defined($fn= <FIND>)) {
  292. $fn =~ s/\0$//; $fn =~ s,^\./,,;
  293. lstat("$dir/$fn") || &syserr("cannot stat file $dir/$fn");
  294. if (-l _) {
  295. $type{$fn}= 'symlink';
  296. &checktype('-l') || next;
  297. defined($n= readlink("$dir/$fn")) ||
  298. &syserr("cannot read link $dir/$fn");
  299. defined($n2= readlink("$origdir/$fn")) ||
  300. &syserr("cannot read orig link $origdir/$fn");
  301. $n eq $n2 || &unrepdiff2("symlink to $n2","symlink to $n");
  302. } elsif (-f _) {
  303. $type{$fn}= 'plain file';
  304. if (!lstat("$origdir/$fn")) {
  305. $! == ENOENT || &syserr("cannot stat orig file $origdir/$fn");
  306. $ofnread= '/dev/null';
  307. } elsif (-f _) {
  308. $ofnread= "$origdir/$fn";
  309. } else {
  310. &unrepdiff2("something else","plain file");
  311. next;
  312. }
  313. defined($c3= open(DIFFGEN,"-|")) || &syserr("fork for diff");
  314. if (!$c3) {
  315. exec('diff','-u',
  316. '-L',"$basedirname.orig/$fn",
  317. '-L',"$basedirname/$fn",
  318. '--',"$ofnread","$dir/$fn"); &syserr("exec diff");
  319. }
  320. $difflinefound= 0;
  321. $/= "\n";
  322. while (<DIFFGEN>) {
  323. if (m/^binary/i) {
  324. close(DIFFGEN); $/= "\0";
  325. &unrepdiff("binary file contents changed");
  326. next file;
  327. } elsif (m/^[-+\@ ]/) {
  328. $difflinefound=1;
  329. } elsif (m/^\\ No newline at end of file/) {
  330. &warn("file $fn has no final newline ".
  331. "(either original or modified version)");
  332. } else {
  333. s/\n$//;
  334. &internerr("unknown line from diff -u on $fn: \`$_'");
  335. }
  336. print(GZIP $_) || &syserr("failed to write to gzip");
  337. }
  338. close(DIFFGEN); $/= "\0";
  339. if (WIFEXITED($?) && (($es=WEXITSTATUS($?))==0 || $es==1)) {
  340. if ($es==1 && !$difflinefound) {
  341. &unrepdiff("diff gave 1 but no diff lines found");
  342. }
  343. } else {
  344. subprocerr("diff on $dir/$fn");
  345. }
  346. } elsif (-p _) {
  347. $type{$fn}= 'pipe';
  348. &checktype('-p');
  349. } elsif (-b _ || -c _ || -S _) {
  350. &unrepdiff("device or socket is not allowed");
  351. } elsif (-d _) {
  352. $type{$fn}= 'directory';
  353. } else {
  354. &unrepdiff("unknown file type ($!)");
  355. }
  356. }
  357. close(FIND); $? && subprocerr("find on $dir");
  358. close(GZIP) || &syserr("finish write to gzip pipe");
  359. &reapgzip;
  360. defined($c2= open(FIND,"-|")) || &syserr("fork for 2nd find");
  361. if (!$c2) {
  362. chdir($origdir) || &syserr("chdir to $origdir for 2nd find");
  363. exec('find','.','-print0'); &syserr("exec 2nd find");
  364. }
  365. $/= "\0";
  366. while (defined($fn= <FIND>)) {
  367. $fn =~ s/\0$//; $fn =~ s,^\./,,;
  368. next if defined($type{$fn});
  369. lstat("$origdir/$fn") || &syserr("cannot check orig file $origdir/$fn");
  370. if (-f _) {
  371. &warn("ignoring deletion of file $fn");
  372. } elsif (-d _) {
  373. &warn("ignoring deletion of directory $fn");
  374. } elsif (-l _) {
  375. &warn("ignoring deletion of symlink $fn");
  376. } else {
  377. &unrepdiff2('not a file, directory or link','nonexistent');
  378. }
  379. }
  380. close(FIND); $? && subprocerr("find on $dirname");
  381. &addfile("$basenamerev.diff.gz");
  382. }
  383. if ($sourcestyle =~ m/[prPR]/) {
  384. erasedir($origdir);
  385. }
  386. print("$progname: building $sourcepackage in $basenamerev.dsc\n")
  387. || &syserr("write building message");
  388. open(STDOUT,"> $basenamerev.dsc") || &syserr("create $basenamerev.dsc");
  389. &outputclose;
  390. if ($ur) {
  391. print(STDERR "$progname: unrepresentable changes to source\n")
  392. || &syserr("write error msg: $!");
  393. exit(1);
  394. }
  395. exit(0);
  396. } else {
  397. $sourcestyle =~ y/X/p/;
  398. $sourcestyle =~ m/[pun]/ ||
  399. &usageerr("source handling style -s$sourcestyle not allowed with -b");
  400. @ARGV==1 || &usageerr("-x needs exactly one argument, the .dsc");
  401. $dsc= shift(@ARGV);
  402. $dsc= "./$dsc" unless $dsc =~ m:^/:;
  403. $dscdir= $dsc; $dscdir= "./$dscdir" unless $dsc =~ m,^/|^\./,;
  404. $dscdir =~ s,/[^/]+$,,;
  405. open(CDATA,"< $dsc") || &error("cannot open .dsc file $dsc: $!");
  406. &parsecdata('S',-1,"source control file $dsc");
  407. for $f (qw(Source Version Files)) {
  408. defined($fi{"S $f"}) ||
  409. &error("missing critical source control field $f");
  410. }
  411. $sourcepackage= $fi{'S Source'};
  412. $sourcepackage =~ m/[^-+.0-9a-z]/ &&
  413. &error("source package name contains illegal character \`$&'");
  414. $sourcepackage =~ m/^[0-9a-z]./ ||
  415. &error("source package name is too short or starts with non-alphanum");
  416. $version= $fi{'S Version'};
  417. $version =~ m/[^-+:.0-9a-zA-Z]/ &&
  418. &error("version number contains illegal character \`$&'");
  419. $version =~ s/^\d+://;
  420. if ($version =~ m/-([^-]+)$/) {
  421. $baseversion= $`; $revision= $1;
  422. } else {
  423. $baseversion= $version; $revision= '';
  424. }
  425. $files= $fi{'S Files'};
  426. for $file (split(/\n /,$files)) {
  427. next if $file eq '';
  428. $file =~ m/^([0-9a-f]{32})[ \t]+(\d+)[ \t]+([0-9a-zA-Z][-+:.,=0-9a-zA-Z_]+)$/
  429. || &error("Files field contains bad line \`$file'");
  430. ($md5sum{$3},$size{$3},$file) = ($1,$2,$3);
  431. &setfile(\$tarfile) if $file =~ m/\.tar\.gz$/;
  432. &setfile(\$difffile) if $file =~ m/\.diff\.gz$/;
  433. }
  434. $newdirectory= $sourcepackage.'-'.$baseversion;
  435. $expectprefix= $newdirectory; $expectprefix.= '.orig' if length($difffile);
  436. length($tarfile) || &error("no tarfile in Files field");
  437. checkstats($tarfile);
  438. checkstats($difffile) if length($difffile);
  439. checktarsane("$dscdir/$tarfile",$expectprefix);
  440. if (length($difffile)) {
  441. if (!$dirincluded{"$expectprefix/debian"}) {
  442. $mkdebian=1; $dirincluded{"$expectprefix/debian"}= 1;
  443. }
  444. &forkgzipread("$dscdir/$difffile");
  445. $/="\n";
  446. while (length($_=<GZIP>)) {
  447. s/\n$// || &error("diff is missing trailing newline");
  448. if (m/^--- /) {
  449. $fn= $';
  450. substr($fn,0,length($expectprefix)+1) eq "$expectprefix/" ||
  451. &error("diff patches file ($fn) not in expected subdirectory");
  452. $fn =~ m/\.dpkg-orig$/ &&
  453. &error("diff patches file with name ending .dpkg-orig");
  454. $dirname= $fn;
  455. $dirname =~ s,/[^/]+$,, && defined($dirincluded{$dirname}) ||
  456. &error("diff patches file ($fn) whose directory does not appear".
  457. " in tarfile");
  458. defined($notfileobject{$fn}) &&
  459. &error("diff patches something which is not a plain file");
  460. $_= <GZIP>; s/\n$// ||
  461. &error("diff finishes in middle of ---/+++ (line $.)");
  462. $_ eq '+++ '.$newdirectory.substr($fn,length($expectprefix)) ||
  463. &error("line after --- for file $fn isn't as expected");
  464. $filepatched{$fn}++ && &error("diff patches file $fn twice");
  465. } elsif (!m/^[-+ \@]/) {
  466. &error("diff contains unknown line \`$_'");
  467. }
  468. }
  469. close(GZIP);
  470. &reapgzip;
  471. }
  472. print("$progname: extracting $sourcepackage in $newdirectory\n")
  473. || &syserr("write extracting message");
  474. &erasedir($newdirectory);
  475. &erasedir("$newdirectory.orig");
  476. extracttar("$dscdir/$tarfile",'.');
  477. if (length($difffile)) {
  478. rename($expectprefix,$newdirectory) ||
  479. &syserr("failed to rename newly-extracted $expectprefix to $newdirectory");
  480. if ($sourcestyle =~ m/u/) {
  481. extracttar("$dscdir/$tarfile",'.');
  482. } elsif ($sourcestyle =~ m/p/) {
  483. stat("$dscdir/$tarfile") ||
  484. &syserr("failed to stat \`$dscdir/$tarfile' to see if need to copy");
  485. ($dsctardev,$dsctarino) = stat _;
  486. $dumptar= $sourcepackage.'_'.$baseversion.'.orig.tar.gz';
  487. if (!stat($dumptar)) {
  488. $! == ENOENT || &syserr("failed to check destination \`$dumptar'".
  489. " to see if need to copy");
  490. } else {
  491. ($dumptardev,$dumptarino) = stat _;
  492. if ($dumptardev == $dsctardev && $dumptarino == $dsctarino) {
  493. $dumptar= '';
  494. }
  495. }
  496. if (length($dumptar)) {
  497. system('cp','--',"$dscdir/$tarfile","$dumptar");
  498. $? && subprocerr("cp $dscdir/$tarfile to $dumptar");
  499. }
  500. }
  501. if ($mkdebian) {
  502. mkdir("$newdirectory/debian",0777) ||
  503. &syserr("failed to create $newdirectory/debian subdirectory");
  504. }
  505. &forkgzipread("$dscdir/$difffile");
  506. defined($c2= fork) || &syserr("fork for patch");
  507. if (!$c2) {
  508. open(STDIN,"<&GZIP") || &syserr("reopen gzip for patch");
  509. chdir($newdirectory) || &syserr("chdir to $newdirectory for patch");
  510. exec('patch','-s','-t','-F','0','-N','-p1','-u',
  511. '-V','never','-b','.dpkg-orig');
  512. &syserr("exec patch");
  513. }
  514. close(GZIP);
  515. $c2 == waitpid($c2,0) || &syserr("wait for patch");
  516. $? && subprocerr("patch");
  517. &reapgzip;
  518. for $fn (keys %filepatched) {
  519. $ftr= "$newdirectory/".substr($fn,length($expectprefix)+1).".dpkg-orig";
  520. unlink($ftr) || &syserr("remove patch backup file $ftr");
  521. }
  522. if (!(@s= lstat("$newdirectory/debian/rules"))) {
  523. $! == ENOENT || &syserr("cannot stat $newdirectory/debian/rules");
  524. &warn("$newdirectory/debian/rules does not exist");
  525. } elsif (-f _) {
  526. chmod($s[2] | 0111, "$newdirectory/debian/rules") ||
  527. &syserr("cannot make $newdirectory/debian/rules executable");
  528. } else {
  529. &warn("$newdirectory/debian/rules is not a plain file");
  530. }
  531. }
  532. $execmode= 0777 & ~umask;
  533. (@s= stat('.')) || &syserr("cannot stat \`.'");
  534. $dirmode= $execmode | ($s[2] & 02000);
  535. $plainmode= $execmode & ~0111;
  536. $fifomode= ($plainmode & 0222) | (($plainmode & 0222) << 1);
  537. for $fn (@filesinarchive) {
  538. $fn= substr($fn,length($expectprefix)+1);
  539. $fn= "$newdirectory/$fn";
  540. (@s= lstat($fn)) || &syserr("cannot stat extracted object \`$fn'");
  541. $mode= $s[2];
  542. if (-d _) {
  543. $newmode= $dirmode;
  544. } elsif (-f _) {
  545. $newmode= ($mode & 0111) ? $execmode : $plainmode;
  546. } elsif (-p _) {
  547. $newmode= $fifomode;
  548. } elsif (!-l _) {
  549. &internerr("unknown object \`$fn' after extract (mode ".
  550. sprintf("0%o",$mode).")");
  551. }
  552. next if ($mode & 07777) == $newmode;
  553. chmod($newmode,$fn) ||
  554. &syserr(sprintf("cannot change mode of \`%s' to 0%o from 0%o",
  555. $fn,$newmode,$mode));
  556. }
  557. exit(0);
  558. }
  559. sub checkstats {
  560. my ($f)= @_;
  561. my @s,$m;
  562. open(STDIN,"< $dscdir/$f") || &syserr("cannot read $dscdir/$f");
  563. (@s= stat(STDIN)) || &syserr("cannot fstat $dscdir/$f");
  564. $s[7] == $size{$f} || &error("file $f has size $s[7] instead of expected $size{$f}");
  565. $m= `md5sum`; $? && subprocerr("md5sum $f"); $m =~ s/\n$//;
  566. $m =~ m/^[0-9a-f]{32}$/ || &failure("md5sum of $f gave bad output \`$m'");
  567. $m eq $md5sum{$f} || &error("file $f has md5sum $m instead of expected $md5sum{$f}");
  568. open(STDIN,"</dev/null") || &syserr("reopen stdin from /dev/null");
  569. }
  570. sub erasedir {
  571. my ($dir) = @_;
  572. if (!lstat($dir)) {
  573. $! == ENOENT && return;
  574. &syserr("cannot stat directory $dir (before removal)");
  575. }
  576. system 'rm','-rf','--',$dir;
  577. $? && subprocerr("rm -rf $dir");
  578. if (!stat($dir)) {
  579. $! == ENOENT && return;
  580. &syserr("unable to check for removal of dir \`$dir'");
  581. }
  582. &failure("rm -rf failed to remove \`$dir'");
  583. }
  584. sub checktarsane {
  585. my ($tarfileread,$epfx) = @_;
  586. my $c2,$fn,$pname,$slash,$mode,$dirname,$type;
  587. &forkgzipread("$tarfileread");
  588. defined($c2= open(CPIO,"-|")) || &syserr("fork for cpio");
  589. if (!$c2) {
  590. open(STDIN,"<&GZIP") || &syserr("reopen gzip for cpio");
  591. &cpiostderr;
  592. exec('cpio','-0t'); &syserr("exec cpio");
  593. }
  594. $/= "\0";
  595. close(GZIP);
  596. file:
  597. while (defined($fn= <CPIO>)) {
  598. $fn =~ s/\0$//; $pname= $fn; $pname =~ y/ -~/?/c;
  599. if ($fn =~ m/\n/) {
  600. if (!@filesinarchive) {
  601. &error("first output from cpio -0t (from \`$tarfileread') ".
  602. "contains newline - you probably have an out of ".
  603. "date version of cpio. 2.4.2-2 is known to work");
  604. } else {
  605. &error("tarfile \`$tarfileread' contains object with".
  606. " newline in its name ($pname)");
  607. }
  608. }
  609. $slash= substr($fn,length($epfx),1);
  610. (($slash eq '/' || $slash eq '') &&
  611. substr($fn,0,length($epfx)) eq $epfx) ||
  612. &error("tarfile \`$tarfileread' contains object ($pname) ".
  613. "not in expected directory ($epfx)");
  614. $fn =~ m,/\.\./, &&
  615. &error("tarfile \`$tarfilread' contains object with".
  616. " /../ in its name ($pname)");
  617. push(@filesinarchive,$fn);
  618. }
  619. close(CPIO); $? && subprocerr("cpio");
  620. $/= "\n";
  621. &reapgzip;
  622. &forkgzipread("$tarfileread");
  623. defined($c2= open(TAR,"-|")) || &syserr("fork for tar -t");
  624. if (!$c2) {
  625. $ENV{'LANG'}= 'C';
  626. open(STDIN,"<&GZIP") || &syserr("reopen gzip for tar -t");
  627. exec('tar','-vvtf','-'); &syserr("exec tar -vvtf -");
  628. }
  629. close(GZIP);
  630. $efix= 0;
  631. file:
  632. while (length($_= <TAR>)) {
  633. s/\n$//;
  634. m,^(\S{10})\s, ||
  635. &error("tarfile \`$tarfileread' contains unknown object ".
  636. "listed by tar as \`$_'");
  637. $fn= $filesinarchive[$efix++]; $mode= $1;
  638. if ($mode =~ m/^l/) { $_ =~ s/ -\> .*//; }
  639. substr($_,length($_)-length($fn)-1) eq " $fn" ||
  640. &error("tarfile \`$tarfileread' contains unexpected object".
  641. " listed by tar as \`$_', expected \`$fn'");
  642. $mode =~ s/^([-dpsl])// ||
  643. &error("tarfile \`$tarfileread' contains object \`$fn' with ".
  644. "unknown or forbidden type \`".substr($_,0,1)."'");
  645. $fn =~ m/\.dpkg-orig$/ &&
  646. &error("tarfile \`$tarfileread' contains file with name ending .dpkg-orig");
  647. $type= $&;
  648. $mode =~ m/[sStT]/ && $type ne 'd' &&
  649. &error("tarfile \`$tarfileread' contains setuid, setgid".
  650. " or sticky object \`$fn'");
  651. $fn eq "$epfx/debian" && $type ne 'd' &&
  652. &error("tarfile \`$tarfileread' contains object \`debian'".
  653. " that isn't a directory");
  654. $fn =~ s,/$,, if $type eq 'd';
  655. $dirname= $fn;
  656. $dirname =~ s,/[^/]+$,, && !defined($dirincluded{$dirname}) &&
  657. &error("tarfile \`$tarfileread' contains object \`$fn' but its containing ".
  658. "directory \`$dirname' does not precede it");
  659. $dirincluded{$fn}= 1 if $type eq 'd';
  660. $notfileobject{$fn}= 1 if $type ne '-';
  661. }
  662. close(TAR); $? && subprocerr("tar -t");
  663. &reapgzip;
  664. }
  665. sub extracttar {
  666. my ($tarfileread,$dirchdir) = @_;
  667. &forkgzipread("$tarfileread");
  668. defined($c2= fork) || &syserr("fork for cpio -i");
  669. if (!$c2) {
  670. chdir("$dirchdir") || &syserr("cannot chdir to \`$dirchdir' for tar extract");
  671. open(STDIN,"<&GZIP") || &syserr("reopen gzip for cpio -i");
  672. &cpiostderr;
  673. exec('cpio','-Hustar','-im','--no-preserve-owner'); &syserr("exec cpio -i");
  674. }
  675. close(GZIP);
  676. $c2 == waitpid($c2,0) || &syserr("wait for cpio -i");
  677. $? && subprocerr("cpio -i");
  678. &reapgzip;
  679. }
  680. sub cpiostderr {
  681. open(STDERR,"| egrep -v '^[0-9]+ blocks\$' >&2") ||
  682. &syserr("reopen stderr for cpio to grep out blocks message");
  683. }
  684. sub setfile {
  685. my ($varref)= @_;
  686. &error("repeated file type - files ".$$varref." and $file") if length($$varref);
  687. $$varref= $file;
  688. }
  689. sub checktype {
  690. if (!lstat("$origdir/$fn")) {
  691. &unrepdiff2("nonexistent",$type{$fn});
  692. } else {
  693. $v= eval("$_[0] _ ? 2 : 1"); $v || &internerr("checktype $@ ($_[0])");
  694. return 1 if $v == 2;
  695. &unrepdiff2("something else",$type{$fn});
  696. }
  697. return 0;
  698. }
  699. sub setopmode {
  700. defined($opmode) && &usageerr("only one of -x or -b allowed, and only once");
  701. $opmode= $_[0];
  702. }
  703. sub unrepdiff {
  704. print(STDERR "$progname: cannot represent change to $fn: $_[0]\n")
  705. || &syserr("write syserr unrep");
  706. $ur++;
  707. }
  708. sub unrepdiff2 {
  709. print(STDERR "$progname: cannot represent change to $fn:\n".
  710. "$progname: new version is $_[1]\n".
  711. "$progname: old version is $_[0]\n")
  712. || &syserr("write syserr unrep");
  713. $ur++;
  714. }
  715. sub forkgzipwrite {
  716. #print STDERR "forkgzipwrite $_[0]\n";
  717. open(GZIPFILE,"> $_[0]") || &syserr("create file $_[0]");
  718. pipe(GZIPREAD,GZIP) || &syserr("pipe for gzip");
  719. defined($cgz= fork) || &syserr("fork for gzip");
  720. if (!$cgz) {
  721. open(STDIN,"<&GZIPREAD") || &syserr("reopen gzip pipe"); close(GZIPREAD);
  722. close(GZIP); open(STDOUT,">&GZIPFILE") || &syserr("reopen tar.gz");
  723. exec('gzip','-9'); &syserr("exec gzip");
  724. }
  725. close(GZIPREAD);
  726. $gzipsigpipeok= 0;
  727. }
  728. sub forkgzipread {
  729. #print STDERR "forkgzipread $_[0]\n";
  730. open(GZIPFILE,"< $_[0]") || &syserr("read file $_[0]");
  731. pipe(GZIP,GZIPWRITE) || &syserr("pipe for gunzip");
  732. defined($cgz= fork) || &syserr("fork for gunzip");
  733. if (!$cgz) {
  734. open(STDOUT,">&GZIPWRITE") || &syserr("reopen gunzip pipe"); close(GZIPWRITE);
  735. close(GZIP); open(STDIN,"<&GZIPFILE") || &syserr("reopen input file");
  736. exec('gunzip'); &syserr("exec gunzip");
  737. }
  738. close(GZIPWRITE);
  739. $gzipsigpipeok= 1;
  740. }
  741. sub reapgzip {
  742. #print STDERR "reapgzip $_[0]\n";
  743. $cgz == waitpid($cgz,0) || &syserr("wait for gzip");
  744. !$? || ($gzipsigpipeok && WIFSIGNALED($?) && WTERMSIG($?)==SIGPIPE) ||
  745. subprocerr("gzip");
  746. close(GZIPFILE);
  747. }
  748. sub addfile {
  749. my ($filename)= @_;
  750. stat($filename) || &syserr("could not stat output file \`$filename'");
  751. $size= (stat _)[7];
  752. my $md5sum= `md5sum <$filename`;
  753. $? && &subprocerr("md5sum $filename");
  754. $md5sum =~ s/^([0-9a-f]{32})\n$/$1/ || &failure("md5sum gave bogus output \`$_'");
  755. $f{'Files'}.= "\n $md5sum $size $filename";
  756. }