1 /* lpd 1.5 - 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
) {
22 fprintf(stderr
, "lpd: %s: %s\n", mess
, strerror(errno
));
25 void fatal(char *mess
) {
30 char jobX
[] = "jobXXXXXX";
31 char tmpX
[] = "tmpXXXXXX";
33 void spoolerr(char *file
) {
41 void spool(char *path
) {
43 /* Place a file into the spool directory, either by copying it,
44 * or by leaving a reference.
56 if ((f
= open(path
, O_RDONLY
)) >= 0) {
65 if ((t
= fopen(tmpX
, "w")) == nil
)
68 while ( (c
= getchar()) != EOF
&& putc(c
,t
) != EOF
)
74 if (ferror(t
) || fclose(t
) == EOF
)
80 if ((j
= open(jobX
, O_WRONLY
|O_CREAT
|O_EXCL
, 0000)) < 0)
84 if (write(j
, file
, strlen(file
)+1) < 0 || write(j
, &u
, sizeof(u
)) < 0
85 || write(j
, path
, strlen(path
)+1) < 0
87 || chmod(jobX
, 0600) < 0)
94 char name
[sizeof(jobX
)];
99 /* Look for print jobs in the spool directory. Make a list of them sorted
100 * by age. Return true iff the list is nonempty.
104 struct dirent
*entry
;
105 struct job
*newjob
, **ajob
;
111 if ((spool
= opendir(".")) == nil
)
114 while ((entry
= readdir(spool
)) != nil
) {
115 if (strncmp(entry
->d_name
, "job", 3) != 0)
118 if (stat(entry
->d_name
, &st
) < 0 || (st
.st_mode
& 0777) == 0000)
121 if ((newjob
= malloc(sizeof(*newjob
))) == nil
)
124 newjob
->age
= st
.st_mtime
;
125 strcpy(newjob
->name
, entry
->d_name
);
128 while (*ajob
!= nil
&& (*ajob
)->age
< newjob
->age
)
129 ajob
= &(*ajob
)->next
;
139 /* What to do with control-X:
141 * 1 give up on controlling the printer,
142 * assume user knows how printer works,
146 0, 1, 1, 1, 1, 1, 1, 0, /* \0, ^G don't show. */
147 1, 2, 2, 1, 2, 2, 1, 1, /* \t, \n, \f, \r */
148 1, 1, 1, 1, 1, 1, 1, 1,
149 1, 1, 1, 1, 1, 1, 1, 1
154 int count
, column
, line
, ncols
= 80, nlines
= 66;
158 /* Copy the characters in the output buffer to the printer, with retries if
165 int retry
= 0, complain
= 0;
168 while ((r
= write(lp
, bp
, count
)) < 0) {
171 if (retry
== complain
) {
172 fprintf(stderr
, "lpd: %s: Printer out of paper\n", PRINTER
);
173 complain
= retry
+ 60;
186 /* Send characters to the output buffer to be printed and do so if the buffer
187 * is full. Track the position of the write-head in `column' and `line'.
195 } else if (c
== '\r') {
197 } else if (c
== '\n') {
199 } else if (++column
> ncols
) {
210 void print(FILE *f
) {
212 /* Send the contents of an open file to the printer. Expand tabs and change
213 * linefeed to a carriage-return linefeed sequence. Print a formfeed at the
214 * end if needed to reach the top of the next page. If a control character
215 * is printed that we do not know about, then the user is assumed to know
216 * what they are doing, so output processing is disabled.
221 count
= column
= line
= 0;
223 while ((c
= getc(f
)) != EOF
) {
226 case '\t': /* Tab spaces to next 8th column */
229 } while (column
& 7);
231 case '\n': /* Newline => CR/LF */
235 default: /* Check anything else */
237 case 1: /* Assume smart user */
242 } while ((c
= getc(f
)) != EOF
);
245 case 2: /* Print this one */
247 case 0: /* Ignore this one */
265 void joberr(char *job
) {
266 fprintf(stderr
, "lpd: something is wrong with %s\n", job
);
268 fatal("can't remove it");
273 /* Print all the jobs in the job list. */
275 char file
[257], *pf
=file
;
283 if ((j
= fopen(job
->name
, "r")) == nil
) {
289 if (pf
== file
+ sizeof(file
) || (c
= getc(j
)) == EOF
) {
299 if ((f
= fopen(file
, "r")) == nil
)
300 fprintf(stderr
, "lpd: can't read %s\n", file
);
305 if (file
[0] != '/' && unlink(file
) < 0)
308 if (unlink(job
->name
) < 0)
315 /* Find the line printer dimensions in the termcap database under "lp". */
320 if (tgetent(printcap
, "lp") == 1) {
321 if ((n
= tgetnum("co")) > 0) ncols
= n
;
322 if ((n
= tgetnum("li")) > 0) nlines
= n
;
328 /* Become a daemon, print jobs while there are any, exit. */
332 if ((fd
= open("/dev/tty", O_RDONLY
)) != -1) {
333 /* We have a controlling tty! Disconnect. */
345 if ((fd
= open("/dev/null", O_RDONLY
)) < 0)
349 if ((fd
= open(LOG
, O_WRONLY
)) < 0)
360 if ((lp
= open(PRINTER
, O_WRONLY
)) < 0) {
374 int main(int argc
, char **argv
) {
376 fprintf(stderr
, "Usage: %s [path | stdin < path]\n", argv
[0]);
382 if (chdir(SPOOL
) < 0)