xref: /openbsd-src/usr.sbin/lpd/lp_displayq.c (revision 3b188dab47094e37e38dcd2dcd35528ab7a95e4d)
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