#include <pwd.h>
#include <stdlib.h>
#include <signal.h>
#include <syslog.h>
#include <unistd.h>
#include "lpd.h"
#include "lp.h"
#include "log.h"
#include "proc.h"
static void engine_shutdown(void);
static void engine_dispatch_priv(struct imsgproc *, struct imsg *, void *);
static void engine_dispatch_frontend(struct imsgproc *, struct imsg *, void *);
char *lpd_hostname;
void
engine(int debug, int verbose)
{
struct passwd *pw;
log_init(debug, LOG_LPR);
log_setverbose(verbose);
log_procinit("engine");
setproctitle("engine");
if ((lpd_hostname = malloc(HOST_NAME_MAX+1)) == NULL)
fatal("%s: malloc", __func__);
gethostname(lpd_hostname, HOST_NAME_MAX + 1);
if ((pw = getpwnam(LPD_USER)) == NULL)
fatal("%s: getpwnam: %s", __func__, LPD_USER);
if (setgroups(1, &pw->pw_gid) ||
setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
fatal("%s: cannot drop privileges", __func__);
if (pledge("stdio rpath wpath cpath flock dns sendfd recvfd proc",
NULL) == -1)
fatal("%s: pledge", __func__);
event_init();
signal(SIGPIPE, SIG_IGN);
p_priv = proc_attach(PROC_PRIV, 3);
if (p_priv == NULL)
fatal("%s: proc_attach", __func__);
proc_setcallback(p_priv, engine_dispatch_priv, NULL);
proc_enable(p_priv);
event_dispatch();
engine_shutdown();
}
static void
engine_shutdown()
{
lpr_shutdown();
log_debug("exiting");
exit(0);
}
static void
engine_dispatch_priv(struct imsgproc *proc, struct imsg *imsg, void *arg)
{
struct lp_printer lp;
int fd;
if (imsg == NULL) {
log_debug("%s: imsg connection lost", __func__);
event_loopexit(NULL);
return;
}
if (log_getverbose() > LOGLEVEL_IMSG)
log_imsg(proc, imsg);
switch (imsg->hdr.type) {
case IMSG_SOCK_FRONTEND:
m_end(proc);
if ((fd = imsg_get_fd(imsg)) == -1)
fatalx("failed to receive frontend socket");
p_frontend = proc_attach(PROC_FRONTEND, fd);
proc_setcallback(p_frontend, engine_dispatch_frontend, NULL);
proc_enable(p_frontend);
break;
case IMSG_CONF_START:
m_end(proc);
break;
case IMSG_CONF_END:
m_end(proc);
while (lp_scanprinters(&lp) == 1) {
lpr_printjob(lp.lp_name);
lp_clearprinter(&lp);
}
break;
default:
fatalx("%s: unexpected imsg %s", __func__,
log_fmt_imsgtype(imsg->hdr.type));
}
}
static void
engine_dispatch_frontend(struct imsgproc *proc, struct imsg *imsg, void *arg)
{
if (imsg == NULL) {
log_debug("%s: imsg connection lost", __func__);
event_loopexit(NULL);
return;
}
if (log_getverbose() > LOGLEVEL_IMSG)
log_imsg(proc, imsg);
switch (imsg->hdr.type) {
case IMSG_GETADDRINFO:
case IMSG_GETNAMEINFO:
resolver_dispatch_request(proc, imsg);
break;
case IMSG_LPR_ALLOWEDHOST:
case IMSG_LPR_DISPLAYQ:
case IMSG_LPR_PRINTJOB:
case IMSG_LPR_RECVJOB:
case IMSG_LPR_RECVJOB_CLEAR:
case IMSG_LPR_RECVJOB_CF:
case IMSG_LPR_RECVJOB_DF:
case IMSG_LPR_RECVJOB_COMMIT:
case IMSG_LPR_RECVJOB_ROLLBACK:
case IMSG_LPR_RMJOB:
lpr_dispatch_frontend(proc, imsg);
break;
default:
fatalx("%s: unexpected imsg %s", __func__,
log_fmt_imsgtype(imsg->hdr.type));
}
}