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