summaryrefslogtreecommitdiffstats
path: root/usr.sbin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/lpr/common_source/common.c133
-rw-r--r--usr.sbin/lpr/common_source/lp.h18
-rw-r--r--usr.sbin/lpr/lpc/cmds.c278
-rw-r--r--usr.sbin/lpr/lpc/cmdtab.c21
-rw-r--r--usr.sbin/lpr/lpc/extern.h21
5 files changed, 457 insertions, 14 deletions
diff --git a/usr.sbin/lpr/common_source/common.c b/usr.sbin/lpr/common_source/common.c
index a61bba3..d04e8f2 100644
--- a/usr.sbin/lpr/common_source/common.c
+++ b/usr.sbin/lpr/common_source/common.c
@@ -50,6 +50,7 @@ static const char rcsid[] =
#include <sys/types.h>
#include <dirent.h>
+#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
@@ -252,6 +253,138 @@ status_file_name(const struct printer *pp, char *buf, size_t len)
return buf;
}
+/*
+ * Routine to change operational state of a print queue. The operational
+ ¥Êstate is indicated by the access bits on the lock file for the queue.
+ * At present, this is only called from various routines in lpc/cmds.c.
+ *
+ * XXX - Note that this works by changing access-bits on the
+ * file, and you can only do that if you are the owner of
+ * the file, or root. Thus, this won't really work for
+ * userids in the "LPR_OPER" group, unless lpc is running
+ * setuid to root (or maybe setuid to daemon).
+ * Generally lpc is installed setgid to daemon, but does
+ * not run setuid.
+ */
+int
+set_qstate(int action, const char *lfname)
+{
+ struct stat stbuf;
+ mode_t chgbits, newbits, oldmask;
+ const char *failmsg, *okmsg;
+ int chres, errsav, fd, res, statres;
+
+ /*
+ * Find what the current access-bits are.
+ */
+ memset(&stbuf, 0, sizeof(stbuf));
+ seteuid(euid);
+ statres = stat(lfname, &stbuf);
+ errsav = errno;
+ seteuid(uid);
+ if ((statres < 0) && (errsav != ENOENT)) {
+ printf("\tcannot stat() lock file\n");
+ return (SQS_STATFAIL);
+ /* NOTREACHED */
+ }
+
+ /*
+ * Determine which bit(s) should change for the requested action.
+ */
+ chgbits = stbuf.st_mode;
+ newbits = LOCK_FILE_MODE;
+ okmsg = NULL;
+ failmsg = NULL;
+ if (action & SQS_DISABLEQ) {
+ chgbits |= LFM_QUEUE_DIS;
+ newbits |= LFM_QUEUE_DIS;
+ okmsg = "queuing disabled";
+ failmsg = "disable queuing";
+ }
+ if (action & SQS_STOPP) {
+ chgbits |= LFM_PRINT_DIS;
+ newbits |= LFM_PRINT_DIS;
+ okmsg = "printing disabled";
+ failmsg = "disable printing";
+ if (action & SQS_DISABLEQ) {
+ okmsg = "printer and queuing disabled";
+ failmsg = "disable queuing and printing";
+ }
+ }
+ if (action & SQS_ENABLEQ) {
+ chgbits &= ~LFM_QUEUE_DIS;
+ newbits &= ~LFM_QUEUE_DIS;
+ okmsg = "queuing enabled";
+ failmsg = "enable queuing";
+ }
+ if (action & SQS_STARTP) {
+ chgbits &= ~LFM_PRINT_DIS;
+ newbits &= ~LFM_PRINT_DIS;
+ okmsg = "printing enabled";
+ failmsg = "enable printing";
+ }
+ if (okmsg == NULL) {
+ /* This routine was called with an invalid action. */
+ printf("\t<error in set_qstate!>\n");
+ return (SQS_PARMERR);
+ /* NOTREACHED */
+ }
+
+ res = 0;
+ if (statres >= 0) {
+ /* The file already exists, so change the access. */
+ seteuid(euid);
+ chres = chmod(lfname, chgbits);
+ errsav = errno;
+ seteuid(uid);
+ res = SQS_CHGOK;
+ if (res < 0)
+ res = SQS_CHGFAIL;
+ } else if (newbits == LOCK_FILE_MODE) {
+ /*
+ * The file does not exist, but the state requested is
+ * the same as the default state when no file exists.
+ * Thus, there is no need to create the file.
+ */
+ res = SQS_SKIPCREOK;
+ } else {
+ /*
+ * The file did not exist, so create it with the
+ * appropriate access bits for the requested action.
+ * Push a new umask around that create, to make sure
+ * all the read/write bits are set as desired.
+ */
+ oldmask = umask(S_IWOTH);
+ seteuid(euid);
+ fd = open(lfname, O_WRONLY|O_CREAT, newbits);
+ errsav = errno;
+ seteuid(uid);
+ umask(oldmask);
+ res = SQS_CREFAIL;
+ if (fd >= 0) {
+ res = SQS_CREOK;
+ close(fd);
+ }
+ }
+
+ switch (res) {
+ case SQS_CHGOK:
+ case SQS_CREOK:
+ case SQS_SKIPCREOK:
+ printf("\t%s\n", okmsg);
+ break;
+ case SQS_CREFAIL:
+ printf("\tcannot create lock file: %s\n",
+ strerror(errsav));
+ break;
+ default:
+ printf("\tcannot %s: %s\n", failmsg, strerror(errsav));
+ break;
+ }
+
+ return (res);
+}
+
/* routine to get a current timestamp, optionally in a standard-fmt string */
void
lpd_gettime(struct timespec *tsp, char *strp, size_t strsize)
diff --git a/usr.sbin/lpr/common_source/lp.h b/usr.sbin/lpr/common_source/lp.h
index 6faaf4d..81ac7ae 100644
--- a/usr.sbin/lpr/common_source/lp.h
+++ b/usr.sbin/lpr/common_source/lp.h
@@ -223,6 +223,23 @@ typedef enum { TR_SENDING, TR_RECVING, TR_PRINTING } tr_sendrecv;
#define TEMP_FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
/*
+ * Bit-flags for set_qstate() actions, followed by the return values.
+ */
+#define SQS_DISABLEQ 0x01 /* Disable the queuing of new jobs */
+#define SQS_STOPP 0x02 /* Stop the printing of jobs */
+#define SQS_ENABLEQ 0x10 /* Enable the queuing of new jobs */
+#define SQS_STARTP 0x20 /* Start the printing of jobs */
+
+#define SQS_PARMERR -9 /* Invalid parameters from caller */
+#define SQS_CREFAIL -3 /* File did not exist, and create failed */
+#define SQS_CHGFAIL -2 /* File exists, but unable to change state */
+#define SQS_STATFAIL -1 /* Unable to stat() the lock file */
+#define SQS_CHGOK 1 /* File existed, and the state was changed */
+#define SQS_CREOK 2 /* File did not exist, but was created OK */
+#define SQS_SKIPCREOK 3 /* File did not exist, and there was */
+ /* no need to create it */
+
+/*
* Command codes used in the protocol.
*/
#define CMD_CHECK_QUE '\1'
@@ -272,6 +289,7 @@ void process(const struct printer *_pp, char *_file);
void rmjob(const char *_printer);
void rmremote(const struct printer *_pp);
void setprintcap(char *_newfile);
+int set_qstate(int _action, const char *_lfname);
void show(const char *_nfile, const char *_datafile, int _copies);
int startdaemon(const struct printer *_pp);
char *status_file_name(const struct printer *_pp, char *_buf,
diff --git a/usr.sbin/lpr/lpc/cmds.c b/usr.sbin/lpr/lpc/cmds.c
index b4a48ee..c87915c 100644
--- a/usr.sbin/lpr/lpc/cmds.c
+++ b/usr.sbin/lpr/lpc/cmds.c
@@ -70,9 +70,18 @@ static const char rcsid[] =
#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 void abortpr(struct printer *_pp, int _dis);
static int doarg(char *_job);
static int doselect(struct dirent *_d);
+static int kill_qtask(const char *lf);
static void putmsg(struct printer *_pp, int _argc, char **_argv);
static int sortq(const void *_a, const void *_b);
static void startpr(struct printer *_pp, int _chgenable);
@@ -278,6 +287,93 @@ out:
}
/*
+ * 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
@@ -302,6 +398,58 @@ upstat(struct printer *pp, const char *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) {
+ seteuid(euid);
+ upstat(pp, "printing disabled\n");
+ seteuid(uid);
+ }
+}
+
+/*
* "global" variables for all the routines related to 'clean' and 'tclean'
*/
static time_t cln_now; /* current time */
@@ -750,6 +898,21 @@ enable(struct printer *pp)
}
/*
+ * 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
@@ -786,6 +949,21 @@ disable(struct printer *pp)
}
/*
+ * 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).
*/
@@ -924,6 +1102,37 @@ restart(struct printer *pp)
}
/*
+ * 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");
+}
+
+/*
* Enable printing on the specified printer and startup the daemon.
*/
void
@@ -962,6 +1171,30 @@ startpr(struct printer *pp, int chgenable)
}
/*
+ * 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
@@ -1064,6 +1297,28 @@ stop(struct printer *pp)
seteuid(uid);
}
+/*
+ * 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) {
+ seteuid(euid);
+ upstat(pp, "printing disabled\n");
+ seteuid(uid);
+ }
+}
+
struct jobqueue **queue;
int nitems;
time_t mtime;
@@ -1237,3 +1492,26 @@ up(struct printer *pp)
{
startpr(pp, 2);
}
+
+/*
+ * 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");
+}
diff --git a/usr.sbin/lpr/lpc/cmdtab.c b/usr.sbin/lpr/lpc/cmdtab.c
index b27c312..acae213 100644
--- a/usr.sbin/lpr/lpc/cmdtab.c
+++ b/usr.sbin/lpr/lpc/cmdtab.c
@@ -65,22 +65,29 @@ char uphelp[] = "enable everything and restart spooling daemon";
#define PR 1 /* a privileged command */
struct cmd cmdtab[] = {
- { "abort", aborthelp, PR, 0, doabort },
+ { "abort", aborthelp, PR, 0, abort_q },
{ "clean", cleanhelp, PR, init_clean, clean_q },
- { "enable", enablehelp, PR, 0, enable },
+ { "enable", enablehelp, PR, 0, enable_q },
{ "exit", quithelp, 0, quit, 0 },
- { "disable", disablehelp, PR, 0, disable },
+ { "disable", disablehelp, PR, 0, disable_q },
{ "down", downhelp, PR, down, 0 },
{ "help", helphelp, 0, help, 0 },
{ "quit", quithelp, 0, quit, 0 },
- { "restart", restarthelp, 0, 0, restart },
- { "start", starthelp, PR, 0, startcmd },
+ { "restart", restarthelp, 0, 0, restart_q },
+ { "start", starthelp, PR, 0, start_q },
{ "status", statushelp, 0, 0, status },
- { "stop", stophelp, PR, 0, stop },
+ { "stop", stophelp, PR, 0, stop_q },
{ "tclean", tcleanhelp, 0, init_tclean, clean_q },
{ "topq", topqhelp, PR, topq, 0 },
- { "up", uphelp, PR, 0, up },
+ { "up", uphelp, PR, 0, up_q },
{ "?", helphelp, 0, help, 0 },
+ { "xabort", aborthelp, PR, 0, doabort },
+ { "xenable", enablehelp, PR, 0, enable },
+ { "xdisable", disablehelp, PR, 0, disable },
+ { "xrestart", restarthelp, 0, 0, restart },
+ { "xstart", starthelp, PR, 0, startcmd },
+ { "xstop", stophelp, PR, 0, stop },
+ { "xup", uphelp, PR, 0, up },
{ 0, 0, 0, 0, 0},
};
diff --git a/usr.sbin/lpr/lpc/extern.h b/usr.sbin/lpr/lpc/extern.h
index 229d9e5..dc9fe9d 100644
--- a/usr.sbin/lpr/lpc/extern.h
+++ b/usr.sbin/lpr/lpc/extern.h
@@ -42,11 +42,11 @@
__BEGIN_DECLS
+void abort_q(struct printer *_pp);
void clean_q(struct printer *_pp);
-void disable(struct printer *_pp);
-void doabort(struct printer *_pp);
+void disable_q(struct printer *_pp);
void down(int _argc, char *_argv[]);
-void enable(struct printer *_pp);
+void enable_q(struct printer *_pp);
void generic(void (*_specificrtn)(struct printer *_pp),
void (*_initcmd)(int _argc, char *_argv[]),
int _argc, char *_argv[]);
@@ -54,12 +54,19 @@ void help(int _argc, char *_argv[]);
void init_clean(int _argc, char *_argv[]);
void init_tclean(int _argc, char *_argv[]);
void quit(int _argc, char *_argv[]);
-void restart(struct printer *_pp);
-void startcmd(struct printer *_pp);
+void restart_q(struct printer *_pp);
+void start_q(struct printer *_pp);
void status(struct printer *_pp);
-void stop(struct printer *_pp);
+void stop_q(struct printer *_pp);
void topq(int _argc, char *_argv[]);
-void up(struct printer *_pp);
+void up_q(struct printer *_pp);
+void disable(struct printer *_pp); /* X-version */
+void doabort(struct printer *_pp); /* X-version */
+void enable(struct printer *_pp); /* X-version */
+void restart(struct printer *_pp); /* X-version */
+void startcmd(struct printer *_pp); /* X-version */
+void stop(struct printer *_pp); /* X-version */
+void up(struct printer *_pp); /* X-version */
__END_DECLS
extern int NCMDS;
OpenPOWER on IntegriCloud