xref: /netbsd/usr.sbin/lpr/lpr/lpr.c (revision 6550d01e)
1 /*	$NetBSD: lpr.c,v 1.44 2011/01/20 15:48:11 ginsbach Exp $	*/
2 
3 /*
4  * Copyright (c) 1983, 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  * (c) UNIX System Laboratories, Inc.
7  * All or some portions of this file are derived from material licensed
8  * to the University of California by American Telephone and Telegraph
9  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
10  * the permission of UNIX System Laboratories, Inc.
11  *
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include <sys/cdefs.h>
39 #ifndef lint
40 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993\
41  The Regents of the University of California.  All rights reserved.");
42 #if 0
43 static char sccsid[] = "@(#)lpr.c	8.4 (Berkeley) 4/28/95";
44 #else
45 __RCSID("$NetBSD: lpr.c,v 1.44 2011/01/20 15:48:11 ginsbach Exp $");
46 #endif
47 #endif /* not lint */
48 
49 /*
50  *      lpr -- off line print
51  *
52  * Allows multiple printers and printers on remote machines by
53  * using information from a printer data base.
54  */
55 
56 #include <sys/param.h>
57 #include <sys/stat.h>
58 #include <sys/file.h>
59 
60 #include <dirent.h>
61 #include <fcntl.h>
62 #include <signal.h>
63 #include <syslog.h>
64 #include <pwd.h>
65 #include <grp.h>
66 #include <unistd.h>
67 #include <stdlib.h>
68 #include <stdio.h>
69 #include <ctype.h>
70 #include <string.h>
71 #include <errno.h>
72 #include <err.h>
73 
74 #include "lp.h"
75 #include "lp.local.h"
76 #include "pathnames.h"
77 
78 static char	*cfname;	/* daemon control files, linked from tf's */
79 static char	*class = host;	/* class title on header page */
80 static char	*dfname;	/* data files */
81 static char	*fonts[4];	/* troff font names */
82 static char	 format = 'f';	/* format char for printing files */
83 static int	 hdr = 1;	/* print header or not (default is yes) */
84 static int	 iflag;		/* indentation wanted */
85 static int	 inchar;	/* location to increment char in file names */
86 static int	 indent;	/* amount to indent */
87 static const char *jobname;	/* job name on header page */
88 static int	 mailflg;	/* send mail */
89 static int	 nact;		/* number of jobs to act on */
90 static int	 ncopies = 1;	/* # of copies to make */
91 static const char *person;	/* user name */
92 static int	 qflag;		/* q job, but don't exec daemon */
93 static int	 reqid;		/* request id */
94 static int	 rflag;		/* remove files upon completion */
95 static int	 Rflag;		/* print request id - like POSIX lp */
96 static int	 sflag;		/* symbolic link flag */
97 static int	 tfd;		/* control file descriptor */
98 static char	*tfname;	/* tmp copy of cf before linking */
99 static char	*title;		/* pr'ing title */
100 static int	 userid;	/* user id */
101 static char	*width;		/* width for versatec printing */
102 
103 static struct stat statb;
104 
105 static void	 card(int, const char *);
106 static void	 chkprinter(const char *);
107 static void	 cleanup(int);
108 static void	 copy(int, const char *);
109 static char	*itoa(int);
110 static const char	*linked(const char *);
111 static char	*lmktemp(const char *, int, int);
112 static void	 mktemps(void);
113 static int	 nfile(char *);
114 static int	 test(const char *);
115 static void	 usage(void) __dead;
116 
117 uid_t	uid, euid;
118 
119 int
120 main(int argc, char *argv[])
121 {
122 	struct passwd *pw;
123 	struct group *gptr;
124 	char *arg;
125 	const char *cp;
126 	char buf[MAXPATHLEN];
127 	int i, f, errs, c;
128 	struct stat stb;
129 	int oerrno;
130 
131 	euid = geteuid();
132 	uid = getuid();
133 	seteuid(uid);
134 
135 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
136 		signal(SIGHUP, cleanup);
137 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
138 		signal(SIGINT, cleanup);
139 	if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
140 		signal(SIGQUIT, cleanup);
141 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
142 		signal(SIGTERM, cleanup);
143 
144 	setprogname(*argv);
145 	gethostname(host, sizeof (host));
146 	host[sizeof(host) - 1] = '\0';
147 	openlog("lpd", 0, LOG_LPR);
148 
149 	errs = 0;
150 	while ((c = getopt(argc, argv,
151 	    ":#:1:2:3:4:C:J:P:RT:U:cdfghi:lmnopqrstvw:")) != -1) {
152 		switch (c) {
153 
154 		case '#':		/* n copies */
155 			if (isdigit((unsigned char)*optarg)) {
156 				i = atoi(optarg);
157 				if (i > 0)
158 					ncopies = i;
159 			}
160 			break;
161 
162 		case '4':		/* troff fonts */
163 		case '3':
164 		case '2':
165 		case '1':
166 			fonts[optopt - '1'] = optarg;
167 			break;
168 
169 		case 'C':		/* classification spec */
170 			hdr++;
171 			class = optarg;
172 			break;
173 
174 		case 'J':		/* job name */
175 			hdr++;
176 			jobname = optarg;
177 			break;
178 
179 		case 'P':		/* specifiy printer name */
180 			printer = optarg;
181 			break;
182 
183 		case 'R':		/* print request id */
184 			Rflag++;
185 			break;
186 
187 		case 'T':		/* pr's title line */
188 			title = optarg;
189 			break;
190 
191 		case 'U':		/* user name */
192 			hdr++;
193 			person = optarg;
194 			break;
195 
196 		case 'c':		/* print cifplot output */
197 		case 'd':		/* print tex output (dvi files) */
198 		case 'g':		/* print graph(1G) output */
199 		case 'l':		/* literal output */
200 		case 'o':		/* print postscript output */
201 		case 'n':		/* print ditroff output */
202 		case 'p':		/* print using ``pr'' */
203 		case 't':		/* print troff output (cat files) */
204 		case 'v':		/* print vplot output */
205 			format = optopt;
206 			break;
207 
208 		case 'f':		/* print fortran output */
209 			format = 'r';
210 			break;
211 
212 		case 'h':		/* toggle want of header page */
213 			hdr = !hdr;
214 			break;
215 
216 		case 'i':		/* indent output */
217 			iflag++;
218 			indent = atoi(optarg);
219 			if (indent < 0)
220 				indent = 8;
221 			break;
222 
223 		case 'm':		/* send mail when done */
224 			mailflg++;
225 			break;
226 
227 		case 'q':		/* just q job */
228 			qflag++;
229 			break;
230 
231 		case 'r':		/* remove file when done */
232 			rflag++;
233 			break;
234 
235 		case 's':		/* try to link files */
236 			sflag++;
237 			break;
238 
239 		case 'w':		/* versatec page width */
240 			width = optarg;
241 			break;
242 
243 		case ':':               /* catch "missing argument" error */
244 			if (optopt == 'i') {
245 				iflag++; /* -i without args is valid */
246 				indent = 8;
247 			} else
248 				errs++;
249 			break;
250 
251 		default:
252 			errs++;
253 		}
254 	}
255 	argc -= optind;
256 	argv += optind;
257 	if (errs)
258 		usage();
259 	if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
260 		printer = DEFLP;
261 	chkprinter(printer);
262 	if (SC && ncopies > 1)
263 		errx(EXIT_FAILURE, "multiple copies are not allowed");
264 	if (MC > 0 && ncopies > MC)
265 		errx(EXIT_FAILURE, "only %ld copies are allowed", MC);
266 	/*
267 	 * Get the identity of the person doing the lpr using the same
268 	 * algorithm as lprm.
269 	 */
270 	userid = getuid();
271 	if (userid != DU || person == 0) {
272 		if ((pw = getpwuid(userid)) == NULL)
273 			errx(EXIT_FAILURE, "Who are you?");
274 		person = pw->pw_name;
275 	}
276 	/*
277 	 * Check for restricted group access.
278 	 */
279 	if (RG != NULL && userid != DU) {
280 		if ((gptr = getgrnam(RG)) == NULL)
281 			errx(EXIT_FAILURE,
282 			     "Restricted group specified incorrectly");
283 		if (gptr->gr_gid != getgid()) {
284 			while (*gptr->gr_mem != NULL) {
285 				if ((strcmp(person, *gptr->gr_mem)) == 0)
286 					break;
287 				gptr->gr_mem++;
288 			}
289 			if (*gptr->gr_mem == NULL)
290 				errx(EXIT_FAILURE,
291 				     "Not a member of the restricted group");
292 		}
293 	}
294 	/*
295 	 * Check to make sure queuing is enabled if userid is not root.
296 	 */
297 	(void)snprintf(buf, sizeof buf, "%s/%s", SD, LO);
298 	if (userid && stat(buf, &stb) == 0 && (stb.st_mode & S_IXGRP))
299 		errx(EXIT_FAILURE, "Printer queue is disabled");
300 	/*
301 	 * Initialize the control file.
302 	 */
303 	mktemps();
304 	tfd = nfile(tfname);
305 	seteuid(euid);
306 	(void)fchown(tfd, DU, -1);	/* owned by daemon for protection */
307 	seteuid(uid);
308 	card('H', host);
309 	card('P', person);
310 	if (hdr && !SH) {
311 		if (jobname == NULL) {
312 			if (argc == 0)
313 				jobname = "stdin";
314 			else
315 				jobname = (arg = strrchr(argv[0], '/')) ?
316 				    arg+1 : argv[0];
317 		}
318 		card('J', jobname);
319 		card('C', class);
320 		card('L', person);
321 	}
322 	if (iflag)
323 		card('I', itoa(indent));
324 	if (mailflg)
325 		card('M', person);
326 	if (format == 't' || format == 'n' || format == 'd')
327 		for (i = 0; i < 4; i++)
328 			if (fonts[i] != NULL)
329 				card('1'+i, fonts[i]);
330 	if (width != NULL)
331 		card('W', width);
332 
333 	/*
334 	 * Read the files and spool them.
335 	 */
336 	if (argc == 0)
337 		copy(0, " ");
338 	else while (argc--) {
339 		if (argv[0][0] == '-' && argv[0][1] == '\0') {
340 			/* use stdin */
341 			copy(0, " ");
342 			argv++;
343 			continue;
344 		}
345 		if ((f = test(arg = *argv++)) < 0)
346 			continue;	/* file unreasonable */
347 
348 		if (sflag && (cp = linked(arg)) != NULL) {
349 			(void)snprintf(buf, sizeof buf,
350 			    "%llu %llu",
351 			    (unsigned long long)statb.st_dev,
352 			    (unsigned long long)statb.st_ino);
353 			card('S', buf);
354 			if (format == 'p')
355 				card('T', title ? title : arg);
356 			for (i = 0; i < ncopies; i++)
357 				card(format, &dfname[inchar-2]);
358 			card('U', &dfname[inchar-2]);
359 			if (f)
360 				card('U', cp);
361 			card('N', arg);
362 			dfname[inchar]++;
363 			nact++;
364 			continue;
365 		}
366 		if (sflag)
367 			warnx("%s: not linked, copying instead", arg);
368 		seteuid(uid);
369 		if ((i = open(arg, O_RDONLY)) < 0) {
370 			oerrno = errno;
371 			seteuid(uid);
372 			errno = oerrno;
373 			warn("cannot open %s", arg);
374 			continue;
375 		} else {
376 			copy(i, arg);
377 			(void)close(i);
378 			if (f && unlink(arg) < 0)
379 				warn("%s: not removed", arg);
380 		}
381 		seteuid(uid);
382 	}
383 
384 	if (nact) {
385 		(void)close(tfd);
386 		tfname[inchar]--;
387 		/*
388 		 * Touch the control file to fix position in the queue.
389 		 */
390 		seteuid(euid);
391 		if ((tfd = open(tfname, O_RDWR)) >= 0) {
392 			char ch;
393 
394 			if (read(tfd, &ch, 1) == 1 &&
395 			    lseek(tfd, (off_t)0, 0) == 0 &&
396 			    write(tfd, &ch, 1) != 1) {
397 				warn("cannot touch %s", tfname);
398 				tfname[inchar]++;
399 				cleanup(0);
400 			}
401 			(void)close(tfd);
402 		}
403 		if (link(tfname, cfname) < 0) {
404 			warn("cannot rename %s", cfname);
405 			tfname[inchar]++;
406 			cleanup(0);
407 		}
408 		unlink(tfname);
409 		seteuid(uid);
410 		if (Rflag)
411 			printf("request id is %d\n", reqid);
412 		if (qflag)		/* just queue things up */
413 			exit(0);
414 		if (!startdaemon(printer))
415 			printf("jobs queued, but cannot start daemon.\n");
416 		exit(0);
417 	}
418 	cleanup(0);
419 #ifdef __GNUC__
420 	return (0);
421 #endif
422 	/* NOTREACHED */
423 }
424 
425 /*
426  * Create the file n and copy from file descriptor f.
427  */
428 static void
429 copy(int f, const char *n)
430 {
431 	int fd, i, nr;
432 	size_t nc;
433 	char buf[BUFSIZ];
434 
435 	if (format == 'p')
436 		card('T', title ? title : n);
437 	for (i = 0; i < ncopies; i++)
438 		card(format, &dfname[inchar-2]);
439 	card('U', &dfname[inchar-2]);
440 	card('N', n);
441 	fd = nfile(dfname);
442 	nr = nc = 0;
443 	while ((i = read(f, buf, sizeof buf)) > 0) {
444 		if (write(fd, buf, i) != i) {
445 			warn("%s: temp file write error", n);
446 			break;
447 		}
448 		nc += i;
449 		if (nc >= sizeof buf) {
450 			nc -= sizeof buf;
451 			nr++;
452 			if (MX > 0 && nr > MX) {
453 				warnx("%s: copy file is too large "
454 				    "(check :mx:?)\n", n);
455 				break;
456 			}
457 		}
458 	}
459 	(void)close(fd);
460 	if (nc == 0 && nr == 0)
461 		printf("%s: %s: empty input file\n", getprogname(),
462 		    f ? n : "stdin");
463 	else
464 		nact++;
465 }
466 
467 /*
468  * Try and link the file to dfname. Return a pointer to the full
469  * path name if successful.
470  */
471 static const char *
472 linked(const char *file)
473 {
474 	char *cp;
475 	static char buf[BUFSIZ];
476 	int ret;
477 
478 	if (*file != '/') {
479 		/* XXX: 2 and file for "/file" */
480 		if (getcwd(buf, sizeof(buf) - 2 - strlen(file)) == NULL)
481 			return(NULL);
482 		while (file[0] == '.') {
483 			switch (file[1]) {
484 			case '/':
485 				file += 2;
486 				continue;
487 			case '.':
488 				if (file[2] == '/') {
489 					if ((cp = strrchr(buf, '/')) != NULL)
490 						*cp = '\0';
491 					file += 3;
492 					continue;
493 				}
494 			}
495 			break;
496 		}
497 		strlcat(buf, "/", sizeof(buf));
498 		strlcat(buf, file, sizeof(buf));
499 		file = buf;
500 	}
501 	seteuid(euid);
502 	ret = symlink(file, dfname);
503 	seteuid(uid);
504 	return(ret ? NULL : file);
505 }
506 
507 /*
508  * Put a line into the control file.
509  */
510 static void
511 card(int c, const char *p2)
512 {
513 	char buf[BUFSIZ];
514 	char *p1 = buf;
515 	size_t len = 2;
516 
517 	if (strlen(p2) > BUFSIZ - 2)
518 		errx(EXIT_FAILURE,
519 		     "Internal error:  String longer than %d", BUFSIZ);
520 
521 	*p1++ = c;
522 	while ((c = *p2++) != '\0') {
523 		*p1++ = (c == '\n') ? ' ' : c;
524 		len++;
525 	}
526 	*p1++ = '\n';
527 	if (write(tfd, buf, len) != (ssize_t)len)
528 		warn("Control file write error");
529 }
530 
531 /*
532  * Create a new file in the spool directory.
533  */
534 static int
535 nfile(char *n)
536 {
537 	int f;
538 	int oldumask = umask(0);		/* should block signals */
539 	int oerrno;
540 
541 	seteuid(euid);
542 	f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD);
543 	oerrno = errno;
544 	(void)umask(oldumask);
545 	if (f < 0) {
546 		errno = oerrno;
547 		warn("cannot create %s", n);
548 		cleanup(0);
549 	}
550 	if (fchown(f, userid, -1) < 0) {
551 		warn("cannot chown %s", n);
552 		cleanup(0);	/* cleanup does exit */
553 	}
554 	seteuid(uid);
555 	if (++n[inchar] > 'z') {
556 		if (++n[inchar-2] == 't') {
557 			printf("too many files - break up the job\n");
558 			cleanup(0);
559 		}
560 		n[inchar] = 'A';
561 	} else if (n[inchar] == '[')
562 		n[inchar] = 'a';
563 	return(f);
564 }
565 
566 /*
567  * Cleanup after interrupts and errors.
568  */
569 static void
570 cleanup(int signo)
571 {
572 	int i;
573 
574 	signal(SIGHUP, SIG_IGN);
575 	signal(SIGINT, SIG_IGN);
576 	signal(SIGQUIT, SIG_IGN);
577 	signal(SIGTERM, SIG_IGN);
578 	i = inchar;
579 	seteuid(euid);
580 	if (tfname)
581 		do
582 			unlink(tfname);
583 		while (tfname[i]-- != 'A');
584 	if (cfname)
585 		do
586 			unlink(cfname);
587 		while (cfname[i]-- != 'A');
588 	if (dfname)
589 		do {
590 			do
591 				unlink(dfname);
592 			while (dfname[i]-- != 'A');
593 			dfname[i] = 'z';
594 		} while (dfname[i-2]-- != 'd');
595 	exit(1);
596 }
597 
598 /*
599  * Test to see if this is a printable file.
600  * Return -1 if it is not, 0 if its printable, and 1 if
601  * we should remove it after printing.
602  */
603 static int
604 test(const char *file)
605 {
606 	int fd;
607 	char *cp;
608 
609 	seteuid(uid);
610 	if (access(file, 4) < 0) {
611 		warn("cannot access %s", file);
612 		goto bad;
613 	}
614 	if (stat(file, &statb) < 0) {
615 		warn("cannot stat %s", file);
616 		goto bad;
617 	}
618 	if (S_ISDIR(statb.st_mode)) {
619 		warnx("%s is a directory", file);
620 		goto bad;
621 	}
622 	if (statb.st_size == 0) {
623 		warnx("%s is an empty file", file);
624 		goto bad;
625  	}
626 	if ((fd = open(file, O_RDONLY)) < 0) {
627 		warn("cannot open %s", file);
628 		goto bad;
629 	}
630 	(void)close(fd);
631 	if (rflag) {
632 		if ((cp = strrchr(file, '/')) == NULL) {
633 			if (access(".", 2) == 0)
634 				return(1);
635 		} else {
636 			if (cp == file) {
637 				fd = access("/", 2);
638 			} else {
639 				*cp = '\0';
640 				fd = access(file, 2);
641 				*cp = '/';
642 			}
643 			if (fd == 0)
644 				return(1);
645 		}
646 		warnx("%s: is not removable by you", file);
647 	}
648 	return(0);
649 bad:
650 	seteuid(uid);
651 	return(-1);
652 }
653 
654 /*
655  * itoa - integer to string conversion
656  */
657 static char *
658 itoa(int i)
659 {
660 	static char b[10] = "########";
661 	char *p;
662 
663 	p = &b[8];
664 	do
665 		*p-- = i%10 + '0';
666 	while (i /= 10);
667 	return(++p);
668 }
669 
670 /*
671  * Perform lookup for printer name or abbreviation --
672  */
673 static void
674 chkprinter(const char *s)
675 {
676 	char *cp;
677 
678 	getprintcap(s);
679 	RG = cgetstr(bp, "rg", &cp) == -1 ? NULL : cp;
680 	if (cgetnum(bp, "mx", &MX) < 0)
681 		MX = DEFMX;
682 	if (cgetnum(bp,"mc", &MC) < 0)
683 		MC = DEFMAXCOPIES;
684 	if (cgetnum(bp, "du", &DU) < 0)
685 		DU = DEFUID;
686 	SC = (cgetcap(bp, "sc", ':') != NULL);
687 }
688 
689 /*
690  * Make the temp files.
691  */
692 static void
693 mktemps(void)
694 {
695 	int len, fd, n;
696 	char *cp;
697 	char buf[MAXPATHLEN];
698 
699 	(void)snprintf(buf, sizeof(buf), "%s/.seq", SD);
700 	seteuid(euid);
701 	if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0)
702 		err(1, "cannot create %s", buf);
703 	if (flock(fd, LOCK_EX))
704 		err(1, "cannot lock %s", buf);
705 	seteuid(uid);
706 	n = 0;
707 	if ((len = read(fd, buf, sizeof(buf))) > 0) {
708 		for (cp = buf; len--; ) {
709 			if (*cp < '0' || *cp > '9')
710 				break;
711 			n = n * 10 + (*cp++ - '0');
712 		}
713 	}
714 	reqid = n;
715 	len = strlen(SD) + strlen(host) + 8;
716 	tfname = lmktemp("tf", n, len);
717 	cfname = lmktemp("cf", n, len);
718 	dfname = lmktemp("df", n, len);
719 	inchar = strlen(SD) + 3;
720 	n = (n + 1) % 1000;
721 	(void)lseek(fd, (off_t)0, 0);
722 	(void)snprintf(buf, sizeof(buf), "%03d\n", n);
723 	(void)write(fd, buf, strlen(buf));
724 	(void)close(fd);	/* unlocks as well */
725 }
726 
727 /*
728  * Make a temp file name.
729  */
730 static char *
731 lmktemp(const char *id, int num, int len)
732 {
733 	char *s;
734 
735 	if ((s = malloc(len)) == NULL)
736 		err(EXIT_FAILURE, NULL);
737 	(void)snprintf(s, len, "%s/%sA%03d%s", SD, id, num, host);
738 	return(s);
739 }
740 
741 static void
742 usage(void)
743 {
744 
745 	fprintf(stderr,
746 	    "Usage: %s [-Pprinter] [-#num] [-C class] [-J job] [-T title] "
747 	    "[-U user]\n"
748 	    "%s [-i[numcols]] [-1234 font] [-wnum] [-cdfghlmnopqRrstv] "
749 	    "[name ...]\n", getprogname(), getprogname());
750 	exit(1);
751 }
752