summaryrefslogtreecommitdiffstats
path: root/usr.sbin/lpr/common_source
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/common_source
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/common_source')
-rw-r--r--usr.sbin/lpr/common_source/Makefile4
-rw-r--r--usr.sbin/lpr/common_source/matchjobs.c585
-rw-r--r--usr.sbin/lpr/common_source/matchjobs.h101
3 files changed, 688 insertions, 2 deletions
diff --git a/usr.sbin/lpr/common_source/Makefile b/usr.sbin/lpr/common_source/Makefile
index 0f03941..352f79c 100644
--- a/usr.sbin/lpr/common_source/Makefile
+++ b/usr.sbin/lpr/common_source/Makefile
@@ -7,7 +7,7 @@
#
LIB= lpr
INTERNALLIB= YES
-SRCS= common.c ctlinfo.c displayq.c net.c printcap.c request.c \
- rmjob.c startdaemon.c
+SRCS= common.c ctlinfo.c displayq.c matchjobs.c net.c \
+ printcap.c request.c rmjob.c startdaemon.c
.include <bsd.lib.mk>
diff --git a/usr.sbin/lpr/common_source/matchjobs.c b/usr.sbin/lpr/common_source/matchjobs.c
new file mode 100644
index 0000000..568aab3
--- /dev/null
+++ b/usr.sbin/lpr/common_source/matchjobs.c
@@ -0,0 +1,585 @@
+/*
+ * ------+---------+---------+---------+---------+---------+---------+---------*
+ * 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 <dirent.h> /* for MAXNAMLEN, for job_cfname in lp.h! */
+#include <ctype.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include "ctlinfo.h"
+#include "lp.h"
+#include "matchjobs.h"
+
+#define DEBUG_PARSEJS 0 /* set to 1 when testing */
+#define DEBUG_SCANJS 0 /* set to 1 when testing */
+
+static int match_jobspec(struct jobqueue *_jq, struct jobspec *_jspec);
+
+/*
+ * 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)
+
+/*
+ * Format a single jobspec into a string fit for printing.
+ */
+void
+format_jobspec(struct jobspec *jspec, int fmt_wanted)
+{
+ char rangestr[40], buildstr[200];
+ const char fromuser[] = "from user ";
+ const char fromhost[] = "from host ";
+ size_t strsize;
+
+ /*
+ * If the struct already has a fmtstring, then release it
+ * before building a new one.
+ */
+ if (jspec->fmtoutput != NULL) {
+ free(jspec->fmtoutput);
+ jspec->fmtoutput = NULL;
+ }
+
+ jspec->pluralfmt = 1; /* assume a "plural result" */
+ rangestr[0] = '\0';
+ if (jspec->startnum >= 0) {
+ if (jspec->startnum != jspec->endrange)
+ snprintf(rangestr, sizeof(rangestr), "%ld-%ld",
+ jspec->startnum, jspec->endrange);
+ else {
+ jspec->pluralfmt = 0;
+ snprintf(rangestr, sizeof(rangestr), "%ld",
+ jspec->startnum);
+ }
+ }
+
+ strsize = sizeof(buildstr);
+ buildstr[0] = '\0';
+ switch (fmt_wanted) {
+ case FMTJS_TERSE:
+ /* Build everything but the hostname in a temp string. */
+ if (jspec->wanteduser != NULL)
+ strlcat(buildstr, jspec->wanteduser, strsize);
+ if (rangestr[0] != '\0') {
+ if (buildstr[0] != '\0')
+ strlcat(buildstr, ":", strsize);
+ strlcat(buildstr, rangestr, strsize);
+ }
+ if (jspec->wantedhost != NULL)
+ strlcat(buildstr, "@", strsize);
+
+ /* Get space for the final result, including hostname */
+ strsize = strlen(buildstr) + 1;
+ if (jspec->wantedhost != NULL)
+ strsize += strlen(jspec->wantedhost);
+ jspec->fmtoutput = malloc(strsize);
+
+ /* Put together the final result */
+ strlcpy(jspec->fmtoutput, buildstr, strsize);
+ if (jspec->wantedhost != NULL)
+ strlcat(jspec->fmtoutput, jspec->wantedhost, strsize);
+ break;
+
+ case FMTJS_VERBOSE:
+ default:
+ /* Build everything but the hostname in a temp string. */
+ strlcat(buildstr, rangestr, strsize);
+ if (jspec->wanteduser != NULL) {
+ if (rangestr[0] != '\0')
+ strlcat(buildstr, " ", strsize);
+ strlcat(buildstr, fromuser, strsize);
+ strlcat(buildstr, jspec->wanteduser, strsize);
+ }
+ if (jspec->wantedhost != NULL) {
+ if (jspec->wanteduser == NULL) {
+ if (rangestr[0] != '\0')
+ strlcat(buildstr, " ", strsize);
+ strlcat(buildstr, fromhost, strsize);
+ } else
+ strlcat(buildstr, "@", strsize);
+ }
+
+ /* Get space for the final result, including hostname */
+ strsize = strlen(buildstr) + 1;
+ if (jspec->wantedhost != NULL)
+ strsize += strlen(jspec->wantedhost);
+ jspec->fmtoutput = malloc(strsize);
+
+ /* Put together the final result */
+ strlcpy(jspec->fmtoutput, buildstr, strsize);
+ if (jspec->wantedhost != NULL)
+ strlcat(jspec->fmtoutput, jspec->wantedhost, strsize);
+ break;
+ }
+}
+
+/*
+ * Free all the jobspec-related information.
+ */
+void
+free_jobspec(struct jobspec_hdr *js_hdr)
+{
+ struct jobspec *jsinf;
+
+ while (!STAILQ_EMPTY(js_hdr)) {
+ jsinf = STAILQ_FIRST(js_hdr);
+ STAILQ_REMOVE_HEAD(js_hdr, nextjs);
+ if (jsinf->fmtoutput)
+ free(jsinf->fmtoutput);
+ if (jsinf->matcheduser)
+ free(jsinf->matcheduser);
+ free(jsinf);
+ }
+}
+
+/*
+ * This routine takes a string as typed in from the user, and parses it
+ * into a job-specification. A job specification would match one or more
+ * jobs in the queue of some single printer (the specification itself does
+ * not indicate which queue should be searched).
+ *
+ * This recognizes a job-number range by itself (all digits, or a range
+ * indicated by "digits-digits"), or a userid by itself. If a `:' is
+ * found, it is treated as a separator between a job-number range and
+ * a userid, where the job number range is the side which has a digit as
+ * the first character. If an `@' is found, everything to the right of
+ * it is treated as the hostname the job originated from.
+ *
+ * So, the user can specify:
+ * jobrange userid userid:jobrange jobrange:userid
+ * jobrange@hostname jobrange:userid@hostname
+ * userid@hostname userid:jobrange@hostname
+ *
+ * XXX - it would be nice to add "not options" too, such as ^user,
+ * ^jobrange, and @^hostname.
+ *
+ * This routine may modify the original input string if that input is
+ * valid. If the input was *not* valid, then this routine should return
+ * with the input string the same as when the routine was called.
+ */
+int
+parse_jobspec(char *jobstr, struct jobspec_hdr *js_hdr)
+{
+ struct jobspec *jsinfo;
+ char *atsign, *colon, *lhside, *numstr, *period, *rhside;
+ int jobnum;
+
+#if DEBUG_PARSEJS
+ printf("\t [ pjs-input = %s ]\n", jobstr);
+#endif
+
+ if ((jobstr == NULL) || (*jobstr == '\0'))
+ return (0);
+
+ jsinfo = malloc(sizeof(struct jobspec));
+ memset(jsinfo, 0, sizeof(struct jobspec));
+ jsinfo->startnum = jsinfo->endrange = -1;
+
+ /* Find the separator characters, and nullify them. */
+ numstr = NULL;
+ atsign = strchr(jobstr, '@');
+ colon = strchr(jobstr, ':');
+ if (atsign != NULL)
+ *atsign = '\0';
+ if (colon != NULL)
+ *colon = '\0';
+
+ /* The at-sign always indicates a hostname. */
+ if (atsign != NULL) {
+ rhside = atsign + 1;
+ if (*rhside != '\0')
+ jsinfo->wantedhost = rhside;
+ }
+
+ /* Finish splitting the input into three parts. */
+ rhside = NULL;
+ if (colon != NULL) {
+ rhside = colon + 1;
+ if (*rhside == '\0')
+ rhside = NULL;
+ }
+ lhside = NULL;
+ if (*jobstr != '\0')
+ lhside = jobstr;
+
+ /*
+ * If there is a `:' here, then it's either jobrange:userid,
+ * userid:jobrange, or (if @hostname was not given) perhaps it
+ * might be hostname:jobnum. The side which has a digit as the
+ * first character is assumed to be the jobrange. It is an
+ * input error if both sides start with a digit, or if neither
+ * side starts with a digit.
+ */
+ if ((lhside != NULL) && (rhside != NULL)) {
+ if (isdigitch(*lhside)) {
+ if (isdigitch(*rhside))
+ goto bad_input;
+ numstr = lhside;
+ jsinfo->wanteduser = rhside;
+ } else if (isdigitch(*rhside)) {
+ numstr = rhside;
+ /*
+ * The original implementation of 'lpc topq' accepted
+ * hostname:jobnum. If the input did not include a
+ * @hostname, then assume the userid is a hostname if
+ * it includes a '.'.
+ */
+ period = strchr(lhside, '.');
+ if ((atsign == NULL) && (period != NULL))
+ jsinfo->wantedhost = lhside;
+ else
+ jsinfo->wanteduser = lhside;
+ } else {
+ /* Neither side is a job number = user error */
+ goto bad_input;
+ }
+ } else if (lhside != NULL) {
+ if (isdigitch(*lhside))
+ numstr = lhside;
+ else
+ jsinfo->wanteduser = lhside;
+ } else if (rhside != NULL) {
+ if (isdigitch(*rhside))
+ numstr = rhside;
+ else
+ jsinfo->wanteduser = rhside;
+ }
+
+ /*
+ * Break down the numstr. It should be all digits, or a range
+ * specified as "\d+-\d+".
+ */
+ if (numstr != NULL) {
+ errno = 0;
+ jobnum = strtol(numstr, &numstr, 10);
+ if (errno != 0) /* error in conversion */
+ goto bad_input;
+ if (jobnum < 0) /* a bogus value for this purpose */
+ goto bad_input;
+ if (jobnum > 99999) /* too large for job number */
+ goto bad_input;
+ jsinfo->startnum = jsinfo->endrange = jobnum;
+
+ /* Check for a range of numbers */
+ if ((*numstr == '-') && (isdigitch(*(numstr + 1)))) {
+ numstr++;
+ errno = 0;
+ jobnum = strtol(numstr, &numstr, 10);
+ if (errno != 0) /* error in conversion */
+ goto bad_input;
+ if (jobnum < jsinfo->startnum)
+ goto bad_input;
+ if (jobnum > 99999) /* too large for job number */
+ goto bad_input;
+ jsinfo->endrange = jobnum;
+ }
+
+ /*
+ * If there is anything left in the numstr, and if the
+ * original string did not include a userid or a hostname,
+ * then this might be the ancient form of '\d+hostname'
+ * (with no seperator between jobnum and hostname). Accept
+ * that for backwards compatibility, but otherwise any
+ * remaining characters mean a user-error. Note that the
+ * ancient form accepted only a single number, but this
+ * will also accept a range of numbers.
+ */
+ if (*numstr != '\0') {
+ if (atsign != NULL)
+ goto bad_input;
+ if (jsinfo->wantedhost != NULL)
+ goto bad_input;
+ if (jsinfo->wanteduser != NULL)
+ goto bad_input;
+ /* Treat as the rest of the string as a hostname */
+ jsinfo->wantedhost = numstr;
+ }
+ }
+
+ if ((jsinfo->startnum < 0) && (jsinfo->wanteduser == NULL) &&
+ (jsinfo->wantedhost == NULL))
+ goto bad_input;
+
+ /*
+ * The input was valid, in the sense that it could be parsed
+ * into the individual parts. Add this jobspec to the list
+ * of jobspecs.
+ */
+ STAILQ_INSERT_TAIL(js_hdr, jsinfo, nextjs);
+
+#if DEBUG_PARSEJS
+ printf("\t [ will check for");
+ if (jsinfo->startnum >= 0) {
+ if (jsinfo->startnum == jsinfo->endrange)
+ printf(" jobnum = %ld", jsinfo->startnum);
+ else
+ printf(" jobrange = %ld to %ld", jsinfo->startnum,
+ jsinfo->endrange);
+ } else {
+ printf(" jobs");
+ }
+ if ((jsinfo->wanteduser != NULL) || (jsinfo->wantedhost != NULL)) {
+ printf(" from");
+ if (jsinfo->wanteduser != NULL)
+ printf(" user = %s", jsinfo->wanteduser);
+ if (jsinfo->wantedhost != NULL)
+ printf(" host = %s", jsinfo->wantedhost);
+ }
+ printf("]\n");
+#endif
+
+ return (1);
+
+bad_input:
+ /*
+ * Restore any `@' and `:', in case the calling routine wants to
+ * write an error message which includes the input string.
+ */
+ if (atsign != NULL)
+ *atsign = '@';
+ if (colon != NULL)
+ *colon = ':';
+ if (jsinfo != NULL)
+ free(jsinfo);
+ return (0);
+}
+
+/*
+ * Check to see if a given job (specified by a jobqueue entry) matches
+ * all of the specifications in a given jobspec.
+ *
+ * Returns 0 if no match, 1 if the job does match.
+ */
+static int
+match_jobspec(struct jobqueue *jq, struct jobspec *jspec)
+{
+ struct cjobinfo *cfinf;
+ char *cp, *cf_numstr, *cf_hoststr;
+ int jnum, match;
+
+#if DEBUG_SCANJS
+ printf("\t [ match-js checking %s ]\n", jq->job_cfname);
+#endif
+
+ if (jspec == NULL || jq == NULL)
+ return (0);
+
+ /*
+ * Keep track of which jobs have already been matched by this
+ * routine, and thus (probably) already processed.
+ */
+ if (jq->job_matched)
+ return (0);
+
+ /*
+ * The standard `cf' file has the job number start in position 4,
+ * but some implementations have that as an extra file-sequence
+ * letter, and start the job number in position 5. The job
+ * number is usually three bytes, but may be as many as five.
+ *
+ * XXX - All this nonsense should really be handled in a single
+ * place, like getq()...
+ */
+ cf_numstr = jq->job_cfname + 3;
+ if (!isdigitch(*cf_numstr))
+ cf_numstr++;
+ jnum = 0;
+ for (cp = cf_numstr; (cp < cf_numstr + 5) && isdigitch(*cp); cp++)
+ jnum = jnum * 10 + (*cp - '0');
+ cf_hoststr = cp;
+ cfinf = NULL;
+ match = 0; /* assume the job will not match */
+ jspec->matcheduser = NULL;
+
+ /*
+ * Check the job-number range.
+ */
+ if (jspec->startnum >= 0) {
+ if (jnum < jspec->startnum)
+ goto nomatch;
+ if (jnum > jspec->endrange)
+ goto nomatch;
+ }
+
+ /*
+ * Check the hostname. Strictly speaking this should be done by
+ * reading the control file, but it is less expensive to check
+ * the hostname-part of the control file name. Also, this value
+ * can be easily seen in 'lpq -l', while there is no easy way for
+ * a user/operator to see the hostname in the control file.
+ */
+ if (jspec->wantedhost != NULL) {
+ if (fnmatch(jspec->wantedhost, cf_hoststr, 0) != 0)
+ goto nomatch;
+ }
+
+ /*
+ * Check for a match on the user name. This has to be done
+ * by reading the control file.
+ */
+ if (jspec->wanteduser != NULL) {
+ cfinf = ctl_readcf("fakeq", jq->job_cfname);
+ if (cfinf == NULL)
+ goto nomatch;
+ if (fnmatch(jspec->wanteduser, cfinf->cji_username, 0) != 0)
+ goto nomatch;
+ }
+
+ /* This job matches all of the specified criteria. */
+ match = 1;
+ jq->job_matched = 1; /* avoid matching the job twice */
+ jspec->matchcnt++;
+ if (jspec->wanteduser != NULL) {
+ /*
+ * If the user specified a userid (which may have been a
+ * pattern), then the caller's "doentry()" routine might
+ * want to know the userid of this job that matched.
+ */
+ jspec->matcheduser = strdup(cfinf->cji_username);
+ }
+#if DEBUG_SCANJS
+ printf("\t [ job matched! ]\n");
+#endif
+
+nomatch:
+ if (cfinf != NULL)
+ ctl_freeinf(cfinf);
+ return (match);
+}
+
+/*
+ * Scan a queue for all jobs which match a jobspec. The queue is scanned
+ * from top to bottom.
+ *
+ * The caller can provide a routine which will be executed for each job
+ * that does match. Note that the processing routine might do anything
+ * to the matched job -- including the removal of it.
+ *
+ * This returns the number of jobs which were matched.
+ */
+int
+scanq_jobspec(int qcount, struct jobqueue **squeue, int sopts, struct
+ jobspec_hdr *js_hdr, process_jqe doentry, void *doentryinfo)
+{
+ struct jobqueue **qent;
+ struct jobspec *jspec;
+ int cnt, matched, total;
+
+ if (qcount < 1)
+ return (0);
+ if (js_hdr == NULL)
+ return (-1);
+
+ /* The caller must specify one of the scanning orders */
+ if ((sopts & (SCQ_JSORDER|SCQ_QORDER)) == 0)
+ return (-1);
+
+ total = 0;
+ if (sopts & SCQ_JSORDER) {
+ /*
+ * For each job specification, scan through the queue
+ * looking for every job that matches.
+ */
+ STAILQ_FOREACH(jspec, js_hdr, nextjs) {
+ for (qent = squeue, cnt = 0; cnt < qcount;
+ qent++, cnt++) {
+ matched = match_jobspec(*qent, jspec);
+ if (!matched)
+ continue;
+ total++;
+ if (doentry != NULL)
+ doentry(doentryinfo, *qent, jspec);
+ if (jspec->matcheduser != NULL) {
+ free(jspec->matcheduser);
+ jspec->matcheduser = NULL;
+ }
+ }
+ /*
+ * The entire queue has been scanned for this
+ * jobspec. Call the user's routine again with
+ * a NULL queue-entry, so it can print out any
+ * kind of per-jobspec summary.
+ */
+ if (doentry != NULL)
+ doentry(doentryinfo, NULL, jspec);
+ }
+ } else {
+ /*
+ * For each job in the queue, check all of the job
+ * specifications to see if any one of them matches
+ * that job.
+ */
+ for (qent = squeue, cnt = 0; cnt < qcount;
+ qent++, cnt++) {
+ STAILQ_FOREACH(jspec, js_hdr, nextjs) {
+ matched = match_jobspec(*qent, jspec);
+ if (!matched)
+ continue;
+ total++;
+ if (doentry != NULL)
+ doentry(doentryinfo, *qent, jspec);
+ if (jspec->matcheduser != NULL) {
+ free(jspec->matcheduser);
+ jspec->matcheduser = NULL;
+ }
+ /*
+ * Once there is a match, then there is no
+ * point in checking this same job against
+ * all the other jobspec's.
+ */
+ break;
+ }
+ }
+ }
+
+ return (total);
+}
diff --git a/usr.sbin/lpr/common_source/matchjobs.h b/usr.sbin/lpr/common_source/matchjobs.h
new file mode 100644
index 0000000..d4c0682
--- /dev/null
+++ b/usr.sbin/lpr/common_source/matchjobs.h
@@ -0,0 +1,101 @@
+/*
+ * ------+---------+---------+---------+---------+---------+---------+---------*
+ * 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.
+ *
+ * ------+---------+---------+---------+---------+---------+---------+---------*
+ * $FreeBSD$
+ * ------+---------+---------+---------+---------+---------+---------+---------*
+ */
+
+#include <sys/queue.h>
+
+/*
+ * The "matcheduser" field is *only* valid during the call to the
+ * given "doentry()" routine, and is only set if the specification
+ * included a userid.
+ */
+struct jobspec {
+ STAILQ_ENTRY(jobspec) nextjs;
+ char *wantedhost;
+ char *wanteduser;
+ char *matcheduser; /* only valid for "doentry()" */
+ char *fmtoutput; /* set by format_jobspec() */
+ long startnum;
+ long endrange;
+ int pluralfmt; /* boolean set by format_jobspec() */
+ uint matchcnt;
+};
+STAILQ_HEAD(jobspec_hdr, jobspec);
+
+/*
+ * Format options for format_jobspec.
+ */
+#define FMTJS_TERSE 1 /* user:jobrange@host */
+#define FMTJS_VERBOSE 2 /* jobrange from user@host */
+
+/*
+ * Options for scanq_jobspec.
+ *
+ * The caller must choose the order that entries should be scanned:
+ * 1) JSORDER: Matched jobs are processed (by calling the "doentry()"
+ * routine) in the order that the user specified those jobs.
+ * 2) QORDER: Matched jobs are processed in the order that the jobs are
+ * listed the queue. This guarantees that the "doentry()" routine
+ * will be called only once per job.
+ *
+ * There is a "job_matched" variable in struct jobqueue, which is used
+ * to make sure that the "doentry()" will only be called once for any
+ * given job in JSORDER processing. The "doentry()" routine can turn
+ * that off, if it does want to be called multiple times when the job
+ * is matched by multiple specifiers.
+ *
+ * The JSORDER processing will also call the "doentry()" routine once
+ * after each scan of the queue, with the jobqueue set to null. This
+ * provides a way for the caller to print out a summary message for
+ * each jobspec that was given.
+ */
+#define SCQ_JSORDER 0x0001 /* follow the user-specified order */
+#define SCQ_QORDER 0x0002 /* the order of jobs in the queue */
+
+#include <sys/cdefs.h>
+__BEGIN_DECLS
+struct jobqueue;
+
+typedef int process_jqe(void *_myinfo, struct jobqueue *_jq,
+ struct jobspec *_jspec);
+
+void format_jobspec(struct jobspec *_jspec, int _fmt_wanted);
+void free_jobspec(struct jobspec_hdr *_js_hdr);
+int scanq_jobspec(int _qitems, struct jobqueue **_squeue, int _sopts,
+ struct jobspec_hdr *_js_hdr, process_jqe _doentry,
+ void *_doentryinfo);
+int parse_jobspec(char *_jobstr, struct jobspec_hdr *_js_hdr);
+__END_DECLS
+
OpenPOWER on IntegriCloud