|
|
1.1 root 1: /*
2: * The line printer spooler daemon.
3: * This should be invoked from the `/etc/rc'
4: * file and by the `lpr' command.
5: * (NOTE: this command should be setuid to daemon)
6: */
7:
8: #include <stdio.h>
9: #include <sys/dir.h>
10: #include <pwd.h>
11: #include <sgtty.h>
12: #include <signal.h>
13: #include <errno.h>
14:
15: #define DAEMON 1 /* Daemon's magic number */
16: #define BANWID 10 /* Longest banner */
17: #define MAXCOM 40 /* Longest comment line sent through mail */
18: #define FF 014 /* Form feed */
19: #define SMALL 037 /* Set small characters -- paper tiger */
20: #define NORMAL 036 /* Set normal characters -- paper tiger */
21:
22: #ifdef LASER
23: char spooldir[] = "/usr/spool/hpd";
24: char *printer = "/dev/hp";
25: #else
26: char spooldir[] = "/usr/spool/lpd";
27: char *printer = "/dev/lp";
28: #endif
29: char lockfile[] = "dpid";
30:
31: char *argv0;
32: char obuf[BUFSIZ];
33: char cfline[300]; /* Control file line */
34: char comment[300]; /* Comment line */
35: FILE *lp;
36: int printing; /* On while printing */
37:
38: char *lgets();
39: int cancel();
40: int restart();
41:
42: main(argc, argv)
43: char *argv[];
44: {
45: int fd;
46: int pid;
47:
48: argv0 = argv[0];
49: setuid(DAEMON);
50: if (chdir(spooldir) < 0)
51: lperr("spool directory botch");
52: if ((fd = creat(lockfile, 0400)) < 0)
53: exit(0);
54: if (fork())
55: exit(0);
56: signal(SIGINT, SIG_IGN);
57: signal(SIGHUP, SIG_IGN);
58: signal(SIGTRAP, cancel);
59: signal(SIGREST, restart);
60: pid = getpid();
61: write(fd, &pid, sizeof pid);
62: close(fd);
63: if (argc > 1)
64: printer = argv[1];
65: if ((lp = fopen(printer, "w")) == NULL)
66: lperr( "%s: %s", printer, sys_errlist[errno]);
67: ioctl(fileno(lp), TIOCEXCL, NULL);
68: setbuf(lp, obuf);
69: process();
70: rmexit(0);
71: }
72:
73: /*
74: * Find work to do.
75: * The basic algorithm is to
76: * run down the current directory
77: * looking for files whose names
78: * begin with `cf' and do the work
79: * associated with each of them.
80: */
81: process()
82: {
83: FILE *dirfile;
84: struct direct dir;
85: char *r = "r";
86:
87: if ((dirfile = fopen(".", r)) != NULL) {
88: while (fread(&dir, sizeof dir, 1, dirfile) == 1) {
89: if (dir.d_ino == 0
90: || dir.d_name[0] != 'c'
91: || dir.d_name[1] != 'f')
92: continue;
93: control(dir.d_name);
94: rewind(dirfile);
95: }
96: fclose(dirfile);
97: }
98: }
99:
100: /*
101: * Do the action specified by the control
102: * file. Essentially, this must interpret
103: * the control lines for such things as
104: * mail notification, banners, etc.
105: */
106: control(cfname)
107: register char *cfname;
108: {
109: FILE *cfp;
110: char mbuf[MAXCOM+40];
111: char *message = "%s: Listing complete: %.*s\n";
112: int state; /* 0 to suppress header, 1 before first banner, 2 after */
113:
114: if ((cfp = fopen(cfname, "r")) != NULL) {
115: again:
116: printing = state = 1;
117: while (lgets(cfline, sizeof cfline, cfp) != NULL) {
118: if (!printing)
119: message = "%s: Listing killed by order: %.*s\n";
120: else if (printing < 0) {
121: rewind(cfp);
122: putc(FF, lp);
123: goto again;
124: }
125: switch (cfline[0]) {
126: case 'A':
127: if (state)
128: putc(FF, lp); /* FF after banner */
129: if (print(cfline+1)) {
130: message = "%s: Printer file error: %.*s\n";
131: strcpy(comment, cfline+1);
132: }
133: putc(FF, lp); /* FF after file */
134: break;
135:
136: case 'B':
137: state = 0; /* suppress header */
138: break;
139:
140: case 'D':
141: strcpy(comment, cfline+1);
142: break;
143:
144: case 'L':
145: if (state == 0)
146: break;
147: if (state == 1) {
148: state = 2;
149: fprintf(lp, "%s\n\n", cfname);
150: }
151: if (printing > 0) {
152: cfline[BANWID+1] = '\0';
153: /* Paper tiger controls
154: putc(SMALL, lp);
155: */
156: banner(cfline+1, lp);
157: /* Paper tiger controls
158: putc(NORMAL, lp);
159: */
160: }
161: break;
162:
163: case 'M':
164: sprintf(mbuf, message, argv0, MAXCOM, comment);
165: notify(cfline+1, mbuf);
166: break;
167:
168: case 'R':
169: /* Charge ID -- not used */
170: break;
171:
172: case 'U':
173: unlink(cfline+1);
174: break;
175:
176: default:
177: lperr("Bad control line `%s'", cfline);
178: }
179: }
180: fclose(cfp);
181: printing = 0;
182: }
183: unlink(cfname);
184: }
185:
186: /*
187: * Routine to notify a user about
188: * the completion of a transaction
189: * Usually called by some daemon (e.g.
190: * line printer daemon).
191: * Return non-zero on failure.
192: */
193: notify(name, msg)
194: char *name;
195: char *msg;
196: {
197: register struct passwd *pwp;
198: int pfd[2];
199: register int pid, fd;
200: int status;
201:
202: if (*name>='0' && *name<='9')
203: if ((pwp = getpwuid(atoi(name))) == NULL)
204: name = NULL; else
205: name = pwp->pw_name;
206: if (name==NULL || pipe(pfd)<0 || (pid = fork())<0)
207: return (1);
208: if (pid) {
209: close(pfd[0]);
210: write(pfd[1], msg, strlen(msg));
211: close(pfd[1]);
212: while (wait(&status) >= 0)
213: ;
214: } else {
215: close(pfd[1]);
216: dup2(pfd[0], 0);
217: close(pfd[0]);
218: for (fd=3; fd<_NFILE; fd++)
219: close(fd);
220: execlp("/bin/mail", "mail", name, NULL);
221: return (1);
222: }
223: return (0);
224: }
225:
226: /*
227: * Cancel the listing that is printing
228: * just now.
229: */
230: cancel()
231: {
232: signal(SIGTRAP, SIG_IGN);
233: if (printing) {
234: printing = 0;
235: fprintf(lp, "\n\n\nListing cancelled by order\n");
236: }
237: signal(SIGTRAP, cancel);
238: }
239:
240: /*
241: * Restart the listing that
242: * is running just now.
243: */
244: restart()
245: {
246: signal(SIGREST, SIG_IGN);
247: if (printing) {
248: printing = -1;
249: fprintf(lp, "\n\n\nListing restarted by order\n");
250: }
251: signal(SIGREST, restart);
252: }
253:
254: /*
255: * Like fgets but no newline is put at the end
256: * of the string. Also the rest of an input
257: * line is flushed on truncated strings.
258: */
259: char *
260: lgets(as, lim, iop)
261: char *as;
262: register lim;
263: FILE *iop;
264: {
265: register c;
266: register char *s;
267:
268: s = as;
269: while (--lim > 0 && (c = getc(iop)) != EOF)
270: if ((*s++ = c) == '\n') {
271: s--;
272: break;
273: }
274: *s = 0;
275: if (lim==0 && c!='\n')
276: while ((c = getc(iop))!='\n' && c!=EOF)
277: ;
278: return (c==EOF && s==as ? NULL : as);
279: }
280:
281: /* VARARGS */
282: lperr(x)
283: {
284: fprintf(stderr, "%s: %r\n", argv0, &x);
285: rmexit(1);
286: }
287:
288: /*
289: * Remove lock file and exit.
290: */
291: rmexit(s)
292: {
293: unlink(lockfile);
294: if (lp != NULL)
295: fclose(lp);
296: exit(s);
297: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.