00001
00002
00003
00004 #define nil 0
00005 #include <stdio.h>
00006 #include <stdlib.h>
00007 #include <limits.h>
00008 #include <string.h>
00009 #include <errno.h>
00010 #include <sys/types.h>
00011 #include <sys/stat.h>
00012 #include <dirent.h>
00013 #include <fcntl.h>
00014 #include <unistd.h>
00015 #include <termcap.h>
00016
00017 char PRINTER[] = "/dev/lp";
00018 char SPOOL[] = "/usr/spool/lpd";
00019 char LOG[] = "/dev/log";
00020
00021 void report(char *mess)
00022 {
00023 fprintf(stderr, "lpd: %s: %s\n", mess, strerror(errno));
00024 }
00025
00026 void fatal(char *mess)
00027 {
00028 report(mess);
00029 exit(1);
00030 }
00031
00032 char jobX[] = "jobXXXXXX";
00033 char tmpX[] = "tmpXXXXXX";
00034
00035 void spoolerr(char *file)
00036 {
00037 int e= errno;
00038
00039 unlink(jobX);
00040 unlink(tmpX);
00041 fatal(file);
00042 }
00043
00044 void spool(char *path)
00045
00046
00047
00048 {
00049 char *file;
00050 int j, u;
00051
00052 mktemp(jobX);
00053 file= mktemp(tmpX);
00054
00055 if (path[0] == '/') {
00056 int f;
00057
00058 if ((f= open(path, O_RDONLY)) >= 0) {
00059 close(f);
00060 file= path;
00061 }
00062 }
00063 if (file != path) {
00064 int c;
00065 FILE *t;
00066
00067 if ((t= fopen(tmpX, "w")) == nil) spoolerr(tmpX);
00068
00069 while ((c= getchar()) != EOF && putc(c, t) != EOF) {}
00070
00071 if (ferror(stdin)) spoolerr(path);
00072
00073 if (ferror(t) || fclose(t) == EOF) spoolerr(tmpX);
00074
00075 fclose(stdin);
00076 }
00077
00078 if ((j= open(jobX, O_WRONLY|O_CREAT|O_EXCL, 0000)) < 0) spoolerr(jobX);
00079
00080 u= getuid();
00081 if (write(j, file, strlen(file)+1) < 0
00082 || write(j, &u, sizeof(u)) < 0
00083 || write(j, path, strlen(path)+1) < 0
00084 || close(j) < 0
00085 || chmod(jobX, 0600) < 0
00086 ) spoolerr(jobX);
00087 }
00088
00089 struct job {
00090 struct job *next;
00091 time_t age;
00092 char name[sizeof(jobX)];
00093 } *jobs = nil;
00094
00095 int job(void)
00096
00097
00098
00099 {
00100 DIR *spool;
00101 struct dirent *entry;
00102 struct job *newjob, **ajob;
00103 struct stat st;
00104
00105 if (jobs != nil) return 1;
00106
00107 if ((spool= opendir(".")) == nil) fatal(SPOOL);
00108
00109 while ((entry= readdir(spool)) != nil) {
00110 if (strncmp(entry->d_name, "job", 3) != 0) continue;
00111
00112 if (stat(entry->d_name, &st) < 0
00113 || (st.st_mode & 0777) == 0000) continue;
00114
00115 if ((newjob= malloc(sizeof(*newjob))) == nil) fatal("malloc()");
00116 newjob->age = st.st_mtime;
00117 strcpy(newjob->name, entry->d_name);
00118
00119 ajob= &jobs;
00120 while (*ajob != nil && (*ajob)->age < newjob->age)
00121 ajob= &(*ajob)->next;
00122
00123 newjob->next= *ajob;
00124 *ajob= newjob;
00125 }
00126 closedir(spool);
00127
00128 return jobs != nil;
00129 }
00130
00131
00132
00133
00134
00135
00136 char control[] = {
00137 0, 1, 1, 1, 1, 1, 1, 0,
00138 2, 2, 2, 1, 2, 2, 1, 1,
00139 1, 1, 1, 1, 1, 1, 1, 1,
00140 1, 1, 1, 1, 1, 1, 1, 1
00141 };
00142
00143 int lp;
00144 char buf[BUFSIZ];
00145 int count, column, line, ncols = 80, nlines = 66;
00146
00147 int flush(void)
00148
00149
00150
00151 {
00152 char *bp= buf;
00153
00154 while (count > 0) {
00155 int retry = 0, complain = 0;
00156 int r;
00157
00158 while ((r= write(lp, bp, count)) < 0) {
00159 if (errno != EAGAIN) fatal(PRINTER);
00160 if (retry == complain) {
00161 fprintf(stderr,
00162 "lpd: %s: Printer out of paper\n",
00163 PRINTER);
00164 complain= retry + 60;
00165 }
00166 sleep(1);
00167 retry++;
00168 }
00169 bp+= r;
00170 count-= r;
00171 }
00172 count = 0;
00173 }
00174
00175 int put(int c)
00176
00177
00178
00179 {
00180 buf[count++] = c;
00181
00182 switch (c) {
00183 case '\f':
00184 column = 0;
00185 line = 0;
00186 break;
00187 case '\r':
00188 column = 0;
00189 break;
00190 case '\n':
00191 line++;
00192 break;
00193 case '\b':
00194 column--;
00195 break;
00196 default:
00197 if (++column > ncols) { line++; column= 1; }
00198 }
00199 if (line == nlines) line= 0;
00200
00201 if (count == BUFSIZ) flush();
00202 }
00203
00204 void print(FILE *f)
00205
00206
00207
00208
00209
00210
00211 {
00212 int c;
00213
00214 count= column= line= 0;
00215
00216 while ((c= getc(f)) != EOF) {
00217 if (c < ' ') {
00218 switch (control[c]) {
00219 case 0: continue;
00220 case 1:
00221
00222 do {
00223 buf[count++] = c;
00224 if (count == BUFSIZ) flush();
00225 } while ((c= getc(f)) != EOF);
00226
00227 flush();
00228 return;
00229 case 2: ;
00230 }
00231 }
00232
00233 switch (c) {
00234 case '\n':
00235 put('\r');
00236 put('\n');
00237 break;
00238 case '\t':
00239 do {
00240 put(' ');
00241 } while (column & 07);
00242 break;
00243 case '\b':
00244 if (column > 0) put(c);
00245 break;
00246 default:
00247 put(c);
00248 }
00249 }
00250 if (column > 0) { put('\r'); put('\n'); }
00251 if (line > 0) put('\f');
00252 flush();
00253 return;
00254 }
00255
00256 void joberr(char *job)
00257 {
00258 fprintf(stderr, "lpd: something is wrong with %s\n", job);
00259
00260 if (unlink(job) < 0) fatal("can't remove it");
00261 }
00262
00263 void work(void)
00264
00265 {
00266 FILE *j, *f;
00267 char file[PATH_MAX+1], *pf=file;
00268 int c;
00269 struct job *job;
00270
00271 job= jobs;
00272 jobs= jobs->next;
00273
00274 if ((j= fopen(job->name, "r")) == nil) {
00275 joberr(job->name);
00276 return;
00277 }
00278
00279 do {
00280 if (pf == file + sizeof(file) || (c= getc(j)) == EOF) {
00281 fclose(j);
00282 joberr(job->name);
00283 return;
00284 }
00285 *pf++ = c;
00286 } while (c != 0);
00287
00288 fclose(j);
00289
00290 if ((f= fopen(file, "r")) == nil)
00291 fprintf(stderr, "lpd: can't read %s\n", file);
00292 else {
00293 print(f);
00294 fclose(f);
00295 }
00296 if (file[0] != '/' && unlink(file) < 0) report(file);
00297
00298 if (unlink(job->name) < 0) fatal(job->name);
00299 free(job);
00300 }
00301
00302 void getcap(void)
00303
00304 {
00305 char printcap[1024];
00306 int n;
00307
00308 if (tgetent(printcap, "lp") == 1) {
00309 if ((n= tgetnum("co")) > 0) ncols= n;
00310 if ((n= tgetnum("li")) > 0) nlines= n;
00311 }
00312 }
00313
00314 void haunt(void)
00315
00316 {
00317 int fd;
00318
00319 if ((fd= open("/dev/tty", O_RDONLY)) != -1) {
00320
00321 close(fd);
00322
00323 switch(fork()) {
00324 case -1: fatal("can't fork");
00325 case 0: break;
00326 default: exit(0);
00327 }
00328
00329 if ((fd= open("/dev/null", O_RDONLY)) < 0) fatal("/dev/null");
00330 dup2(fd, 0);
00331 close(fd);
00332 if ((fd= open(LOG, O_WRONLY)) < 0) fatal(LOG);
00333 dup2(fd, 1);
00334 dup2(fd, 2);
00335 close(fd);
00336 setsid();
00337 }
00338
00339 getcap();
00340
00341 do {
00342 if ((lp= open(PRINTER, O_WRONLY)) < 0) {
00343
00344 if (errno == EBUSY) exit(0);
00345 fatal(PRINTER);
00346 }
00347
00348 while (job()) work();
00349
00350 close(lp);
00351 } while (job());
00352 }
00353
00354 int main(int argc, char **argv)
00355 {
00356 if (argc > 2) {
00357 fprintf(stderr, "Usage: %s [path | stdin < path]\n", argv[0]);
00358 exit(1);
00359 }
00360
00361 umask(0077);
00362
00363 if (chdir(SPOOL) < 0) fatal(SPOOL);
00364
00365 if (argc == 2) spool(argv[1]);
00366
00367 haunt();
00368 }