Advertisement
Guest User

vrms

a guest
Feb 8th, 2016
263
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Bash 11.03 KB | None | 0 0
  1. #!/usr/bin/perl
  2. #
  3. # This program is free software; you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation; either version 2 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  11. # GNU General Public License for more details.
  12. #
  13.  
  14. use strict;
  15. use warnings;
  16.  
  17. use Getopt::Long;
  18.  
  19. # Declaration of important/main variables.
  20. my $quiet = 0;
  21. my $sparse = 0;
  22. my $help = 0;
  23. my $explain = 1;
  24. my $debug = 0;
  25. my $reasondir = '/usr/share/vrms/reasons/';
  26. my %reason = ();
  27.  
  28. #
  29. # Auxiliary functions section (FIXME: put them in a file by themselves).
  30. #
  31.  
  32. # sub usage:
  33. # Input: nothing.
  34. # Output: Messages to stdout telling the usage of the program.
  35. sub usage() {
  36.     print <<EOF;
  37. Usage: vrms [OPTIONS] ...
  38.  
  39. --quiet, -q     Do nothing if there are no non-free packages installed.
  40. --explain, -e       Give a brief explanation of why a package is non-free,
  41.               if available.
  42. --sparse, -s        Just list non-free packages, nothing else.
  43. --reason-dir=DIR    Use DIR as the reason directory.
  44. --help, -h      Display this help.
  45. --debug, -d     Generate debugging information.
  46.  
  47. All options can be prefixed with "no" (eg: --noexplain) to turn them off.
  48. EOF
  49. }
  50.  
  51. # sub parse_reason_file:
  52. # Input: the name of a reason file and the global hash %reason
  53. # Output: the hash %reason filled with reasons from the input file
  54. # (FIXME: %reason shouldn't be global)
  55. sub parse_reason_file {
  56.     my $file = shift;
  57.     print "Parsing reason file $file\n" if $debug >= 1;
  58.     open(REASON, "<", $file) or
  59.     die "Can't open FILE [$file]: $!\n";
  60.    
  61.     while (my $line = <REASON>) {
  62.     chomp $line;
  63.     # Grab a line of the form 'package: reason', skip if we don't match
  64.     my ($pkg, $reason) = ($line =~ /^(\S+):\s+(.*)\s*$/) or next;
  65.     print "'$pkg' because '$reason'\n" if ($debug >= 1);
  66.    
  67.     # If this is _our_ master file, then prefer anything
  68.     # else (so that package maintainers can override)
  69.     next if exists $reason{$pkg} and $file =~ /\/vrms$/;
  70.    
  71.     $reason{$pkg} = $reason;
  72.     }
  73.    
  74.     close REASON or
  75.     die "Can't close FILE [$file]: $!\n";
  76. }
  77.  
  78. #
  79. # Main program starts here.
  80. #
  81. GetOptions('q|quiet' => \$quiet,
  82.        's|sparse' => \$sparse,
  83.        'e|explain!' => \$explain,
  84.        'reason-dir=s' => \$reasondir,
  85.        'd|debug+' => \$debug,
  86.        'h|help' => \$help);
  87.  
  88. if ($help) {
  89.     usage();
  90.     exit 0;
  91. }
  92.  
  93. opendir(REASONDIR, $reasondir) or
  94.     die "Can't open DIR [$reasondir]: $!\n";
  95. # Parse all the reason files in $reasondir except those beginning with
  96. #  a . or ending with a ~
  97. parse_reason_file("$reasondir/$_")
  98.     foreach (grep {!/~$/ && !/^\./} readdir(REASONDIR));
  99. closedir REASONDIR or
  100.     die "Can't close DIR [$reasondir]: $!\n";
  101.  
  102. my $statusfile = '/var/lib/dpkg/status';
  103. my $is_nonfree = 0;     ###  preset none found, yet
  104. my %nonfree = ();
  105. my $is_other_nonfree = 0;   ###  preset none found, yet
  106. my %other_nonfree = ();
  107. my $is_contrib = 0;     ###  preset none found, yet
  108. my %contrib = ();
  109. my $is_other_contrib = 0;   ###  preset none found, yet
  110. my %other_contrib = ();
  111. my %pkg_status = ();
  112. my $pkgcnt = 0;
  113. my $clumpcnt = 0;
  114. my $dontcarelines = 5;      ### no. of lines a non-installed entry may have in the statusfile
  115.  
  116.  
  117. my $sysname = "";
  118. chop($sysname = `uname -n`);
  119.  
  120. open(PKG_SOURCE, "< $statusfile") or
  121.     die "Can't open FILE [$statusfile]: $!\n";
  122.  
  123. $/ = "";  ###  snarf a paragraph at a time
  124. while(<PKG_SOURCE>) {
  125.     my $clump = $_;
  126.     $clumpcnt++;
  127.     my (@pkglines) = split(/\n/, $clump);
  128.     ###  iff more than $dontcarelines lines, package is installed, so process it
  129.     ###   (speed-up by skipping don't-care entries)
  130.     if (@pkglines > $dontcarelines) {
  131.     my $pkg = "";       ###  name of this package
  132.     my $pkgstatus = ""; ###  status
  133.     my $plan = "";      ###  install plan (hold, deinstall, purge, install, etc.)
  134.     my $state = "";     ###  state (ok or ???)
  135.     my $status = "";    ###  status (installed, not-installed, etc.)
  136.     my $section = "";   ###  section this is where non-free is marked
  137.     my $shortdescr = "";    ###  one-liner description of pkg
  138.     my $linenbr = 0;    ###  current line number of this pkackag's info
  139.     my $label = "";     ###  junk field (not used, except to catch split values)
  140.     my $has_pkg = 0;    ###  reset the markers
  141.     my $has_status = 0;
  142.     my $has_section = 0;
  143.     foreach (@pkglines) {
  144.         chomp;
  145.         $linenbr++;
  146.         if (/^Package:/) {
  147.         ($label, $pkg) =  split(/:\s+/,$_,2);
  148.         $pkgcnt++;
  149.         printf "pkg(%4.4d) pkg=[%s]\n",$pkgcnt,$pkg if $debug >= 1;
  150.         $has_pkg = 1;   ###  we have necessary section
  151.         next;
  152.         }
  153.         if (/^Status:/) {
  154.         my $label = "";
  155.         ($label,  $pkgstatus) = split(/:\s+/,$_,2);
  156.         print "\tpkgstatus=[$pkgstatus]\n" if $debug >= 1;
  157.         $pkg_status{$pkg} = $pkgstatus;
  158.         ($plan, $state, $status) = split(/\s+/,$pkgstatus);
  159.         print "\t\tplan=[$plan]\n" if $debug >= 1;
  160.         print "\t\tstate=[$state]\n" if $debug >= 1;
  161.         print "\t\tstatus=[$status]\n" if $debug >= 1;
  162.         $has_status = 1;    ###  we have necessary section
  163.         next;
  164.         }
  165.         if (/^Section:/) {
  166.         my $label = "";
  167.         ($label, $section) = split(/:\s+/,$_,2);
  168.         print "\tsection=[$section]\n" if $debug >= 1;
  169.         $has_section = 1;   ###  we have necessary section
  170.         if ($section =~ /contrib|non-free|restricted|multiverse|partner/) {
  171.             ###  read thru rest of array to find descr instead of waiting for it
  172.             my $found_descr =0;
  173.             while (! $found_descr) {
  174.             if ($linenbr > $#pkglines) {
  175.                 ###  iff badly formed entry ensure blank description
  176.                 print "\tEEEE shortdescr=[$shortdescr]\n" if $debug >= 1;
  177.                 last;
  178.             }
  179.             my $dline = $pkglines[$linenbr++];
  180.             if($dline =~ /^Description:/) {
  181.                 ($label, $shortdescr) = split(/:\s+/,$dline,2);
  182.                 print "\tshortdescr=[$shortdescr]\n" if $debug >= 1;
  183.                 $found_descr = 1;
  184.             }
  185.             }
  186.             if ($section =~ /contrib/) {
  187.             if (lc $status eq 'installed') {
  188.                 $is_contrib = 1;
  189.                 $contrib{$pkg} = $shortdescr;
  190.             } else {
  191.                 $is_other_contrib = 1;
  192.                 $other_contrib{$pkg} = $shortdescr;
  193.             }
  194.             } else {
  195.             if (lc $status eq 'installed') {
  196.                 $is_nonfree = 1;
  197.                 $nonfree{$pkg} = $shortdescr;
  198.             } else {
  199.                 $is_other_nonfree = 1;
  200.                 $other_nonfree{$pkg} = $shortdescr;
  201.             }
  202.             }
  203.         }
  204.         last;   ### this is last desriptor of package we care about so end loop
  205.         } else {
  206.         ###  un-processed lines from package info
  207.         if($debug >= 1) {
  208.             print "\t\t--- $_\n";
  209.         }
  210.         }
  211.     }
  212.     if (!$has_status or !$has_pkg) {
  213.         print STDERR "vrms: ERROR- Badly formed dpkg-status entry #$clumpcnt!\n";
  214.         print STDERR "             pkg=[$pkg], pkgstatus=[$pkgstatus], section=[$section] \n";
  215.     }
  216.     } else {
  217.     ###  Entries which are 2 or 4 lines are not-installed
  218.     if ($debug >= 1) {
  219.         ###  emit debug so can veryify parsing
  220.         my $lineCt = @pkglines;
  221.         print " SKIPPED <5: $lineCt lines\n";
  222.         foreach (@pkglines) {
  223.         my $spacer = ($_ =~ /Package:/) ? "" : "   ";
  224.         print " SKIPPED <5:$spacer [$_]\n";
  225.         }
  226.     }
  227.     }
  228. }
  229. close (PKG_SOURCE) or
  230.     die "Can't close FILE [$statusfile]: $!\n";
  231.  
  232. #print "$pkgcnt packages installed\n";
  233.  
  234. my $nfcnt = 0;
  235. my $pkgname = "";
  236.  
  237. my $nonfreecnt = (keys %nonfree);
  238.  
  239. if($is_nonfree) {
  240.     if($sparse) {
  241.     foreach $pkgname (sort keys (%nonfree)) {
  242.         $nfcnt++;
  243.         print "$pkgname\n";
  244.     }
  245.     } else {
  246.     $~ = "nonfree_head";
  247.     write ;
  248.     $~ = "nfp";
  249.     foreach $pkgname (sort keys(%nonfree) ) {
  250.         $nfcnt++;
  251.         write ;
  252.         print "  Reason: $reason{$pkgname}\n"
  253.         if (exists $reason{$pkgname} and $explain);
  254.     }
  255.     }
  256. }
  257.  
  258. my $pnfcnt = 0;
  259. my $other_nonfreecnt = (keys %other_nonfree);
  260. if($is_other_nonfree) {
  261.     if($sparse) {
  262.     foreach $pkgname (sort keys(%other_nonfree)) {
  263.         $pnfcnt++;
  264.         print "$pkgname\n";
  265.     }
  266.     } else {
  267.     $~ = "nonfree_partialhead";
  268.     write;
  269.     $~ = "pnf";
  270.     foreach $pkgname (sort keys(%other_nonfree)) {
  271.         $pnfcnt++;
  272.         write;
  273.         print "  Reason: $reason{$pkgname}\n"
  274.         if (exists $reason{$pkgname} and $explain);
  275.     }
  276.     }
  277. }
  278.  
  279. my $cbcnt = 0;
  280.  
  281. my $contribcnt = (keys %contrib);
  282.  
  283. if($is_contrib) {
  284.     print "\n";
  285.     if($sparse) {
  286.     foreach $pkgname (sort keys (%contrib)) {
  287.         $cbcnt++;
  288.         print "$pkgname\n";
  289.     }
  290.     } else {
  291.     $~ = "contrib_head";
  292.     write ;
  293.     $~ = "cbp";
  294.     foreach $pkgname (sort keys(%contrib) ) {
  295.         $cbcnt++;
  296.         write ;
  297.         print "  Reason: $reason{$pkgname}\n"
  298.         if (exists $reason{$pkgname} and $explain);
  299.     }
  300.     }
  301. }
  302.  
  303. my $pcbcnt = 0;
  304. my $other_contribcnt = (keys %other_contrib);
  305. if($is_other_contrib) {
  306.     if($sparse) {
  307.     foreach $pkgname (sort keys(%other_contrib)) {
  308.         $pcbcnt++;
  309.         print "$pkgname\n";
  310.     }
  311.     } else {
  312.     $~ = "contrib_partialhead";
  313.     write;
  314.     $~ = "pcb";
  315.     foreach $pkgname (sort keys(%other_contrib)) {
  316.         $pcbcnt++;
  317.         write;
  318.         print "  Reason: $reason{$pkgname}\n"
  319.         if (exists $reason{$pkgname} and $explain);
  320.     }
  321.     }
  322. }
  323.  
  324. if (!$quiet and !$sparse) {
  325.     printf "\n";
  326.     if ($nfcnt != 0 or $pnfcnt != 0) {
  327.     my $total_nonfree = $nonfreecnt + $other_nonfreecnt;
  328.     my $total_installed = $pkgcnt;
  329.     my $percentage = $total_nonfree * 100 / $total_installed;
  330.     printf "  %d non-free packages, %2.1f%% of %d installed packages.\n",
  331.     $total_nonfree, $percentage, $total_installed;
  332.     }
  333.     if ($cbcnt != 0 or $pcbcnt != 0) {
  334.     my $total_contrib = $contribcnt + $other_contribcnt;
  335.     my $total_installed = $pkgcnt;
  336.     my $percentage = $total_contrib * 100 / $total_installed;
  337.     printf "  %d contrib packages, %2.1f%% of %d installed packages.\n",
  338.     $total_contrib, $percentage, $total_installed;
  339.     }
  340. }
  341. if (!$quiet and $nfcnt == 0 and $pnfcnt == 0 and $cbcnt == 0 and $pcbcnt == 0) {
  342.     print "No non-free or contrib packages installed on $sysname!  rms would be proud.\n"
  343. }
  344.  
  345.  
  346. format nonfree_head =
  347. @||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
  348. "Non-free packages installed on $sysname"
  349.  
  350. .
  351. format nonfree_partialhead =
  352.  
  353. @||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
  354. "Non-free packages with status other than installed on $sysname"
  355.  
  356. .
  357.  
  358. format contrib_head =
  359. @||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
  360. "Contrib packages installed on $sysname"
  361.  
  362. .
  363. format contrib_partialhead =
  364.  
  365. @||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
  366. "Contrib packages with status other than installed on $sysname"
  367.  
  368. .
  369.  
  370. format nfp =
  371. @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  372. $pkgname, $nonfree{$pkgname}
  373. .
  374.  
  375. format pnf =
  376. @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<@<<@< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  377. $pkgname, '(', $pkg_status{$pkgname},')', $other_nonfree{$pkgname}
  378. .
  379.  
  380. format cbp =
  381. @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  382. $pkgname, $contrib{$pkgname}
  383. .
  384.  
  385. format pcb =
  386. @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< @<@<<@< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  387. $pkgname, '(', $pkg_status{$pkgname},')', $other_contrib{$pkgname}
  388. .
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement