summaryrefslogtreecommitdiffstats
path: root/usr.sbin/lpr/lpc/cmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/lpr/lpc/cmds.c')
-rw-r--r--usr.sbin/lpr/lpc/cmds.c1307
1 files changed, 0 insertions, 1307 deletions
diff --git a/usr.sbin/lpr/lpc/cmds.c b/usr.sbin/lpr/lpc/cmds.c
deleted file mode 100644
index 06ea4b0..0000000
--- a/usr.sbin/lpr/lpc/cmds.c
+++ /dev/null
@@ -1,1307 +0,0 @@
-/*
- * Copyright (c) 1983, 1993
- * The Regents of the University of California. All rights reserved.
- *
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by the University of
- * California, Berkeley and its contributors.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#ifndef lint
-static const char copyright[] =
-"@(#) Copyright (c) 1983, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif /* not lint */
-
-#if 0
-#ifndef lint
-static char sccsid[] = "@(#)cmds.c 8.2 (Berkeley) 4/28/95";
-#endif /* not lint */
-#endif
-
-#include "lp.cdefs.h" /* A cross-platform version of <sys/cdefs.h> */
-__FBSDID("$FreeBSD$");
-
-/*
- * lpc -- line printer control program -- commands:
- */
-
-#include <sys/param.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/file.h>
-
-#include <signal.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <dirent.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include "lp.h"
-#include "lp.local.h"
-#include "lpc.h"
-#include "extern.h"
-#include "pathnames.h"
-
-/*
- * Return values from kill_qtask().
- */
-#define KQT_LFERROR -2
-#define KQT_KILLFAIL -1
-#define KQT_NODAEMON 0
-#define KQT_KILLOK 1
-
-static char *args2line(int argc, char **argv);
-static int doarg(char *_job);
-static int doselect(struct dirent *_d);
-static int kill_qtask(const char *lf);
-static int sortq(const void *_a, const void *_b);
-static int touch(struct jobqueue *_jq);
-static void unlinkf(char *_name);
-static void upstat(struct printer *_pp, const char *_msg, int _notify);
-static void wrapup_clean(int _laststatus);
-
-/*
- * generic framework for commands which operate on all or a specified
- * set of printers
- */
-enum qsel_val { /* how a given ptr was selected */
- QSEL_UNKNOWN = -1, /* ... not selected yet */
- QSEL_BYNAME = 0, /* ... user specifed it by name */
- QSEL_ALL = 1 /* ... user wants "all" printers */
- /* (with more to come) */
-};
-
-static enum qsel_val generic_qselect; /* indicates how ptr was selected */
-static int generic_initerr; /* result of initrtn processing */
-static char *generic_cmdname;
-static char *generic_msg; /* if a -msg was specified */
-static char *generic_nullarg;
-static void (*generic_wrapup)(int _last_status); /* perform rtn wrap-up */
-
-void
-generic(void (*specificrtn)(struct printer *_pp), int cmdopts,
- void (*initrtn)(int _argc, char *_argv[]), int argc, char *argv[])
-{
- int cmdstatus, more, targc;
- struct printer myprinter, *pp;
- char **margv, **targv;
-
- if (argc == 1) {
- /*
- * Usage needs a special case for 'down': The user must
- * either include `-msg', or only the first parameter
- * that they give will be processed as a printer name.
- */
- printf("usage: %s {all | printer ...}", argv[0]);
- if (strcmp(argv[0], "down") == 0) {
- printf(" -msg [<text> ...]\n");
- printf(" or: down {all | printer} [<text> ...]");
- } else if (cmdopts & LPC_MSGOPT)
- printf(" [-msg <text> ...]");
- printf("\n");
- return;
- }
-
- /* The first argument is the command name. */
- generic_cmdname = *argv++;
- argc--;
-
- /*
- * The initialization routine for a command might set a generic
- * "wrapup" routine, which should be called after processing all
- * the printers in the command. This might print summary info.
- *
- * Note that the initialization routine may also parse (and
- * nullify) some of the parameters given on the command, leaving
- * only the parameters which have to do with printer names.
- */
- pp = &myprinter;
- generic_wrapup = NULL;
- generic_qselect = QSEL_UNKNOWN;
- cmdstatus = 0;
- /* this just needs to be a distinct value of type 'char *' */
- if (generic_nullarg == NULL)
- generic_nullarg = strdup("");
-
- /*
- * Some commands accept a -msg argument, which indicates that
- * all remaining arguments should be combined into a string.
- */
- generic_msg = NULL;
- if (cmdopts & LPC_MSGOPT) {
- targc = argc;
- targv = argv;
- for (; targc > 0; targc--, targv++) {
- if (strcmp(*targv, "-msg") == 0) {
- argc -= targc;
- generic_msg = args2line(targc - 1, targv + 1);
- break;
- }
- }
- }
-
- /* call initialization routine, if there is one for this cmd */
- if (initrtn != NULL) {
- generic_initerr = 0;
- (*initrtn)(argc, argv);
- if (generic_initerr)
- return;
- /*
- * The initrtn may have null'ed out some of the parameters.
- * Compact the parameter list to remove those nulls, and
- * correct the arg-count.
- */
- targc = argc;
- targv = argv;
- margv = argv;
- argc = 0;
- for (; targc > 0; targc--, targv++) {
- if (*targv != generic_nullarg) {
- if (targv != margv)
- *margv = *targv;
- margv++;
- argc++;
- }
- }
- }
-
- if (argc == 1 && strcmp(*argv, "all") == 0) {
- generic_qselect = QSEL_ALL;
- more = firstprinter(pp, &cmdstatus);
- if (cmdstatus)
- goto looperr;
- while (more) {
- (*specificrtn)(pp);
- do {
- more = nextprinter(pp, &cmdstatus);
-looperr:
- switch (cmdstatus) {
- case PCAPERR_TCOPEN:
- printf("warning: %s: unresolved "
- "tc= reference(s) ",
- pp->printer);
- case PCAPERR_SUCCESS:
- break;
- default:
- fatal(pp, "%s", pcaperr(cmdstatus));
- }
- } while (more && cmdstatus);
- }
- goto wrapup;
- }
-
- generic_qselect = QSEL_BYNAME; /* specifically-named ptrs */
- for (; argc > 0; argc--, argv++) {
- init_printer(pp);
- cmdstatus = getprintcap(*argv, pp);
- switch (cmdstatus) {
- default:
- fatal(pp, "%s", pcaperr(cmdstatus));
- case PCAPERR_NOTFOUND:
- printf("unknown printer %s\n", *argv);
- continue;
- case PCAPERR_TCOPEN:
- printf("warning: %s: unresolved tc= reference(s)\n",
- *argv);
- break;
- case PCAPERR_SUCCESS:
- break;
- }
- (*specificrtn)(pp);
- }
-
-wrapup:
- if (generic_wrapup) {
- (*generic_wrapup)(cmdstatus);
- }
- free_printer(pp);
- if (generic_msg)
- free(generic_msg);
-}
-
-/*
- * Convert an argv-array of character strings into a single string.
- */
-static char *
-args2line(int argc, char **argv)
-{
- char *cp1, *cend;
- const char *cp2;
- char buf[1024];
-
- if (argc <= 0)
- return strdup("\n");
-
- cp1 = buf;
- cend = buf + sizeof(buf) - 1; /* save room for '\0' */
- while (--argc >= 0) {
- cp2 = *argv++;
- while ((cp1 < cend) && (*cp1++ = *cp2++))
- ;
- cp1[-1] = ' ';
- }
- cp1[-1] = '\n';
- *cp1 = '\0';
- return strdup(buf);
-}
-
-/*
- * Kill the current daemon, to stop printing of the active job.
- */
-static int
-kill_qtask(const char *lf)
-{
- FILE *fp;
- pid_t pid;
- int errsav, killres, lockres, res;
-
- seteuid(euid);
- fp = fopen(lf, "r");
- errsav = errno;
- seteuid(uid);
- res = KQT_NODAEMON;
- if (fp == NULL) {
- /*
- * If there is no lock file, then there is no daemon to
- * kill. Any other error return means there is some
- * kind of problem with the lock file.
- */
- if (errsav != ENOENT)
- res = KQT_LFERROR;
- goto killdone;
- }
-
- /* If the lock file is empty, then there is no daemon to kill */
- if (getline(fp) == 0)
- goto killdone;
-
- /*
- * If the file can be locked without blocking, then there
- * no daemon to kill, or we should not try to kill it.
- *
- * XXX - not sure I understand the reasoning behind this...
- */
- lockres = flock(fileno(fp), LOCK_SH|LOCK_NB);
- (void) fclose(fp);
- if (lockres == 0)
- goto killdone;
-
- pid = atoi(line);
- if (pid < 0) {
- /*
- * If we got a negative pid, then the contents of the
- * lock file is not valid.
- */
- res = KQT_LFERROR;
- goto killdone;
- }
-
- seteuid(uid);
- killres = kill(pid, SIGTERM);
- errsav = errno;
- seteuid(uid);
- if (killres == 0) {
- res = KQT_KILLOK;
- printf("\tdaemon (pid %d) killed\n", pid);
- } else if (errno == ESRCH) {
- res = KQT_NODAEMON;
- } else {
- res = KQT_KILLFAIL;
- printf("\tWarning: daemon (pid %d) not killed:\n", pid);
- printf("\t %s\n", strerror(errsav));
- }
-
-killdone:
- switch (res) {
- case KQT_LFERROR:
- printf("\tcannot open lock file: %s\n",
- strerror(errsav));
- break;
- case KQT_NODAEMON:
- printf("\tno daemon to abort\n");
- break;
- case KQT_KILLFAIL:
- case KQT_KILLOK:
- /* These two already printed messages to the user. */
- break;
- default:
- printf("\t<internal error in kill_qtask>\n");
- break;
- }
-
- return (res);
-}
-
-/*
- * Write a message into the status file.
- */
-static void
-upstat(struct printer *pp, const char *msg, int notifyuser)
-{
- int fd;
- char statfile[MAXPATHLEN];
-
- status_file_name(pp, statfile, sizeof statfile);
- umask(0);
- seteuid(euid);
- fd = open(statfile, O_WRONLY|O_CREAT|O_EXLOCK, STAT_FILE_MODE);
- seteuid(uid);
- if (fd < 0) {
- printf("\tcannot create status file: %s\n", strerror(errno));
- return;
- }
- (void) ftruncate(fd, 0);
- if (msg == (char *)NULL)
- (void) write(fd, "\n", 1);
- else
- (void) write(fd, msg, strlen(msg));
- (void) close(fd);
- if (notifyuser) {
- if ((msg == (char *)NULL) || (strcmp(msg, "\n") == 0))
- printf("\tstatus message is now set to nothing.\n");
- else
- printf("\tstatus message is now: %s", msg);
- }
-}
-
-/*
- * kill an existing daemon and disable printing.
- */
-void
-abort_q(struct printer *pp)
-{
- int killres, setres;
- char lf[MAXPATHLEN];
-
- lock_file_name(pp, lf, sizeof lf);
- printf("%s:\n", pp->printer);
-
- /*
- * Turn on the owner execute bit of the lock file to disable printing.
- */
- setres = set_qstate(SQS_STOPP, lf);
-
- /*
- * If set_qstate found that there already was a lock file, then
- * call a routine which will read that lock file and kill the
- * lpd-process which is listed in that lock file. If the lock
- * file did not exist, then either there is no daemon running
- * for this queue, or there is one running but *it* could not
- * write a lock file (which means we can not determine the
- * process id of that lpd-process).
- */
- switch (setres) {
- case SQS_CHGOK:
- case SQS_CHGFAIL:
- /* Kill the process */
- killres = kill_qtask(lf);
- break;
- case SQS_CREOK:
- case SQS_CREFAIL:
- printf("\tno daemon to abort\n");
- break;
- case SQS_STATFAIL:
- printf("\tassuming no daemon to abort\n");
- break;
- default:
- printf("\t<unexpected result (%d) from set_qstate>\n",
- setres);
- break;
- }
-
- if (setres >= 0)
- upstat(pp, "printing disabled\n", 0);
-}
-
-/*
- * "global" variables for all the routines related to 'clean' and 'tclean'
- */
-static time_t cln_now; /* current time */
-static double cln_minage; /* minimum age before file is removed */
-static long cln_sizecnt; /* amount of space freed up */
-static int cln_debug; /* print extra debugging msgs */
-static int cln_filecnt; /* number of files destroyed */
-static int cln_foundcore; /* found a core file! */
-static int cln_queuecnt; /* number of queues checked */
-static int cln_testonly; /* remove-files vs just-print-info */
-
-static int
-doselect(struct dirent *d)
-{
- int c = d->d_name[0];
-
- if ((c == 'c' || c == 'd' || c == 'r' || c == 't') &&
- d->d_name[1] == 'f')
- return 1;
- if (c == 'c') {
- if (!strcmp(d->d_name, "core"))
- cln_foundcore = 1;
- }
- if (c == 'e') {
- if (!strncmp(d->d_name, "errs.", 5))
- return 1;
- }
- return 0;
-}
-
-/*
- * Comparison routine that clean_q() uses for scandir.
- *
- * The purpose of this sort is to have all `df' files end up immediately
- * after the matching `cf' file. For files matching `cf', `df', `rf', or
- * `tf', it sorts by job number and machine, then by `cf', `df', `rf', or
- * `tf', and then by the sequence letter (which is A-Z, or a-z). This
- * routine may also see filenames which do not start with `cf', `df', `rf',
- * or `tf' (such as `errs.*'), and those are simply sorted by the full
- * filename.
- *
- * XXX
- * This assumes that all control files start with `cfA*', and it turns
- * out there are a few implementations of lpr which will create `cfB*'
- * filenames (they will have datafile names which start with `dfB*').
- */
-static int
-sortq(const void *a, const void *b)
-{
- const int a_lt_b = -1, a_gt_b = 1, cat_other = 10;
- const char *fname_a, *fname_b, *jnum_a, *jnum_b;
- int cat_a, cat_b, ch, res, seq_a, seq_b;
-
- fname_a = (*(const struct dirent * const *)a)->d_name;
- fname_b = (*(const struct dirent * const *)b)->d_name;
-
- /*
- * First separate filenames into cagatories. Catagories are
- * legitimate `cf', `df', `rf' & `tf' filenames, and "other" - in
- * that order. It is critical that the mapping be exactly the
- * same for 'a' vs 'b', so define a macro for the job.
- *
- * [aside: the standard `cf' file has the jobnumber start in
- * position 4, but some implementations have that as an extra
- * file-sequence letter, and start the job number in position 5.]
- */
-#define MAP_TO_CAT(fname_X,cat_X,jnum_X,seq_X) do { \
- cat_X = cat_other; \
- ch = *(fname_X + 2); \
- jnum_X = fname_X + 3; \
- seq_X = 0; \
- if ((*(fname_X + 1) == 'f') && (isalpha(ch))) { \
- seq_X = ch; \
- if (*fname_X == 'c') \
- cat_X = 1; \
- else if (*fname_X == 'd') \
- cat_X = 2; \
- else if (*fname_X == 'r') \
- cat_X = 3; \
- else if (*fname_X == 't') \
- cat_X = 4; \
- if (cat_X != cat_other) { \
- ch = *jnum_X; \
- if (!isdigit(ch)) { \
- if (isalpha(ch)) { \
- jnum_X++; \
- ch = *jnum_X; \
- seq_X = (seq_X << 8) + ch; \
- } \
- if (!isdigit(ch)) \
- cat_X = cat_other; \
- } \
- } \
- } \
-} while (0)
-
- MAP_TO_CAT(fname_a, cat_a, jnum_a, seq_a);
- MAP_TO_CAT(fname_b, cat_b, jnum_b, seq_b);
-
-#undef MAP_TO_CAT
-
- /* First handle all cases which have "other" files */
- if ((cat_a >= cat_other) || (cat_b >= cat_other)) {
- /* for two "other" files, just compare the full name */
- if (cat_a == cat_b)
- res = strcmp(fname_a, fname_b);
- else if (cat_a < cat_b)
- res = a_lt_b;
- else
- res = a_gt_b;
- goto have_res;
- }
-
- /*
- * At this point, we know both files are legitimate `cf', `df', `rf',
- * or `tf' files. Compare them by job-number and machine name.
- */
- res = strcmp(jnum_a, jnum_b);
- if (res != 0)
- goto have_res;
-
- /*
- * We have two files which belong to the same job. Sort based
- * on the catagory of file (`c' before `d', etc).
- */
- if (cat_a < cat_b) {
- res = a_lt_b;
- goto have_res;
- } else if (cat_a > cat_b) {
- res = a_gt_b;
- goto have_res;
- }
-
- /*
- * Two files in the same catagory for a single job. Sort based
- * on the sequence letter(s). (usually `A' thru `Z', etc).
- */
- if (seq_a < seq_b) {
- res = a_lt_b;
- goto have_res;
- } else if (seq_a > seq_b) {
- res = a_gt_b;
- goto have_res;
- }
-
- /*
- * Given that the filenames in a directory are unique, this SHOULD
- * never happen (unless there are logic errors in this routine).
- * But if it does happen, we must return "is equal" or the caller
- * might see inconsistent results in the sorting order, and that
- * can trigger other problems.
- */
- printf("\t*** Error in sortq: %s == %s !\n", fname_a, fname_b);
- printf("\t*** cat %d == %d ; seq = %d %d\n", cat_a, cat_b,
- seq_a, seq_b);
- res = 0;
-
-have_res:
- return res;
-}
-
-/*
- * Remove all spool files and temporaries from the spooling area.
- * Or, perhaps:
- * Remove incomplete jobs from spooling area.
- */
-
-void
-clean_gi(int argc, char *argv[])
-{
-
- /* init some fields before 'clean' is called for each queue */
- cln_queuecnt = 0;
- cln_now = time(NULL);
- cln_minage = 3600.0; /* only delete files >1h old */
- cln_filecnt = 0;
- cln_sizecnt = 0;
- cln_debug = 0;
- cln_testonly = 0;
- generic_wrapup = &wrapup_clean;
-
- /* see if there are any options specified before the ptr list */
- for (; argc > 0; argc--, argv++) {
- if (**argv != '-')
- break;
- if (strcmp(*argv, "-d") == 0) {
- /* just an example of an option... */
- cln_debug++;
- *argv = generic_nullarg; /* "erase" it */
- } else {
- printf("Invalid option '%s'\n", *argv);
- generic_initerr = 1;
- }
- }
-
- return;
-}
-
-void
-tclean_gi(int argc, char *argv[])
-{
-
- /* only difference between 'clean' and 'tclean' is one value */
- /* (...and the fact that 'clean' is priv and 'tclean' is not) */
- clean_gi(argc, argv);
- cln_testonly = 1;
-
- return;
-}
-
-void
-clean_q(struct printer *pp)
-{
- char *cp, *cp1, *lp;
- struct dirent **queue;
- size_t linerem;
- int didhead, i, n, nitems, rmcp;
-
- cln_queuecnt++;
-
- didhead = 0;
- if (generic_qselect == QSEL_BYNAME) {
- printf("%s:\n", pp->printer);
- didhead = 1;
- }
-
- lp = line;
- cp = pp->spool_dir;
- while (lp < &line[sizeof(line) - 1]) {
- if ((*lp++ = *cp++) == 0)
- break;
- }
- lp[-1] = '/';
- linerem = sizeof(line) - (lp - line);
-
- cln_foundcore = 0;
- seteuid(euid);
- nitems = scandir(pp->spool_dir, &queue, doselect, sortq);
- seteuid(uid);
- if (nitems < 0) {
- if (!didhead) {
- printf("%s:\n", pp->printer);
- didhead = 1;
- }
- printf("\tcannot examine spool directory\n");
- return;
- }
- if (cln_foundcore) {
- if (!didhead) {
- printf("%s:\n", pp->printer);
- didhead = 1;
- }
- printf("\t** found a core file in %s !\n", pp->spool_dir);
- }
- if (nitems == 0)
- return;
- if (!didhead)
- printf("%s:\n", pp->printer);
- if (cln_debug) {
- printf("\t** ----- Sorted list of files being checked:\n");
- i = 0;
- do {
- cp = queue[i]->d_name;
- printf("\t** [%3d] = %s\n", i, cp);
- } while (++i < nitems);
- printf("\t** ----- end of sorted list\n");
- }
- i = 0;
- do {
- cp = queue[i]->d_name;
- rmcp = 0;
- if (*cp == 'c') {
- /*
- * A control file. Look for matching data-files.
- */
- /* XXX
- * Note the logic here assumes that the hostname
- * part of cf-filenames match the hostname part
- * in df-filenames, and that is not necessarily
- * true (eg: for multi-homed hosts). This needs
- * some further thought...
- */
- n = 0;
- while (i + 1 < nitems) {
- cp1 = queue[i + 1]->d_name;
- if (*cp1 != 'd' || strcmp(cp + 3, cp1 + 3))
- break;
- i++;
- n++;
- }
- if (n == 0) {
- rmcp = 1;
- }
- } else if (*cp == 'e') {
- /*
- * Must be an errrs or email temp file.
- */
- rmcp = 1;
- } else {
- /*
- * Must be a df with no cf (otherwise, it would have
- * been skipped above) or an rf or tf file (which can
- * always be removed if it is old enough).
- */
- rmcp = 1;
- }
- if (rmcp) {
- if (strlen(cp) >= linerem) {
- printf("\t** internal error: 'line' overflow!\n");
- printf("\t** spooldir = %s\n", pp->spool_dir);
- printf("\t** cp = %s\n", cp);
- return;
- }
- strlcpy(lp, cp, linerem);
- unlinkf(line);
- }
- } while (++i < nitems);
-}
-
-static void
-wrapup_clean(int laststatus __unused)
-{
-
- printf("Checked %d queues, and ", cln_queuecnt);
- if (cln_filecnt < 1) {
- printf("no cruft was found\n");
- return;
- }
- if (cln_testonly) {
- printf("would have ");
- }
- printf("removed %d files (%ld bytes).\n", cln_filecnt, cln_sizecnt);
-}
-
-static void
-unlinkf(char *name)
-{
- struct stat stbuf;
- double agemod, agestat;
- int res;
- char linkbuf[BUFSIZ];
-
- /*
- * We have to use lstat() instead of stat(), in case this is a df*
- * "file" which is really a symlink due to 'lpr -s' processing. In
- * that case, we need to check the last-mod time of the symlink, and
- * not the file that the symlink is pointed at.
- */
- seteuid(euid);
- res = lstat(name, &stbuf);
- seteuid(uid);
- if (res < 0) {
- printf("\terror return from stat(%s):\n", name);
- printf("\t %s\n", strerror(errno));
- return;
- }
-
- agemod = difftime(cln_now, stbuf.st_mtime);
- agestat = difftime(cln_now, stbuf.st_ctime);
- if (cln_debug > 1) {
- /* this debugging-aid probably is not needed any more... */
- printf("\t\t modify age=%g secs, stat age=%g secs\n",
- agemod, agestat);
- }
- if ((agemod <= cln_minage) && (agestat <= cln_minage))
- return;
-
- /*
- * if this file is a symlink, then find out the target of the
- * symlink before unlink-ing the file itself
- */
- if (S_ISLNK(stbuf.st_mode)) {
- seteuid(euid);
- res = readlink(name, linkbuf, sizeof(linkbuf));
- seteuid(uid);
- if (res < 0) {
- printf("\terror return from readlink(%s):\n", name);
- printf("\t %s\n", strerror(errno));
- return;
- }
- if (res == sizeof(linkbuf))
- res--;
- linkbuf[res] = '\0';
- }
-
- cln_filecnt++;
- cln_sizecnt += stbuf.st_size;
-
- if (cln_testonly) {
- printf("\twould remove %s\n", name);
- if (S_ISLNK(stbuf.st_mode)) {
- printf("\t (which is a symlink to %s)\n", linkbuf);
- }
- } else {
- seteuid(euid);
- res = unlink(name);
- seteuid(uid);
- if (res < 0)
- printf("\tcannot remove %s (!)\n", name);
- else
- printf("\tremoved %s\n", name);
- /* XXX
- * Note that for a df* file, this code should also check to see
- * if it is a symlink to some other file, and if the original
- * lpr command included '-r' ("remove file"). Of course, this
- * code would not be removing the df* file unless there was no
- * matching cf* file, and without the cf* file it is currently
- * impossible to determine if '-r' had been specified...
- *
- * As a result of this quandry, we may be leaving behind a
- * user's file that was supposed to have been removed after
- * being printed. This may effect services such as CAP or
- * samba, if they were configured to use 'lpr -r', and if
- * datafiles are not being properly removed.
- */
- if (S_ISLNK(stbuf.st_mode)) {
- printf("\t (which was a symlink to %s)\n", linkbuf);
- }
- }
-}
-
-/*
- * Enable queuing to the printer (allow lpr to add new jobs to the queue).
- */
-void
-enable_q(struct printer *pp)
-{
- int setres;
- char lf[MAXPATHLEN];
-
- lock_file_name(pp, lf, sizeof lf);
- printf("%s:\n", pp->printer);
-
- setres = set_qstate(SQS_ENABLEQ, lf);
-}
-
-/*
- * Disable queuing.
- */
-void
-disable_q(struct printer *pp)
-{
- int setres;
- char lf[MAXPATHLEN];
-
- lock_file_name(pp, lf, sizeof lf);
- printf("%s:\n", pp->printer);
-
- setres = set_qstate(SQS_DISABLEQ, lf);
-}
-
-/*
- * Disable queuing and printing and put a message into the status file
- * (reason for being down). If the user specified `-msg', then use
- * everything after that as the message for the status file. If the
- * user did NOT specify `-msg', then the command should take the first
- * parameter as the printer name, and all remaining parameters as the
- * message for the status file. (This is to be compatible with the
- * original definition of 'down', which was implemented long before
- * `-msg' was around).
- */
-void
-down_gi(int argc, char *argv[])
-{
-
- /* If `-msg' was specified, then this routine has nothing to do. */
- if (generic_msg != NULL)
- return;
-
- /*
- * If the user only gave one parameter, then use a default msg.
- * (if argc == 1 at this point, then *argv == name of printer).
- */
- if (argc == 1) {
- generic_msg = strdup("printing disabled\n");
- return;
- }
-
- /*
- * The user specified multiple parameters, and did not specify
- * `-msg'. Build a message from all the parameters after the
- * first one (and nullify those parameters so generic-processing
- * will not process them as printer-queue names).
- */
- argc--;
- argv++;
- generic_msg = args2line(argc, argv);
- for (; argc > 0; argc--, argv++)
- *argv = generic_nullarg; /* "erase" it */
-}
-
-void
-down_q(struct printer *pp)
-{
- int setres;
- char lf[MAXPATHLEN];
-
- lock_file_name(pp, lf, sizeof lf);
- printf("%s:\n", pp->printer);
-
- setres = set_qstate(SQS_DISABLEQ+SQS_STOPP, lf);
- if (setres >= 0)
- upstat(pp, generic_msg, 1);
-}
-
-/*
- * Exit lpc
- */
-void
-quit(int argc __unused, char *argv[] __unused)
-{
- exit(0);
-}
-
-/*
- * Kill and restart the daemon.
- */
-void
-restart_q(struct printer *pp)
-{
- int killres, setres, startok;
- char lf[MAXPATHLEN];
-
- lock_file_name(pp, lf, sizeof lf);
- printf("%s:\n", pp->printer);
-
- killres = kill_qtask(lf);
-
- /*
- * XXX - if the kill worked, we should probably sleep for
- * a second or so before trying to restart the queue.
- */
-
- /* make sure the queue is set to print jobs */
- setres = set_qstate(SQS_STARTP, lf);
-
- seteuid(euid);
- startok = startdaemon(pp);
- seteuid(uid);
- if (!startok)
- printf("\tcouldn't restart daemon\n");
- else
- printf("\tdaemon restarted\n");
-}
-
-/*
- * Set the status message of each queue listed. Requires a "-msg"
- * parameter to indicate the end of the queue list and start of msg text.
- */
-void
-setstatus_gi(int argc __unused, char *argv[] __unused)
-{
-
- if (generic_msg == NULL) {
- printf("You must specify '-msg' before the text of the new status message.\n");
- generic_initerr = 1;
- }
-}
-
-void
-setstatus_q(struct printer *pp)
-{
- char lf[MAXPATHLEN];
-
- lock_file_name(pp, lf, sizeof lf);
- printf("%s:\n", pp->printer);
-
- upstat(pp, generic_msg, 1);
-}
-
-/*
- * Enable printing on the specified printer and startup the daemon.
- */
-void
-start_q(struct printer *pp)
-{
- int setres, startok;
- char lf[MAXPATHLEN];
-
- lock_file_name(pp, lf, sizeof lf);
- printf("%s:\n", pp->printer);
-
- setres = set_qstate(SQS_STARTP, lf);
-
- seteuid(euid);
- startok = startdaemon(pp);
- seteuid(uid);
- if (!startok)
- printf("\tcouldn't start daemon\n");
- else
- printf("\tdaemon started\n");
- seteuid(uid);
-}
-
-/*
- * Print the status of the printer queue.
- */
-void
-status(struct printer *pp)
-{
- struct stat stbuf;
- register int fd, i;
- register struct dirent *dp;
- DIR *dirp;
- char file[MAXPATHLEN];
-
- printf("%s:\n", pp->printer);
- lock_file_name(pp, file, sizeof file);
- if (stat(file, &stbuf) >= 0) {
- printf("\tqueuing is %s\n",
- ((stbuf.st_mode & LFM_QUEUE_DIS) ? "disabled"
- : "enabled"));
- printf("\tprinting is %s\n",
- ((stbuf.st_mode & LFM_PRINT_DIS) ? "disabled"
- : "enabled"));
- } else {
- printf("\tqueuing is enabled\n");
- printf("\tprinting is enabled\n");
- }
- if ((dirp = opendir(pp->spool_dir)) == NULL) {
- printf("\tcannot examine spool directory\n");
- return;
- }
- i = 0;
- while ((dp = readdir(dirp)) != NULL) {
- if (*dp->d_name == 'c' && dp->d_name[1] == 'f')
- i++;
- }
- closedir(dirp);
- if (i == 0)
- printf("\tno entries in spool area\n");
- else if (i == 1)
- printf("\t1 entry in spool area\n");
- else
- printf("\t%d entries in spool area\n", i);
- fd = open(file, O_RDONLY);
- if (fd < 0 || flock(fd, LOCK_SH|LOCK_NB) == 0) {
- (void) close(fd); /* unlocks as well */
- printf("\tprinter idle\n");
- return;
- }
- (void) close(fd);
- /* print out the contents of the status file, if it exists */
- status_file_name(pp, file, sizeof file);
- fd = open(file, O_RDONLY|O_SHLOCK);
- if (fd >= 0) {
- (void) fstat(fd, &stbuf);
- if (stbuf.st_size > 0) {
- putchar('\t');
- while ((i = read(fd, line, sizeof(line))) > 0)
- (void) fwrite(line, 1, i, stdout);
- }
- (void) close(fd); /* unlocks as well */
- }
-}
-
-/*
- * Stop the specified daemon after completing the current job and disable
- * printing.
- */
-void
-stop_q(struct printer *pp)
-{
- int setres;
- char lf[MAXPATHLEN];
-
- lock_file_name(pp, lf, sizeof lf);
- printf("%s:\n", pp->printer);
-
- setres = set_qstate(SQS_STOPP, lf);
-
- if (setres >= 0)
- upstat(pp, "printing disabled\n", 0);
-}
-
-struct jobqueue **queue;
-int nitems;
-time_t mtime;
-
-/*
- * Put the specified jobs at the top of printer queue.
- */
-void
-topq(int argc, char *argv[])
-{
- register int i;
- struct stat stbuf;
- int cmdstatus, changed;
- struct printer myprinter, *pp = &myprinter;
-
- if (argc < 3) {
- printf("usage: topq printer [jobnum ...] [user ...]\n");
- return;
- }
-
- --argc;
- ++argv;
- init_printer(pp);
- cmdstatus = getprintcap(*argv, pp);
- switch(cmdstatus) {
- default:
- fatal(pp, "%s", pcaperr(cmdstatus));
- case PCAPERR_NOTFOUND:
- printf("unknown printer %s\n", *argv);
- return;
- case PCAPERR_TCOPEN:
- printf("warning: %s: unresolved tc= reference(s)", *argv);
- break;
- case PCAPERR_SUCCESS:
- break;
- }
- printf("%s:\n", pp->printer);
-
- seteuid(euid);
- if (chdir(pp->spool_dir) < 0) {
- printf("\tcannot chdir to %s\n", pp->spool_dir);
- goto out;
- }
- seteuid(uid);
- nitems = getq(pp, &queue);
- if (nitems == 0)
- return;
- changed = 0;
- mtime = queue[0]->job_time;
- for (i = argc; --i; ) {
- if (doarg(argv[i]) == 0) {
- printf("\tjob %s is not in the queue\n", argv[i]);
- continue;
- } else
- changed++;
- }
- for (i = 0; i < nitems; i++)
- free(queue[i]);
- free(queue);
- if (!changed) {
- printf("\tqueue order unchanged\n");
- return;
- }
- /*
- * Turn on the public execute bit of the lock file to
- * get lpd to rebuild the queue after the current job.
- */
- seteuid(euid);
- if (changed && stat(pp->lock_file, &stbuf) >= 0)
- (void) chmod(pp->lock_file, stbuf.st_mode | LFM_RESET_QUE);
-
-out:
- seteuid(uid);
-}
-
-/*
- * Reposition the job by changing the modification time of
- * the control file.
- */
-static int
-touch(struct jobqueue *jq)
-{
- struct timeval tvp[2];
- int ret;
-
- tvp[0].tv_sec = tvp[1].tv_sec = --mtime;
- tvp[0].tv_usec = tvp[1].tv_usec = 0;
- seteuid(euid);
- ret = utimes(jq->job_cfname, tvp);
- seteuid(uid);
- return (ret);
-}
-
-/*
- * Checks if specified job name is in the printer's queue.
- * Returns: negative (-1) if argument name is not in the queue.
- */
-static int
-doarg(char *job)
-{
- register struct jobqueue **qq;
- register int jobnum, n;
- register char *cp, *machine;
- int cnt = 0;
- FILE *fp;
-
- /*
- * Look for a job item consisting of system name, colon, number
- * (example: ucbarpa:114)
- */
- if ((cp = strchr(job, ':')) != NULL) {
- machine = job;
- *cp++ = '\0';
- job = cp;
- } else
- machine = NULL;
-
- /*
- * Check for job specified by number (example: 112 or 235ucbarpa).
- */
- if (isdigit(*job)) {
- jobnum = 0;
- do
- jobnum = jobnum * 10 + (*job++ - '0');
- while (isdigit(*job));
- for (qq = queue + nitems; --qq >= queue; ) {
- n = 0;
- for (cp = (*qq)->job_cfname+3; isdigit(*cp); )
- n = n * 10 + (*cp++ - '0');
- if (jobnum != n)
- continue;
- if (*job && strcmp(job, cp) != 0)
- continue;
- if (machine != NULL && strcmp(machine, cp) != 0)
- continue;
- if (touch(*qq) == 0) {
- printf("\tmoved %s\n", (*qq)->job_cfname);
- cnt++;
- }
- }
- return(cnt);
- }
- /*
- * Process item consisting of owner's name (example: henry).
- */
- for (qq = queue + nitems; --qq >= queue; ) {
- seteuid(euid);
- fp = fopen((*qq)->job_cfname, "r");
- seteuid(uid);
- if (fp == NULL)
- continue;
- while (getline(fp) > 0)
- if (line[0] == 'P')
- break;
- (void) fclose(fp);
- if (line[0] != 'P' || strcmp(job, line+1) != 0)
- continue;
- if (touch(*qq) == 0) {
- printf("\tmoved %s\n", (*qq)->job_cfname);
- cnt++;
- }
- }
- return(cnt);
-}
-
-/*
- * Enable both queuing & printing, and start printer (undo `down').
- */
-void
-up_q(struct printer *pp)
-{
- int setres, startok;
- char lf[MAXPATHLEN];
-
- lock_file_name(pp, lf, sizeof lf);
- printf("%s:\n", pp->printer);
-
- setres = set_qstate(SQS_ENABLEQ+SQS_STARTP, lf);
-
- seteuid(euid);
- startok = startdaemon(pp);
- seteuid(uid);
- if (!startok)
- printf("\tcouldn't start daemon\n");
- else
- printf("\tdaemon started\n");
-}
OpenPOWER on IntegriCloud