1 /* $OpenBSD: lp.c,v 1.4 2022/12/28 21:30:17 jmc Exp $ */
2
3 /*
4 * Copyright (c) 2017 Eric Faurot <eric@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20 #include <sys/mount.h>
21 #include <sys/stat.h>
22
23 #include <ctype.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <signal.h>
29 #include <stdarg.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33
34 #include "lp.h"
35
36 #include "log.h"
37
38 #define XXX_PID_MAX 99999
39
40 struct qentry {
41 char *name;
42 time_t mtime;
43 };
44
45 static int readent(struct lp_printer *, char *);
46 static int qentrycmp(const void *, const void *);
47 static int fullpath(struct lp_printer *, const char *, char *, size_t);
48 static int checksize(struct lp_printer *, size_t);
49
50 static int scanning;
51 static char *db[] = {
52 _PATH_PRINTCAP,
53 NULL,
54 };
55
56 /*
57 * Fill a printer structure from its /etc/printcap entry.
58 * Return 0 on success, or -1 on error.
59 */
60 int
lp_getprinter(struct lp_printer * lp,const char * name)61 lp_getprinter(struct lp_printer *lp, const char *name)
62 {
63 char *buf = NULL;
64 int r;
65
66 memset(lp, 0, sizeof(*lp));
67
68 r = cgetent(&buf, db, name);
69 if (r == 0)
70 r = readent(lp, buf);
71 free(buf);
72
73 switch (r) {
74 case -3:
75 log_warnx("%s: potential reference loop", name);
76 break;
77 case -2:
78 log_warn("%s", name);
79 break;
80 case -1:
81 log_warnx("%s: unknown printer", name);
82 break;
83 case 0:
84 return 0;
85 case 1:
86 log_warnx("%s: unresolved tc expansion", name);
87 break;
88 default:
89 log_warnx("%s: unexpected return value %d", name, r);
90 }
91
92 lp_clearprinter(lp);
93 return -1;
94 }
95
96 /*
97 * Iterate over /etc/printcap and fill the printer structure from the next
98 * entry, if any.
99 *
100 * Return 0 if no entry is found.
101 * 1 if a printer is filled.
102 * -1 on error, and set errno.
103 */
104 int
lp_scanprinters(struct lp_printer * lp)105 lp_scanprinters(struct lp_printer *lp)
106 {
107 char *buf;
108 int r, saved_errno;
109
110 if (scanning++ == 0)
111 r = cgetfirst(&buf, db);
112 else
113 r = cgetnext(&buf, db);
114
115 if (r == 0) {
116 cgetclose();
117 scanning = 0;
118 return 0;
119 } else if (r == 1) {
120 memset(lp, 0, sizeof(*lp));
121 r = readent(lp, buf);
122 free(buf);
123 if (r == -2)
124 goto fail;
125 return 1;
126 } else if (r == -1)
127 fatal("cannot open %s", _PATH_PRINTCAP);
128 else if (r == -2)
129 errno = ELOOP; /* potential reference loop */
130
131 fail:
132 saved_errno = errno;
133 lp_clearprinter(lp);
134 cgetclose();
135 scanning = 0;
136 errno = saved_errno;
137 return -1;
138 }
139
140 static int
readent(struct lp_printer * lp,char * buf)141 readent(struct lp_printer *lp, char *buf)
142 {
143 char *s;
144
145 s = strchr(buf, ':');
146 if (s)
147 *s = '\0';
148 lp->lp_name = strdup(buf);
149 if (s)
150 *s = ':';
151 if (lp->lp_name == NULL)
152 return -2;
153
154 s = lp->lp_name;
155 while ((s = strchr(s, '|'))) {
156 *s++ = '\0';
157 if (lp->lp_aliascount < LP_MAXALIASES)
158 lp->lp_aliases[lp->lp_aliascount++] = s;
159 }
160
161 #define CGETSTR(x) if (cgetstr(buf, #x, &(lp->lp_ ## x)) == -2) \
162 goto fail
163 #define CGETNUM(x, d) if (cgetnum(buf, #x, &(lp->lp_ ## x)) == -1) \
164 (lp->lp_ ## x) = d;
165 #define CGETBOOL(x) lp->lp_ ## x = cgetcap(buf, #x, ':') ? 1 : 0
166
167 CGETSTR(af);
168 CGETNUM(br, 0);
169 CGETSTR(cf);
170 CGETSTR(df);
171 CGETSTR(ff);
172 CGETBOOL(fo);
173 CGETSTR(gf);
174 CGETBOOL(hl);
175 CGETBOOL(ic);
176 CGETSTR(if);
177 CGETSTR(lf);
178 CGETSTR(lo);
179 CGETSTR(lp);
180 CGETNUM(mc, 0);
181 CGETSTR(ms);
182 CGETNUM(mx, 0);
183 CGETSTR(nd);
184 CGETSTR(nf);
185 CGETSTR(of);
186 CGETNUM(pc, DEFAULT_PC);
187 CGETNUM(pl, DEFAULT_PL);
188 CGETNUM(pw, DEFAULT_PW);
189 CGETNUM(px, 0);
190 CGETNUM(py, 0);
191 CGETSTR(rf);
192 CGETSTR(rg);
193 CGETSTR(rm);
194 CGETSTR(rp);
195 CGETBOOL(rs);
196 CGETBOOL(rw);
197 CGETBOOL(sb);
198 CGETBOOL(sc);
199 CGETSTR(sd);
200 CGETBOOL(sf);
201 CGETBOOL(sh);
202 CGETSTR(st);
203 CGETSTR(tf);
204 CGETSTR(tr);
205 CGETSTR(vf);
206
207 if (lp->lp_rm && lp->lp_rm[0]) {
208 lp->lp_type = PRN_LPR;
209 lp->lp_host = lp->lp_rm;
210 lp->lp_port = NULL;
211 }
212 else if (strchr(LP_LP(lp), '@')) {
213 lp->lp_type = PRN_NET;
214 lp->lp_port = strdup(LP_LP(lp));
215 lp->lp_host = strchr(lp->lp_port, '@');
216 *lp->lp_host++ = '\0';
217 }
218 else {
219 lp->lp_type = PRN_LOCAL;
220 }
221
222 return 0;
223 fail:
224 return -2;
225 }
226
227 void
lp_clearprinter(struct lp_printer * lp)228 lp_clearprinter(struct lp_printer *lp)
229 {
230 free(lp->lp_name);
231 free(lp->lp_port);
232 if (lp->lp_lock)
233 fclose(lp->lp_lock);
234 free(lp->lp_af);
235 free(lp->lp_cf);
236 free(lp->lp_df);
237 free(lp->lp_ff);
238 free(lp->lp_gf);
239 free(lp->lp_if);
240 free(lp->lp_lf);
241 free(lp->lp_lo);
242 free(lp->lp_lp);
243 free(lp->lp_ms);
244 free(lp->lp_nd);
245 free(lp->lp_nf);
246 free(lp->lp_of);
247 free(lp->lp_rf);
248 free(lp->lp_rg);
249 free(lp->lp_rm);
250 free(lp->lp_rp);
251 free(lp->lp_sd);
252 free(lp->lp_st);
253 free(lp->lp_tf);
254 free(lp->lp_tr);
255 free(lp->lp_vf);
256 memset(lp, 0, sizeof(*lp));
257 }
258
259 static int
qentrycmp(const void * aa,const void * bb)260 qentrycmp(const void *aa, const void *bb)
261 {
262 const struct qentry *a = aa, *b = bb;
263
264 if (a->mtime < b->mtime)
265 return -1;
266 if (a->mtime > b->mtime)
267 return 1;
268
269 return strcmp(a->name, b->name);
270 }
271
272 /*
273 * Read the printer queue content.
274 * Return the task count, or -1 on error.
275 */
276 int
lp_readqueue(struct lp_printer * lp,struct lp_queue * q)277 lp_readqueue(struct lp_printer *lp, struct lp_queue *q)
278 {
279 struct qentry *qe = NULL, *tqe;
280 struct dirent *d;
281 struct stat st;
282 size_t len, sz, nqi, nqe = 0, nqa = 0, n, i;
283 char path[PATH_MAX], *end;
284 DIR *dp= NULL;
285
286 len = strlcpy(path, LP_SD(lp), sizeof(path));
287 if (len == 0 || len >= sizeof(path)) {
288 log_warn("%s: %s: invalid spool directory name",
289 __func__, LP_SD(lp));
290 goto fail;
291 }
292
293 if ((dp = opendir(path)) == NULL) {
294 log_warn("%s: opendir", __func__);
295 goto fail;
296 }
297
298 if (fstat(dirfd(dp), &st) == -1) {
299 log_warn("%s: fstat", __func__);
300 goto fail;
301 }
302 /* Assume half the files are cf files. */
303 nqi = st.st_nlink / 2;
304
305 if (path[len-1] != '/') {
306 len = strlcat(path, "/", sizeof(path));
307 if (len >= sizeof(path)) {
308 errno = ENAMETOOLONG;
309 log_warn("%s: strlcat", __func__);
310 goto fail;
311 }
312 }
313 end = path + len;
314 sz = sizeof(path) - len;
315
316 errno = 0;
317 while ((d = readdir(dp))) {
318 if (d->d_name[0] != 'c' || d->d_name[1] != 'f')
319 continue;
320
321 if (strlen(d->d_name) < 7)
322 continue;
323
324 if (!isdigit((unsigned char)d->d_name[3]) ||
325 !isdigit((unsigned char)d->d_name[4]) ||
326 !isdigit((unsigned char)d->d_name[5]))
327 continue;
328
329 if (strlcpy(end, d->d_name, sz) >= sz) {
330 errno = ENAMETOOLONG;
331 log_warn("%s: strlcat", __func__);
332 goto fail;
333 }
334
335 if (stat(path, &st) == -1) {
336 log_warn("%s: stat", __func__);
337 goto fail;
338 }
339
340 if (nqe == nqa) {
341 n = nqa ? (nqa + 5) : nqi;
342 tqe = recallocarray(qe, nqa, n, sizeof(*qe));
343 if (tqe == NULL) {
344 log_warn("%s: recallocarray", __func__);
345 goto fail;
346 }
347 qe = tqe;
348 nqa = n;
349 }
350
351 if ((qe[nqe].name = strdup(d->d_name)) == NULL) {
352 log_warn("%s: strdup", __func__);
353 goto fail;
354 }
355 qe[nqe].mtime = st.st_mtime;
356 nqe++;
357 }
358 if (errno) {
359 log_warn("%s: readdir", __func__);
360 goto fail;
361 }
362 closedir(dp);
363 dp = NULL;
364
365 qsort(qe, nqe, sizeof(*qe), qentrycmp);
366
367 q->count = nqe;
368 q->cfname = calloc(nqe, sizeof(*q->cfname));
369 if (q->cfname == NULL) {
370 log_warn("%s: calloc", __func__);
371 goto fail;
372 }
373 for (i = 0; i < nqe; i++)
374 q->cfname[i] = qe[i].name;
375
376 free(qe);
377 return nqe;
378
379 fail:
380 if (dp)
381 closedir(dp);
382 for (i = 0; i < nqe; i++)
383 free(qe[i].name);
384 free(qe);
385 lp_clearqueue(q);
386 return -1;
387 }
388
389 void
lp_clearqueue(struct lp_queue * q)390 lp_clearqueue(struct lp_queue *q)
391 {
392 int i;
393
394 for (i = 0; i < q->count; i++)
395 free(q->cfname[i]);
396 free(q->cfname);
397 }
398
399 static int
fullpath(struct lp_printer * lp,const char * fname,char * dst,size_t sz)400 fullpath(struct lp_printer *lp, const char *fname, char *dst, size_t sz)
401 {
402 int r;
403
404 r = snprintf(dst, sz, "%s/%s", LP_SD(lp), fname);
405 if (r < 0 || (size_t)r >= sz) {
406 errno = ENAMETOOLONG;
407 return -1;
408 }
409
410 return 0;
411 }
412
413 /*
414 * fopen(3) a file in the printer spooldir for reading.
415 */
416 FILE *
lp_fopen(struct lp_printer * lp,const char * fname)417 lp_fopen(struct lp_printer *lp, const char *fname)
418 {
419 char path[PATH_MAX];
420
421 if (fullpath(lp, fname, path, sizeof(path)) == -1)
422 return NULL;
423
424 return fopen(path, "r");
425 }
426
427 /*
428 * unlink(2) a file in the printer spooldir.
429 */
430 int
lp_unlink(struct lp_printer * lp,const char * fname)431 lp_unlink(struct lp_printer *lp, const char *fname)
432 {
433 char path[PATH_MAX];
434
435 if (fullpath(lp, fname, path, sizeof(path)) == -1)
436 return -1;
437
438 return unlink(path);
439 }
440
441 /*
442 * stat(2) a file in the printer spooldir.
443 */
444 int
lp_stat(struct lp_printer * lp,const char * fname,struct stat * st)445 lp_stat(struct lp_printer *lp, const char *fname, struct stat *st)
446 {
447 char path[PATH_MAX];
448
449 if (fullpath(lp, fname, path, sizeof(path)) == -1)
450 return -1;
451
452 return stat(path, st);
453 }
454
455 /*
456 * Grab the lockfile for this printer, and associate it to the printer.
457 * Return -1 on error or 0 otherwise.
458 */
459 int
lp_lock(struct lp_printer * lp)460 lp_lock(struct lp_printer *lp)
461 {
462 char path[PATH_MAX];
463 struct stat st;
464 int fd, saved_errno;
465
466 if (lp->lp_lock) {
467 errno = EWOULDBLOCK;
468 return -1;
469 }
470
471 if (fullpath(lp, LP_LO(lp), path, sizeof(path)) == -1) {
472 log_warn("%s: %s", __func__, LP_LO(lp));
473 return -1;
474 }
475
476 fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_NONBLOCK|O_EXLOCK|O_TRUNC,
477 0640);
478 if (fd == -1) {
479 if (errno != EWOULDBLOCK)
480 log_warn("%s: open", __func__);
481 return -1;
482 }
483
484 if (fstat(fd, &st) == -1) {
485 log_warn("%s: fstat", __func__);
486 saved_errno = errno;
487 (void)close(fd);
488 errno = saved_errno;
489 return -1;
490 }
491
492 if (!S_ISREG(st.st_mode)) {
493 errno = EFTYPE;
494 log_warnx("%s: %s: Not a regular file", __func__, path);
495 (void)close(fd);
496 return -1;
497 }
498
499 if ((lp->lp_lock = fdopen(fd, "w")) == NULL) {
500 log_warn("%s: fdopen", __func__);
501 saved_errno = errno;
502 (void)close(fd);
503 errno = saved_errno;
504 return -1;
505 }
506
507 lp_setcurrtask(lp, NULL);
508
509 return 0;
510 }
511
512 /*
513 * Truncate the lock file and close it.
514 */
515 void
lp_unlock(struct lp_printer * lp)516 lp_unlock(struct lp_printer *lp)
517 {
518 if (ftruncate(fileno(lp->lp_lock), 0) == -1)
519 log_warn("%s: ftruncate", __func__);
520 if (fclose(lp->lp_lock) == EOF)
521 log_warn("%s: fclose", __func__);
522 lp->lp_lock = NULL;
523 }
524
525 int
lp_getqueuestate(struct lp_printer * lp,int reset,int * qstate)526 lp_getqueuestate(struct lp_printer *lp, int reset, int *qstate)
527 {
528 FILE *fp;
529 struct stat st;
530 int saved_errno;
531
532 *qstate = 0;
533
534 fp = lp->lp_lock;
535 if (lp->lp_lock == NULL) {
536 fp = lp_fopen(lp, LP_LO(lp));
537 if (fp == NULL) {
538 if (errno == ENOENT)
539 return 0;
540 log_warn("%s: lp_fopen", __func__);
541 return -1;
542 }
543 }
544
545 if (fstat(fileno(fp), &st) == -1) {
546 log_warn("%s: fstat", __func__);
547 if (lp->lp_lock == NULL) {
548 saved_errno = errno;
549 (void)fclose(fp);
550 errno = saved_errno;
551 }
552 return -1;
553 }
554
555 if (st.st_mode & S_IXUSR)
556 *qstate |= LPQ_PRINTER_DOWN;
557 if (st.st_mode & S_IXGRP)
558 *qstate |= LPQ_QUEUE_OFF;
559 if (st.st_mode & S_IXOTH) {
560 *qstate |= LPQ_QUEUE_UPDATED;
561 if (reset) {
562 st.st_mode &= ~S_IXOTH & 0777;
563 if (fchmod(fileno(lp->lp_lock), st.st_mode) == -1)
564 log_warn("%s: fchmod", __func__);
565 }
566 }
567
568 if (lp->lp_lock == NULL)
569 fclose(fp);
570
571 return 0;
572 }
573
574 /*
575 * Update the current task description in the lock file.
576 * The lock file must be opened.
577 */
578 void
lp_setcurrtask(struct lp_printer * lp,const char * cfile)579 lp_setcurrtask(struct lp_printer *lp, const char *cfile)
580 {
581 int r;
582
583 if (ftruncate(fileno(lp->lp_lock), 0) == -1)
584 log_warn("%s: ftruncate", __func__);
585
586 if (cfile)
587 r = fprintf(lp->lp_lock, "%d\n%s\n", (int)getpid(), cfile);
588 else
589 r = fprintf(lp->lp_lock, "%d\n", (int)getpid());
590 if (r < 0)
591 log_warn("%s: fprintf", __func__);
592
593 if (fflush(lp->lp_lock) != 0)
594 log_warn("%s: fflush", __func__);
595 }
596
597 /*
598 * Find the pid of the running process if any, and the task being printed.
599 *
600 * Returns -1 on error (errno set).
601 * 0 if no process is running.
602 * 1 if a printer process is up.
603 * 2 if a printer process is up and a file is being printed.
604 */
605 int
lp_getcurrtask(struct lp_printer * lp,pid_t * ppid,char * dst,size_t dstsz)606 lp_getcurrtask(struct lp_printer *lp, pid_t *ppid, char *dst, size_t dstsz)
607 {
608 FILE *fp;
609 const char *errstr;
610 char *line = NULL;
611 size_t linesz = 0;
612 ssize_t len;
613 pid_t pid;
614 int r, saved_errno;
615
616 pid = *ppid = 0;
617 dst[0] = '\0';
618 r = -1;
619
620 fp = lp_fopen(lp, LP_LO(lp));
621 if (fp == NULL) {
622 if (errno == ENOENT)
623 return 0;
624 log_warn("%s: lp_fopen", __func__);
625 return -1;
626 }
627
628 while ((len = getline(&line, &linesz, fp)) != -1) {
629 if (line[len-1] == '\n')
630 line[len-1] = '\0';
631
632 /* Read filename. */
633 if (pid) {
634 (void)strlcpy(dst, line, dstsz);
635 break;
636 }
637
638 pid = strtonum(line, 2, XXX_PID_MAX, &errstr);
639 if (errstr) {
640 log_warn("%s: strtonum", __func__);
641 goto done;
642 }
643 }
644
645 if ((errno = ferror(fp))) {
646 log_warn("%s: getline", __func__);
647 goto done;
648 }
649
650 r = 0;
651 if (pid == 0)
652 goto done;
653
654 if (kill(pid, 0) == -1 && errno != EPERM) {
655 if (errno != ESRCH)
656 log_warn("%s: kill", __func__);
657 goto done;
658 }
659
660 *ppid = pid;
661 r = dst[0] ? 2 : 1;
662
663 done:
664 free(line);
665 saved_errno = errno;
666 (void)fclose(fp);
667 errno = saved_errno;
668 return r;
669 }
670
671 /*
672 * Read the current printer status file.
673 * Return -1 on error, 0 on success.
674 */
675 int
lp_getstatus(struct lp_printer * lp,char * buf,size_t bufsz)676 lp_getstatus(struct lp_printer *lp, char *buf, size_t bufsz)
677 {
678 size_t len;
679 char *line;
680 FILE *fp;
681 int saved_errno;
682
683 buf[0] = '\0';
684
685 fp = lp_fopen(lp, LP_ST(lp));
686 if (fp == NULL) {
687 if (errno == ENOENT)
688 return 0;
689 log_warn("%s: lp_fopen", __func__);
690 return -1;
691 }
692
693 line = fgetln(fp, &len);
694 if (line) {
695 if (len >= bufsz)
696 len = bufsz - 1;
697 else if (line[len - 1] == '\n')
698 len--;
699 memmove(buf, line, len);
700 buf[len] = '\0';
701 }
702 else if ((errno = ferror(fp))) {
703 log_warn("%s: fgetln", __func__);
704 saved_errno = errno;
705 (void)fclose(fp);
706 errno = saved_errno;
707 return -1;
708 }
709
710 (void)fclose(fp);
711 return 0;
712 }
713
714 /*
715 * Update the current printer status.
716 */
717 void
lp_setstatus(struct lp_printer * lp,const char * fmt,...)718 lp_setstatus(struct lp_printer *lp, const char *fmt, ...)
719 {
720 va_list ap;
721 FILE *fp;
722 char path[PATH_MAX], *s;
723 int fd = -1, r, saved_errno;
724
725 va_start(ap, fmt);
726 r = vasprintf(&s, fmt, ap);
727 va_end(ap);
728
729 if (r == -1) {
730 log_warn("%s: vasprintf", __func__);
731 return;
732 }
733
734 if (fullpath(lp, LP_ST(lp), path, sizeof(path)) == -1) {
735 log_warn("%s: fullpath", __func__);
736 free(s);
737 return;
738 }
739
740 fd = open(path, O_WRONLY|O_CREAT|O_NOFOLLOW|O_EXLOCK|O_TRUNC, 0660);
741 if (fd == -1) {
742 log_warn("%s: open", __func__);
743 free(s);
744 return;
745 }
746
747 fp = fdopen(fd, "w");
748 if (fp == NULL) {
749 log_warn("%s: fdopen", __func__);
750 saved_errno = errno;
751 (void)close(fd);
752 free(s);
753 errno = saved_errno;
754 return;
755 }
756
757 r = fprintf(fp, "%s\n", s);
758
759 if (r <= 0) {
760 log_warn("%s: fprintf", __func__);
761 saved_errno = errno;
762 (void)fclose(fp);
763 free(s);
764 errno = saved_errno;
765 return;
766 }
767
768 (void)fclose(fp);
769 free(s);
770 }
771
772 /*
773 * Check that the given string is a valid filename for the spooler.
774 */
775 int
lp_validfilename(const char * fname,int cf)776 lp_validfilename(const char *fname, int cf)
777 {
778 size_t len, i;
779
780 len = strlen(fname);
781 if (len <= 6) /* strlen("cfA000") */
782 return 0;
783
784 if (fname[0] != (cf ? 'c' : 'd') ||
785 fname[1] != 'f' ||
786 fname[2] < 'A' ||
787 fname[2] > 'Z' ||
788 !isdigit((unsigned char)fname[3]) ||
789 !isdigit((unsigned char)fname[4]) ||
790 !isdigit((unsigned char)fname[5]))
791 return 0;
792
793 for (i = 6; i < len; i++)
794 if (!isalpha((unsigned char)fname[i]) &&
795 !isdigit((unsigned char)fname[i]) &&
796 strchr("-_.", (unsigned char)fname[i]) == NULL)
797 return 0;
798
799 return 1;
800 }
801
802 /*
803 * Create a new control or data file in the printer spooldir.
804 * Control files have there name changed to a temporary name. They are renamed
805 * to their final name by lp_commit().
806 */
807 int
lp_create(struct lp_printer * lp,int cf,size_t sz,const char * fname)808 lp_create(struct lp_printer *lp, int cf, size_t sz, const char *fname)
809 {
810 struct stat st;
811 char path[PATH_MAX];
812 int fd;
813
814 /* Make sure the file size is acceptable. */
815 if (checksize(lp, sz) == -1)
816 return -1;
817
818 if (fullpath(lp, fname, path, sizeof(path)) == -1) {
819 log_warn("%s: %s", __func__, fname);
820 return -1;
821 }
822
823 if (cf) {
824 /*
825 * Create a temporary file, but we want to avoid
826 * a collision with the final cf filename.
827 */
828 /* XXX this would require a lock on .seq */
829 path[strlen(LP_SD(lp)) + 1] = 'c';
830 if (stat(path, &st) == 0) {
831 errno = EEXIST;
832 log_warn("%s: %s", __func__, fname);
833 return -1;
834 }
835 path[strlen(LP_SD(lp)) + 1] = 't';
836 }
837
838 fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0660);
839 if (fd == -1)
840 log_warn("%s: open", __func__);
841
842 return fd;
843 }
844
845 /*
846 * Commit the job given by its temporary CF name.
847 * This is done by renaming the temporary CF file name to its final name.
848 * The functions return 0 on success, or -1 on error and set errno.
849 */
850 int
lp_commit(struct lp_printer * lp,const char * cf)851 lp_commit(struct lp_printer *lp, const char *cf)
852 {
853 char ipath[PATH_MAX], opath[PATH_MAX];
854
855 if (fullpath(lp, cf, ipath, sizeof(ipath)) == -1 ||
856 fullpath(lp, cf, opath, sizeof(opath)) == -1)
857 return -1;
858
859 ipath[strlen(LP_SD(lp)) + 1] = 't';
860 opath[strlen(LP_SD(lp)) + 1] = 'c';
861
862 return rename(ipath, opath);
863 }
864
865 /*
866 * Check if a file size is acceptable.
867 * Return -1 on error or if false (EFBIG or ENOSPC), 0 otherwise.
868 */
869 static int
checksize(struct lp_printer * lp,size_t sz)870 checksize(struct lp_printer *lp, size_t sz)
871 {
872 struct statfs st;
873 ssize_t len;
874 size_t linesz = 0;
875 off_t req, avail, minfree;
876 char *line = NULL;
877 const char *errstr;
878 FILE *fp;
879 int saved_errno;
880
881 if (sz == 0) {
882 errno = EINVAL;
883 return -1;
884 }
885
886 /* Check printer limit. */
887 if (lp->lp_mx && sz > (size_t)lp->lp_mx) {
888 errno = EFBIG;
889 return -1;
890 }
891
892 /*
893 * Check for minfree. Note that it does not really guarantee the
894 * directory will not be filled up anyway, since it's not taking
895 * other incoming files into account.
896 */
897 fp = lp_fopen(lp, "minfree");
898 if (fp == NULL) {
899 if (errno == ENOENT)
900 return 0;
901 log_warn("%s: lp_fopen", __func__);
902 return -1;
903 }
904
905 len = getline(&line, &linesz, fp);
906 saved_errno = errno;
907 (void)fclose(fp);
908 if (len == -1) {
909 errno = saved_errno;
910 return 0;
911 }
912
913 if (line[len - 1] == '\n')
914 line[len - 1] = '\0';
915 minfree = strtonum(line, 0, INT_MAX, &errstr);
916 free(line);
917
918 if (errstr)
919 return 0;
920
921 if (statfs(LP_SD(lp), &st) == -1)
922 return 0;
923
924 req = sz / 512 + (sz % 512) ? 1 : 0;
925 avail = st.f_bavail * (st.f_bsize / 512);
926 if (avail < minfree || (avail - minfree) < req) {
927 errno = ENOSPC;
928 return -1;
929 }
930
931 return 0;
932 }
933