2

I'm looking for a way to view the timestamp of a job in CUPS. I've searched the man pages and can't seem to find it.

The long term goal is to have a script that parses the time from the jobID and will automatically delete any job that is over a certain age - to avoid overloading the server. My CUPS server has over 2000 print queues.

forraceg
  • 23
  • 3
  • CUPS maintains a directory of files under `/var/spool/cups`. Did you have a look there? – slm Oct 08 '14 at 01:21

3 Answers3

2

I found the following 2 questions within the U&L site that would seem to give hints as a possible way to do this. These 2 questions:

Would seem to imply that you could use lpstat to get what you want. I noticed that I could run this command:

$ sudo lpstat -W completed
mfc-8480dn-1652         root              1024   Tue 28 Jan 2014 01:19:34 AM EST

And this one:

$ sudo lpstat -W completed -u saml | head -2
mfc-8480dn-1524         saml             23552   Thu 28 Nov 2013 10:45:44 AM EST
mfc-8480dn-1526         saml            699392   Sat 30 Nov 2013 10:34:34 AM EST

But the -u all did nothing for me.

$ sudo lpstat -W completed -u all | head -2
$

Curiously I could do this:

$ sudo lpstat -W completed -u saml,root | head -3
mfc-8480dn-1524         saml             23552   Thu 28 Nov 2013 10:45:44 AM EST
mfc-8480dn-1526         saml            699392   Sat 30 Nov 2013 10:34:34 AM EST
mfc-8480dn-1652         root              1024   Tue 28 Jan 2014 01:19:34 AM EST

So one hackish way to do this would be to formalize a list of the users on your system and then add that as a subcommand to the -u argument like so:

$ sudo lpstat -W completed -u $(getent passwd | \
    awk -F: '{print $1}' | paste -sd ',')

Just to show that this sees all the users locally you can get a unique list of your users like so:

$ sudo lpstat -W completed -u $(getent passwd | \
    awk -F: '{print $1}' | paste -sd ',') | awk '{print $2}' | sort -u
ethan
root
sam
tammy

Issues?

One problem with this is if the user printing to CUPS does not have an account locally then they won't get displayed.

