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