#include "lp.cdefs.h"
#include <sys/file.h>
#include <sys/param.h>
#include <sys/queue.h>
#include <sys/time.h>
#include <dirent.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
#define DEBUG_SCANJS 0
static int match_jobspec(struct jobqueue *_jq, struct jobspec *_jspec);
#define isdigitch(Anychar) isdigit(((int) Anychar) & 255)
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 (jspec->fmtoutput != NULL) {
free(jspec->fmtoutput);
jspec->fmtoutput = NULL;
}
jspec->pluralfmt = 1;
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:
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);
strsize = strlen(buildstr) + 1;
if (jspec->wantedhost != NULL)
strsize += strlen(jspec->wantedhost);
jspec->fmtoutput = malloc(strsize);
strlcpy(jspec->fmtoutput, buildstr, strsize);
if (jspec->wantedhost != NULL)
strlcat(jspec->fmtoutput, jspec->wantedhost, strsize);
break;
case FMTJS_VERBOSE:
default:
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);
}
strsize = strlen(buildstr) + 1;
if (jspec->wantedhost != NULL)
strsize += strlen(jspec->wantedhost);
jspec->fmtoutput = malloc(strsize);
strlcpy(jspec->fmtoutput, buildstr, strsize);
if (jspec->wantedhost != NULL)
strlcat(jspec->fmtoutput, jspec->wantedhost, strsize);
break;
}
}
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);
}
}
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;
numstr = NULL;
atsign = strchr(jobstr, '@');
colon = strchr(jobstr, ':');
if (atsign != NULL)
*atsign = '\0';
if (colon != NULL)
*colon = '\0';
if (atsign != NULL) {
rhside = atsign + 1;
if (*rhside != '\0')
jsinfo->wantedhost = rhside;
}
rhside = NULL;
if (colon != NULL) {
rhside = colon + 1;
if (*rhside == '\0')
rhside = NULL;
}
lhside = NULL;
if (*jobstr != '\0')
lhside = jobstr;
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;
period = strchr(lhside, '.');
if ((atsign == NULL) && (period != NULL))
jsinfo->wantedhost = lhside;
else
jsinfo->wanteduser = lhside;
} else {
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;
}
if (numstr != NULL) {
errno = 0;
jobnum = strtol(numstr, &numstr, 10);
if (errno != 0)
goto bad_input;
if (jobnum < 0)
goto bad_input;
if (jobnum > 99999)
goto bad_input;
jsinfo->startnum = jsinfo->endrange = jobnum;
if ((*numstr == '-') && (isdigitch(*(numstr + 1)))) {
numstr++;
errno = 0;
jobnum = strtol(numstr, &numstr, 10);
if (errno != 0)
goto bad_input;
if (jobnum < jsinfo->startnum)
goto bad_input;
if (jobnum > 99999)
goto bad_input;
jsinfo->endrange = jobnum;
}
if (*numstr != '\0') {
if (atsign != NULL)
goto bad_input;
if (jsinfo->wantedhost != NULL)
goto bad_input;
if (jsinfo->wanteduser != NULL)
goto bad_input;
jsinfo->wantedhost = numstr;
}
}
if ((jsinfo->startnum < 0) && (jsinfo->wanteduser == NULL) &&
(jsinfo->wantedhost == NULL))
goto bad_input;
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:
if (atsign != NULL)
*atsign = '@';
if (colon != NULL)
*colon = ':';
if (jsinfo != NULL)
free(jsinfo);
return (0);
}
static int
match_jobspec(struct jobqueue *jq, struct jobspec *jspec)
{
struct cjobinfo *cfinf;
const char *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);
if (jq->job_matched)
return (0);
jnum = calc_jobnum(jq->job_cfname, &cf_hoststr);
cfinf = NULL;
match = 0;
jspec->matcheduser = NULL;
if (jspec->startnum >= 0) {
if (jnum < jspec->startnum)
goto nomatch;
if (jnum > jspec->endrange)
goto nomatch;
}
if (jspec->wantedhost != NULL) {
if (fnmatch(jspec->wantedhost, cf_hoststr, 0) != 0)
goto nomatch;
}
if (jspec->wanteduser != NULL) {
cfinf = ctl_readcf("fakeq", jq->job_cfname);
if (cfinf == NULL)
goto nomatch;
if (fnmatch(jspec->wanteduser, cfinf->cji_acctuser, 0) != 0)
goto nomatch;
}
match = 1;
jq->job_matched = 1;
jspec->matchcnt++;
if (jspec->wanteduser != NULL) {
jspec->matcheduser = strdup(cfinf->cji_acctuser);
}
#if DEBUG_SCANJS
printf("\t [ job matched! ]\n");
#endif
nomatch:
if (cfinf != NULL)
ctl_freeinf(cfinf);
return (match);
}
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);
if ((sopts & (SCQ_JSORDER|SCQ_QORDER)) == 0)
return (-1);
total = 0;
if (sopts & SCQ_JSORDER) {
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;
}
}
if (doentry != NULL)
doentry(doentryinfo, NULL, jspec);
}
} else {
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;
}
break;
}
}
}
return (total);
}