cmds.c revision 1.24 1 /* $NetBSD: cmds.c,v 1.24 2011/08/31 16:24:59 plunky 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.24 2011/08/31 16:24:59 plunky 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 void *, const void *);
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
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
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
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
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
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
259 sortq(const void *a, const void *b)
260 {
261 const struct dirent *const *d1, *const *d2;
262 int c1, c2;
263
264 d1 = (const struct dirent *const *)a;
265 d2 = (const struct dirent *const *)b;
266 if ((c1 = strcmp((*d1)->d_name + 3, (*d2)->d_name + 3)) != 0)
267 return(c1);
268 c1 = (*d1)->d_name[0];
269 c2 = (*d2)->d_name[0];
270 if (c1 == c2)
271 return((*d1)->d_name[2] - (*d2)->d_name[2]);
272 if (c1 == 'c')
273 return(-1);
274 if (c1 == 'd' || c2 == 'c')
275 return(1);
276 return(-1);
277 }
278
279 /*
280 * Remove incomplete jobs from spooling area.
281 */
282 static void
283 cleanpr(void)
284 {
285 int i, n;
286 char *cp1, *lp, *ep;
287 const char *cp;
288 struct dirent **queue;
289 int nitems;
290
291 getcaps();
292 printf("%s:\n", printer);
293
294 /* XXX depends on SD being non nul */
295 ep = line + sizeof(line);
296 for (lp = line, cp = SD; (size_t)(lp - line) < sizeof(line) &&
297 (*lp++ = *cp++) != '\0'; )
298 ;
299 lp[-1] = '/';
300
301 seteuid(euid);
302 nitems = scandir(SD, &queue, doselect, sortq);
303 seteuid(uid);
304 if (nitems < 0) {
305 printf("\tcannot examine spool directory\n");
306 return;
307 }
308 if (nitems == 0)
309 return;
310 i = 0;
311 do {
312 cp = queue[i]->d_name;
313 if (*cp == 'c') {
314 n = 0;
315 while (i + 1 < nitems) {
316 cp1 = queue[i + 1]->d_name;
317 if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
318 break;
319 i++;
320 n++;
321 }
322 if (n == 0) {
323 strlcpy(lp, cp, ep - lp);
324 unlinkf(line);
325 }
326 } else {
327 /*
328 * Must be a df with no cf (otherwise, it would have
329 * been skipped above) or a tf file (which can always
330 * be removed).
331 */
332 strlcpy(lp, cp, ep - lp);
333 unlinkf(line);
334 }
335 } while (++i < nitems);
336 }
337
338 static void
339 unlinkf(const char *name)
340 {
341 seteuid(euid);
342 if (unlink(name) < 0)
343 printf("\tcannot remove %s\n", name);
344 else
345 printf("\tremoved %s\n", name);
346 seteuid(uid);
347 }
348
349 /*
350 * Enable queuing to the printer (allow lpr's).
351 */
352 void
353 enable(int argc, char *argv[])
354 {
355 int c;
356 char *cp1, *cp2;
357 char prbuf[100];
358
359 if (argc == 1) {
360 printf("Usage: enable {all | printer ...}\n");
361 return;
362 }
363 if (argc == 2 && !strcmp(argv[1], "all")) {
364 printer = prbuf;
365 while (cgetnext(&bp, printcapdb) > 0) {
366 cp1 = prbuf;
367 cp2 = bp;
368 while ((c = *cp2++) && c != '|' && c != ':' &&
369 (size_t)(cp1 - prbuf) < sizeof(prbuf))
370 *cp1++ = c;
371 *cp1 = '\0';
372 enablepr();
373 }
374 return;
375 }
376 while (--argc) {
377 printer = *++argv;
378 if (!getcapdesc())
379 continue;
380 enablepr();
381 }
382 }
383
384 static int
385 getcapdesc(void)
386 {
387 int st;
388 if ((st = cgetent(&bp, printcapdb, printer)) == -2) {
389 printf("cannot open printer description file\n");
390 return 0;
391 } else if (st == -1) {
392 printf("unknown printer %s\n", printer);
393 return 0;
394 } else if (st == -3)
395 fatal("potential reference loop detected in printcap file");
396 return 1;
397 }
398
399 static void
400 enablepr(void)
401 {
402 struct stat stbuf;
403
404 getcaps();
405 printf("%s:\n", printer);
406
407 /*
408 * Turn off the group execute bit of the lock file to enable queuing.
409 */
410 seteuid(euid);
411 if (stat(line, &stbuf) >= 0) {
412 if (chmod(line, stbuf.st_mode & 0767) < 0)
413 printf("\tcannot enable queuing\n");
414 else
415 printf("\tqueuing enabled\n");
416 }
417 seteuid(uid);
418 }
419
420 /*
421 * Disable queuing.
422 */
423 void
424 disable(int argc, char *argv[])
425 {
426 int c;
427 char *cp1, *cp2;
428 char prbuf[100];
429
430 if (argc == 1) {
431 printf("Usage: disable {all | printer ...}\n");
432 return;
433 }
434 if (argc == 2 && !strcmp(argv[1], "all")) {
435 printer = prbuf;
436 while (cgetnext(&bp, printcapdb) > 0) {
437 cp1 = prbuf;
438 cp2 = bp;
439 while ((c = *cp2++) && c != '|' && c != ':' &&
440 (size_t)(cp1 - prbuf) < sizeof(prbuf))
441 *cp1++ = c;
442 *cp1 = '\0';
443 disablepr();
444 }
445 return;
446 }
447 while (--argc) {
448 printer = *++argv;
449 if (!getcapdesc())
450 continue;
451 disablepr();
452 }
453 }
454
455 static void
456 disablepr(void)
457 {
458 int fd;
459 struct stat stbuf;
460
461 getcaps();
462 printf("%s:\n", printer);
463 /*
464 * Turn on the group execute bit of the lock file to disable queuing.
465 */
466 seteuid(euid);
467 if (stat(line, &stbuf) >= 0) {
468 if (chmod(line, (stbuf.st_mode & 0777) | 010) < 0)
469 printf("\tcannot disable queuing\n");
470 else
471 printf("\tqueuing disabled\n");
472 } else if (errno == ENOENT) {
473 if ((fd = open(line, O_WRONLY|O_CREAT, 0670)) < 0)
474 printf("\tcannot create lock file\n");
475 else {
476 (void)close(fd);
477 printf("\tqueuing disabled\n");
478 }
479 } else
480 printf("\tcannot stat lock file\n");
481 seteuid(uid);
482 }
483
484 /*
485 * Disable queuing and printing and put a message into the status file
486 * (reason for being down).
487 */
488 void
489 down(int argc, char *argv[])
490 {
491 int c;
492 char *cp1, *cp2;
493 char prbuf[100];
494
495 if (argc == 1) {
496 printf("Usage: down {all | printer} [message ...]\n");
497 return;
498 }
499 if (!strcmp(argv[1], "all")) {
500 printer = prbuf;
501 while (cgetnext(&bp, printcapdb) > 0) {
502 cp1 = prbuf;
503 cp2 = bp;
504 while ((c = *cp2++) && c != '|' && c != ':' &&
505 (size_t)(cp1 - prbuf) < sizeof(prbuf))
506 *cp1++ = c;
507 *cp1 = '\0';
508 putmsg(argc - 2, argv + 2);
509 }
510 return;
511 }
512 printer = argv[1];
513 if (!getcapdesc())
514 return;
515 putmsg(argc - 2, argv + 2);
516 }
517
518 static void
519 getcaps(void)
520 {
521 char *cp;
522 SD = cgetstr(bp, "sd", &cp) == -1 ? _PATH_DEFSPOOL : cp;
523 LO = cgetstr(bp, "lo", &cp) == -1 ? DEFLOCK : cp;
524 ST = cgetstr(bp, "st", &cp) == -1 ? DEFSTAT : cp;
525 (void)snprintf(line, sizeof(line), "%s/%s", SD, LO);
526 }
527
528 static void
529 putmsg(int argc, char **argv)
530 {
531 int fd;
532 char *cp1, *cp2;
533 char buf[1024];
534 struct stat stbuf;
535
536 printf("%s:\n", printer);
537 /*
538 * Turn on the group execute bit of the lock file to disable queuing and
539 * turn on the owner execute bit of the lock file to disable printing.
540 */
541 seteuid(euid);
542 if (stat(line, &stbuf) >= 0) {
543 if (chmod(line, (stbuf.st_mode & 0777) | 0110) < 0)
544 printf("\tcannot disable queuing\n");
545 else
546 printf("\tprinter and queuing disabled\n");
547 } else if (errno == ENOENT) {
548 if ((fd = open(line, O_WRONLY|O_CREAT, 0770)) < 0)
549 printf("\tcannot create lock file\n");
550 else {
551 (void)close(fd);
552 printf("\tprinter and queuing disabled\n");
553 }
554 seteuid(uid);
555 return;
556 } else
557 printf("\tcannot stat lock file\n");
558 /*
559 * Write the message into the status file.
560 */
561 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST);
562 fd = open(line, O_WRONLY|O_CREAT, 0664);
563 if (fd < 0 || flock(fd, LOCK_EX) < 0) {
564 printf("\tcannot create status file\n");
565 seteuid(uid);
566 if (fd >= 0)
567 (void)close(fd);
568 return;
569 }
570 seteuid(uid);
571 (void)ftruncate(fd, 0);
572 if (argc <= 0) {
573 (void)write(fd, "\n", 1);
574 (void)close(fd);
575 return;
576 }
577 cp1 = buf;
578 while (--argc >= 0) {
579 cp2 = *argv++;
580 while ((size_t)(cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++))
581 ;
582 cp1[-1] = ' ';
583 }
584 cp1[-1] = '\n';
585 *cp1 = '\0';
586 (void)write(fd, buf, strlen(buf));
587 (void)close(fd);
588 }
589
590 /*
591 * Exit lpc
592 */
593 void
594 quit(int argc, char *argv[])
595 {
596 exit(0);
597 }
598
599 /*
600 * Kill and restart the daemon.
601 */
602 void
603 restart(int argc, char *argv[])
604 {
605 int c;
606 char *cp1, *cp2;
607 char prbuf[100];
608
609 if (argc == 1) {
610 printf("Usage: restart {all | printer ...}\n");
611 return;
612 }
613 if (argc == 2 && !strcmp(argv[1], "all")) {
614 printer = prbuf;
615 while (cgetnext(&bp, printcapdb) > 0) {
616 cp1 = prbuf;
617 cp2 = bp;
618 while ((c = *cp2++) && c != '|' && c != ':' &&
619 (size_t)(cp1 - prbuf) < sizeof(prbuf))
620 *cp1++ = c;
621 *cp1 = '\0';
622 abortpr(0);
623 startpr(0);
624 }
625 return;
626 }
627 while (--argc) {
628 printer = *++argv;
629 if (!getcapdesc())
630 continue;
631 abortpr(0);
632 startpr(0);
633 }
634 }
635
636 /*
637 * Enable printing on the specified printer and startup the daemon.
638 */
639 void
640 startcmd(int argc, char *argv[])
641 {
642 int c;
643 char *cp1, *cp2;
644 char prbuf[100];
645
646 if (argc == 1) {
647 printf("Usage: start {all | printer ...}\n");
648 return;
649 }
650 if (argc == 2 && !strcmp(argv[1], "all")) {
651 printer = prbuf;
652 while (cgetnext(&bp, printcapdb) > 0) {
653 cp1 = prbuf;
654 cp2 = bp;
655 while ((c = *cp2++) && c != '|' && c != ':' &&
656 (size_t)(cp1 - prbuf) < sizeof(prbuf))
657 *cp1++ = c;
658 *cp1 = '\0';
659 startpr(1);
660 }
661 return;
662 }
663 while (--argc) {
664 printer = *++argv;
665 if (!getcapdesc())
666 continue;
667 startpr(1);
668 }
669 }
670
671 static void
672 startpr(int ena)
673 {
674 struct stat stbuf;
675
676 getcaps();
677 printf("%s:\n", printer);
678
679 /*
680 * Turn off the owner execute bit of the lock file to enable printing.
681 */
682 seteuid(euid);
683 if (ena && stat(line, &stbuf) >= 0) {
684 if (chmod(line, stbuf.st_mode & (ena == 2 ? 0666 : 0677)) < 0)
685 printf("\tcannot enable printing\n");
686 else
687 printf("\tprinting enabled\n");
688 }
689 if (!startdaemon(printer))
690 printf("\tcouldn't start daemon\n");
691 else
692 printf("\tdaemon started\n");
693 seteuid(uid);
694 }
695
696 /*
697 * Print the status of each queue listed or all the queues.
698 */
699 void
700 status(int argc, char *argv[])
701 {
702 int c;
703 char *cp1, *cp2;
704 char prbuf[100];
705
706 if (argc == 1 || (argc == 2 && strcmp(argv[1], "all") == 0)) {
707 printer = prbuf;
708 while (cgetnext(&bp, printcapdb) > 0) {
709 cp1 = prbuf;
710 cp2 = bp;
711 while ((c = *cp2++) && c != '|' && c != ':' &&
712 (size_t)(cp1 - prbuf) < sizeof(prbuf))
713 *cp1++ = c;
714 *cp1 = '\0';
715 prstat();
716 }
717 return;
718 }
719 while (--argc) {
720 printer = *++argv;
721 if (!getcapdesc())
722 continue;
723 prstat();
724 }
725 }
726
727 /*
728 * Print the status of the printer queue.
729 */
730 static void
731 prstat(void)
732 {
733 struct stat stbuf;
734 int fd, i;
735 struct dirent *dp;
736 DIR *dirp;
737
738 getcaps();
739 printf("%s:\n", printer);
740 if (stat(line, &stbuf) >= 0) {
741 printf("\tqueuing is %s\n",
742 (stbuf.st_mode & 010) ? "disabled" : "enabled");
743 printf("\tprinting is %s\n",
744 (stbuf.st_mode & 0100) ? "disabled" : "enabled");
745 } else {
746 printf("\tqueuing is enabled\n");
747 printf("\tprinting is enabled\n");
748 }
749 if ((dirp = opendir(SD)) == NULL) {
750 printf("\tcannot examine spool directory\n");
751 return;
752 }
753 i = 0;
754 while ((dp = readdir(dirp)) != NULL) {
755 if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
756 i++;
757 }
758 closedir(dirp);
759 if (i == 0)
760 printf("\tno entries\n");
761 else if (i == 1)
762 printf("\t1 entry in spool area\n");
763 else
764 printf("\t%d entries in spool area\n", i);
765 fd = open(line, O_RDONLY);
766 if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
767 if (fd >= 0)
768 (void)close(fd); /* unlocks as well */
769 printf("\tprinter idle\n");
770 return;
771 }
772 (void)close(fd);
773 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST);
774 fd = open(line, O_RDONLY);
775 if (fd >= 0) {
776 (void)flock(fd, LOCK_SH);
777 (void)fstat(fd, &stbuf);
778 if (stbuf.st_size > 0) {
779 putchar('\t');
780 while ((i = read(fd, line, sizeof(line))) > 0)
781 (void)fwrite(line, 1, i, stdout);
782 }
783 (void)close(fd); /* unlocks as well */
784 }
785 }
786
787 /*
788 * Stop the specified daemon after completing the current job and disable
789 * printing.
790 */
791 void
792 stop(int argc, char *argv[])
793 {
794 int c;
795 char *cp1, *cp2;
796 char prbuf[100];
797
798 if (argc == 1) {
799 printf("Usage: stop {all | printer ...}\n");
800 return;
801 }
802 if (argc == 2 && !strcmp(argv[1], "all")) {
803 printer = prbuf;
804 while (cgetnext(&bp, printcapdb) > 0) {
805 cp1 = prbuf;
806 cp2 = bp;
807 while ((c = *cp2++) && c != '|' && c != ':' &&
808 (size_t)(cp1 - prbuf) < sizeof(prbuf))
809 *cp1++ = c;
810 *cp1 = '\0';
811 stoppr();
812 }
813 return;
814 }
815 while (--argc) {
816 printer = *++argv;
817 if (!getcapdesc())
818 continue;
819 stoppr();
820 }
821 }
822
823 static void
824 stoppr(void)
825 {
826 int fd;
827 struct stat stbuf;
828
829 getcaps();
830 printf("%s:\n", printer);
831
832 /*
833 * Turn on the owner execute bit of the lock file to disable printing.
834 */
835 seteuid(euid);
836 if (stat(line, &stbuf) >= 0) {
837 if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
838 printf("\tcannot disable printing\n");
839 else {
840 upstat("printing disabled\n");
841 printf("\tprinting disabled\n");
842 }
843 } else if (errno == ENOENT) {
844 if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
845 printf("\tcannot create lock file\n");
846 else {
847 (void)close(fd);
848 upstat("printing disabled\n");
849 printf("\tprinting disabled\n");
850 }
851 } else
852 printf("\tcannot stat lock file\n");
853 seteuid(uid);
854 }
855
856 struct queue **queue;
857 int nitems;
858 time_t mtime;
859
860 /*
861 * Put the specified jobs at the top of printer queue.
862 */
863 void
864 topq(int argc, char *argv[])
865 {
866 int i;
867 struct stat stbuf;
868 int changed;
869
870 if (argc < 3) {
871 printf("Usage: topq printer [jobnum ...] [user ...]\n");
872 return;
873 }
874
875 --argc;
876 printer = *++argv;
877 if (!getcapdesc())
878 return;
879
880 getcaps();
881 printf("%s:\n", printer);
882
883 seteuid(euid);
884 if (chdir(SD) < 0) {
885 printf("\tcannot chdir to %s\n", SD);
886 goto out;
887 }
888 seteuid(uid);
889 nitems = getq(&queue);
890 if (nitems == 0)
891 return;
892 changed = 0;
893 mtime = queue[0]->q_time;
894 for (i = argc; --i; ) {
895 if (doarg(argv[i]) == 0) {
896 printf("\tjob %s is not in the queue\n", argv[i]);
897 continue;
898 } else
899 changed++;
900 }
901 for (i = 0; i < nitems; i++)
902 free(queue[i]);
903 free(queue);
904 if (!changed) {
905 printf("\tqueue order unchanged\n");
906 return;
907 }
908 /*
909 * Turn on the public execute bit of the lock file to
910 * get lpd to rebuild the queue after the current job.
911 */
912 seteuid(euid);
913 if (changed && stat(LO, &stbuf) >= 0)
914 (void)chmod(LO, (stbuf.st_mode & 0777) | 01);
915
916 out:
917 seteuid(uid);
918 }
919
920 /*
921 * Reposition the job by changing the modification time of
922 * the control file.
923 */
924 static int
925 touch(struct queue *q)
926 {
927 struct timeval tvp[2];
928 int ret;
929
930 tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
931 tvp[0].tv_usec = tvp[1].tv_usec = 0;
932 seteuid(euid);
933 ret = utimes(q->q_name, tvp);
934 seteuid(uid);
935 return (ret);
936 }
937
938 /*
939 * Checks if specified job name is in the printer's queue.
940 * Returns: negative (-1) if argument name is not in the queue.
941 */
942 static int
943 doarg(const char *job)
944 {
945 struct queue **qq;
946 int jobnum, n;
947 char *cp;
948 const char *machine;
949 int cnt = 0;
950 FILE *fp;
951
952 /*
953 * Look for a job item consisting of system name, colon, number
954 * (example: ucbarpa:114)
955 */
956 if ((cp = strchr(job, ':')) != NULL) {
957 machine = job;
958 *cp++ = '\0';
959 job = cp;
960 } else
961 machine = NULL;
962
963 /*
964 * Check for job specified by number (example: 112 or 235ucbarpa).
965 */
966 if (isdigit((unsigned char)*job)) {
967 jobnum = 0;
968 do
969 jobnum = jobnum * 10 + (*job++ - '0');
970 while (isdigit((unsigned char)*job));
971 for (qq = queue + nitems; --qq >= queue; ) {
972 n = 0;
973 for (cp = (*qq)->q_name+3; isdigit((unsigned char)*cp); )
974 n = n * 10 + (*cp++ - '0');
975 if (jobnum != n)
976 continue;
977 if (*job && strcmp(job, cp) != 0)
978 continue;
979 if (machine != NULL && strcmp(machine, cp) != 0)
980 continue;
981 if (touch(*qq) == 0) {
982 printf("\tmoved %s\n", (*qq)->q_name);
983 cnt++;
984 }
985 }
986 return(cnt);
987 }
988 /*
989 * Process item consisting of owner's name (example: henry).
990 */
991 for (qq = queue + nitems; --qq >= queue; ) {
992 seteuid(euid);
993 fp = fopen((*qq)->q_name, "r");
994 seteuid(uid);
995 if (fp == NULL)
996 continue;
997 while (get_line(fp) > 0)
998 if (line[0] == 'P')
999 break;
1000 (void)fclose(fp);
1001 if (line[0] != 'P' || strcmp(job, line+1) != 0)
1002 continue;
1003 if (touch(*qq) == 0) {
1004 printf("\tmoved %s\n", (*qq)->q_name);
1005 cnt++;
1006 }
1007 }
1008 return(cnt);
1009 }
1010
1011 /*
1012 * Enable everything and start printer (undo `down').
1013 */
1014 void
1015 up(int argc, char *argv[])
1016 {
1017 int c;
1018 char *cp1, *cp2;
1019 char prbuf[100];
1020
1021 if (argc == 1) {
1022 printf("Usage: up {all | printer ...}\n");
1023 return;
1024 }
1025 if (argc == 2 && !strcmp(argv[1], "all")) {
1026 printer = prbuf;
1027 while (cgetnext(&bp, printcapdb) > 0) {
1028 cp1 = prbuf;
1029 cp2 = bp;
1030 while ((c = *cp2++) && c != '|' && c != ':' &&
1031 (size_t)(cp1 - prbuf) < sizeof(prbuf))
1032 *cp1++ = c;
1033 *cp1 = '\0';
1034 startpr(2);
1035 }
1036 return;
1037 }
1038 while (--argc) {
1039 printer = *++argv;
1040 if (!getcapdesc())
1041 continue;
1042 startpr(2);
1043 }
1044 }
1045