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