dpkg-source.pl 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477
  1. #! /usr/bin/perl
  2. use strict;
  3. use warnings;
  4. use Dpkg;
  5. use Dpkg::Gettext;
  6. use Dpkg::ErrorHandling qw(warning warnerror error failure unknown
  7. internerr syserr subprocerr usageerr
  8. $warnable_error $quiet_warnings);
  9. use Dpkg::Arch qw(debarch_eq);
  10. use Dpkg::Deps qw(@src_dep_fields %dep_field_type);
  11. use Dpkg::Fields qw(:list capit);
  12. use Dpkg::Compression;
  13. use Dpkg::Cdata;
  14. use Dpkg::Control;
  15. use Dpkg::Substvars;
  16. use Dpkg::Version qw(check_version);
  17. use Dpkg::Vars;
  18. use Dpkg::Changelog qw(parse_changelog);
  19. use Dpkg::Source::Compressor;
  20. my @filesinarchive;
  21. my %dirincluded;
  22. my %notfileobject;
  23. my $fn;
  24. my $ur;
  25. my $varlistfile;
  26. my $controlfile;
  27. my $changelogfile;
  28. my $changelogformat;
  29. our $diff_ignore_regexp = '';
  30. my $diff_ignore_default_regexp = '
  31. # Ignore general backup files
  32. (?:^|/).*~$|
  33. # Ignore emacs recovery files
  34. (?:^|/)\.#.*$|
  35. # Ignore vi swap files
  36. (?:^|/)\..*\.swp$|
  37. # Ignore baz-style junk files or directories
  38. (?:^|/),,.*(?:$|/.*$)|
  39. # File-names that should be ignored (never directories)
  40. (?:^|/)(?:DEADJOE|\.cvsignore|\.arch-inventory|\.bzrignore|\.gitignore)$|
  41. # File or directory names that should be ignored
  42. (?:^|/)(?:CVS|RCS|\.deps|\{arch\}|\.arch-ids|\.svn|\.hg|_darcs|\.git|
  43. \.shelf|_MTN|\.bzr(?:\.backup|tags)?)(?:$|/.*$)
  44. ';
  45. # Take out comments and newlines
  46. $diff_ignore_default_regexp =~ s/^#.*$//mg;
  47. $diff_ignore_default_regexp =~ s/\n//sg;
  48. no warnings 'qw';
  49. my @tar_ignore_default_pattern = qw(
  50. *.a
  51. *.la
  52. *.o
  53. *.so
  54. *.swp
  55. *~
  56. ,,*
  57. .[#~]*
  58. .arch-ids
  59. .arch-inventory
  60. .bzr
  61. .bzr.backup
  62. .bzr.tags
  63. .bzrignore
  64. .cvsignore
  65. .deps
  66. .git
  67. .gitignore
  68. .hg
  69. .shelf
  70. .svn
  71. CVS
  72. DEADJOE
  73. RCS
  74. _MTN
  75. _darcs
  76. {arch}
  77. );
  78. my $sourcestyle = 'X';
  79. my $min_dscformat = 1;
  80. my $max_dscformat = 3;
  81. my $def_dscformat = "1.0"; # default format for -b
  82. my $expectprefix;
  83. # Compression
  84. my $compression = 'gzip';
  85. my $comp_level = '9';
  86. my $comp_ext = $comp_ext{$compression};
  87. # Packages
  88. my %remove;
  89. my %override;
  90. # Files
  91. my %md5sum;
  92. my %size;
  93. my %type; # used by checktype
  94. my %filepatched; # used by checkdiff
  95. my %dirtocreate; # used by checkdiff
  96. my @tar_ignore;
  97. my $substvars = Dpkg::Substvars->new();
  98. my $compressor = Dpkg::Source::Compressor->new();
  99. use POSIX;
  100. use Fcntl qw (:mode);
  101. use English;
  102. use File::Temp qw (tempfile);
  103. textdomain("dpkg-dev");
  104. my @dsc_fields = (qw(Format Source Binary Architecture Version Origin
  105. Maintainer Uploaders Dm-Upload-Allowed Homepage
  106. Standards-Version Vcs-Browser Vcs-Arch Vcs-Bzr
  107. Vcs-Cvs Vcs-Darcs Vcs-Git Vcs-Hg Vcs-Mtn Vcs-Svn),
  108. @src_dep_fields);
  109. # Make sure patch doesn't get any funny ideas
  110. delete $ENV{'POSIXLY_CORRECT'};
  111. my @exit_handlers = ();
  112. sub exit_handler {
  113. &$_ foreach ( reverse @exit_handlers );
  114. exit(127);
  115. }
  116. $SIG{'INT'} = \&exit_handler;
  117. $SIG{'HUP'} = \&exit_handler;
  118. $SIG{'QUIT'} = \&exit_handler;
  119. sub version {
  120. printf _g("Debian %s version %s.\n"), $progname, $version;
  121. print _g("
  122. Copyright (C) 1996 Ian Jackson and Klee Dienes.");
  123. print _g("
  124. This is free software; see the GNU General Public Licence version 2 or
  125. later for copying conditions. There is NO warranty.
  126. ");
  127. }
  128. sub usage {
  129. printf _g(
  130. "Usage: %s [<option> ...] <command>
  131. Commands:
  132. -x <filename>.dsc [<output-dir>]
  133. extract source package.
  134. -b <dir> [<orig-dir>|<orig-targz>|\'\']
  135. build source package.
  136. Build options:
  137. -c<controlfile> get control info from this file.
  138. -l<changelogfile> get per-version info from this file.
  139. -F<changelogformat> force change log format.
  140. -V<name>=<value> set a substitution variable.
  141. -T<varlistfile> read variables here, not debian/substvars.
  142. -D<field>=<value> override or add a .dsc field and value.
  143. -U<field> remove a field.
  144. -E turn certain warnings into errors.
  145. -W when -E is enabled, -W disables it.
  146. -q quiet operation, do not print warnings.
  147. -i[<regexp>] filter out files to ignore diffs of
  148. (defaults to: '%s').
  149. -I[<pattern>] filter out files when building tarballs
  150. (defaults to: %s).
  151. -sa auto select orig source (-sA is default).
  152. -sk use packed orig source (unpack & keep).
  153. -sp use packed orig source (unpack & remove).
  154. -su use unpacked orig source (pack & keep).
  155. -sr use unpacked orig source (pack & remove).
  156. -ss trust packed & unpacked orig src are same.
  157. -sn there is no diff, do main tarfile only.
  158. -sA,-sK,-sP,-sU,-sR like -sa,-sk,-sp,-su,-sr but may overwrite.
  159. -Z<compression> select compression to use (defaults to 'gzip',
  160. supported are: %s).
  161. -z<level> compression level to use (defaults to '9',
  162. supported are: '1'-'9', 'best', 'fast')
  163. Extract options:
  164. -sp (default) leave orig source packed in current dir.
  165. -sn do not copy original source to current dir.
  166. -su unpack original source tree too.
  167. General options:
  168. -h, --help show this help message.
  169. --version show the version.
  170. "), $progname,
  171. $diff_ignore_default_regexp,
  172. join('', map { " -I$_" } @tar_ignore_default_pattern),
  173. "@comp_supported" ;
  174. }
  175. sub handleformat {
  176. my $fmt = shift;
  177. return unless $fmt =~ /^(\d+)/; # only check major version
  178. return $1 >= $min_dscformat && $1 <= $max_dscformat;
  179. }
  180. sub loadvcs {
  181. my $vcs = shift;
  182. my $mod = "Dpkg::Source::VCS::$vcs";
  183. eval qq{require $mod};
  184. return if $@;
  185. return import $mod;
  186. }
  187. my $opmode;
  188. my $tar_ignore_default_pattern_done;
  189. while (@ARGV && $ARGV[0] =~ m/^-/) {
  190. $_=shift(@ARGV);
  191. if (m/^-b$/) {
  192. &setopmode('build');
  193. } elsif (m/^-x$/) {
  194. &setopmode('extract');
  195. } elsif (m/^-Z/) {
  196. $compression = $POSTMATCH;
  197. $comp_ext = $comp_ext{$compression};
  198. usageerr(_g("%s is not a supported compression"), $compression)
  199. unless $comp_supported{$compression};
  200. } elsif (m/^-z/) {
  201. $comp_level = $POSTMATCH;
  202. usageerr(_g("%s is not a compression level"), $comp_level)
  203. unless $comp_level =~ /^([1-9]|fast|best)$/;
  204. } elsif (m/^-s([akpursnAKPUR])$/) {
  205. warning(_g("-s%s option overrides earlier -s%s option"), $1, $sourcestyle)
  206. if $sourcestyle ne 'X';
  207. $sourcestyle= $1;
  208. } elsif (m/^-c/) {
  209. $controlfile= $POSTMATCH;
  210. } elsif (m/^-l/) {
  211. $changelogfile= $POSTMATCH;
  212. } elsif (m/^-F([0-9a-z]+)$/) {
  213. $changelogformat=$1;
  214. } elsif (m/^-D([^\=:]+)[=:]/) {
  215. $override{$1}= $POSTMATCH;
  216. } elsif (m/^-U([^\=:]+)$/) {
  217. $remove{$1}= 1;
  218. } elsif (m/^-i(.*)$/) {
  219. $diff_ignore_regexp = $1 ? $1 : $diff_ignore_default_regexp;
  220. } elsif (m/^-I(.+)$/) {
  221. push @tar_ignore, "--exclude=$1";
  222. } elsif (m/^-I$/) {
  223. unless ($tar_ignore_default_pattern_done) {
  224. push @tar_ignore,
  225. map { "--exclude=$_" } @tar_ignore_default_pattern;
  226. # Prevent adding multiple times
  227. $tar_ignore_default_pattern_done = 1;
  228. }
  229. } elsif (m/^-V(\w[-:0-9A-Za-z]*)[=:]/) {
  230. $substvars->set($1, $POSTMATCH);
  231. } elsif (m/^-T/) {
  232. $varlistfile = $POSTMATCH;
  233. warning(_g("substvars support is deprecated (see README.feature-removal-schedule)"));
  234. } elsif (m/^-(h|-help)$/) {
  235. &usage; exit(0);
  236. } elsif (m/^--version$/) {
  237. &version; exit(0);
  238. } elsif (m/^-W$/) {
  239. $warnable_error= 1;
  240. } elsif (m/^-E$/) {
  241. $warnable_error= 0;
  242. } elsif (m/^-q$/) {
  243. $quiet_warnings = 1;
  244. } elsif (m/^--$/) {
  245. last;
  246. } else {
  247. usageerr(_g("unknown option \`%s'"), $_);
  248. }
  249. }
  250. defined($opmode) || &usageerr(_g("need -x or -b"));
  251. $SIG{'PIPE'} = 'DEFAULT';
  252. if ($opmode eq 'build') {
  253. @ARGV || &usageerr(_g("-b needs a directory"));
  254. @ARGV<=2 || &usageerr(_g("-b takes at most a directory and an orig source argument"));
  255. my $dir = shift(@ARGV);
  256. $dir= "./$dir" unless $dir =~ m:^/:; $dir =~ s,/*$,,;
  257. stat($dir) || error(_g("cannot stat directory %s: %s"), $dir, $!);
  258. -d $dir || error(_g("directory argument %s is not a directory"), $dir);
  259. $changelogfile= "$dir/debian/changelog" unless defined($changelogfile);
  260. $controlfile= "$dir/debian/control" unless defined($controlfile);
  261. my %options = (file => $changelogfile);
  262. $options{"changelogformat"} = $changelogformat if $changelogformat;
  263. my $changelog = parse_changelog(%options);
  264. my $control = Dpkg::Control->new($controlfile);
  265. my $fields = Dpkg::Fields::Object->new();
  266. $fields->{"Format"} = $compression eq 'gzip' ? $def_dscformat : '2.0';
  267. my @sourcearch;
  268. my %archadded;
  269. my $archspecific = 0; # XXX: Not used?!
  270. my @binarypackages;
  271. # Scan control info of source package
  272. my $src_fields = $control->get_source();
  273. foreach $_ (keys %{$src_fields}) {
  274. my $v = $src_fields->{$_};
  275. if (m/^Source$/i) {
  276. set_source_package($v);
  277. } elsif (m/^(Format|Standards-Version|Origin|Maintainer|Homepage)$/i ||
  278. m/^Dm-Upload-Allowed$/i ||
  279. m/^Vcs-(Browser|Arch|Bzr|Cvs|Darcs|Git|Hg|Mtn|Svn)$/i) {
  280. $fields->{$_} = $v;
  281. } elsif (m/^Uploaders$/i) {
  282. ($fields->{$_} = $v) =~ s/[\r\n]//g; # Merge in a single-line
  283. } elsif (m/^Build-(Depends|Conflicts)(-Indep)?$/i) {
  284. my $dep;
  285. my $type = $dep_field_type{capit($_)};
  286. $dep = Dpkg::Deps::parse($v, union => $type eq 'union');
  287. error(_g("error occurred while parsing %s"), $_) unless defined $dep;
  288. my $facts = Dpkg::Deps::KnownFacts->new();
  289. $dep->simplify_deps($facts);
  290. $dep->sort();
  291. $fields->{$_} = $dep->dump();
  292. } elsif (s/^X[BC]*S[BC]*-//i) { # Include XS-* fields
  293. $fields->{$_} = $v;
  294. } elsif (m/^$control_src_field_regex$/i || m/^X[BC]+-/i) {
  295. # Silently ignore valid fields
  296. } else {
  297. unknown(_g('general section of control info file'));
  298. }
  299. }
  300. # Scan control info of binary packages
  301. foreach my $pkg ($control->get_packages()) {
  302. my $p = $pkg->{'Package'};
  303. push(@binarypackages,$p);
  304. foreach $_ (keys %{$pkg}) {
  305. my $v = $pkg->{$_};
  306. if (m/^Architecture$/) {
  307. if (debarch_eq($v, 'any')) {
  308. @sourcearch= ('any');
  309. } elsif (debarch_eq($v, 'all')) {
  310. if (!@sourcearch || $sourcearch[0] eq 'all') {
  311. @sourcearch= ('all');
  312. } else {
  313. @sourcearch= ('any');
  314. }
  315. } else {
  316. if (@sourcearch && grep($sourcearch[0] eq $_, 'any', 'all')) {
  317. @sourcearch= ('any');
  318. } else {
  319. for my $a (split(/\s+/, $v)) {
  320. error(_g("`%s' is not a legal architecture string"),
  321. $a)
  322. unless $a =~ /^[\w-]+$/;
  323. error(_g("architecture %s only allowed on its " .
  324. "own (list for package %s is `%s')"),
  325. $a, $p, $a)
  326. if grep($a eq $_, 'any','all');
  327. push(@sourcearch,$a) unless $archadded{$a}++;
  328. }
  329. }
  330. }
  331. $fields->{'Architecture'}= join(' ',@sourcearch);
  332. } elsif (s/^X[BC]*S[BC]*-//i) { # Include XS-* fields
  333. $fields->{$_} = $v;
  334. } elsif (m/^$control_pkg_field_regex$/ ||
  335. m/^X[BC]+-/i) { # Silently ignore valid fields
  336. } else {
  337. unknown(_g("package's section of control info file"));
  338. }
  339. }
  340. }
  341. # Scan fields of dpkg-parsechangelog
  342. foreach $_ (keys %{$changelog}) {
  343. my $v = $changelog->{$_};
  344. if (m/^Source$/) {
  345. set_source_package($v);
  346. } elsif (m/^Version$/) {
  347. check_version($v);
  348. $fields->{$_} = $v;
  349. } elsif (s/^X[BS]*C[BS]*-//i) {
  350. $fields->{$_} = $v;
  351. } elsif (m/^(Maintainer|Changes|Urgency|Distribution|Date|Closes)$/i ||
  352. m/^X[BS]+-/i) {
  353. } else {
  354. unknown(_g("parsed version of changelog"));
  355. }
  356. }
  357. my $vcs;
  358. if ($fields->{Format} =~ /^\s*(\d+\.\d+)\s*$/) {
  359. if ($1 >= 3.0) {
  360. error(_g("don't know how to generate %s format source package (missing vcs specifier in Format field?)"),
  361. $1);
  362. }
  363. if ($1 > 1.0) {
  364. error(_g("don't know how to generate %s format source package"),
  365. $1);
  366. }
  367. }
  368. elsif ($fields->{Format} =~ /^\s*(\d+(?:\.\d+)?)\s+\((\w+)\)\s*$/) {
  369. $fields->{Format} = $1;
  370. if ($1 < 3.0) {
  371. error(_g("control info file 'Format' field for version %s does not support vcs specifier \"%s\""),
  372. $1, $2);
  373. }
  374. if ($1 >= 4) {
  375. error(_g("unsupported control info file 'Format' value \"%s\""),
  376. $1);
  377. }
  378. $vcs = $2;
  379. loadvcs($2)
  380. || error(_g("unsupported vcs \"%s\" in control info file 'Format' field"), $2);
  381. if ($sourcestyle =~ /[akpursKPUR]/) {
  382. warning(_g("source handling style -s%s not supported when generating %s format source package"),
  383. $sourcestyle, $vcs);
  384. }
  385. $sourcestyle = 'v';
  386. }
  387. $sourcestyle =~ y/X/A/;
  388. $sourcestyle =~ m/[akpursnAKPURv]/ ||
  389. usageerr(_g("source handling style -s%s not allowed with -b"),
  390. $sourcestyle);
  391. $fields->{'Binary'}= join(', ', @binarypackages);
  392. foreach my $f (keys %override) {
  393. $fields->{$f} = $override{$f};
  394. }
  395. for my $f (qw(Version)) {
  396. defined($fields->{$f}) ||
  397. error(_g("missing information for critical output field %s"), $f);
  398. }
  399. for my $f (qw(Maintainer Architecture Standards-Version)) {
  400. defined($fields->{$f}) ||
  401. warning(_g("missing information for output field %s"), $f);
  402. }
  403. defined($sourcepackage) || &error(_g("unable to determine source package name !"));
  404. $fields->{'Source'} = $sourcepackage;
  405. for my $f (keys %remove) {
  406. delete $fields->{$f};
  407. }
  408. my $version = $fields->{'Version'};
  409. $version =~ s/^\d+://;
  410. my $upstreamversion = $version;
  411. $upstreamversion =~ s/-[^-]*$//;
  412. my $basenamerev = $sourcepackage.'_'.$version;
  413. my $basename = $sourcepackage.'_'.$upstreamversion;
  414. my $basedirname = $basename;
  415. $basedirname =~ s/_/-/;
  416. my $origdir = "$dir.orig";
  417. my $origtargz;
  418. # Try to find a .orig tarball for the package
  419. my @origtargz = map { "$basename.orig.tar.$comp_ext{$_}" } ($compression, @comp_supported);
  420. foreach my $origtar (@origtargz) {
  421. if (stat($origtar)) {
  422. -f _ || error(_g("packed orig `%s' exists but is not a plain file"),
  423. $origtar);
  424. $origtargz = $origtar;
  425. last;
  426. } elsif ($! != ENOENT) {
  427. syserr(_g("unable to stat putative packed orig `%s'"), $origtar);
  428. }
  429. }
  430. if (@ARGV) {
  431. # We have a second-argument <orig-dir> or <orig-targz>, check what it
  432. # is to decide the mode to use
  433. my $origarg = shift(@ARGV);
  434. if (length($origarg)) {
  435. stat($origarg) ||
  436. error(_g("cannot stat orig argument %s: %s"), $origarg, $!);
  437. if (-d _) {
  438. $origdir= $origarg;
  439. $origdir= "./$origdir" unless $origdir =~ m,^/,; $origdir =~ s,/*$,,;
  440. $sourcestyle =~ y/aA/rR/;
  441. $sourcestyle =~ m/[ursURS]/ ||
  442. error(_g("orig argument is unpacked but source handling " .
  443. "style -s%s calls for packed (.orig.tar.<ext>)"),
  444. $sourcestyle);
  445. } elsif (-f _) {
  446. $origtargz= $origarg;
  447. $sourcestyle =~ y/aA/pP/;
  448. $sourcestyle =~ m/[kpsKPS]/ ||
  449. error(_g("orig argument is packed but source handling " .
  450. "style -s%s calls for unpacked (.orig/)"),
  451. $sourcestyle);
  452. } else {
  453. &error("orig argument $origarg is not a plain file or directory");
  454. }
  455. } else {
  456. $sourcestyle =~ y/aA/nn/;
  457. $sourcestyle =~ m/n/ ||
  458. error(_g("orig argument is empty (means no orig, no diff) " .
  459. "but source handling style -s%s wants something"),
  460. $sourcestyle);
  461. }
  462. } elsif ($sourcestyle =~ m/[aA]/) {
  463. # We have no explicit <orig-dir> or <orig-targz>, try to use
  464. # a .orig tarball first, then a .orig directory and fall back to
  465. # creating a native .tar.gz
  466. if ($origtargz) {
  467. $sourcestyle =~ y/aA/pP/; # .orig.tar.<ext>
  468. } else {
  469. if (stat($origdir)) {
  470. -d _ || error(_g("unpacked orig `%s' exists but is not a directory"),
  471. $origdir);
  472. $sourcestyle =~ y/aA/rR/; # .orig directory
  473. } elsif ($! != ENOENT) {
  474. syserr(_g("unable to stat putative unpacked orig `%s'"), $origdir);
  475. } else {
  476. $sourcestyle =~ y/aA/nn/; # Native tar.gz
  477. }
  478. }
  479. }
  480. my $dirbase = $dir;
  481. $dirbase =~ s,/?$,,;
  482. $dirbase =~ s,[^/]+$,,;
  483. my $dirname = $&;
  484. $dirname eq $basedirname ||
  485. warning(_g("source directory '%s' is not <sourcepackage>" .
  486. "-<upstreamversion> '%s'"), $dir, $basedirname);
  487. my $tarname;
  488. my $tardirname;
  489. my $tardirbase;
  490. my $origdirname;
  491. if ($sourcestyle eq 'v') {
  492. $tarname="$basenamerev.$vcs.tar.gz";
  493. $tardirbase= $dirbase; $tardirname= "$dirbase/$tarname.tmp";
  494. eval qq{Dpkg::Source::VCS::${vcs}::prep_tar(\$dir, \$tardirname)};
  495. if ($@) {
  496. failure($@);
  497. }
  498. push @exit_handlers, sub { erasedir($tardirname) };
  499. }
  500. elsif ($sourcestyle ne 'n') {
  501. my $origdirbase = $origdir;
  502. $origdirbase =~ s,/?$,,;
  503. $origdirbase =~ s,[^/]+$,,; $origdirname= $&;
  504. $origdirname eq "$basedirname.orig" ||
  505. warning(_g(".orig directory name %s is not <package>" .
  506. "-<upstreamversion> (wanted %s)"),
  507. $origdirname, "$basedirname.orig");
  508. $tardirbase= $origdirbase; $tardirname= $origdirname;
  509. $tarname= $origtargz || "$basename.orig.tar.$comp_ext";
  510. if ($tarname =~ /\Q$basename\E\.orig\.tar\.($comp_regex)/) {
  511. if (($1 ne 'gz') && ($fields->{'Format'} < 2)) { $fields->{'Format'} = '2.0' };
  512. } else {
  513. warning(_g(".orig.tar name %s is not <package>_<upstreamversion>" .
  514. ".orig.tar (wanted %s)"),
  515. $tarname, "$basename.orig.tar.$comp_regex");
  516. }
  517. } else {
  518. $tardirbase= $dirbase; $tardirname= $dirname;
  519. $tarname= "$basenamerev.tar.$comp_ext";
  520. }
  521. if ($sourcestyle =~ m/[nurURv]/) {
  522. if (stat($tarname)) {
  523. $sourcestyle =~ m/[nURv]/ ||
  524. error(_g("tarfile `%s' already exists, not overwriting, " .
  525. "giving up; use -sU or -sR to override"), $tarname);
  526. } elsif ($! != ENOENT) {
  527. syserr(_g("unable to check for existence of `%s'"), $tarname);
  528. }
  529. printf(_g("%s: building %s in %s")."\n",
  530. $progname, $sourcepackage, $tarname)
  531. || &syserr(_g("write building tar message"));
  532. my ($ntfh, $newtar) = tempfile( "$tarname.new.XXXXXX",
  533. DIR => &getcwd, UNLINK => 0 );
  534. &forkgzipwrite($newtar);
  535. defined(my $c2 = fork) || syserr(_g("fork for tar"));
  536. if (!$c2) {
  537. chdir($tardirbase) ||
  538. syserr(_g("chdir to above (orig) source %s"), $tardirbase);
  539. open(STDOUT,">&GZIP") || &syserr(_g("reopen gzip for tar"));
  540. # FIXME: put `--' argument back when tar is fixed
  541. exec('tar',@tar_ignore,'-cf','-',$tardirname) or &syserr(_g("exec tar"));
  542. }
  543. close(GZIP);
  544. &reapgzip;
  545. $c2 == waitpid($c2,0) || &syserr(_g("wait for tar"));
  546. $? && !(WIFSIGNALED($c2) && WTERMSIG($c2) == SIGPIPE) && subprocerr("tar");
  547. rename($newtar,$tarname) ||
  548. syserr(_g("unable to rename `%s' (newly created) to `%s'"),
  549. $newtar, $tarname);
  550. chmod(0666 &~ umask(), $tarname) ||
  551. syserr(_g("unable to change permission of `%s'"), $tarname);
  552. } else {
  553. printf(_g("%s: building %s using existing %s")."\n",
  554. $progname, $sourcepackage, $tarname)
  555. || &syserr(_g("write using existing tar message"));
  556. }
  557. addfile($fields, "$tarname");
  558. if ($sourcestyle =~ m/[kpKP]/) {
  559. if (stat($origdir)) {
  560. $sourcestyle =~ m/[KP]/ ||
  561. error(_g("orig dir `%s' already exists, not overwriting, ".
  562. "giving up; use -sA, -sK or -sP to override"),
  563. $origdir);
  564. push @exit_handlers, sub { erasedir($origdir) };
  565. erasedir($origdir);
  566. pop @exit_handlers;
  567. } elsif ($! != ENOENT) {
  568. syserr(_g("unable to check for existence of orig dir `%s'"),
  569. $origdir);
  570. }
  571. $expectprefix= $origdir; $expectprefix =~ s,^\./,,;
  572. my $expectprefix_dirname = $origdirname;
  573. mkdir("$origtargz.tmp-nest",0755) ||
  574. syserr(_g("unable to create `%s'"), "$origtargz.tmp-nest");
  575. push @exit_handlers, sub { erasedir("$origtargz.tmp-nest") };
  576. extracttar($origtargz,"$origtargz.tmp-nest",$expectprefix_dirname);
  577. rename("$origtargz.tmp-nest/$expectprefix_dirname",$expectprefix) ||
  578. syserr(_g("unable to rename `%s' to `%s'"),
  579. "$origtargz.tmp-nest/$expectprefix_dirname",
  580. $expectprefix);
  581. rmdir("$origtargz.tmp-nest") ||
  582. syserr(_g("unable to remove `%s'"), "$origtargz.tmp-nest");
  583. pop @exit_handlers;
  584. }
  585. if ($sourcestyle eq 'v') {
  586. erasedir($tardirname)
  587. }
  588. if ($sourcestyle =~ m/[kpursKPUR]/) {
  589. my $diffname = "$basenamerev.diff.$comp_ext";
  590. printf(_g("%s: building %s in %s")."\n",
  591. $progname, $sourcepackage, $diffname)
  592. || &syserr(_g("write building diff message"));
  593. my ($ndfh, $newdiffgz) = tempfile( "$diffname.new.XXXXXX",
  594. DIR => &getcwd, UNLINK => 0 );
  595. &forkgzipwrite($newdiffgz);
  596. defined(my $c2 = open(FIND, "-|")) || syserr(_g("fork for find"));
  597. if (!$c2) {
  598. chdir($dir) || syserr(_g("chdir to %s for find"), $dir);
  599. exec('find','.','-print0') or &syserr(_g("exec find"));
  600. }
  601. $/= "\0";
  602. file:
  603. while (defined($fn= <FIND>)) {
  604. $fn =~ s/\0$//;
  605. next file if $fn =~ m/$diff_ignore_regexp/o;
  606. $fn =~ s,^\./,,;
  607. lstat("$dir/$fn") || syserr(_g("cannot stat file %s"), "$dir/$fn");
  608. my $mode = S_IMODE((lstat(_))[2]);
  609. my $size = (lstat(_))[7];
  610. if (-l _) {
  611. $type{$fn}= 'symlink';
  612. checktype($origdir, $fn, '-l') || next;
  613. defined(my $n = readlink("$dir/$fn")) ||
  614. syserr(_g("cannot read link %s"), "$dir/$fn");
  615. defined(my $n2 = readlink("$origdir/$fn")) ||
  616. syserr(_g("cannot read orig link %s"), "$origdir/$fn");
  617. $n eq $n2 || &unrepdiff2(sprintf(_g("symlink to %s"), $n2),
  618. sprintf(_g("symlink to %s"), $n));
  619. } elsif (-f _) {
  620. my $ofnread;
  621. $type{$fn}= 'plain file';
  622. if (!lstat("$origdir/$fn")) {
  623. $! == ENOENT ||
  624. syserr(_g("cannot stat orig file %s"), "$origdir/$fn");
  625. $ofnread= '/dev/null';
  626. if( !$size ) {
  627. warning(_g("newly created empty file '%s' will not " .
  628. "be represented in diff"), $fn);
  629. } else {
  630. if( $mode & ( S_IXUSR | S_IXGRP | S_IXOTH ) ) {
  631. warning(_g("executable mode %04o of '%s' will " .
  632. "not be represented in diff"), $mode, $fn)
  633. unless $fn eq 'debian/rules';
  634. }
  635. if( $mode & ( S_ISUID | S_ISGID | S_ISVTX ) ) {
  636. warning(_g("special mode %04o of '%s' will not " .
  637. "be represented in diff"), $mode, $fn);
  638. }
  639. }
  640. } elsif (-f _) {
  641. $ofnread= "$origdir/$fn";
  642. } else {
  643. &unrepdiff2(_g("something else"),
  644. _g("plain file"));
  645. next;
  646. }
  647. defined(my $c3 = open(DIFFGEN, "-|")) || syserr(_g("fork for diff"));
  648. if (!$c3) {
  649. $ENV{'LC_ALL'}= 'C';
  650. $ENV{'LANG'}= 'C';
  651. $ENV{'TZ'}= 'UTC0';
  652. my $tab = ("$basedirname/$fn" =~ / /) ? "\t" : '';
  653. exec('diff','-u',
  654. '-L',"$basedirname.orig/$fn$tab",
  655. '-L',"$basedirname/$fn$tab",
  656. '--',"$ofnread","$dir/$fn") or &syserr(_g("exec diff"));
  657. }
  658. my $difflinefound = 0;
  659. $/= "\n";
  660. while (<DIFFGEN>) {
  661. if (m/^binary/i) {
  662. close(DIFFGEN); $/= "\0";
  663. &unrepdiff(_g("binary file contents changed"));
  664. next file;
  665. } elsif (m/^[-+\@ ]/) {
  666. $difflinefound=1;
  667. } elsif (m/^\\ No newline at end of file$/) {
  668. warning(_g("file %s has no final newline (either " .
  669. "original or modified version)"), $fn);
  670. } else {
  671. s/\n$//;
  672. internerr(_g("unknown line from diff -u on %s: `%s'"),
  673. $fn, $_);
  674. }
  675. print(GZIP $_) || &syserr(_g("failed to write to compression pipe"));
  676. }
  677. close(DIFFGEN); $/= "\0";
  678. my $es;
  679. if (WIFEXITED($?) && (($es=WEXITSTATUS($?))==0 || $es==1)) {
  680. if ($es==1 && !$difflinefound) {
  681. &unrepdiff(_g("diff gave 1 but no diff lines found"));
  682. }
  683. } else {
  684. subprocerr(_g("diff on %s"), "$dir/$fn");
  685. }
  686. } elsif (-p _) {
  687. $type{$fn}= 'pipe';
  688. checktype($origdir, $fn, '-p');
  689. } elsif (-b _ || -c _ || -S _) {
  690. &unrepdiff(_g("device or socket is not allowed"));
  691. } elsif (-d _) {
  692. $type{$fn}= 'directory';
  693. if (!lstat("$origdir/$fn")) {
  694. $! == ENOENT ||
  695. syserr(_g("cannot stat orig file %s"), "$origdir/$fn");
  696. } elsif (! -d _) {
  697. &unrepdiff2(_g('not a directory'),
  698. _g('directory'));
  699. }
  700. } else {
  701. &unrepdiff(sprintf(_g("unknown file type (%s)"), $!));
  702. }
  703. }
  704. close(FIND); $? && subprocerr("find on $dir");
  705. close(GZIP) || &syserr(_g("finish write to compression pipe"));
  706. &reapgzip;
  707. rename($newdiffgz, $diffname) ||
  708. syserr(_g("unable to rename `%s' (newly created) to `%s'"),
  709. $newdiffgz, $diffname);
  710. chmod(0666 &~ umask(), $diffname) ||
  711. syserr(_g("unable to change permission of `%s'"), $diffname);
  712. defined($c2= open(FIND,"-|")) || &syserr(_g("fork for 2nd find"));
  713. if (!$c2) {
  714. chdir($origdir) || syserr(_g("chdir to %s for 2nd find"), $origdir);
  715. exec('find','.','-print0') or &syserr(_g("exec 2nd find"));
  716. }
  717. $/= "\0";
  718. while (defined($fn= <FIND>)) {
  719. $fn =~ s/\0$//;
  720. next if $fn =~ m/$diff_ignore_regexp/o;
  721. $fn =~ s,^\./,,;
  722. next if defined($type{$fn});
  723. lstat("$origdir/$fn") ||
  724. syserr(_g("cannot check orig file %s"), "$origdir/$fn");
  725. if (-f _) {
  726. warning(_g("ignoring deletion of file %s"), $fn);
  727. } elsif (-d _) {
  728. warning(_g("ignoring deletion of directory %s"), $fn);
  729. } elsif (-l _) {
  730. warning(_g("ignoring deletion of symlink %s"), $fn);
  731. } else {
  732. &unrepdiff2(_g('not a file, directory or link'),
  733. _g('nonexistent'));
  734. }
  735. }
  736. close(FIND); $? && subprocerr("find on $dirname");
  737. addfile($fields, $diffname);
  738. }
  739. if ($sourcestyle =~ m/[prPR]/) {
  740. erasedir($origdir);
  741. }
  742. printf(_g("%s: building %s in %s")."\n",
  743. $progname, $sourcepackage, "$basenamerev.dsc")
  744. || &syserr(_g("write building message"));
  745. open(DSC, ">", "$basenamerev.dsc") ||
  746. syserr(_g("create %s"), "$basenamerev.dsc");
  747. $substvars->parse($varlistfile) if $varlistfile && -e $varlistfile;
  748. tied(%{$fields})->set_field_importance(@dsc_fields);
  749. tied(%{$fields})->output(\*DSC, $substvars);
  750. close(DSC);
  751. if ($ur) {
  752. printf(STDERR _g("%s: unrepresentable changes to source")."\n",
  753. $progname) || syserr(_g("write error msg: %s"), $!);
  754. exit(1);
  755. }
  756. exit(0);
  757. } else { # -> opmode ne 'build'
  758. $sourcestyle =~ y/X/p/;
  759. $sourcestyle =~ m/[pun]/ ||
  760. usageerr(_g("source handling style -s%s not allowed with -x"),
  761. $sourcestyle);
  762. @ARGV>=1 || &usageerr(_g("-x needs at least one argument, the .dsc"));
  763. @ARGV<=2 || &usageerr(_g("-x takes no more than two arguments"));
  764. my $dsc = shift(@ARGV);
  765. $dsc= "./$dsc" unless $dsc =~ m:^/:;
  766. ! -d $dsc
  767. || &usageerr(_g("-x needs the .dsc file as first argument, not a directory"));
  768. my $dscdir = $dsc;
  769. $dscdir = "./$dscdir" unless $dsc =~ m,^/|^\./,;
  770. $dscdir =~ s,/[^/]+$,,;
  771. my $newdirectory;
  772. if (@ARGV) {
  773. $newdirectory= shift(@ARGV);
  774. ! -e $newdirectory || error(_g("unpack target exists: %s"), $newdirectory);
  775. }
  776. my $is_signed = 0;
  777. open(DSC, "<", $dsc) || error(_g("cannot open .dsc file %s: %s"), $dsc, $!);
  778. while (<DSC>) {
  779. next if /^\s*$/o;
  780. $is_signed = 1 if /^-----BEGIN PGP SIGNED MESSAGE-----$/o;
  781. last;
  782. }
  783. close(DSC);
  784. if ($is_signed) {
  785. if (-x '/usr/bin/gpg') {
  786. my $gpg_command = 'gpg -q --verify ';
  787. if (-r '/usr/share/keyrings/debian-keyring.gpg') {
  788. $gpg_command = $gpg_command.'--keyring /usr/share/keyrings/debian-keyring.gpg ';
  789. }
  790. $gpg_command = $gpg_command.quotemeta($dsc).' 2>&1';
  791. my @gpg_output = `$gpg_command`;
  792. my $gpg_status = $? >> 8;
  793. if ($gpg_status) {
  794. print STDERR join("",@gpg_output);
  795. error(_g("failed to verify signature on %s"), $dsc)
  796. if ($gpg_status == 1);
  797. }
  798. } else {
  799. warning(_g("could not verify signature on %s since gpg isn't installed"),
  800. $dsc);
  801. }
  802. } else {
  803. warning(_g("extracting unsigned source package (%s)"), $dsc);
  804. }
  805. open(CDATA, "<", $dsc) || error(_g("cannot open .dsc file %s: %s"), $dsc, $!);
  806. my $fields = parsecdata(\*CDATA, sprintf(_g("source control file %s"), $dsc),
  807. allow_pgp => 1);
  808. close(CDATA);
  809. for my $f (qw(Source Version Files)) {
  810. defined($fields->{$f}) ||
  811. error(_g("missing critical source control field %s"), $f);
  812. }
  813. my $dscformat = $def_dscformat;
  814. if (defined $fields->{'Format'}) {
  815. if (not handleformat($fields->{'Format'})) {
  816. error(_g("Unsupported format of .dsc file (%s)"), $fields->{'Format'});
  817. }
  818. $dscformat=$fields->{'Format'};
  819. }
  820. set_source_package($fields->{'Source'});
  821. my $version = $fields->{'Version'};
  822. my $baseversion;
  823. my $revision;
  824. check_version($version);
  825. $version =~ s/^\d+://;
  826. if ($version =~ m/-([^-]+)$/) {
  827. $baseversion= $`; $revision= $1;
  828. } else {
  829. $baseversion= $version; $revision= '';
  830. }
  831. my $files = $fields->{'Files'};
  832. my @tarfiles;
  833. my $difffile;
  834. my $debianfile;
  835. my %vcsfiles;
  836. my %seen;
  837. for my $file (split(/\n /, $files)) {
  838. next if $file eq '';
  839. $file =~ m/^([0-9a-f]{32})[ \t]+(\d+)[ \t]+([0-9a-zA-Z][-+:.,=0-9a-zA-Z_~]+)$/
  840. || error(_g("Files field contains bad line `%s'"), $file);
  841. ($md5sum{$3},$size{$3},$file) = ($1,$2,$3);
  842. local $_ = $file;
  843. error(_g("Files field contains invalid filename `%s'"), $file)
  844. unless s/^\Q$sourcepackage\E_\Q$baseversion\E(?=[.-])// and
  845. s/\.$comp_regex$//;
  846. s/^-\Q$revision\E(?=\.)// if length $revision;
  847. error(_g("repeated file type - files `%s' and `%s'"), $seen{$_}, $file)
  848. if $seen{$_};
  849. $seen{$_} = $file;
  850. checkstats($dscdir, $file);
  851. if (/^\.(?:orig(-\w+)?\.)?tar$/) {
  852. if ($1) { push @tarfiles, $file; } # push orig-foo.tar.gz to the end
  853. else { unshift @tarfiles, $file; }
  854. } elsif (/^\.debian\.tar$/) {
  855. $debianfile = $file;
  856. } elsif (/^\.(\w+)\.tar$/) {
  857. my $vcs=$1;
  858. # TODO try to load vcs module
  859. push @tarfiles, $file;
  860. $vcsfiles{$file}=$vcs;
  861. } elsif (/^\.diff$/) {
  862. $difffile = $file;
  863. } else {
  864. error(_g("unrecognised file type - `%s'"), $file);
  865. }
  866. }
  867. &error(_g("no tarfile in Files field")) unless @tarfiles;
  868. my $native = !($difffile || $debianfile);
  869. if ($native) {
  870. warning(_g("multiple tarfiles in native package")) if @tarfiles > 1;
  871. warning(_g("native package with .orig.tar"))
  872. unless $seen{'.tar'} or $seen{"-$revision.tar"} or %vcsfiles;
  873. } else {
  874. warning(_g("no upstream tarfile in Files field"))
  875. unless $seen{'.orig.tar'} or %vcsfiles;
  876. if ($dscformat =~ /^1\./) {
  877. warning(_g("multiple upstream tarballs in %s format dsc"), $dscformat)
  878. if @tarfiles > 1;
  879. warning(_g("debian.tar in %s format dsc"), $dscformat)
  880. if $debianfile;
  881. }
  882. }
  883. if (%vcsfiles && $dscformat !~ /^3\./) {
  884. warning(sprintf(_g("<rc>.tar file in %s format dsc"), $dscformat));
  885. }
  886. $newdirectory = $sourcepackage.'-'.$baseversion unless defined($newdirectory);
  887. $expectprefix = $newdirectory;
  888. $expectprefix .= '.orig' if $difffile || $debianfile;
  889. checkdiff("$dscdir/$difffile") if $difffile;
  890. printf(_g("%s: extracting %s in %s")."\n",
  891. $progname, $sourcepackage, $newdirectory)
  892. || &syserr(_g("write extracting message"));
  893. &erasedir($newdirectory);
  894. ! -e "$expectprefix"
  895. || rename("$expectprefix","$newdirectory.tmp-keep")
  896. || syserr(_g("unable to rename `%s' to `%s'"), $expectprefix, "$newdirectory.tmp-keep");
  897. push @tarfiles, $debianfile if $debianfile;
  898. for my $tarfile (@tarfiles)
  899. {
  900. my $target;
  901. if ($tarfile =~ /\.orig-(\w+)\.tar/) {
  902. my $sub = $1;
  903. $sub =~ s/\d+$// if $sub =~ /\D/;
  904. $target = "$expectprefix/$sub";
  905. } elsif ($tarfile =~ /\.debian\.tar/) {
  906. $target = "$expectprefix/debian";
  907. } else {
  908. $target = $expectprefix;
  909. }
  910. my $tmp = "$target.tmp-nest";
  911. (my $t = $target) =~ s!.*/!!;
  912. mkdir($tmp, 0700) || syserr(_g("unable to create `%s'"), $tmp);
  913. printf(_g("%s: unpacking %s")."\n", $progname, $tarfile);
  914. extracttar("$dscdir/$tarfile",$tmp,$t);
  915. rename("$tmp/$t",$target)
  916. || syserr(_g("unable to rename `%s' to `%s'"), "$tmp/$t", $target);
  917. rmdir($tmp)
  918. || syserr(_g("unable to remove `%s'"), $tmp);
  919. # for the first tar file:
  920. if ($tarfile eq $tarfiles[0] and !$native)
  921. {
  922. # -sp: copy the .orig.tar.gz if required
  923. if ($sourcestyle =~ /p/) {
  924. stat("$dscdir/$tarfile") ||
  925. syserr(_g("failed to stat `%s' to see if need to copy"),
  926. "$dscdir/$tarfile");
  927. my ($dsctardev, $dsctarino) = stat _;
  928. my $copy_required;
  929. if (stat($tarfile)) {
  930. my ($dumptardev, $dumptarino) = stat _;
  931. $copy_required = ($dumptardev != $dsctardev ||
  932. $dumptarino != $dsctarino);
  933. } else {
  934. $! == ENOENT ||
  935. syserr(_g("failed to check destination `%s' " .
  936. "to see if need to copy"), $tarfile);
  937. $copy_required = 1;
  938. }
  939. if ($copy_required) {
  940. system('cp','--',"$dscdir/$tarfile", $tarfile);
  941. $? && subprocerr("cp $dscdir/$tarfile to $tarfile");
  942. }
  943. }
  944. # -su: keep .orig directory unpacked
  945. elsif ($sourcestyle =~ /u/ and $expectprefix ne $newdirectory) {
  946. ! -e "$newdirectory.tmp-keep"
  947. || &error(_g("unable to keep orig directory (already exists)"));
  948. system('cp','-ar','--',$expectprefix,"$newdirectory.tmp-keep");
  949. $? && subprocerr("cp $expectprefix to $newdirectory.tmp-keep");
  950. }
  951. }
  952. if (exists $vcsfiles{$tarfile}) {
  953. printf(_g("%s: extracting source from %s repository")."\n", $progname, $vcsfiles{$tarfile});
  954. loadvcs($vcsfiles{$tarfile})
  955. || error(sprintf(_g("unsupported vcs \"%s\""), $vcsfiles{$tarfile}));
  956. eval qq{Dpkg::Source::VCS::$vcsfiles{$tarfile}::post_unpack_tar(\$target)};
  957. if ($@) {
  958. &syserr($@);
  959. }
  960. }
  961. }
  962. my @patches;
  963. push @patches, "$dscdir/$difffile" if $difffile;
  964. if ($debianfile and -d (my $pd = "$expectprefix/debian/patches"))
  965. {
  966. my @p;
  967. opendir D, $pd;
  968. while (defined ($_ = readdir D))
  969. {
  970. # patches match same rules as run-parts
  971. next unless /^[\w-]+$/ and -f "$pd/$_";
  972. my $p = $_;
  973. checkdiff("$pd/$p");
  974. push @p, $p;
  975. }
  976. closedir D;
  977. push @patches, map "$newdirectory/debian/patches/$_", sort @p;
  978. }
  979. for my $dircreate (keys %dirtocreate) {
  980. my $dircreatem = "";
  981. for my $dircreatep (split("/", $dircreate)) {
  982. $dircreatem .= $dircreatep . "/";
  983. if (!lstat($dircreatem)) {
  984. $! == ENOENT || syserr(_g("cannot stat %s"), $dircreatem);
  985. mkdir($dircreatem,0777)
  986. || syserr(_g("failed to create %s subdirectory"), $dircreatem);
  987. }
  988. else {
  989. -d _ || error(_g("diff patches file in directory `%s', " .
  990. "but %s isn't a directory !"),
  991. $dircreate, $dircreatem);
  992. }
  993. }
  994. }
  995. if ($newdirectory ne $expectprefix)
  996. {
  997. rename($expectprefix,$newdirectory) ||
  998. syserr(_g("failed to rename newly-extracted %s to %s"),
  999. $expectprefix, $newdirectory);
  1000. # rename the copied .orig directory
  1001. ! -e "$newdirectory.tmp-keep"
  1002. || rename("$newdirectory.tmp-keep",$expectprefix)
  1003. || syserr(_g("failed to rename saved %s to %s"),
  1004. "$newdirectory.tmp-keep", $expectprefix);
  1005. }
  1006. for my $patch (@patches) {
  1007. printf(_g("%s: applying %s")."\n", $progname, $patch);
  1008. if ($patch =~ /\.$comp_regex$/) {
  1009. &forkgzipread($patch);
  1010. *DIFF = *GZIP;
  1011. } else {
  1012. open DIFF, $patch or error(_g("can't open diff `%s'"), $patch);
  1013. }
  1014. defined(my $c2 = fork) || syserr(_g("fork for patch"));
  1015. if (!$c2) {
  1016. open(STDIN,"<&DIFF") || &syserr(_g("reopen gzip for patch"));
  1017. chdir($newdirectory) || syserr(_g("chdir to %s for patch"), $newdirectory);
  1018. $ENV{'LC_ALL'}= 'C';
  1019. $ENV{'LANG'}= 'C';
  1020. exec('patch','-s','-t','-F','0','-N','-p1','-u',
  1021. '-V','never','-g0','-b','-z','.dpkg-orig') or &syserr(_g("exec patch"));
  1022. }
  1023. close(DIFF);
  1024. $c2 == waitpid($c2,0) || &syserr(_g("wait for patch"));
  1025. $? && subprocerr("patch");
  1026. &reapgzip if $patch =~ /\.$comp_regex$/;
  1027. }
  1028. my $now = time;
  1029. for $fn (keys %filepatched) {
  1030. my $ftr = "$newdirectory/" . substr($fn, length($expectprefix) + 1);
  1031. utime($now, $now, $ftr) ||
  1032. syserr(_g("cannot change timestamp for %s"), $ftr);
  1033. $ftr.= ".dpkg-orig";
  1034. unlink($ftr) || syserr(_g("remove patch backup file %s"), $ftr);
  1035. }
  1036. if (!(my @s = lstat("$newdirectory/debian/rules"))) {
  1037. $! == ENOENT || syserr(_g("cannot stat %s"), "$newdirectory/debian/rules");
  1038. warning(_g("%s does not exist"), "$newdirectory/debian/rules");
  1039. } elsif (-f _) {
  1040. chmod($s[2] | 0111, "$newdirectory/debian/rules") ||
  1041. syserr(_g("cannot make %s executable"), "$newdirectory/debian/rules");
  1042. } else {
  1043. warning(_g("%s is not a plain file"), "$newdirectory/debian/rules");
  1044. }
  1045. my $execmode = 0777 & ~umask;
  1046. (my @s = stat('.')) || syserr(_g("cannot stat `.'"));
  1047. my $dirmode = $execmode | ($s[2] & 02000);
  1048. my $plainmode = $execmode & ~0111;
  1049. my $fifomode = ($plainmode & 0222) | (($plainmode & 0222) << 1);
  1050. for $fn (@filesinarchive) {
  1051. $fn=~ s,^$expectprefix,$newdirectory,;
  1052. (my @s = lstat($fn)) ||
  1053. syserr(_g("cannot stat extracted object `%s'"), $fn);
  1054. my $mode = $s[2];
  1055. my $newmode;
  1056. if (-d _) {
  1057. $newmode= $dirmode;
  1058. } elsif (-f _) {
  1059. $newmode= ($mode & 0111) ? $execmode : $plainmode;
  1060. } elsif (-p _) {
  1061. $newmode= $fifomode;
  1062. } elsif (!-l _) {
  1063. internerr(_g("unknown object `%s' after extract (mode 0%o)"),
  1064. $fn, $mode);
  1065. } else { next; }
  1066. next if ($mode & 07777) == $newmode;
  1067. chmod($newmode,$fn) ||
  1068. syserr(_g("cannot change mode of `%s' to 0%o from 0%o"),
  1069. $fn, $newmode, $mode);
  1070. }
  1071. exit(0);
  1072. }
  1073. sub checkstats {
  1074. my $dscdir = shift;
  1075. my ($f) = @_;
  1076. my @s;
  1077. my $m;
  1078. open(STDIN, "<", "$dscdir/$f") || syserr(_g("cannot read %s"), "$dscdir/$f");
  1079. (@s = stat(STDIN)) || syserr(_g("cannot fstat %s"), "$dscdir/$f");
  1080. $s[7] == $size{$f} || error(_g("file %s has size %s instead of expected %s"),
  1081. $f, $s[7], $size{$f});
  1082. $m= `md5sum`; $? && subprocerr("md5sum $f"); $m =~ s/\n$//;
  1083. $m = readmd5sum( $m );
  1084. $m eq $md5sum{$f} || error(_g("file %s has md5sum %s instead of expected %s"),
  1085. $f, $m, $md5sum{$f});
  1086. open(STDIN, "<", "/dev/null") || &syserr(_g("reopen stdin from /dev/null"));
  1087. }
  1088. sub erasedir {
  1089. my ($dir) = @_;
  1090. if (!lstat($dir)) {
  1091. $! == ENOENT && return;
  1092. syserr(_g("cannot stat directory %s (before removal)"), $dir);
  1093. }
  1094. system 'rm','-rf','--',$dir;
  1095. $? && subprocerr("rm -rf $dir");
  1096. if (!stat($dir)) {
  1097. $! == ENOENT && return;
  1098. syserr(_g("unable to check for removal of dir `%s'"), $dir);
  1099. }
  1100. failure(_g("rm -rf failed to remove `%s'"), $dir);
  1101. }
  1102. # check diff for sanity, find directories to create as a side effect
  1103. sub checkdiff
  1104. {
  1105. my $diff = shift;
  1106. if ($diff =~ /\.$comp_regex$/) {
  1107. &forkgzipread($diff);
  1108. *DIFF = *GZIP;
  1109. } else {
  1110. open DIFF, $diff or error(_g("can't open diff `%s'"), $diff);
  1111. }
  1112. $/="\n";
  1113. $_ = <DIFF>;
  1114. HUNK:
  1115. while (defined($_) || !eof(DIFF)) {
  1116. # skip cruft leading up to patch (if any)
  1117. until (/^--- /) {
  1118. last HUNK unless defined ($_ = <DIFF>);
  1119. }
  1120. # read file header (---/+++ pair)
  1121. s/\n$// or error(_g("diff `%s' is missing trailing newline"), $diff);
  1122. s/^--- // or
  1123. error(_g("expected ^--- in line %d of diff `%s'"), $., $diff);
  1124. s/\t.*//;
  1125. $_ eq '/dev/null' or s!^(\./)?[^/]+/!$expectprefix/! or
  1126. error(_g("diff `%s' patches file with no subdirectory"), $diff);
  1127. /\.dpkg-orig$/ and
  1128. error(_g("diff `%s' patches file with name ending .dpkg-orig"),
  1129. $diff);
  1130. $fn = $_;
  1131. (defined($_= <DIFF>) and s/\n$//) or
  1132. error(_g("diff `%s' finishes in middle of ---/+++ (line %d)"),
  1133. $diff, $.);
  1134. s/\t.*//;
  1135. (s/^\+\+\+ // and s!^(\./)?[^/]+/!!) or
  1136. error(_g("line after --- isn't as expected in diff `%s' (line %d)"),
  1137. $diff, $.);
  1138. if ($fn eq '/dev/null') {
  1139. $fn = "$expectprefix/$_";
  1140. } else {
  1141. $_ eq substr($fn, length($expectprefix) + 1) or
  1142. error(_g("line after --- isn't as expected in diff `%s' (line %d)"),
  1143. $diff, $.);
  1144. }
  1145. my $dirname = $fn;
  1146. if ($dirname =~ s,/[^/]+$,, && !defined($dirincluded{$dirname})) {
  1147. $dirtocreate{$dirname} = 1;
  1148. }
  1149. defined($notfileobject{$fn}) &&
  1150. error(_g("diff `%s' patches something which is not a plain file"),
  1151. $diff);
  1152. defined($filepatched{$fn}) &&
  1153. $filepatched{$fn} eq $diff &&
  1154. error(_g("diff patches file %s twice"), $fn);
  1155. $filepatched{$fn} = $diff;
  1156. # read hunks
  1157. my $hunk = 0;
  1158. while (defined($_ = <DIFF>) && !(/^--- / or /^Index:/)) {
  1159. # read hunk header (@@)
  1160. s/\n$// or error(_g("diff `%s' is missing trailing newline"), $diff);
  1161. next if /^\\ No newline/;
  1162. /^@@ -\d+(,(\d+))? \+\d+(,(\d+))? @\@( .*)?$/ or
  1163. error(_g("Expected ^\@\@ in line %d of diff `%s'"), $., $diff);
  1164. my ($olines, $nlines) = ($1 ? $2 : 1, $3 ? $4 : 1);
  1165. ++$hunk;
  1166. # read hunk
  1167. while ($olines || $nlines) {
  1168. defined($_ = <DIFF>) or
  1169. error(_g("unexpected end of diff `%s'"), $diff);
  1170. s/\n$// or
  1171. error(_g("diff `%s' is missing trailing newline"), $diff);
  1172. next if /^\\ No newline/;
  1173. if (/^ /) { --$olines; --$nlines; }
  1174. elsif (/^-/) { --$olines; }
  1175. elsif (/^\+/) { --$nlines; }
  1176. else {
  1177. error(_g("expected [ +-] at start of line %d of diff `%s'"),
  1178. $., $diff);
  1179. }
  1180. }
  1181. }
  1182. $hunk or error(_g("expected ^\@\@ at line %d of diff `%s'"), $., $diff);
  1183. }
  1184. close(DIFF);
  1185. &reapgzip if $diff =~ /\.$comp_regex$/;
  1186. }
  1187. sub extracttar {
  1188. my ($tarfileread,$dirchdir,$newtopdir) = @_;
  1189. my ($mode, $modes_set, $i, $j);
  1190. &forkgzipread("$tarfileread");
  1191. defined(my $c2 = fork) || syserr(_g("fork for tar -xkf -"));
  1192. if (!$c2) {
  1193. open(STDIN,"<&GZIP") || &syserr(_g("reopen gzip for tar -xkf -"));
  1194. &cpiostderr;
  1195. chdir($dirchdir) ||
  1196. syserr(_g("cannot chdir to `%s' for tar extract"), $dirchdir);
  1197. exec('tar','--no-same-owner','--no-same-permissions',
  1198. '-xkf','-') or &syserr(_g("exec tar -xkf -"));
  1199. }
  1200. close(GZIP);
  1201. $c2 == waitpid($c2,0) || &syserr(_g("wait for tar -xkf -"));
  1202. $? && subprocerr("tar -xkf -");
  1203. &reapgzip;
  1204. # Unfortunately tar insists on applying our umask _to the original
  1205. # permissions_ rather than mostly-ignoring the original
  1206. # permissions. We fix it up with chmod -R (which saves us some
  1207. # work) but we have to construct a u+/- string which is a bit
  1208. # of a palaver. (Numeric doesn't work because we need [ugo]+X
  1209. # and [ugo]=<stuff> doesn't work because that unsets sgid on dirs.)
  1210. #
  1211. # We still need --no-same-permissions because otherwise tar might
  1212. # extract directory setgid (which we want inherited, not
  1213. # extracted); we need --no-same-owner because putting the owner
  1214. # back is tedious - in particular, correct group ownership would
  1215. # have to be calculated using mount options and other madness.
  1216. #
  1217. # It would be nice if tar could do it right, or if pax could cope
  1218. # with GNU format tarfiles with long filenames.
  1219. #
  1220. $mode= 0777 & ~umask;
  1221. for ($i=0; $i<9; $i+=3) {
  1222. $modes_set.= ',' if $i;
  1223. $modes_set.= qw(u g o)[$i/3];
  1224. for ($j=0; $j<3; $j++) {
  1225. $modes_set.= $mode & (0400 >> ($i+$j)) ? '+' : '-';
  1226. $modes_set.= qw(r w X)[$j];
  1227. }
  1228. }
  1229. system 'chmod','-R',$modes_set,'--',$dirchdir;
  1230. $? && subprocerr("chmod -R $modes_set $dirchdir");
  1231. opendir(D, "$dirchdir") || syserr(_g("Unable to open dir %s"), $dirchdir);
  1232. my @dirchdirfiles = grep($_ ne "." && $_ ne "..", readdir(D));
  1233. closedir(D) || syserr(_g("Unable to close dir %s"), $dirchdir);
  1234. if (@dirchdirfiles==1 && -d "$dirchdir/$dirchdirfiles[0]") {
  1235. rename("$dirchdir/$dirchdirfiles[0]", "$dirchdir/$newtopdir") ||
  1236. syserr(_g("Unable to rename %s to %s"),
  1237. "$dirchdir/$dirchdirfiles[0]",
  1238. "$dirchdir/$newtopdir");
  1239. } else {
  1240. mkdir("$dirchdir/$newtopdir.tmp", 0777) or
  1241. syserr(_g("Unable to mkdir %s"), "$dirchdir/$newtopdir.tmp");
  1242. for (@dirchdirfiles) {
  1243. rename("$dirchdir/$_", "$dirchdir/$newtopdir.tmp/$_") or
  1244. syserr(_g("Unable to rename %s to %s"),
  1245. "$dirchdir/$_",
  1246. "$dirchdir/$newtopdir.tmp/$_");
  1247. }
  1248. rename("$dirchdir/$newtopdir.tmp", "$dirchdir/$newtopdir") or
  1249. syserr(_g("Unable to rename %s to %s"),
  1250. "$dirchdir/$newtopdir.tmp",
  1251. "$dirchdir/$newtopdir");
  1252. }
  1253. }
  1254. sub cpiostderr {
  1255. open(STDERR,"| grep -E -v '^[0-9]+ blocks\$' >&2") ||
  1256. &syserr(_g("reopen stderr for tar to grep out blocks message"));
  1257. }
  1258. sub checktype {
  1259. my ($dir, $fn, $type) = @_;
  1260. if (!lstat("$dir/$fn")) {
  1261. &unrepdiff2(_g("nonexistent"),$type{$fn});
  1262. } else {
  1263. my $v = eval("$type _ ? 2 : 1");
  1264. $v || internerr(_g("checktype %s (%s)"), "$@", $type);
  1265. return 1 if $v == 2;
  1266. &unrepdiff2(_g("something else"),$type{$fn});
  1267. }
  1268. return 0;
  1269. }
  1270. sub setopmode {
  1271. defined($opmode) && &usageerr(_g("only one of -x or -b allowed, and only once"));
  1272. $opmode= $_[0];
  1273. }
  1274. sub unrepdiff {
  1275. printf(STDERR _g("%s: cannot represent change to %s: %s")."\n",
  1276. $progname, $fn, $_[0])
  1277. || &syserr(_g("write syserr unrep"));
  1278. $ur++;
  1279. }
  1280. sub unrepdiff2 {
  1281. printf(STDERR _g("%s: cannot represent change to %s:\n".
  1282. "%s: new version is %s\n".
  1283. "%s: old version is %s\n"),
  1284. $progname, $fn, $progname, $_[1], $progname, $_[0])
  1285. || &syserr(_g("write syserr unrep"));
  1286. $ur++;
  1287. }
  1288. sub forkgzipwrite {
  1289. $compressor->set_compression_level($comp_level);
  1290. my $handle = $compressor->compress_from_pipe_to_file($_[0]);
  1291. open(GZIP, ">>&=", $handle) || syserr(_g("cannot associate handle"));
  1292. close($handle);
  1293. }
  1294. sub forkgzipread {
  1295. $compressor->set_compression_level($comp_level);
  1296. my $handle = $compressor->uncompress_from_file_to_pipe($_[0]);
  1297. open(GZIP, "<&=", $handle) || syserr(_g("cannot associate handle"));
  1298. close($handle);
  1299. }
  1300. sub reapgzip {
  1301. $compressor->wait_end_process();
  1302. }
  1303. my %added_files;
  1304. sub addfile {
  1305. my ($fields, $filename)= @_;
  1306. $added_files{$filename}++ &&
  1307. internerr(_g("tried to add file `%s' twice"), $filename);
  1308. stat($filename) || syserr(_g("could not stat output file `%s'"), $filename);
  1309. my $size = (stat _)[7];
  1310. my $md5sum= `md5sum <$filename`;
  1311. $? && &subprocerr("md5sum $filename");
  1312. $md5sum = readmd5sum( $md5sum );
  1313. $fields->{'Files'}.= "\n $md5sum $size $filename";
  1314. }
  1315. sub readmd5sum {
  1316. (my $md5sum = shift) or return;
  1317. $md5sum =~ s/^([0-9a-f]{32})\s*\*?-?\s*\n?$/$1/o
  1318. || failure(_g("md5sum gave bogus output `%s'"), $md5sum);
  1319. return $md5sum;
  1320. }