📄 printjob.c
字号:
static char xlator_call_flags[8];/****************************************************************//* This is the set of char pointers used by printcap_escapes, * note that the escapes are initialised by reference, so these * pointers may be changed in the course of execution, * This applies particularly to printer and AF, which have * #defines to keep the naming tidy and the information localised. */static char *es_percent = "%";static char *es_null = "";static char *es_space = " ";static char *es_width = width+2;static char *es_length = length+2;static char *es_title = title;static char *es_indent = indent+2;static char *es_pxwidth = pxwidth+2;static char *es_pxlength = pxlength+2;#define es_printer printerstatic char *es_fromhost = fromhost;static char *es_logname = logname;static char *es_jobname = jobname;static char *es_job_id = job_id;#define es_account_file AFstatic char *es_datatype = datatype;static char *es_orientation = orientation;static char *es_pagesize = pagesize;static char *es_xflags = &xlator_call_flags[0];struct es_pair printcap_escapes[] = { { '%', &es_percent }, /* defines the escape character */ { '0', &es_null }, /* the null string (for null arguments) */ { '_', &es_space }, { 'W', &es_width }, { 'L', &es_length }, { 'T', &es_title }, { 'I', &es_indent }, { 'X', &es_pxwidth }, { 'Y', &es_pxlength }, { 'P', &es_printer }, { 'H', &es_fromhost }, { 'U', &es_logname }, { 'j', &es_jobname }, { 'J', &es_job_id }, { 'A', &es_account_file }, { 'D', &es_datatype }, { 'O', &es_orientation }, { 'F', &es_pagesize }, { 'x', &es_xflags }, { '\0', 0 }};/* * Environment buffers for signal catching code */jmp_buf env, sigpipe_env;printjob(begin)int begin;{ struct connection out_plug; /* output connection */ init(); /* set up capabilities */ (void) write(1, "", 1); /* ack that daemon is started */ (void) close(1); /* set up log file */ (void) close(2); if((begin==1) && (RM==NULL)) { inid = open(ininame,O_RDWR|O_CREAT,0660); /* create a init file */ write(inid, "init file\n", 10); (void) close(inid); } if (open(LF, O_WRONLY|O_APPEND) < 0) (void) open("/dev/null", O_WRONLY); dup(1); pid = getpid(); /* for use with lprm */ setpgrp(0, pid); dlog(0, "%s: daemon %d started", lpd_time(), pid); init_features(); /* set flags for this printer version */ set_connection_type(); /* decide connection type */ cx_init(&out_plug, connection_type); /* initialise connection */ { int signal_number; if ((signal_number = setjmp(env)) != 0) { final_cleanup(&out_plug, signal_number); exit(1); } else { signal(SIGHUP, onintr); signal(SIGINT, onintr); signal(SIGQUIT, onquit); signal(SIGTERM, onintr); signal(SIGCHLD, SIG_DFL); } } set_printer_type(); /* decide printer type (PS or not) */ /* If we're type PostScript, open Device Control Module archive */ switch (printer_type) { case pt_non_PS: break; case pt_LN03R: case pt_LPS: if (!DL) { fatal("Dl must be specified for %s printer_type", PS_choices[(int)printer_type]); exit(1); } if (ar_init(DL) != 0) { fatal("archive %s not found\n", DL); } break; } /* * uses short form file names */ if (chdir(SD) < 0) { log("cannot chdir to %s", SD); exit(1); } lfd = open(LO, O_WRONLY|O_CREAT, 0644); if (lfd < 0) { log("cannot create %s", LO); exit(1); } if (flock(lfd, LOCK_EX|LOCK_NB) < 0) { if (errno == EWOULDBLOCK) /* active deamon present */ exit(0); log("cannot lock %s", LO); exit(1); } ftruncate(lfd, 0); /* * write process id for others to know */ sprintf(line, "%u\n", pid); pidoff = strlen(line); if (write(lfd, line, pidoff) != pidoff) { log("cannot write daemon pid"); exit(1); } tof = !FO; process_the_queue(&out_plug); final_cleanup(&out_plug, 0); exit(0);}/* * get_q_state -- find state of queue by checking lock file mode */static enum q_state_eget_q_state(){ struct stat stb; if (fstat(lfd, &stb) == 0) { if (stb.st_mode & 0100) { return q_disabled; } else if (stb.st_mode & 0001) { if (fchmod(lfd, stb.st_mode & 0776) < 0) log("cannot chmod %s", LO); return q_rebuild; } else { return q_enabled; } } else { return q_disabled; }}static voidprocess_the_queue(cxp)register CXP cxp;{ int count = 0; int nitems = 0; register struct queue *q, **qp; struct queue **queue; enum q_state_e q_state = get_q_state(); while (1) { dlog(1, "process_the_queue: while"); if (q_state == q_disabled || (nitems = getq(&queue)) <= 0) { dlog(1, "process_the_queue: getq - nitems %d",nitems); break; } q_state = q_enabled; for (qp = queue; nitems--; ) { dlog(1, "process_the_queue: for nitems %d",nitems); q = *qp++; switch(q_state) { case q_enabled: dlog(1, "process_the_queue: q_enabled"); count += process_a_job(cxp, q->q_name); q_state = get_q_state(); break; case q_disabled: case q_rebuild: dlog(1, "process_the_queue: q_disabled"); break; } free((char *) q); } dlog(1, "process_the_queue:free"); free((char *) queue); } if (nitems < 0) { log("can't scan spool directory %s", SD); } if (printer_type == pt_non_PS && count > 0) { dlog(1, "process_the_queue: pt_non_ps"); switch (connection_type) { case con_dev: case con_lat: if (!SF && !tof) (void) write(cxp->cx_out_fd, FF, strlen(FF)); if (TR != NULL) /* output trailer */ (void) write(cxp->cx_out_fd, TR, strlen(TR)); break; default: dlog(1, "process_the_queue: default"); /* do nothing */ break; } }}static intprocess_a_job(cxp, command_file)register CXP cxp;char *command_file;{ struct stat stb; register int i, n_retries; register unsigned how_long; enum job_status_e job_status; if (stat(command_file, &stb) < 0) return 0; (void) lseek(lfd, pidoff, 0); (void) sprintf(line, "%s\n", command_file); i = strlen(line); if (write(lfd, line, i) != i) { log("can't write (%d) control file name %s", errno, LO); return 0; } how_long = MIN_RETRY_WAIT; for (n_retries = 0; n_retries < PRINT_NRETRIES; n_retries++) { dlog(1, "process_the_job: command file %s",command_file); job_status = try_the_job(cxp, command_file); switch (job_status) { case js_ok: return 1; /* job ok and printed */ case js_failed: default: log("%s: Job %d aborted", lpd_time(), atoi(command_file+3)); (void)cx_close(cxp); /* close printer connection */ cleanup_job(command_file, js_failed); return 0; /* job failed */ case js_retry: /* try reprinting the job after a sleep */ (void)cx_close(cxp); /* close printer connection */ log("%s: Job %d, Retry #%d in %d secs", lpd_time(), atoi(command_file+3), n_retries + 1, how_long); status("Sleeping for %d seconds before retrying", how_long); sleep(how_long); break; } how_long = (((how_long * 2) > MAX_RETRY_WAIT) ? MAX_RETRY_WAIT : (how_long * 2)); } log("Job %d abandonned after %d retries", atoi(command_file+3), n_retries); cleanup_job(command_file, js_too_many_retries); return 0;}static enum job_status_etry_the_job(cxp, command_file)register CXP cxp;char *command_file;{ enum job_status_e job_status = js_failed; if (setjmp(sigpipe_env) == 0) { signal(SIGPIPE, onsigpipe); job_init(); switch(connection_type) { case con_dev: case con_lat: case con_tcp: /* * actions associated with cx_open and cx_start * only happen if needed here since out_plug * maintains state and knows what to do */ (void)cx_open(cxp); cx_start(cxp); job_status = printit(cxp, command_file); break; case con_remote: /* open output if necessary */ (void)cx_open(cxp); job_status = sendit(cxp, command_file); break; case con_network: job_status = printit(cxp, command_file); break; case con_dqs: /* for dqs - print */ dlog(1, "try_the_job: connection type dqs"); job_status = startdqs(printer,cxp,command_file); if(job_status == js_ok) dlog(1, "try_the_job: job_status is OK exit child"); else dlog(1, "try_the_job: job_status FAILED exit child"); exit(0); default: log("Unknown connection type"); break; } } else { int cx_ret_code; stop_mon(); dlog(0, "caught SIGPIPE writing to output filter"); cx_ret_code = cx_close(cxp); job_status = ((cx_ret_code == 1) ? js_retry : js_failed); } return job_status;}char fonts[4][50]; /* fonts for troff */static char ifonts[4][18] = { "/usr/lib/vfont/R", "/usr/lib/vfont/I", "/usr/lib/vfont/B", "/usr/lib/vfont/S"};static voidcleanup_job(command_file, why)char *command_file;enum job_status_e why;{ FILE *cfp; /* control file */ /* * open control file */ if ((cfp = fopen(command_file, "r")) == NULL) { log("open failure (%d) of control file %s", errno, command_file); /* shouldn't happen, must have opened ok before */ return; } cf_pass2(cfp, why); /* * clean-up incase another control file exists */ (void) fclose(cfp); (void) unlink(command_file);}/* * cf_pass2 -- * * Second pass through command file called by printit and cleanup_job */intcf_pass2(cfp, job_status)FILE *cfp; /* control file */enum job_status_e job_status;{ fseek(cfp, 0L, 0); while (getline(cfp)) { switch (line[0]) { case 'M': sendmail(line+1, fromhost, jobname, job_status); continue; case 'U': (void) unlink(line+1); continue; default: continue; } }}/* build filter * Parse the string prog into filter elements, replace escapes if found, * If no escapes are found then add in default arguments * for backward compatibility (NB remember to terminate with 0) * The filter(s) are appended to the filter_chain *fcp. * The escapes are described by the escapes pointed to by esp. *//*VARARGS3*/voidbuild_filter(fcp, esp, prog, va_alist)FCP fcp; /* filter chain we're building */ESP esp; /* The escapes */char *prog; /* Program string */va_dcl /* Default arguments to filter 0 terminated */{ struct filter_chain filter_tmp; int escapes_found = 0; /* return flag from do_escapes */ register char *p; fc_init(&filter_tmp); /* tmp: parsed first program put here */ /* parse the command in prog */ for (p = parse_prog(&filter_tmp, prog); p; ) { p = parse_prog(&filter_tmp, p); } if (enable_printcap_escapes) { escapes_found = do_escapes(&filter_tmp, esp); } /* append first command to filter chain */ fc_add_args_v(fcp, filter_tmp.fc_argv[0]); if (!escapes_found) { va_list args; /* Add in default args to first command in pipeline */ va_start(args); fc_add_args_va(fcp, args); va_end(args); } fc_end_filter(fcp); /* terminate 1st command */ { int i; /* loop index */ for (i = 1; i < filter_tmp.fc_nf; i++) { /* append each command to filter chain */ fc_add_args_v(fcp, filter_tmp.fc_argv[i]); fc_end_filter(fcp); } } fc_delete(&filter_tmp, 0);}/* build_filter_chain * Set up filter chain * [ {PR, PP} | ] [ IF | ] OF * or * { RF, TF, NF, DF, CF, VF }. * * Instructions whether OF is needed is passed by return code. * * Changes: * (PP added to above description, AT 26-jan-88) * (semantics of IF changed, AT 28-jan-88) * Returns: */#define BFC_ERR (-1) /* foul up */#define BFC_USE_OUTPUT_FILTER 1 /* use the output filter */#define BFC_BYPASS 0 /* don't use the output filter */static intbuild_filter_chain(format, fcp)int format;register FCP fcp; /* filter constructed in here */{ int retcode = BFC_BYPASS; struct escapes escapes; /* escapes */ es_init(&escapes, printcap_escapes); switch(format) { int fd; int i; static char *vfpre = "/usr/lib/vfont/"; case 'p': /* print using pr-like filter */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -