1*3b188dabSeric /* $OpenBSD: lp_displayq.c,v 1.1.1.1 2018/04/27 16:14:36 eric Exp $ */
2*3b188dabSeric
3*3b188dabSeric /*
4*3b188dabSeric * Copyright (c) 2017 Eric Faurot <eric@openbsd.org>
5*3b188dabSeric *
6*3b188dabSeric * Permission to use, copy, modify, and distribute this software for any
7*3b188dabSeric * purpose with or without fee is hereby granted, provided that the above
8*3b188dabSeric * copyright notice and this permission notice appear in all copies.
9*3b188dabSeric *
10*3b188dabSeric * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11*3b188dabSeric * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12*3b188dabSeric * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13*3b188dabSeric * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14*3b188dabSeric * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15*3b188dabSeric * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16*3b188dabSeric * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*3b188dabSeric */
18*3b188dabSeric
19*3b188dabSeric #include <limits.h>
20*3b188dabSeric #include <stdlib.h>
21*3b188dabSeric #include <string.h>
22*3b188dabSeric #include <unistd.h>
23*3b188dabSeric
24*3b188dabSeric #include "lp.h"
25*3b188dabSeric
26*3b188dabSeric #include "log.h"
27*3b188dabSeric
28*3b188dabSeric static void dolong(int, struct lp_printer *, struct lp_jobfilter *, int,
29*3b188dabSeric const char *, int);
30*3b188dabSeric static void doshort(int, struct lp_printer *, struct lp_jobfilter *, int,
31*3b188dabSeric const char *, int);
32*3b188dabSeric
33*3b188dabSeric void
lp_displayq(int ofd,struct lp_printer * lp,int lng,struct lp_jobfilter * jf)34*3b188dabSeric lp_displayq(int ofd, struct lp_printer *lp, int lng, struct lp_jobfilter *jf)
35*3b188dabSeric {
36*3b188dabSeric struct lp_queue q;
37*3b188dabSeric pid_t currpid;
38*3b188dabSeric char status[256], currjob[PATH_MAX];
39*3b188dabSeric int i, active, qstate;
40*3b188dabSeric
41*3b188dabSeric /* Warn about the queue state if needed. */
42*3b188dabSeric if (lp_getqueuestate(lp, 0, &qstate) == -1)
43*3b188dabSeric log_warnx("cannot get queue state");
44*3b188dabSeric else {
45*3b188dabSeric if (qstate & LPQ_PRINTER_DOWN) {
46*3b188dabSeric if (lp->lp_type == PRN_LPR)
47*3b188dabSeric dprintf(ofd, "%s: ", lpd_hostname);
48*3b188dabSeric dprintf(ofd, "Warning: %s is down\n", lp->lp_name);
49*3b188dabSeric }
50*3b188dabSeric if (qstate & LPQ_QUEUE_OFF) {
51*3b188dabSeric if (lp->lp_type == PRN_LPR)
52*3b188dabSeric dprintf(ofd, "%s: ", lpd_hostname);
53*3b188dabSeric dprintf(ofd, "Warning: %s queue is turned off\n",
54*3b188dabSeric lp->lp_name);
55*3b188dabSeric }
56*3b188dabSeric }
57*3b188dabSeric
58*3b188dabSeric /* Read queue content. */
59*3b188dabSeric if ((lp_readqueue(lp, &q)) == -1) {
60*3b188dabSeric log_warnx("cannot read queue");
61*3b188dabSeric if (lp->lp_type == PRN_LPR)
62*3b188dabSeric dprintf(ofd, "%s: ", lpd_hostname);
63*3b188dabSeric dprintf(ofd, "Warning: cannot read queue\n");
64*3b188dabSeric }
65*3b188dabSeric
66*3b188dabSeric /* Display current printer status. */
67*3b188dabSeric if (lp_getcurrtask(lp, &currpid, currjob, sizeof(currjob)) == -1)
68*3b188dabSeric log_warnx("cannot get current task");
69*3b188dabSeric
70*3b188dabSeric if (currpid) {
71*3b188dabSeric if (lp->lp_type == PRN_LPR)
72*3b188dabSeric dprintf(ofd, "%s: ", lpd_hostname);
73*3b188dabSeric if (lp_getstatus(lp, status, sizeof(status)) == -1) {
74*3b188dabSeric log_warnx("cannot read printer status");
75*3b188dabSeric dprintf(ofd, "Warning: cannot read status file\n");
76*3b188dabSeric }
77*3b188dabSeric else
78*3b188dabSeric dprintf(ofd, "%s\n", status);
79*3b188dabSeric }
80*3b188dabSeric
81*3b188dabSeric /* Display queue content. */
82*3b188dabSeric if (q.count == 0) {
83*3b188dabSeric if (lp->lp_type != PRN_LPR)
84*3b188dabSeric dprintf(ofd, "no entries\n");
85*3b188dabSeric }
86*3b188dabSeric else {
87*3b188dabSeric if (currpid == 0) {
88*3b188dabSeric if (lp->lp_type == PRN_LPR)
89*3b188dabSeric dprintf(ofd, "%s: ", lpd_hostname);
90*3b188dabSeric dprintf(ofd, "Warning: no daemon present\n");
91*3b188dabSeric }
92*3b188dabSeric if (!lng) {
93*3b188dabSeric dprintf(ofd, "Rank Owner Job Files");
94*3b188dabSeric dprintf(ofd, "%43s\n", "Total Size");
95*3b188dabSeric }
96*3b188dabSeric for (i = 0; i < q.count; i++) {
97*3b188dabSeric active = !strcmp(q.cfname[i], currjob);
98*3b188dabSeric if (lng)
99*3b188dabSeric dolong(ofd, lp, jf, i+1, q.cfname[i], active);
100*3b188dabSeric else
101*3b188dabSeric doshort(ofd, lp, jf, i+1, q.cfname[i], active);
102*3b188dabSeric }
103*3b188dabSeric }
104*3b188dabSeric
105*3b188dabSeric lp_clearqueue(&q);
106*3b188dabSeric }
107*3b188dabSeric
108*3b188dabSeric static int
checklists(const char * cfname,struct lp_jobfilter * jf,const char * person)109*3b188dabSeric checklists(const char *cfname, struct lp_jobfilter *jf, const char *person)
110*3b188dabSeric {
111*3b188dabSeric int i;
112*3b188dabSeric
113*3b188dabSeric if (jf->nuser == 0 && jf->njob == 0)
114*3b188dabSeric return 1;
115*3b188dabSeric
116*3b188dabSeric /* Check if user is in user list. */
117*3b188dabSeric for (i = 0; i < jf->nuser; i++)
118*3b188dabSeric if (!strcmp(jf->users[i], person))
119*3b188dabSeric return 1;
120*3b188dabSeric
121*3b188dabSeric /* Skip if hostnames don't match. */
122*3b188dabSeric if (strcmp(LP_JOBHOST(cfname), jf->hostfrom))
123*3b188dabSeric return 0;
124*3b188dabSeric
125*3b188dabSeric /* Check for matching jobnum. */
126*3b188dabSeric for (i = 0; i < jf->njob; i++)
127*3b188dabSeric if (jf->jobs[i] == LP_JOBNUM(cfname))
128*3b188dabSeric return 1;
129*3b188dabSeric
130*3b188dabSeric return 0;
131*3b188dabSeric }
132*3b188dabSeric
133*3b188dabSeric static const char *
rankstr(int rank,int active)134*3b188dabSeric rankstr(int rank, int active)
135*3b188dabSeric {
136*3b188dabSeric static char buf[16];
137*3b188dabSeric const char *sfx;
138*3b188dabSeric
139*3b188dabSeric if (active)
140*3b188dabSeric return "active";
141*3b188dabSeric
142*3b188dabSeric sfx = "th";
143*3b188dabSeric switch (rank % 10) {
144*3b188dabSeric case 1:
145*3b188dabSeric if ((rank / 10) % 10 != 1)
146*3b188dabSeric sfx = "st";
147*3b188dabSeric break;
148*3b188dabSeric case 2:
149*3b188dabSeric sfx = "nd";
150*3b188dabSeric break;
151*3b188dabSeric case 3:
152*3b188dabSeric sfx = "rd";
153*3b188dabSeric
154*3b188dabSeric }
155*3b188dabSeric
156*3b188dabSeric snprintf(buf, sizeof(buf), "%d%s", rank, sfx);
157*3b188dabSeric return buf;
158*3b188dabSeric }
159*3b188dabSeric
160*3b188dabSeric static void
doshort(int ofd,struct lp_printer * lp,struct lp_jobfilter * jf,int rank,const char * cfname,int active)161*3b188dabSeric doshort(int ofd, struct lp_printer *lp, struct lp_jobfilter *jf, int rank,
162*3b188dabSeric const char *cfname, int active)
163*3b188dabSeric {
164*3b188dabSeric struct stat st;
165*3b188dabSeric FILE *fp;
166*3b188dabSeric const char *fname;
167*3b188dabSeric char dfname[PATH_MAX], names[80], *line = NULL;
168*3b188dabSeric ssize_t len;
169*3b188dabSeric size_t linesz = 0, totalsz = 0;
170*3b188dabSeric int copies = 0;
171*3b188dabSeric
172*3b188dabSeric fp = lp_fopen(lp, cfname);
173*3b188dabSeric if (fp == NULL) {
174*3b188dabSeric log_warn("cannot open %s", cfname);
175*3b188dabSeric return;
176*3b188dabSeric }
177*3b188dabSeric
178*3b188dabSeric names[0] = '\0';
179*3b188dabSeric
180*3b188dabSeric while ((len = getline(&line, &linesz, fp)) != -1) {
181*3b188dabSeric if (line[len-1] == '\n')
182*3b188dabSeric line[len - 1] = '\0';
183*3b188dabSeric switch (line[0]) {
184*3b188dabSeric case 'P':
185*3b188dabSeric if (!checklists(cfname, jf, line + 1))
186*3b188dabSeric goto end;
187*3b188dabSeric
188*3b188dabSeric dprintf(ofd, "%-7s%-11s%-4i ", rankstr(rank, active),
189*3b188dabSeric line + 1, LP_JOBNUM(cfname));
190*3b188dabSeric break;
191*3b188dabSeric
192*3b188dabSeric case 'N':
193*3b188dabSeric fname = line + 1;
194*3b188dabSeric if (!strcmp(fname, " "))
195*3b188dabSeric fname = "(standard input)";
196*3b188dabSeric
197*3b188dabSeric if (names[0])
198*3b188dabSeric (void)strlcat(names, ", ", sizeof(names));
199*3b188dabSeric (void)strlcat(names, fname, sizeof(names));
200*3b188dabSeric if (lp_stat(lp, dfname, &st) == -1)
201*3b188dabSeric log_warn("cannot stat %s", dfname);
202*3b188dabSeric else
203*3b188dabSeric totalsz += copies * st.st_size;
204*3b188dabSeric copies = 0;
205*3b188dabSeric break;
206*3b188dabSeric
207*3b188dabSeric default:
208*3b188dabSeric if (line[0] < 'a' || line[0] > 'z')
209*3b188dabSeric continue;
210*3b188dabSeric if (copies++ == 0)
211*3b188dabSeric (void)strlcpy(dfname, line+1, sizeof(dfname));
212*3b188dabSeric break;
213*3b188dabSeric }
214*3b188dabSeric }
215*3b188dabSeric
216*3b188dabSeric dprintf(ofd, "%-37s %lld bytes\n", names, (long long)totalsz);
217*3b188dabSeric
218*3b188dabSeric end:
219*3b188dabSeric free(line);
220*3b188dabSeric }
221*3b188dabSeric
222*3b188dabSeric static void
dolong(int ofd,struct lp_printer * lp,struct lp_jobfilter * jf,int rank,const char * cfname,int active)223*3b188dabSeric dolong(int ofd, struct lp_printer *lp, struct lp_jobfilter *jf, int rank,
224*3b188dabSeric const char *cfname, int active)
225*3b188dabSeric {
226*3b188dabSeric struct stat st;
227*3b188dabSeric FILE *fp;
228*3b188dabSeric const char *fname;
229*3b188dabSeric char dfname[PATH_MAX], names[80], buf[64], *line = NULL;
230*3b188dabSeric ssize_t len;
231*3b188dabSeric size_t linesz = 0;
232*3b188dabSeric int copies = 0;
233*3b188dabSeric
234*3b188dabSeric fp = lp_fopen(lp, cfname);
235*3b188dabSeric if (fp == NULL) {
236*3b188dabSeric log_warn("cannot open %s", cfname);
237*3b188dabSeric return;
238*3b188dabSeric }
239*3b188dabSeric
240*3b188dabSeric names[0] = '\0';
241*3b188dabSeric
242*3b188dabSeric while ((len = getline(&line, &linesz, fp)) != -1) {
243*3b188dabSeric if (line[len-1] == '\n')
244*3b188dabSeric line[len - 1] = '\0';
245*3b188dabSeric switch (line[0]) {
246*3b188dabSeric case 'P':
247*3b188dabSeric if (!checklists(cfname, jf, line + 1))
248*3b188dabSeric goto end;
249*3b188dabSeric
250*3b188dabSeric snprintf(buf, sizeof(buf), "%s: %s", line+1,
251*3b188dabSeric rankstr(rank, active));
252*3b188dabSeric dprintf(ofd, "\n%-41s[job %s]\n", buf, cfname + 3);
253*3b188dabSeric break;
254*3b188dabSeric
255*3b188dabSeric case 'N':
256*3b188dabSeric fname = line + 1;
257*3b188dabSeric if (!strcmp(fname, " "))
258*3b188dabSeric fname = "(standard input)";
259*3b188dabSeric
260*3b188dabSeric if (copies > 1)
261*3b188dabSeric dprintf(ofd, "\t%-2d copies of %-19s", copies,
262*3b188dabSeric fname);
263*3b188dabSeric else
264*3b188dabSeric dprintf(ofd, "\t%-32s", fname);
265*3b188dabSeric
266*3b188dabSeric if (lp_stat(lp, dfname, &st) == -1) {
267*3b188dabSeric log_warn("cannot stat %s", dfname);
268*3b188dabSeric dprintf(ofd, " ??? bytes\n");
269*3b188dabSeric }
270*3b188dabSeric else
271*3b188dabSeric dprintf(ofd, " %lld bytes\n",
272*3b188dabSeric (long long)st.st_size);
273*3b188dabSeric copies = 0;
274*3b188dabSeric break;
275*3b188dabSeric
276*3b188dabSeric default:
277*3b188dabSeric if (line[0] < 'a' || line[0] > 'z')
278*3b188dabSeric continue;
279*3b188dabSeric if (copies++ == 0)
280*3b188dabSeric (void)strlcpy(dfname, line+1, sizeof(dfname));
281*3b188dabSeric break;
282*3b188dabSeric }
283*3b188dabSeric }
284*3b188dabSeric
285*3b188dabSeric end:
286*3b188dabSeric free(line);
287*3b188dabSeric }
288