check-lib-depends 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798
  1. #!/usr/bin/perl
  2. # $OpenBSD: check-lib-depends,v 1.29 2014/03/24 15:18:17 afresh1 Exp $
  3. # Copyright (c) 2004-2010 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. use strict;
  17. use warnings;
  18. use File::Spec;
  19. use OpenBSD::PackingList;
  20. use OpenBSD::SharedLibs;
  21. use OpenBSD::LibSpec;
  22. use OpenBSD::Temp;
  23. use OpenBSD::AddCreateDelete;
  24. use OpenBSD::Getopt;
  25. # FileSource: where we get the files to analyze
  26. package FileSource;
  27. # file system
  28. package FsFileSource;
  29. our @ISA = qw(FileSource);
  30. sub new
  31. {
  32. my ($class, $location) = @_;
  33. bless {location => $location }, $class
  34. }
  35. sub retrieve
  36. {
  37. my ($self, $state, $item) = @_;
  38. return $self->{location}.$item->fullname;
  39. }
  40. sub skip
  41. {
  42. }
  43. sub clean
  44. {
  45. }
  46. # package archive
  47. package PkgFileSource;
  48. our @ISA = qw(FileSource);
  49. sub new
  50. {
  51. my ($class, $handle, $location) = @_;
  52. bless {handle => $handle, location => $location }, $class;
  53. }
  54. sub prepare_to_extract
  55. {
  56. my ($self, $item) = @_;
  57. require OpenBSD::ArcCheck;
  58. my $o = $self->{handle}->next;
  59. $o->{cwd} = $item->cwd;
  60. if (!$o->check_name($item)) {
  61. die "Error checking name for $o->{name} vs. $item->{name}\n";
  62. }
  63. $o->{name} = $item->fullname;
  64. $o->{destdir} = $self->{location};
  65. return $o;
  66. }
  67. sub extracted_name
  68. {
  69. my ($self, $item) = @_;
  70. return $self->{location}.$item->fullname;
  71. }
  72. sub retrieve
  73. {
  74. my ($self, $state, $item) = @_;
  75. my $o = $self->prepare_to_extract($item);
  76. $o->create;
  77. return $self->extracted_name($item);
  78. }
  79. sub skip
  80. {
  81. my ($self, $item) = @_;
  82. my $o = $self->prepare_to_extract($item);
  83. $self->{handle}->skip;
  84. }
  85. sub clean
  86. {
  87. my ($self, $item) = @_;
  88. unlink($self->extracted_name($item));
  89. }
  90. # Recorder: how we keep track of which binary uses which library
  91. package Recorder;
  92. sub new
  93. {
  94. my $class = shift;
  95. return bless {}, $class;
  96. }
  97. sub reduce_libname
  98. {
  99. my ($self, $lib) = @_;
  100. $lib =~ s/^(.*\/)?lib(.*)\.so\.(\d+)\.\d+$/$2.$3/;
  101. return $lib;
  102. }
  103. sub libs
  104. {
  105. my $self = shift;
  106. return keys %$self;
  107. }
  108. sub record_rpath
  109. {
  110. }
  111. # SimpleRecorder: remember one single binary for each library
  112. package SimpleRecorder;
  113. our @ISA = qw(Recorder);
  114. sub record
  115. {
  116. my ($self, $lib, $filename) = @_;
  117. $self->{$self->reduce_libname($lib)} = $filename;
  118. }
  119. sub binary
  120. {
  121. my ($self, $lib) = @_;
  122. return $self->{$lib};
  123. }
  124. # AllRecorder: remember all binaries for each library
  125. package AllRecorder;
  126. our @ISA = qw(Recorder);
  127. sub record
  128. {
  129. my ($self, $lib, $filename) = @_;
  130. push(@{$self->{$self->reduce_libname($lib)}}, $filename);
  131. }
  132. sub binaries
  133. {
  134. my ($self, $lib) = @_;
  135. return @{$self->{$lib}};
  136. }
  137. sub binary
  138. {
  139. my ($self, $lib) = @_;
  140. return $self->{$lib}->[0];
  141. }
  142. sub dump
  143. {
  144. my ($self, $fh) = @_;
  145. for my $lib (sort $self->libs) {
  146. print $fh "$lib:\t\n";
  147. for my $binary (sort $self->binaries($lib)) {
  148. print $fh "\t$binary\n";
  149. }
  150. }
  151. }
  152. package DumpRecorder;
  153. our @ISA = qw(Recorder);
  154. sub record
  155. {
  156. my ($self, $lib, $filename) = @_;
  157. push(@{$self->{$filename}->{libs}}, $lib);
  158. }
  159. sub record_rpath
  160. {
  161. my ($self, $path, $filename) = @_;
  162. push(@{$self->{$filename}->{rpath}}, $path);
  163. }
  164. sub dump
  165. {
  166. my ($self, $fh) = @_;
  167. while (my ($binary, $v) = each %$self) {
  168. print $fh $binary;
  169. if (defined $v->{rpath}) {
  170. print $fh "(", join(':', @{$v->{rpath}}), ")";
  171. }
  172. print $fh ": ", join(',', @{$v->{libs}}), "\n";
  173. }
  174. }
  175. sub retrieve
  176. {
  177. my ($self, $state, $filename) = @_;
  178. open(my $fh, '<', $filename) or
  179. $state->fatal("Can't read #1: #2", $filename, $!);
  180. while (my $line = <$fh>) {
  181. chomp $line;
  182. if ($line =~ m/^(.*?)\:\s(.*)$/) {
  183. my ($binary, $libs) = ($1, $2);
  184. if ($binary =~ m/^(.*)\(.*\)$/) {
  185. $binary = $1;
  186. }
  187. my @libs = split(/,/, $libs);
  188. $self->{$binary}= \@libs;
  189. } else {
  190. $state->errsay("Can't parse #1", $line);
  191. }
  192. }
  193. close $fh;
  194. }
  195. # Issue: intermediate objects that record problems with libraries
  196. package Issue;
  197. sub new
  198. {
  199. my ($class, $lib, $binary, @packages) = @_;
  200. bless { lib => $lib, binary => $binary, packages => \@packages },
  201. $class;
  202. }
  203. sub stringize
  204. {
  205. my $self = shift;
  206. my $string = $self->{lib};
  207. if (@{$self->{packages}} > 0) {
  208. $string.=" from ".join(',', @{$self->{packages}});
  209. }
  210. return $string." ($self->{binary})";
  211. }
  212. sub do_record_wantlib
  213. {
  214. my ($self, $h) = @_;
  215. my $want = $self->{lib};
  216. $want =~ s/\.\d+$//;
  217. $h->{$want} = 1;
  218. }
  219. sub record_wantlib
  220. {
  221. }
  222. sub not_reachable
  223. {
  224. return 0;
  225. }
  226. sub print
  227. {
  228. my $self = shift;
  229. print $self->message, "\n";
  230. }
  231. package Issue::SystemLib;
  232. our @ISA = qw(Issue);
  233. sub message
  234. {
  235. my $self = shift;
  236. return "WANTLIB: ". $self->stringize. " (system lib)";
  237. }
  238. sub record_wantlib
  239. {
  240. &Issue::do_record_wantlib;
  241. }
  242. package Issue::DirectDependency;
  243. our @ISA = qw(Issue);
  244. sub message
  245. {
  246. my $self = shift;
  247. return "LIB_DEPENDS: ". $self->stringize;
  248. }
  249. package Issue::IndirectDependency;
  250. our @ISA = qw(Issue);
  251. sub message
  252. {
  253. my $self = shift;
  254. return "WANTLIB: ". $self->stringize;
  255. }
  256. sub record_wantlib
  257. {
  258. &Issue::do_record_wantlib;
  259. }
  260. package Issue::NotReachable;
  261. our @ISA = qw(Issue);
  262. sub message
  263. {
  264. my $self = shift;
  265. return "Missing lib: ". $self->stringize. " (NOT REACHABLE)";
  266. }
  267. sub not_reachable
  268. {
  269. my $self = shift;
  270. return "Bogus WANTLIB: ". $self->stringize. " (NOT REACHABLE)";
  271. }
  272. package MyFile;
  273. our @ISA = qw(OpenBSD::PackingElement::FileBase);
  274. sub fullname
  275. {
  276. my $self = shift;
  277. return $self->{name};
  278. }
  279. package OpenBSD::PackingElement;
  280. sub record_needed_libs
  281. {
  282. }
  283. sub find_libs
  284. {
  285. }
  286. sub register_libs
  287. {
  288. }
  289. sub depwalk
  290. {
  291. }
  292. package OpenBSD::PackingElement::Wantlib;
  293. sub register_libs
  294. {
  295. my ($item, $t) = @_;
  296. my $name = $item->{name};
  297. $name =~ s/^(.*\/)?(.*)\.(\d+)\.\d+$/$2.$3/;
  298. $t->{$name} = 1;
  299. }
  300. package OpenBSD::PackingElement::Lib;
  301. sub register_libs
  302. {
  303. my ($item, $t) = @_;
  304. if ($item->fullname =~ m/^(.*\/)?lib(.*)\.so\.(\d+)\.\d+$/) {
  305. $t->{"$2.$3"} = 2;
  306. }
  307. }
  308. package OpenBSD::PackingElement::FileBase;
  309. sub find_libs
  310. {
  311. my ($item, $dest, $special) = @_;
  312. my $fullname = $item->fullname;
  313. if (defined $special->{$fullname}) {
  314. for my $lib (@{$special->{$fullname}}) {
  315. $dest->record($lib, $fullname);
  316. }
  317. }
  318. }
  319. sub run_objdump
  320. {
  321. my ($state, $n) = @_;
  322. my $cmd;
  323. if ($state->{old}) {
  324. open($cmd, "-|", "ldd", "-f", "NEEDED lib%o.so.%m.%n\n", $n) or
  325. $state->fatal("run ldd: #1", $!);
  326. } else {
  327. unless (open($cmd, '-|')) {
  328. open(STDERR, '>', '/dev/null');
  329. exec('objdump', '-p', $n) or
  330. $state->fatal("exec objdump: #!", $!);
  331. }
  332. }
  333. return $cmd;
  334. }
  335. sub parse_objdump
  336. {
  337. my ($cmd, $dest, $fullname) = @_;
  338. my @l = ();
  339. while (my $line = <$cmd>) {
  340. if ($line =~ m/^\s+NEEDED\s+(.*?)\s*$/) {
  341. my $lib = $1;
  342. push(@l, $lib);
  343. # detect linux binaries
  344. if ($lib eq 'libc.so.6') {
  345. return ();
  346. }
  347. } elsif ($line =~ m/^\s+RPATH\s+(.*)\s*$/) {
  348. my $p = {};
  349. for my $path (split /\:/, $1) {
  350. next if $path eq '/usr/local/lib';
  351. next if $path eq '/usr/X11R6/lib';
  352. next if $path eq '/usr/lib';
  353. $p->{$path} = 1;
  354. }
  355. for my $path (keys %$p) {
  356. $dest->record_rpath($path, $fullname);
  357. }
  358. }
  359. }
  360. return @l;
  361. }
  362. sub record_needed_libs
  363. {
  364. my ($item, $state, $dest, $source) = @_;
  365. my $fullname = File::Spec->canonpath($item->fullname);
  366. my $linux_bin = 0;
  367. my $freebsd_bin = 0;
  368. if ($fullname =~ m,^/usr/local/emul/(?:redhat|fedora)/,) {
  369. $linux_bin = 1;
  370. }
  371. if ($fullname =~ m,^/usr/local/emul/freebsd/,) {
  372. $freebsd_bin = 1;
  373. }
  374. if ($linux_bin || $freebsd_bin || $item->{symlink} || $item->{link}) {
  375. $source->skip($item);
  376. return;
  377. }
  378. my $n = $source->retrieve($state, $item);
  379. my $cmd = run_objdump($state, $n);
  380. for my $lib (parse_objdump($cmd, $dest, $fullname)) {
  381. # don't look for modules
  382. next if $lib =~ m/\.so$/;
  383. $dest->record($lib, $fullname);
  384. }
  385. close($cmd);
  386. $source->clean($item);
  387. }
  388. package OpenBSD::PackingElement::Dependency;
  389. sub depwalk
  390. {
  391. my ($self, $h) = @_;
  392. $h->{$self->{def}} = $self->{pkgpath};
  393. }
  394. package CheckLibDepends::State;
  395. our @ISA = qw(OpenBSD::AddCreateDelete::State);
  396. sub handle_options
  397. {
  398. my $state = shift;
  399. $state->SUPER::handle_options('od:fB:F:s:O:',
  400. '[-o] [-d pkgrepo] [-B destdir] [-s source] [-O dest]');
  401. $state->{destdir} = $state->opt('B') // $state->opt('F');
  402. $state->{destdir} //= '/';
  403. $state->{destdir}.= '/' unless $state->{destdir} =~ m|/$|;
  404. $state->{dest} = $state->opt('O');
  405. $state->{source} = $state->opt('s');
  406. $state->{full} = $state->opt('f');
  407. $state->{repository} = $state->opt('d');
  408. $state->{old} = $state->opt('o');
  409. }
  410. sub init
  411. {
  412. my $self = shift;
  413. $self->{errors} = 0;
  414. $self->SUPER::init(@_);
  415. }
  416. sub context
  417. {
  418. my ($self, $pkgname) = @_;
  419. $self->{context} = $pkgname;
  420. }
  421. sub error
  422. {
  423. my $state = shift;
  424. $state->{errors}++;
  425. $state->say_with_context(@_);
  426. }
  427. sub say_with_context
  428. {
  429. my $state = shift;
  430. if ($state->{context}) {
  431. $state->say("#1:", $state->{context});
  432. undef $state->{context};
  433. }
  434. $state->say(@_);
  435. }
  436. package CheckLibDepends;
  437. use OpenBSD::PackageInfo;
  438. use File::Path;
  439. use File::Find;
  440. my $dependencies = {};
  441. sub register_dependencies
  442. {
  443. my $plist = shift;
  444. my $pkgname = $plist->pkgname;
  445. my $h = {};
  446. $dependencies->{$pkgname} = $h;
  447. $plist->depwalk($h);
  448. }
  449. sub get_plist
  450. {
  451. my ($self, $state, $pkgname, $pkgpath) = @_;
  452. # try physical package
  453. if (defined $state->{repository}) {
  454. my $location = "$state->{repository}/$pkgname.tgz";
  455. my $true_package = $state->repo->find($location);
  456. if ($true_package) {
  457. my $dir = $true_package->info;
  458. if (-d $dir) {
  459. my $plist = OpenBSD::PackingList->fromfile($dir.CONTENTS);
  460. $true_package->close;
  461. rmtree($dir);
  462. return $plist;
  463. }
  464. }
  465. }
  466. # ask the ports tree
  467. $state->say("Asking ports for dependency #1(#2)", $pkgname, $pkgpath);
  468. my $portsdir = $ENV{PORTSDIR} || "/usr/ports";
  469. my $make = $ENV{MAKE} || "make";
  470. open my $fh, "cd $portsdir && env -i SUBDIR=$pkgpath ECHO_MSG=: make print-plist-with-depends |" or return undef;
  471. my $plist = OpenBSD::PackingList->read($fh);
  472. close $fh;
  473. return $plist;
  474. }
  475. sub handle_dependency
  476. {
  477. my ($self, $state, $pkgname, $pkgpath) = @_;
  478. my $plist = $self->get_plist($state, $pkgname, $pkgpath);
  479. if (!defined $plist || !defined $plist->pkgname) {
  480. $state->errsay("Error: can't solve dependency for #1(#2)",
  481. $pkgname, $pkgpath);
  482. return;
  483. }
  484. if ($plist->pkgname ne $pkgname) {
  485. delete $dependencies->{$pkgname};
  486. for my $p (keys %$dependencies) {
  487. if ($dependencies->{$p}->{$pkgname}) {
  488. $dependencies->{$p}->{$plist->pkgname} =
  489. $dependencies->{$p}->{$pkgname};
  490. delete $dependencies->{$p}->{$pkgname};
  491. }
  492. }
  493. }
  494. register_dependencies($plist);
  495. OpenBSD::SharedLibs::add_libs_from_plist($plist);
  496. return $plist->pkgname;
  497. }
  498. sub lookup_library
  499. {
  500. my ($dir, $spec) = @_;
  501. my $libspec = OpenBSD::LibSpec->from_string($spec);
  502. my $r = OpenBSD::SharedLibs::lookup_libspec($dir, $libspec);
  503. if (!defined $r) {
  504. return ();
  505. } else {
  506. return map {$_->origin} @$r;
  507. }
  508. }
  509. sub report_lib_issue
  510. {
  511. my ($self, $state, $plist, $lib, $binary) = @_;
  512. OpenBSD::SharedLibs::add_libs_from_system('/');
  513. my $libspec = "$lib.0";
  514. my $want = $lib;
  515. $want =~ s/\.\d+$//;
  516. for my $dir (qw(/usr /usr/X11R6)) {
  517. my @r = lookup_library($dir, $libspec);
  518. if (grep { $_ eq 'system' } @r) {
  519. return Issue::SystemLib->new($lib, $binary);
  520. }
  521. }
  522. while (my ($p, $pkgpath) = each %{$dependencies->{$plist->pkgname}}) {
  523. next if defined $dependencies->{$p};
  524. $self->handle_dependency($state, $p, $pkgpath);
  525. }
  526. my @r = lookup_library('/usr/local', $libspec);
  527. if (@r > 0) {
  528. for my $p (@r) {
  529. if (defined $dependencies->{$plist->pkgname}->{$p}) {
  530. return Issue::DirectDependency->new($lib, $binary, $p);
  531. }
  532. }
  533. }
  534. # okay, let's walk for WANTLIB
  535. my @todo = %{$dependencies->{$plist->pkgname}};
  536. my $done = {};
  537. while (@todo >= 2) {
  538. my $path = pop @todo;
  539. my $dep = pop @todo;
  540. next if $done->{$dep};
  541. $done->{$dep} = 1;
  542. $dep = $self->handle_dependency($state, $dep, $path)
  543. unless defined $dependencies->{$dep};
  544. next if !defined $dep;
  545. $done->{$dep} = 1;
  546. push(@todo, %{$dependencies->{$dep}});
  547. }
  548. @r = lookup_library(OpenBSD::Paths->localbase, $libspec);
  549. for my $p (@r) {
  550. if (defined $done->{$p}) {
  551. return Issue::IndirectDependency->new($lib, $binary, $p);
  552. }
  553. }
  554. return Issue::NotReachable->new($lib,, $binary, @r);
  555. }
  556. sub print_list
  557. {
  558. my ($self, $state, $head, $h) = @_;
  559. my $line = "";
  560. for my $k (sort keys %$h) {
  561. if (length $line > 50) {
  562. $state->say_with_context("#1#2", $head, $line);
  563. $line = "";
  564. }
  565. $line .= ' '.$k;
  566. }
  567. if ($line ne '') {
  568. $state->say_with_context("#1#2", $head, $line);
  569. }
  570. }
  571. sub analyze
  572. {
  573. my ($self, $state, $plist, $source) = @_;
  574. my $pkgname = $plist->pkgname;
  575. if ($plist->fullpkgpath) {
  576. $state->context($pkgname."(".$plist->fullpkgpath.")");
  577. } else {
  578. $state->context($pkgname);
  579. }
  580. my $needed_libs = $state->{full} ? AllRecorder->new : SimpleRecorder->new;
  581. my $has_libs = {};
  582. if ($state->{source}) {
  583. my $special = DumpRecorder->new;
  584. $special->retrieve($state, $state->{source});
  585. $plist->find_libs($needed_libs, $special);
  586. } else {
  587. $plist->record_needed_libs($state, $needed_libs, $source);
  588. }
  589. $plist->register_libs($has_libs);
  590. if (!defined $dependencies->{$pkgname}) {
  591. register_dependencies($plist);
  592. OpenBSD::SharedLibs::add_libs_from_plist($plist);
  593. }
  594. my $r = { wantlib => {}, libdepends => {}, wantlib2 => {} };
  595. for my $lib (sort $needed_libs->libs) {
  596. my $fullname = $needed_libs->binary($lib);
  597. if (!defined $has_libs->{$lib}) {
  598. my $issue = $self->report_lib_issue($state, $plist,
  599. $lib, $fullname);
  600. $state->error("#1", $issue->message);
  601. $issue->record_wantlib($r->{wantlib});
  602. } elsif ($has_libs->{$lib} == 1) {
  603. my $issue = $self->report_lib_issue($state, $plist,
  604. $lib, $fullname);
  605. if ($issue->not_reachable) {
  606. $state->error("#1", $issue->not_reachable);
  607. }
  608. }
  609. $has_libs->{$lib} = 2;
  610. }
  611. my $extra = {};
  612. for my $k (keys %$has_libs) {
  613. my $v = $has_libs->{$k};
  614. next if $v == 2;
  615. $extra->{$k} = 1;
  616. }
  617. $self->print_list($state, "Extra: ", $extra);
  618. $self->print_list($state, "\tWANTLIB +=", $r->{wantlib});
  619. if ($state->{full}) {
  620. $needed_libs->dump(\*STDOUT);
  621. }
  622. }
  623. sub do_pkg
  624. {
  625. my ($self, $state, $pkgname) = @_;
  626. my $true_package = $state->repo->find($pkgname);
  627. return 0 unless $true_package;
  628. my $dir = $true_package->info;
  629. # twice read
  630. return 0 unless -d $dir;
  631. my $plist = OpenBSD::PackingList->fromfile($dir.CONTENTS);
  632. if ($state->{source}) {
  633. $self->analyze($state, $plist);
  634. } elsif ($state->{destdir} ne '/') {
  635. $self->analyze($state, $plist,
  636. FsFileSource->new($state->{destdir}));
  637. } else {
  638. my $temp = OpenBSD::Temp->dir;
  639. $self->analyze($state, $plist,
  640. PkgFileSource->new($true_package, $temp));
  641. rmtree($temp);
  642. }
  643. $true_package->close;
  644. $true_package->wipe_info;
  645. $plist->forget;
  646. return 1;
  647. }
  648. sub do_plist
  649. {
  650. my ($self, $state) = @_;
  651. my $plist = OpenBSD::PackingList->read(\*STDIN);
  652. if (!defined $plist->{name}) {
  653. $state->error("Error reading plist");
  654. return;
  655. } else {
  656. $self->analyze($state, $plist,
  657. FsFileSource->new($state->{destdir}));
  658. }
  659. }
  660. sub main
  661. {
  662. my $self = shift;
  663. my $state = CheckLibDepends::State->new('check-lib-depends');
  664. $state->handle_options;
  665. my $fs = $state->{destdir};
  666. if ($state->{dest}) {
  667. my $recorder = DumpRecorder->new;
  668. my $cwd = $fs;
  669. my $source = FsFileSource->new($fs);
  670. find({
  671. wanted => sub {
  672. return if -l $_;
  673. return unless -f _;
  674. my $name = $_;
  675. $name =~ s/^\Q$fs\E/\//;
  676. # XXX hack FileBase object;
  677. my $i = bless {name => $name}, "MyFile";
  678. $i->record_needed_libs($state, $recorder, $source);
  679. },
  680. no_chdir => 1 }, $fs);
  681. if ($state->{dest}) {
  682. open my $fh, '>', $state->{dest} or
  683. $state->fatal("Can't write to #1: #2",
  684. $state->{dest}, $!);
  685. $recorder->dump($fh);
  686. close $fh;
  687. } else {
  688. $recorder->dump(\*STDOUT);
  689. }
  690. exit(0);
  691. }
  692. if (@ARGV == 0 && ($state->{destdir} ne '/' || $state->{source})) {
  693. $self->do_plist($state);
  694. } else {
  695. $state->progress->for_list("Scanning", \@ARGV,
  696. sub {
  697. $self->do_pkg($state, shift);
  698. });
  699. }
  700. exit($state->{errors} ? 1 : 0);
  701. }
  702. $OpenBSD::Temp::tempbase = "/tmp";
  703. __PACKAGE__->main;