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