Deleted Added
full compact
printjob.c (86935) printjob.c (94032)
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[] =
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 86935 2001-11-27 01:32:25Z gad $";
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);
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);
133static void init(struct printer *_pp);
134static void openpr(const struct printer *_pp);
135static void opennet(const struct printer *_pp);
136static void opentty(const struct printer *_pp);
137static void openrem(const struct printer *pp);
138static int print(struct printer *_pp, int _format, char *_file);
139static int printit(struct printer *_pp, char *_file);
140static void pstatus(const struct printer *_pp, const char *_msg, ...)

--- 825 unchanged lines hidden (view full) ---

966 * Send a data file to the remote machine and spool it.
967 * Return positive if we should try resending.
968 */
969static int
970sendfile(struct printer *pp, int type, char *file, char format)
971{
972 register int f, i, amt;
973 struct stat stb;
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;
974 FILE *fp;
975 char buf[BUFSIZ];
976 int closedpr, resp, sizerr, statrc;
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;
977
978 statrc = lstat(file, &stb);
979 if (statrc < 0) {
980 syslog(LOG_ERR, "%s: error from lstat(%s): %m",
981 pp->printer, file);
982 return(ERROR);
983 }
984 f = open(file, O_RDONLY);

--- 6 unchanged lines hidden (view full) ---

991 * Check to see if data file is a symbolic link. If so, it should
992 * still point to the same file or someone is trying to print something
993 * he shouldn't.
994 */
995 if ((stb.st_mode & S_IFMT) == S_IFLNK && fstat(f, &stb) == 0 &&
996 (stb.st_dev != fdev || stb.st_ino != fino))
997 return(ACCESS);
998
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
999 job_dfcnt++; /* increment datafile counter for this job */
1000
1001 /* everything seems OK, start it up */
1001 /* Everything seems OK for reading the file, now to send it */
1002 filtcmd = NULL;
1002 sizerr = 0;
1003 sizerr = 0;
1003 closedpr = 0;
1004 tfd = -1;
1004 if (type == '\3') {
1005 if (type == '\3') {
1005 if (pp->filters[LPF_INPUT]) {
1006 /*
1007 * We're sending something with an ifilter. We have to
1008 * run the ifilter and store the output as a temporary
1009 * spool file (tfile...), because the protocol requires
1010 * us to send the file size before we start sending any
1011 * of the data.
1012 */
1013 char *av[15];
1014 int n;
1015 int ifilter;
1016 union wait status; /* XXX */
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++;
1017
1013
1018 strcpy(tfile,TFILENAME);
1019 if ((tfd = mkstemp(tfile)) == -1) {
1020 syslog(LOG_ERR, "mkstemp: %m");
1021 return(ERROR);
1022 }
1023 if ((av[0] = strrchr(pp->filters[LPF_INPUT], '/')) == NULL)
1024 av[0] = pp->filters[LPF_INPUT];
1025 else
1026 av[0]++;
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");
1027 if (format == 'l')
1035 if (format == 'l')
1028 av[n=1] = "-c";
1029 else
1030 n = 0;
1031 av[++n] = width;
1032 av[++n] = length;
1033 av[++n] = indent;
1034 av[++n] = "-n";
1035 av[++n] = logname;
1036 av[++n] = "-h";
1037 av[++n] = origin_host;
1038 av[++n] = pp->acct_file;
1039 av[++n] = 0;
1040 if ((ifilter = dofork(pp, DORETURN)) == 0) { /* child */
1041 dup2(f, 0);
1042 dup2(tfd, 1);
1043 /* setup stderr for the filter (child process)
1044 * so it goes to our temporary errors file */
1045 n = open(tempstderr, O_WRONLY|O_TRUNC, 0664);
1046 if (n >= 0)
1047 dup2(n, 2);
1048 closelog();
1049 closeallfds(3);
1050 execv(pp->filters[LPF_INPUT], av);
1051 syslog(LOG_ERR, "cannot execv %s",
1052 pp->filters[LPF_INPUT]);
1053 exit(2);
1054 }
1055 (void) close(f);
1056 if (ifilter < 0)
1057 status.w_retcode = 100;
1058 else {
1059 while ((pid = wait((int *)&status)) > 0 &&
1060 pid != ifilter)
1061 ;
1062 if (pid < 0) {
1063 status.w_retcode = 100;
1064 syslog(LOG_WARNING, "%s: after execv(%s), wait() returned: %m",
1065 pp->printer, pp->filters[LPF_INPUT]);
1066 }
1067 }
1068 /* Copy the filter's output to "lf" logfile */
1069 if ((fp = fopen(tempstderr, "r"))) {
1070 while (fgets(buf, sizeof(buf), fp))
1071 fputs(buf, stderr);
1072 fclose(fp);
1073 }
1074 /* process the return-code from the filter */
1075 switch (status.w_retcode) {
1076 case 0:
1077 break;
1078 case 1:
1079 unlink(tfile);
1080 return(REPRINT);
1081 case 2:
1082 unlink(tfile);
1083 return(ERROR);
1084 default:
1085 syslog(LOG_WARNING, "%s: filter '%c' exited"
1086 " (retcode=%d)",
1087 pp->printer, format, status.w_retcode);
1088 unlink(tfile);
1089 return(FILTERERR);
1090 }
1091 statrc = fstat(tfd, &stb); /* to find size of tfile */
1092 if (statrc < 0) {
1093 syslog(LOG_ERR, "%s: error processing 'if', fstat(%s): %m",
1094 pp->printer, tfile);
1095 return(ERROR);
1096 }
1097 f = tfd;
1098 lseek(f,0,SEEK_SET);
1099 } else if (ofilter) {
1100 /*
1101 * We're sending something with an ofilter, we have to
1102 * store the output as a temporary file (tfile)... the
1103 * protocol requires us to send the file size
1104 */
1105 int i;
1106 for (i = 0; i < stb.st_size; i += BUFSIZ) {
1107 amt = BUFSIZ;
1108 if (i + amt > stb.st_size)
1109 amt = stb.st_size - i;
1110 if (sizerr == 0 && read(f, buf, amt) != amt) {
1111 sizerr = 1;
1112 break;
1113 }
1114 if (write(ofd, buf, amt) != amt) {
1115 (void) close(f);
1116 return(REPRINT);
1117 }
1118 }
1119 close(ofd);
1120 close(f);
1121 while ((i = wait(NULL)) > 0 && i != ofilter)
1122 ;
1123 if (i < 0)
1124 syslog(LOG_WARNING, "%s: after closing 'of', wait() returned: %m",
1125 pp->printer);
1126 ofilter = 0;
1127 statrc = fstat(tfd, &stb); /* to find size of tfile */
1128 if (statrc < 0) {
1129 syslog(LOG_ERR, "%s: error processing 'of', fstat(%s): %m",
1130 pp->printer, tfile);
1131 openpr(pp);
1132 return(ERROR);
1133 }
1134 f = tfd;
1135 lseek(f,0,SEEK_SET);
1136 closedpr = 1;
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;
1137 }
1138 }
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);
1139
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
1140 (void) sprintf(buf, "%c%qd %s\n", type, stb.st_size, file);
1141 amt = strlen(buf);
1142 for (i = 0; ; i++) {
1143 if (write(pfd, buf, amt) != amt ||
1144 (resp = response(pp)) < 0 || resp == '\1') {
1145 (void) close(f);
1146 if (tfd != -1 && type == '\3') {
1147 tfd = -1;
1148 unlink(tfile);
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);
1149 if (closedpr)
1150 openpr(pp);
1151 }
1152 return(REPRINT);
1153 } else if (resp == '\0')
1154 break;
1155 if (i == 0)
1156 pstatus(pp,
1157 "no space on remote; waiting for queue to drain");
1158 if (i == 10)

--- 11 unchanged lines hidden (view full) ---

1170 amt = stb.st_size - i;
1171 if (sizerr == 0 && read(f, buf, amt) != amt)
1172 sizerr = 1;
1173 if (write(pfd, buf, amt) != amt) {
1174 (void) close(f);
1175 if (tfd != -1 && type == '\3') {
1176 tfd = -1;
1177 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);
1178 if (closedpr)
1179 openpr(pp);
1180 }
1181 return(REPRINT);
1182 }
1183 }
1184
1185 (void) close(f);
1186 if (tfd != -1 && type == '\3') {
1187 tfd = -1;
1188 unlink(tfile);
1189 }
1190 if (sizerr) {
1191 syslog(LOG_INFO, "%s: %s: changed size", pp->printer, file);
1192 /* tell recvjob to ignore this file */
1193 (void) write(pfd, "\1", 1);
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);
1194 if (closedpr)
1195 openpr(pp);
1196 return(ERROR);
1197 }
1198 if (write(pfd, "", 1) != 1 || response(pp)) {
1150 return(ERROR);
1151 }
1152 if (write(pfd, "", 1) != 1 || response(pp)) {
1199 if (closedpr)
1200 openpr(pp);
1201 return(REPRINT);
1202 }
1153 return(REPRINT);
1154 }
1203 if (closedpr)
1204 openpr(pp);
1205 if (type == '\3')
1206 trstat_write(pp, TR_SENDING, stb.st_size, logname,
1207 pp->remote_host, origin_host);
1208 return(OK);
1209}
1210
1211/*
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/*
1212 * Check to make sure there have been no errors and that both programs
1213 * are in sync with eachother.
1214 * Return non-zero if the connection was lost.
1215 */
1216static char
1217response(const struct printer *pp)
1218{
1219 char resp;

--- 334 unchanged lines hidden (view full) ---

1554static void
1555openpr(const struct printer *pp)
1556{
1557 int p[2];
1558 char *cp;
1559
1560 if (pp->remote) {
1561 openrem(pp);
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;
1562 } else if (*pp->lp) {
1563 if ((cp = strchr(pp->lp, '@')) != NULL)
1564 opennet(pp);
1565 else
1566 opentty(pp);
1567 } else {
1568 syslog(LOG_ERR, "%s: no line printer device or host name",
1569 pp->printer);

--- 236 unchanged lines hidden ---
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 ---