Patrick Welche <prlw1@cam.ac.uk>
[netbsd-mini2440.git] / usr.sbin / lpr / lpc / cmds.c
blob6c740857a8f4f794de3080bec241a90ab0e4c988
1 /* $NetBSD: cmds.c,v 1.21 2009/01/18 09:57:26 lukem Exp $ */
2 /*
3 * Copyright (c) 1983, 1993
4 * The Regents of the University of California. All rights reserved.
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.
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.
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.21 2009/01/18 09:57:26 lukem Exp $");
40 #endif
41 #endif /* not lint */
44 * lpc -- line printer control program -- commands:
47 #include <sys/param.h>
48 #include <sys/time.h>
49 #include <sys/stat.h>
50 #include <sys/file.h>
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"
67 extern uid_t uid, euid;
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);
87 * kill an existing daemon and disable printing.
89 void
90 doabort(int argc, char *argv[])
92 int c;
93 char *cp1, *cp2;
94 char prbuf[100];
96 if (argc == 1) {
97 printf("Usage: abort {all | printer ...}\n");
98 return;
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);
111 return;
113 while (--argc) {
114 printer = *++argv;
115 if (!getcapdesc())
116 continue;
117 abortpr(1);
121 static void
122 abortpr(int dis)
124 FILE *fp;
125 struct stat stbuf;
126 int pid, fd;
128 getcaps();
129 printf("%s:\n", printer);
132 * Turn on the owner execute bit of the lock file to disable printing.
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");
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");
152 goto out;
153 } else {
154 printf("\tcannot stat lock file\n");
155 goto out;
159 * Kill the current daemon to stop printing now.
161 if ((fp = fopen(line, "r")) == NULL) {
162 printf("\tcannot open lock file\n");
163 goto out;
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;
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);
183 * Write a message into the status file.
185 static void
186 upstat(const char *msg)
188 int fd;
189 char statfile[MAXPATHLEN];
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;
201 (void)ftruncate(fd, 0);
202 if (msg == (char *)NULL)
203 (void)write(fd, "\n", 1);
204 else
205 (void)write(fd, msg, strlen(msg));
206 (void)close(fd);
210 * Remove all spool files and temporaries from the spooling area.
212 void
213 clean(int argc, char *argv[])
215 int c;
216 char *cp1, *cp2;
217 char prbuf[100];
219 if (argc == 1) {
220 printf("Usage: clean {all | printer ...}\n");
221 return;
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();
234 return;
236 while (--argc) {
237 printer = *++argv;
238 if (!getcapdesc())
239 continue;
240 cleanpr();
244 static int
245 doselect(const struct dirent *d)
247 int c = d->d_name[0];
249 if ((c == 't' || c == 'c' || c == 'd') && d->d_name[1] == 'f')
250 return(1);
251 return(0);
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.
258 static int
259 sortq(const void *a, const void *b)
261 const struct dirent *const *d1, *const *d2;
262 int c1, c2;
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);
280 * Remove incomplete jobs from spooling area.
282 static void
283 cleanpr(void)
285 int i, n;
286 char *cp1, *lp, *ep;
287 const char *cp;
288 struct dirent **queue;
289 int nitems;
291 getcaps();
292 printf("%s:\n", printer);
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'; )
299 lp[-1] = '/';
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;
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++;
322 if (n == 0) {
323 strlcpy(lp, cp, ep - lp);
324 unlinkf(line);
326 } else {
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).
332 strlcpy(lp, cp, ep - lp);
333 unlinkf(line);
335 } while (++i < nitems);
338 static void
339 unlinkf(const char *name)
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);
350 * Enable queuing to the printer (allow lpr's).
352 void
353 enable(int argc, char *argv[])
355 int c;
356 char *cp1, *cp2;
357 char prbuf[100];
359 if (argc == 1) {
360 printf("Usage: enable {all | printer ...}\n");
361 return;
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();
374 return;
376 while (--argc) {
377 printer = *++argv;
378 if (!getcapdesc())
379 continue;
380 enablepr();
384 static int
385 getcapdesc(void)
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;
399 static void
400 enablepr(void)
402 struct stat stbuf;
404 getcaps();
405 printf("%s:\n", printer);
408 * Turn off the group execute bit of the lock file to enable queuing.
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");
417 seteuid(uid);
421 * Disable queuing.
423 void
424 disable(int argc, char *argv[])
426 int c;
427 char *cp1, *cp2;
428 char prbuf[100];
430 if (argc == 1) {
431 printf("Usage: disable {all | printer ...}\n");
432 return;
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();
445 return;
447 while (--argc) {
448 printer = *++argv;
449 if (!getcapdesc())
450 continue;
451 disablepr();
455 static void
456 disablepr(void)
458 int fd;
459 struct stat stbuf;
461 getcaps();
462 printf("%s:\n", printer);
464 * Turn on the group execute bit of the lock file to disable queuing.
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");
479 } else
480 printf("\tcannot stat lock file\n");
481 seteuid(uid);
485 * Disable queuing and printing and put a message into the status file
486 * (reason for being down).
488 void
489 down(int argc, char *argv[])
491 int c;
492 char *cp1, *cp2;
493 char prbuf[100];
495 if (argc == 1) {
496 printf("Usage: down {all | printer} [message ...]\n");
497 return;
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);
510 return;
512 printer = argv[1];
513 if (!getcapdesc())
514 return;
515 putmsg(argc - 2, argv + 2);
518 static void
519 getcaps(void)
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);
528 static void
529 putmsg(int argc, char **argv)
531 int fd;
532 char *cp1, *cp2;
533 char buf[1024];
534 struct stat stbuf;
536 printf("%s:\n", printer);
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.
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");
554 seteuid(uid);
555 return;
556 } else
557 printf("\tcannot stat lock file\n");
559 * Write the message into the status file.
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 return;
568 seteuid(uid);
569 (void)ftruncate(fd, 0);
570 if (argc <= 0) {
571 (void)write(fd, "\n", 1);
572 (void)close(fd);
573 return;
575 cp1 = buf;
576 while (--argc >= 0) {
577 cp2 = *argv++;
578 while ((size_t)(cp1 - buf) < sizeof(buf) && (*cp1++ = *cp2++))
580 cp1[-1] = ' ';
582 cp1[-1] = '\n';
583 *cp1 = '\0';
584 (void)write(fd, buf, strlen(buf));
585 (void)close(fd);
589 * Exit lpc
591 void
592 quit(int argc, char *argv[])
594 exit(0);
598 * Kill and restart the daemon.
600 void
601 restart(int argc, char *argv[])
603 int c;
604 char *cp1, *cp2;
605 char prbuf[100];
607 if (argc == 1) {
608 printf("Usage: restart {all | printer ...}\n");
609 return;
611 if (argc == 2 && !strcmp(argv[1], "all")) {
612 printer = prbuf;
613 while (cgetnext(&bp, printcapdb) > 0) {
614 cp1 = prbuf;
615 cp2 = bp;
616 while ((c = *cp2++) && c != '|' && c != ':' &&
617 (size_t)(cp1 - prbuf) < sizeof(prbuf))
618 *cp1++ = c;
619 *cp1 = '\0';
620 abortpr(0);
621 startpr(0);
623 return;
625 while (--argc) {
626 printer = *++argv;
627 if (!getcapdesc())
628 continue;
629 abortpr(0);
630 startpr(0);
635 * Enable printing on the specified printer and startup the daemon.
637 void
638 startcmd(int argc, char *argv[])
640 int c;
641 char *cp1, *cp2;
642 char prbuf[100];
644 if (argc == 1) {
645 printf("Usage: start {all | printer ...}\n");
646 return;
648 if (argc == 2 && !strcmp(argv[1], "all")) {
649 printer = prbuf;
650 while (cgetnext(&bp, printcapdb) > 0) {
651 cp1 = prbuf;
652 cp2 = bp;
653 while ((c = *cp2++) && c != '|' && c != ':' &&
654 (size_t)(cp1 - prbuf) < sizeof(prbuf))
655 *cp1++ = c;
656 *cp1 = '\0';
657 startpr(1);
659 return;
661 while (--argc) {
662 printer = *++argv;
663 if (!getcapdesc())
664 continue;
665 startpr(1);
669 static void
670 startpr(int ena)
672 struct stat stbuf;
674 getcaps();
675 printf("%s:\n", printer);
678 * Turn off the owner execute bit of the lock file to enable printing.
680 seteuid(euid);
681 if (ena && stat(line, &stbuf) >= 0) {
682 if (chmod(line, stbuf.st_mode & (ena == 2 ? 0666 : 0677)) < 0)
683 printf("\tcannot enable printing\n");
684 else
685 printf("\tprinting enabled\n");
687 if (!startdaemon(printer))
688 printf("\tcouldn't start daemon\n");
689 else
690 printf("\tdaemon started\n");
691 seteuid(uid);
695 * Print the status of each queue listed or all the queues.
697 void
698 status(int argc, char *argv[])
700 int c;
701 char *cp1, *cp2;
702 char prbuf[100];
704 if (argc == 1 || (argc == 2 && strcmp(argv[1], "all") == 0)) {
705 printer = prbuf;
706 while (cgetnext(&bp, printcapdb) > 0) {
707 cp1 = prbuf;
708 cp2 = bp;
709 while ((c = *cp2++) && c != '|' && c != ':' &&
710 (size_t)(cp1 - prbuf) < sizeof(prbuf))
711 *cp1++ = c;
712 *cp1 = '\0';
713 prstat();
715 return;
717 while (--argc) {
718 printer = *++argv;
719 if (!getcapdesc())
720 continue;
721 prstat();
726 * Print the status of the printer queue.
728 static void
729 prstat(void)
731 struct stat stbuf;
732 int fd, i;
733 struct dirent *dp;
734 DIR *dirp;
736 getcaps();
737 printf("%s:\n", printer);
738 if (stat(line, &stbuf) >= 0) {
739 printf("\tqueuing is %s\n",
740 (stbuf.st_mode & 010) ? "disabled" : "enabled");
741 printf("\tprinting is %s\n",
742 (stbuf.st_mode & 0100) ? "disabled" : "enabled");
743 } else {
744 printf("\tqueuing is enabled\n");
745 printf("\tprinting is enabled\n");
747 if ((dirp = opendir(SD)) == NULL) {
748 printf("\tcannot examine spool directory\n");
749 return;
751 i = 0;
752 while ((dp = readdir(dirp)) != NULL) {
753 if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
754 i++;
756 closedir(dirp);
757 if (i == 0)
758 printf("\tno entries\n");
759 else if (i == 1)
760 printf("\t1 entry in spool area\n");
761 else
762 printf("\t%d entries in spool area\n", i);
763 fd = open(line, O_RDONLY);
764 if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
765 if (fd >= 0)
766 (void)close(fd); /* unlocks as well */
767 printf("\tprinter idle\n");
768 return;
770 (void)close(fd);
771 (void)snprintf(line, sizeof(line), "%s/%s", SD, ST);
772 fd = open(line, O_RDONLY);
773 if (fd >= 0) {
774 (void)flock(fd, LOCK_SH);
775 (void)fstat(fd, &stbuf);
776 if (stbuf.st_size > 0) {
777 putchar('\t');
778 while ((i = read(fd, line, sizeof(line))) > 0)
779 (void)fwrite(line, 1, i, stdout);
781 (void)close(fd); /* unlocks as well */
786 * Stop the specified daemon after completing the current job and disable
787 * printing.
789 void
790 stop(int argc, char *argv[])
792 int c;
793 char *cp1, *cp2;
794 char prbuf[100];
796 if (argc == 1) {
797 printf("Usage: stop {all | printer ...}\n");
798 return;
800 if (argc == 2 && !strcmp(argv[1], "all")) {
801 printer = prbuf;
802 while (cgetnext(&bp, printcapdb) > 0) {
803 cp1 = prbuf;
804 cp2 = bp;
805 while ((c = *cp2++) && c != '|' && c != ':' &&
806 (size_t)(cp1 - prbuf) < sizeof(prbuf))
807 *cp1++ = c;
808 *cp1 = '\0';
809 stoppr();
811 return;
813 while (--argc) {
814 printer = *++argv;
815 if (!getcapdesc())
816 continue;
817 stoppr();
821 static void
822 stoppr(void)
824 int fd;
825 struct stat stbuf;
827 getcaps();
828 printf("%s:\n", printer);
831 * Turn on the owner execute bit of the lock file to disable printing.
833 seteuid(euid);
834 if (stat(line, &stbuf) >= 0) {
835 if (chmod(line, (stbuf.st_mode & 0777) | 0100) < 0)
836 printf("\tcannot disable printing\n");
837 else {
838 upstat("printing disabled\n");
839 printf("\tprinting disabled\n");
841 } else if (errno == ENOENT) {
842 if ((fd = open(line, O_WRONLY|O_CREAT, 0760)) < 0)
843 printf("\tcannot create lock file\n");
844 else {
845 (void)close(fd);
846 upstat("printing disabled\n");
847 printf("\tprinting disabled\n");
849 } else
850 printf("\tcannot stat lock file\n");
851 seteuid(uid);
854 struct queue **queue;
855 int nitems;
856 time_t mtime;
859 * Put the specified jobs at the top of printer queue.
861 void
862 topq(int argc, char *argv[])
864 int i;
865 struct stat stbuf;
866 int changed;
868 if (argc < 3) {
869 printf("Usage: topq printer [jobnum ...] [user ...]\n");
870 return;
873 --argc;
874 printer = *++argv;
875 if (!getcapdesc())
876 return;
878 getcaps();
879 printf("%s:\n", printer);
881 seteuid(euid);
882 if (chdir(SD) < 0) {
883 printf("\tcannot chdir to %s\n", SD);
884 goto out;
886 seteuid(uid);
887 nitems = getq(&queue);
888 if (nitems == 0)
889 return;
890 changed = 0;
891 mtime = queue[0]->q_time;
892 for (i = argc; --i; ) {
893 if (doarg(argv[i]) == 0) {
894 printf("\tjob %s is not in the queue\n", argv[i]);
895 continue;
896 } else
897 changed++;
899 for (i = 0; i < nitems; i++)
900 free(queue[i]);
901 free(queue);
902 if (!changed) {
903 printf("\tqueue order unchanged\n");
904 return;
907 * Turn on the public execute bit of the lock file to
908 * get lpd to rebuild the queue after the current job.
910 seteuid(euid);
911 if (changed && stat(LO, &stbuf) >= 0)
912 (void)chmod(LO, (stbuf.st_mode & 0777) | 01);
914 out:
915 seteuid(uid);
919 * Reposition the job by changing the modification time of
920 * the control file.
922 static int
923 touch(struct queue *q)
925 struct timeval tvp[2];
926 int ret;
928 tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
929 tvp[0].tv_usec = tvp[1].tv_usec = 0;
930 seteuid(euid);
931 ret = utimes(q->q_name, tvp);
932 seteuid(uid);
933 return (ret);
937 * Checks if specified job name is in the printer's queue.
938 * Returns: negative (-1) if argument name is not in the queue.
940 static int
941 doarg(const char *job)
943 struct queue **qq;
944 int jobnum, n;
945 char *cp;
946 const char *machine;
947 int cnt = 0;
948 FILE *fp;
951 * Look for a job item consisting of system name, colon, number
952 * (example: ucbarpa:114)
954 if ((cp = strchr(job, ':')) != NULL) {
955 machine = job;
956 *cp++ = '\0';
957 job = cp;
958 } else
959 machine = NULL;
962 * Check for job specified by number (example: 112 or 235ucbarpa).
964 if (isdigit((unsigned char)*job)) {
965 jobnum = 0;
967 jobnum = jobnum * 10 + (*job++ - '0');
968 while (isdigit((unsigned char)*job));
969 for (qq = queue + nitems; --qq >= queue; ) {
970 n = 0;
971 for (cp = (*qq)->q_name+3; isdigit((unsigned char)*cp); )
972 n = n * 10 + (*cp++ - '0');
973 if (jobnum != n)
974 continue;
975 if (*job && strcmp(job, cp) != 0)
976 continue;
977 if (machine != NULL && strcmp(machine, cp) != 0)
978 continue;
979 if (touch(*qq) == 0) {
980 printf("\tmoved %s\n", (*qq)->q_name);
981 cnt++;
984 return(cnt);
987 * Process item consisting of owner's name (example: henry).
989 for (qq = queue + nitems; --qq >= queue; ) {
990 seteuid(euid);
991 fp = fopen((*qq)->q_name, "r");
992 seteuid(uid);
993 if (fp == NULL)
994 continue;
995 while (get_line(fp) > 0)
996 if (line[0] == 'P')
997 break;
998 (void)fclose(fp);
999 if (line[0] != 'P' || strcmp(job, line+1) != 0)
1000 continue;
1001 if (touch(*qq) == 0) {
1002 printf("\tmoved %s\n", (*qq)->q_name);
1003 cnt++;
1006 return(cnt);
1010 * Enable everything and start printer (undo `down').
1012 void
1013 up(int argc, char *argv[])
1015 int c;
1016 char *cp1, *cp2;
1017 char prbuf[100];
1019 if (argc == 1) {
1020 printf("Usage: up {all | printer ...}\n");
1021 return;
1023 if (argc == 2 && !strcmp(argv[1], "all")) {
1024 printer = prbuf;
1025 while (cgetnext(&bp, printcapdb) > 0) {
1026 cp1 = prbuf;
1027 cp2 = bp;
1028 while ((c = *cp2++) && c != '|' && c != ':' &&
1029 (size_t)(cp1 - prbuf) < sizeof(prbuf))
1030 *cp1++ = c;
1031 *cp1 = '\0';
1032 startpr(2);
1034 return;
1036 while (--argc) {
1037 printer = *++argv;
1038 if (!getcapdesc())
1039 continue;
1040 startpr(2);