1 /* lpd 1.6 - Printer daemon Author: Kees J. Bot
10 #include <sys/types.h>
17 char PRINTER
[] = "/dev/lp";
18 char SPOOL
[] = "/usr/spool/lpd";
19 char LOG
[] = "/dev/log";
21 void report(char *mess
)
23 fprintf(stderr
, "lpd: %s: %s\n", mess
, strerror(errno
));
26 void fatal(char *mess
)
32 char jobX
[] = "jobXXXXXX";
33 char tmpX
[] = "tmpXXXXXX";
35 void spoolerr(char *file
)
42 void spool(char *path
)
43 /* Place a file into the spool directory, either by copying it, or by leaving
56 if ((f
= open(path
, O_RDONLY
)) >= 0) {
65 if ((t
= fopen(tmpX
, "w")) == nil
) spoolerr(tmpX
);
67 while ((c
= getchar()) != EOF
&& putc(c
, t
) != EOF
) {}
69 if (ferror(stdin
)) spoolerr(path
);
71 if (ferror(t
) || fclose(t
) == EOF
) spoolerr(tmpX
);
76 if ((j
= open(jobX
, O_WRONLY
|O_CREAT
|O_EXCL
, 0000)) < 0) spoolerr(jobX
);
79 if (write(j
, file
, strlen(file
)+1) < 0
80 || write(j
, &u
, sizeof(u
)) < 0
81 || write(j
, path
, strlen(path
)+1) < 0
83 || chmod(jobX
, 0600) < 0
90 char name
[sizeof(jobX
)];
94 /* Look for print jobs in the spool directory. Make a list of them sorted
95 * by age. Return true iff the list is nonempty.
100 struct job
*newjob
, **ajob
;
103 if (jobs
!= nil
) return 1;
105 if ((spool
= opendir(".")) == nil
) fatal(SPOOL
);
107 while ((entry
= readdir(spool
)) != nil
) {
108 if (strncmp(entry
->d_name
, "job", 3) != 0) continue;
110 if (stat(entry
->d_name
, &st
) < 0
111 || (st
.st_mode
& 0777) == 0000) continue;
113 if ((newjob
= malloc(sizeof(*newjob
))) == nil
) fatal("malloc()");
114 newjob
->age
= st
.st_mtime
;
115 strcpy(newjob
->name
, entry
->d_name
);
118 while (*ajob
!= nil
&& (*ajob
)->age
< newjob
->age
)
119 ajob
= &(*ajob
)->next
;
129 /* What to do with control-X:
131 * 1 give up on controlling the printer, assume user knows how printer works,
135 0, 1, 1, 1, 1, 1, 1, 0, /* \0, \a don't show. */
136 2, 2, 2, 1, 2, 2, 1, 1, /* \b, \t, \n, \f, \r */
137 1, 1, 1, 1, 1, 1, 1, 1,
138 1, 1, 1, 1, 1, 1, 1, 1
143 int count
, column
, line
, ncols
= 80, nlines
= 66;
146 /* Copy the characters in the output buffer to the printer, with retries if
153 int retry
= 0, complain
= 0;
156 while ((r
= write(lp
, bp
, count
)) < 0) {
157 if (errno
!= EAGAIN
) fatal(PRINTER
);
158 if (retry
== complain
) {
160 "lpd: %s: Printer out of paper\n",
162 complain
= retry
+ 60;
174 /* Send characters to the output buffer to be printed and do so if the buffer
175 * is full. Track the position of the write-head in `column' and `line'.
195 if (++column
> ncols
) { line
++; column
= 1; }
197 if (line
== nlines
) line
= 0;
199 if (count
== BUFSIZ
) flush();
203 /* Send the contents of an open file to the printer. Expand tabs and change
204 * linefeed to a carriage-return linefeed sequence. Print a formfeed at the
205 * end if needed to reach the top of the next page. If a control character
206 * is printed that we do not know about, then the user is assumed to know
207 * what they are doing, so output processing is disabled.
212 count
= column
= line
= 0;
214 while ((c
= getc(f
)) != EOF
) {
216 switch (control
[c
]) {
217 case 0: continue; /* Ignore this one. */
219 /* Can't handle this junk, assume smart user. */
222 if (count
== BUFSIZ
) flush();
223 } while ((c
= getc(f
)) != EOF
);
239 } while (column
& 07);
242 if (column
> 0) put(c
);
248 if (column
> 0) { put('\r'); put('\n'); }
249 if (line
> 0) put('\f');
254 void joberr(char *job
)
256 fprintf(stderr
, "lpd: something is wrong with %s\n", job
);
258 if (unlink(job
) < 0) fatal("can't remove it");
262 /* Print all the jobs in the job list. */
265 char file
[PATH_MAX
+1], *pf
=file
;
272 if ((j
= fopen(job
->name
, "r")) == nil
) {
278 if (pf
== file
+ sizeof(file
) || (c
= getc(j
)) == EOF
) {
288 if ((f
= fopen(file
, "r")) == nil
)
289 fprintf(stderr
, "lpd: can't read %s\n", file
);
294 if (file
[0] != '/' && unlink(file
) < 0) report(file
);
296 if (unlink(job
->name
) < 0) fatal(job
->name
);
301 /* Find the line printer dimensions in the termcap database under "lp". */
306 if (tgetent(printcap
, "lp") == 1) {
307 if ((n
= tgetnum("co")) > 0) ncols
= n
;
308 if ((n
= tgetnum("li")) > 0) nlines
= n
;
313 /* Become a daemon, print jobs while there are any, exit. */
317 if ((fd
= open("/dev/tty", O_RDONLY
)) != -1) {
318 /* We have a controlling tty! Disconnect. */
322 case -1: fatal("can't fork");
327 if ((fd
= open("/dev/null", O_RDONLY
)) < 0) fatal("/dev/null");
330 if ((fd
= open(LOG
, O_WRONLY
)) < 0) fatal(LOG
);
340 if ((lp
= open(PRINTER
, O_WRONLY
)) < 0) {
342 if (errno
== EBUSY
) exit(0);
346 while (job()) work();
352 int main(int argc
, char **argv
)
355 fprintf(stderr
, "Usage: %s [path | stdin < path]\n", argv
[0]);
361 if (chdir(SPOOL
) < 0) fatal(SPOOL
);
363 if (argc
== 2) spool(argv
[1]);