/* * 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); }
/* * 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); } }
/* * Free the dynamically-allocated strings in a `struct printer'. * Idempotent. */ void free_printer(struct printer *pp) { enum lpd_filters filt; #define cfree(x) do { if (x) free(x); } while(0) cfree(pp->printer); cfree(pp->acct_file); for (filt = 0; filt < LPF_COUNT; filt++) cfree(pp->filters[filt]); cfree(pp->form_feed); cfree(pp->log_file); cfree(pp->lock_file); cfree(pp->lp); cfree(pp->restrict_grp); cfree(pp->remote_host); cfree(pp->remote_queue); cfree(pp->spool_dir); cfree(pp->stat_recv); cfree(pp->stat_send); cfree(pp->status_file); cfree(pp->trailer); cfree(pp->mode_set); init_printer(pp); }
static void hrPrinter_get_OS_entries(void) { int status, more; struct printer myprinter, *pp = &myprinter; init_printer(pp); HRDBG("---->Getting printers ....."); more = firstprinter(pp, &status); if (status) goto errloop; while (more) { do { HRDBG("---->Got printer %s", pp->printer); handle_printer(pp); more = nextprinter(pp, &status); errloop: if (status) syslog(LOG_WARNING, "hrPrinterTable: printcap entry for %s " "has errors, skipping", pp->printer ? pp->printer : "<noname?>"); } while (more && status); } lastprinter(); printer_tick = this_tick; }
/* * Initialization: * - converter = converter interface (this * is copied into pp->converter). * - file = output stream to use (must be an open file) * - area = specify display area + truncate + stretch * if area is NULL then the default is used * - mode = initial mode * - indent = initial indentation (increment) * * mode + indent are the bottom stack element */ void init_pp(pp_t *pp, pp_token_converter_t *converter, FILE *file, pp_area_t *area, pp_print_mode_t mode, uint32_t indent) { if (area == NULL) { area = &default_area; } assert(area->width >= PP_MINIMAL_WIDTH && area->height >= PP_MINIMAL_HEIGHT); init_printer(&pp->printer, file, converter, area, mode, indent); init_formatter(&pp->formatter, &pp->printer); }
/* * 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); } }
int init(struct map_data **map, int argc, char *argv[]) { // process tags char *map_path; if ( argc > 1 ) map_path = argv[1]; else map_path = "test.map"; *map = load_map( map_path ); if (!*map) { fprintf(stderr, "Could not open map: %s\n", map_path); return 1; } //construct map if (!(*map)->data) { fprintf(stderr, "Data got corrupted!\n"); return 1; } // init screen initscr(); if((has_color = has_colors()) == FALSE) { endwin(); printf("Your terminal does not support color\n"); return 1; } else { assert( start_color() ); assert( init_printer() ); assert( init_pathfinder( is_traversable_test ) ); assert( init_keyboard( (*map)->height, (*map)->width-1 ) ); } // get keys cbreak(); raw(); return 0; }
/* * Scan through the database of printers using cgetfirst/cgetnext. * Return false of error or end-of-database; else true. */ int firstprinter(struct printer *pp, int *error) { int status; char *bp; init_printer(pp); status = cgetfirst(&bp, printcapdb); if (firstnextmap(&status) == 0) { if (error) *error = status; return 0; } if (error) *error = status; status = getprintcap_int(bp, pp); free(bp); if (error && status) *error = status; return 1; }
/* * Main print server thread. Accepts connect requests from * clients and spawns additional threads to service requests. * * LOCKING: none. */ int main(int argc, char *argv[]) { pthread_t tid; struct addrinfo *ailist, *aip; int sockfd, err, i, n, maxfd; char *host; fd_set rendezvous, rset; struct sigaction sa; struct passwd *pwdp; if (argc != 1) err_quit("usage: printd"); daemonize("printd"); sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL) < 0) log_sys("sigaction failed"); sigemptyset(&mask); sigaddset(&mask, SIGHUP); sigaddset(&mask, SIGTERM); if ((err = pthread_sigmask(SIG_BLOCK, &mask, NULL)) != 0) log_sys("pthread_sigmask failed"); n = sysconf(_SC_HOST_NAME_MAX); if (n < 0) /* best guess */ n = HOST_NAME_MAX; if ((host = malloc(n)) == NULL) log_sys("malloc error"); if (gethostname(host, n) < 0) log_sys("gethostname error"); if ((err = getaddrlist(host, "print", &ailist)) != 0) { log_quit("getaddrinfo error: %s", gai_strerror(err)); exit(1); } FD_ZERO(&rendezvous); maxfd = -1; for (aip = ailist; aip != NULL; aip = aip->ai_next) { if ((sockfd = initserver(SOCK_STREAM, aip->ai_addr, aip->ai_addrlen, QLEN)) >= 0) { FD_SET(sockfd, &rendezvous); if (sockfd > maxfd) maxfd = sockfd; } } if (maxfd == -1) log_quit("service not enabled"); pwdp = getpwnam(LPNAME); if (pwdp == NULL) log_sys("can't find user %s", LPNAME); if (pwdp->pw_uid == 0) log_quit("user %s is privileged", LPNAME); if (setgid(pwdp->pw_gid) < 0 || setuid(pwdp->pw_uid) < 0) log_sys("can't change IDs to user %s", LPNAME); init_request(); init_printer(); err = pthread_create(&tid, NULL, printer_thread, NULL); if (err == 0) err = pthread_create(&tid, NULL, signal_thread, NULL); if (err != 0) log_exit(err, "can't create thread"); build_qonstart(); log_msg("daemon initialized"); for (;;) { rset = rendezvous; if (select(maxfd+1, &rset, NULL, NULL, NULL) < 0) log_sys("select failed"); for (i = 0; i <= maxfd; i++) { if (FD_ISSET(i, &rset)) { /* * Accept the connection and handle the request. */ if ((sockfd = accept(i, NULL, NULL)) < 0) log_ret("accept failed"); pthread_create(&tid, NULL, client_thread, (void *)((long)sockfd)); } } } exit(1); }
/* * Single thread to communicate with the printer. * * LOCKING: acquires and releases joblock and configlock. */ void * printer_thread(void *arg) { struct job *jp; int hlen, ilen, sockfd, fd, nr, nw, extra; char *icp, *hcp, *p; struct ipp_hdr *hp; struct stat sbuf; struct iovec iov[2]; char name[FILENMSZ]; char hbuf[HBUFSZ]; char ibuf[IBUFSZ]; char buf[IOBUFSZ]; char str[64]; struct timespec ts = { 60, 0 }; /* 1 minute */ for (;;) { /* * Get a job to print. */ pthread_mutex_lock(&joblock); while (jobhead == NULL) { log_msg("printer_thread: waiting..."); pthread_cond_wait(&jobwait, &joblock); } remove_job(jp = jobhead); log_msg("printer_thread: picked up job %d", jp->jobid); pthread_mutex_unlock(&joblock); update_jobno(); /* * Check for a change in the config file. */ pthread_mutex_lock(&configlock); if (reread) { freeaddrinfo(printer); printer = NULL; printer_name = NULL; reread = 0; pthread_mutex_unlock(&configlock); init_printer(); } else { pthread_mutex_unlock(&configlock); } /* * Send job to printer. */ sprintf(name, "%s/%s/%d", SPOOLDIR, DATADIR, jp->jobid); if ((fd = open(name, O_RDONLY)) < 0) { log_msg("job %d canceled - can't open %s: %s", jp->jobid, name, strerror(errno)); free(jp); continue; } if (fstat(fd, &sbuf) < 0) { log_msg("job %d canceled - can't fstat %s: %s", jp->jobid, name, strerror(errno)); free(jp); close(fd); continue; } if ((sockfd = connect_retry(AF_INET, SOCK_STREAM, 0, printer->ai_addr, printer->ai_addrlen)) < 0) { log_msg("job %d deferred - can't contact printer: %s", jp->jobid, strerror(errno)); goto defer; } /* * Set up the IPP header. */ icp = ibuf; hp = (struct ipp_hdr *)icp; hp->major_version = 1; hp->minor_version = 1; hp->operation = htons(OP_PRINT_JOB); hp->request_id = htonl(jp->jobid); icp += offsetof(struct ipp_hdr, attr_group); *icp++ = TAG_OPERATION_ATTR; icp = add_option(icp, TAG_CHARSET, "attributes-charset", "utf-8"); icp = add_option(icp, TAG_NATULANG, "attributes-natural-language", "en-us"); sprintf(str, "http://%s/ipp", printer_name); icp = add_option(icp, TAG_URI, "printer-uri", str); icp = add_option(icp, TAG_NAMEWOLANG, "requesting-user-name", jp->req.usernm); icp = add_option(icp, TAG_NAMEWOLANG, "job-name", jp->req.jobnm); if (jp->req.flags & PR_TEXT) { p = "text/plain"; extra = 1; } else { p = "application/postscript"; extra = 0; } icp = add_option(icp, TAG_MIMETYPE, "document-format", p); *icp++ = TAG_END_OF_ATTR; ilen = icp - ibuf; /* * Set up the HTTP header. */ hcp = hbuf; sprintf(hcp, "POST /ipp HTTP/1.1\r\n"); hcp += strlen(hcp); sprintf(hcp, "Content-Length: %ld\r\n", (long)sbuf.st_size + ilen + extra); hcp += strlen(hcp); strcpy(hcp, "Content-Type: application/ipp\r\n"); hcp += strlen(hcp); sprintf(hcp, "Host: %s:%d\r\n", printer_name, IPP_PORT); hcp += strlen(hcp); *hcp++ = '\r'; *hcp++ = '\n'; hlen = hcp - hbuf; /* * Write the headers first. Then send the file. */ iov[0].iov_base = hbuf; iov[0].iov_len = hlen; iov[1].iov_base = ibuf; iov[1].iov_len = ilen; if (writev(sockfd, iov, 2) != hlen + ilen) { log_ret("can't write to printer"); goto defer; } if (jp->req.flags & PR_TEXT) { /* * Hack: allow PostScript to be printed as plain text. */ if (write(sockfd, "\b", 1) != 1) { log_ret("can't write to printer"); goto defer; } } while ((nr = read(fd, buf, IOBUFSZ)) > 0) { if ((nw = writen(sockfd, buf, nr)) != nr) { if (nw < 0) log_ret("can't write to printer"); else log_msg("short write (%d/%d) to printer", nw, nr); goto defer; } } if (nr < 0) { log_ret("can't read %s", name); goto defer; } /* * Read the response from the printer. */ if (printer_status(sockfd, jp)) { unlink(name); sprintf(name, "%s/%s/%d", SPOOLDIR, REQDIR, jp->jobid); unlink(name); free(jp); jp = NULL; } defer: close(fd); if (sockfd >= 0) close(sockfd); if (jp != NULL) { replace_job(jp); nanosleep(&ts, NULL); } } }
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"); } }