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