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