#include "lp.cdefs.h"
#include <sys/param.h>
#include <sys/uio.h>
#include <ctype.h>
#include <dirent.h>
#include <err.h>
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define psignal foil_gcc_psignal
#define sys_siglist foil_gcc_siglist
#include <unistd.h>
#undef psignal
#undef sys_siglist
#include "lp.h"
#include "lp.local.h"
#include "pathnames.h"
static char root[] = "root";
static int all = 0;
static int cur_daemon;
static char current[7+MAXHOSTNAMELEN];
static void alarmhandler(int _signo);
static void do_unlink(char *_file);
static int isowner(char *_owner, char *_file, const char *_cfhost);
void
rmjob(const char *printer)
{
register int i, nitems;
int assassinated = 0;
struct dirent **files;
char *cp;
struct printer myprinter, *pp = &myprinter;
init_printer(pp);
if ((i = getprintcap(printer, pp)) < 0)
fatal(pp, "getprintcap: %s", pcaperr(i));
if ((cp = checkremote(pp))) {
printf("Warning: %s\n", cp);
free(cp);
}
if (users < 0) {
if (getuid() == 0)
all = 1;
else {
user[0] = person;
users = 1;
}
}
if (!strcmp(person, "-all")) {
if (from_host == local_host)
fatal(pp, "The login name \"-all\" is reserved");
all = 1;
person = root;
}
PRIV_START
if (chdir(pp->spool_dir) < 0)
fatal(pp, "cannot chdir to spool directory");
if ((nitems = scandir(".", &files, iscf, NULL)) < 0)
fatal(pp, "cannot access spool directory");
PRIV_END
if (nitems) {
if (lockchk(pp, pp->lock_file) && chk(current)) {
PRIV_START
assassinated = kill(cur_daemon, SIGINT) == 0;
PRIV_END
if (!assassinated)
fatal(pp, "cannot kill printer daemon");
}
for (i = 0; i < nitems; i++)
process(pp, files[i]->d_name);
}
rmremote(pp);
if (assassinated && !startdaemon(pp))
fatal(pp, "cannot restart printer daemon\n");
exit(0);
}
int
lockchk(struct printer *pp, char *slockf)
{
register FILE *fp;
register int i, n;
PRIV_START
if ((fp = fopen(slockf, "r")) == NULL) {
if (errno == EACCES)
fatal(pp, "%s: %s", slockf, strerror(errno));
else
return(0);
}
PRIV_END
if (!get_line(fp)) {
(void) fclose(fp);
return(0);
}
cur_daemon = atoi(line);
if (kill(cur_daemon, 0) < 0 && errno != EPERM) {
(void) fclose(fp);
return(0);
}
for (i = 1; (n = fread(current, sizeof(char), sizeof(current), fp)) <= 0; i++) {
if (i > 5) {
n = 1;
break;
}
sleep(i);
}
current[n-1] = '\0';
(void) fclose(fp);
return(1);
}
void
process(const struct printer *pp, char *file)
{
FILE *cfp;
if (!chk(file))
return;
PRIV_START
if ((cfp = fopen(file, "r")) == NULL)
fatal(pp, "cannot open %s", file);
PRIV_END
while (get_line(cfp)) {
switch (line[0]) {
case 'U':
if (strchr(line+1, '/') || strncmp(line+1, "df", 2))
break;
do_unlink(line+1);
}
}
(void) fclose(cfp);
do_unlink(file);
}
static void
do_unlink(char *file)
{
int ret;
if (from_host != local_host)
printf("%s: ", local_host);
PRIV_START
ret = unlink(file);
PRIV_END
printf(ret ? "cannot dequeue %s\n" : "%s dequeued\n", file);
}
int
chk(char *file)
{
int *r, jnum;
char **u;
const char *cfhost;
FILE *cfp;
if (strlen(file) < 7 || file[0] != 'c' || file[1] != 'f')
return(0);
jnum = calc_jobnum(file, &cfhost);
if (all && (from_host == local_host || !strcmp(from_host, cfhost)))
return(1);
PRIV_START
if ((cfp = fopen(file, "r")) == NULL)
return(0);
PRIV_END
while (get_line(cfp)) {
if (line[0] == 'P')
break;
}
(void) fclose(cfp);
if (line[0] != 'P')
return(0);
if (users == 0 && requests == 0)
return(!strcmp(file, current) && isowner(line+1, file, cfhost));
for (r = requ; r < &requ[requests]; r++)
if (*r == jnum && isowner(line+1, file, cfhost))
return(1);
for (u = user; u < &user[users]; u++)
if (!strcmp(*u, line+1) && isowner(line+1, file, cfhost))
return(1);
return(0);
}
static int
isowner(char *owner, char *file, const char *cfhost)
{
if (!strcmp(person, root) && (from_host == local_host ||
!strcmp(from_host, cfhost)))
return (1);
if (!strcmp(person, owner) && !strcmp(from_host, cfhost))
return (1);
if (from_host != local_host)
printf("%s: ", local_host);
printf("%s: Permission denied\n", file);
return(0);
}
void
rmremote(const struct printer *pp)
{
int i, elem, firstreq, niov, rem, totlen;
char buf[BUFSIZ];
void (*savealrm)(int);
struct iovec *iov;
if (!pp->remote)
return;
fflush(stdout);
if (users > 0)
niov = 4 + 2 * users + requests + 1;
else
niov = 4 + requests + 1;
iov = malloc(niov * sizeof *iov);
if (iov == NULL)
fatal(pp, "out of memory in rmremote()");
iov[0].iov_base = "\5";
iov[1].iov_base = pp->remote_queue;
iov[2].iov_base = " ";
iov[3].iov_base = all ? "-all" : person;
elem = 4;
for (i = 0; i < users; i++) {
iov[elem].iov_base = " ";
iov[elem + 1].iov_base = user[i];
elem += 2;
}
firstreq = elem;
for (i = 0; i < requests; i++) {
asprintf((char **)&iov[elem].iov_base, " %d", requ[i]);
if (iov[elem].iov_base == 0)
fatal(pp, "out of memory in rmremote()");
elem++;
}
iov[elem++].iov_base = "\n";
for (totlen = i = 0; i < niov; i++)
totlen += (iov[i].iov_len = strlen(iov[i].iov_base));
savealrm = signal(SIGALRM, alarmhandler);
alarm(pp->conn_timeout);
rem = getport(pp, pp->remote_host, 0);
(void)signal(SIGALRM, savealrm);
if (rem < 0) {
if (from_host != local_host)
printf("%s: ", local_host);
printf("connection to %s is down\n", pp->remote_host);
} else {
if (writev(rem, iov, niov) != totlen)
fatal(pp, "Lost connection");
while ((i = read(rem, buf, sizeof(buf))) > 0)
(void) fwrite(buf, 1, i, stdout);
(void) close(rem);
}
for (i = 0; i < requests; i++)
free(iov[firstreq + i].iov_base);
free(iov);
}
int
iscf(const struct dirent *d)
{
return(d->d_name[0] == 'c' && d->d_name[1] == 'f');
}
void
alarmhandler(int signo __unused)
{
}