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"; 3231492Swollman 33117623Sgad#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */ 34117623Sgad__FBSDID("$FreeBSD$"); 35117623Sgad 3631492Swollman#include <sys/types.h> 3731492Swollman#include <sys/queue.h> 3831492Swollman#include <sys/stat.h> 3931492Swollman 4031492Swollman#include <err.h> 4131492Swollman#include <errno.h> 4231492Swollman#include <grp.h> 4331492Swollman#include <stdio.h> 4431492Swollman#include <string.h> 4531492Swollman#include <stdlib.h> 4631492Swollman#include <unistd.h> 4731492Swollman 4831492Swollman#include <sys/param.h> /* needed for lp.h but not used here */ 4931492Swollman#include <dirent.h> /* ditto */ 5031492Swollman#include "lp.h" 5131492Swollman#include "lp.local.h" 5288004Sgad#include "pathnames.h" 5388004Sgad#include "skimprintcap.h" 5431492Swollman 5531492Swollmanstatic void check_spool_dirs(void); 5631492Swollmanstatic int interpret_error(const struct printer *pp, int error); 5731492Swollmanstatic void make_spool_dir(const struct printer *pp); 5831492Swollmanstatic void note_spool_dir(const struct printer *pp, const struct stat *st); 5931492Swollmanstatic void usage(void) __dead2; 6031492Swollman 6131492Swollmanstatic int problems; /* number of problems encountered */ 6231492Swollman 6331492Swollman/* 6431492Swollman * chkprintcap - check the printcap file for syntactic and semantic errors 6531492Swollman * Returns the number of problems found. 6631492Swollman */ 6731492Swollmanint 6831492Swollmanmain(int argc, char **argv) 6931492Swollman{ 7088004Sgad struct skiminfo *skres; 7188004Sgad char *pcap_fname; 7288004Sgad int c, error, makedirs, more, queuecnt, verbosity; 7331492Swollman struct printer myprinter, *pp; 7431492Swollman 7531492Swollman makedirs = 0; 7688004Sgad queuecnt = 0; 7788004Sgad verbosity = 0; 7888004Sgad pcap_fname = NULL; 7931492Swollman pp = &myprinter; 8031492Swollman 8188004Sgad while ((c = getopt(argc, argv, "df:v")) != -1) { 8231492Swollman switch (c) { 8331492Swollman case 'd': 8431492Swollman makedirs = 1; 8531492Swollman break; 8631492Swollman 8731492Swollman case 'f': 8888004Sgad pcap_fname = strdup(optarg); 8988004Sgad setprintcap(pcap_fname); 9031492Swollman break; 9131492Swollman 9288004Sgad case 'v': 9388004Sgad verbosity++; 9488004Sgad break; 9588004Sgad 9631492Swollman default: 9731492Swollman usage(); 9831492Swollman } 9931492Swollman } 10031492Swollman 10131492Swollman if (optind != argc) 10231492Swollman usage(); 10331492Swollman 10488004Sgad if (pcap_fname == NULL) 10588004Sgad pcap_fname = strdup(_PATH_PRINTCAP); 10688004Sgad 10788004Sgad /* 10888004Sgad * Skim through the printcap file looking for simple user-mistakes 10988004Sgad * which will produce the wrong result for the user, but which may 11088004Sgad * be pretty hard for the user to notice. Such user-mistakes will 11188004Sgad * only generate warning messages. The (fatal-) problem count will 11288004Sgad * only be incremented if there is a system problem trying to read 11388004Sgad * the printcap file. 11488004Sgad */ 11588004Sgad skres = skim_printcap(pcap_fname, verbosity); 11688004Sgad if (skres->fatalerr) 11788004Sgad return (skres->fatalerr); 11888004Sgad 11988004Sgad /* 12088004Sgad * Now use the standard capability-db routines to check the values 12188004Sgad * in each of the queues defined in the printcap file. 12288004Sgad */ 12331492Swollman more = firstprinter(pp, &error); 12431492Swollman if (interpret_error(pp, error) && more) 12531492Swollman goto next; 12631492Swollman 12731492Swollman while (more) { 12831492Swollman struct stat stab; 12931492Swollman 13088004Sgad queuecnt++; 13131492Swollman errno = 0; 13231492Swollman if (stat(pp->spool_dir, &stab) < 0) { 13331492Swollman if (errno == ENOENT && makedirs) { 13431492Swollman make_spool_dir(pp); 13531492Swollman } else { 13631492Swollman problems++; 13731492Swollman warn("%s: %s", pp->printer, pp->spool_dir); 13831492Swollman } 13931492Swollman } else { 14031492Swollman note_spool_dir(pp, &stab); 14131492Swollman } 14231492Swollman 14388004Sgad /* Make other queue-specific validity checks here... */ 14431492Swollman 14531492Swollmannext: 14631492Swollman more = nextprinter(pp, &error); 14731492Swollman if (interpret_error(pp, error) && more) 14831492Swollman goto next; 14931492Swollman } 15088004Sgad 15131492Swollman check_spool_dirs(); 15288004Sgad 15388004Sgad if (queuecnt != skres->entries) { 15488004Sgad warnx("WARNING: found %d entries when skimming %s,", 15588004Sgad skres->entries, pcap_fname); 15688004Sgad warnx("WARNING: but only found %d queues to process!", 15788004Sgad queuecnt); 15888004Sgad } 15988004Sgad return (problems); 16031492Swollman} 16131492Swollman 16231492Swollman/* 16331492Swollman * Interpret the error code. Returns 1 if we should skip to the next 16431492Swollman * record (as this record is unlikely to make sense). If the problem 16531492Swollman * is very severe, exit. Otherwise, return zero. 16631492Swollman */ 16731492Swollmanstatic int 16831492Swollmaninterpret_error(const struct printer *pp, int error) 16931492Swollman{ 17031492Swollman switch(error) { 17131492Swollman case PCAPERR_OSERR: 17231492Swollman err(++problems, "reading printer database"); 17331492Swollman case PCAPERR_TCLOOP: 17431492Swollman ++problems; 17531492Swollman warnx("%s: loop detected in tc= expansion", pp->printer); 17631492Swollman return 1; 17731492Swollman case PCAPERR_TCOPEN: 17831492Swollman warnx("%s: unresolved tc= expansion", pp->printer); 17931492Swollman return 1; 18031492Swollman case PCAPERR_SUCCESS: 18131492Swollman break; 18231492Swollman default: 18331492Swollman errx(++problems, "unknown printcap library error %d", error); 18431492Swollman } 18531492Swollman return 0; 18631492Swollman} 18731492Swollman 18831492Swollman/* 18931492Swollman * Keep the list of spool directories. Note that we don't whine 19031492Swollman * until all spool directories are noted, so that all of the more serious 19131492Swollman * problems are noted first. We keep the list sorted by st_dev and 19231492Swollman * st_ino, so that the problem spool directories can be noted in 19331492Swollman * a single loop. 19431492Swollman */ 19531492Swollmanstruct dirlist { 19660938Sjake LIST_ENTRY(dirlist) link; 19731492Swollman struct stat stab; 19831492Swollman char *path; 19931492Swollman char *printer; 20031492Swollman}; 20131492Swollman 20260938Sjakestatic LIST_HEAD(, dirlist) dirlist; 20331492Swollman 20431492Swollmanstatic int 20531492Swollmanlessp(const struct dirlist *a, const struct dirlist *b) 20631492Swollman{ 20731492Swollman if (a->stab.st_dev == b->stab.st_dev) 20831492Swollman return a->stab.st_ino < b->stab.st_ino; 20931492Swollman return a->stab.st_dev < b->stab.st_dev; 21031492Swollman} 21131492Swollman 21231492Swollmanstatic int 21331492Swollmanequal(const struct dirlist *a, const struct dirlist *b) 21431492Swollman{ 21531492Swollman return ((a->stab.st_dev == b->stab.st_dev) 21631492Swollman && (a->stab.st_ino == b->stab.st_ino)); 21731492Swollman} 21831492Swollman 21931492Swollmanstatic void 22031492Swollmannote_spool_dir(const struct printer *pp, const struct stat *st) 22131492Swollman{ 22231492Swollman struct dirlist *dp, *dp2, *last; 22331492Swollman 22431492Swollman dp = malloc(sizeof *dp); 22531492Swollman if (dp == 0) 22631492Swollman err(++problems, "malloc(%lu)", (u_long)sizeof *dp); 22731492Swollman 22831492Swollman dp->stab = *st; 22931492Swollman dp->printer = strdup(pp->printer); 23031492Swollman if (dp->printer == 0) 23131492Swollman err(++problems, "malloc(%lu)", strlen(pp->printer) + 1UL); 23231492Swollman dp->path = strdup(pp->spool_dir); 23331492Swollman if (dp->path == 0) 23431492Swollman err(++problems, "malloc(%lu)", strlen(pp->spool_dir) + 1UL); 23531492Swollman 23631492Swollman last = 0; 23770520Sphk LIST_FOREACH(dp2, &dirlist, link) { 23870520Sphk if(!lessp(dp, dp2)) 23970520Sphk break; 24031492Swollman last = dp2; 24131492Swollman } 24231492Swollman 24331492Swollman if (last) { 24431492Swollman LIST_INSERT_AFTER(last, dp, link); 24531492Swollman } else { 24631492Swollman LIST_INSERT_HEAD(&dirlist, dp, link); 24731492Swollman } 24831492Swollman} 24931492Swollman 25031492Swollmanstatic void 25131492Swollmancheck_spool_dirs(void) 25231492Swollman{ 25331492Swollman struct dirlist *dp, *dp2; 25431492Swollman 25570520Sphk for (dp = LIST_FIRST(&dirlist); dp; dp = dp2) { 25670520Sphk dp2 = LIST_NEXT(dp, link); 25731492Swollman 25831492Swollman if (dp2 != 0 && equal(dp, dp2)) { 25931492Swollman ++problems; 26031492Swollman if (strcmp(dp->path, dp2->path) == 0) { 26131492Swollman warnx("%s and %s share the same spool, %s", 26231492Swollman dp->printer, dp2->printer, dp->path); 26331492Swollman } else { 26431492Swollman warnx("%s (%s) and %s (%s) are the same " 26531492Swollman "directory", dp->path, dp->printer, 26631492Swollman dp2->path, dp2->printer); 26731492Swollman } 26831492Swollman continue; 26931492Swollman } 27031492Swollman /* Should probably check owners and modes here. */ 27131492Swollman } 27231492Swollman} 27331492Swollman 27431492Swollman#ifndef SPOOL_DIR_MODE 27531492Swollman#define SPOOL_DIR_MODE (S_IRUSR | S_IWUSR | S_IXUSR \ 27631492Swollman | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) 27731492Swollman#endif 27831492Swollman 27931492Swollmanstatic void 28031492Swollmanmake_spool_dir(const struct printer *pp) 28131492Swollman{ 28231492Swollman char *sd = pp->spool_dir; 28331492Swollman struct group *gr; 28431492Swollman struct stat stab; 28531492Swollman 28631492Swollman if (mkdir(sd, S_IRUSR | S_IXUSR) < 0) { 28731492Swollman problems++; 28831492Swollman warn("%s: mkdir %s", pp->printer, sd); 28931492Swollman return; 29031492Swollman } 29131492Swollman gr = getgrnam("daemon"); 29231492Swollman if (gr == 0) 29331492Swollman errx(++problems, "cannot locate daemon group"); 29431492Swollman 29531492Swollman if (chown(sd, pp->daemon_user, gr->gr_gid) < 0) { 29631492Swollman ++problems; 29731492Swollman warn("%s: cannot change ownership to %ld:%ld", sd, 29831492Swollman (long)pp->daemon_user, (long)gr->gr_gid); 29931492Swollman return; 30031492Swollman } 30131492Swollman 30231492Swollman if (chmod(sd, SPOOL_DIR_MODE) < 0) { 30331492Swollman ++problems; 30431569Sjdp warn("%s: cannot change mode to %lo", sd, (long)SPOOL_DIR_MODE); 30531492Swollman return; 30631492Swollman } 30731492Swollman if (stat(sd, &stab) < 0) 30831492Swollman err(++problems, "stat: %s", sd); 30931492Swollman 31031492Swollman note_spool_dir(pp, &stab); 31131492Swollman} 31231492Swollman 31331492Swollmanstatic void 31431492Swollmanusage(void) 31531492Swollman{ 31688004Sgad fprintf(stderr, "usage:\n\tchkprintcap [-dv] [-f printcapfile]\n"); 31731492Swollman exit(1); 31831492Swollman} 319