|
|
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.