Bug Summary

File:src/usr.sbin/lpr/lpc/cmds.c
Warning:line 390, column 3
Address of stack memory associated with local variable 'prbuf' is still referred to by the global variable 'printer' upon returning to the caller. This will be a dangling reference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name cmds.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/lpr/lpc/obj -resource-dir /usr/local/lib/clang/13.0.0 -I /usr/src/usr.sbin/lpr/lpc/../common_source -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/lpr/lpc/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/usr.sbin/lpr/lpc/cmds.c
1/* $OpenBSD: cmds.c,v 1.28 2018/04/26 12:42:51 guenther Exp $ */
2/* $NetBSD: cmds.c,v 1.12 1997/10/05 15:12:06 mrg Exp $ */
3
4/*
5 * Copyright (c) 1983, 1993
6 * The Regents of the University of California. All rights reserved.
7 *
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34/*
35 * lpc -- line printer control program -- commands:
36 */
37
38#include <sys/time.h>
39#include <sys/stat.h>
40
41#include <signal.h>
42#include <fcntl.h>
43#include <errno(*__errno()).h>
44#include <dirent.h>
45#include <unistd.h>
46#include <limits.h>
47#include <stdlib.h>
48#include <stdio.h>
49#include <ctype.h>
50#include <string.h>
51#include "lp.h"
52#include "lp.local.h"
53#include "lpc.h"
54#include "extern.h"
55#include "pathnames.h"
56
57static void abortpr(int);
58static void cleanpr(void);
59static void disablepr(void);
60static int doarg(char *);
61static int doselect(const struct dirent *);
62static void enablepr(void);
63static void prstat(void);
64static void putmsg(int, char **);
65static int sortq(const struct dirent **, const struct dirent **);
66static void startpr(int);
67static void stoppr(void);
68static int touch(struct queue *);
69static void unlinkf(char *);
70static void upstat(char *);
71
72/*
73 * kill an existing daemon and disable printing.
74 */
75void
76doabort(int argc, char **argv)
77{
78 int c, status;
79 char *cp1, *cp2;
80 char prbuf[100];
81
82 if (argc == 1) {
83 printf("usage: abort {all | printer ...}\n");
84 return;
85 }
86 if (argc == 2 && strcmp(argv[1], "all") == 0) {
87 printer = prbuf;
88 while (cgetnext(&bp, printcapdb) > 0) {
89 cp1 = prbuf;
90 cp2 = bp;
91 while ((c = *cp2++) && c != '|' && c != ':' &&
92 (cp1 - prbuf) < sizeof(prbuf) - 1)
93 *cp1++ = c;
94 *cp1 = '\0';
95 abortpr(1);
96 }
97 return;
98 }
99 while (--argc) {
100 printer = *++argv;
101 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
102 printf("cannot open printer description file\n");
103 continue;
104 } else if (status == -1) {
105 printf("unknown printer %s\n", printer);
106 continue;
107 } else if (status == -3)
108 fatal("potential reference loop detected in printcap file");
109 abortpr(1);
110 }
111}
112
113static void
114abortpr(int dis)
115{
116 FILE *fp;
117 struct stat stbuf;
118 int pid, fd;
119
120 if (cgetstr(bp, "sd", &SD) == -1)
121 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
122 if (cgetstr(bp, "lo", &LO) == -1)
123 LO = DEFLOCK"lock";
124 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
125 printf("%s:\n", printer);
126
127 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
128 /*
129 * Turn on the owner execute bit of the lock file to disable printing.
130 */
131 if (dis) {
132 if (stat(line, &stbuf) >= 0) {
133 stbuf.st_mode |= S_IXUSR0000100;
134 if (chmod(line, stbuf.st_mode & 0777) < 0)
135 printf("\tcannot disable printing\n");
136 else {
137 upstat("printing disabled\n");
138 printf("\tprinting disabled\n");
139 }
140 } else if (errno(*__errno()) == ENOENT2) {
141 if ((fd = safe_open(line, O_WRONLY0x0001|O_CREAT0x0200|O_NOFOLLOW0x0100,
142 0760)) < 0)
143 printf("\tcannot create lock file\n");
144 else {
145 (void)fchown(fd, DEFUID1, -1);
146 (void)close(fd);
147 upstat("printing disabled\n");
148 printf("\tprinting disabled\n");
149 printf("\tno daemon to abort\n");
150 }
151 goto out;
152 } else {
153 printf("\tcannot stat lock file\n");
154 goto out;
155 }
156 }
157 /*
158 * Kill the current daemon to stop printing now.
159 */
160 fd = safe_open(line, O_RDONLY0x0000|O_NOFOLLOW0x0100, 0);
161 if (fd < 0 || (fp = fdopen(fd, "r")) == NULL((void *)0)) {
162 if (fd >= 0)
163 close(fd);
164 printf("\tcannot open lock file\n");
165 goto out;
166 }
167 if (!get_line(fp) || flock(fileno(fp)(!__isthreaded ? ((fp)->_file) : (fileno)(fp)), LOCK_SH0x01|LOCK_NB0x04) == 0) {
168 (void)fclose(fp); /* unlocks as well */
169 printf("\tno daemon to abort\n");
170 goto out;
171 }
172 (void)fclose(fp);
173 if (kill(pid = atoi(line), SIGTERM15) < 0) {
174 if (errno(*__errno()) == ESRCH3)
175 printf("\tno daemon to abort\n");
176 else
177 printf("\tWarning: daemon (pid %d) not killed\n", pid);
178 } else
179 printf("\tdaemon (pid %d) killed\n", pid);
180out:
181 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
182}
183
184/*
185 * Write a message into the status file (assumes PRIV_START already called)
186 */
187static void
188upstat(char *msg)
189{
190 int fd;
191 char statfile[PATH_MAX1024];
192
193 if (cgetstr(bp, "st", &ST) == -1)
194 ST = DEFSTAT"status";
195 (void)snprintf(statfile, sizeof(statfile), "%s/%s", SD, ST);
196 fd = safe_open(statfile, O_WRONLY0x0001|O_CREAT0x0200|O_NOFOLLOW0x0100, 0660);
197 if (fd < 0 || flock(fd, LOCK_EX0x02) < 0) {
198 printf("\tcannot create status file\n");
199 if (fd >= 0)
200 (void)close(fd); /* unlocks as well */
201 return;
202 }
203 (void)fchown(fd, DEFUID1, -1);
204 (void)ftruncate(fd, 0);
205 if (msg == (char *)NULL((void *)0))
206 (void)write(fd, "\n", 1);
207 else
208 (void)write(fd, msg, strlen(msg));
209 (void)close(fd);
210}
211
212/*
213 * Remove all spool files and temporaries from the spooling area.
214 */
215void
216clean(int argc, char **argv)
217{
218 int c, status;
219 char *cp1, *cp2;
220 char prbuf[100];
221
222 if (argc == 1) {
223 printf("usage: clean {all | printer ...}\n");
224 return;
225 }
226 if (argc == 2 && strcmp(argv[1], "all") == 0) {
227 printer = prbuf;
228 while (cgetnext(&bp, printcapdb) > 0) {
229 cp1 = prbuf;
230 cp2 = bp;
231 while ((c = *cp2++) && c != '|' && c != ':' &&
232 (cp1 - prbuf) < sizeof(prbuf) - 1)
233 *cp1++ = c;
234 *cp1 = '\0';
235 cleanpr();
236 }
237 return;
238 }
239 while (--argc) {
240 printer = *++argv;
241 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
242 printf("cannot open printer description file\n");
243 continue;
244 } else if (status == -1) {
245 printf("unknown printer %s\n", printer);
246 continue;
247 } else if (status == -3)
248 fatal("potential reference loop detected in printcap file");
249
250 cleanpr();
251 }
252}
253
254static int
255doselect(const struct dirent *d)
256{
257 int c = d->d_name[0];
258
259 if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
260 return(1);
261 return(0);
262}
263
264/*
265 * Comparison routine for scandir. Sort by job number and machine, then
266 * by `cf', `tf', or `df', then by the sequence letter A-Z, a-z.
267 */
268static int
269sortq(const struct dirent **d1, const struct dirent **d2)
270{
271 int c1, c2;
272
273 if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3)) != 0)
274 return(c1);
275 c1 = (*d1)->d_name[0];
276 c2 = (*d2)->d_name[0];
277 if (c1 == c2)
278 return((*d1)->d_name[2] - (*d2)->d_name[2]);
279 if (c1 == 'c')
280 return(-1);
281 if (c1 == 'd' || c2 == 'c')
282 return(1);
283 return(-1);
284}
285
286/*
287 * Remove incomplete jobs from spooling area.
288 */
289static void
290cleanpr(void)
291{
292 int i, n;
293 char *cp, *cp1, *lp;
294 struct dirent **queue;
295 int nitems;
296
297 if (cgetstr(bp, "sd", &SD) == -1)
298 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
299 printf("%s:\n", printer);
300
301 /* XXX depends on SD being non-NUL */
302 for (lp = line, cp = SD; (lp - line) < sizeof(line) &&
303 (*lp++ = *cp++) != '\0'; )
304 ;
305 lp[-1] = '/';
306 if (lp - line >= sizeof(line)) {
307 printf("\tspool directory name too long\n");
308 return;
309 }
310
311 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
312 nitems = scandir(SD, &queue, doselect, sortq);
313 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
314 if (nitems < 0) {
315 printf("\tcannot examine spool directory\n");
316 return;
317 }
318 if (nitems == 0)
319 return;
320 i = 0;
321 do {
322 cp = queue[i]->d_name;
323 if (*cp == 'c') {
324 n = 0;
325 while (i + 1 < nitems) {
326 cp1 = queue[i + 1]->d_name;
327 if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
328 break;
329 i++;
330 n++;
331 }
332 if (n == 0) {
333 if (strlcpy(lp, cp, sizeof(line) - (lp - line))
334 >= sizeof(line) - (lp - line))
335 printf("\tpath too long, %s/%s", SD, cp);
336 else
337 unlinkf(line);
338 }
339 } else {
340 /*
341 * Must be a df with no cf (otherwise, it would have
342 * been skipped above) or a tf file (which can always
343 * be removed).
344 */
345 if (strlcpy(lp, cp, sizeof(line) - (lp - line)) >=
346 sizeof(line) - (lp - line))
347 printf("\tpath too long, %s/%s", SD, cp);
348 else
349 unlinkf(line);
350 }
351 } while (++i < nitems);
352}
353
354static void
355unlinkf(char *name)
356{
357 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
358 if (unlink(name) < 0)
359 printf("\tcannot remove %s\n", name);
360 else
361 printf("\tremoved %s\n", name);
362 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
363}
364
365/*
366 * Enable queuing to the printer (allow lpr's).
367 */
368void
369enable(int argc, char **argv)
370{
371 int c, status;
372 char *cp1, *cp2;
373 char prbuf[100];
374
375 if (argc == 1) {
1
Assuming 'argc' is not equal to 1
2
Taking false branch
376 printf("usage: enable {all | printer ...}\n");
377 return;
378 }
379 if (argc == 2 && strcmp(argv[1], "all") == 0) {
3
Assuming 'argc' is equal to 2
4
Taking true branch
380 printer = prbuf;
381 while (cgetnext(&bp, printcapdb) > 0) {
5
Assuming the condition is false
6
Loop condition is false. Execution continues on line 390
382 cp1 = prbuf;
383 cp2 = bp;
384 while ((c = *cp2++) && c != '|' && c != ':' &&
385 (cp1 - prbuf) < sizeof(prbuf) - 1)
386 *cp1++ = c;
387 *cp1 = '\0';
388 enablepr();
389 }
390 return;
7
Address of stack memory associated with local variable 'prbuf' is still referred to by the global variable 'printer' upon returning to the caller. This will be a dangling reference
391 }
392 while (--argc) {
393 printer = *++argv;
394 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
395 printf("cannot open printer description file\n");
396 continue;
397 } else if (status == -1) {
398 printf("unknown printer %s\n", printer);
399 continue;
400 } else if (status == -3)
401 fatal("potential reference loop detected in printcap file");
402
403 enablepr();
404 }
405}
406
407static void
408enablepr(void)
409{
410 struct stat stbuf;
411
412 if (cgetstr(bp, "sd", &SD) == -1)
413 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
414 if (cgetstr(bp, "lo", &LO) == -1)
415 LO = DEFLOCK"lock";
416 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
417 printf("%s:\n", printer);
418
419 /*
420 * Turn off the group execute bit of the lock file to enable queuing.
421 */
422 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
423 if (stat(line, &stbuf) >= 0) {
424 stbuf.st_mode &= ~S_IXGRP0000010;
425 if (chmod(line, stbuf.st_mode & 0777) < 0)
426 printf("\tcannot enable queuing\n");
427 else
428 printf("\tqueuing enabled\n");
429 }
430 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
431}
432
433/*
434 * Disable queuing.
435 */
436void
437disable(int argc, char **argv)
438{
439 int c, status;
440 char *cp1, *cp2;
441 char prbuf[100];
442
443 if (argc == 1) {
444 printf("usage: disable {all | printer ...}\n");
445 return;
446 }
447 if (argc == 2 && strcmp(argv[1], "all") == 0) {
448 printer = prbuf;
449 while (cgetnext(&bp, printcapdb) > 0) {
450 cp1 = prbuf;
451 cp2 = bp;
452 while ((c = *cp2++) && c != '|' && c != ':' &&
453 (cp1 - prbuf) < sizeof(prbuf) - 1)
454 *cp1++ = c;
455 *cp1 = '\0';
456 disablepr();
457 }
458 return;
459 }
460 while (--argc) {
461 printer = *++argv;
462 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
463 printf("cannot open printer description file\n");
464 continue;
465 } else if (status == -1) {
466 printf("unknown printer %s\n", printer);
467 continue;
468 } else if (status == -3)
469 fatal("potential reference loop detected in printcap file");
470
471 disablepr();
472 }
473}
474
475static void
476disablepr(void)
477{
478 int fd;
479 struct stat stbuf;
480
481 if (cgetstr(bp, "sd", &SD) == -1)
482 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
483 if (cgetstr(bp, "lo", &LO) == -1)
484 LO = DEFLOCK"lock";
485 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
486 printf("%s:\n", printer);
487 /*
488 * Turn on the group execute bit of the lock file to disable queuing.
489 */
490 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
491 if (stat(line, &stbuf) >= 0) {
492 stbuf.st_mode |= S_IXGRP0000010;
493 if (chmod(line, stbuf.st_mode & 0777) < 0)
494 printf("\tcannot disable queuing\n");
495 else
496 printf("\tqueuing disabled\n");
497 } else if (errno(*__errno()) == ENOENT2) {
498 if ((fd = safe_open(line, O_WRONLY0x0001|O_CREAT0x0200|O_NOFOLLOW0x0100, 0670)) < 0)
499 printf("\tcannot create lock file\n");
500 else {
501 (void)fchown(fd, DEFUID1, -1);
502 (void)close(fd);
503 printf("\tqueuing disabled\n");
504 }
505 } else
506 printf("\tcannot stat lock file\n");
507 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
508}
509
510/*
511 * Disable queuing and printing and put a message into the status file
512 * (reason for being down).
513 */
514void
515down(int argc, char **argv)
516{
517 int c, status;
518 char *cp1, *cp2;
519 char prbuf[100];
520
521 if (argc == 1) {
522 printf("usage: down {all | printer} [message ...]\n");
523 return;
524 }
525 if (strcmp(argv[1], "all") == 0) {
526 printer = prbuf;
527 while (cgetnext(&bp, printcapdb) > 0) {
528 cp1 = prbuf;
529 cp2 = bp;
530 while ((c = *cp2++) && c != '|' && c != ':' &&
531 (cp1 - prbuf) < sizeof(prbuf) - 1)
532 *cp1++ = c;
533 *cp1 = '\0';
534 putmsg(argc - 2, argv + 2);
535 }
536 return;
537 }
538 printer = argv[1];
539 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
540 printf("cannot open printer description file\n");
541 return;
542 } else if (status == -1) {
543 printf("unknown printer %s\n", printer);
544 return;
545 } else if (status == -3)
546 fatal("potential reference loop detected in printcap file");
547
548 putmsg(argc - 2, argv + 2);
549}
550
551static void
552putmsg(int argc, char **argv)
553{
554 int fd;
555 char *cp1, *cp2;
556 char buf[1024];
557 struct stat stbuf;
558
559 if (cgetstr(bp, "sd", &SD) == -1)
560 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
561 if (cgetstr(bp, "lo", &LO) == -1)
562 LO = DEFLOCK"lock";
563 if (cgetstr(bp, "st", &ST) == -1)
564 ST = DEFSTAT"status";
565 printf("%s:\n", printer);
566 /*
567 * Turn on the group execute bit of the lock file to disable queuing and
568 * turn on the owner execute bit of the lock file to disable printing.
569 */
570 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
571 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
572 if (stat(line, &stbuf) >= 0) {
573 stbuf.st_mode |= (S_IXGRP0000010|S_IXUSR0000100);
574 if (chmod(line, stbuf.st_mode & 0777) < 0)
575 printf("\tcannot disable queuing\n");
576 else
577 printf("\tprinter and queuing disabled\n");
578 } else if (errno(*__errno()) == ENOENT2) {
579 if ((fd = safe_open(line, O_WRONLY0x0001|O_CREAT0x0200|O_NOFOLLOW0x0100, 0770)) < 0)
580 printf("\tcannot create lock file\n");
581 else {
582 (void)fchown(fd, DEFUID1, -1);
583 (void)close(fd);
584 printf("\tprinter and queuing disabled\n");
585 }
586 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
587 return;
588 } else
589 printf("\tcannot stat lock file\n");
590 /*
591 * Write the message into the status file.
592 */
593 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST);
594 fd = safe_open(line, O_WRONLY0x0001|O_CREAT0x0200|O_NOFOLLOW0x0100, 0660);
595 if (fd < 0 || flock(fd, LOCK_EX0x02) < 0) {
596 printf("\tcannot create status file\n");
597 if (fd >= 0)
598 (void)close(fd); /* unlocks as well */
599 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
600 return;
601 }
602 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
603 (void)fchown(fd, DEFUID1, -1);
604 (void)ftruncate(fd, 0);
605 if (argc <= 0) {
606 (void)write(fd, "\n", 1);
607 (void)close(fd);
608 return;
609 }
610 cp1 = buf;
611 while (--argc >= 0) {
612 cp2 = *argv++;
613 while ((cp1 - buf) < sizeof(buf) - 1 && (*cp1++ = *cp2++))
614 ;
615 cp1[-1] = ' ';
616 }
617 cp1[-1] = '\n';
618 *cp1 = '\0';
619 (void)write(fd, buf, strlen(buf));
620 (void)close(fd);
621}
622
623/*
624 * Exit lpc
625 */
626void
627quit(int argc, char **argv)
628{
629 exit(0);
630}
631
632/*
633 * Kill and restart the daemon.
634 */
635void
636restart(int argc, char **argv)
637{
638 int c, status;
639 char *cp1, *cp2;
640 char prbuf[100];
641
642 if (argc == 1) {
643 printf("usage: restart {all | printer ...}\n");
644 return;
645 }
646 if (argc == 2 && strcmp(argv[1], "all") == 0) {
647 printer = prbuf;
648 while (cgetnext(&bp, printcapdb) > 0) {
649 cp1 = prbuf;
650 cp2 = bp;
651 while ((c = *cp2++) && c != '|' && c != ':' &&
652 (cp1 - prbuf) < sizeof(prbuf) - 1)
653 *cp1++ = c;
654 *cp1 = '\0';
655 abortpr(0);
656 startpr(0);
657 }
658 return;
659 }
660 while (--argc) {
661 printer = *++argv;
662 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
663 printf("cannot open printer description file\n");
664 continue;
665 } else if (status == -1) {
666 printf("unknown printer %s\n", printer);
667 continue;
668 } else if (status == -3)
669 fatal("potential reference loop detected in printcap file");
670
671 abortpr(0);
672 startpr(0);
673 }
674}
675
676/*
677 * Enable printing on the specified printer and startup the daemon.
678 */
679void
680startcmd(int argc, char **argv)
681{
682 int c, status;
683 char *cp1, *cp2;
684 char prbuf[100];
685
686 if (argc == 1) {
687 printf("usage: start {all | printer ...}\n");
688 return;
689 }
690 if (argc == 2 && strcmp(argv[1], "all") == 0) {
691 printer = prbuf;
692 while (cgetnext(&bp, printcapdb) > 0) {
693 cp1 = prbuf;
694 cp2 = bp;
695 while ((c = *cp2++) && c != '|' && c != ':' &&
696 (cp1 - prbuf) < sizeof(prbuf) - 1)
697 *cp1++ = c;
698 *cp1 = '\0';
699 startpr(1);
700 }
701 return;
702 }
703 while (--argc) {
704 printer = *++argv;
705 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
706 printf("cannot open printer description file\n");
707 continue;
708 } else if (status == -1) {
709 printf("unknown printer %s\n", printer);
710 continue;
711 } else if (status == -3)
712 fatal("potential reference loop detected in printcap file");
713
714 startpr(1);
715 }
716}
717
718static void
719startpr(int enable)
720{
721 struct stat stbuf;
722
723 if (cgetstr(bp, "sd", &SD) == -1)
724 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
725 if (cgetstr(bp, "lo", &LO) == -1)
726 LO = DEFLOCK"lock";
727 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
728 printf("%s:\n", printer);
729
730 /*
731 * Turn off the owner execute bit of the lock file to enable printing.
732 * If we are marking the printer "up" also turn off group execute bit.
733 */
734 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
735 if (enable && stat(line, &stbuf) >= 0) {
736 if (enable == 2)
737 stbuf.st_mode &= ~(S_IXUSR0000100|S_IXGRP0000010);
738 else
739 stbuf.st_mode &= ~S_IXUSR0000100;
740 if (chmod(line, stbuf.st_mode & 0777) < 0)
741 printf("\tcannot enable printing\n");
742 else
743 printf("\tprinting enabled\n");
744 }
745 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
746 if (!startdaemon(printer))
747 printf("\tcouldn't start daemon\n");
748 else
749 printf("\tdaemon started\n");
750}
751
752/*
753 * Print the status of each queue listed or all the queues.
754 */
755void
756status(int argc, char **argv)
757{
758 int c, status;
759 char *cp1, *cp2;
760 char prbuf[100];
761
762 if (argc == 1 || (argc == 2 && strcmp(argv[1], "all") == 0)) {
763 printer = prbuf;
764 while (cgetnext(&bp, printcapdb) > 0) {
765 cp1 = prbuf;
766 cp2 = bp;
767 while ((c = *cp2++) && c != '|' && c != ':' &&
768 (cp1 - prbuf) < sizeof(prbuf) - 1)
769 *cp1++ = c;
770 *cp1 = '\0';
771 prstat();
772 }
773 return;
774 }
775 while (--argc) {
776 printer = *++argv;
777 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
778 printf("cannot open printer description file\n");
779 continue;
780 } else if (status == -1) {
781 printf("unknown printer %s\n", printer);
782 continue;
783 } else if (status == -3)
784 fatal("potential reference loop detected in printcap file");
785
786 prstat();
787 }
788}
789
790/*
791 * Print the status of the printer queue.
792 */
793static void
794prstat(void)
795{
796 struct stat stbuf;
797 int fd, i;
798 struct dirent *dp;
799 DIR *dirp;
800
801 if (cgetstr(bp, "sd", &SD) == -1)
802 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
803 if (cgetstr(bp, "lo", &LO) == -1)
804 LO = DEFLOCK"lock";
805 if (cgetstr(bp, "st", &ST) == -1)
806 ST = DEFSTAT"status";
807 printf("%s:\n", printer);
808 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
809 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
810 i = stat(line, &stbuf);
811 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
812 if (i >= 0) {
813 printf("\tqueuing is %s\n",
814 (stbuf.st_mode & 010) ? "disabled" : "enabled");
815 printf("\tprinting is %s\n",
816 (stbuf.st_mode & 0100) ? "disabled" : "enabled");
817 } else {
818 printf("\tqueuing is enabled\n");
819 printf("\tprinting is enabled\n");
820 }
821 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
822 dirp = opendir(SD);
823 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
824 if (dirp == NULL((void *)0)) {
825 printf("\tcannot examine spool directory\n");
826 return;
827 }
828 i = 0;
829 while ((dp = readdir(dirp)) != NULL((void *)0)) {
830 if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
831 i++;
832 }
833 closedir(dirp);
834 if (i == 0)
835 printf("\tno entries\n");
836 else if (i == 1)
837 printf("\t1 entry in spool area\n");
838 else
839 printf("\t%d entries in spool area\n", i);
840 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
841 fd = safe_open(line, O_RDONLY0x0000|O_NOFOLLOW0x0100, 0);
842 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
843 if (fd < 0 || flock(fd, LOCK_SH0x01|LOCK_NB0x04) == 0) {
844 printf("\tprinter idle\n");
845 if (fd >= 0)
846 (void)close(fd); /* unlocks as well */
847 return;
848 }
849 (void)close(fd);
850 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST);
851 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
852 fd = safe_open(line, O_RDONLY0x0000|O_NOFOLLOW0x0100, 0);
853 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
854 if (fd >= 0) {
855 (void)flock(fd, LOCK_SH0x01);
856 if (fstat(fd, &stbuf) == 0 && stbuf.st_size > 0) {
857 putchar('\t')(!__isthreaded ? __sputc('\t', (&__sF[1])) : (putc)('\t',
(&__sF[1])))
;
858 while ((i = read(fd, line, sizeof(line))) > 0)
859 (void)fwrite(line, 1, i, stdout(&__sF[1]));
860 }
861 (void)close(fd); /* unlocks as well */
862 }
863}
864
865/*
866 * Stop the specified daemon after completing the current job and disable
867 * printing.
868 */
869void
870stop(int argc, char **argv)
871{
872 int c, status;
873 char *cp1, *cp2;
874 char prbuf[100];
875
876 if (argc == 1) {
877 printf("usage: stop {all | printer ...}\n");
878 return;
879 }
880 if (argc == 2 && strcmp(argv[1], "all") == 0) {
881 printer = prbuf;
882 while (cgetnext(&bp, printcapdb) > 0) {
883 cp1 = prbuf;
884 cp2 = bp;
885 while ((c = *cp2++) && c != '|' && c != ':' &&
886 (cp1 - prbuf) < sizeof(prbuf) - 1)
887 *cp1++ = c;
888 *cp1 = '\0';
889 stoppr();
890 }
891 return;
892 }
893 while (--argc) {
894 printer = *++argv;
895 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
896 printf("cannot open printer description file\n");
897 continue;
898 } else if (status == -1) {
899 printf("unknown printer %s\n", printer);
900 continue;
901 } else if (status == -3)
902 fatal("potential reference loop detected in printcap file");
903
904 stoppr();
905 }
906}
907
908static void
909stoppr(void)
910{
911 int fd;
912 struct stat stbuf;
913
914 if (cgetstr(bp, "sd", &SD) == -1)
915 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
916 if (cgetstr(bp, "lo", &LO) == -1)
917 LO = DEFLOCK"lock";
918 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
919 printf("%s:\n", printer);
920
921 /*
922 * Turn on the owner execute bit of the lock file to disable printing.
923 */
924 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
925 if (stat(line, &stbuf) >= 0) {
926 stbuf.st_mode |= S_IXUSR0000100;
927 if (chmod(line, stbuf.st_mode & 0777) < 0)
928 printf("\tcannot disable printing\n");
929 else {
930 upstat("printing disabled\n");
931 printf("\tprinting disabled\n");
932 }
933 } else if (errno(*__errno()) == ENOENT2) {
934 if ((fd = safe_open(line, O_WRONLY0x0001|O_CREAT0x0200|O_NOFOLLOW0x0100, 0760)) < 0)
935 printf("\tcannot create lock file\n");
936 else {
937 (void)fchown(fd, DEFUID1, -1);
938 (void)close(fd);
939 upstat("printing disabled\n");
940 printf("\tprinting disabled\n");
941 }
942 } else
943 printf("\tcannot stat lock file\n");
944 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
945}
946
947struct queue **queue;
948int nitems;
949time_t mtime;
950
951/*
952 * Put the specified jobs at the top of printer queue.
953 */
954void
955topq(int argc, char **argv)
956{
957 int i;
958 struct stat stbuf;
959 int status, changed;
960
961 if (argc < 3) {
962 printf("usage: topq printer [jobnum ...] [user ...]\n");
963 return;
964 }
965
966 --argc;
967 printer = *++argv;
968 status = cgetent(&bp, printcapdb, printer);
969 if (status == -2) {
970 printf("cannot open printer description file\n");
971 return;
972 } else if (status == -1) {
973 printf("%s: unknown printer\n", printer);
974 return;
975 } else if (status == -3)
976 fatal("potential reference loop detected in printcap file");
977
978 if (cgetstr(bp, "sd", &SD) == -1)
979 SD = _PATH_DEFSPOOL"/var/spool/output/lpd";
980 if (cgetstr(bp, "lo", &LO) == -1)
981 LO = DEFLOCK"lock";
982 printf("%s:\n", printer);
983
984 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
985 if (chdir(SD) < 0) {
986 printf("\tcannot chdir to %s\n", SD);
987 goto out;
988 }
989 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
990 nitems = getq(&queue);
991 if (nitems == 0)
992 return;
993 changed = 0;
994 mtime = queue[0]->q_time;
995 for (i = argc; --i; ) {
996 if (doarg(argv[i]) == 0) {
997 printf("\tjob %s is not in the queue\n", argv[i]);
998 continue;
999 } else
1000 changed++;
1001 }
1002 for (i = 0; i < nitems; i++)
1003 free(queue[i]);
1004 free(queue);
1005 if (!changed) {
1006 printf("\tqueue order unchanged\n");
1007 return;
1008 }
1009 /*
1010 * Turn on the public execute bit of the lock file to
1011 * get lpd to rebuild the queue after the current job.
1012 */
1013 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
1014 if (changed && stat(LO, &stbuf) >= 0) {
1015 stbuf.st_mode |= S_IXOTH0000001;
1016 (void)chmod(LO, stbuf.st_mode & 0777);
1017 }
1018
1019out:
1020 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
1021}
1022
1023/*
1024 * Reposition the job by changing the modification time of
1025 * the control file.
1026 */
1027static int
1028touch(struct queue *q)
1029{
1030 struct timeval tvp[2];
1031 int ret;
1032
1033 tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
1034 tvp[0].tv_usec = tvp[1].tv_usec = 0;
1035 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
1036 ret = utimes(q->q_name, tvp);
1037 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
1038 return (ret);
1039}
1040
1041/*
1042 * Checks if specified job name is in the printer's queue.
1043 * Returns: negative (-1) if argument name is not in the queue.
1044 */
1045int
1046doarg(char *job)
1047{
1048 struct queue **qq;
1049 int jobnum, fd, n;
1050 char *cp, *machine;
1051 int cnt = 0;
1052 FILE *fp;
1053
1054 /*
1055 * Look for a job item consisting of system name, colon, number
1056 * (example: ucbarpa:114)
1057 */
1058 if ((cp = strchr(job, ':')) != NULL((void *)0)) {
1059 machine = job;
1060 *cp++ = '\0';
1061 job = cp;
1062 } else
1063 machine = NULL((void *)0);
1064
1065 /*
1066 * Check for job specified by number (example: 112 or 235ucbarpa).
1067 */
1068 if (isdigit((unsigned char)*job)) {
1069 jobnum = 0;
1070 do
1071 jobnum = jobnum * 10 + (*job++ - '0');
1072 while (isdigit((unsigned char)*job));
1073 for (qq = queue + nitems; --qq >= queue; ) {
1074 n = 0;
1075 for (cp = (*qq)->q_name+3; isdigit((unsigned char)*cp); )
1076 n = n * 10 + (*cp++ - '0');
1077 if (jobnum != n)
1078 continue;
1079 if (*job && strcmp(job, cp) != 0)
1080 continue;
1081 if (machine != NULL((void *)0) && strcmp(machine, cp) != 0)
1082 continue;
1083 if (touch(*qq) == 0) {
1084 printf("\tmoved %s\n", (*qq)->q_name);
1085 cnt++;
1086 }
1087 }
1088 return(cnt);
1089 }
1090 /*
1091 * Process item consisting of owner's name (example: henry).
1092 */
1093 for (qq = queue + nitems; --qq >= queue; ) {
1094 PRIV_STARTdo { int save_errno = (*__errno()); (void)seteuid(effective_uid
); (void)setegid(effective_gid); (*__errno()) = save_errno; }
while (0)
;
1095 fd = safe_open((*qq)->q_name, O_RDONLY0x0000|O_NOFOLLOW0x0100, 0);
1096 PRIV_ENDdo { int save_errno = (*__errno()); (void)setegid(real_gid); (
void)seteuid(real_uid); (*__errno()) = save_errno; } while (0
)
;
1097 if (fd < 0 || (fp = fdopen(fd, "r")) == NULL((void *)0)) {
1098 if (fd >= 0)
1099 close(fd);
1100 continue;
1101 }
1102 while (get_line(fp) > 0)
1103 if (line[0] == 'P')
1104 break;
1105 (void)fclose(fp);
1106 if (line[0] != 'P' || strcmp(job, line+1) != 0)
1107 continue;
1108 if (touch(*qq) == 0) {
1109 printf("\tmoved %s\n", (*qq)->q_name);
1110 cnt++;
1111 }
1112 }
1113 return(cnt);
1114}
1115
1116/*
1117 * Enable everything and start printer (undo `down').
1118 */
1119void
1120up(int argc, char **argv)
1121{
1122 int c, status;
1123 char *cp1, *cp2;
1124 char prbuf[100];
1125
1126 if (argc == 1) {
1127 printf("usage: up {all | printer ...}\n");
1128 return;
1129 }
1130 if (argc == 2 && strcmp(argv[1], "all") == 0) {
1131 printer = prbuf;
1132 while (cgetnext(&bp, printcapdb) > 0) {
1133 cp1 = prbuf;
1134 cp2 = bp;
1135 while ((c = *cp2++) && c != '|' && c != ':' &&
1136 (cp1 - prbuf) < sizeof(prbuf) - 1)
1137 *cp1++ = c;
1138 *cp1 = '\0';
1139 startpr(2);
1140 }
1141 return;
1142 }
1143 while (--argc) {
1144 printer = *++argv;
1145 if ((status = cgetent(&bp, printcapdb, printer)) == -2) {
1146 printf("cannot open printer description file\n");
1147 continue;
1148 } else if (status == -1) {
1149 printf("unknown printer %s\n", printer);
1150 continue;
1151 } else if (status == -3)
1152 fatal("potential reference loop detected in printcap file");
1153
1154 startpr(2);
1155 }
1156}