But if you have a directory that contains your LPD control files, typically it's /var/spool/cups, you'll notice a bunch of control files in there. These files are kept as a result of theMaxJobs` setting, which defaults to 500 when unset.

$ sudo ls -l /var/spool/cups/ | wc -l
502

Another source of usernames?

If you look through these files you'll notice that they contain usernames, and not just ones for accounts that are present on the system.

$ strings /var/spool/cups/* | grep -A 1 job-originating-user-name | head -5
job-originating-user-name
tammyB
--
job-originating-user-name
tammyB

So we could select all the entries that contain the username followed by the B.

$ sudo strings /var/spool/cups/* | grep -A 1 job-originating-user-name | \
    grep -oP '.*(?=B)' | sort -u
ethan
guest-AO22e7
root
sam
saml
slm
tammy

This list can then be adapted in the same way as we were originally using to take the list of users from getent passwd, like so:

$ sudo lpstat -W completed -u $(strings /var/spool/cups/* | \
    grep -A 1 job-originating-user-name | \
    grep -oP '.*(?=B)' |sort -u | paste -sd ',') 
mfc-8480dn-1525         tammy           545792   Thu 28 Nov 2013 01:36:59 PM EST
mfc-8480dn-1526         saml            699392   Sat 30 Nov 2013 10:34:34 AM EST
mfc-8480dn-1652         root              1024   Tue 28 Jan 2014 01:19:34 AM EST
mfc-8480dn-1672         saml              1024   Sun 09 Feb 2014 01:56:26 PM EST

References

slm
  • 363,520
  • 117
  • 767
  • 871
  • Thanks SLM. The 'lpstat -W not-completed' was especially helpful. I've combined that with an 'awk '{ print $5 $6 $8}' to display only the date data. I need to find a way to convert the abbreviated month to numbers so that I can do a datediff and have anything over a set amount automatically cancelled (if I even need to do a datediff). Unless you know of a ready way to do that then I'll probably just make start a new question – forraceg Oct 21 '14 at 22:15
  • @forraceg - nothing baked into CUPS, so that will require some scripting. IF this A solved your pls remember to mark it as accepted so other's know your issue's been resolved. I'd start another Q for the date thing if you do not know how to approach it. – slm Oct 21 '14 at 22:41
  • Use only `-u` without passing any usernames. Then it returns the jobs of all users. – mgutt May 25 '23 at 14:47
0

I have another perhaps simpler approach to cleaning up old print jobs. Instead of finding a way to convert the abbreviated time stamps on the print jobs, it's easier to use the find command to accomplish the task of deleting old print jobs fitting a certain criteria. For example, if you want to find print jobs older than 4 days:

find /var/spool/cups -name "*-001" -mtime +4

All active print jobs in cups have files in /var/spool/cups with the extension -001. After that, it's just a matter of using your favorite string manipulation tool to grab the actual print job number from the output.

don_crissti
  • 79,330
  • 30
  • 216
  • 245
cyong
  • 1
0

Actually, ignore all this completely, and don't bother trying to get the date from the job list at all. You don't need to, unless you need a pinpoint accurate printjob timestamp (and even then, it is not immediately apparent from the output or the manual of lpstat whether the given datetime is of when the job was sent or when it was completed).

You don't need to do it at all because you can just generate a datestamp of 'now' at the moment you detect your job in the "completed" jobs list.

._. printJob=$(lp somefile | awk '{print $4}')
._. printJobCompleted=$(lpstat -W "completed" | grep $printJob )
._. printedDatestamp=$(date +%s)

Though of course you can't tell the job is completed till it is. So you might want to loop and sleep till you detect it is.

If you do want the date that's in the queue, perhaps do something like this:

Capture your print job id when you send the instruction to print:

._. printJob=$(lp somefile | awk '{print $4}')
._. echo $printJob
Kyocera-ECOSYS-P5021cdw-564

(It's necessary to parse lp's output through awk because it seems lp has no option to simply return the print job):

._. lp somefile
request id is Kyocera-ECOSYS-P5021cdw-568 (1 file(s))

(awk '{print $4}' get's the fourth word of that output string).

Then use lpstat to get the completed job details:

._. lpstat -W "completed" | grep $printJob
Kyocera-ECOSYS-P5021cdw-564 ming             2048   Sun 18 Apr 2021 11:20:56 BST

Isolating that part of it that includes the date is a bit awkward, because lpstat seems to offer now direct way to do it, and the date consists of multiple words. So perhaps either:

._. printJobDateString=$(lpstat -W "completed" | grep $printJob | awk '{print $4,$5,$6,$7,$8,$9}')

._. echo $printJobDateString
Sun 18 Apr 2021 11:20:56 BST

(And neither does awk seem to offer of way of capturing a range - please correct me if I am wrong).

... or do the same with the shell built-in read, which, for reasons I do not know, does treat the whole date string as a single word (the fourth word in the output string, where read marks the first four words with the names a,b,c,d):

._. printJobDateString=$(lpstat -W "completed" | grep $printJob | while read a b c d; do echo "$d"; done)
._. echo $printJobDateString
Sun 18 Apr 2021 11:20:56 BST

Finally, perhaps turn it into a seconds-since-epoch datestamp, for ease of comparison:

._. printedDatestamp=$(date --date="$printJobDateString" +%s)
._. echo $printedDatestamp
1618741256

printJobDateString will be empty if lpstat had no record of the job in its completed list. In that case, date will assume it to be 1/1/1970 when you convert it to epoch seconds.

Actually though, it might be quite unlikely that your print job does not end up in the "completed" jobs list, because that list seems to collect cancelled jobs as well as completed jobs. So ignore the warning below. Ha.

Beware though, if lpstat doesn't have your print job, it will return an empty string. And if you feed 'date' an empty string, it will spit out today's date. And if you have that in a script, it might mislead you into thinking the job has completed, because it will give you today's date.

For example:

._. date -d @$(date --date="" +%s) +"%F %T %z"
2021-04-17 00:00:00 +0100

Whereas, 'date' takes 0 to be the start of the Unix 'epoch' (the dawn of groovy time) - 1 January 1970:

._. date -d @0 +"%F %T %z"
1970-01-01 01:00:00 +0100

This might more usefully indicate a non-completed job than today's date. So turn the empty string to a zero (if you get one) before feeding it to 'date', perhaps like this:

._. emptyString=""
._. zero=$( [[ -z "$emptyString" ]] && echo 0 || echo "$emptyString" )
._. echo zero
0

In other words, generate the datestamp like this:

._. printedDatestamp=$(date --date="$( [[ -z "$printJobDateString" ]] && echo 0 || echo "$printJobDateString" )" +%s)

Finally, all the steps together:

._. printJob=$(lp -P "1-4" -o fit-to-page -o number-up=2 -o sides=two-sided-short-edge -o KCEcoprint=On "$fn" | awk '{print $4}')
._. printJobDateString=$(lpstat -W "completed" | grep $printJob | while read a b c d; do echo "$d"; done)
._. printedDatestamp=$(date --date="$( [[ -z "$printJobDateString" ]] && echo 0 || echo "$printJobDateString" )" +%s)

P.S.

Use sleep as well, after sending the print job, in a loop that keeps going till you get an empty string, by grepping your printJob over the output of lpstat -W "not-completed". Only then poll lpstat -W "completed".

There: the timestamp of a print job. And who was it who said that linux print control was humane? Nobody. Nobody said any such thing. And anything they did say about it they muttered under their breath.

markling
  • 183
  • 16