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