Accsnmp is a hardware accounting wrapper backend for CUPS that queries the printer for pagecount directly over SNMP.
Accsnmp is an accounting backend for CUPS, inserted between the filter layer
and the backend layer as a wrapper around other CUPS backends. It attempts to
address some of the shortcomings inherent in the CUPS accounting design:
1) It will account correctly for raw queues, for which CUPS cannot natively.
2) It deals directly with the hardware printer device to find out how many
pages were printed. This means that any and every printer job language is
supported, requiring no parsing of the job itself. Even in postscript, there
is a relative lack of standard practice in creating DSC compliant documents.
Dealing with the hardware is bound to be more accurate.
This backend is designed to work with any of the other backends that address a
printer by IP address. In other words, printer device types that have a URI
containing an IP address. Accsnmp works by wrapping that other backend and
parsing the device URI to figure out what device to query. It has been tested
extensively with the lpd backend, and also the socket and ipp backends.
Accounting is accomplished by storing each user's printing total in a series of
flat text files, one per user. Very simple and all done in one self-contained
accounting function. Rewrite to taste.
This backend requires:
1) Perl 5.8.x
2) The Net::SNMP Perl module
3) A printer that supports the common printer MIB
Virtually every OS comes with Perl, and to install the Net::SNMP module,
read up on using CPAN. You can test number three easily enough by using the
snmpget command-line tool on a Linux box. At the top of the script you will
find a couple of variables named *_oid. Run manual queries against your
printers using the values of those variables like so:
$ snmpget -v 1 -c 'public' 192.168.100.100 18.104.22.168.22.214.171.124.126.96.36.199.1
$ snmpget -v 1 -c 'public' 192.168.100.100 188.8.131.52.184.108.40.206.220.127.116.11
If they return something other than a timeout or garbage, you should be set.
If you have gotten this far, the rest is easy. Download the script and copy
it into the CUPS backends directory, which is typically /usr/lib/cups/backend.
Once there, you have to send CUPS a SIGHUP for it to re-scan all the available
$ killall -HUP cupsd
$ /etc/init.d/cups reload
A restart will work just as well, but there is no real need to stop and start
the server daemon.
Now check the web interface. When creating or modifying printers, you should
see an option for an "Accounted Printer (SNMP)" in the dropdown box of
Since CUPS 1.2 or 1.3, it seems that specific permissions must be set on the
backend. Otherwise it will fail to appear in the dropdown list, or report
"/usr/lib/cups/backend/accsnmp failed" in the logs. Matching the lpd backend
in recent versions of CUPS:
$ chown root:root /usr/lib/cups/backend/accsnmp
$ chmod 700 /usr/lib/cups/backend/accsnmp
This backend will almost certainly not work on your system until you visit
the next section about setup and configuration.
This script is designed to be very flexible and assumes a few things about
your system which you may need or want to change. This is controlled by a
series of variables at the top of the script. While a handful are to be
understood as system globals to be set in the script, all variables in the
\%conf hash, while possible to set in-script, can be overridden on a per-queue
basis in the qconf configuration file.
The below variables are listed with their default setting and description.
System Global Variables
These variables are set in the script, and are therefore global in scope.
- backend_dir = /usr/lib/cups/backend
The location of the CUPS backends on your system.
- queues_conf = /etc/cups/queues.conf
The location of the accsnmp configuration file in "qconf" format (see below).
If this file does not exist, accsnmp will use only the defaults in the script.
- acc_printer_list = /etc/cups/accounted-printers.txt
Deprecated configuration file that merely marked certain queues as color
printers to adjust page accounting. This file will still be referenced if it
exists, but is due to be removed in a future release.
These variables have vanilla defaults in the script, but can be overridden on a
per-queue basis in the qconf file if you so choose.
- acc_dir => /var/log/cups/acc
This is the location of the directory containing the text files into which
user printing totals are written by the accounting function provided within
the script. Make sure this directory exists and is writable by the CUPS
user:group (example lp:sys). When set to nothing, user totals are not kept.
- acc_factor => 1
Multiply page counts by this number. Can be any whole number or decimal. If
decimal, see acc_precision.
- acc_log => ''
Normally accsnmp sends page log messages to the CUPS page_log. However, it
can log elsewhere if this variable is set. When set to nothing, logs to
- acc_precision => 0
Determines the number of decimal places to maintain when page counts are
fractional numbers. Note that decimals may not print correctly in the
standard page log.
- backend_attempts => 0
Number of times accsnmp will retry the backend it is wrapping before giving up
and exiting with error. In CUPS 1.1.x, backends try to print to a printer for
several minutes before exiting with error and disabling the queue, while later
CUPS behavior is determined by printer-error-policy. If set to 0, accsnmp
will try forever.
- check_job => 0
If set to 1, all printjob titles are checked against a list of baddies. This
is not horribly safe, but can be useful as a quick measure to prevent certain
jobs from printing. Salt the check_job function to taste. If set to 0, no
checks are done.
- check_user => 0
If set to 1, all printjob usernames are checked against a list of baddies.
This is not horribly safe, but can be useful as a quick measure to prevent
certain accounts from printing. Salt the check_user function to taste. If
set to 0, no checks are done.
Note: As there is no authentication at this stage of printing, usernames are
only as reliable as any authentication (or complete lack thereof) that is done
in the frontend on the queue itself.
- debug => 0
If set to 1, print debugging info to /tmp/$q.debug.
- lock_alarm => 0
When locking is in use (see lock_file), determines how long in seconds accsnmp
will try to establish a lock before exiting with error. If set to 0, accsnmp
will try forever. See the section on locking.
- lock_file => ''
When set to a writable file path, accsnmp will ensure no other accsnmp
processes set to use this same lock file will print until the lock is
released. When set to nothing, no locking is done. See the section on
- pagecount_oid => '18.104.22.168.22.214.171.124.126.96.36.199.1'
The SNMP OID for the printer hardware page counter.
- printerstatus_oid => '188.8.131.52.184.108.40.206.220.127.116.11'
The SNMP OID for the printer status indicator.
- save_job => 0
When set to 1, temporary files are saved in the CUPS temp directory for later
- snmp_alarm => 0
Determines how long in seconds accsnmp will keep trying snmp gets against the
printer. When set to 0, accsnmp will try forever.
- snmp_community => 'public'
The public, read-only SNMP community.
Variables above can be optionally overridden on a per-queue basis through an
external configuration file.
The qconf file is formatted exactly like the printcap file, except that
comments, blank lines, and whitespace between all elements are allowed. All
variables above can be overridden on a per-queue basis. Location is
determined by the queues_conf variable. If this file does not exist,
variable values are simply those set in the script. Example file:
# TEST1 has debugging, saving jobs, and factor four set
# TEST2 is identical
TEST2 | debug : save_jobs : acc_factor=4
# Some other random configuration
TEST3 | acc_factor=.49 : acc_precision=6
TEST4 | acc_dir=/var/cupsacc/counts : acc_log=/var/cupsacc/fakelog
This is a deprecated configuration file that simply lists accounted queues,
with a scheme for marking those that are color. Location is determined by the
acc_printer_list variable. If this file exists, containing the queue in
question, and the queue is marked color, the acc_factor is set to 3. Example
Because accsnmp queries the hardware to determine the pagecount for a job,
accsnmp takes great pains to ensure that jobs are submitted serially to the
printer, returning only when the wrapped backend is finished and any
accounting chores are done. No extra locking is necessary when just one
accsnmp queue prints to just one printer.
When multiple accsnmp queues print to one printer, external locking must be
done to ensure all queues coordinate to submit jobs serially. Otherwise, a
previous job may still be in progress, and SNMP queries for count and status
could be thrown off on subsequent jobs, practically ensuring accounting
With accsnmp-1.03, the option to specify a lock_file exists. As an example,
assume two queues TEST1 and TEST2. If we edit the queues_conf file as such:
TEST1 | lock_file=/etc/cups/locks/TEST
TEST2 | lock_file=/etc/cups/locks/TEST
Both queues will abide by the locks set on the TEST file at the given path,
ensuring that jobs are printed serially, and print totals are accounted
correctly. A lock_alarm can also be set, which will cause accsnmp to exit
after the given number of seconds if the file cannot be locked.
Note: The chosen file path needs to be writable by the backend, often root,
and will be overwritten with each print job, so take care not to point it at
Note: Lock alarms are not of much use when using the retry-job printer error
policy, since the job will remain queued, and CUPS will simply try again.
Note: You probably only want to set this in the qconf file rather than the
script unless you really do want only one system-wide accsnmp job to print at
a time. This is intended for queues pointing to the same printer to avoid
You may wish to simply setup a printer and try to fire away test pages,
looking at the CUPS log to see what problems exist. Set it up initially with
a device URI like this:
Check the logs. Try enabling debugging within the script. If it all works,
enjoy. Good luck!
1) With a wrapper inserted in this way, stopping and starting the queue while
jobs are backed up will requeue the first job and leave an orphan wrapped
backend job sitting on the system waiting to print. I know of no way around
this and it hasn't been much of an issue in our experience.
2) Currently this backend may not do duplex accounting the way you wish.
It accounts each face of a duplex sheet as one page of printing, so a
two-sided printout will count for two pages. I am aware of a potential fix
courtesy of a gentleman named Werner Maes, but I have not implemented it
because we find that the reality of duplex printing is that it costs just as
much or more per sheet than one-sided printing given the extra mechanical
complexity and wear-and-tear involved. With the new qconf file, this is more
3) I have run across printers now and then whose status does not change during
printing or changes unreliably. This is a pain because the backend will not
loop correctly checking the printer status, or will report that something
printed when in fact nothing has. On most of the HPs, Canons, and Epsons I
have had access to, only a couple printers were a problem. And usually these
issues only presented on edge cases (printing to a printer that is jammed or
out of paper)
accsnmp 1.04 (20120419)
- Integrated perldoc.
accsnmp 1.03 (20100413)
- Tested heavily against cups-1.2.x, lightly against cups-1.3.x, and
particularly against cups-1.4.x.
- All script variables can be overridden on a per-queue basis using new
"qconf" configuration file format. Most variables renamed in a more
consistent manner to fit with this scheme.
- New config variables acc_factor and acc_precision, to allow for custom
per-queue page accounting, and even fractional values.
- New config variables lock_file and lock_alarm, to allow for multiple accsnmp
queues to safely share one printer.
- URI syntax check loosened to accept accsnmp:/<original uri> as well as
accsnmp://<original uri>, since the latter will no longer work with
cups-1.4.x. Reported by Gilles Sadowski.
- Page log output now prints "npages accsnmp" rather than "username npages"
since the latter will no longer work with cups-1.4.x, and reprinting the
username is redundant anyway.
- Signals warn and die are now trapped and send messages to cups error log.
- More debug output.
- Fixed a logic error when backend attempts = 1 that caused the backend to
bail out with an error but still print.
- Fixed comment errors pointed out by Marcus Lauer.
- James Nau pointed out that everywhere I was doing a forceExit, I should have
just exited with return code 5, which means cancel the job. RTFM the backend
- Tempfile renamed to indicate it was created by accsnmp.
- The snmp_get function now checks to see if there was actually a non-null value
returned. Some devices are crap.
accsnmp 1.02 (20070124)
- The addition of a changelog :)
- The accounting function will now set the username to "NO_USER" if no username
is given. Otherwise, accsnmp will print, but not log the job. This is moot if
$USER_BLACKLIST is on (in which case printing will be blocked with no username).
- More comment cleanup.
- Main body eval/alarm loop removed and put into snmpGet function to control all
snmp gets. Controlled by $SNMP_ALARM variable, where accsnmp will try to reach
the printer on each snmp get for $SNMP_ALARM seconds. 0 for infinite.
- Fixed bug where ugly Net::SNMP hash reference was printed instead of the
error itself. RTFM.
- The URI is now handled much more simply, and there is now a syntax check of
the URI itself as seen in the beh backend.
- Fixed bug reported by Till Kamppeter: copies needs to be set to 1 when a filter/backend
does not see a printfile argument. RTFM.
- Now only spools a temp file if job arrives on STDIN, or $SAVE_JOBS = 1. Saves
us from pointless spooling as we already have a print file to work with.
- The backend we are wrapping is now also governed by a while loop. Controlled by
$BACKEND_ATTEMPTS variable. Setting to 0 means infinite retries.
- The DEVICE_URI environment variable was not reset before handoff to real
backend. Affected ipp backend at least. Found by Sarosh Jamal.
accsnmp 1.01 (20050606)
- 1.00 with very minor documentation cleanup.
accsnmp 1.00 (20050224)
- Initial release.