1/* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: --- 29 unchanged lines hidden (view full) --- 38 The Regents of the University of California. All rights reserved.\n"; 39#endif /* not lint */ 40 41#ifndef lint 42/* 43static char sccsid[] = "@(#)printjob.c 8.7 (Berkeley) 5/10/95"; 44*/ 45static const char rcsid[] = |
46 "$FreeBSD: head/usr.sbin/lpr/lpd/printjob.c 94032 2002-04-07 05:37:27Z gad $"; |
47#endif /* not lint */ 48 49 50/* 51 * printjob -- print jobs in the queue. 52 * 53 * NOTE: the lock file is used to pass information to lpq and lprm. 54 * it does not need to be removed because file locks are dynamic. --- 70 unchanged lines hidden (view full) --- 125#define TFILENAME "fltXXXXXX" 126static char tfile[] = TFILENAME; /* file name for filter output */ 127 128static void abortpr(int _signo); 129static void alarmhandler(int _signo); 130static void banner(struct printer *_pp, char *_name1, char *_name2); 131static int dofork(const struct printer *_pp, int _action); 132static int dropit(int _c); |
133static int execfilter(struct printer *_pp, char *_f_cmd, char **_f_av, 134 int _infd, int _outfd); |
135static void init(struct printer *_pp); 136static void openpr(const struct printer *_pp); 137static void opennet(const struct printer *_pp); 138static void opentty(const struct printer *_pp); 139static void openrem(const struct printer *pp); 140static int print(struct printer *_pp, int _format, char *_file); 141static int printit(struct printer *_pp, char *_file); 142static void pstatus(const struct printer *_pp, const char *_msg, ...) --- 825 unchanged lines hidden (view full) --- 968 * Send a data file to the remote machine and spool it. 969 * Return positive if we should try resending. 970 */ 971static int 972sendfile(struct printer *pp, int type, char *file, char format) 973{ 974 register int f, i, amt; 975 struct stat stb; |
976 char *av[15], *filtcmd; 977 char buf[BUFSIZ], opt_c[4], opt_h[4], opt_n[4]; 978 int filtstat, narg, resp, sizerr, statrc; |
979 980 statrc = lstat(file, &stb); 981 if (statrc < 0) { 982 syslog(LOG_ERR, "%s: error from lstat(%s): %m", 983 pp->printer, file); 984 return(ERROR); 985 } 986 f = open(file, O_RDONLY); --- 6 unchanged lines hidden (view full) --- 993 * Check to see if data file is a symbolic link. If so, it should 994 * still point to the same file or someone is trying to print something 995 * he shouldn't. 996 */ 997 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 && 998 (stb.st_dev != fdev || stb.st_ino != fino)) 999 return(ACCESS); 1000 |
1001 /* Everything seems OK for reading the file, now to send it */ 1002 filtcmd = NULL; |
1003 sizerr = 0; |
1004 tfd = -1; |
1005 if (type == '\3') { |
1006 /* 1007 * Type == 3 means this is a datafile, not a control file. 1008 * Increment the counter of data-files in this job, and 1009 * then check for input or output filters (which are only 1010 * applied to datafiles, not control files). 1011 */ 1012 job_dfcnt++; |
1013 |
1014 /* 1015 * Note that here we are filtering datafiles, one at a time, 1016 * as they are sent to the remote machine. Here, the *only* 1017 * difference between an input filter (`if=') and an output 1018 * filter (`of=') is the argument list that the filter is 1019 * started up with. Here, the output filter is executed 1020 * for each individual file as it is sent. This is not the 1021 * same as local print queues, where the output filter is 1022 * started up once, and then all jobs are passed thru that 1023 * single invocation of the output filter. 1024 * 1025 * Also note that a queue for a remote-machine can have an 1026 * input filter or an output filter, but not both. 1027 */ 1028 if (pp->filters[LPF_INPUT]) { 1029 filtcmd = pp->filters[LPF_INPUT]; 1030 av[0] = filtcmd; 1031 narg = 0; 1032 strcpy(opt_c, "-c"); 1033 strcpy(opt_h, "-h"); 1034 strcpy(opt_n, "-n"); |
1035 if (format == 'l') |
1036 av[++narg] = opt_c; 1037 av[++narg] = width; 1038 av[++narg] = length; 1039 av[++narg] = indent; 1040 av[++narg] = opt_n; 1041 av[++narg] = logname; 1042 av[++narg] = opt_h; 1043 av[++narg] = origin_host; 1044 av[++narg] = pp->acct_file; 1045 av[++narg] = NULL; 1046 } else if (pp->filters[LPF_OUTPUT]) { 1047 filtcmd = pp->filters[LPF_OUTPUT]; 1048 av[0] = filtcmd; 1049 narg = 0; 1050 av[++narg] = width; 1051 av[++narg] = length; 1052 av[++narg] = NULL; |
1053 } 1054 } |
1055 if (filtcmd) { 1056 /* 1057 * If there is an input or output filter, we have to run 1058 * the datafile thru that filter and store the result as 1059 * a temporary spool file, because the protocol requires 1060 * that we send the remote host the file-size before we 1061 * start to send any of the data. 1062 */ 1063 strcpy(tfile, TFILENAME); 1064 tfd = mkstemp(tfile); 1065 if (tfd == -1) { 1066 syslog(LOG_ERR, "%s: mkstemp(%s): %m", pp->printer, 1067 TFILENAME); 1068 return (ERROR); 1069 } 1070 filtstat = execfilter(pp, filtcmd, av, f, tfd); |
1071 |
1072 /* process the return-code from the filter */ 1073 switch (filtstat) { 1074 case 0: 1075 break; 1076 case 1: 1077 unlink(tfile); 1078 return (REPRINT); 1079 case 2: 1080 unlink(tfile); 1081 return (ERROR); 1082 default: 1083 syslog(LOG_WARNING, 1084 "%s: filter '%c' exited (retcode=%d)", 1085 pp->printer, format, filtstat); 1086 unlink(tfile); 1087 return (FILTERERR); 1088 } 1089 statrc = fstat(tfd, &stb); /* to find size of tfile */ 1090 if (statrc < 0) { 1091 syslog(LOG_ERR, 1092 "%s: error processing 'if', fstat(%s): %m", 1093 pp->printer, tfile); 1094 return (ERROR); 1095 } 1096 f = tfd; 1097 lseek(f,0,SEEK_SET); 1098 } 1099 |
1100 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file); 1101 amt = strlen(buf); 1102 for (i = 0; ; i++) { 1103 if (write(pfd, buf, amt) != amt || 1104 (resp = response(pp)) < 0 || resp == '\1') { 1105 (void) close(f); 1106 if (tfd != -1 && type == '\3') { 1107 tfd = -1; 1108 unlink(tfile); |
1109 } 1110 return(REPRINT); 1111 } else if (resp == '\0') 1112 break; 1113 if (i == 0) 1114 pstatus(pp, 1115 "no space on remote; waiting for queue to drain"); 1116 if (i == 10) --- 11 unchanged lines hidden (view full) --- 1128 amt = stb.st_size - i; 1129 if (sizerr == 0 && read(f, buf, amt) != amt) 1130 sizerr = 1; 1131 if (write(pfd, buf, amt) != amt) { 1132 (void) close(f); 1133 if (tfd != -1 && type == '\3') { 1134 tfd = -1; 1135 unlink(tfile); |
1136 } 1137 return(REPRINT); 1138 } 1139 } 1140 1141 (void) close(f); 1142 if (tfd != -1 && type == '\3') { 1143 tfd = -1; 1144 unlink(tfile); 1145 } 1146 if (sizerr) { 1147 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file); 1148 /* tell recvjob to ignore this file */ 1149 (void) write(pfd, "\1", 1); |
1150 return(ERROR); 1151 } 1152 if (write(pfd, "", 1) != 1 || response(pp)) { |
1153 return(REPRINT); 1154 } |
1155 if (type == '\3') 1156 trstat_write(pp, TR_SENDING, stb.st_size, logname, 1157 pp->remote_host, origin_host); 1158 return(OK); 1159} 1160 1161/* |
1162 * This routine is called to execute one of the filters as was 1163 * specified in a printcap entry. 1164 */ 1165static int 1166execfilter(struct printer *pp, char *f_cmd, char *f_av[], int infd, int outfd) 1167{ 1168 int errfd, fpid, wpid; 1169 FILE *errfp; 1170 union wait status; /* XXX */ 1171 char buf[BUFSIZ], *slash; 1172 1173 fpid = dofork(pp, DORETURN); 1174 if (fpid != 0) { 1175 /* 1176 * This is the parent process, which just waits for the child 1177 * to complete and then returns the result. Note that it is 1178 * the child process which reads the input stream. 1179 */ 1180 (void) close(infd); 1181 if (fpid < 0) 1182 status.w_retcode = 100; 1183 else { 1184 while ((wpid = wait((int *)&status)) > 0 && 1185 wpid != fpid) 1186 ; 1187 if (wpid < 0) { 1188 status.w_retcode = 100; 1189 syslog(LOG_WARNING, 1190 "%s: after execv(%s), wait() returned: %m", 1191 pp->printer, f_cmd); 1192 } 1193 } 1194 1195 /* 1196 * Copy everything the filter wrote to stderr from our 1197 * temporary errors file to the "lf=" logfile. 1198 */ 1199 errfp = fopen(tempstderr, "r"); 1200 if (errfp) { 1201 while (fgets(buf, sizeof(buf), errfp)) 1202 fputs(buf, stderr); 1203 fclose(errfp); 1204 } 1205 1206 return (status.w_retcode); 1207 } 1208 1209 /* 1210 * This is the child process, which is the one that executes the 1211 * given filter. 1212 */ 1213 /* 1214 * If the first parameter has any slashes in it, then change it 1215 * to point to the first character after the last slash. 1216 */ 1217 slash = strrchr(f_av[0], '/'); 1218 if (slash != NULL) 1219 f_av[0] = slash + 1; 1220 /* 1221 * XXX - in the future, this should setup an explicit list of 1222 * environment variables and use execve()! 1223 */ 1224 1225 /* 1226 * Setup stdin, stdout, and stderr as we want them when the filter 1227 * is running. Stderr is setup so it points to a temporary errors 1228 * file, and the parent process will copy that temporary file to 1229 * the real logfile after the filter completes. 1230 */ 1231 dup2(infd, 0); 1232 dup2(outfd, 1); 1233 errfd = open(tempstderr, O_WRONLY|O_TRUNC, 0664); 1234 if (errfd >= 0) 1235 dup2(errfd, 2); 1236 closelog(); 1237 closeallfds(3); 1238 execv(f_cmd, f_av); 1239 syslog(LOG_ERR, "%s: cannot execv %s", pp->printer, f_cmd); 1240 exit(2); 1241 /* NOTREACHED */ 1242} 1243 1244/* |
1245 * Check to make sure there have been no errors and that both programs 1246 * are in sync with eachother. 1247 * Return non-zero if the connection was lost. 1248 */ 1249static char 1250response(const struct printer *pp) 1251{ 1252 char resp; --- 334 unchanged lines hidden (view full) --- 1587static void 1588openpr(const struct printer *pp) 1589{ 1590 int p[2]; 1591 char *cp; 1592 1593 if (pp->remote) { 1594 openrem(pp); |
1595 /* 1596 * Lpd does support the setting of 'of=' filters for 1597 * jobs going to remote machines, but that does not 1598 * have the same meaning as 'of=' does when handling 1599 * local print queues. For remote machines, all 'of=' 1600 * filter processing is handled in sendfile(), and that 1601 * does not use these global "output filter" variables. 1602 */ 1603 ofd = -1; 1604 ofilter = 0; 1605 return; |
1606 } else if (*pp->lp) { 1607 if ((cp = strchr(pp->lp, '@')) != NULL) 1608 opennet(pp); 1609 else 1610 opentty(pp); 1611 } else { 1612 syslog(LOG_ERR, "%s: no line printer device or host name", 1613 pp->printer); --- 236 unchanged lines hidden --- |