/* * Routine to get the information for a single printer (which will be * called by the routines which implement individual commands). * Note: This is for commands operating on a *single* printer. */ struct printer * setup_myprinter(char *pwanted, struct printer *pp, int sump_opts) { int cdres, cmdstatus; init_printer(pp); cmdstatus = getprintcap(pwanted, pp); switch (cmdstatus) { default: fatal(pp, "%s", pcaperr(cmdstatus)); /* NOTREACHED */ case PCAPERR_NOTFOUND: printf("unknown printer %s\n", pwanted); return (NULL); case PCAPERR_TCOPEN: printf("warning: %s: unresolved tc= reference(s)", pwanted); break; case PCAPERR_SUCCESS: break; } if ((sump_opts & SUMP_NOHEADER) == 0) printf("%s:\n", pp->printer); if (sump_opts & SUMP_CHDIR_SD) { PRIV_START cdres = chdir(pp->spool_dir); PRIV_END if (cdres < 0) { printf("\tcannot chdir to %s\n", pp->spool_dir); free_printer(pp); return (NULL); } }
/* * Perform lookup for printer name or abbreviation -- */ static int chkprinter(const char *ptrname) { int stat; struct printer myprinter, *pp = &myprinter; init_printer(&myprinter); stat = getprintcap(ptrname, pp); switch(stat) { case PCAPERR_OSERR: printf("pac: getprintcap: %s\n", pcaperr(stat)); exit(3); case PCAPERR_NOTFOUND: return 0; case PCAPERR_TCLOOP: fatal(pp, "%s", pcaperr(stat)); } if ((acctfile = pp->acct_file) == NULL) errx(3, "accounting not enabled for printer %s", ptrname); if (!pflag && pp->price100) price = pp->price100/10000.0; sumfile = (char *) calloc(sizeof(char), strlen(acctfile)+5); if (sumfile == NULL) errx(1, "calloc failed"); strcpy(sumfile, acctfile); strcat(sumfile, "_sum"); return(1); }
/* * Perform lookup for printer name or abbreviation -- */ static void chkprinter(const char *s) { char *cp; getprintcap(s); RG = cgetstr(bp, "rg", &cp) == -1 ? NULL : cp; if (cgetnum(bp, "mx", &MX) < 0) MX = DEFMX; if (cgetnum(bp,"mc", &MC) < 0) MC = DEFMAXCOPIES; if (cgetnum(bp, "du", &DU) < 0) DU = DEFUID; SC = (cgetcap(bp, "sc", ':') != NULL); }
/* * Perform lookup for printer name or abbreviation -- */ static void chkprinter(const char *ptrname, struct printer *pp) { int status; init_printer(pp); status = getprintcap(ptrname, pp); switch(status) { case PCAPERR_OSERR: case PCAPERR_TCLOOP: errx(1, "%s: %s", ptrname, pcaperr(status)); case PCAPERR_NOTFOUND: errx(1, "%s: unknown printer", ptrname); case PCAPERR_TCOPEN: warnx("%s: unresolved tc= reference(s)", ptrname); } }
void rmjob(const char *printer) { register int i, nitems; int assassinated = 0; struct dirent **files; char *cp; struct printer myprinter, *pp = &myprinter; init_printer(pp); if ((i = getprintcap(printer, pp)) < 0) fatal(pp, "getprintcap: %s", pcaperr(i)); if ((cp = checkremote(pp))) { printf("Warning: %s\n", cp); free(cp); } /* * If the format was `lprm -' and the user isn't the super-user, * then fake things to look like he said `lprm user'. */ if (users < 0) { if (getuid() == 0) all = 1; /* all files in local queue */ else { user[0] = person; users = 1; } } if (!strcmp(person, "-all")) { if (from_host == local_host) fatal(pp, "The login name \"-all\" is reserved"); all = 1; /* all those from 'from_host' */ person = root; } seteuid(euid); if (chdir(pp->spool_dir) < 0) fatal(pp, "cannot chdir to spool directory"); if ((nitems = scandir(".", &files, iscf, NULL)) < 0) fatal(pp, "cannot access spool directory"); seteuid(uid); if (nitems) { /* * Check for an active printer daemon (in which case we * kill it if it is reading our file) then remove stuff * (after which we have to restart the daemon). */ if (lockchk(pp, pp->lock_file) && chk(current)) { seteuid(euid); assassinated = kill(cur_daemon, SIGINT) == 0; seteuid(uid); if (!assassinated) fatal(pp, "cannot kill printer daemon"); } /* * process the files */ for (i = 0; i < nitems; i++) process(pp, files[i]->d_name); } rmremote(pp); /* * Restart the printer daemon if it was killed */ if (assassinated && !startdaemon(pp)) fatal(pp, "cannot restart printer daemon\n"); exit(0); }
int main(int argc, char **argv) { int ch, aflag, lflag; const char *printer; struct printer myprinter, *pp = &myprinter; printer = NULL; euid = geteuid(); uid = getuid(); seteuid(uid); progname = *argv; if (gethostname(local_host, sizeof(local_host))) err(1, "gethostname"); openlog("lpd", 0, LOG_LPR); aflag = lflag = 0; while ((ch = getopt(argc, argv, "alP:")) != -1) switch((char)ch) { case 'a': ++aflag; break; case 'l': /* long output */ ++lflag; break; case 'P': /* printer name */ printer = optarg; break; case '?': default: usage(); } if (!aflag && printer == NULL && (printer = getenv("PRINTER")) == NULL) printer = DEFLP; for (argc -= optind, argv += optind; argc; --argc, ++argv) if (isdigit(argv[0][0])) { if (requests >= MAXREQUESTS) fatal(0, "too many requests"); requ[requests++] = atoi(*argv); } else { if (users >= MAXUSERS) fatal(0, "too many users"); user[users++] = *argv; } if (aflag) { int more, status; more = firstprinter(pp, &status); if (status) goto looperr; while (more) { if (ckqueue(pp) > 0) { printf("%s:\n", pp->printer); displayq(pp, lflag); printf("\n"); } do { more = nextprinter(pp, &status); looperr: switch (status) { case PCAPERR_TCOPEN: printf("warning: %s: unresolved " "tc= reference(s) ", pp->printer); case PCAPERR_SUCCESS: break; default: fatal(pp, "%s", pcaperr(status)); } } while (more && status); } } else { int status; init_printer(pp); status = getprintcap(printer, pp); if (status < 0) fatal(pp, "%s", pcaperr(status)); displayq(pp, lflag); } exit(0); }
void generic(void (*specificrtn)(struct printer *_pp), int cmdopts, void (*initrtn)(int _argc, char *_argv[]), int argc, char *argv[]) { int cmdstatus, more, targc; struct printer myprinter, *pp; char **margv, **targv; if (argc == 1) { /* * Usage needs a special case for 'down': The user must * either include `-msg', or only the first parameter * that they give will be processed as a printer name. */ printf("usage: %s {all | printer ...}", argv[0]); if (strcmp(argv[0], "down") == 0) { printf(" -msg [<text> ...]\n"); printf(" or: down {all | printer} [<text> ...]"); } else if (cmdopts & LPC_MSGOPT) printf(" [-msg <text> ...]"); printf("\n"); return; } /* The first argument is the command name. */ generic_cmdname = *argv++; argc--; /* * The initialization routine for a command might set a generic * "wrapup" routine, which should be called after processing all * the printers in the command. This might print summary info. * * Note that the initialization routine may also parse (and * nullify) some of the parameters given on the command, leaving * only the parameters which have to do with printer names. */ pp = &myprinter; generic_wrapup = NULL; generic_qselect = QSEL_UNKNOWN; cmdstatus = 0; /* this just needs to be a distinct value of type 'char *' */ if (generic_nullarg == NULL) generic_nullarg = strdup(""); /* * Some commands accept a -msg argument, which indicates that * all remaining arguments should be combined into a string. */ generic_msg = NULL; if (cmdopts & LPC_MSGOPT) { targc = argc; targv = argv; for (; targc > 0; targc--, targv++) { if (strcmp(*targv, "-msg") == 0) { argc -= targc; generic_msg = args2line(targc - 1, targv + 1); break; } } } /* call initialization routine, if there is one for this cmd */ if (initrtn != NULL) { generic_initerr = 0; (*initrtn)(argc, argv); if (generic_initerr) return; /* * The initrtn may have null'ed out some of the parameters. * Compact the parameter list to remove those nulls, and * correct the arg-count. */ targc = argc; targv = argv; margv = argv; argc = 0; for (; targc > 0; targc--, targv++) { if (*targv != generic_nullarg) { if (targv != margv) *margv = *targv; margv++; argc++; } } } if (argc == 1 && strcmp(*argv, "all") == 0) { generic_qselect = QSEL_ALL; more = firstprinter(pp, &cmdstatus); if (cmdstatus) goto looperr; while (more) { (*specificrtn)(pp); do { more = nextprinter(pp, &cmdstatus); looperr: switch (cmdstatus) { case PCAPERR_TCOPEN: printf("warning: %s: unresolved " "tc= reference(s) ", pp->printer); case PCAPERR_SUCCESS: break; default: fatal(pp, "%s", pcaperr(cmdstatus)); } } while (more && cmdstatus); } goto wrapup; } generic_qselect = QSEL_BYNAME; /* specifically-named ptrs */ for (; argc > 0; argc--, argv++) { init_printer(pp); cmdstatus = getprintcap(*argv, pp); switch (cmdstatus) { default: fatal(pp, "%s", pcaperr(cmdstatus)); case PCAPERR_NOTFOUND: printf("unknown printer %s\n", *argv); continue; case PCAPERR_TCOPEN: printf("warning: %s: unresolved tc= reference(s)\n", *argv); break; case PCAPERR_SUCCESS: break; } (*specificrtn)(pp); } wrapup: if (generic_wrapup) { (*generic_wrapup)(cmdstatus); } free_printer(pp); if (generic_msg) free(generic_msg); }
static void doit(void) { 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(0, "Command line too long"); if ((n = read(STDOUT_FILENO, cp, 1)) != 1) { if (n < 0) fatal(0, "Lost connection"); return; } } while (*cp++ != '\n'); *--cp = '\0'; cp = cbuf; if (lflag) { if (*cp >= '\1' && *cp <= '\5') syslog(LOG_INFO, "%s requests %s %s", from_host, cmdnames[(u_char)*cp], cp+1); else syslog(LOG_INFO, "bad request (%d) from %s", *cp, from_host); } switch (*cp++) { case CMD_CHECK_QUE: /* check the queue, print any jobs there */ startprinting(cp); break; case CMD_TAKE_THIS: /* receive files to be queued */ if (!from_remote) { syslog(LOG_INFO, "illegal request (%d)", *cp); exit(1); } recvjob(cp); break; 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 != ' ') { cp++; continue; } *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0') break; if (isdigit(*cp)) { if (requests >= MAXREQUESTS) fatal(0, "Too many requests"); requ[requests++] = atoi(cp); } else { if (users >= MAXUSERS) fatal(0, "Too many users"); user[users++] = cp; } } status = getprintcap(printer, pp); if (status < 0) fatal(pp, "%s", pcaperr(status)); displayq(pp, cbuf[0] == CMD_SHOWQ_LONG); exit(0); case CMD_RMJOB: /* remove a job from the queue */ if (!from_remote) { syslog(LOG_INFO, "illegal request (%d)", *cp); exit(1); } printer = cp; while (*cp && *cp != ' ') cp++; if (!*cp) break; *cp++ = '\0'; person = cp; while (*cp) { if (*cp != ' ') { cp++; continue; } *cp++ = '\0'; while (isspace(*cp)) cp++; if (*cp == '\0') break; if (isdigit(*cp)) { if (requests >= MAXREQUESTS) fatal(0, "Too many requests"); requ[requests++] = atoi(cp); } else { if (users >= MAXUSERS) fatal(0, "Too many users"); user[users++] = cp; } } rmjob(printer); break; } fatal(0, "Illegal service request"); } }
/* * Display the current state of the queue. Format = 1 if long format. */ void displayq(int format) { struct queue *q; int i, nitems, fd, ret; char *cp, *ecp; struct queue **queue; struct stat statb; FILE *fp; lflag = format; totsize = 0; rank = -1; getprintcap(printer); /* * Print out local queue * Find all the control files in the spooling directory */ seteuid(euid); if (chdir(SD) < 0) fatal("cannot chdir to spooling directory"); seteuid(uid); if ((nitems = getq(&queue)) < 0) fatal("cannot examine spooling area\n"); seteuid(euid); ret = stat(LO, &statb); seteuid(uid); if (ret >= 0) { if (statb.st_mode & S_IXUSR) { if (remote) printf("%s: ", host); printf("Warning: %s is down: ", printer); seteuid(euid); fd = open(ST, O_RDONLY); seteuid(uid); if (fd >= 0) { (void)flock(fd, LOCK_SH); while ((i = read(fd, line, sizeof(line))) > 0) (void)fwrite(line, 1, (size_t)i, stdout); (void)close(fd); /* unlocks as well */ } else putchar('\n'); } if (statb.st_mode & S_IXGRP) { if (remote) printf("%s: ", host); printf("Warning: %s queue is turned off\n", printer); } } if (nitems) { seteuid(euid); fp = fopen(LO, "r"); seteuid(uid); if (fp == NULL) nodaemon(); else { /* get daemon pid */ cp = current; ecp = cp + sizeof(current) - 1; while ((i = getc(fp)) != EOF && i != '\n') { if (cp < ecp) *cp++ = i; } *cp = '\0'; i = atoi(current); if (i <= 0) { ret = -1; } else { seteuid(euid); ret = kill(i, 0); seteuid(uid); } if (ret < 0) { nodaemon(); } else { /* read current file name */ cp = current; ecp = cp + sizeof(current) - 1; while ((i = getc(fp)) != EOF && i != '\n') { if (cp < ecp) *cp++ = i; } *cp = '\0'; /* * Print the status file. */ if (remote) printf("%s: ", host); seteuid(euid); fd = open(ST, O_RDONLY); seteuid(uid); if (fd >= 0) { (void)flock(fd, LOCK_SH); while ((i = read(fd, line, sizeof(line))) > 0) (void)fwrite(line, 1, (size_t)i, stdout); (void)close(fd); /* unlocks as well */ } else putchar('\n'); } (void)fclose(fp); } /* * Now, examine the control files and print out the jobs to * be done for each user. */ if (!lflag) header(); for (i = 0; i < nitems; i++) { q = queue[i]; inform(q->q_name); } } freeq(queue, nitems); if (!remote) { if (nitems == 0) puts("no entries"); return; } /* * Print foreign queue * Note that a file in transit may show up in either queue. */ if (nitems) putchar('\n'); (void)snprintf(line, sizeof(line), "%c%s", format + '\3', RP); cp = line; ecp = line + sizeof(line); for (i = 0; i < requests && (size_t)(cp - line + 11) < sizeof(line) - 2; i++) { cp += strlen(cp); (void)snprintf(cp, ecp - cp, " %d", requ[i]); } for (i = 0; i < users && cp - line + 1 + strlen(user[i]) < sizeof(line) - 2; i++) { cp += strlen(cp); if ((size_t)(cp - line) > sizeof(line) - 2) break; *cp++ = ' '; /* truncation may happen */ (void)strlcpy(cp, user[i], ecp - cp); } (void)strlcat(line, "\n", sizeof(line)); fd = getport(RM); if (fd < 0) { if (from != host) printf("%s: ", host); (void)printf("connection to %s is down\n", RM); } else { struct sigaction osa, nsa; i = strlen(line); if (write(fd, line, (size_t)i) != i) fatal("Lost connection"); nsa.sa_handler = alarmer; sigemptyset(&nsa.sa_mask); sigaddset(&nsa.sa_mask, SIGALRM); nsa.sa_flags = 0; (void)sigaction(SIGALRM, &nsa, &osa); alarm(wait_time); while ((i = read(fd, line, sizeof(line))) > 0) { (void)fwrite(line, 1, (size_t)i, stdout); alarm(wait_time); } alarm(0); (void)sigaction(SIGALRM, &osa, NULL); (void)close(fd); } }