| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483 |
- #!/usr/bin/perl --
- #
- # dpkg: Debian GNU/Linux package maintenance utility
- #
- # Copyright (C) 1994 Matt Welsh <mdw@sunsite.unc.edu>
- # Copyright (C) 1994 Carl Streeter <streeter@cae.wisc.edu>
- # Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
- # Copyright (C) 1994 Ian Jackson <iwj10@cus.cam.ac.uk>
- #
- # dpkg is free software; you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as
- # published by the Free Software Foundation; either version 2,
- # or (at your option) any later version.
- #
- # dpkg is distributed in the hope that it will be useful, but
- # WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- #
- # You should have received a copy of the GNU General Public
- # License along with dpkg; if not, write to the Free Software
- # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- #
- $version= '0.93.15'; # This line modified by Makefile
- sub version {
- print STDERR <<END;
- Debian GNU/Linux \`dpkg\' package handling tool version $version.
- Copyright (C)1994 Matt Welsh, Carl Streeter, Ian Murdock, Ian Jackson.
- This is free software; see the GNU General Public Licence version 2
- or later for copying conditions. There is NO warranty.
- END
- }
- sub usage {
- print STDERR <<END;
- Usage: dpkg -i|--install <opts> <.deb file name> ... | -a|--auto <dir> ...
- dpkg --unpack <opts> <.deb file name> ... | -a|--auto <dir> ...
- dpkg -A|--avail <opts> <.deb file name> ... | -a|--auto <dir> ...
- dpkg --configure <opts> <package name> ... | -a|--auto
- dpkg -r|--remove <opts> <package name> ... | -a|--auto
- dpkg -l|--list <status select> [<regexp> ...]
- dpkg -s|--status <status select> [<package-name> ...]
- dpkg -S|--search <glob pattern> ...
- dpkg -b|--build|-c|--contents|-e|--control|--info|-f|--field|
- -x|--extract|-X|--vextract ... (see dpkg-deb --help)
- Options: --purge --control-quiet --control-verbose --version --help
- -R|--root=<directory> --admindir=<directory> --instdir=<directory>
- --no-keep-old-conf --no-keep-new-conf -N|--no-also-select
- --ignore-depends=<package name>,...
- --conf-(same|diff|all)-(new|old|promptnew|promptold)
- --force-<thing>,<thing>,... --no-force-...|--refuse-...
- Status selections: --isok-[o][h] (OK, Hold; alternatives are y, n)
- --want-[u][i][d][p] (Unknown, Install, Deinstall, Purge)
- --stat-[nupircNO] (Not, Unpacked, Postinst-failed, Installed, Removal-failed,
- Config-files, Not/Config-files, Not/Config-files/Installed)
- Force things: conflicts, depends, downgrade, depends-version, prermfail,
- configure-any, hold, extractfail
- (default is --no-force everything, except --force-downgrade)
- Use \`$dselect\' for user-friendly package management.
- END
- }
- $instroot= '';
- $controlwarn = 1;
- $estatus = 0;
- $filename_pattern = "*.deb";
- %force= ( 'conflicts',0, 'depends',0, 'depends-version',0, 'downgrade',1,
- 'prermfail',0, 'postrmfail',0, 'hold',0, 'configure-any',0,
- 'extractfail',0 );
- %selectmap_h= ('o','ok', 'h','hold', 'y','ok', 'n','hold');
- %selectmap_w= ('u', 'unknown', 'i', 'install', 'd', 'deinstall', 'p', 'purge');
- %selectmap_s= ('n', 'not-installed',
- 'u', 'unpacked',
- 'p', 'postinst-failed',
- 'i', 'installed',
- 'r', 'removal-failed',
- 'c', 'config-files',
- 'n', 'not-installed,config-files',
- 'o', 'not-installed,config-files,installed');
- %selectthings= ('isok','h', 'want','w', 'stat','s');
- require 'lib.pl'; # This line modified by Makefile
- $0 =~ m|[^/]+$|; $name = $dpkg;
- $|=1;
- umask(022);
- $action= 'none';
- %myabbrevact= ('i','install', 'r','remove', 'A','avail',
- 'S','search', 'l','list', 's','status');
- # $conf...[0] corresponds to `same', 1 to diff
- $confusenew[0]= 0; $confprompt[0]= 0;
- $confusenew[1]= 1; $confprompt[1]= 1;
- # Ie, default is to prompt only when hashes differ,
- # and to use new when hashes differ
- while ($ARGV[0] =~ m/^-/) {
- $_= shift(@ARGV);
- $noptsdone++;
- if (m/^--$/) {
- $noptsdone--; last;
- } elsif (m/^--(install|remove|unpack|configure|avail|list|status)$/) {
- &setaction($1);
- } elsif (m/^--(build|contents|control|info|field|extract|vextract)$/) {
- $noptsdone--; &backend($1);
- } elsif (m/^--ignore-depends=($packagere(,$packagere)*)$/o) {
- grep($ignore_depends{$_}=1, split(/,/,$1));
- } elsif (m/^--(force|no-force|refuse)-/) {
- $fvalue= ($1 eq 'force');
- for $fv (split(/,/,$')) {
- defined($force{$fv}) || &badusage("unknown --force option \`$fv'");
- $force{$fv}= $fvalue;
- }
- } elsif (m/^--conf-(same|diff|all)-(new|old|promptnew|promptold)$/) {
- $new= $2 eq 'new' || $2 eq 'promptnew';
- $prompt= $2 eq 'promptnew' || $2 eq 'promptold';
- if ($1 ne 'same') { $confusenew[1]= $new; $confprompt[1]= $prompt; }
- if ($1 ne 'diff') { $confusenew[0]= $new; $confprompt[0]= $prompt; }
- } elsif (m/^--(\w+)-(\w+)$/ && defined($selectthings{$1})) {
- $thisname= $1;
- $thisthing= $selectthings{$thisname};
- $_=$2;
- eval '%thismap= %selectmap_'.$thisthing;
- while (s/^.//) {
- if (!defined($thismap{$&})) {
- &badusage("unknown status letter $& for status field $thisname");
- }
- $thiscodes= $thismap{$&};
- $selectdo.= "undef \$select_$thisthing;";
- for $v (split(m/,/, $thiscodes)) {
- $selectdo .= "\$select_$thisthing{'$v'}=1;";
- }
- }
- } elsif (m/^--root=/) {
- $instroot=$'; &setadmindir("$instroot/$orgadmindir");
- } elsif (m/^--admindir=/) {
- &setadmindir("$'");
- } elsif (m/^--instdir=/) {
- $instroot=$';
- } elsif (m/^--auto$/) {
- $auto= 1;
- } elsif (m/^--purge$/) {
- $purge= 1;
- } elsif (m/^--skip-same-version$/) {
- print STDERR
- "Warning: dpkg --skip-same-version not implemented, will process\n".
- " process even packages the same version of which is installed.\n";
- } elsif (m/^--no-also-select$/) {
- $noalsoselect= 1;
- } elsif (m/^--control-verbose$/) {
- $controlwarn= 1;
- } elsif (m/^--control-quiet$/) {
- $controlwarn= 0;
- } elsif (m/^--no-keep-old-conf$/) {
- $nokeepold= 1;
- } elsif (m/^--no-keep-new-conf$/) {
- $nokeepnew= 1;
- } elsif (m/^--succinct-prompts$/) {
- $succinct= 1;
- } elsif (m/^--debug$/) {
- $debug= 1;
- } elsif (m/^--help$/) {
- &usage; exit(0);
- } elsif (m/^--version$/) {
- &version; exit(0);
- } elsif (m/^--/) {
- &badusage("unknown option \`$_'");
- } else {
- s/^-//; $noptsdone--;
- while (s/^.//) {
- $noptsdone++;
- if (defined($myabbrevact{$&})) {
- &setaction($myabbrevact{$&});
- } elsif (defined($debabbrevact{$&})) {
- $noptsdone--; &backend($debabbrevact{$&});
- } elsif ($& eq 'a') {
- $auto= 1;
- } elsif ($& eq 'D') {
- $debug= 1;
- } elsif ($& eq 'N') {
- $noautoselect= 1;
- } elsif ($& eq 'R') {
- s/^=// || &badusage("missing value for -R=<dir> option");
- $instroot= $_; &setadmindir("$instroot/$orgadmindir"); $_='';
- } else {
- &badusage("unknown option \`-$&'");
- }
- }
- }
- }
- $action eq 'none' && &badusage("an action must be specified");
- &debug("arguments parsed");
- #*** list, status or search - the nonactive operations ***#
- if ($action eq 'list' || $action eq 'status') {
- &database_start;
- if ($action eq 'list' || !@ARGV) {
- &selectall(*selectmap_h,*select_h);
- &selectall(*selectmap_w,*select_w);
- &selectall(*selectmap_s,*select_s);
- if (@ARGV) { $select_s{'not-installed'}=0; }
- }
- $ecode= 0;
- if ($action eq 'status') {
- for ($i=0;$i<=$#keysortorder;$i++) {
- $keysortorder{$keysortorder[$i]}= sprintf("%6d ",$i);
- # &debug("set $i: $keysortorder[$i], sortorder ".
- # "\`$keysortorder{$keysortorder[$i]}'");
- }
- @ARGV= &applyselcrit(sort keys %st_p21) unless @ARGV;
- for $p (@ARGV) {
- if (!$st_p21{$p}) {
- print(STDERR "$name: no information available about package $p\n")
- || &bombout("writing to stderr: $!");
- $ecode= 1;
- }
- print("Package: $p\n",
- "Status: $st_p2w{$p} $st_p2h{$p} $st_p2s{$p}\n") || &outerr;
- for $k (sort { $keysortorder{$a}.$a cmp $keysortorder{$b}.$b; }
- keys %all_k21) {
- # &debug("field $k, sortorder \`$keysortorder{$k}'");
- next unless defined($st_pk2v{$p,$k});
- $v= $st_pk2v{$p,$k}; next unless length($v);
- if ($k eq 'conffiles' || $k eq 'list') {
- $v= sprintf("(%d files, not listed)",
- scalar(grep(m/\S/, split(/\n/,$v))));
- }
- print("$k: $v\n") || &outerr;
- }
- if (defined($av_p21{$p})) {
- print("\n\`Available' version of package $p, where different:\n")
- || &outerr;
- for $k (keys %all_k21) {
- next unless defined($av_pk2v{$p,$k});
- $v= $st_pk2v{$p,$k}; next unless length($v);
- $u= $st_pk2v{$p,$k}; next if $u eq $v;
- print("$k: $v\n") || &outerr;
- }
- print("\n") || &outerr;
- }
- }
- } else { # $action eq 'list'
- $listhead=0;
- if (@ARGV) {
- for $r (@ARGV) {
- &listinfo(&applyselcrit(sort grep(m/$r/,keys %st_p21)));
- }
- } else {
- undef $r;
- &listinfo(&applyselcrit(sort keys %st_p21));
- }
- }
- &database_finish;
- exit($ecode);
- }
- sub listinfo {
- if (!@_) {
- print(STDERR
- defined($r) ?
- "No selected packages found matching regexp \`$r'.\n" :
- "No packages matched selection criteria.\n") ||
- &bombout("writing to stderr: $!");
- return;
- }
- if (!$listhead) {
- print <<END
- Err? Name Version Rev Description
- | Status=Not/Unpacked/Postinst-failed/Installed/Removal-failed/Config-files
- |/ Desired=Unknown/Install/Deinstall/Purge
- ||/ | | | |
- +++-============-==========-===-===============================================
- END
- || &outerr;
- $listhead= 1;
- }
- for $p (@_) {
- $des= $st_pk2v{$p,'description'};
- $des= $` if $des =~ m/\n/;
- printf("%s%.1s%.1s %-12.12s %-10.10s %-3.3s %-47.47s\n",
- $st_p2h{$p} eq 'hold' ? 'x' : ' ', $st_p2s{$p}, $st_p2w{$p},
- $p, $st_pk2v{$p,'version'}, $st_pk2v{$p,'package_revision'},
- $des);
- }
- }
- sub applyselcrit {
- &debug("sel from @_");
- for $f (@_) { &debug("$f :$st_p2s{$f},$select_s{$st_p2s{$f}}:$st_p2w{$f},$select_w{$st_p2w{$f}}:$st_p2h{$f},$select_h{$st_p2h{$f}}:"); }
- @ascr= grep($select_s{$st_p2s{$_}} &&
- $select_w{$st_p2w{$_}} &&
- $select_h{$st_p2h{$_}},
- @_);
- &debug("sel gave @ascr");
- @ascr;
- }
- sub selectall {
- local (*map, *sel) = @_;
- local ($v);
- for $v (values %map) {
- next if m/,/;
- $sel{$v}=1;
- }
- }
- if ($action eq 'search') {
- @ARGV || &badusage("need at least one glob pattern for --$action");
- &database_start;
- while (@ARGV) {
- $orgpat= $_= shift(@ARGV);
- s/\W/\\$&/g;
- s|\\\*\\\*|.*|g;
- s|\\\*|[^/]*|g;
- s|\\\?|[^/]|g;
- $pat= $_; $f=0;
- for $p (sort keys %st_p21) {
- $s= $st_p2s{$p};
- next if $s eq 'not-installed' || $s eq 'config-files';
- &filesinpackage($arg, $package);
- @ilist= grep(m/^$pat$/,@ilist);
- next unless @ilist;
- $f=1;
- for $_ (@ilist) { print("$p: $_\n") || &outerr; }
- }
- if (!$f) {
- print(STDERR "No packages found containing \`$orgpat'.\n")
- || &bombout("writing to stderr: $!");
- $ecode= 1;
- }
- }
- &database_finish;
- exit($ecode);
- }
- #*** lock and read in databases ***#
- &database_start;
- &debug("databases read");
- #*** derive argument list for --auto ***#
- if ($auto) {
- if ($action eq 'install' || $action eq 'unpack' || $action eq 'avail') {
- @ARGV || &badusage("need at least one directory for --$action --auto");
- pipe(RP,WP) || &bombout("create pipe for \`find': $!");
- defined($c= fork) || &bombout("fork for \`find': $!");
- if (!$c) {
- close(RP); open(STDOUT,">& WP"); close(WP);
- exec('find',@ARGV,'-name',$filename_pattern,'-type','f','-print0');
- die "$name: could not exec \`find': $!";
- }
- close(WP);
- $/="\0"; @ARGV= <RP>; $/="\n";
- eof || &bombout("read filenames from \`find': $!");
- close(RP);
- $!=0; waitpid($c,0) eq $c || &bombout("wait for \`find' failed: $!");
- $? && &bombout("\`find' process returned error code ".&ecode);
- @ARGV || &bombout("no packages found to $action");
- } else {
- @ARGV && &badusage("no package names may be specified with --$action --auto");
- if ($action eq 'remove') {
- eval 'sub condition {
- $wants eq "deinstall" || $wants eq "purge" || return 0;
- $cstatus eq "not-installed" && return 0;
- $cstatus eq "config-files" && $wants eq "deinstall" && return 0;
- return 1;
- } 1;' || &internalerr("sub condition: $@");
- } elsif ($action eq 'configure') {
- eval 'sub condition {
- $wants eq "install" || return 0;
- $cstatus eq "unpacked" || $cstatus eq "postinst-failed" || return 0;
- return 1;
- } 1;' || &internalerr("sub condition: $@");
- } else {
- &internalerr("unknown auto nonames action $action");
- }
- for $p (keys %st_p21) {
- next if $st_p2h{$p} eq 'hold';
- $wants= $st_p2w{$p}; $cstatus= $st_p2s{$p};
- next unless &condition;
- push(@ARGV,$p);
- }
- }
- &debug("auto: arglist @ARGV");
- } else {
- @ARGV || &badusage("need a list of packages or filenames");
- }
- if ($action eq 'install' || $action eq 'unpack') {
- grep(s:^[^/.]:./$&:, @ARGV); # Sanitise filenames
- }
- &debug("action: $action; arglist @ARGV");
- #*** actually do things ***#
- for $arg (@ARGV) {
- $package= ''; @undo=();
- &debug("&do_$action($arg)");
- if (!eval "&do_$action(\$arg); 1;") { &handleerror || last; }
- &checkpointstatus;
- }
- &checkpointstatus;
- if (!$abort) {
- &debug("&middle_$action($arg)");
- if (!eval "&middle_$action; 1;") { print STDERR $@; $abort=1; }
- }
- &checkpointstatus;
- if (!$abort) {
- while (@deferred) {
- $arg= shift(@deferred); $package= ''; @undo=();
- &debug("&deferred_$action($arg) ($dependtry: $sincenothing)");
- if (!eval "&deferred_$action(\$arg); 1;") { &handleerror || last; }
- &checkpointstatus;
- }
- &checkpointstatus;
- }
- if ($errors) {
- print STDERR "$name: $errors errors occurred.\n";
- $estatus= 1;
- }
- &database_finish;
- &cleanup;
- exit($estatus);
- #*** useful subroutines for main control section ***#
- sub handleerror {
- print STDERR $@;
- if (length($package) && defined($st_p21{$package})) {
- $st_p2h{$package}='hold'; &amended_status($package);
- }
- $errors++;
- if ($errors >20) { print STDERR "$name: too many errors, halting\n"; return 0; }
- return !$abort;
- }
- sub checkpointstatus {
- return unless keys %statusupdated;
- &amended_status(keys %statusupdated);
- undef %statusupdated;
- }
- sub backend {
- &setaction('');
- ($noptsdone) && &badusage("action \`$_[0]' must be first argument");
- &debug("backend --$_[0]");
- exec($backend, "--$_[0]", @ARGV);
- &bombout("unable to run $backend: $!");
- }
- sub setaction {
- $action eq 'none' || &badusage("conflicting actions \`$action' and \`$1'");
- $action= $_[0];
- }
- #*** error handlers for use in actions ***#
- sub warn { warn "$name - warning: @_\n"; }
- sub subcriterr { warn "$name - subcritical error: @_\n"; $estatus=1; }
- sub error { &acleanup; die "$name - error: @_\n"; }
- sub internalerr { &acleanup; die "$name - internal error, please report: @_\n"; }
- sub fatalerr { &acleanup; die "$name - fatal error, halting: @_\n"; $abort=1; }
- sub corruptingerr {
- local ($corruptingerr)= @_;
- &acleanup;
- die "$name - horrible error: $corruptingerr;\n".
- "Package manager data is now out of step with installed system.\n".
- "Please re-install \`$package' to ensure system consistency!\n".
- "(Seek assistance from an expert if problems persist.)\n";
- $abort=1;
- }
- sub forcibleerr {
- local ($msg,@forces) = @_;
- if (@forces= grep($force{$_},@forces)) {
- &warn("$msg (proceeding due to --force-$forces[0])");
- } else {
- &error("$msg (skipping this package)");
- }
- }
- sub acleanup {
- while (@undo) {
- eval(pop(@undo));
- $@ && print STDERR "error while cleaning up: $@";
- }
- }
- #*** --install ***#
- sub do_install {
- &do_unpack($arg);
- $arg= $package;
- &do_configure($arg);
- }
- sub deferred_install { &deferred_configure; }
- sub middle_install { &middle_configure }
- #*** --avail ***#
- sub do_avail {
- unlink($controli);
- if ($! != &ENOENT) {
- system('rm','-rf',$controli);
- unlink($controli);
- $! == &ENOENT || &fatalerr("unable to get rid of $controli: $!");
- }
- &debug("extract control $backend --control $arg $controli");
- $!=0; system($backend,"--control",$arg,$controli);
- $? && &error("$arg: could not extract control information (".&ecode.")");
- open(CONTROL,"$controli/control") ||
- &error("$arg: corrupt - unable to read control file: $!");
- &parse_control("$arg");
- for $k (keys %cf_k2v) {
- $av_pk2v{$p,$k}= $cf_k2v{$k};
- }
- for $k (@nokeepfields) {
- delete $av_pk2v{$p,$k} unless defined($cf_k2v{$k});
- }
- &amended_available($p);
- $package=$p;
- }
- sub deferred_avail { }
- sub middle_avail { }
- #*** --unpack ***#
- sub middle_unpack { }
- sub do_unpack {
- &do_avail;
- $cstatus= $st_p2s{$package};
- if ($st_p2w{$package} ne 'install') {
- if (!$noalsoselect) {
- $st_p2w{$package}= 'install'; $statusupdated{$package}= 1;
- print STDOUT "Selecting previously deselected package $package.\n";
- } else {
- print STDOUT "Skipping deselected package $package.\n";
- return;
- }
- }
- for $tp (split(/,/, $av_pk2v{$package,'conflicts'})) {
- $tp =~ s/^\s*//; $tp =~ s/\s+$//;
- ($tps, $rightver, $inst, $want, $tpp)= &installationstatus($tp);
- unless ($tps eq 'not-installed' || $tps eq 'config-files' || !$rightver) {
- &forcibleerr("$arg: conflicts with package $tpp ($want),".
- " found $inst on system",
- 'conflicts');
- }
- }
- if ($cstatus eq 'installed') {
- if (&compare_verrevs($av_pk2v{$package,'version'},
- $av_pk2v{$package,'package_revision'},
- $st_k2v{'version'},$st_k2v{'package_revision'}) <0) {
- &forcibleerr("$arg: downgrading installed $package version ".
- "$st_k2v{'version'}, ".
- "package revision $st_k2v{'package_revision'} ".
- "to older version ".
- "$av_pk2v{$package,'version'}, ".
- "package revision $av_pk2v{$package,'package_revision'}",
- 'downgrade');
- }
- }
- if (open(CONF,"$controli/conffiles")) {
- @configf= <CONF>;
- eof || &error("$arg: unable to read $controli/conffiles: $!");
- close(CONF);
- grep((chop, m,^/, || s,^,/,), @configf);
- } elsif ($! != &ENOENT) {
- &error("$arg: cannot get config files list: $!");
- } else {
- @configf= ();
- }
- if ($cstatus eq 'installed' || $cstatus eq 'unpacked' ||
- $cstatus eq 'postinst-failed' || $cstatus eq 'removal-failed') {
- &filesinpackage($arg,$package);
- print STDOUT "Preparing to replace $package ...\n";
- }
- if ($cstatus eq 'installed') {
- if (!eval {
- &run_script_ne("$scriptsdir/$package.prerm", 'old pre-removal script',
- 'upgrade',
- $av_pk2v{$package,'version'}.'-'.
- $av_pk2v{$package,'package_revision'});
- 1;
- }) {
- &warn("$@... trying script from new package instead.");
- &run_script("$controli/prerm", 'new prerm script',
- 'failed-upgrade',
- $st_k2v{'version'}.'-'.$st_k2v{'package_revision'});
- }
- push(@undo,
- '$st_p2s{$package}= "postinst-failed"; $statusupdated{$package}=1;
- &run_script_ne("$scriptsdir/$package.postinst",
- "old post-installation script",
- "abort-upgrade",
- $av_pk2v{$package,"version"}."-".
- $av_pk2v{$package,"package_revision"});
- $st_p2s{$package}= "installed"; $statusupdated{$package}=1;');
- }
- @fbackups=();
- if ($cstatus eq 'installed' || $cstatus eq 'unpacked' ||
- $cstatus eq 'postinst-failed' || $cstatus eq 'removal-failed') {
- for ($i=0; $i<=$#ilist; $i++) {
- next if grep($_ eq $ilist[$i], @configf);
- $_= $ilist[$i];
- unless (lstat("$instroot/$_")) {
- $! == &ENOENT || &error("old file $_ unstattable: $!");
- next;
- }
- next if -d _;
- rename("$instroot/$_","$instroot/$_.dpkg-tmp") ||
- &error("couldn't rename old file $_ to $_.dpkg-tmp: $!");
- push(@undo,
- '$_=pop(@fbackups); rename("$instroot/$_.dpkg-tmp","$instroot/$_") ||
- die "unable to undo rename of $_ to $_.dpkg-tmp: $!"');
- push(@fbackups, $_);
- }
- if (!eval {
- &run_script_ne("$scriptsdir/$package.postrm", 'old post-removal script',
- 'upgrade',
- $av_pk2v{$package,'version'}.'-'.
- $av_pk2v{$package,'package_revision'});
- 1;
- }) {
- &warn("$@... trying script from new package instead.");
- &run_script("$controli/postrm", 'new post-removal script',
- 'failed-upgrade',
- $st_k2v{'version'}.'-'.$st_k2v{'package_revision'});
- }
- push(@undo,
- '&run_script_ne("$scriptsdir/$package.preinst",
- "old pre-installation script",
- "abort-upgrade",
- $av_pk2v{$package,"version"}.
- "-".$av_pk2v{$package,"package_revision"})');
- }
- $shortarg= $arg; $shortarg =~ s:.{15,}/:.../:;
- print STDOUT "Unpacking $arg, containing $package ...\n";
- &run_script("$controli/preinst", 'pre-installation script',
- 'upgrade', $st_k2v{'version'}.'-'.$st_k2v{'package_revision'});
- push(@undo,'&run_script_ne("$controli/postrm", "post-removal script",
- "abort-upgrade",
- $st_k2v{"version"}."-".$st_k2v{"package_revision"})');
- if ($cstatus ne 'not-installed') {
- for $_ (split(/\n/,$st_pk2v{$package,'conffiles'})) {
- s/^ //; next unless length($_);
- if (!m/^(\S+) (-|newconffile|nonexistent|[0-9a-f]{32})$/) {
- &warn("$arg: ignoring bad stuff in old conffiles field \`$_'");
- next;
- }
- $oldhash{$1}= $2;
- }
- }
- for $f (@configf) {
- $drf= &conffderef($f); if (!defined($drf)) { next; }
- if (lstat("$instroot/$drf.dpkg-tmp")) {
- $undo=1;
- } else {
- $! == &ENOENT || &error("unable to stat backup config file $_.dpkg-tmp: $!");
- if (lstat("$instroot/$drf")) {
- rename("$instroot/$drf","$instroot/$drf.dpkg-tmp") ||
- &error("couldn't back up config file $f (= $drf): $!");
- $undo=1;
- } elsif ($! == &ENOENT) {
- $undo=0;
- } else {
- &error("unable to stat config file $drf: $!");
- }
- }
- if ($undo) {
- push(@undo,
- '$_=pop(@undof); rename("$instroot/$_.dpkg-tmp","$instroot/$_") ||
- die "unable to undo backup of config file $_: $!"');
- push(@undof, $drf);
- }
- }
- open(NL,">$listsdir/$package.list.new") ||
- &error("$package: cannot create $listsdir/$package.list.new: $!");
- defined($c= fork) || &error("$package: cannot pipe/fork for $backend --vextract");
- if (!$c) {
- if (!open(STDOUT,">&NL")) {
- print STDERR "$name: cannot redirect stdout: $!\n"; exit(1);
- }
- $vexroot= length($instroot) ? $instroot : '/';
- exec($backend,"--vextract",$arg,$vexroot);
- print STDERR "$name: cannot exec $backend --vextract $arg $vexroot: $!\n";
- exit(1);
- }
- $!=0; waitpid($c,0) == $c || &error("could not wait for $backend: $!");
- $? && &forcibleerr("$package: failed to install (".&ecode.")", 'extractfail');
- rename("$listsdir/$package.list.new","$listsdir/$package.list") ||
- &error("$package: failed to install new $listsdir/$package.list: $!");
-
- $newconff='';
- for $f (@configf) {
- $h= $oldhash{$f};
- $h='newconffile' unless length($h);
- $newconff.= "\n $f $h";
- &debug("new hash, after unpack, of $f, is $h");
- }
- for $k (keys %all_k21) {
- next if $k eq 'binary' || $k eq 'source' || $k eq 'section';
- $st_pk2v{$package,$k}= $av_pk2v{$package,$k};
- }
- $st_pk2v{$package,'conffiles'}= $newconff; $all_k21{'conffiles'}= 1;
- $st_p2s{$package}= 'unpacked'; $st_p2h{$package}= 'ok'; $st_p21{$package}= 1;
- $statusupdated{$package}= 1;
- @undo=(); @undof=();
- for $f (@fbackups) {
- unlink("$instroot/$f.dpkg-tmp") || $! == &ENOENT ||
- &subcriterr("$package: unable to delete saved old file $f.dpkg-tmp: $!\n");
- }
- undef %fordeletion;
- opendir(PI,"$scriptsdir") ||
- &corruptingerr("$package: unable to read $scriptsdir directory ($!)");
- while(defined($_=readdir(PI))) {
- next unless substr($_,0,length($package)+1) eq $package.'.';
- $fordeletion{$_}= 1;
- }
- closedir(PI);
- opendir(PI,"$controli") ||
- &corruptingerr("$package: unable to read $controli".
- " new package control information directory ($!)");
- $fordeletion{"$package.list"}= 0;
- while(defined($_=readdir(PI))) {
- next if m/^\.\.?$/ || m/^conffiles$/ || m/^control$/;
- rename("$controli/$_","$scriptsdir/$package.$_") ||
- &corruptingerr("$package: unable to install new package control".
- " information file $scriptsdir/$package.$_ ($!)");
- $fordeletion{"$package.$_"}= 0;
- }
- closedir(PI);
- for $_ (keys %fordeletion) {
- next unless $fordeletion{$_};
- unlink("$scriptsdir/$_") ||
- &corruptingerr("$package: unable to remove old package script".
- " $scriptsdir/$_ ($!)");
- }
- }
- #*** --configure ***#
- sub do_configure {
- $package=$arg; $cstatus= $st_p2s{$package};
- if (!defined($st_p21{$package})) { $cstatus= 'not-installed'; }
- unless ($cstatus eq 'unpacked' || $cstatus eq 'postinst-failed') {
- if ($cstatus eq 'not-installed') {
- &error("no package named \`$package' is installed, cannot configure");
- } else {
- &error("$package: is currently in state \`$cstatus', cannot configure");
- }
- }
- push(@deferred,$package);
- }
- sub middle_configure {
- $sincenothing=0; $dependtry=1;
- }
- sub deferred_configure {
- # The algorithm for deciding what to configure first is as follows:
- # Loop through all packages doing a `try 1' until we've been round
- # and nothing has been done, then do `try 2' and `try 3' likewise.
- # Try 1:
- # Are all dependencies of this package done ? If so, do it.
- # Are any of the dependencies missing or the wrong version ?
- # If so, abort (unless --force-depends, in which case defer)
- # Will we need to configure a package we weren't given as an
- # argument ? If so, abort - except if --force-configure-any,
- # in which case we add the package to the argument list.
- # If none of the above, defer the package.
- # Try 2:
- # Find a cycle and break it (see above).
- # Do as for try 1.
- # Try 3 (only if --force-depends-version).
- # Same as for try 2, but don't mind version number in dependencies.
- # Try 4 (only if --force-depends).
- # Do anyway.
- $package= $arg;
- if ($sincenothing++ > $#deferred*2+2) {
- $dependtry++; $sincenothing=0;
- &internalerr("$package: nothing configured, but try was already 4 !")
- if $dependtry > 4;
- }
- if ($dependtry > 1) { &findbreakcycle($package); }
- ($ok, @aemsgs) = &dependencies_ok($package,'');
- if ($ok == 1) {
- push(@deferred,$package); return;
- } elsif ($ok == 0) {
- $sincenothing= 0;
- &error("$arg: dependency problems - not configuring this package:\n ".
- join("\n ",@aemsgs));
- } elsif (@aemsgs) {
- &warn("$arg: dependency problems, configuring anyway as you request:\n ".
- join("\n ",@aemsgs));
- }
- $sincenothing= 0;
- print STDOUT "Setting up $package ...\n";
- if ($st_p2s{$package} eq 'unpacked') {
- &debug("conffiles updating >$st_pk2v{$package,'conffiles'}<");
- undef %oldhash; @configf=();
- for $_ (split(/\n/,$st_pk2v{$package,'conffiles'})) {
- s/^ //; next unless length($_);
- if (!m/^(\S+) (-|newconffile|nonexistent|[0-9a-f]{32})$/) {
- &warn("$arg: ignoring bad stuff in old conffiles field \`$_'");
- next;
- }
- $oldhash{$1}= $2; push(@configf,$1);
- &debug("old hash of $1 is $2");
- }
- undef %newhash;
- for $file (@configf) {
- $drf= &conffderef($file);
- if (!defined($drf)) { $newhash{$file}= '-'; next; }
- $newhash{$file}= &hash("$instroot/$drf");
- &debug("new hash of $file is $newhash{$file} (old $oldhash{$file})");
- if ($oldhash{$file} eq 'newconffile') {
- $usenew= 1;
- } else {
- if (!&files_not_identical("$instroot/$drf",
- "$instroot/$drf.dpkg-tmp")) {
- rename("$instroot/$drf.dpkg-tmp",$drf) || $!==&ENOENT ||
- &error("$package: unable to reinstall ".
- "existing conffile $drf.dpkg-tmp: $!");
- &debug("files identical $file");
- } else {
- $diff= $newhash{$file} ne $oldhash{$file};
- $usenew= $confusenew[$diff];
- &debug("the decision - diff $diff;".
- " usenew $usenew prompt $confpromt[$diff]");
- if ($confprompt[$diff]) {
- $symlinked = $drf eq $file ? '' :
- $succinct ? " (-> $drf)" :
- " (which is a symlink to $drf)";
- for (;;) {
- print
- $succinct ? "
- Package $package, file $file$symlinked, ".($diff ? "CHANGED": "not changed")
- : $diff ? "
- In package $package, distributed version of configuration
- file $file$symlinked has changed
- since the last time it was installed. You may:
- * Install the new version and edit it later to reflect your wishes.
- ". ($nokeepold ?
- "(Your old version will not be saved.)" :
- "(Your old version will be saved in $drf.dpkg-old.)") . "
- * Leave your old version in place, and perhaps check later that
- you don't want to update it to take account of new features.
- ". ($nokeepnew ?
- "(The new version be discarded.)" :
- "(The new version will be placed in $drf.dpkg-new.)")
- : "
- Package $package contains the same distributed version of
- configuration file $file$symlinked
- as the last time it was installed. You may:
- * Install the distributed version, overwriting your changes.
- ". ($nokeepold ?
- "(Your changed version will not be saved.)" :
- "(Your changed version will be saved in $drf.dpkg-old.)") . "
- * Leave your own version in place.
- ". ($nokeepnew ?
- "(The distributed version be discarded.)" :
- "(The distributed version will be placed in $drf.dpkg-new.)");
- print "
- $file: install new version ? (y/n, default=". ($usenew?'y':'n'). ") ";
- $!=0; defined($iread= <STDIN>) ||
- &error("$package: prompting, EOF/error on stdin: $!");
- $_= $iread; s/^\s*//; s/\s+$//;
- ($usenew=0, last) if m/^n(o)?$/i;
- ($usenew=1, last) if m/^y(es)?$/i;
- last if m/^$/;
- print "\nPlease answer \`y' or \`n'.\n";
- }
- }
- &debug("decided, usenew $usenew");
- if ($usenew) {
- ©perm("$drf.dpkg-tmp",$drf,$drf);
- if ($nokeepold) {
- unlink("$instroot/$drf.dpkg-tmp") || $!==&ENOENT ||
- &error("$package: unable to delete old conffile ".
- "$drf.dpkg-tmp: $!");
- unlink("$instroot/$drf.dpkg-old") || $!==&ENOENT ||
- &error("$package: unable to delete very old ".
- "conffile $drf.dpkg-old: $!");
- } else {
- rename("$instroot/$drf.dpkg-tmp","$instroot/$drf.dpkg-old")
- || $!==&ENOENT ||
- &error("$package: unable to back up old conffile ".
- "$drf.dpkg-tmp as $drf.dpkg-old: $!");
- }
- } else {
- unlink("$instroot/$drf.dpkg-new") || $!==&ENOENT ||
- &error("$package: unable to delete old new conffile ".
- "$drf.dpkg-new: $!");
- if (!$nokeepnew) {
- link("$instroot/$drf","$instroot/$drf.dpkg-new")
- || $!==&ENOENT ||
- &error("$package: unable save new conffile ".
- "$drf as $drf.dpkg-new: $!");
- }
- if (!rename("$instroot/$drf.dpkg-tmp","$instroot/$drf")) {
- $!==&ENOENT || &error("$package: unable reinstall old ".
- "conffile $drf.dpkg-tmp as $drf: $!");
- unlink("$instroot/$drf");
- }
- }
- }
- }
- }
- $newconff='';
- for $f (@configf) {
- $h= $newhash{$f}; $newconff.= "\n $f $h";
- }
- $st_pk2v{$package,'conffiles'}= $newconff; $all_k21{'conffiles'}= 1;
- }
- $st_p2s{$package}= 'postinst-failed'; $statusupdated{$package}= 1;
- &run_script("$scriptsdir/$package.postinst",
- 'post-installation script', 'configure');
- $st_p2s{$package}= 'installed';
- $st_p2h{$package}= 'ok'; $statusupdated{$package}= 1;
- }
- #*** --remove ***#
- sub do_remove {
- $package=$arg; $cstatus= $st_p2s{$package};
- if (!defined($st_p21{$package}) ||
- $cstatus eq 'not-installed' ||
- !$purge && $cstatus eq 'config-files') {
- &error("$package: is not installed, cannot remove");
- }
- push(@deferred,$package);
- if (!$auto) {
- $ns= $purge ? 'purge' : 'deinstall';
- if ($st_p2w{$package} ne $ns) {
- $st_p2w{$package}= $ns; $statusupdated{$package}= 1;
- }
- }
- }
- sub middle_remove {
- $sincenothing=0; $dependtry=1;
- for $p (keys %st_p2s) {
- $cstatus= $st_p2s{$p};
- next unless $cstatus eq 'installed';
- for $tp (split(/[\|,]/, $st_pk2v{$p,'depends'})) {
- $tp =~ s/\s*\(.+\)\s*$//; $tp =~ s/^\s*//; $tp =~ s/\s+$//;
- $tp =~ m/^$packagere$/o ||
- &internalerr("package $p dependency $tp didn't match re");
- $depended{$tp}.= "$p ";
- }
- }
- }
- sub deferred_remove {
- $package= $arg;
- if ($sincenothing++ > $#deferred*2+2) {
- $dependtry++; $sincenothing=0;
- &internalerr("$package: nothing configured, but try was already 4 !")
- if $dependtry > 4;
- }
- @raemsgs= (); $rok= 2;
- &debug("$package may be depended on by any of >$depended{$package}<");
- for $fp (split(/ /, $depended{$package})) {
- next if $fp eq '' || $ignore_depends{$tp};
- $is= $st_p2s{$fp};
- next if $is eq 'not-installed' || $is eq 'unpacked' ||
- $is eq 'removal-failed' || $is eq 'config-files';
- if ($dependtry > 1) { &findbreakcycle($fp); }
- ($ok, @aemsgs) = &dependencies_ok($fp,$package);
- if ($rok != 1) { push(@raemsgs,@aemsgs); }
- $rok= $ok if $ok < $rok;
- }
- if ($rok == 1) {
- push(@deferred,$package); return;
- } elsif ($rok == 0) {
- $sincenothing= 0;
- &error("$arg: dependency problems - not removing this package:\n ".
- join("\n ",@raemsgs));
- } elsif (@raemsgs) {
- &warn("$arg: dependency problems, removing anyway as you request:\n ".
- join("\n ",@raemsgs));
- }
- $sincenothing= 0;
- &filesinpackage($arg,$package);
- undef %hash; @configfr= @configf= ();
- for $_ (split(/\n/,$st_pk2v{$package,'conffiles'})) {
- s/^ //; next unless length($_);
- if (!m/^(\S+) (-|newconffile|nonexistent|[0-9a-f]{32})$/) {
- &warn("$arg: ignoring bad stuff in old conffiles field \`$_'");
- next;
- }
- unshift(@configfr,$1); push(@configf,$1);
- $hash{$1}= $2;
- }
-
- if ($st_p2s{$package} ne 'config-files') {
- print STDOUT "Removing $package ...\n";
- &run_script("$scriptsdir/$package.prerm", 'pre-removal script', 'remove');
- $st_p2s{$package}= 'removal-failed'; $statusupdated{$package}= 1;
- for $file (reverse @ilist) {
- next if grep($_ eq $file, @configf);
- unlink("$instroot/$file.dpkg-tmp") || $! == &ENOENT ||
- &error("$arg: cannot remove supposed old temp file $file: $!");
- next if unlink("$instroot/$file");
- next if $! == &ENOENT;
- &error("$arg: cannot remove file $file: $!") unless $! == &EISDIR;
- next if rmdir("$instroot/$file");
- &error("$arg: cannot remove directory $file: $!") unless $! == &ENOTEMPTY;
- }
- &run_script("$scriptsdir/$package.postrm", 'post-removal script', 'remove');
- opendir(DSD,"$scriptsdir") ||
- &error("$arg: cannot read directory $scriptsdir: $!");
- for $_ (readdir(DSD)) {
- next unless m/\.[^.]$/;
- next if $& eq '.postrm' || $& eq '.list';
- # need postrm for --purge, and list has to go last in case it
- # goes wrong
- next unless $` eq $package;
- unlink("$scriptsdir/$_") ||
- &error("$arg: unable to delete control information $scriptsdir/$_: $!");
- }
- closedir(DSD);
- $st_p2s{$package}= 'config-files';
- $statusupdated{$package}= 1;
- }
- if ($purge) {
- print STDOUT "Purging configuration files for $package ...\n";
- push(@undo,
- '$newconff="";
- for $f (@configf) { $newconff.= "\n $f $hash{$f}"; }
- $st_pk2v{$package,"conffiles"}= $newconff; $all_k21{"conffiles"}= 1;');
- for $file (@configfr) {
- $drf= &conffderef($file); if (!defined($drf)) { next; }
- unlink("$instroot/$drf") || $! == &ENOENT ||
- &error("$arg: cannot remove old config file $file (= $drf): $!");
- $hash{$file}= 'newconffile';
- unlink("$instroot/$file") || $! == &ENOENT ||
- &error("$arg: cannot remove old config file $file: $!")
- if $file ne $drf;
- for $ext ('.dpkg-tmp', '.dpkg-old', '.dpkg-new', '~', '.bak', '%') {
- unlink("$instroot/$drf$ext") || $! == &ENOENT ||
- &error("$arg: cannot remove old config file $drf$ext: $!");
- }
- unlink("#$instroot/$drf#") || $! == &ENOENT ||
- &error("$arg: cannot remove old auto-save file #$drf#: $!");
- $drf =~ m,^(.*)/, || next; $dir= $1; $base= $';
- if (opendir(CFD,"$instroot/$dir")) {
- for $_ (readdir(CFD)) {
- next unless m/\.~\d+~$/;
- next unless $` eq $base;
- unlink("$instroot/$dir/$_") || $! == &ENOENT ||
- &error("$arg: cannot remove old emacs backup file $dir/$_: $!");
- }
- closedir(CFD);
- if (grep($_ eq $dir, @ilist)) {
- rmdir("$instroot/$dir") || $! == &ENOTEMPTY ||
- &error("$arg: cannot remove config file directory $dir: $!");
- }
- } elsif ($! != &ENOENT) {
- &error("$arg: cannot read config file dir $dir: $!");
- }
- }
- &run_script("$scriptsdir/$package.postrm", 'post-removal script for purge',
- 'purge');
- unlink("$scriptsdir/$package.postrm") || $! == &ENOENT ||
- &error("$arg: cannot remove old postrm script: $!");
- &setnotinstalled;
- @undo= ();
- } elsif (!@configf && !stat("$scripts/$package.postrm")) {
- # If there are no config files and no postrm script then we
- # go straight into `purge'. However, perhaps the stat didn't
- # fail with ENOENT ...
- $! == &ENOENT || &error("$package: stat failed on postrm script: $!");
- $st_p2w{$package}= 'purge';
- &setnotinstalled;
- }
- $st_p2h{$package}= 'ok'; $statusupdated{$package}= 1;
- }
- sub setnotinstalled {
- unlink("$listsdir/$package.list") ||
- &error("$arg: unable to delete old file list: $!");
- $st_p2s{$package}= 'not-installed';
- for $k (keys %all_k21) { delete $st_pk2v{$package,$k}; }
- }
- #*** dependency processing - common to --configure and --remove ***#
- # The algorithm for deciding what to configure or remove first is as
- # follows:
- #
- # Loop through all packages doing a `try 1' until we've been round and
- # nothing has been done, then do `try 2' and `try 3' likewise.
- #
- # When configuring, in each try we check to see whether all
- # dependencies of this package are done. If so we do it. If some of
- # the dependencies aren't done yet but will be later we defer the
- # package, otherwise it is an error.
- #
- # When removing, in each try we check to see whether there are any
- # packages that would have dependencies missing if we removed this
- # one. If not we remove it now. If some of these packages are
- # themselves scheduled for removal we defer the package until they
- # have been done.
- #
- # The criteria for satisfying a dependency vary with the various
- # tries. In try 1 we treat the dependencies as absolute. In try 2 we
- # check break any cycles in the dependency graph involving the package
- # we are trying to process before trying to process the package
- # normally. In try 3 (which should only be reached if
- # --force-depends-version is set) we ignore version number clauses in
- # Depends lines. In try 4 (only reached if --force-depends is set) we
- # say "ok" regardless.
- #
- # If we are configuring and one of the packages we depend on is
- # awaiting configuration but wasn't specified in the argument list we
- # will add it to the argument list if --configure-any is specified.
- # In this case we note this as having "done something" so that we
- # don't needlessly escalate to higher levels of dependency checking
- # and breaking.
- sub dependencies_ok {
- local ($dp, $removingp) = @_;
- local ($tpo, $however_t, $ok, $found, @aemsgs, @oemsgs);
- local ($tp, $rightver, $inst, $want, $thisf, $matched, $tpp);
- $ok= 2; # 2=ok, 1=defer, 0=halt
- &debug("checking dependencies of $dp (- $removingp)");
- for $tpo (split(/,/, $st_pk2v{$dp,'depends'})) {
- $tpo =~ s/^\s*//; $tpo =~ s/\s+$//;
- &debug(" checking group $dp -> $tpo");
- $matched= 0; @oemsgs=();
- $found=0; # 0=none, 1=defer, 2=withwarning, 3=ok
- for $tp (split(/\|/, $tpo)) {
- $tp =~ s/^\s*//; $tp =~ s/\s+$//;
- &debug(" checking possibility $dp -> $tp");
- if ($ignore_depends{$tp}) { &debug("ignoring so ok"); $found=3; last; }
- if (defined($cyclebreak{$dp,$tp})) { &debug("break cycle"); $found=3; last; }
- if ($tp eq $removingp) {
- ($tps, $rightver, $inst, $want, $tpp)= ('removing-now', 1, '','', $tp);
- $matched= 1;
- } else {
- ($tps, $rightver, $inst, $want, $tpp)= &installationstatus($tp);
- &debug("installationstatus($tp) -> !$tps!$rightver!$inst!$want!$tps|");
- }
- if (($tps eq 'installed' || $tps eq 'unpacked' || $tps eq 'postinst-failed')
- && !$rightver) {
- push(@oemsgs,"version of $tpp on system is $inst (wanted $want)");
- if ($force{'depends'}) { $thisf= $dependtry >= 3 ? 2 : 1; }
- } elsif ($tps eq 'unpacked' || $tps eq 'postinst-failed') {
- if (grep($_ eq $tpp, @deferred)) {
- $thisf=1;
- } elsif (!length($removingp) && $force{'configure-any'}) {
- &warn("will also configure $tpp");
- push(@deferred,$tpp); $sincenothing=0; $thisf=1;
- } else {
- push(@oemsgs,"package $tpp is not configured yet");
- if ($force{'depends'}) { $thisf= $dependtry >= 4 ? 2 : 1; }
- }
- } elsif ($tps eq 'installed') {
- $found=3; last;
- } elsif ($tps eq 'removing-now') {
- push(@oemsgs,"$tpp is to be removed");
- if ($force{'depends'}) { $thisf= $dependtry >= 4 ? 2 : 1; }
- } else {
- push(@oemsgs,"$tpp ($want) is not installed");
- if ($force{'depends'}) { $thisf= $dependtry >= 4 ? 2 : 1; }
- }
- &debug(" found $found");
- $found=$thisf if $thisf>$found;
- }
- &debug(" found $found matched $matched");
- next if length($removingp) && !$matched;
- if (length($removingp) && $tpo !~ m/\|/) {
- $however_t= '';
- } elsif (@oemsgs > 1) {
- $however_t= "\n However, ". join(",\n ", @oemsgs[0..($#oemsgs-1)]).
- " and\n ". $oemsgs[$#oemsgs]. ".";
- } else {
- $however_t= "\n However, @oemsgs.";
- }
- if ($found == 0) {
- push(@aemsgs, "$dp depends on $tpo.$however_t");
- $ok=0;
- } elsif ($found == 1) {
- $ok=1 if $ok>1;
- } elsif ($found == 2) {
- push(@aemsgs, "$dp depends on $tpo.$however_t");
- } elsif ($found != 3) {
- &internalerr("found value in deferred_configure $found not known");
- }
- }
- &debug("ok $ok msgs >>@aemsgs<<");
- return ($ok, @aemsgs);
- }
- sub findbreakcycle {
- # Cycle breaking works recursively down the package dependency
- # tree. @sofar is the list of packages we've descended down
- # already - if we encounter any of its packages again in a
- # dependency we have found a cycle.
- #
- # Cycles are preferentially broken by ignoring a dependency from
- # a package which doesn't have a postinst script. If there isn't
- # such a dependency in the cycle we break at the `start' of the
- # cycle from the point of view of our package.
- #
- local ($package,@sofar) = @_;
- local ($tp,$tpp,$tps,$rightver,$inst,$want,$i,$dr,$de,@sf);
- &debug("findbreakcycle($package; @sofar)");
- push(@sofar,$package);
- for $tp (split(/[,|]/, $st_pk2v{$package,'depends'})) {
- $tp =~ s/^\s*//; $tp =~ s/\s+$//;
- ($tps, $rightver, $inst, $want, $tpp)= &installationstatus($tp);
- next unless $tps eq 'config-files' || $tps eq 'unpacked';
- next if $cyclebreak{$package,$tpp};
- if (grep($_ eq $tpp, @sofar)) {
- &debug("found cycle $package, $tpp (@sofar)");
- @sf= (@sofar,$tpp);
- for ($i=0;
- $i<$#sf;
- $i++) {
- next if stat("$scriptsdir/$sf[$i].postinst");
- last if $! == &ENOENT;
- &error("$arg: unable to stat $scriptsdir/$sf[$i].postinst: $!");
- }
- $i=0 if $i>=$#sf;
- ($dr,$de)= @sf[$i..$i+1];
- if (!defined($cyclebreak{$dr,$de})) {
- $sincenothing=0; $cyclebreak{$dr,$de}= 1;
- &debug("broken cycle $i (@sf) at $dr -> $de");
- return 1;
- }
- } else {
- return if &findbreakcycle($tpp,@sofar);
- }
- }
- return 0;
- }
- #*** useful subroutines for actions ***#
- sub filesinpackage {
- # Returns the list in @ilist.
- # If error, calls &error("$epfx: ...");
- local ($epfx, $package) = @_;
- open(LIST,"$listsdir/$package.list") ||
- &error("$epfx: database broken for $package - ".
- "can't get installed files list: $!");
- @ilist= <LIST>;
- eof || &error("$epfx: cannot read $listsdir/$package.list: $!");
- close(LIST);
- @ilist= grep((chop,
- s|/$||,
- m|^/| || s|^|/|,
- m/./),
- @ilist);
- }
- sub installationstatus {
- local ($controlstring) = @_;
- local ($lversion,$lpackage,$lstatus,$lrevision,$cmp) = @_;
- local ($cc);
- $lversion= $controlstring;
- $lversion =~ s/^($packagere)\s*// ||
- &internalerr("needed installation status of bogus thing \`$lversion'");
- $lpackage= $1;
- $lstatus= defined($st_p2s{$lpackage}) ? $st_p2s{$lpackage} : 'not-installed';
- if ($lstatus ne 'not-installed') {
- if (length($lversion)) {
- $lversion =~ s/^\s*\(\s*// && $lversion =~ s/\s*\)\s*$// ||
- &internalerr("failed to strip version \`$lversion'");
- if ($lversion =~ s/^[><=]//) { $cc= $&; } else { $cc= '='; }
- $lrevision = ($lversion =~ s/-([^-]+)$//) ? $1 : '';
- $wantedstring= "version $lversion";
- $wantedstring .= ", package revision $lrevision" if length($lrevision);
- $cmp= &compare_verrevs($st_pk2v{$lpackage,'version'},
- $st_pk2v{$lpackage,'package_revision'},
- $lversion,
- $lrevision);
- $installedstring= "version $st_pk2v{$lpackage,'version'}";
- $installedstring .=
- ", package revision $st_pk2v{$lpackage,'package_revision'}"
- if length($st_pk2v{$lpackage,'package_revision'});
- if ($cc eq '>') {
- $rightver= $cmp>=0; $wantedstring.= ' or later';
- } elsif ($cc eq '<') {
- $rightver= $cmp<=0; $wantedstring.= ' or earlier';
- } else {
- s/^=//;
- $rightver= !$cmp; $wantedstring= "exactly $wantedstring";
- }
- } else {
- $rightver= 1;
- $wantedstring= "any version";
- $installedstring= $st_pk2v{$lpackage,'version'}.'-'.
- $st_pk2v{$lpackage,'package_revision'};
- }
- } else {
- $rightver= -1;
- $installedstring= "not installed";
- }
- return ($lstatus,$rightver,$installedstring,$wantedstring,$lpackage);
- }
- sub parse_control {
- # reads from fh CONTROL
- local ($fn) = @_;
- local ($cf,$ln,$l,$k,$v);
- defined($cf= &readall('CONTROL')) || &error("read control file $fn: $!");
- close(CONTROL);
- $p= &parse_control_entry;
- if (@cwarnings) {
- &warn("$fn: control file contains oddities: ".join("; ",@cwarnings))
- unless $controlwarn;
- }
- if (@cerrors) {
- &error("$fn: control file contains errors: ".join("; ",@cerrors));
- }
- }
- sub run_script_ne {
- local ($script,$describe,@args) = @_;
- local ($extranewlines) = $script =~ m/postinst/;
- &debug("running $describe = $script @args");
- if (!stat("$script")) {
- return if $! == &ENOENT;
- die "couldn't stat $script: $!\n";
- }
- if (! -x _) {
- chmod(0755, "$script") || die "couldn't make $script executable: $!\n";
- }
- print "\n" if $extranewlines;
- &debug("forking now");
- defined($rsc= fork) || die "couldn't fork for running $script: $!\n";
- if (!$rsc) {
- if ($instroot !~ m|^/*$| && !chroot($instroot)) {
- print STDERR "$name: failed to chroot to $instroot for $describe: $!\n";
- exit(1);
- }
- exec($script,@args);
- print STDERR "$name: failed to exec $script: $!\n";
- exit(1);
- }
- $!=0; waitpid($rsc,0) == $rsc || die "couldn't wait for $describe: $!\n";
- $? && die "$describe failed (".&ecode.")\n";
- &debug("script done");
- print "\n" if $extranewlines;
- }
- sub run_script {
- return if eval { &run_script_ne; 1; };
- $rse= $@; chop($rse); &error("$package: $rse");
- }
- sub hash {
- local ($file) = @_; # NB: filename must already have $instroot here
- local ($c);
- if (open(HF,"<$file")) {
- defined($c= open(MDP,"-|")) || &error("fork/pipe for hash: $!");
- if (!$c) {
- if (!open(STDIN,"<&HF")) {
- print STDERR "$name: unable to redirect stdin for hash: $!\n"; exit(1);
- }
- exec($md5sum); print STDERR "$name: unable to exec $md5sum: $!\n"; exit(1);
- }
- defined($hash= &readall('MDP')) || &error("unable to read from $md5sum: $!\n");
- $!=0; close(MDP); $? && &error("$md5sum returned error (".&ecode.")");
- $hash =~ s/\n+$//;
- $hash =~ m/^[0-9a-f]{32}$/i || &error("$md5sum returned bogus output \`$hash'");
- return $hash;
- } elsif ($! == &ENOENT) {
- return 'nonexistent';
- } else {
- &warn("$arg: unable to open conffile $file for hash: $!");
- return '-';
- }
- }
- sub files_not_identical {
- local ($file1,$file2) = @_; # NB: filenames must already have $instroot here
- if (stat($file1)) {
- if (stat($file2)) {
- system("cmp","-s",$file1,$file2);
- if (&WIFEXITED($?)) {
- $es= &WEXITSTATUS($?);
- return $es if $es == 0 || $es == 1;
- }
- &error("cmp $file1 $file2 returned error (".&ecode.")");
- } elsif ($! == &ENOENT) {
- return 1;
- } else {
- &error("failed to stat conffile $file2: $!");
- }
- } elsif ($! == &ENOENT) {
- if (stat($file2)) {
- return 1;
- } elsif ($! == &ENOENT) {
- return 0;
- } else {
- &error("failed to stat conffile $file2: $!");
- }
- } else {
- &error("failed to stat conffile $file1: $!");
- }
- }
- sub copyperm {
- local ($from,$to,$name) = @_;
- if (@statv= stat("$instroot/$from")) {
- chown($statv[4],$statv[5],"$instroot/$to") ||
- $!==&ENOENT ||
- &warn("$package: unable to preserve ownership of $name");
- chmod($statv[2],"$instroot/$to") ||
- $!==&ENOENT ||
- &warn("$package: unable to preserve permissions of $name");
- } elsif ($! != &ENOENT) {
- &warn("$package: unable to check permissions and ownership of".
- " $name in order to preserve them");
- }
- }
- sub conffderef {
- local ($file) = @_;
- local ($drf, $warning);
- $drf= $file; $warning='';
- for (;;) {
- if (!lstat("$instroot/$drf")) {
- last if $! == &ENOENT; $warning= "unable to lstat: $!"; last;
- } elsif (-f _) {
- last;
- } elsif (-l _) {
- if (!defined($lv= readlink("$instroot/$drf"))) {
- $warning= "unable to readlink: $!"; last;
- }
- if ($lv =~ m|^/|) {
- $drf= $lv;
- } else {
- $drf =~ s|/[^/]+$|/$lv|;
- }
- } else {
- $warning= "not a plain file or symlink"; last;
- }
- }
- &debug("conffile $file drf $drf warns \`$warning'");
- if ($warning) {
- &warn("$arg: possible problem with configuration file $file (= $drf):\n".
- " $warning");
- return undef;
- } else {
- return $drf;
- }
- }
|