summaryrefslogtreecommitdiffstats
path: root/usr.sbin/lpr/lpc
diff options
context:
space:
mode:
authorgad <gad@FreeBSD.org>2002-07-17 00:51:19 +0000
committergad <gad@FreeBSD.org>2002-07-17 00:51:19 +0000
commit4b659b5a6528102c39a77f1eda6a80e1941b6441 (patch)
tree8fdd71a37288853cfb368173c4dc43d9473e927f /usr.sbin/lpr/lpc
parent17cab9c595d7186722116b4c4ce891703664b642 (diff)
downloadFreeBSD-src-4b659b5a6528102c39a77f1eda6a80e1941b6441.zip
FreeBSD-src-4b659b5a6528102c39a77f1eda6a80e1941b6441.tar.gz
Changes which rewrite 'lpc topq', and which add 'lpc bottomq'. These
reflect much valuable feedback from wollman. More details on the new 'lpc topq' are in the log message for revision 1.2 of lpc/movejobs.c. The previous implementation of 'lpc topq' is available as 'lpc xtopq', in case there are any problems noticed in the new implementation. If there are no problems with this version, a later update will remove the 'lpc xtopq' command. Reviewed by: freebsd-print@bostonradio.org MFC after: 6 days
Diffstat (limited to 'usr.sbin/lpr/lpc')
-rw-r--r--usr.sbin/lpr/lpc/Makefile2
-rw-r--r--usr.sbin/lpr/lpc/cmdtab.c7
-rw-r--r--usr.sbin/lpr/lpc/extern.h13
-rw-r--r--usr.sbin/lpr/lpc/lpc.887
-rw-r--r--usr.sbin/lpr/lpc/lpc.c42
-rw-r--r--usr.sbin/lpr/lpc/movejobs.c272
6 files changed, 415 insertions, 8 deletions
diff --git a/usr.sbin/lpr/lpc/Makefile b/usr.sbin/lpr/lpc/Makefile
index 7ce0f4c..f050857 100644
--- a/usr.sbin/lpr/lpc/Makefile
+++ b/usr.sbin/lpr/lpc/Makefile
@@ -5,7 +5,7 @@
PROG= lpc
MAN= lpc.8
-SRCS= lpc.c cmds.c cmdtab.c
+SRCS= lpc.c cmds.c cmdtab.c movejobs.c
BINGRP= daemon
BINMODE= 2555
diff --git a/usr.sbin/lpr/lpc/cmdtab.c b/usr.sbin/lpr/lpc/cmdtab.c
index 2d9b17d..045bc34 100644
--- a/usr.sbin/lpr/lpc/cmdtab.c
+++ b/usr.sbin/lpr/lpc/cmdtab.c
@@ -48,6 +48,7 @@ static const char rcsid[] =
* lpc -- command tables
*/
char aborthelp[] = "terminate a spooling daemon immediately and disable printing";
+char botmqhelp[] = "move job(s) to the bottom of printer queue";
char cleanhelp[] = "remove cruft files from a queue";
char enablehelp[] = "turn a spooling queue on";
char disablehelp[] = "turn a spooling queue off";
@@ -61,7 +62,7 @@ char starthelp[] = "enable printing and start a spooling daemon";
char statushelp[] = "show status of daemon and queue";
char stophelp[] = "stop a spooling daemon after current job completes and disable printing";
char tcleanhelp[] = "test to see what files a clean cmd would remove";
-char topqhelp[] = "put job at top of printer queue";
+char topqhelp[] = "move job(s) to the top of printer queue";
char uphelp[] = "enable everything and restart spooling daemon";
/* Use some abbreviations so entries won't need to wrap */
@@ -70,6 +71,7 @@ char uphelp[] = "enable everything and restart spooling daemon";
struct cmd cmdtab[] = {
{ "abort", aborthelp, PR, 0, abort_q },
+ { "bottomq", botmqhelp, PR, bottomq_cmd, 0 },
{ "clean", cleanhelp, PR, clean_gi, clean_q },
{ "enable", enablehelp, PR, 0, enable_q },
{ "exit", quithelp, 0, quit, 0 },
@@ -83,9 +85,10 @@ struct cmd cmdtab[] = {
{ "setstatus", setstatushelp, PR|M, setstatus_gi, setstatus_q },
{ "stop", stophelp, PR, 0, stop_q },
{ "tclean", tcleanhelp, 0, tclean_gi, clean_q },
- { "topq", topqhelp, PR, topq, 0 },
+ { "topq", topqhelp, PR, topq_cmd, 0 },
{ "up", uphelp, PR, 0, up_q },
{ "?", helphelp, 0, help, 0 },
+ { "xtopq", topqhelp, PR, topq, 0 },
{ 0, 0, 0, 0, 0},
};
diff --git a/usr.sbin/lpr/lpc/extern.h b/usr.sbin/lpr/lpc/extern.h
index c2b3c7c..ee9fe97 100644
--- a/usr.sbin/lpr/lpc/extern.h
+++ b/usr.sbin/lpr/lpc/extern.h
@@ -40,9 +40,15 @@
#include <sys/types.h>
#include <sys/cdefs.h>
+/*
+ * Options for setup_myprinter().
+ */
+#define SUMP_NOHEADER 0x0001 /* Do not print a header line */
+#define SUMP_CHDIR_SD 0x0002 /* chdir into the spool directory */
__BEGIN_DECLS
void abort_q(struct printer *_pp);
+void bottomq_cmd(int _argc, char *_argv[]);
void clean_gi(int _argc, char *_argv[]);
void clean_q(struct printer *_pp);
void disable_q(struct printer *_pp);
@@ -61,8 +67,13 @@ void start_q(struct printer *_pp);
void status(struct printer *_pp);
void stop_q(struct printer *_pp);
void tclean_gi(int _argc, char *_argv[]);
-void topq(int _argc, char *_argv[]);
+void topq_cmd(int _argc, char *_argv[]);
void up_q(struct printer *_pp);
+void topq(int _argc, char *_argv[]); /* X-version */
+
+/* from lpc.c: */
+struct printer *setup_myprinter(char *_pwanted, struct printer *_pp,
+ int _sump_opts);
__END_DECLS
extern int NCMDS;
diff --git a/usr.sbin/lpr/lpc/lpc.8 b/usr.sbin/lpr/lpc/lpc.8
index 8d62b3f..a9ce4cb 100644
--- a/usr.sbin/lpr/lpc/lpc.8
+++ b/usr.sbin/lpr/lpc/lpc.8
@@ -32,7 +32,7 @@
.\" @(#)lpc.8 8.5 (Berkeley) 4/28/95
.\" $FreeBSD$
.\"
-.Dd June 15, 2002
+.Dd July 16, 2002
.Dt LPC 8
.Os
.Sh NAME
@@ -92,6 +92,18 @@ then disable printing (preventing new daemons from being started by
.Xr lpr 1 )
for the specified printers.
.Pp
+.It Ic bottomq Ar printer Xo
+.Op Ar jobspec ...
+.Xc
+Take the specified jobs in the order specified and move them to the
+bottom of the printer queue.
+Each
+.Ar jobspec
+can match multiple print jobs.
+The full description of a
+.Ar jobspec
+is given below.
+.Pp
.It Ic clean Brq Cm all | Ar printer
Remove any temporary files, data files, and control files that cannot
be printed (i.e., do not form a complete printer job)
@@ -188,16 +200,83 @@ command is a privileged command, while the
command is not restricted.
.Pp
.It Ic topq Ar printer Xo
-.Op Ar jobnum ...
-.Op Ar user ...
+.Op Ar jobspec ...
.Xc
-Place the jobs in the order listed at the top of the printer queue.
+Take the specified jobs in the order specified and move them to the
+top of the printer queue.
+Each
+.Ar jobspec
+can match multiple print jobs.
+The full description of a
+.Ar jobspec
+is given below.
.Pp
.It Ic up Brq Cm all | Ar printer
Enable everything and start a new printer daemon.
Undoes the effects of
.Ic down .
.El
+.Pp
+Commands such as
+.Ic topq
+and
+.Ic bottomq
+can take one or more
+.Ar jobspec
+to specify which jobs the command should operate on.
+A
+.Ar jobspec
+can be:
+.Bl -bullet
+.It
+a single job number, which will match all jobs in the printer's queue
+which have the same job number. Eg:
+.Ar 17 ,
+.It
+a range of job numbers, which will match all jobs with a number between
+the starting and ending job numbers, inclusive. Eg:
+.Ar 21-32 ,
+.It
+a specific userid, which will match all jobs which were sent by that
+user. Eg:
+.Ar jones ,
+.It
+a host name, when prefixed by an `@', which will match all jobs in
+the queue which were sent from the given host. Eg:
+.Ar @freebsd.org ,
+.It
+a job range and a userid, separated by a `:', which will match all jobs
+which both match the job range and were sent by the specified user. Eg:
+.Ar jones:17
+or
+.Ar 21-32:jones ,
+.It
+a job range and/or a userid, followed by a host name, which will match
+all jobs which match all the specified criteria. Eg:
+.Ar jones@freebsd.org
+or
+.Ar 21-32@freebsd.org
+or
+.Ar jones:17@freebsd.org .
+.El
+.Pp
+The values for userid and host name can also include pattern-matching
+characters, similar to the pattern matching done for filenames in
+most command shells.
+Note that if you enter a
+.Ic topq
+or
+.Ic bottomq
+command as parameters on the initial
+.Nm
+command, then the shell will expand any pattern-matching characters
+that it can (based on what files in finds in the current directory)
+before
+.Nm
+processes the command.
+In that case, any parameters which include pattern-matching characters
+should be enclosed in quotes, so that the shell will not try to
+expand them.
.Sh FILES
.Bl -tag -width /var/spool/*/lockx -compact
.It Pa /etc/printcap
diff --git a/usr.sbin/lpr/lpc/lpc.c b/usr.sbin/lpr/lpc/lpc.c
index 357e4ad..d681bb6 100644
--- a/usr.sbin/lpr/lpc/lpc.c
+++ b/usr.sbin/lpr/lpc/lpc.c
@@ -374,3 +374,45 @@ ingroup(const char *grname)
return(1);
return(0);
}
+
+/*
+ * Routine to get the information for a single printer (which will be
+ * called by the routines which implement individual commands).
+ * Note: This is for commands operating on a *single* printer.
+ */
+struct printer *
+setup_myprinter(char *pwanted, struct printer *pp, int sump_opts)
+{
+ int cdres, cmdstatus;
+
+ init_printer(pp);
+ cmdstatus = getprintcap(pwanted, pp);
+ switch (cmdstatus) {
+ default:
+ fatal(pp, "%s", pcaperr(cmdstatus));
+ /* NOTREACHED */
+ case PCAPERR_NOTFOUND:
+ printf("unknown printer %s\n", pwanted);
+ return (NULL);
+ case PCAPERR_TCOPEN:
+ printf("warning: %s: unresolved tc= reference(s)", pwanted);
+ break;
+ case PCAPERR_SUCCESS:
+ break;
+ }
+ if ((sump_opts & SUMP_NOHEADER) == 0)
+ printf("%s:\n", pp->printer);
+
+ if (sump_opts & SUMP_CHDIR_SD) {
+ seteuid(euid);
+ cdres = chdir(pp->spool_dir);
+ seteuid(uid);
+ if (cdres < 0) {
+ printf("\tcannot chdir to %s\n", pp->spool_dir);
+ free_printer(pp);
+ return (NULL);
+ }
+ }
+
+ return (pp);
+}
diff --git a/usr.sbin/lpr/lpc/movejobs.c b/usr.sbin/lpr/lpc/movejobs.c
new file mode 100644
index 0000000..08b805d
--- /dev/null
+++ b/usr.sbin/lpr/lpc/movejobs.c
@@ -0,0 +1,272 @@
+/*
+ * ------+---------+---------+---------+---------+---------+---------+---------*
+ * Copyright (c) 2002 - Garance Alistair Drosehn <gad@FreeBSD.org>.
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the FreeBSD Project
+ * or FreeBSD, Inc.
+ *
+ * ------+---------+---------+---------+---------+---------+---------+---------*
+ */
+
+#ifndef lint
+static const char rcsid[] =
+ "$FreeBSD$";
+#endif /* not lint */
+
+/*
+ * movejobs.c - The lpc commands which move jobs around.
+ */
+
+#include <sys/file.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h> /* just for MAXNAMLEN, for job_cfname in lp.h! */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "lp.h"
+#include "lpc.h"
+#include "matchjobs.h"
+#include "extern.h"
+
+/* Values for origcmd in tqbq_common() */
+#define IS_TOPQ 1
+#define IS_BOTQ 2
+
+static int process_jobs(int _argc, char *_argv[], process_jqe
+ _process_rtn, void *myinfo);
+static process_jqe touch_jqe;
+static void tqbq_common(int _argc, char *_argv[], int _origcmd);
+
+/*
+ * isdigit is defined to work on an 'int', in the range 0 to 255, plus EOF.
+ * Define a wrapper which can take 'char', either signed or unsigned.
+ */
+#define isdigitch(Anychar) isdigit(((int) Anychar) & 255)
+
+struct touchjqe_info { /* for topq/bottomq */
+ time_t newtime;
+};
+
+static int nitems;
+static struct jobqueue **queue;
+
+/*
+ * Process all the jobs, as specified by the user.
+ */
+static int
+process_jobs(int argc, char *argv[], process_jqe process_rtn, void *myinfo)
+{
+ struct jobspec_hdr jobs_wanted;
+ int i, matchcnt, pjres;
+
+ STAILQ_INIT(&jobs_wanted);
+ for (i = 0; i < argc; i++) {
+ pjres = parse_jobspec(argv[i], &jobs_wanted);
+ if (pjres == 0) {
+ printf("\tinvalid job specifier: %s\n", argv[i]);
+ continue;
+ }
+ }
+ matchcnt = scanq_jobspec(nitems, queue, SCQ_JSORDER, &jobs_wanted,
+ process_rtn, myinfo);
+
+ free_jobspec(&jobs_wanted);
+ return (matchcnt);
+}
+
+/*
+ * Reposition the job by changing the modification time of the
+ * control file.
+ */
+static int
+touch_jqe(void *myinfo, struct jobqueue *jq, struct jobspec *jspec)
+{
+ struct timeval tvp[2];
+ struct touchjqe_info *touch_info;
+ int ret;
+
+ /*
+ * If the entire queue has been scanned for the current jobspec,
+ * then let the user know if there were no jobs matched by that
+ * specification.
+ */
+ if (jq == NULL) {
+ if (jspec->matchcnt == 0) {
+ format_jobspec(jspec, FMTJS_VERBOSE);
+ if (jspec->pluralfmt)
+ printf("\tjobs %s are not in the queue\n",
+ jspec->fmtoutput);
+ else
+ printf("\tjob %s is not in the queue\n",
+ jspec->fmtoutput);
+ }
+ return (1);
+ }
+
+ /*
+ * Do a little juggling with "matched" vs "processed", so a single
+ * job can be matched by multiple specifications, and yet it will
+ * be moved only once. This is so, eg, 'topq lp 7 7' will not
+ * complain "job 7 is not in queue" for the second specification.
+ */
+ jq->job_matched = 0;
+ if (jq->job_processed) {
+ printf("\tmoved %s earlier\n", jq->job_cfname);
+ return (1);
+ }
+ jq->job_processed = 1;
+
+ touch_info = myinfo;
+ tvp[0].tv_sec = tvp[1].tv_sec = ++touch_info->newtime;
+ tvp[0].tv_usec = tvp[1].tv_usec = 0;
+ seteuid(euid);
+ ret = utimes(jq->job_cfname, tvp);
+ seteuid(uid);
+
+ if (ret == 0) {
+ if (jspec->matcheduser)
+ printf("\tmoved %s (user %s)\n", jq->job_cfname,
+ jspec->matcheduser);
+ else
+ printf("\tmoved %s\n", jq->job_cfname);
+ }
+ return (ret);
+}
+
+/*
+ * Put the specified jobs at the bottom of printer queue.
+ */
+void
+bottomq_cmd(int argc, char *argv[])
+{
+
+ if (argc < 3) {
+ printf("usage: bottomq printer [jobspec ...]\n");
+ return;
+ }
+ --argc; /* First argv was the command name */
+ ++argv;
+
+ tqbq_common(argc, argv, IS_BOTQ);
+}
+
+/*
+ * Put the specified jobs at the top of printer queue.
+ */
+void
+topq_cmd(int argc, char *argv[])
+{
+
+ if (argc < 3) {
+ printf("usage: topq printer [jobspec ...]\n");
+ return;
+ }
+ --argc; /* First argv was the command name */
+ ++argv;
+
+ tqbq_common(argc, argv, IS_TOPQ);
+}
+
+/*
+ * Processing in common between topq and bottomq commands.
+ */
+void
+tqbq_common(int argc, char *argv[], int origcmd)
+{
+ struct printer myprinter, *pp;
+ struct touchjqe_info touch_info;
+ int i, movecnt, setres;
+
+ pp = setup_myprinter(*argv, &myprinter, SUMP_CHDIR_SD);
+ if (pp == NULL)
+ return;
+ --argc; /* Second argv was the printer name */
+ ++argv;
+
+ nitems = getq(pp, &queue);
+ if (nitems == 0) {
+ printf("\tthere are no jobs in the queue\n");
+ free_printer(pp);
+ return;
+ }
+
+ /*
+ * The only real difference between topq and bottomq is the
+ * initial value used for newtime.
+ */
+ switch (origcmd) {
+ case IS_BOTQ:
+ /*
+ * When moving jobs to the bottom of the queue, pick a
+ * starting value which is one second after the last job
+ * in the queue.
+ */
+ touch_info.newtime = queue[nitems - 1]->job_time + 1;
+ break;
+ case IS_TOPQ:
+ /*
+ * When moving jobs to the top of the queue, the greatest
+ * number of jobs which could be moved is all the jobs
+ * that are in the queue. Pick a starting value which
+ * leaves plenty of room for all existing jobs.
+ */
+ touch_info.newtime = queue[0]->job_time - nitems - 5;
+ break;
+ default:
+ printf("\ninternal error in topq/bottomq processing.\n");
+ return;
+ }
+
+ movecnt = process_jobs(argc, argv, touch_jqe, &touch_info);
+
+ /*
+ * If any jobs were moved, then chmod the lock file to notify any
+ * active process for this queue that the queue has changed, so
+ * it will rescan the queue to find out the new job order.
+ */
+ if (movecnt == 0)
+ printf("\tqueue order unchanged\n");
+ else {
+ setres = set_qstate(SQS_QCHANGED, pp->lock_file);
+ if (setres < 0)
+ printf("\t* queue order changed for %s, but the\n"
+ "\t* attempt to set_qstate() failed [%d]!\n",
+ pp->printer, setres);
+ }
+
+ for (i = 0; i < nitems; i++)
+ free(queue[i]);
+ free(queue);
+ free_printer(pp);
+}
+
OpenPOWER on IntegriCloud