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