dpkg-source.pl 32 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839
  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','-cO',$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. } else {
  330. s/\n$//;
  331. &internerr("unknown line from diff -u on $dir/$fn: \`$_'");
  332. }
  333. print(GZIP $_) || &syserr("failed to write to gzip");
  334. }
  335. close(DIFFGEN); $/= "\0";
  336. if (WIFEXITED($?) && (($es=WEXITSTATUS($?))==0 || $es==1)) {
  337. if ($es==1 && !$difflinefound) {
  338. &unrepdiff("diff gave 1 but no diff lines found");
  339. }
  340. } else {
  341. subprocerr("diff on $dir/$fn");
  342. }
  343. } elsif (-p _) {
  344. $type{$fn}= 'pipe';
  345. &checktype('-p');
  346. } elsif (-b _ || -c _ || -S _) {
  347. &unrepdiff("device or socket is not allowed");
  348. } elsif (-d _) {
  349. $type{$fn}= 'directory';
  350. } else {
  351. &unrepdiff("unknown file type ($!)");
  352. }
  353. }
  354. close(FIND); $? && subprocerr("find on $dir");
  355. close(GZIP) || &syserr("finish write to gzip pipe");
  356. &reapgzip;
  357. defined($c2= open(FIND,"-|")) || &syserr("fork for 2nd find");
  358. if (!$c2) {
  359. chdir($origdir) || &syserr("chdir to $origdir for 2nd find");
  360. exec('find','.','-print0'); &syserr("exec 2nd find");
  361. }
  362. $/= "\0";
  363. while (defined($fn= <FIND>)) {
  364. $fn =~ s/\0$//; $fn =~ s,^\./,,;
  365. next if defined($type{$fn});
  366. lstat("$origdir/$fn") || &syserr("cannot check orig file $origdir/$fn");
  367. if (-f _) {
  368. &warn("ignoring deletion of file $fn");
  369. } elsif (-d _) {
  370. &warn("ignoring deletion of directory $fn");
  371. } elsif (-l _) {
  372. &warn("ignoring deletion of symlink $fn");
  373. } else {
  374. &unrepdiff2('not a file, directory or link','nonexistent');
  375. }
  376. }
  377. close(FIND); $? && subprocerr("find on $dirname");
  378. &addfile("$basenamerev.diff.gz");
  379. }
  380. if ($sourcestyle =~ m/[prPR]/) {
  381. erasedir($origdir);
  382. }
  383. print("$progname: building $sourcepackage in $basenamerev.dsc\n")
  384. || &syserr("write building message");
  385. open(STDOUT,"> $basenamerev.dsc") || &syserr("create $basenamerev.dsc");
  386. &outputclose;
  387. if ($ur) {
  388. print(STDERR "$progname: unrepresentable changes to source\n")
  389. || &syserr("write error msg: $!");
  390. exit(1);
  391. }
  392. exit(0);
  393. } else {
  394. $sourcestyle =~ y/X/p/;
  395. $sourcestyle =~ m/[pun]/ ||
  396. &usageerr("source handling style -s$sourcestyle not allowed with -b");
  397. @ARGV==1 || &usageerr("-x needs exactly one argument, the .dsc");
  398. $dsc= shift(@ARGV);
  399. $dsc= "./$dsc" unless $dsc =~ m:^/:;
  400. $dscdir= $dsc; $dscdir= "./$dscdir" unless $dsc =~ m,^/|^\./,;
  401. $dscdir =~ s,/[^/]+$,,;
  402. open(CDATA,"< $dsc") || &error("cannot open .dsc file $dsc: $!");
  403. &parsecdata('S',-1,"source control file $dsc");
  404. for $f (qw(Source Version Files)) {
  405. defined($fi{"S $f"}) ||
  406. &error("missing critical source control field $f");
  407. }
  408. $sourcepackage= $fi{'S Source'};
  409. $sourcepackage =~ m/[^-+.0-9a-z]/ &&
  410. &error("source package name contains illegal character \`$&'");
  411. $sourcepackage =~ m/^[0-9a-z]./ ||
  412. &error("source package name is too short or starts with non-alphanum");
  413. $version= $fi{'S Version'};
  414. $version =~ m/[^-+:.0-9a-zA-Z]/ &&
  415. &error("version number contains illegal character \`$&'");
  416. $version =~ s/^\d+://;
  417. if ($version =~ m/-([^-]+)$/) {
  418. $baseversion= $`; $revision= $1;
  419. } else {
  420. $baseversion= $version; $revision= '';
  421. }
  422. $files= $fi{'S Files'};
  423. for $file (split(/\n /,$files)) {
  424. next if $file eq '';
  425. $file =~ m/^([0-9a-f]{32})[ \t]+(\d+)[ \t]+([0-9a-zA-Z][-+:.,=0-9a-zA-Z_]+)$/
  426. || &error("Files field contains bad line \`$file'");
  427. ($md5sum{$3},$size{$3},$file) = ($1,$2,$3);
  428. &setfile(\$tarfile) if $file =~ m/\.tar\.gz$/;
  429. &setfile(\$difffile) if $file =~ m/\.diff\.gz$/;
  430. }
  431. $newdirectory= $sourcepackage.'-'.$baseversion;
  432. $expectprefix= $newdirectory; $expectprefix.= '.orig' if length($difffile);
  433. length($tarfile) || &error("no tarfile in Files field");
  434. checkstats($tarfile);
  435. checkstats($difffile) if length($difffile);
  436. checktarsane("$dscdir/$tarfile",$expectprefix);
  437. if (length($difffile)) {
  438. if (!$dirincluded{"$expectprefix/debian"}) {
  439. $mkdebian=1; $dirincluded{"$expectprefix/debian"}= 1;
  440. }
  441. &forkgzipread("$dscdir/$difffile");
  442. $/="\n";
  443. while (length($_=<GZIP>)) {
  444. s/\n$// || &error("diff is missing trailing newline");
  445. if (m/^--- /) {
  446. $fn= $';
  447. substr($fn,0,length($expectprefix)+1) eq "$expectprefix/" ||
  448. &error("diff patches file ($fn) not in expected subdirectory");
  449. $fn =~ m/\.dpkg-orig$/ &&
  450. &error("diff patches file with name ending .dpkg-orig");
  451. $dirname= $fn;
  452. $dirname =~ s,/[^/]+$,, && defined($dirincluded{$dirname}) ||
  453. &error("diff patches file ($fn) whose directory does not appear".
  454. " in tarfile");
  455. defined($notfileobject{$fn}) &&
  456. &error("diff patches something which is not a plain file");
  457. $_= <GZIP>; s/\n$// ||
  458. &error("diff finishes in middle of ---/+++ (line $.)");
  459. $_ eq '+++ '.$newdirectory.substr($fn,length($expectprefix)) ||
  460. &error("line after --- for file $fn isn't as expected");
  461. $filepatched{$fn}++ && &error("diff patches file $fn twice");
  462. } elsif (!m/^[-+ \@]/) {
  463. &error("diff contains unknown line \`$_'");
  464. }
  465. }
  466. close(GZIP);
  467. &reapgzip;
  468. }
  469. print("$progname: extracting $sourcepackage in $newdirectory\n")
  470. || &syserr("write extracting message");
  471. &erasedir($newdirectory);
  472. &erasedir("$newdirectory.orig");
  473. extracttar("$dscdir/$tarfile",'.');
  474. if (length($difffile)) {
  475. rename($expectprefix,$newdirectory) ||
  476. &syserr("failed to rename newly-extracted $expectprefix to $newdirectory");
  477. if ($sourcestyle =~ m/u/) {
  478. extracttar("$dscdir/$tarfile",'.');
  479. } elsif ($sourcestyle =~ m/p/) {
  480. stat("$dscdir/$tarfile") ||
  481. &syserr("failed to stat \`$dscdir/$tarfile' to see if need to copy");
  482. ($dsctardev,$dsctarino) = stat _;
  483. $dumptar= $sourcepackage.'_'.$baseversion.'.orig.tar.gz';
  484. if (!stat($dumptar)) {
  485. $! == ENOENT || &syserr("failed to check destination \`$dumptar'".
  486. " to see if need to copy");
  487. } else {
  488. ($dumptardev,$dumptarino) = stat _;
  489. if ($dumptardev == $dsctardev && $dumptarino == $dsctarino) {
  490. $dumptar= '';
  491. }
  492. }
  493. if (length($dumptar)) {
  494. system('cp','--',"$dscdir/$tarfile","$dumptar");
  495. $? && subprocerr("cp $dscdir/$tarfile to $dumptar");
  496. }
  497. }
  498. if ($mkdebian) {
  499. mkdir("$newdirectory/debian",0777) ||
  500. &syserr("failed to create $newdirectory/debian subdirectory");
  501. }
  502. &forkgzipread("$dscdir/$difffile");
  503. defined($c2= fork) || &syserr("fork for patch");
  504. if (!$c2) {
  505. open(STDIN,"<&GZIP") || &syserr("reopen gzip for patch");
  506. chdir($newdirectory) || &syserr("chdir to $newdirectory for patch");
  507. exec('patch','-s','-t','-F','0','-N','-p1','-u',
  508. '-V','never','-b','.dpkg-orig');
  509. &syserr("exec patch");
  510. }
  511. close(GZIP);
  512. $c2 == waitpid($c2,0) || &syserr("wait for patch");
  513. $? && subprocerr("patch");
  514. &reapgzip;
  515. for $fn (keys %filepatched) {
  516. $ftr= "$newdirectory/".substr($fn,length($expectprefix)+1).".dpkg-orig";
  517. unlink($ftr) || &syserr("remove patch backup file $ftr");
  518. }
  519. if (!(@s= lstat("$newdirectory/debian/rules"))) {
  520. $! == ENOENT || &syserr("cannot stat $newdirectory/debian/rules");
  521. &warn("$newdirectory/debian/rules does not exist");
  522. } elsif (-f _) {
  523. chmod($s[2] | 0111, "$newdirectory/debian/rules") ||
  524. &syserr("cannot make $newdirectory/debian/rules executable");
  525. } else {
  526. &warn("$newdirectory/debian/rules is not a plain file");
  527. }
  528. }
  529. $execmode= 0777 & ~umask;
  530. (@s= stat('.')) || &syserr("cannot stat \`.'");
  531. $dirmode= $execmode | ($s[2] & 02000);
  532. $plainmode= $execmode & ~0111;
  533. $fifomode= ($plainmode & 0222) | (($plainmode & 0222) << 1);
  534. for $fn (@filesinarchive) {
  535. $fn= substr($fn,length($expectprefix)+1);
  536. $fn= "$newdirectory/$fn";
  537. (@s= lstat($fn)) || &syserr("cannot stat extracted object \`$fn'");
  538. $mode= $s[2];
  539. if (-d _) {
  540. $newmode= $dirmode;
  541. } elsif (-f _) {
  542. $newmode= ($mode & 0111) ? $execmode : $plainmode;
  543. } elsif (-p _) {
  544. $newmode= $fifomode;
  545. } elsif (!-l _) {
  546. &internerr("unknown object \`$fn' after extract (mode ".
  547. sprintf("0%o",$mode).")");
  548. }
  549. next if ($mode & 07777) == $newmode;
  550. chmod($newmode,$fn) ||
  551. &syserr(sprintf("cannot change mode of \`%s' to 0%o from 0%o",
  552. $fn,$newmode,$mode));
  553. }
  554. exit(0);
  555. }
  556. sub checkstats {
  557. my ($f)= @_;
  558. my @s,$m;
  559. open(STDIN,"< $dscdir/$f") || &syserr("cannot read $dscdir/$f");
  560. (@s= stat(STDIN)) || &syserr("cannot fstat $dscdir/$f");
  561. $s[7] == $size{$f} || &error("file $f has size $s[7] instead of expected $size{$f}");
  562. $m= `md5sum`; $? && subprocerr("md5sum $f"); $m =~ s/\n$//;
  563. $m =~ m/^[0-9a-f]{32}$/ || &failure("md5sum of $f gave bad output \`$m'");
  564. $m eq $md5sum{$f} || &error("file $f has md5sum $m instead of expected $md5sum{$f}");
  565. open(STDIN,"</dev/null") || &syserr("reopen stdin from /dev/null");
  566. }
  567. sub erasedir {
  568. my ($dir) = @_;
  569. if (!lstat($dir)) {
  570. $! == ENOENT && return;
  571. &syserr("cannot stat directory $dir (before removal)");
  572. }
  573. system 'rm','-rf','--',$dir;
  574. $? && subprocerr("rm -rf $dir");
  575. if (!stat($dir)) {
  576. $! == ENOENT && return;
  577. &syserr("unable to check for removal of dir \`$dir'");
  578. }
  579. &failure("rm -rf failed to remove \`$dir'");
  580. }
  581. sub checktarsane {
  582. my ($tarfileread,$epfx) = @_;
  583. my $c2,$fn,$pname,$slash,$mode,$dirname,$type;
  584. &forkgzipread("$tarfileread");
  585. defined($c2= open(CPIO,"-|")) || &syserr("fork for cpio");
  586. if (!$c2) {
  587. open(STDIN,"<&GZIP") || &syserr("reopen gzip for cpio");
  588. &cpiostderr;
  589. exec('cpio','-0t'); &syserr("exec cpio");
  590. }
  591. $/= "\0";
  592. close(GZIP);
  593. file:
  594. while (defined($fn= <CPIO>)) {
  595. $fn =~ s/\0$//; $pname= $fn; $pname =~ y/ -~/?/c;
  596. if ($fn =~ m/\n/) {
  597. if (!@filesinarchive) {
  598. &error("first output from cpio -0t (from \`$tarfileread') ".
  599. "contains newline - you probably have an out of ".
  600. "date version of cpio. 2.4.2-2 is known to work");
  601. } else {
  602. &error("tarfile \`$tarfileread' contains object with".
  603. " newline in its name ($pname)");
  604. }
  605. }
  606. $slash= substr($fn,length($epfx),1);
  607. (($slash eq '/' || $slash eq '') &&
  608. substr($fn,0,length($epfx)) eq $epfx) ||
  609. &error("tarfile \`$tarfileread' contains object ($pname) ".
  610. "not in expected directory ($epfx)");
  611. $fn =~ m,/\.\./, &&
  612. &error("tarfile \`$tarfilread' contains object with".
  613. " /../ in its name ($pname)");
  614. push(@filesinarchive,$fn);
  615. }
  616. close(CPIO); $? && subprocerr("cpio");
  617. $/= "\n";
  618. &reapgzip;
  619. &forkgzipread("$tarfileread");
  620. defined($c2= open(TAR,"-|")) || &syserr("fork for tar -t");
  621. if (!$c2) {
  622. $ENV{'LANG'}= 'C';
  623. open(STDIN,"<&GZIP") || &syserr("reopen gzip for tar -t");
  624. exec('tar','-vvtf','-'); &syserr("exec tar -vvtf -");
  625. }
  626. close(GZIP);
  627. $efix= 0;
  628. file:
  629. while (length($_= <TAR>)) {
  630. s/\n$//;
  631. m,^(\S{10})\s, ||
  632. &error("tarfile \`$tarfileread' contains unknown object ".
  633. "listed by tar as \`$_'");
  634. $fn= $filesinarchive[$efix++]; $mode= $1;
  635. if ($mode =~ m/^l/) { $_ =~ s/ -\> .*//; }
  636. substr($_,length($_)-length($fn)-1) eq " $fn" ||
  637. &error("tarfile \`$tarfileread' contains unexpected object".
  638. " listed by tar as \`$_', expected \`$fn'");
  639. $mode =~ s/^([-dpsl])// ||
  640. &error("tarfile \`$tarfileread' contains object \`$fn' with ".
  641. "unknown or forbidden type \`".substr($_,0,1)."'");
  642. $fn =~ m/\.dpkg-orig$/ &&
  643. &error("tarfile \`$tarfileread' contains file with name ending .dpkg-orig");
  644. $type= $&;
  645. $mode =~ m/[sStT]/ && $type ne 'd' &&
  646. &error("tarfile \`$tarfileread' contains setuid, setgid".
  647. " or sticky object \`$fn'");
  648. $fn eq "$epfx/debian" && $type ne 'd' &&
  649. &error("tarfile \`$tarfileread' contains object \`debian'".
  650. " that isn't a directory");
  651. $fn =~ s,/$,, if $type eq 'd';
  652. $dirname= $fn;
  653. $dirname =~ s,/[^/]+$,, && !defined($dirincluded{$dirname}) &&
  654. &error("tarfile \`$tarfileread' contains object \`$fn' but its containing ".
  655. "directory \`$dirname' does not precede it");
  656. $dirincluded{$fn}= 1 if $type eq 'd';
  657. $notfileobject{$fn}= 1 if $type ne '-';
  658. }
  659. close(TAR); $? && subprocerr("tar -t");
  660. &reapgzip;
  661. }
  662. sub extracttar {
  663. my ($tarfileread,$dirchdir) = @_;
  664. &forkgzipread("$tarfileread");
  665. defined($c2= fork) || &syserr("fork for cpio -i");
  666. if (!$c2) {
  667. chdir("$dirchdir") || &syserr("cannot chdir to \`$dirchdir' for tar extract");
  668. open(STDIN,"<&GZIP") || &syserr("reopen gzip for cpio -i");
  669. &cpiostderr;
  670. exec('cpio','-Hustar','-im','--no-preserve-owner'); &syserr("exec cpio -i");
  671. }
  672. close(GZIP);
  673. $c2 == waitpid($c2,0) || &syserr("wait for cpio -i");
  674. $? && subprocerr("cpio -i");
  675. &reapgzip;
  676. }
  677. sub cpiostderr {
  678. open(STDERR,"| egrep -v '^[0-9]+ blocks\$' >&2") ||
  679. &syserr("reopen stderr for cpio to grep out blocks message");
  680. }
  681. sub setfile {
  682. my ($varref)= @_;
  683. &error("repeated file type - files ".$$varref." and $file") if length($$varref);
  684. $$varref= $file;
  685. }
  686. sub checktype {
  687. if (!lstat("$origdir/$fn")) {
  688. &unrepdiff2("nonexistent",$type{$fn});
  689. } else {
  690. $v= eval("$_[0] _ ? 2 : 1"); $v || &internerr("checktype $@ ($_[0])");
  691. return 1 if $v == 2;
  692. &unrepdiff2("something else",$type{$fn});
  693. }
  694. return 0;
  695. }
  696. sub setopmode {
  697. defined($opmode) && &usageerr("only one of -x or -b allowed, and only once");
  698. $opmode= $_[0];
  699. }
  700. sub unrepdiff {
  701. print(STDERR "$progname: cannot represent change to $fn: $_[0]\n")
  702. || &syserr("write syserr unrep");
  703. $ur++;
  704. }
  705. sub unrepdiff2 {
  706. print(STDERR "$progname: cannot represent change to $fn:\n".
  707. "$progname: new version is $_[1]\n".
  708. "$progname: old version is $_[0]\n")
  709. || &syserr("write syserr unrep");
  710. $ur++;
  711. }
  712. sub forkgzipwrite {
  713. #print STDERR "forkgzipwrite $_[0]\n";
  714. open(GZIPFILE,"> $_[0]") || &syserr("create file $_[0]");
  715. pipe(GZIPREAD,GZIP) || &syserr("pipe for gzip");
  716. defined($cgz= fork) || &syserr("fork for gzip");
  717. if (!$cgz) {
  718. open(STDIN,"<&GZIPREAD") || &syserr("reopen gzip pipe"); close(GZIPREAD);
  719. close(GZIP); open(STDOUT,">&GZIPFILE") || &syserr("reopen tar.gz");
  720. exec('gzip','-9'); &syserr("exec gzip");
  721. }
  722. close(GZIPREAD);
  723. $gzipsigpipeok= 0;
  724. }
  725. sub forkgzipread {
  726. #print STDERR "forkgzipread $_[0]\n";
  727. open(GZIPFILE,"< $_[0]") || &syserr("read file $_[0]");
  728. pipe(GZIP,GZIPWRITE) || &syserr("pipe for gunzip");
  729. defined($cgz= fork) || &syserr("fork for gunzip");
  730. if (!$cgz) {
  731. open(STDOUT,">&GZIPWRITE") || &syserr("reopen gunzip pipe"); close(GZIPWRITE);
  732. close(GZIP); open(STDIN,"<&GZIPFILE") || &syserr("reopen input file");
  733. exec('gunzip'); &syserr("exec gunzip");
  734. }
  735. close(GZIPWRITE);
  736. $gzipsigpipeok= 1;
  737. }
  738. sub reapgzip {
  739. #print STDERR "reapgzip $_[0]\n";
  740. $cgz == waitpid($cgz,0) || &syserr("wait for gzip");
  741. !$? || ($gzipsigpipeok && WIFSIGNALED($?) && WTERMSIG($?)==SIGPIPE) ||
  742. subprocerr("gzip");
  743. close(GZIPFILE);
  744. }
  745. sub addfile {
  746. my ($filename)= @_;
  747. stat($filename) || &syserr("could not stat output file \`$filename'");
  748. $size= (stat _)[7];
  749. my $md5sum= `md5sum <$filename`;
  750. $? && &subprocerr("md5sum $filename");
  751. $md5sum =~ s/^([0-9a-f]{32})\n$/$1/ || &failure("md5sum gave bogus output \`$_'");
  752. $f{'Files'}.= "\n $md5sum $size $filename";
  753. }