diff options
Diffstat (limited to 'usr.sbin/lpr/lpd/lpd.c')
-rw-r--r-- | usr.sbin/lpr/lpd/lpd.c | 202 |
1 files changed, 110 insertions, 92 deletions
diff --git a/usr.sbin/lpr/lpd/lpd.c b/usr.sbin/lpr/lpd/lpd.c index e62e6bf..50ee865 100644 --- a/usr.sbin/lpr/lpd/lpd.c +++ b/usr.sbin/lpr/lpd/lpd.c @@ -43,7 +43,7 @@ static const char copyright[] = static char sccsid[] = "@(#)lpd.c 8.7 (Berkeley) 5/10/95"; #endif static const char rcsid[] = - "$Id$"; + "$Id: lpd.c,v 1.8 1997/09/24 06:47:54 charnier Exp $"; #endif /* not lint */ /* @@ -111,8 +111,11 @@ static void mcleanup __P((int)); static void doit __P((void)); static void startup __P((void)); static void chkhost __P((struct sockaddr_in *)); -static int ckqueue __P((char *)); +static int ckqueue __P((struct printer *)); static void usage __P((void)); +/* From rcmd.c: */ +int __ivaliduser __P((FILE *, u_long, const char *, + const char *)); uid_t uid, euid; @@ -125,7 +128,8 @@ main(argc, argv) fd_set defreadfds; struct sockaddr_un un, fromunix; struct sockaddr_in sin, frominet; - int omask, lfd; + int lfd; + sigset_t omask, nmask; struct servent *sp, serv; euid = geteuid(); /* these shouldn't be different */ @@ -173,6 +177,31 @@ main(argc, argv) if (argc != 0) usage(); + /* + * We run chkprintcap right away to catch any errors and blat them + * to stderr while we still have it open, rather than sending them + * to syslog and leaving the user wondering why lpd started and + * then stopped. There should probably be a command-line flag to + * ignore errors from chkprintcap. + */ + { + pid_t pid; + int status; + pid = fork(); + if (pid < 0) { + err(EX_OSERR, "cannot fork"); + } else if (pid == 0) { /* child */ + execl(_PATH_CHKPRINTCAP, _PATH_CHKPRINTCAP, (char *)0); + err(EX_OSERR, "cannot execute %s", _PATH_CHKPRINTCAP); + } + if (waitpid(pid, &status, 0) < 0) { + err(EX_OSERR, "cannot wait"); + } + if (WIFEXITED(status) && WEXITSTATUS(status) != 0) + errx(EX_OSFILE, "%d errors in printcap file, exiting", + WEXITSTATUS(status)); + } + #ifndef DEBUG /* * Set up standard environment by detaching from the parent. @@ -183,17 +212,22 @@ main(argc, argv) openlog("lpd", LOG_PID, LOG_LPR); syslog(LOG_INFO, "restarted"); (void) umask(0); - lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT, 0644); + /* + * NB: This depends on O_NONBLOCK semantics doing the right thing; + * i.e., applying only to the O_EXLOCK and not to the rest of the + * open/creation. As of 1997-12-02, this is the case for commonly- + * used filesystems. There are other places in this code which + * make the same assumption. + */ + lfd = open(_PATH_MASTERLOCK, O_WRONLY|O_CREAT|O_EXLOCK|O_NONBLOCK, + LOCK_FILE_MODE); if (lfd < 0) { - syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); - exit(1); - } - if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { if (errno == EWOULDBLOCK) /* active deamon present */ exit(0); syslog(LOG_ERR, "%s: %m", _PATH_MASTERLOCK); exit(1); } + fcntl(lfd, F_SETFL, 0); /* turn off non-blocking mode */ ftruncate(lfd, 0); /* * write process id for others to know @@ -215,8 +249,14 @@ main(argc, argv) syslog(LOG_ERR, "socket: %m"); exit(1); } -#define mask(s) (1 << ((s) - 1)) - omask = sigblock(mask(SIGHUP)|mask(SIGINT)|mask(SIGQUIT)|mask(SIGTERM)); + + sigemptyset(&nmask); + sigaddset(&nmask, SIGHUP); + sigaddset(&nmask, SIGINT); + sigaddset(&nmask, SIGQUIT); + sigaddset(&nmask, SIGTERM); + sigprocmask(SIG_BLOCK, &nmask, &omask); + (void) umask(07); signal(SIGHUP, mcleanup); signal(SIGINT, mcleanup); @@ -233,7 +273,7 @@ main(argc, argv) exit(1); } (void) umask(0); - sigsetmask(omask); + sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); FD_ZERO(&defreadfds); FD_SET(funix, &defreadfds); listen(funix, 5); @@ -259,6 +299,9 @@ main(argc, argv) */ memset(&frominet, 0, sizeof(frominet)); memset(&fromunix, 0, sizeof(fromunix)); + /* + * XXX - should be redone for multi-protocol + */ for (;;) { int domain, nfds, s; fd_set readfds; @@ -353,17 +396,21 @@ char *cmdnames[] = { static void doit() { - register char *cp; - register int n; + char *cp, *printer; + int n; + int status; + struct printer myprinter, *pp = &myprinter; + + init_printer(&myprinter); for (;;) { cp = cbuf; do { if (cp >= &cbuf[sizeof(cbuf) - 1]) - fatal("Command line too long"); + fatal(0, "Command line too long"); if ((n = read(1, cp, 1)) != 1) { if (n < 0) - fatal("Lost connection"); + fatal(0, "Lost connection"); return; } } while (*cp++ != '\n'); @@ -372,26 +419,25 @@ doit() if (lflag) { if (*cp >= '\1' && *cp <= '\5') syslog(LOG_INFO, "%s requests %s %s", - from, cmdnames[*cp], cp+1); + from, cmdnames[(u_char)*cp], cp+1); else syslog(LOG_INFO, "bad request (%d) from %s", *cp, from); } switch (*cp++) { - case '\1': /* check the queue and print any jobs there */ - printer = cp; - printjob(); + case CMD_CHECK_QUE: /* check the queue, print any jobs there */ + startprinting(cp); break; - case '\2': /* receive files to be queued */ + case CMD_TAKE_THIS: /* receive files to be queued */ if (!from_remote) { syslog(LOG_INFO, "illegal request (%d)", *cp); exit(1); } - printer = cp; - recvjob(); + recvjob(cp); break; - case '\3': /* display the queue (short form) */ - case '\4': /* display the queue (long form) */ + case CMD_SHOWQ_SHORT: /* display the queue (short form) */ + case CMD_SHOWQ_LONG: /* display the queue (long form) */ + /* XXX - this all needs to be redone. */ printer = cp; while (*cp) { if (*cp != ' ') { @@ -405,17 +451,20 @@ doit() break; if (isdigit(*cp)) { if (requests >= MAXREQUESTS) - fatal("Too many requests"); + fatal(0, "Too many requests"); requ[requests++] = atoi(cp); } else { if (users >= MAXUSERS) - fatal("Too many users"); + fatal(0, "Too many users"); user[users++] = cp; } } - displayq(cbuf[0] - '\3'); + status = getprintcap(printer, pp); + if (status < 0) + fatal(pp, pcaperr(status)); + displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); exit(0); - case '\5': /* remove a job from the queue */ + case CMD_RMJOB: /* remove a job from the queue */ if (!from_remote) { syslog(LOG_INFO, "illegal request (%d)", *cp); exit(1); @@ -439,18 +488,18 @@ doit() break; if (isdigit(*cp)) { if (requests >= MAXREQUESTS) - fatal("Too many requests"); + fatal(0, "Too many requests"); requ[requests++] = atoi(cp); } else { if (users >= MAXUSERS) - fatal("Too many users"); + fatal(0, "Too many users"); user[users++] = cp; } } - rmjob(); + rmjob(printer); break; } - fatal("Illegal service request"); + fatal(0, "Illegal service request"); } } @@ -461,66 +510,36 @@ doit() static void startup() { - char *buf; - register char *cp; - int pid; - char *spooldirs[16]; /* Which spooldirs are active? */ - int i; /* Printer index presently processed */ - int j; /* Printer index of potential conflict */ - char *spooldir; /* Spooldir of present printer */ - int canfreespool; /* Is the spooldir malloc()ed? */ - - /* - * Restart the daemons and test for spooldir conflict. - */ - i = 0; - while (cgetnext(&buf, printcapdb) > 0) { - - /* Check for duplicate spooldirs */ - canfreespool = 1; - if (cgetstr(buf, "sd", &spooldir) <= 0) { - spooldir = _PATH_DEFSPOOL; - canfreespool = 0; + int pid, status, more; + struct printer myprinter, *pp = &myprinter; + + more = firstprinter(pp, &status); + if (status) + goto errloop; + while (more) { + if (ckqueue(pp) <= 0) { + goto next; } - if (i < sizeof(spooldirs)/sizeof(spooldirs[0])) - spooldirs[i] = spooldir; - for (j = 0; - j < MIN(i,sizeof(spooldirs)/sizeof(spooldirs[0])); - j++) { - if (strcmp(spooldir, spooldirs[j]) == 0) { - syslog(LOG_ERR, - "startup: duplicate spool directories: %s", - spooldir); - mcleanup(0); - } - } - if (canfreespool && i >= sizeof(spooldirs)/sizeof(spooldirs[0])) - free(spooldir); - i++; - /* Spooldir test done */ - - if (ckqueue(buf) <= 0) { - free(buf); - continue; /* no work to do for this printer */ - } - for (cp = buf; *cp; cp++) - if (*cp == '|' || *cp == ':') { - *cp = '\0'; - break; - } if (lflag) - syslog(LOG_INFO, "work for %s", buf); + syslog(LOG_INFO, "work for %s", pp->printer); if ((pid = fork()) < 0) { syslog(LOG_WARNING, "startup: cannot fork"); mcleanup(0); } - if (!pid) { - printer = buf; - cgetclose(); - printjob(); + if (pid == 0) { + lastprinter(); + printjob(pp); /* NOTREACHED */ } - else free(buf); + do { +next: + more = nextprinter(pp, &status); +errloop: + if (status) + syslog(LOG_WARNING, + "printcap for %s has errors, skipping", + pp->printer ? pp->printer : "<???>"); + } while (more && status); } } @@ -528,15 +547,14 @@ startup() * Make sure there's some work to do before forking off a child */ static int -ckqueue(cap) - char *cap; +ckqueue(pp) + struct printer *pp; { register struct dirent *d; DIR *dirp; char *spooldir; - if (cgetstr(cap, "sd", &spooldir) == -1) - spooldir = _PATH_DEFSPOOL; + spooldir = pp->spool_dir; if ((dirp = opendir(spooldir)) == NULL) return (-1); while ((d = readdir(dirp)) != NULL) { @@ -567,7 +585,7 @@ chkhost(f) hp = gethostbyaddr((char *)&f->sin_addr, sizeof(struct in_addr), f->sin_family); if (hp == NULL) - fatal("Host name for your address (%s) unknown", + fatal(0, "Host name for your address (%s) unknown", inet_ntoa(f->sin_addr)); (void) strncpy(fromb, hp->h_name, sizeof(fromb) - 1); @@ -577,7 +595,7 @@ chkhost(f) /* Check for spoof, ala rlogind */ hp = gethostbyname(fromb); if (!hp) - fatal("hostname for your address (%s) unknown", + fatal(0, "hostname for your address (%s) unknown", inet_ntoa(f->sin_addr)); for (; good == 0 && hp->h_addr_list[0] != NULL; hp->h_addr_list++) { if (!bcmp(hp->h_addr_list[0], (caddr_t)&f->sin_addr, @@ -585,7 +603,7 @@ chkhost(f) good = 1; } if (good == 0) - fatal("address for your hostname (%s) not matched", + fatal(0, "address for your hostname (%s) not matched", inet_ntoa(f->sin_addr)); hostf = fopen(_PATH_HOSTSEQUIV, "r"); @@ -603,7 +621,7 @@ again: hostf = fopen(_PATH_HOSTSLPD, "r"); goto again; } - fatal("Your host does not have line printer access"); + fatal(0, "Your host does not have line printer access"); /*NOTREACHED*/ } |