Merge branch 'master' of ssh://crater.dragonflybsd.org/repository/git/dragonfly
[dragonfly.git] / usr.sbin / lpr / lpr / lpr.c
blob67593ec10a7542a9b9f6f87ffce7ef31badb78e3
1 /*
2 * Copyright (c) 1983, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37 * SUCH DAMAGE.
39 * @(#) Copyright (c) 1983, 1989, 1993 The Regents of the University of California. All rights reserved.
40 * @(#)from: lpr.c 8.4 (Berkeley) 4/28/95
41 * $FreeBSD: src/usr.sbin/lpr/lpr/lpr.c,v 1.32.2.11 2002/04/28 23:40:23 gad Exp $
42 * $DragonFly: src/usr.sbin/lpr/lpr/lpr.c,v 1.5 2005/08/08 18:58:56 joerg Exp $
46 * lpr -- off line print
48 * Allows multiple printers and printers on remote machines by
49 * using information from a printer data base.
52 #include <sys/param.h>
53 #include <sys/stat.h>
55 #include <netinet/in.h> /* N_BADMAG uses ntohl() */
57 #include <dirent.h>
58 #include <fcntl.h>
59 #include <a.out.h>
60 #include <err.h>
61 #include <inttypes.h>
62 #include <locale.h>
63 #include <signal.h>
64 #include <syslog.h>
65 #include <pwd.h>
66 #include <grp.h>
67 #include <unistd.h>
68 #include <stdlib.h>
69 #include <stdio.h>
70 #include <ctype.h>
71 #include <string.h>
72 #include "lp.h"
73 #include "lp.local.h"
74 #include "pathnames.h"
76 static char *cfname; /* daemon control files, linked from tf's */
77 static char *class = local_host; /* class title on header page */
78 static char *dfname; /* data files */
79 static char *fonts[4]; /* troff font names */
80 static char format = 'f'; /* format char for printing files */
81 static int hdr = 1; /* print header or not (default is yes) */
82 static int iflag; /* indentation wanted */
83 static int inchar; /* location to increment char in file names */
84 static int indent; /* amount to indent */
85 static const char *jobname; /* job name on header page */
86 static int mailflg; /* send mail */
87 static int nact; /* number of jobs to act on */
88 static int ncopies = 1; /* # of copies to make */
89 static char *lpr_username; /* person sending the print job(s) */
90 static int qflag; /* q job, but don't exec daemon */
91 static int rflag; /* remove files upon completion */
92 static int sflag; /* symbolic link flag */
93 static int tfd; /* control file descriptor */
94 static char *tfname; /* tmp copy of cf before linking */
95 static char *title; /* pr'ing title */
96 static char *locale; /* pr'ing locale */
97 static int userid; /* user id */
98 static char *Uflag; /* user name specified with -U flag */
99 static char *width; /* width for versatec printing */
100 static char *Zflag; /* extra filter options for LPRng servers */
102 static struct stat statb;
104 static void card(int _c, const char *_p2);
105 static int checkwriteperm(const char *_file, const char *_directory);
106 static void chkprinter(const char *_ptrname, struct printer *_pp);
107 static void cleanup(int _signo);
108 static void copy(const struct printer *_pp, int _f, const char _n[]);
109 static char *itoa(int _i);
110 static const char *linked(const char *_file);
111 int main(int _argc, char *_argv[]);
112 static char *lmktemp(const struct printer *_pp, const char *_id,
113 int _num, int len);
114 static void mktemps(const struct printer *_pp);
115 static int nfile(char *_n);
116 static int test(const char *_file);
117 static void usage(void);
119 uid_t uid, euid;
122 main(int argc, char *argv[])
124 struct passwd *pw;
125 struct group *gptr;
126 const char *arg, *cp, *printer;
127 char *p;
128 char buf[BUFSIZ];
129 int c, i, f, errs;
130 int ret, didlink;
131 struct stat stb;
132 struct stat statb1, statb2;
133 struct printer myprinter, *pp = &myprinter;
135 printer = NULL;
136 euid = geteuid();
137 uid = getuid();
138 seteuid(uid);
139 if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
140 signal(SIGHUP, cleanup);
141 if (signal(SIGINT, SIG_IGN) != SIG_IGN)
142 signal(SIGINT, cleanup);
143 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
144 signal(SIGQUIT, cleanup);
145 if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
146 signal(SIGTERM, cleanup);
148 progname = argv[0];
149 gethostname(local_host, sizeof(local_host));
150 openlog("lpd", 0, LOG_LPR);
152 errs = 0;
153 while ((c = getopt(argc, argv,
154 ":#:1:2:3:4:C:J:L:P:T:U:Z:cdfghi:lnmprstvw:"))
155 != -1)
156 switch (c) {
157 case '#': /* n copies */
158 i = strtol(optarg, &p, 10);
159 if (*p)
160 errx(1, "Bad argument to -#, number expected");
161 if (i > 0)
162 ncopies = i;
163 break;
165 case '1': /* troff fonts */
166 case '2':
167 case '3':
168 case '4':
169 fonts[optopt - '1'] = optarg;
170 break;
172 case 'C': /* classification spec */
173 hdr++;
174 class = optarg;
175 break;
177 case 'J': /* job name */
178 hdr++;
179 jobname = optarg;
180 break;
182 case 'P': /* specifiy printer name */
183 printer = optarg;
184 break;
186 case 'L': /* pr's locale */
187 locale = optarg;
188 break;
190 case 'T': /* pr's title line */
191 title = optarg;
192 break;
194 case 'U': /* user name */
195 hdr++;
196 Uflag = optarg;
197 break;
199 case 'Z':
200 Zflag = optarg;
201 break;
203 case 'c': /* print cifplot output */
204 case 'd': /* print tex output (dvi files) */
205 case 'g': /* print graph(1G) output */
206 case 'l': /* literal output */
207 case 'n': /* print ditroff output */
208 case 't': /* print troff output (cat files) */
209 case 'p': /* print using ``pr'' */
210 case 'v': /* print vplot output */
211 format = optopt;
212 break;
214 case 'f': /* print fortran output */
215 format = 'r';
216 break;
218 case 'h': /* nulifiy header page */
219 hdr = 0;
220 break;
222 case 'i': /* indent output */
223 iflag++;
224 indent = strtol(optarg, &p, 10);
225 if (*p)
226 errx(1, "Bad argument to -i, number expected");
227 break;
229 case 'm': /* send mail when done */
230 mailflg++;
231 break;
233 case 'q': /* just queue job */
234 qflag++;
235 break;
237 case 'r': /* remove file when done */
238 rflag++;
239 break;
241 case 's': /* try to link files */
242 sflag++;
243 break;
245 case 'w': /* versatec page width */
246 width = optarg;
247 break;
249 case ':': /* catch "missing argument" error */
250 if (optopt == 'i') {
251 iflag++; /* -i without args is valid */
252 indent = 8;
253 } else
254 errs++;
255 break;
257 default:
258 errs++;
260 argc -= optind;
261 argv += optind;
262 if (errs)
263 usage();
264 if (printer == NULL && (printer = getenv("PRINTER")) == NULL)
265 printer = DEFLP;
266 chkprinter(printer, pp);
267 if (pp->no_copies && ncopies > 1)
268 errx(1, "multiple copies are not allowed");
269 if (pp->max_copies > 0 && ncopies > pp->max_copies)
270 errx(1, "only %ld copies are allowed", pp->max_copies);
272 * Get the identity of the person doing the lpr using the same
273 * algorithm as lprm. Actually, not quite -- lprm will override
274 * the login name with "root" if the user is running as root;
275 * the daemon actually checks for the string "root" in its
276 * permission checking. Sigh.
278 userid = getuid();
279 if (Uflag) {
280 if (userid != 0 && userid != pp->daemon_user)
281 errx(1, "only privileged users may use the `-U' flag");
282 lpr_username = Uflag; /* -U person doing 'lpr' */
283 } else {
284 lpr_username = getlogin(); /* person doing 'lpr' */
285 if (userid != pp->daemon_user || lpr_username == 0) {
286 if ((pw = getpwuid(userid)) == NULL)
287 errx(1, "Who are you?");
288 lpr_username = pw->pw_name;
293 * Check for restricted group access.
295 if (pp->restrict_grp != NULL && userid != pp->daemon_user) {
296 if ((gptr = getgrnam(pp->restrict_grp)) == NULL)
297 errx(1, "Restricted group specified incorrectly");
298 if (gptr->gr_gid != getgid()) {
299 while (*gptr->gr_mem != NULL) {
300 if ((strcmp(lpr_username, *gptr->gr_mem)) == 0)
301 break;
302 gptr->gr_mem++;
304 if (*gptr->gr_mem == NULL)
305 errx(1, "Not a member of the restricted group");
309 * Check to make sure queuing is enabled if userid is not root.
311 lock_file_name(pp, buf, sizeof buf);
312 if (userid && stat(buf, &stb) == 0 && (stb.st_mode & LFM_QUEUE_DIS))
313 errx(1, "Printer queue is disabled");
315 * Initialize the control file.
317 mktemps(pp);
318 tfd = nfile(tfname);
319 seteuid(euid);
320 fchown(tfd, pp->daemon_user, -1);
321 /* owned by daemon for protection */
322 seteuid(uid);
323 card('H', local_host);
324 card('P', lpr_username);
325 card('C', class);
326 if (hdr && !pp->no_header) {
327 if (jobname == NULL) {
328 if (argc == 0)
329 jobname = "stdin";
330 else
331 jobname = ((arg = strrchr(argv[0], '/'))
332 ? arg + 1 : argv[0]);
334 card('J', jobname);
335 card('L', lpr_username);
337 if (format != 'p' && Zflag != 0)
338 card('Z', Zflag);
339 if (iflag)
340 card('I', itoa(indent));
341 if (mailflg)
342 card('M', lpr_username);
343 if (format == 't' || format == 'n' || format == 'd')
344 for (i = 0; i < 4; i++)
345 if (fonts[i] != NULL)
346 card('1'+i, fonts[i]);
347 if (width != NULL)
348 card('W', width);
350 * XXX
351 * Our use of `Z' here is incompatible with LPRng's
352 * use. We assume that the only use of our existing
353 * `Z' card is as shown for `p' format (pr) files.
355 if (format == 'p') {
356 char *s;
358 if (locale)
359 card('Z', locale);
360 else if ((s = setlocale(LC_TIME, "")) != NULL)
361 card('Z', s);
365 * Read the files and spool them.
367 if (argc == 0)
368 copy(pp, 0, " ");
369 else while (argc--) {
370 if (argv[0][0] == '-' && argv[0][1] == '\0') {
371 /* use stdin */
372 copy(pp, 0, " ");
373 argv++;
374 continue;
376 if ((f = test(arg = *argv++)) < 0)
377 continue; /* file unreasonable */
379 if (sflag && (cp = linked(arg)) != NULL) {
380 snprintf(buf, sizeof(buf), "%d %"PRId64, statb.st_dev,
381 (uint64_t)statb.st_ino);
382 card('S', buf);
383 if (format == 'p')
384 card('T', title ? title : arg);
385 for (i = 0; i < ncopies; i++)
386 card(format, &dfname[inchar-2]);
387 card('U', &dfname[inchar-2]);
388 if (f)
389 card('U', cp);
390 card('N', arg);
391 dfname[inchar]++;
392 nact++;
393 continue;
395 if (sflag)
396 printf("%s: %s: not linked, copying instead\n",
397 progname, arg);
399 if (f) {
401 * The user wants the file removed after it is copied
402 * to the spool area, so see if the file can be moved
403 * instead of copy/unlink'ed. This is much faster and
404 * uses less spool space than copying the file. This
405 * can be very significant when running services like
406 * samba, pcnfs, CAP, et al.
408 seteuid(euid);
409 didlink = 0;
411 * There are several things to check to avoid any
412 * security issues. Some of these are redundant
413 * under BSD's, but are necessary when lpr is built
414 * under some other OS's (which I do do...)
416 if (lstat(arg, &statb1) < 0)
417 goto nohardlink;
418 if (S_ISLNK(statb1.st_mode))
419 goto nohardlink;
420 if (link(arg, dfname) != 0)
421 goto nohardlink;
422 didlink = 1;
424 * Make sure the user hasn't tried to trick us via
425 * any race conditions
427 if (lstat(dfname, &statb2) < 0)
428 goto nohardlink;
429 if (statb1.st_dev != statb2.st_dev)
430 goto nohardlink;
431 if (statb1.st_ino != statb2.st_ino)
432 goto nohardlink;
434 * Skip if the file already had multiple hard links,
435 * because changing the owner and access-bits would
436 * change ALL versions of the file
438 if (statb2.st_nlink > 2)
439 goto nohardlink;
441 * If we can access and remove the original file
442 * without special setuid-ness then this method is
443 * safe. Otherwise, abandon the move and fall back
444 * to the (usual) copy method.
446 seteuid(uid);
447 ret = access(dfname, R_OK);
448 if (ret == 0)
449 ret = unlink(arg);
450 seteuid(euid);
451 if (ret != 0)
452 goto nohardlink;
454 * Unlink of user file was successful. Change the
455 * owner and permissions, add entries to the control
456 * file, and skip the file copying step.
458 chown(dfname, pp->daemon_user, getegid());
459 chmod(dfname, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
460 seteuid(uid);
461 if (format == 'p')
462 card('T', title ? title : arg);
463 for (i = 0; i < ncopies; i++)
464 card(format, &dfname[inchar-2]);
465 card('U', &dfname[inchar-2]);
466 card('N', arg);
467 nact++;
468 continue;
469 nohardlink:
470 if (didlink)
471 unlink(dfname);
472 seteuid(uid); /* restore old uid */
473 } /* end: if (f) */
475 if ((i = open(arg, O_RDONLY)) < 0) {
476 printf("%s: cannot open %s\n", progname, arg);
477 } else {
478 copy(pp, i, arg);
479 close(i);
480 if (f && unlink(arg) < 0)
481 printf("%s: %s: not removed\n", progname, arg);
485 if (nact) {
486 close(tfd);
487 tfname[inchar]--;
489 * Touch the control file to fix position in the queue.
491 seteuid(euid);
492 if ((tfd = open(tfname, O_RDWR)) >= 0) {
493 char touch_c;
495 if (read(tfd, &touch_c, 1) == 1 &&
496 lseek(tfd, (off_t)0, 0) == 0 &&
497 write(tfd, &touch_c, 1) != 1) {
498 printf("%s: cannot touch %s\n", progname,
499 tfname);
500 tfname[inchar]++;
501 cleanup(0);
503 close(tfd);
505 if (link(tfname, cfname) < 0) {
506 printf("%s: cannot rename %s\n", progname, cfname);
507 tfname[inchar]++;
508 cleanup(0);
510 unlink(tfname);
511 seteuid(uid);
512 if (qflag) /* just q things up */
513 exit(0);
514 if (!startdaemon(pp))
515 printf("jobs queued, but cannot start daemon.\n");
516 exit(0);
518 cleanup(0);
519 return (1);
520 /* NOTREACHED */
524 * Create the file n and copy from file descriptor f.
526 static void
527 copy(const struct printer *pp, int f, const char n[])
529 int fd, i, nr, nc;
530 char buf[BUFSIZ];
532 if (format == 'p')
533 card('T', title ? title : n);
534 for (i = 0; i < ncopies; i++)
535 card(format, &dfname[inchar-2]);
536 card('U', &dfname[inchar-2]);
537 card('N', n);
538 fd = nfile(dfname);
539 nr = nc = 0;
540 while ((i = read(f, buf, BUFSIZ)) > 0) {
541 if (write(fd, buf, i) != i) {
542 printf("%s: %s: temp file write error\n", progname, n);
543 break;
545 nc += i;
546 if (nc >= BUFSIZ) {
547 nc -= BUFSIZ;
548 nr++;
549 if (pp->max_blocks > 0 && nr > pp->max_blocks) {
550 printf("%s: %s: copy file is too large\n",
551 progname, n);
552 break;
556 close(fd);
557 if (nc==0 && nr==0)
558 printf("%s: %s: empty input file\n", progname,
559 f ? n : "stdin");
560 else
561 nact++;
565 * Try and link the file to dfname. Return a pointer to the full
566 * path name if successful.
568 static const char *
569 linked(const char *file)
571 char *cp;
572 static char buf[MAXPATHLEN];
573 int ret;
575 if (*file != '/') {
576 if (getcwd(buf, sizeof(buf)) == NULL)
577 return(NULL);
578 while (file[0] == '.') {
579 switch (file[1]) {
580 case '/':
581 file += 2;
582 continue;
583 case '.':
584 if (file[2] == '/') {
585 if ((cp = strrchr(buf, '/')) != NULL)
586 *cp = '\0';
587 file += 3;
588 continue;
591 break;
593 strncat(buf, "/", sizeof(buf) - strlen(buf) - 1);
594 strncat(buf, file, sizeof(buf) - strlen(buf) - 1);
595 file = buf;
597 seteuid(euid);
598 ret = symlink(file, dfname);
599 seteuid(uid);
600 return(ret ? NULL : file);
604 * Put a line into the control file.
606 static void
607 card(int c, const char *p2)
609 char buf[BUFSIZ];
610 char *p1 = buf;
611 size_t len = 2;
613 *p1++ = c;
614 while ((c = *p2++) != '\0' && len < sizeof(buf)) {
615 *p1++ = (c == '\n') ? ' ' : c;
616 len++;
618 *p1++ = '\n';
619 write(tfd, buf, len);
623 * Create a new file in the spool directory.
625 static int
626 nfile(char *n)
628 int f;
629 int oldumask = umask(0); /* should block signals */
631 seteuid(euid);
632 f = open(n, O_WRONLY | O_EXCL | O_CREAT, FILMOD);
633 umask(oldumask);
634 if (f < 0) {
635 printf("%s: cannot create %s\n", progname, n);
636 cleanup(0);
638 if (fchown(f, userid, -1) < 0) {
639 printf("%s: cannot chown %s\n", progname, n);
640 cleanup(0); /* cleanup does exit */
642 seteuid(uid);
643 if (++n[inchar] > 'z') {
644 if (++n[inchar-2] == 't') {
645 printf("too many files - break up the job\n");
646 cleanup(0);
648 n[inchar] = 'A';
649 } else if (n[inchar] == '[')
650 n[inchar] = 'a';
651 return(f);
655 * Cleanup after interrupts and errors.
657 static void
658 cleanup(int signo __unused)
660 int i;
662 signal(SIGHUP, SIG_IGN);
663 signal(SIGINT, SIG_IGN);
664 signal(SIGQUIT, SIG_IGN);
665 signal(SIGTERM, SIG_IGN);
666 i = inchar;
667 seteuid(euid);
668 if (tfname)
670 unlink(tfname);
671 while (tfname[i]-- != 'A');
672 if (cfname)
674 unlink(cfname);
675 while (cfname[i]-- != 'A');
676 if (dfname)
677 do {
679 unlink(dfname);
680 while (dfname[i]-- != 'A');
681 dfname[i] = 'z';
682 } while (dfname[i-2]-- != 'd');
683 exit(1);
687 * Test to see if this is a printable file.
688 * Return -1 if it is not, 0 if its printable, and 1 if
689 * we should remove it after printing.
691 static int
692 test(const char *file)
694 struct exec execb;
695 size_t dlen;
696 int fd;
697 char *cp, *dirpath;
699 if (access(file, 4) < 0) {
700 printf("%s: cannot access %s\n", progname, file);
701 return(-1);
703 if (stat(file, &statb) < 0) {
704 printf("%s: cannot stat %s\n", progname, file);
705 return(-1);
707 if ((statb.st_mode & S_IFMT) == S_IFDIR) {
708 printf("%s: %s is a directory\n", progname, file);
709 return(-1);
711 if (statb.st_size == 0) {
712 printf("%s: %s is an empty file\n", progname, file);
713 return(-1);
715 if ((fd = open(file, O_RDONLY)) < 0) {
716 printf("%s: cannot open %s\n", progname, file);
717 return(-1);
720 * XXX Shall we add a similar test for ELF?
722 if (read(fd, &execb, sizeof(execb)) == sizeof(execb) &&
723 !N_BADMAG(execb)) {
724 printf("%s: %s is an executable program", progname, file);
725 goto error1;
727 close(fd);
728 if (rflag) {
730 * aside: note that 'cp' is technically a 'const char *'
731 * (because it points into 'file'), even though strrchr
732 * returns a value of type 'char *'.
734 if ((cp = strrchr(file, '/')) == NULL) {
735 if (checkwriteperm(file,".") == 0)
736 return(1);
737 } else {
738 if (cp == file) {
739 fd = checkwriteperm(file,"/");
740 } else {
741 /* strlcpy will change the '/' to '\0' */
742 dlen = cp - file + 1;
743 dirpath = malloc(dlen);
744 strlcpy(dirpath, file, dlen);
745 fd = checkwriteperm(file, dirpath);
746 free(dirpath);
748 if (fd == 0)
749 return(1);
751 printf("%s: %s: is not removable by you\n", progname, file);
753 return(0);
755 error1:
756 printf(" and is unprintable\n");
757 close(fd);
758 return(-1);
761 static int
762 checkwriteperm(const char *file, const char *directory)
764 struct stat stats;
765 if (access(directory, W_OK) == 0) {
766 stat(directory, &stats);
767 if (stats.st_mode & S_ISVTX) {
768 stat(file, &stats);
769 if(stats.st_uid == userid) {
770 return(0);
772 } else return(0);
774 return(-1);
778 * itoa - integer to string conversion
780 static char *
781 itoa(int i)
783 static char b[10] = "########";
784 char *p;
786 p = &b[8];
788 *p-- = i%10 + '0';
789 while (i /= 10);
790 return(++p);
794 * Perform lookup for printer name or abbreviation --
796 static void
797 chkprinter(const char *ptrname, struct printer *pp)
799 int status;
801 init_printer(pp);
802 status = getprintcap(ptrname, pp);
803 switch(status) {
804 case PCAPERR_OSERR:
805 case PCAPERR_TCLOOP:
806 errx(1, "%s: %s", ptrname, pcaperr(status));
807 case PCAPERR_NOTFOUND:
808 errx(1, "%s: unknown printer", ptrname);
809 case PCAPERR_TCOPEN:
810 warnx("%s: unresolved tc= reference(s)", ptrname);
815 * Tell the user what we wanna get.
817 static void
818 usage(void)
820 fprintf(stderr, "%s\n",
821 "usage: lpr [-Pprinter] [-#num] [-C class] [-J job] [-T title] [-U user]\n"
822 "\t[-Z daemon-options] [-i[numcols]] [-i[numcols]] [-1234 font]\n"
823 "\t[-L locale] [-wnum] [-cdfghlnmprstv] [name ...]");
824 exit(1);
829 * Make the temp files.
831 static void
832 mktemps(const struct printer *pp)
834 int len, fd, n;
835 char *cp;
836 char buf[BUFSIZ];
838 snprintf(buf, sizeof(buf), "%s/.seq", pp->spool_dir);
839 seteuid(euid);
840 if ((fd = open(buf, O_RDWR|O_CREAT, 0661)) < 0) {
841 printf("%s: cannot create %s\n", progname, buf);
842 exit(1);
844 if (flock(fd, LOCK_EX)) {
845 printf("%s: cannot lock %s\n", progname, buf);
846 exit(1);
848 seteuid(uid);
849 n = 0;
850 if ((len = read(fd, buf, sizeof(buf))) > 0) {
851 for (cp = buf; len--; ) {
852 if (*cp < '0' || *cp > '9')
853 break;
854 n = n * 10 + (*cp++ - '0');
857 len = strlen(pp->spool_dir) + strlen(local_host) + 8;
858 tfname = lmktemp(pp, "tf", n, len);
859 cfname = lmktemp(pp, "cf", n, len);
860 dfname = lmktemp(pp, "df", n, len);
861 inchar = strlen(pp->spool_dir) + 3;
862 n = (n + 1) % 1000;
863 lseek(fd, (off_t)0, 0);
864 snprintf(buf, sizeof(buf), "%03d\n", n);
865 write(fd, buf, strlen(buf));
866 close(fd); /* unlocks as well */
870 * Make a temp file name.
872 static char *
873 lmktemp(const struct printer *pp, const char *id, int num, int len)
875 char *s;
877 if ((s = malloc(len)) == NULL)
878 errx(1, "out of memory");
879 snprintf(s, len, "%s/%sA%03d%s", pp->spool_dir, id, num, local_host);
880 return(s);