make-plist 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182
  1. #! /usr/bin/perl
  2. # $OpenBSD: make-plist,v 1.11 2016/09/01 13:12:34 ajacoutot Exp $
  3. # Copyright (c) 2004-2008 Marc Espie <espie@openbsd.org>
  4. #
  5. # Permission to use, copy, modify, and distribute this software for any
  6. # purpose with or without fee is hereby granted, provided that the above
  7. # copyright notice and this permission notice appear in all copies.
  8. #
  9. # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  10. # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  11. # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  12. # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  13. # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  14. # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  15. # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  16. # TODO
  17. # - multi-packages with inter-dependencies still are not 100% correct with
  18. # respect to common directories.
  19. use strict;
  20. use warnings;
  21. my $ports1;
  22. BEGIN {
  23. $ports1 = $ENV{PORTSDIR} || '/usr/ports';
  24. }
  25. use lib "$ports1/infrastructure/lib";
  26. use OpenBSD::PackingList;
  27. use OpenBSD::PackingElement;
  28. use OpenBSD::PackageLocator;
  29. use OpenBSD::PackageInfo;
  30. use OpenBSD::Subst;
  31. use File::Basename;
  32. use File::Compare;
  33. use File::Temp;
  34. use OpenBSD::FS;
  35. package OpenBSD::ReverseSubst;
  36. our @ISA = (qw(OpenBSD::Subst));
  37. sub new
  38. {
  39. bless {h => {}, r => [], l => {}, found => {}}, shift;
  40. }
  41. sub hash
  42. {
  43. my $self = shift;
  44. return $self->{h};
  45. }
  46. sub value
  47. {
  48. my ($self, $k) = @_;
  49. return $self->{h}->{$k};
  50. }
  51. sub add
  52. {
  53. my ($self, $k, $v) = @_;
  54. if ($k =~ m/^FULLPKGNAME/) {
  55. unshift(@{$self->{r}}, $k) if $v ne '';
  56. } elsif ($k =~ m/^LIB(.*)_VERSION$/) {
  57. $self->{l}->{$1} = $v;
  58. } else {
  59. push(@{$self->{r}}, $k) if $v ne '';
  60. }
  61. $k =~ s/^\^//;
  62. $self->{h}->{$k} = $v;
  63. }
  64. sub reverse
  65. {
  66. my ($self, $path) = @_;
  67. for my $k (@{$self->{r}}) {
  68. if ($k =~ m/^\^(.*)$/) {
  69. my $k2 = $1;
  70. my $v = $self->{h}->{$k2};
  71. $path =~ s/^\Q$v\E/\$\{\Q$k2\E\}/g;
  72. } else {
  73. my $v = $self->{h}->{$k};
  74. $path =~ s/\Q$v\E/\$\{\Q$k\E\}/g;
  75. }
  76. }
  77. return $path;
  78. }
  79. my $first_warn = 1;
  80. sub reverse_with_lib
  81. {
  82. my ($self, $path) = @_;
  83. if ($path =~ m/^(.*?)lib([^\/]+)\.so\.(\d+\.\d+)$/) {
  84. my ($path, $name, $version) = ($1, $2, $3);
  85. if (!defined $self->{l}->{$name}) {
  86. if ($first_warn) {
  87. print STDERR "WARNING: unregistered shared lib(s)\n";
  88. $first_warn = 0;
  89. }
  90. print STDERR "SHARED_LIBS +=\t$name ",
  91. ' 'x (25-length($name)), "0.0 # $version\n";
  92. $self->{l}->{$name} = $version;
  93. } elsif ($self->{l}->{$name} ne $version) {
  94. print STDERR "WARNING: version mismatch for lib: $name "
  95. . "($version vs. $self->{l}->{$name})\n";
  96. }
  97. $self->{found}->{$name} = 1;
  98. return $self->reverse("${path}lib$name.so.")."\${LIB${name}_VERSION}";
  99. } else {
  100. return $self->reverse($path);
  101. }
  102. }
  103. package main;
  104. # Plists use variable substitution, we have to be able to do it
  105. # both ways to recognize existing entries.
  106. my $base;
  107. our $subst = new OpenBSD::ReverseSubst;
  108. my $destdir = $ENV{'DESTDIR'};
  109. my %known_libs;
  110. die "No $destdir" unless -d $destdir;
  111. my %prefix;
  112. my %plistname;
  113. my %mtree;
  114. my @subs;
  115. my $baseprefix=$ENV{PREFIX};
  116. my $shared_only = 1;
  117. my $make = $ENV{MAKE};
  118. my $portsdir = $ENV{PORTSDIR};
  119. my $portsdir_path = $ENV{PORTSDIR_PATH};
  120. sub prettify
  121. {
  122. my $f = $_[0]->{filename};
  123. $f =~ s/^.*\/pkg\//pkg\//;
  124. return $f;
  125. }
  126. sub report
  127. {
  128. print STDERR "make-plist: ";
  129. for my $i (@_) {
  130. if (ref $i) {
  131. if ($i->isa("OpenBSD::PackingElement")) {
  132. print STDERR $i->stringize;
  133. } elsif ($i->isa("OpenBSD::PackingList")) {
  134. print STDERR prettify($i);
  135. } elsif ($i->isa("OpenBSD::FS::File")) {
  136. print STDERR $i->path;
  137. }
  138. } else {
  139. print STDERR $i;
  140. }
  141. }
  142. print STDERR "\n";
  143. }
  144. my $cached_tree = {};
  145. sub build_mtree
  146. {
  147. my ($sub, $deps) = @_;
  148. my $mtree = {};
  149. # add directories from dependencies
  150. my $stripped = {};
  151. for my $pkgpath (split /\s+/, $deps) {
  152. next if defined $stripped->{$pkgpath};
  153. $stripped->{$pkgpath} = 1;
  154. if (!defined $cached_tree->{$pkgpath}) {
  155. $cached_tree->{$pkgpath} = {};
  156. open my $fh, "cd $portsdir && env -i PORTSDIR_PATH=$portsdir_path SUBDIR=$pkgpath ECHO_MSG=: $make print-plist |" or die "blech\n";
  157. augment_mtree($cached_tree->{$pkgpath}, $fh);
  158. close($fh);
  159. }
  160. print STDERR "Subpackage $sub: Stripping dirs from $pkgpath\n";
  161. for my $e (keys %{$cached_tree->{$pkgpath}}) {
  162. $mtree->{$e} = 1;
  163. }
  164. }
  165. return $mtree;
  166. }
  167. sub parse_arg
  168. {
  169. my $p = shift;
  170. if ($p =~ m/^DEPPATHS(-.*?)\=/) {
  171. $mtree{$1} = build_mtree($1, $');
  172. return;
  173. }
  174. if ($p =~ m/\=/) {
  175. $subst->parse_option($p);
  176. }
  177. if ($p =~ m/^\^PREFIX(\-.*?)\=(.*)\/?$/) {
  178. $prefix{$1} = $2;
  179. } elsif ($p =~ m/^PLIST(\-.*?)\=/) {
  180. $plistname{$1} = $';
  181. }
  182. }
  183. sub parse_env
  184. {
  185. }
  186. sub parse_args
  187. {
  188. for my $i (@ARGV) {
  189. parse_arg($i);
  190. }
  191. my $multi = $ENV{'MULTI_PACKAGES'};
  192. # Normalize
  193. $multi =~ s/^\s+//;
  194. $multi =~ s/\s+$//;
  195. @subs = split /\s+/, $multi;
  196. for my $sub (@subs) {
  197. if (!defined $prefix{$sub} || !defined $plistname{$sub} ||
  198. !defined $mtree{$sub}) {
  199. die "Incomplete information for $sub";
  200. }
  201. }
  202. if (defined $ENV{'SHARED_ONLY'}) {
  203. if ($ENV{'SHARED_ONLY'} =~ m/^Yes$/i) {
  204. $shared_only = 1;
  205. }
  206. }
  207. }
  208. sub deduce_name
  209. {
  210. my ($o, $frag, $not) = @_;
  211. my $noto = $o;
  212. my $nofrag = "no-$frag";
  213. $o =~ s/PFRAG\./PFRAG.$frag-/ or
  214. $o =~ s/PLIST/PFRAG.$frag/;
  215. $noto =~ s/PFRAG\./PFRAG.no-$frag-/ or
  216. $noto =~ s/PLIST/PFRAG.no-$frag/;
  217. if ($not) {
  218. return $noto;
  219. } else {
  220. return $o;
  221. }
  222. }
  223. sub possible_subpackages
  224. {
  225. my $filename= shift;
  226. my $l = [];
  227. for my $sub (@subs) {
  228. if ($filename =~ m/^\Q$prefix{$sub}\E\//) {
  229. push @$l, $sub;
  230. }
  231. }
  232. return $l;
  233. }
  234. # Fragments are new PackingElement unique to make-plist and pkg_create,
  235. # to handle %%thingy%%.
  236. # (and so, make-plist will use a special PLIST reader)
  237. # Method summary:
  238. # add_to_mtree: new directory in dependent package
  239. # add_to_haystack: put stuff so that it can be found on the FS
  240. # copy_extra: stuff that can't be easily deduced but should be copied
  241. # tag_along: set of items that associate themselves to this item
  242. # (e.g., @exec, @unexec, @sample...)
  243. # clone_tags: copy tagged stuff over.
  244. # deduce_fragment: find fragment file name from %%stuff%%
  245. # note $plist->{nonempty}: set as soon as a plist holds anything
  246. # but a cvstag.
  247. package OpenBSD::PackingElement;
  248. sub add_to_mtree
  249. {
  250. }
  251. sub add_object2
  252. {
  253. my ($self, $plist) = @_;
  254. $self->add_object($plist);
  255. $plist->{nonempty} = 1;
  256. }
  257. sub add_to_haystack
  258. {
  259. my ($self, $plist, $haystack) = @_;
  260. $self->{plist} = $plist;
  261. }
  262. sub register
  263. {
  264. }
  265. sub copy_extra
  266. {
  267. }
  268. sub tag_along
  269. {
  270. my ($self, $n) = @_;
  271. $self->{tags} = [] unless defined $self->{tags};
  272. push(@{$self->{tags}}, $n);
  273. }
  274. sub deduce_fragment
  275. {
  276. }
  277. sub delay_tag
  278. {
  279. return 0;
  280. }
  281. sub clone_tags
  282. {
  283. my ($self, $plist) = @_;
  284. if (defined $self->{tags}) {
  285. for my $t (@{$self->{tags}}) {
  286. my $n = $t->clone;
  287. if ($n->isa("OpenBSD::PackingElement::Sample") ||
  288. $n->isa("OpenBSD::PackingElement::Sampledir")) {
  289. main::handle_modes($plist, $n, $t, undef, undef);
  290. }
  291. $n->add_object2($plist);
  292. if ($n->isa("OpenBSD::PackingElement::Fragment") &&
  293. $n->{name} eq "SHARED") {
  294. $plist->{hasshared} = 1;
  295. }
  296. }
  297. }
  298. }
  299. sub copy_annotations
  300. {
  301. }
  302. sub bugfix
  303. {
  304. }
  305. package OpenBSD::PackingElement::Meta;
  306. sub copy_annotations
  307. {
  308. my ($self, $plist) = @_;
  309. $self->clone->add_object2($plist);
  310. }
  311. package OpenBSD::PackingElement::CVSTag;
  312. sub copy_annotations
  313. {
  314. my ($self, $plist) = @_;
  315. $self->clone->add_object($plist);
  316. }
  317. package OpenBSD::PackingElement::NewAuth;
  318. sub copy_annotations
  319. {
  320. &OpenBSD::PackingElement::Meta::copy_annotations;
  321. }
  322. package OpenBSD::PackingElement::SpecialFile;
  323. sub copy_annotations
  324. {
  325. }
  326. package OpenBSD::PackingElement::Fragment;
  327. our @ISA=qw(OpenBSD::PackingElement);
  328. sub register
  329. {
  330. my ($self, $plist) = @_;
  331. $plist->{state}->{lastreal}->tag_along($self);
  332. }
  333. sub deduce_fragment
  334. {
  335. my ($self, $o) = @_;
  336. my $frag = $self->{name};
  337. return if $frag eq "SHARED";
  338. $o =~ s/PFRAG\./PFRAG.$frag-/ or
  339. $o =~ s/PLIST/PFRAG.$frag/;
  340. return $o if -e $o;
  341. }
  342. sub needs_keyword() { 0 }
  343. sub stringize
  344. {
  345. return '%%'.shift->{name}.'%%';
  346. }
  347. package OpenBSD::PackingElement::NoFragment;
  348. our @ISA=qw(OpenBSD::PackingElement::Fragment);
  349. sub deduce_fragment
  350. {
  351. my ($self, $noto) = @_;
  352. my $frag = $self->{name};
  353. return if $frag eq "SHARED";
  354. $noto =~ s/PFRAG\./PFRAG.no-$frag-/ or
  355. $noto =~ s/PLIST/PFRAG.no-$frag/;
  356. return $noto if -e $noto;
  357. }
  358. sub stringize
  359. {
  360. return '!%%'.shift->{name}.'%%';
  361. }
  362. package OpenBSD::PackingElement::Owner;
  363. sub add_to_haystack
  364. {
  365. my ($self, $plist, $haystack) = @_;
  366. $self->SUPER::add_to_haystack($plist, $haystack);
  367. push(@{$haystack->{$main::subst->do($self->{name})}}, $self);
  368. }
  369. package OpenBSD::PackingElement::Group;
  370. sub add_to_haystack
  371. {
  372. &OpenBSD::PackingElement::Owner::add_to_haystack;
  373. }
  374. package OpenBSD::PackingElement::FileObject;
  375. sub add_to_haystack
  376. {
  377. my ($self, $plist, $haystack) = @_;
  378. $self->SUPER::add_to_haystack($plist, $haystack);
  379. my $fullname = $main::subst->do($self->{name});
  380. if ($fullname !~ m/^\//) {
  381. $fullname = $main::subst->do($self->fullname);
  382. }
  383. push(@{$haystack->{$fullname}}, $self);
  384. }
  385. sub bugfix
  386. {
  387. my ($self, $subpackage, $reverse) = @_;
  388. if ($self->{name} =~ m/\$\{(.*)\\$subpackage\}/) {
  389. if ($reverse->{h}->{$1.$subpackage}) {
  390. $self->{name} =~ s/(\$\{.*)\\$subpackage\}/$1\}/;
  391. }
  392. }
  393. }
  394. package OpenBSD::PackingElement::FileBase;
  395. sub register
  396. {
  397. my ($self, $plist) = @_;
  398. $plist->{state}->{lastobject} = $self;
  399. if (defined $self->{accounted_for}) {
  400. $plist->{state}->{lastreal} = $self;
  401. }
  402. }
  403. package OpenBSD::PackingElement::Dir;
  404. sub register
  405. {
  406. my ($self, $plist) = @_;
  407. $plist->{state}->{lastobject} = $self;
  408. if (defined $self->{accounted_for}) {
  409. $plist->{state}->{lastreal} = $self;
  410. }
  411. }
  412. package OpenBSD::PackingElement::Sample;
  413. sub register
  414. {
  415. my ($self, $plist) = @_;
  416. if (defined $self->{copyfrom}) {
  417. if (!defined $self->{copyfrom}->{accounted_for}) {
  418. main::report $plist, ": sample ", $self,
  419. " no longer refers to anything";
  420. }
  421. $self->{copyfrom}->tag_along($self);
  422. } else {
  423. main::report $plist, ": bogus sample ", $self,
  424. " (unattached) detected";
  425. }
  426. }
  427. package OpenBSD::PackingElement::Sysctl;
  428. sub register
  429. {
  430. my ($self, $plist) = @_;
  431. $plist->{state}->{lastreal}->tag_along($self);
  432. }
  433. package OpenBSD::PackingElement::ExeclikeAction;
  434. sub pseudo_expand
  435. {
  436. my ($file, $item) = @_;
  437. if ($file =~ m/\%F/o) {
  438. return "XXXX" unless defined $item;
  439. $file =~ s/\%F/$item->{name}/g;
  440. }
  441. if ($file =~ m/\%D/o) {
  442. return "XXXX" unless defined $item;
  443. $file =~ s/\%D/$item->cwd/ge;
  444. }
  445. if ($file =~ m/\%B/o) {
  446. return "XXXX" unless defined $item;
  447. $file =~ s/\%B/dirname($item->fullname)/ge;
  448. }
  449. if ($file =~ m/\%f/o) {
  450. return "XXXX" unless defined $item;
  451. $file =~ s/\%f/basename($item->fullname)/ge;
  452. }
  453. return $file;
  454. }
  455. sub delay_tag
  456. {
  457. my $self = shift;
  458. if (m/\%[fF]/o) {
  459. return 0;
  460. }
  461. if (m/\%[BD]/o) {
  462. return 1;
  463. }
  464. return 0;
  465. }
  466. sub register
  467. {
  468. my ($self, $plist) = @_;
  469. if (!defined $plist->{state}->{lastobject} ||
  470. $plist->{state}->{lastobject} != $plist->{state}->{lastreal}) {
  471. my $f1 = pseudo_expand($self->{name},
  472. $plist->{state}->{lastobject});
  473. my $f2 = pseudo_expand($self->{name},
  474. $plist->{state}->{lastreal});
  475. if ($f1 ne $f2) {
  476. main::report " orphaned \@", $self->keyword, " ", $self,
  477. " in ", $plist;
  478. return;
  479. }
  480. }
  481. $plist->{state}->{lastreal}->tag_along($self);
  482. }
  483. package OpenBSD::PackingElement::Sampledir;
  484. sub register
  485. {
  486. my ($self, $plist) = @_;
  487. $plist->{state}->{lastreal}->tag_along($self);
  488. }
  489. package OpenBSD::PackingElement::DirlikeObject;
  490. sub add_to_mtree
  491. {
  492. my ($self, $mtree) = @_;
  493. $mtree->{$self->fullname} = 1;
  494. }
  495. package OpenBSD::PackingElement::Comment;
  496. sub cwd
  497. {
  498. my $self = shift;
  499. if (!defined $self->{cwd}) {
  500. die "Update your pkg_add!!!\n";
  501. }
  502. return ${$self->{cwd}};
  503. }
  504. sub add_this_name_to_haystack
  505. {
  506. my ($self, $name, $haystack) = @_;
  507. my $fullname = File::Spec->canonpath($name);
  508. if ($fullname !~ m|^/|o && $self->cwd ne '.') {
  509. $fullname = $self->cwd."/".$fullname;
  510. }
  511. my $n = $main::subst->do($fullname);
  512. push(@{$haystack->{$n}}, $self);
  513. }
  514. sub add_to_haystack
  515. {
  516. my ($self, $plist, $haystack) = @_;
  517. $self->SUPER::add_to_haystack($plist, $haystack);
  518. $self->add_this_name_to_haystack($self->{name}, $haystack);
  519. if ($self->{name} =~ m/^\@\S+\s*(.*)$/o) {
  520. $self->add_this_name_to_haystack($1, $haystack);
  521. }
  522. }
  523. sub copy_annotations
  524. {
  525. }
  526. sub register
  527. {
  528. my ($self, $plist) = @_;
  529. # comments which are not files will `tag along' more or less...
  530. if (!defined $self->{accounted_for}) {
  531. main::report "comment \"", $self, "\" position in ", $plist,
  532. " guessed";
  533. $plist->{state}->{lastreal}->tag_along($self);
  534. }
  535. }
  536. package OpenBSD::PackingElement::Extra;
  537. sub copy_extra
  538. {
  539. my ($self, $plist) = @_;
  540. if ($self->cwd ne $plist->{state}->cwd) {
  541. OpenBSD::PackingElement::Cwd->add($plist, $self->cwd);
  542. }
  543. $self->clone->add_object2($plist);
  544. }
  545. package main;
  546. # add dependent package directories to the set of directories that don't
  547. # need registration.
  548. sub augment_mtree
  549. {
  550. my ($mtree, $fh) = @_;
  551. my $plist = OpenBSD::PackingList->read($fh,
  552. \&OpenBSD::PackingList::SharedItemsOnly)
  553. or die "couldn't read packing-list\n";
  554. $plist->add_to_mtree($mtree);
  555. }
  556. my $haystack = {};
  557. # Basic packing-list with a known prefix
  558. sub create_packinglist
  559. {
  560. my ($filename, $sub) = @_;
  561. my $prefix = $prefix{$sub};
  562. my $plist = OpenBSD::PackingList->new;
  563. $plist->{filename} = $filename;
  564. $plist->{mtree} = $mtree{$sub};
  565. $plist->{state}->set_cwd($prefix);
  566. $prefix.='/' unless $prefix =~ m|/$|;
  567. $plist->{stripprefix} = $prefix;
  568. $plist->{sub} = $sub;
  569. return $plist;
  570. }
  571. # grab original packing list, killing some stuff that is no longer needed.
  572. sub parse_original_plist
  573. {
  574. my ($name, $sub, $all_plists) = @_;
  575. my $plist = create_packinglist($name, $sub);
  576. # special reader for fragments
  577. $plist->fromfile($name,
  578. sub {
  579. my ($fh, $cont) = @_;
  580. while (<$fh>) {
  581. if (m/^\%\%(.*)\%\%$/) {
  582. OpenBSD::PackingElement::Fragment->add($plist, $1);
  583. } elsif (m/^\!\%\%(.*)\%\%$/) {
  584. OpenBSD::PackingElement::NoFragment->add($plist, $1);
  585. } else {
  586. &$cont($_);
  587. }
  588. }
  589. }
  590. ) or return;
  591. $plist->add_to_haystack($plist, $haystack);
  592. # Try to handle fragments
  593. for my $item (@{$plist->{items}}) {
  594. my $fragname = $item->deduce_fragment($name);
  595. next unless defined $fragname;
  596. my $pfrag = create_packinglist($fragname, $sub);
  597. $pfrag->{isfrag} = 1;
  598. push(@$all_plists, $pfrag);
  599. my $origpfrag = parse_original_plist($fragname, $sub, $all_plists);
  600. replaces($origpfrag, $pfrag);
  601. }
  602. return $plist;
  603. }
  604. # link original and new plist
  605. sub replaces
  606. {
  607. my ($orig, $n) = @_;
  608. if (defined $orig) {
  609. $n->{original} = $orig;
  610. $orig->{replacement} = $n;
  611. $n->{filename} = $orig->{filename};
  612. }
  613. }
  614. sub grab_all_lists
  615. {
  616. my $l = [];
  617. for my $sub (@subs) {
  618. my $o;
  619. my $n = create_packinglist($plistname{$sub}, $sub);
  620. push(@$l, $n);
  621. $o = parse_original_plist($plistname{$sub}, $sub, $l);
  622. replaces($o, $n);
  623. my $frag = deduce_name($plistname{$sub}, "shared", 0);
  624. my $ns = create_packinglist($frag, $sub);
  625. $n->{shared} = $ns;
  626. $o = parse_original_plist($frag, $sub, $l);
  627. replaces($o, $ns);
  628. push(@$l, $ns);
  629. }
  630. return @$l;
  631. }
  632. # new object according to type, just copy over some stuff for now
  633. sub create_object
  634. {
  635. my ($type, $short, $item) = @_;
  636. if (defined $item && $item->isa("OpenBSD::PackingElement::Comment")) {
  637. return $item->clone;
  638. }
  639. if ($type eq "directory") {
  640. if (defined $item) {
  641. if ($item->isa("OpenBSD::PackingElement::Mandir")) {
  642. return OpenBSD::PackingElement::Mandir->new($short);
  643. } elsif ($item->isa("OpenBSD::PackingElement::Fontdir")) {
  644. return OpenBSD::PackingElement::Fontdir->new($short);
  645. }
  646. }
  647. return OpenBSD::PackingElement::Dir->new($short);
  648. } elsif ($type eq "manpage") {
  649. return OpenBSD::PackingElement::Manpage->new($short);
  650. } elsif ($type eq "dir" || $type eq "subinfo") {
  651. return undef;
  652. } elsif ($type eq "info") {
  653. return OpenBSD::PackingElement::InfoFile->new($short);
  654. } elsif ($type eq "library") {
  655. return OpenBSD::PackingElement::Lib->new($short);
  656. } elsif ($type eq "binary") {
  657. if (defined $item && $item->isa("OpenBSD::PackingElement::Shell")) {
  658. return OpenBSD::PackingElement::Shell->new($short);
  659. } else {
  660. return OpenBSD::PackingElement::Binary->new($short);
  661. }
  662. } else {
  663. if (defined $item) {
  664. if ($item->isa("OpenBSD::PackingElement::Shell")) {
  665. return OpenBSD::PackingElement::Shell->new($short);
  666. }
  667. }
  668. return OpenBSD::PackingElement::File->new($short);
  669. }
  670. }
  671. # `restate' packing-list according to current mode settings.
  672. # for now, we copy over stuff from old items.
  673. sub handle_modes
  674. {
  675. my ($plist, $item, $o, $file, $haystack) = @_;
  676. my ($mode, $owner, $group) = ('', '', '');
  677. if (defined $item) {
  678. if (defined $item->{nochecksum}) {
  679. $o->{nochecksum} = 1;
  680. }
  681. if (defined $item->{ignore}) {
  682. $o->{ignore} = 1;
  683. }
  684. if (defined $item->{mode}) {
  685. $mode = $item->{mode};
  686. }
  687. if (defined $item->{owner}) {
  688. $owner = $item->{owner};
  689. }
  690. if (defined $item->{group}) {
  691. $group = $item->{group};
  692. }
  693. }
  694. if (defined $file) {
  695. if (defined $haystack->{$file->owner}) {
  696. for my $o (@{$haystack->{$file->owner}}) {
  697. if ($o->isa("OpenBSD::PackingElement::Owner")) {
  698. if ($owner ne '') {
  699. if ($subst->do($owner) eq $file->owner) {
  700. last;
  701. } else {
  702. report "owner mismatch for ",
  703. $file, " ($owner vs. ",
  704. $file->owner, ")";
  705. }
  706. } else {
  707. # don't bother copying root for non special modes.
  708. if ($mode eq '' && $file->owner eq 'root') {
  709. next;
  710. }
  711. $owner = $o->{name};
  712. }
  713. }
  714. }
  715. }
  716. if (defined $haystack->{$file->group}) {
  717. for my $g (@{$haystack->{$file->group}}) {
  718. if ($g->isa("OpenBSD::PackingElement::Group")) {
  719. if ($group ne '') {
  720. if ($subst->do($group) eq $file->group) {
  721. last;
  722. } else {
  723. report "group mismatch for ",
  724. $file, " ($group vs. ",
  725. $file->group, ")";
  726. }
  727. } else {
  728. $group = $g->{name};
  729. }
  730. }
  731. }
  732. }
  733. }
  734. # check whether there's a state change
  735. my ($oldmode, $oldowner, $oldgroup) = ($plist->{state}->{mode},
  736. $plist->{state}->{owner}, $plist->{state}->{group});
  737. $oldmode = '' unless defined $oldmode;
  738. $oldowner = '' unless defined $oldowner;
  739. $oldgroup = '' unless defined $oldgroup;
  740. if ($mode ne $oldmode) {
  741. OpenBSD::PackingElement::Mode->add($plist, $mode);
  742. }
  743. if ($owner ne $oldowner) {
  744. OpenBSD::PackingElement::Owner->add($plist, $owner);
  745. }
  746. if ($group ne $oldgroup) {
  747. OpenBSD::PackingElement::Group->add($plist, $group);
  748. }
  749. }
  750. sub short_name
  751. {
  752. my ($file, $plist) = @_;
  753. my $short = $file->path;
  754. my $base = $plist->{stripprefix};
  755. if ($short =~ m/^\Q$base\E/) {
  756. $short = $';
  757. $short = '/' if $short eq '';
  758. } else {
  759. return undef;
  760. }
  761. if ($file->type eq 'directory') {
  762. $short.='/';
  763. }
  764. if ($file->type eq 'library') {
  765. $short = $subst->reverse_with_lib($short);
  766. } else {
  767. $short = $subst->reverse($short);
  768. }
  769. # If the resulting name is arch-dependent, we warn.
  770. # We don't fix it automatically, as this may need special handling.
  771. if ($short =~ m/alpha|amd64|arm|hppa|i386|mips64|mips64el|powerpc|sparc64|x86[-_]64/) {
  772. report $plist, " may contain arch-dependent\n\t$short";
  773. }
  774. return $short;
  775. }
  776. sub bad_files
  777. {
  778. my ($short, $plist) = @_;
  779. if ($short =~ /\.orig$/) {
  780. report $plist, " may contain patched file\n\t$short";
  781. }
  782. if ($short =~ /\/\.[^\/]*\.swp$/) {
  783. report $plist, " may contain vim swap file\n\t$short";
  784. }
  785. if ($short =~ /\~$/) {
  786. report $plist, " may contain emacs temp file\n\t$short";
  787. }
  788. }
  789. # find out where a file belongs, and insert all corresponding things
  790. # into the right packing-list.
  791. sub handle_file
  792. {
  793. my ($file, $haystack, $allplists, $shared_only) = @_;
  794. my $foundit;
  795. if (defined $haystack->{$file->path}) {
  796. for my $item (@{$haystack->{$file->path}}) {
  797. next if $item->isa("OpenBSD::PackingElement::State");
  798. my $p = $item->{plist}->{replacement};
  799. if ($file->type eq 'directory' &&
  800. $p->{mtree}->{$file->path}) {
  801. next;
  802. }
  803. if ($item->isa("OpenBSD::PackingElement::Sampledir")) {
  804. # XXX Don't copy this over, it's supposed to tag along
  805. return;
  806. }
  807. my $short = short_name($file, $p);
  808. if (!defined $short) {
  809. print STDERR $file->path, " does not belong\n";
  810. return;
  811. }
  812. my $o = create_object($file->type, $short, $item);
  813. if (!defined $o) {
  814. next;
  815. }
  816. $foundit = $item;
  817. if ($o->can("compute_modes")) {
  818. handle_modes($p, $item, $o, $file, $haystack);
  819. }
  820. $o->add_object2($p);
  821. # Copy properties from source item
  822. $item->clone_tags($p);
  823. }
  824. }
  825. if (defined $foundit) {
  826. return;
  827. }
  828. # Try to find a directory that `works'
  829. my $dir = $file->path;
  830. while (($dir = dirname($dir)) ne '/') {
  831. if (defined $haystack->{$dir} && @{$haystack->{$dir}} eq 1) {
  832. my $item = $haystack->{$dir}[0];
  833. next if $item->isa("OpenBSD::PackingElement::Sampledir");
  834. my $p = $item->{plist}->{replacement};
  835. if ($file->type eq 'directory' &&
  836. $p->{mtree}->{$file->path}) {
  837. next;
  838. }
  839. my $short = short_name($file, $p);
  840. my $o = create_object($file->type, $short, undef);
  841. if (!defined $o) {
  842. next;
  843. }
  844. bad_files($short, $p);
  845. if (($file->type eq 'plugin') && !$shared_only) {
  846. if (defined $p->{shared}) {
  847. $p->{wantshared} = 1;
  848. $p = $p->{shared};
  849. }
  850. }
  851. if ($o->can("compute_modes")) {
  852. handle_modes($p, undef, $o, $file, $haystack);
  853. }
  854. $o->add_object2($p);
  855. return;
  856. }
  857. }
  858. my $short;
  859. my $p;
  860. my $default = $allplists->[0];
  861. my $possible = possible_subpackages($file->path);
  862. if (@$possible == 0) {
  863. report "Bogus element outside of every prefix: ", $file;
  864. return;
  865. }
  866. # look for the first matching prefix in plist to produce an entry
  867. for my $try (@$allplists) {
  868. if ($file->type eq 'directory' and
  869. $try->{mtree}->{$file->path}) {
  870. next;
  871. }
  872. $short = short_name($file, $try);
  873. if (defined $short) {
  874. $p = $try;
  875. if ($p ne $default) {
  876. report "Element ", $file, " going to ", $p,
  877. " based on prefix";
  878. }
  879. last;
  880. }
  881. }
  882. if (!defined $p) {
  883. return;
  884. }
  885. my $o = create_object($file->type, $short, undef);
  886. return unless defined $o;
  887. bad_files($short, $p);
  888. if (($file->type eq 'plugin') && !$shared_only) {
  889. $p->{wantshared} = 1;
  890. $p = $p->{shared};
  891. }
  892. handle_modes($p, undef, $o, $file, $haystack);
  893. $o->add_object2($p);
  894. }
  895. sub scan_for_files
  896. {
  897. my ($file, $haystack) = @_;
  898. if (defined $haystack->{$file->path}) {
  899. for my $item (@{$haystack->{$file->path}}) {
  900. next if $item->isa("OpenBSD::PackingElement::State");
  901. my $p = $item->{plist}->{replacement};
  902. if ($file->type eq 'directory' &&
  903. $p->{mtree}->{$file->path}) {
  904. report "Discovered old directory in ", $p,
  905. ": ", $file, " (mtree)\n";
  906. next;
  907. }
  908. $item->{accounted_for} = 1;
  909. return;
  910. }
  911. }
  912. }
  913. # THIS IS WHERE THE MAIN PROGRAM STARTS
  914. parse_args();
  915. print "Scanning destdir\n";
  916. my $files = OpenBSD::FS::get_files($destdir);
  917. print "Getting old lists\n";
  918. my @l = grab_all_lists();
  919. print "1st pass identifying files\n";
  920. for my $i (sort keys %$files) {
  921. scan_for_files($files->{$i}, $haystack);
  922. }
  923. print "Attaching annotations\n";
  924. for my $plist (@l) {
  925. my $orig = $plist->{original};
  926. if (defined $orig) {
  927. delete $orig->{state}->{lastobject};
  928. # place holder for extra stuff that comes before any file
  929. my $orphans = new OpenBSD::PackingElement::Object('');
  930. $orphans->{cwd} = $plist->{state}->{cwd};
  931. $orig->{state}->{lastreal} = $orphans;
  932. $orig->register($orig);
  933. $orig->copy_annotations($plist);
  934. $orphans->clone_tags($plist);
  935. }
  936. if (!$plist->has('cvstags')) {
  937. OpenBSD::PackingElement::CVSTag->add($plist, '$OpenBSD'.'$');
  938. }
  939. }
  940. print "Sorting out destdir files\n";
  941. for my $i (sort keys %$files) {
  942. handle_file($files->{$i}, $haystack, \@l, $shared_only);
  943. }
  944. # Copy extra stuff
  945. for my $plist (@l) {
  946. my $orig = $plist->{original};
  947. next unless defined $orig;
  948. for my $i (@{$orig->{items}}) {
  949. $i->copy_extra($plist);
  950. }
  951. }
  952. my $default = $l[0];
  953. if (($default->{wantshared} || (defined $default->{shared}) && $default->{shared}->{nonempty}) && !$default->{hasshared}) {
  954. unshift(@{$default->{items}}, OpenBSD::PackingElement::Fragment->new("SHARED"));
  955. $default->{nonempty} = 1;
  956. }
  957. # XXX
  958. for my $plist (@l) {
  959. $plist->bugfix($plist->{sub}, $subst);
  960. }
  961. # write new info over, as joe user.
  962. # first we write out everything in /tmp
  963. # then we signal if something changed
  964. # if that's the case, we die if orig files exist, or we copy stuff over.
  965. {
  966. local ($), $>);
  967. if (defined $ENV{'GROUP'}) {
  968. $) = $ENV{'GROUP'};
  969. }
  970. if (defined $ENV{'OWNER'}) {
  971. $> = $ENV{'OWNER'};
  972. }
  973. my $dir = File::Temp::tempdir ( CLEANUP => 1);
  974. $dir.='/';
  975. # write out everything
  976. for my $plist (@l) {
  977. if (!$plist->{nonempty}) {
  978. next;
  979. }
  980. $plist->tofile($dir.basename($plist->{filename}));
  981. }
  982. my $something_changed = 0;
  983. for my $plist (@l) {
  984. my $orig = $plist->{original};
  985. if ($plist->{nonempty}) {
  986. if (defined $orig) {
  987. if (compare($dir.basename($plist->{filename}), $orig->{filename}) != 0) {
  988. print prettify($plist), " changed\n";
  989. $something_changed = 1;
  990. $plist->{changed} = 1;
  991. }
  992. } else {
  993. print prettify($plist), " is new\n";
  994. $something_changed = 1;
  995. $plist->{changed} = 1;
  996. }
  997. } else {
  998. if (defined $orig) {
  999. if ($plist->{isfrag}) {
  1000. print prettify($plist), " empty fragment: NOT writing it\n";
  1001. } else {
  1002. print prettify($plist), " empty\n";
  1003. $something_changed = 1;
  1004. $plist->{changed} = 1;
  1005. }
  1006. }
  1007. }
  1008. }
  1009. my $letsdie = 0;
  1010. if ($something_changed) {
  1011. for my $plist (@l) {
  1012. my $orig = $plist->{original};
  1013. if (defined $orig) {
  1014. if (-e $orig->{filename}.".orig") {
  1015. print prettify($orig),".orig present\n";
  1016. $letsdie = 1;
  1017. }
  1018. }
  1019. }
  1020. }
  1021. if ($letsdie) {
  1022. exit(1);
  1023. }
  1024. for my $plist (@l) {
  1025. my $orig = $plist->{original};
  1026. if ($plist->{changed}) {
  1027. if (defined $orig) {
  1028. rename($orig->{filename}, $orig->{filename}.".orig") or
  1029. die "Can't rename file ", prettify($orig),
  1030. "\n";
  1031. }
  1032. $plist->tofile($plist->{filename}) or
  1033. die "Can't write plist: ", prettify($plist), "\n";
  1034. }
  1035. }
  1036. }
  1037. # and rechecking libraries
  1038. for my $name (sort keys %{$subst->{l}}) {
  1039. next if $subst->{found}{$name};
  1040. print STDERR "WARNING: didn't find any library to match SHARED_LIBS $name\n";
  1041. }