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