chkprintcap.c revision 60938
131492Swollman/* 231492Swollman * Copyright 1997 Massachusetts Institute of Technology 331492Swollman * 431492Swollman * Permission to use, copy, modify, and distribute this software and 531492Swollman * its documentation for any purpose and without fee is hereby 631492Swollman * granted, provided that both the above copyright notice and this 731492Swollman * permission notice appear in all copies, that both the above 831492Swollman * copyright notice and this permission notice appear in all 931492Swollman * supporting documentation, and that the name of M.I.T. not be used 1031492Swollman * in advertising or publicity pertaining to distribution of the 1131492Swollman * software without specific, written prior permission. M.I.T. makes 1231492Swollman * no representations about the suitability of this software for any 1331492Swollman * purpose. It is provided "as is" without express or implied 1431492Swollman * warranty. 1531492Swollman * 1631492Swollman * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 1731492Swollman * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 1831492Swollman * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 1931492Swollman * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 2031492Swollman * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2131492Swollman * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2231492Swollman * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 2331492Swollman * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 2431492Swollman * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 2531492Swollman * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 2631492Swollman * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2731492Swollman * SUCH DAMAGE. 2831492Swollman */ 2931492Swollman 3031492Swollmanstatic const char copyright[] = 3131492Swollman "Copyright (C) 1997, Massachusetts Institute of Technology\r\n"; 3231492Swollmanstatic const char rcsid[] = 3350479Speter "$FreeBSD: head/usr.sbin/lpr/chkprintcap/chkprintcap.c 60938 2000-05-26 02:09:24Z jake $"; 3431492Swollman 3531492Swollman#include <sys/types.h> 3631492Swollman#include <sys/queue.h> 3731492Swollman#include <sys/stat.h> 3831492Swollman 3931492Swollman#include <err.h> 4031492Swollman#include <errno.h> 4131492Swollman#include <grp.h> 4231492Swollman#include <stdio.h> 4331492Swollman#include <string.h> 4431492Swollman#include <stdlib.h> 4531492Swollman#include <unistd.h> 4631492Swollman 4731492Swollman#include <sys/param.h> /* needed for lp.h but not used here */ 4831492Swollman#include <dirent.h> /* ditto */ 4931492Swollman#include "lp.h" 5031492Swollman#include "lp.local.h" 5131492Swollman 5231492Swollmanstatic void check_spool_dirs(void); 5331492Swollmanstatic int interpret_error(const struct printer *pp, int error); 5431492Swollmanstatic void make_spool_dir(const struct printer *pp); 5531492Swollmanstatic void note_spool_dir(const struct printer *pp, const struct stat *st); 5631492Swollmanstatic void usage(void) __dead2; 5731492Swollman 5831492Swollmanstatic int problems; /* number of problems encountered */ 5931492Swollman 6031492Swollman/* 6131492Swollman * chkprintcap - check the printcap file for syntactic and semantic errors 6231492Swollman * Returns the number of problems found. 6331492Swollman */ 6431492Swollmanint 6531492Swollmanmain(int argc, char **argv) 6631492Swollman{ 6731492Swollman int c, error, makedirs, more; 6831492Swollman struct printer myprinter, *pp; 6931492Swollman 7031492Swollman makedirs = 0; 7131492Swollman pp = &myprinter; 7231492Swollman 7331492Swollman while ((c = getopt(argc, argv, "df:")) != -1) { 7431492Swollman switch (c) { 7531492Swollman case 'd': 7631492Swollman makedirs = 1; 7731492Swollman break; 7831492Swollman 7931492Swollman case 'f': 8031492Swollman setprintcap(optarg); 8131492Swollman break; 8231492Swollman 8331492Swollman default: 8431492Swollman usage(); 8531492Swollman } 8631492Swollman } 8731492Swollman 8831492Swollman if (optind != argc) 8931492Swollman usage(); 9031492Swollman 9131492Swollman more = firstprinter(pp, &error); 9231492Swollman if (interpret_error(pp, error) && more) 9331492Swollman goto next; 9431492Swollman 9531492Swollman while (more) { 9631492Swollman struct stat stab; 9731492Swollman 9831492Swollman errno = 0; 9931492Swollman if (stat(pp->spool_dir, &stab) < 0) { 10031492Swollman if (errno == ENOENT && makedirs) { 10131492Swollman make_spool_dir(pp); 10231492Swollman } else { 10331492Swollman problems++; 10431492Swollman warn("%s: %s", pp->printer, pp->spool_dir); 10531492Swollman } 10631492Swollman } else { 10731492Swollman note_spool_dir(pp, &stab); 10831492Swollman } 10931492Swollman 11031492Swollman /* Make other validity checks here... */ 11131492Swollman 11231492Swollmannext: 11331492Swollman more = nextprinter(pp, &error); 11431492Swollman if (interpret_error(pp, error) && more) 11531492Swollman goto next; 11631492Swollman } 11731492Swollman check_spool_dirs(); 11831492Swollman return problems; 11931492Swollman} 12031492Swollman 12131492Swollman/* 12231492Swollman * Interpret the error code. Returns 1 if we should skip to the next 12331492Swollman * record (as this record is unlikely to make sense). If the problem 12431492Swollman * is very severe, exit. Otherwise, return zero. 12531492Swollman */ 12631492Swollmanstatic int 12731492Swollmaninterpret_error(const struct printer *pp, int error) 12831492Swollman{ 12931492Swollman switch(error) { 13031492Swollman case PCAPERR_OSERR: 13131492Swollman err(++problems, "reading printer database"); 13231492Swollman case PCAPERR_TCLOOP: 13331492Swollman ++problems; 13431492Swollman warnx("%s: loop detected in tc= expansion", pp->printer); 13531492Swollman return 1; 13631492Swollman case PCAPERR_TCOPEN: 13731492Swollman warnx("%s: unresolved tc= expansion", pp->printer); 13831492Swollman return 1; 13931492Swollman case PCAPERR_SUCCESS: 14031492Swollman break; 14131492Swollman default: 14231492Swollman errx(++problems, "unknown printcap library error %d", error); 14331492Swollman } 14431492Swollman return 0; 14531492Swollman} 14631492Swollman 14731492Swollman/* 14831492Swollman * Keep the list of spool directories. Note that we don't whine 14931492Swollman * until all spool directories are noted, so that all of the more serious 15031492Swollman * problems are noted first. We keep the list sorted by st_dev and 15131492Swollman * st_ino, so that the problem spool directories can be noted in 15231492Swollman * a single loop. 15331492Swollman */ 15431492Swollmanstruct dirlist { 15560938Sjake LIST_ENTRY(dirlist) link; 15631492Swollman struct stat stab; 15731492Swollman char *path; 15831492Swollman char *printer; 15931492Swollman}; 16031492Swollman 16160938Sjakestatic LIST_HEAD(, dirlist) dirlist; 16231492Swollman 16331492Swollmanstatic int 16431492Swollmanlessp(const struct dirlist *a, const struct dirlist *b) 16531492Swollman{ 16631492Swollman if (a->stab.st_dev == b->stab.st_dev) 16731492Swollman return a->stab.st_ino < b->stab.st_ino; 16831492Swollman return a->stab.st_dev < b->stab.st_dev; 16931492Swollman} 17031492Swollman 17131492Swollmanstatic int 17231492Swollmanequal(const struct dirlist *a, const struct dirlist *b) 17331492Swollman{ 17431492Swollman return ((a->stab.st_dev == b->stab.st_dev) 17531492Swollman && (a->stab.st_ino == b->stab.st_ino)); 17631492Swollman} 17731492Swollman 17831492Swollmanstatic void 17931492Swollmannote_spool_dir(const struct printer *pp, const struct stat *st) 18031492Swollman{ 18131492Swollman struct dirlist *dp, *dp2, *last; 18231492Swollman 18331492Swollman dp = malloc(sizeof *dp); 18431492Swollman if (dp == 0) 18531492Swollman err(++problems, "malloc(%lu)", (u_long)sizeof *dp); 18631492Swollman 18731492Swollman dp->stab = *st; 18831492Swollman dp->printer = strdup(pp->printer); 18931492Swollman if (dp->printer == 0) 19031492Swollman err(++problems, "malloc(%lu)", strlen(pp->printer) + 1UL); 19131492Swollman dp->path = strdup(pp->spool_dir); 19231492Swollman if (dp->path == 0) 19331492Swollman err(++problems, "malloc(%lu)", strlen(pp->spool_dir) + 1UL); 19431492Swollman 19531492Swollman last = 0; 19631492Swollman dp2 = dirlist.lh_first; 19731492Swollman while (dp2 && lessp(dp, dp2)) { 19831492Swollman last = dp2; 19931492Swollman dp2 = dp2->link.le_next; 20031492Swollman } 20131492Swollman 20231492Swollman if (last) { 20331492Swollman LIST_INSERT_AFTER(last, dp, link); 20431492Swollman } else { 20531492Swollman LIST_INSERT_HEAD(&dirlist, dp, link); 20631492Swollman } 20731492Swollman} 20831492Swollman 20931492Swollmanstatic void 21031492Swollmancheck_spool_dirs(void) 21131492Swollman{ 21231492Swollman struct dirlist *dp, *dp2; 21331492Swollman 21431492Swollman for (dp = dirlist.lh_first; dp; dp = dp2) { 21531492Swollman dp2 = dp->link.le_next; 21631492Swollman 21731492Swollman if (dp2 != 0 && equal(dp, dp2)) { 21831492Swollman ++problems; 21931492Swollman if (strcmp(dp->path, dp2->path) == 0) { 22031492Swollman warnx("%s and %s share the same spool, %s", 22131492Swollman dp->printer, dp2->printer, dp->path); 22231492Swollman } else { 22331492Swollman warnx("%s (%s) and %s (%s) are the same " 22431492Swollman "directory", dp->path, dp->printer, 22531492Swollman dp2->path, dp2->printer); 22631492Swollman } 22731492Swollman continue; 22831492Swollman } 22931492Swollman /* Should probably check owners and modes here. */ 23031492Swollman } 23131492Swollman} 23231492Swollman 23331492Swollman#ifndef SPOOL_DIR_MODE 23431492Swollman#define SPOOL_DIR_MODE (S_IRUSR | S_IWUSR | S_IXUSR \ 23531492Swollman | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) 23631492Swollman#endif 23731492Swollman 23831492Swollmanstatic void 23931492Swollmanmake_spool_dir(const struct printer *pp) 24031492Swollman{ 24131492Swollman char *sd = pp->spool_dir; 24231492Swollman struct group *gr; 24331492Swollman struct stat stab; 24431492Swollman 24531492Swollman if (mkdir(sd, S_IRUSR | S_IXUSR) < 0) { 24631492Swollman problems++; 24731492Swollman warn("%s: mkdir %s", pp->printer, sd); 24831492Swollman return; 24931492Swollman } 25031492Swollman gr = getgrnam("daemon"); 25131492Swollman if (gr == 0) 25231492Swollman errx(++problems, "cannot locate daemon group"); 25331492Swollman 25431492Swollman if (chown(sd, pp->daemon_user, gr->gr_gid) < 0) { 25531492Swollman ++problems; 25631492Swollman warn("%s: cannot change ownership to %ld:%ld", sd, 25731492Swollman (long)pp->daemon_user, (long)gr->gr_gid); 25831492Swollman return; 25931492Swollman } 26031492Swollman 26131492Swollman if (chmod(sd, SPOOL_DIR_MODE) < 0) { 26231492Swollman ++problems; 26331569Sjdp warn("%s: cannot change mode to %lo", sd, (long)SPOOL_DIR_MODE); 26431492Swollman return; 26531492Swollman } 26631492Swollman if (stat(sd, &stab) < 0) 26731492Swollman err(++problems, "stat: %s", sd); 26831492Swollman 26931492Swollman note_spool_dir(pp, &stab); 27031492Swollman} 27131492Swollman 27231492Swollmanstatic void 27331492Swollmanusage(void) 27431492Swollman{ 27531492Swollman fprintf(stderr, "usage:\n\tchkprintcap [-d] [-f printcapfile]\n"); 27631492Swollman exit(1); 27731492Swollman} 278