Simple accounting filter/backend (With Perl or another script language)

Nayco anonymous at easysw.com
Tue Jun 15 08:59:39 PDT 2004


If someone wishes to help, here is my current full script... Thanks for suggestions !

Oh, I forgot: This is GPLed ;-) (Hell, I stolen this code from other backends, just translated it to Perl !)

#!/usr/bin/perl -w

use strict;
#use Data::Dumper;
use POSIX qw(strftime);
use File::Basename;

# Variables
my $logfile="/tmp/quota_backend.log";

my $backends_dir = dirname($0);
my $me = basename($0);

my $lockfile = $backends_dir."/".$me.".lock";

# We'll use a logfile for developpement, may no need it after...
open (LOG,">>".$logfile) or die "$me: Unable to create logfile $logfile, exiting !";

# Cups backends work this way that when called without argument, they must output
# which devices they manage. As we don't manage anything but just call other backends
# to process the printing, we've got to call them one by one, modifying parts of the
# output. This way, Cups believes that we manage all printers (I stolen this idea
# from Pykota, free software rocks!) ;-)
# NOTE: Cups only calls backends without arguments during its initialisation
# procedure (Or when reloaded), to see what printers are managed. This should never occur
# during normal operation.
if (@ARGV == 0){

  # Search for a lockfile, and exit if it exists.
  # This is mainly to avoid calling ourselves when scanning the backend directory
  # if the corresponding test (see below) fails. Mind you, a P4 XEON 2GHz managed to stay
  # up during 20 second when this script started calling itself in an infinite loop !
  # The Kernel, however, is so altruistic that it kept killing processes to free up
  # memory so this script could bring down the system... ;-)
  # Remember that we don't need any lockfile when called to process a print job (ie
  # with 6 or 7 arguments, see below), and using it would prevent multiple print jobs at a time,
  # somewhat strange for a print server....
  if (-e $backends_dir."/".$me.".lock"){
    print STDERR "Another instance is already running... Bye !\n";
    exit 1;
  }
  # So, if we managed to get here, it's time to create this lockfile...
  open (LOCKFILE, ">".$lockfile) or die "$me: Unable to create lockfile in $backends_dir, exiting !";

  # Feed the logfile...
  print LOG "---> Started at ".strftime ("%a %b %e %H:%M:%S %Y", localtime)."\n";
  print LOG "  Command line: $0\n";
  print LOG "  Arguments: ".join("|", @ARGV)."\n\n";
  print LOG "  I was called with 0 arguments, let's fool Cups !\n";

  # Get the list of all backends from the Cups backends directory:
  my @backends_list = glob($backends_dir.'/*');

  # We gonna echo this list in the logfile, so:
  print LOG "  Backends list:\n";

  # Let's call each backend, filter output, and echo all on STDIN:
  foreach my $backend (@backends_list){
    # Avoid calling ourselves, we are not in need of a brutal reset, are we ?
    next if ($backend =~ /$0/);   # /!\ TODO: Doublecheck this line so that it ALWAYS work !

    # Echo the name of the backend to the logfile...
    print LOG "    - $backend\n";

    # ...And execute the backend, feeding a list with its output.
    my @sortie = `$backend`;

    # This is the pattern that'll check the output of the backends,
    # and extract the four fields:
    my $motif = "^(\\S+)\\s(\\S+)\\s\"([^\"]+)\"\\s\"([^\"]+)\"\$";

    # A given backend may managed many devices, thus outputing many lines:
    # we process each line.
    foreach my $ligne (@sortie){
      # Check the line against the pattern, and extract the fields
      # in the special variables $1, $2, $3 and $4
      if ($ligne =~ $motif){
        # Then we output what Cups expects, lightly modified so we appear
        # in the device list when configuring a new printer: For example,
        # a "socket" printer will appear as "quota:socket://hostname:port"
        print "$1 $me:$2 \"$3\" \"$4 (Quota Managed)\"\n";
        # Don't forget the logfile: He's so hungry !
        print LOG "      $1 $me:$2 \"$3\" \"$4 (Quota Managed)\"\n";
      }
      # If the backend spited a line that doesn't fit our needs, ignore it,
      # but mention it in the logs.
      else {
        print STDERR "Cette ligne est invalide: \"$ligne\"";
        print LOG "Cette ligne est invalide: \"$ligne\"";
      }
    }
  }

  # Remove the lock file...
  close LOCKFILE;
  unlink $lockfile;
}

# OK, back to the main part of the script; We saw what needed to be done when
# called without argument. Now, when Cups has finished its init, it only calls
# us with 6 or 7 arguments. If there are 7, we gotta read the file to print
# ourselves from the given path. If only 6 are given, the file is sent by STDIN.
else {
  print LOG "---> Print job started at ".strftime ("%a %b %e %H:%M:%S %Y", localtime)."\n";
  print LOG "  Command line: $0\n";
  print LOG "  Arguments: ".join("|", @ARGV)."\n\n";
  print LOG "  \$ENV{DEVICE_URI}= ".$ENV{DEVICE_URI}."\n\n";
  print LOG "  Content:\n";

  # If we were called with the wrong number of arguments, exit.
  if ( (@ARGV < 6) || (@ARGV > 7) ){
    print LOG "  Wrong parameter count.\n";
    print LOG "---> Ended at: ".strftime ("%a %b %e %H:%M:%S %Y", localtime)."\n\n\n";
    close LOG;
    die "$me: Too few or too many parameters, exiting!";
  }

### From this point, this is testing only code..... OK, so is the above ;-)

  # If we were called with 6 arguments, read from STDIN to a tempfile:
  #if (@ARGV == 6){
    my $tmpfile= `mktemp </dev/null /tmp/print.XXXXXX`;
    `cat > $tmpfile`;
  #}

  my $cmd='cat $tmpfile|/usr/lib/cups/backend/socket '.join(" ", @ARGV);

  $ENV{DEVICE_URI} =~ s/^comptage:(.*)/$1/;

  print LOG "Commande éxecutée: $cmd\n\n;";
  `$cmd`;

  `cat $tmpfile >> /tmp/comptage/mac_print.log`;
  unlink $tmpfile;
}

print LOG "---> Ended at: ".strftime ("%a %b %e %H:%M:%S %Y", localtime)."\n\n\n";
close LOG;
exit 0;





More information about the cups-devel mailing list