GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/lpr/lpc/cmds.c Lines: 0 625 0.0 %
Date: 2017-11-07 Branches: 0 454 0.0 %

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