lib.pl 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566
  1. # -*- perl -*-
  2. #
  3. # dpkg library: Debian GNU/Linux package maintenance utility,
  4. # useful library functions.
  5. #
  6. # Copyright (C) 1994 Matt Welsh <mdw@sunsite.unc.edu>
  7. # Copyright (C) 1994 Carl Streeter <streeter@cae.wisc.edu>
  8. # Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
  9. # Copyright (C) 1994 Ian Jackson <iwj10@cus.cam.ac.uk>
  10. #
  11. # dpkg is free software; you can redistribute it and/or modify
  12. # it under the terms of the GNU General Public License as
  13. # published by the Free Software Foundation; either version 2,
  14. # or (at your option) any later version.
  15. #
  16. # dpkg is distributed in the hope that it will be useful, but
  17. # WITHOUT ANY WARRANTY; without even the implied warranty of
  18. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  19. # GNU General Public License for more details.
  20. #
  21. # You should have received a copy of the GNU General Public
  22. # License along with dpkg; if not, write to the Free Software
  23. # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  24. # /var/lib/dpkg/ +---- status
  25. # |---- updates/ +---- <id>
  26. # | |---- tmp.i
  27. # | \---- <id>.new
  28. # |---- available
  29. # |---- lock
  30. # |---- info/ |---- <package>.{post,pre}{inst,rm}
  31. # |---- tmp.$$
  32. # \---- tmp.ci/ +---- control
  33. # |---- conffiles
  34. # |---- {post,pre}{inst,rm}
  35. # |---- list
  36. # \---- conffiles
  37. $backend = "dpkg-deb";
  38. $fpextract = "dpkg-deb";
  39. $md5sum = "md5sum";
  40. $dselect = "dselect";
  41. $dpkg = "dpkg";
  42. $status_mergeevery = 20;
  43. $tmp = "/tmp";
  44. $visiblecontroldir = "DEBIAN";
  45. sub setadmindir {
  46. $dd = $_[0];
  47. $statusdb = "$dd/status";
  48. $updatesdir = "$dd/updates";
  49. $availabledb = "$dd/available";
  50. $scriptsdir = "$dd/info";
  51. $listsdir = "$dd/info";
  52. $lockfile = "$dd/lock";
  53. $lockmine = "$dd/tmp.$$";
  54. $controli = "$dd/tmp.ci";
  55. $importantspace = "$updatesdir/tmp.i";
  56. }
  57. $orgadmindir= "/var/lib/dpkg";
  58. &setadmindir($orgadmindir);
  59. @nokeepfields= ('package','version','package_revision',
  60. 'depends','recommended','optional','conflicts','part');
  61. # Don't keep these fields in the Available database if a new record is
  62. # merged which is missing values for any of them.
  63. $packagere = '\w[-_a-zA-Z0-9+.@:=%]+';
  64. $packageversionre= $packagere.'(\s*\([^()]+\))?';
  65. $singledependencyre= "$packageversionre(\\s*\\|\\s*$packageversionre)*";
  66. # Abbreviations for dpkg-deb options common to dpkg & dpkg-deb.
  67. %debabbrevact= ('b','build', 'c','contents', 'e','control', 'i','info',
  68. 'f','field', 'x','extract', 'X','vextract');
  69. @keysortorder= ('package', 'status', 'version', 'package_revision',
  70. 'maintainer', 'description',
  71. 'depends', 'recommended', 'optional', 'conflicts',
  72. 'list', 'conffiles');
  73. #*** replacements for things in headers ***#
  74. #require 'sys/errno.ph';
  75. sub ENOENT { 2; } # No such file or directory
  76. sub EEXIST { 17; } # File exists
  77. sub EISDIR { 21; } # Is a directory
  78. sub ENOTEMPTY { 39; } # Directory not empty
  79. #require 'sys/stat.ph';
  80. sub S_IFMT { 00170000; }
  81. sub S_IFREG { 0100000; }
  82. sub S_IFLNK { 0120000; }
  83. sub S_ISREG { ($_[0] & &S_IFMT) == &S_IFREG; }
  84. sub S_ISLNK { ($_[0] & &S_IFMT) == &S_IFLNK; }
  85. #require 'sys/wait.ph';
  86. sub WIFEXITED { ($_[0] & 0x0ff) == 0; }
  87. sub WIFSTOPPED { ($_[0] & 0x0ff) == 0x07f; }
  88. sub WIFSIGNALED { !&WIFEXITED && !&WIFSTOPPED; }
  89. sub WCOREDUMP { ($_[0] & 0x080) != 0; }
  90. sub WEXITSTATUS { ($_[0] & 0x0ff00) >> 8; }
  91. sub WSTOPSIG { ($_[0] & 0x0ff00) >> 8; }
  92. sub WTERMSIG { $_[0] & 0x07f; }
  93. #require 'sys/signal.ph';
  94. sub SIGPIPE { 13; }
  95. #require 'sys/syscall.ph';
  96. sub SYS_lseek { 19; }
  97. #*** /var/lib/dpkg database management - `exported' routines ***#
  98. sub database_start {
  99. # Lock the package management databases, amalgamate any
  100. # changes files, and leave the results in:
  101. # From /var/lib/dpkg/status:
  102. # %st_pk2v{ package_name, field_name } = field_value
  103. # %st_p21{ package_name } = 1
  104. # From /var/lib/dpkg/available:
  105. # %av_pk2v{ package_name, field_name } = field_value
  106. # %av_p21{ package_name } = 1
  107. # From both:
  108. # %all_k21{ field_name } = 1
  109. &lock_database;
  110. &read_status_mainfile;
  111. &read_status_extrafiles;
  112. &write_status_mainfile;
  113. &delete_status_extrafiles;
  114. &read_available_file;
  115. &prepare_important_database;
  116. &invent_status_availableonly_packages;
  117. }
  118. sub database_finish {
  119. # Tidy up and unlock the package management databases.
  120. &release_important_database;
  121. &write_available_file;
  122. &write_status_mainfile;
  123. &delete_status_extrafiles;
  124. &unlock_database;
  125. }
  126. sub amended_status {
  127. # Record amended status of package (in an `extra' file).
  128. local (@packages) = @_;
  129. local ($p);
  130. &debug("amended @packages");
  131. for $p (@packages) {
  132. $st_pk2v{$p,'status'}= "$st_p2w{$p} $st_p2h{$p} $st_p2s{$p}";
  133. $st_p21{$p}= 1;
  134. }
  135. $all_k21{'status'}= 1;
  136. local ($ef) = sprintf("%03d",$next_extrafile++);
  137. &write_database_file("$updatesdir/$ef",*st_pk2v,*st_p21,1,@packages);
  138. push(@status_extrafiles_done,$ef); &sync;
  139. if ($next_extrafile >= $status_mergeevery) {
  140. &write_status_mainfile;
  141. &delete_status_extrafiles;
  142. }
  143. $status_modified= 1;
  144. for $p (@packages) { delete $st_pk2v{$p,'status'}; }
  145. &prepare_important_database;
  146. }
  147. sub note_amended_status {
  148. # Note the fact that the status has been modified, but don't
  149. # commit yet.
  150. $status_modified= 1;
  151. }
  152. sub amended_available {
  153. # Record amended available information (in core for the moment -
  154. # noncritical, so we defer writing it out).
  155. $available_modified++;
  156. &invent_status_availableonly_packages(@_);
  157. }
  158. #*** internal routines ***#
  159. sub invent_status_availableonly_packages {
  160. local ($p);
  161. for $p (@_ ? @_ : keys %av_p21) {
  162. next if defined($st_p2w{$p});
  163. $st_p2w{$p}= 'unknown';
  164. $st_p2h{$p}= 'ok';
  165. $st_p2s{$p}= 'not-installed';
  166. }
  167. }
  168. sub read_status_mainfile {
  169. local ($p, @p);
  170. &read_status_database_file($statusdb);
  171. }
  172. sub read_status_extrafiles {
  173. local ($fn);
  174. opendir(UPD,$updatesdir) || &bombout("cannot opendir updates $updatesdir: $!");
  175. for $_ (sort readdir(UPD)) {
  176. next if $_ eq '.' || $_ eq '..';
  177. if (m/\.new$/ || m/\.old$/ || $_ eq 'tmp.i') {
  178. unlink("$updatesdir/$_") ||
  179. &bombout("cannot unlink old update temp file $updatesdir/$_: $!");
  180. } elsif (m/^\d+$/) {
  181. $fn= $_;
  182. &read_status_database_file("$updatesdir/$fn");
  183. $status_modified= 1; push(@status_extrafiles_done, $fn);
  184. } else {
  185. warn("$name: ignoring unexpected file in $updatesdir named \`$_'\n");
  186. }
  187. }
  188. closedir(UPD);
  189. }
  190. sub read_status_database_file {
  191. local ($filename) = @_;
  192. @p= &read_database_file($filename,*st_pk2v,*st_p21);
  193. for $p (@p) {
  194. if (defined($st_pk2v{$p,'status'})) {
  195. $v= $st_pk2v{$p,'status'};
  196. $v =~ y/A-Z/a-z/;
  197. $v =~
  198. m/^(unknown|install|deinstall|purge)\s+(ok|hold)\s+(not-installed|unpacked|postinst-failed|installed|removal-failed|config-files)$/
  199. || &bombout("package \`$p' has bad status in $statusdb (\`$v')");
  200. $st_p2w{$p}= $1;
  201. $st_p2h{$p}= $2;
  202. $st_p2s{$p}= $3;
  203. }
  204. delete($st_pk2v{$p,'status'});
  205. }
  206. $status_modified= 0; @status_extrafiles_done= ();
  207. }
  208. sub write_status_mainfile {
  209. return unless $status_modified;
  210. local ($p);
  211. for $p (keys %st_p21) {
  212. $st_pk2v{$p,'status'}= "$st_p2w{$p} $st_p2h{$p} $st_p2s{$p}";
  213. }
  214. $all_k21{'status'}= 1;
  215. unlink("$statusdb.old") || $!==&ENOENT ||
  216. &bombout("unable to remove $statusdb.old: $!");
  217. link("$statusdb","$statusdb.old") ||
  218. &bombout("unable to back up $statusdb: $!");
  219. &write_database_file($statusdb,*st_pk2v,*st_p21,0);
  220. $status_modified= 0;
  221. &sync;
  222. for $p (keys %st_p21) { delete $st_pk2v{$p,'status'}; }
  223. }
  224. sub delete_status_extrafiles {
  225. #print STDERR "delete @status_extrafiles_done> "; <STDIN>;
  226. for $_ (@status_extrafiles_done) {
  227. unlink("$updatesdir/$_") ||
  228. &bombout("cannot remove already-done update file $updatesdir/$_: $!");
  229. }
  230. $next_extrafile= 0;
  231. @status_extrafiles_done= ();
  232. }
  233. sub read_available_file {
  234. &read_database_file($availabledb,*av_pk2v,*av_p21);
  235. $available_modified= 0;
  236. }
  237. sub write_available_file {
  238. return unless $available_modified;
  239. &write_database_file($availabledb,*av_pk2v,*av_p21,0);
  240. $available_modified= 0;
  241. }
  242. #*** bottom level of read routines ***#
  243. sub read_database_file {
  244. local ($filename, *xx_pk2v, *xx_p21) = @_;
  245. local ($quick,$cf,@cf,%cf_k2v,@cwarnings,@cerrors,$p,@p)= 1;
  246. &debug("reading database file $filename");
  247. open(DB,"<$filename") || &bombout("unable to open $filename for reading: $!");
  248. $/="";
  249. @p=();
  250. while (defined($cf=<DB>)) {
  251. chop($cf);
  252. # $cf =~ s/\n+$/\n/;
  253. $p= &parse_control_entry;
  254. # if (@cwarnings) {
  255. # warn("$name: warning, packaging database file $filename\n".
  256. # " contains oddities in entry for package \`$p':\n ".
  257. # join(";\n ",@cwarnings).
  258. # ".\n This is probably a symptom of a bug.\n");
  259. # }
  260. if (@cerrors) {
  261. &bombout("packaging database corruption - please report:\n".
  262. " file $filename has error(s) in entry for \`$p':\n ".
  263. join(";\n ",@cerrors). ".");
  264. }
  265. $xx_p21{$p}= 1;
  266. for $k (keys %all_k21) { $xx_pk2v{$p,$k}= $cf_k2v{$k}; }
  267. push(@p,$p);
  268. }
  269. &debug("database file $filename read");
  270. $/="\n"; close(DB);
  271. return @p;
  272. }
  273. sub parse_control_entry {
  274. # Expects $cf to be a sequence of lines,
  275. # representing exactly one package's information.
  276. # Results are put in cf_k2v.
  277. # @warnings and @errors are made to contain warning and error
  278. # messages, respectively.
  279. local ($ln,$k,$v,$p,$l);
  280. @cwarnings= @cerrors= ();
  281. undef %cf_k2v;
  282. # &debug(">>>$cf<<<#\n");
  283. if (!$quick) {
  284. if ($cf =~ s/\n\n+/\n/g) { push(@cwarnings, "blank line(s) found and ignored"); }
  285. if ($cf =~ s/^\n+//) { push(@cwarnings, "blank line(s) at start ignored"); }
  286. if ($cf !~ m/\n$/) {
  287. $cf.= "\n"; push(@cwarnings, "missing newline after last line assumed");
  288. }
  289. if ($cf =~ s/\0//g) {
  290. push(@cwarnings, "nul characters discarded");
  291. }
  292. }
  293. $cf =~ s/\n([ \t])/\0$1/g; # join lines
  294. # &debug(">>>$cf<<<*\n");
  295. $ln = 0;
  296. for $_ (split(/\n/,$cf)) {
  297. $ln++; s/\s+$//;
  298. next if m/^#/;
  299. m/^(\S+):[ \t]*/ || (push(@cerrors, "garbage at line $ln, \`$_'"), next);
  300. $k= $1; $v= $'; $k =~ y/A-Z/a-z/; $k='package_revision' if $k eq 'revision';
  301. # &debug("key=\`$k' value=\`$v' line=\`$_'\n");
  302. $ln += ($v =~ s/\0/\n/g);
  303. $cf_k2v{$k}= $v;
  304. $all_k21{$k}= 1;
  305. # while ($cf =~ s/^(\S+):[ \t]*(.*)\n//) {
  306. }
  307. return unless keys %cf_k2v;
  308. $p= $cf_k2v{'package'}; delete $cf_k2v{'package'}; delete $all_k21{'package'};
  309. $cf_k2v{'class'} =~ y/A-Z/a-z/ if defined($cf_k2v{'class'});
  310. $cf_k2v{'section'} =~ y/A-Z/a-z/ if defined($cf_k2v{'section'});
  311. # length($cf) &&
  312. # push(@cerrors, "garbage at line $ln, \`".($cf =~ m/\n/ ? $` : $cf)."'");
  313. if (!$quick) {
  314. defined($p) || push(@cerrors, "no \`package' line");
  315. $p =~ m/^$packagere$/o || &bad_control_field('package');
  316. defined($cf_k2v{'version'}) || push(@cerrors, "no Version field");
  317. for $f ('depends','recommended','optional','conflicts') {
  318. next unless defined($cf_k2v{$f}) && length($cf_k2v{$f});
  319. $cf_k2v{$f} =~ m/^$singledependencyre(\s*,\s*$singledependencyre)*$/o
  320. || &bad_control_field("$f");
  321. }
  322. }
  323. return $p;
  324. }
  325. sub bad_control_field {
  326. push(@cerrors, "bad \`$_[0]' line, contains \`$cf_k2v{$_[0]}'");
  327. }
  328. #*** bottom level of database writing code ***#
  329. sub write_database_file {
  330. local ($filename, *xx_pk2v, *xx_p21, $important, @packages) = @_;
  331. local ($p,$tl,$k,$v);
  332. if (!@packages) { @packages= keys(%xx_p21); }
  333. &debug("called write_database_file $filename, important=$important, for @packages");
  334. if (!$important) {
  335. open(DB,">$filename.new") || &bombout("unable to create $filename.new: $!");
  336. }
  337. $tl= 0;
  338. for $p (@packages) {
  339. &write_database_string("\n") if $tl;
  340. &write_database_string("Package: $p\n");
  341. for $k (keys %all_k21) {
  342. next unless defined($xx_pk2v{$p,$k});
  343. $v= $xx_pk2v{$p,$k};
  344. $v =~ s/\n(\S)/\n $1/g;
  345. &write_database_string("$k: $v\n");
  346. }
  347. }
  348. if ($important) {
  349. if (!truncate(IMP,$tl)) {
  350. if (print(IMP "#")) {
  351. warn("$name: warning - unable to truncate $importantspace: $!;".
  352. "\n commenting the rest out instead seems to have worked.\n");
  353. } else {
  354. &database_corrupted("unable to truncate $importantspace: $!");
  355. }
  356. }
  357. close(IMP) || &database_corrupted("unable to close $importantspace: $!");
  358. rename($importantspace,$filename) ||
  359. &database_corrupted("unable to install $importantspace as $filename: $!");
  360. } else {
  361. close(DB) || &bombout("unable to close $filename.new: $!");
  362. rename("$filename.new",$filename) ||
  363. &bombout("unable to install $filename.new as $filename: $!");
  364. }
  365. }
  366. sub write_database_string {
  367. $tl += length($_[0]);
  368. if ($important) {
  369. print(IMP $_[0]) ||
  370. &database_corrupted("failed write to update file $importantspace: $!");
  371. } else {
  372. print(DB $_[0]) ||
  373. &bombout("failed to write to $filename.new: $!");
  374. }
  375. }
  376. sub database_corrupted {
  377. &debug("corruptingstatus @_");
  378. print STDERR "$name - really horrible error:\n @_\n".
  379. "Package manager status data is now out of step with installed system.\n".
  380. "(Last action has not been recorded. Please try re-installing \`@packages'\n".
  381. "to ensure system consistency, or seek assistance from an expert if\n".
  382. "problems persist.)\n";
  383. &cleanup; exit(2);
  384. }
  385. sub prepare_important_database {
  386. open(IMP,"+>$importantspace") || &bombout("unable to create $importantspace: $!");
  387. select((select(IMP),$|=1)[0]);
  388. print(IMP "#padding\n"x512) || &bombout("unable to pad $importantspace: $!");
  389. seek(IMP,0,0) || &bombout("unable to seek (rewind) $importantspace: $!");
  390. &debug("important database prepared");
  391. }
  392. sub release_important_database {
  393. close(IMP);
  394. unlink($importantspace) || &bombout("unable to delete $importantspace: $!");
  395. &debug("important database released");
  396. }
  397. #*** database lock management ***#
  398. sub lock_database {
  399. # Lock the package management databases. Stale locks will
  400. # be broken, but there is no concurrency checking on the lock-
  401. # breaking code.
  402. push(@cleanups,'unlink($lockmine)');
  403. open(PID,">$lockmine") || &bombout("failed to create new pid file $lockmine: $!");
  404. printf(PID "%010d\n",$$) || &bombout("failed to add pid to $lockmine: $!");
  405. close(PID) || &bombout("failed to close new pid file $lockmine: $!");
  406. unless (link($lockmine,$lockfile)) {
  407. $! == &EEXIST || &bombout("failed to create lock on packages database: $!");
  408. if (open(PID,"<$lockfile")) {
  409. undef $/; $opid= <PID>; $/="\n";
  410. $opid =~ m/^\d{10}\n$/ || &lockfailed(" (pid missing)");
  411. close(PID);
  412. -d '/proc/self' ||
  413. &bombout("/proc/self not found ($!) - /proc not mounted ?");
  414. -d sprintf("/proc/%d",$opid) && &lockfailed(" (in use by pid $opid)");
  415. if (open(PID,"<$lockfile")) {
  416. $opid eq <PID> || &lockfailed(' (pid changed)');
  417. close(PID);
  418. unlink($lockfile) ||
  419. &bombout("failed to break stale lock on database: $!");
  420. print STDERR
  421. "$name: stale lock found on packages database, lock forced\n";
  422. } else {
  423. $!==&ENOENT ||
  424. &bombout("failed to confirm who owns lock on database: $!");
  425. }
  426. } else {
  427. $!==&ENOENT || &bombout("failed to determine who owns lock on database: $!");
  428. }
  429. link($lockmine,$lockfile) ||
  430. &bombout("failed to create lock on packages database: $!");
  431. }
  432. push(@cleanups, 'unlink($lockfile) ||
  433. warn("$name: failed to unlock packages database: $!\n")');
  434. unlink($lockmine);
  435. }
  436. sub unlock_database {
  437. unlink($lockfile) || &bombout("failed to unlock packages database: $!");
  438. pop(@cleanups);
  439. }
  440. #*** error handling ***#
  441. sub lockfailed { &bombout("unable to lock packages database@_"); }
  442. sub bombout { print STDERR "$name - critical error: @_\n"; &cleanup; exit(2); }
  443. sub badusage { print STDERR "$name: @_\n\n"; &usage; &cleanup; exit(3); }
  444. sub outerr {
  445. &bombout("failed write to stdout: $!");
  446. }
  447. sub cleanup {
  448. while (@cleanups) {
  449. eval(pop(@cleanups));
  450. $@ && print STDERR "error while cleaning up: $@";
  451. }
  452. }
  453. sub debug {
  454. return unless $debug;
  455. print "D: @_\n";
  456. }
  457. sub ecode {
  458. local ($w,$s) = ($?,$!);
  459. &debug("ecode $w syserr $s");
  460. return
  461. # (($w & 0x0ffff) == 0x0ff00 ? "problems running program - exit code -1" :
  462. # ($w & 0x0ff) == 0 ? "exit status ".(($w & 0x0ff00) >> 8) :
  463. # ($w & 0x0ff) == 0x07f ? "stopped by signal ".(($w & 0x0ff00) >> 8) :
  464. # "killed by signal ".($w & 0x07f).($w & 0x080 ? " (core dumped)" : '')).
  465. (&WIFEXITED($w) ? "exit status ".&WEXITSTATUS($w) :
  466. &WIFSIGNALED($w) ? "killed by signal ".&WTERMSIG($w).
  467. (&WCOREDUMP($w) ? " (core dumped)" : ""):
  468. &WIFSTOPPED($w) ? "stopped due to signal ".&WSTOPSIG($w) :
  469. "unknown status $w").
  470. ($s ? ", system error $s" : '');
  471. }
  472. #*** miscellaneous helpful routines ***#
  473. sub readall {
  474. local ($fh) = @_;
  475. local ($r,$n,$this) = '';
  476. for (;;) {
  477. defined($n=read($fh,$this,4096)) || return undef;
  478. $n || last;
  479. $r.= $this;
  480. }
  481. return $r;
  482. }
  483. #sub debug_compare_verrevs {
  484. # local (@i)= @_;
  485. # local ($i)= &x_compare_verrevs(@i);
  486. # &debug("compare_verrevs >@i< = >$i<");
  487. # return $i;
  488. #}
  489. sub compare_verrevs {
  490. local ($av,$ar,$bv,$br,$c) = @_;
  491. $c = &compare_vnumbers($av,$bv); return $c if $c;
  492. return &compare_vnumbers($ar,$br);
  493. }
  494. sub compare_vnumbers {
  495. local ($a, $b) = @_;
  496. do {
  497. $a =~ s/^\D*//; $ad= $&; $ad =~ s/\W/ /g;
  498. $b =~ s/^\D*//; $bd= $&; $bd =~ s/\W/ /g;
  499. $cm = $ad cmp $bd; return $cm if $cm;
  500. $a =~ s/^\d*//; $ad= $&;
  501. $b =~ s/^\d*//; $bd= $&;
  502. $cm = $ad <=> $bd; return $cm if $cm;
  503. } while (length ($a) && length ($b));
  504. return length ($a) cmp length ($b);
  505. }
  506. sub sync {
  507. system('sync');
  508. }