#ifdef lint
#undef _FILE_OFFSET_BITS
#endif
#include <door.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <pthread.h>
#include <signal.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <synch.h>
#include <sys/avl.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <syslog.h>
#include <limits.h>
#include <thread.h>
#include <ucred.h>
#include <umem.h>
#include <unistd.h>
#include <libintl.h>
#include <locale.h>
#include <pkglib.h>
#define SADM_DIR "/var/sadm/install"
#define LOCK ".pkg.lock"
#define CLIENTLOCK ".pkg.lock.client"
#define CONTENTS "contents"
#define TCONTENTS "t.contents"
#define BADCONTENTS "contents.badXXXXXX"
#define LLNANOSEC ((int64_t)NANOSEC)
#define DUMPTIMEOUT 60
#define EXITTIMEOUT 300
typedef struct pkgentry {
char *line;
avl_node_t avl;
int pkgoff;
int pathlen;
int len;
} pkgentry_t;
static char IS_ST0[256];
static char IS_ST0Q[256];
static void pkg_door_srv(void *, char *, size_t, door_desc_t *, uint_t);
static char *file_find(pkgfilter_t *, int *);
static void parse_contents(void);
static int parse_log(void);
static void pkgdump(void);
static int logflush(void);
static int avlcmp(const void *, const void *);
static void freeentry(pkgentry_t *);
static void swapentry(pkgentry_t *, pkgentry_t *);
static int establish_lock(char *);
static int no_memory_abort(void);
static int pkgfilter(pkgfilter_t *, door_desc_t *);
static int pkgaddlines(pkgfilter_t *);
static void finish(void);
static void signal_handler(int);
static void my_cond_reltimedwait(hrtime_t, int);
static hrtime_t time_since_(hrtime_t);
static FILE *log;
static char *door = PKGDOOR;
static avl_tree_t listp, *list = &listp;
static char *ccmnt[2];
static int cind = 0;
static mutex_t mtx = DEFAULTMUTEX;
static cond_t cv = DEFAULTCV;
static int flushbeforemark = 1;
static int logerrcnt = 0;
static int loglines = 0;
static int suppressed = 0;
static int logcount;
static int ndumps;
static int ncalls;
static int changes;
static hrtime_t lastchange;
static hrtime_t lastcall;
static volatile int want_to_quit;
static boolean_t read_only = B_FALSE;
static boolean_t permanent = B_FALSE;
static boolean_t one_shot = B_FALSE;
static int write_locked;
static pid_t client_pid;
static int verbose = 1;
static hrtime_t dumptimeout = DUMPTIMEOUT;
static boolean_t sync_needed = B_FALSE;
static uid_t myuid;
static char marker[] = "###Marker\n";
static umem_cache_t *ecache;
static char pkgdir[PATH_MAX];
static void
server_main(int argc, char **argv)
{
int did;
int c;
struct statvfs vfsbuf;
int imexit = 0;
pid_t parent;
char *root = NULL;
char *sadmdir = NULL;
hrtime_t delta;
int dir = 0;
int dfd;
(void) set_prog_name("pkgserv");
openlog("pkgserv", LOG_PID | LOG_ODELAY, LOG_DAEMON);
while ((c = getopt(argc, argv, "d:eoN:pP:R:r:")) != EOF) {
switch (c) {
case 'e':
imexit = 1;
break;
case 'd':
sadmdir = optarg;
if (*sadmdir != '/' || strlen(sadmdir) >= PATH_MAX ||
access(sadmdir, X_OK) != 0)
exit(99);
break;
case 'N':
(void) set_prog_name(optarg);
break;
case 'o':
one_shot = B_TRUE;
verbose = 0;
break;
case 'p':
permanent = B_TRUE;
dumptimeout = 3600;
break;
case 'P':
client_pid = atoi(optarg);
break;
case 'R':
root = optarg;
if (*root != '/' || strlen(root) >= PATH_MAX ||
access(root, X_OK) != 0)
exit(99);
break;
case 'r':
read_only = B_TRUE;
one_shot = B_TRUE;
verbose = 0;
door = optarg;
break;
default:
exit(99);
}
}
if (one_shot && permanent) {
progerr(gettext("Incorrect Usage"));
exit(99);
}
umem_nofail_callback(no_memory_abort);
if (root != NULL && strcmp(root, "/") != 0) {
if (snprintf(pkgdir, PATH_MAX, "%s%s", root,
sadmdir == NULL ? SADM_DIR : sadmdir) >= PATH_MAX) {
exit(99);
}
} else {
if (sadmdir == NULL)
(void) strcpy(pkgdir, SADM_DIR);
else
(void) strcpy(pkgdir, sadmdir);
}
if (chdir(pkgdir) != 0) {
progerr(gettext("can't chdir to %s"), pkgdir);
exit(2);
}
closefrom(3);
if (!read_only && establish_lock(LOCK) < 0) {
progerr(gettext(
"couldn't lock in %s (server running?): %s"),
pkgdir, strerror(errno));
exit(1);
}
did = door_create(pkg_door_srv, 0, DOOR_REFUSE_DESC);
if (did == -1) {
progerr("door_create: %s", strerror(errno));
exit(2);
}
(void) fdetach(door);
if ((dfd = creat(door, 0644)) < 0 || close(dfd) < 0) {
progerr("door_create: %s", strerror(errno));
exit(2);
}
(void) mutex_lock(&mtx);
myuid = geteuid();
(void) sigset(SIGHUP, signal_handler);
(void) sigset(SIGTERM, signal_handler);
(void) sigset(SIGINT, signal_handler);
(void) sigset(SIGQUIT, signal_handler);
(void) signal(SIGPIPE, SIG_IGN);
(void) atexit(finish);
if (fattach(did, door) != 0) {
progerr(gettext("attach door: %s"), strerror(errno));
exit(2);
}
(void) close(did);
ecache = umem_cache_create("entry", sizeof (pkgentry_t),
sizeof (char *), NULL, NULL, NULL, NULL, NULL, 0);
avl_create(list, avlcmp, sizeof (pkgentry_t),
offsetof(pkgentry_t, avl));
IS_ST0['\0'] = 1;
IS_ST0[' '] = 1;
IS_ST0['\t'] = 1;
IS_ST0Q['\0'] = 1;
IS_ST0Q[' '] = 1;
IS_ST0Q['\t'] = 1;
IS_ST0Q['='] = 1;
parse_contents();
if (parse_log() > 0)
pkgdump();
if (imexit)
exit(0);
if (statvfs(".", &vfsbuf) != 0) {
progerr(gettext("statvfs: %s"), strerror(errno));
exit(2);
}
if (strcmp(vfsbuf.f_basetype, "zfs") == 0)
flushbeforemark = 0;
parent = getppid();
if (parent != 1)
(void) kill(parent, SIGUSR1);
if (!one_shot) {
int fd;
(void) setsid();
fd = open("/dev/null", O_RDWR, 0);
if (fd >= 0) {
(void) dup2(fd, STDIN_FILENO);
(void) dup2(fd, STDOUT_FILENO);
(void) dup2(fd, STDERR_FILENO);
if (fd > 2)
(void) close(fd);
}
}
lastcall = lastchange = gethrtime();
for (;;) {
if (want_to_quit) {
pkgdump();
exit(0);
}
if (write_locked ||
(!one_shot && permanent && dir == changes)) {
(void) cond_wait(&cv, &mtx);
continue;
}
delta = time_since_(lastchange);
if (delta < dumptimeout * LLNANOSEC) {
my_cond_reltimedwait(delta, dumptimeout);
continue;
}
if (client_pid > 1 && kill(client_pid, 0) == 0) {
lastchange = lastcall = gethrtime();
continue;
}
if ((one_shot || !permanent) && dir == changes) {
delta = time_since_(lastcall);
if (delta < EXITTIMEOUT * LLNANOSEC) {
my_cond_reltimedwait(delta, EXITTIMEOUT);
continue;
}
exit(0);
}
pkgdump();
dir = changes;
}
}
static void
nothing(int sig)
{
}
int
main(int argc, char **argv)
{
int sig;
sigset_t sset;
int stat;
(void) setlocale(LC_ALL, "");
(void) textdomain(TEXT_DOMAIN);
client_pid = getppid();
(void) sigemptyset(&sset);
(void) sigaddset(&sset, SIGUSR1);
(void) sigaddset(&sset, SIGCLD);
(void) sigset(SIGCLD, nothing);
(void) sigset(SIGUSR1, SIG_DFL);
(void) sigprocmask(SIG_BLOCK, &sset, NULL);
(void) umask(022);
switch (fork()) {
case -1:
exit(99);
case 0:
server_main(argc, argv);
default:
break;
}
for (;;) {
sig = sigwait(&sset);
switch (sig) {
case SIGCLD:
if (wait(&stat) > 0) {
if (WIFEXITED(stat))
_exit(WEXITSTATUS(stat));
else if (WIFSIGNALED(stat))
_exit(99);
}
break;
case SIGUSR1:
_exit(0);
}
}
}
static void
pkg_door_srv(void *cookie, char *argp, size_t asz, door_desc_t *dp,
uint_t ndesc)
{
char *p = NULL;
pkgcmd_t *pcmd = (pkgcmd_t *)argp;
ucred_t *uc = NULL;
uid_t caller;
pid_t pcaller;
door_desc_t ddp;
int dnum = 0;
int one = 1;
int len = -1;
if (asz < sizeof (pkgcmd_t)) {
(void) door_return(NULL, 0, NULL, 0);
return;
}
if (door_ucred(&uc) != 0) {
(void) door_return(NULL, 0, NULL, 0);
return;
}
caller = ucred_geteuid(uc);
pcaller = ucred_getpid(uc);
ucred_free(uc);
if (caller != myuid) {
(void) door_return(NULL, 0, NULL, 0);
return;
}
(void) mutex_lock(&mtx);
ncalls++;
if (pcaller != client_pid && pcaller != -1 &&
(client_pid == 1 || kill(client_pid, 0) != 0)) {
client_pid = pcaller;
}
if (PKG_WRITE_COMMAND(pcmd->cmd))
while (write_locked > 0)
(void) cond_wait(&cv, &mtx);
switch (pcmd->cmd) {
case PKG_FINDFILE:
p = file_find((pkgfilter_t *)argp, &len);
break;
case PKG_DUMP:
if (read_only)
goto err;
if (logcount > 0)
pkgdump();
break;
case PKG_EXIT:
if (logcount > 0)
pkgdump();
exit(0);
case PKG_PKGSYNC:
if (read_only || logflush() != 0)
goto err;
break;
case PKG_FILTER:
if (pkgfilter((pkgfilter_t *)argp, &ddp) == 0)
dnum = 1;
break;
case PKG_ADDLINES:
if (read_only)
goto err;
changes++;
if (pkgaddlines((pkgfilter_t *)argp) != 0)
goto err;
lastchange = gethrtime();
(void) cond_broadcast(&cv);
break;
case PKG_NOP:
break;
default:
goto err;
}
lastcall = gethrtime();
(void) mutex_unlock(&mtx);
(void) door_return(p, len != -1 ? len : p == NULL ? 0 : strlen(p) + 1,
dnum == 0 ? NULL : &ddp, dnum);
return;
err:
(void) mutex_unlock(&mtx);
(void) door_return((void *)&one, 4, NULL, 0);
}
static ptrdiff_t
fieldoff(char *info, int nf)
{
char *q = info;
while (nf > 0) {
if (IS_ST0[(unsigned char)*q++]) {
if (q[-1] == 0)
break;
nf--;
}
}
return (q - info - 1);
}
static char *
mystrcpy(char *buf, int len)
{
char *res = umem_alloc(len, UMEM_NOFAIL);
(void) memcpy(res, buf, len - 1);
res[len - 1] = '\0';
return (res);
}
static pkgentry_t *
parse_line(char *buf, int blen, boolean_t full)
{
char *t;
pkgentry_t *p;
int nfields;
p = umem_cache_alloc(ecache, UMEM_NOFAIL);
buf = p->line = mystrcpy(buf, blen + 1);
p->len = blen + 1;
t = buf;
while (!IS_ST0Q[(unsigned char)*t++])
;
p->pathlen = t - buf - 1;
if (p->pathlen == 0 || p->pathlen >= PATH_MAX) {
progerr("bad entry read in contents file");
logerr("pathname: Unknown");
logerr("problem: unable to read pathname field");
if (one_shot)
exit(2);
}
if (t[-1] == '=')
while (!IS_ST0[(unsigned char)*t++])
;
if (t[-1] == '\0') {
if (full)
goto badline;
p->pkgoff = -1;
return (p);
}
switch (*t) {
case '?':
nfields = 0;
break;
case 's':
case 'l':
nfields = 1;
break;
case 'p':
case 'x':
case 'd':
nfields = 4;
break;
case 'f':
case 'e':
case 'v':
nfields = 7;
break;
case 'c':
case 'b':
nfields = 6;
break;
default:
progerr("bad entry read in contents file");
logerr("pathname: %.*s", p->pathlen, p->line);
logerr("problem: unknown ftype");
freeentry(p);
if (one_shot)
exit(2);
return (NULL);
}
p->pkgoff = t + fieldoff(t, nfields + 1) - buf;
if (p->line[p->pkgoff] != '\0' || p->pkgoff == p->len - 1)
return (p);
badline:
progerr(gettext("bad entry read in contents file"));
logerr(gettext("pathname: Unknown"));
logerr(gettext("problem: unknown ftype"));
freeentry(p);
if (one_shot)
exit(2);
return (NULL);
}
static void
handle_comments(char *buf, int len)
{
if (cind >= 2)
return;
if (buf[0] != '#')
return;
if (ccmnt[cind] != NULL)
umem_free(ccmnt[cind], strlen(ccmnt[cind]) + 1);
ccmnt[cind] = mystrcpy(buf, len);
cind++;
}
static void
parse_contents(void)
{
int cnt;
pkgentry_t *ent, *e2;
avl_index_t where;
int num = 0;
struct stat stb;
ptrdiff_t off;
char *p, *q, *map;
pkgentry_t *lastentry = NULL;
int d;
int cntserrs = 0;
cnt = open(CONTENTS, O_RDONLY);
cind = 0;
if (cnt == -1) {
if (errno == ENOENT)
return;
exit(99);
}
if (fstat(cnt, &stb) != 0) {
(void) close(cnt);
exit(99);
}
if (stb.st_size == 0) {
(void) close(cnt);
return;
}
map = mmap(0, stb.st_size, PROT_READ, MAP_PRIVATE, cnt, 0);
(void) close(cnt);
if (map == (char *)-1)
return;
(void) madvise(map, stb.st_size, MADV_WILLNEED);
for (off = 0; off < stb.st_size; off += q - p) {
p = map + off;
q = memchr(p, '\n', stb.st_size - off);
if (q == NULL)
break;
q++;
num++;
if (p[0] == '#' || p[0] == '\n') {
handle_comments(p, q - p);
continue;
}
ent = parse_line(p, q - p - 1, B_TRUE);
if (ent == NULL) {
cntserrs++;
continue;
}
if (lastentry == NULL) {
avl_add(list, ent);
lastentry = ent;
} else if ((d = avlcmp(ent, lastentry)) == 1) {
avl_insert_here(list, ent, lastentry, AVL_AFTER);
lastentry = ent;
} else if (d == 0 ||
(e2 = avl_find(list, ent, &where)) != NULL) {
if (d == 0)
e2 = lastentry;
if (strcmp(ent->line, e2->line) != 0) {
progerr(gettext("two entries for %.*s"),
ent->pathlen, ent->line);
cntserrs++;
}
freeentry(ent);
} else {
progerr(gettext("bad read of contents file"));
logerr(gettext("pathname: Unknown"));
logerr(gettext(
"problem: unable to read pathname field"));
if (one_shot)
exit(2);
avl_insert(list, ent, where);
}
}
cind = 0;
(void) munmap(map, stb.st_size);
if (cntserrs > 0 && stb.st_nlink == 1) {
char bcf[sizeof (BADCONTENTS)];
(void) strcpy(bcf, BADCONTENTS);
if (mktemp(bcf) != NULL) {
(void) link(CONTENTS, bcf);
syslog(LOG_WARNING, "A bad contents file was saved: %s",
bcf);
}
}
}
static int
parse_log(void)
{
pkgentry_t *ent, *look;
avl_index_t where;
int num = 0;
int logfd;
struct stat stb;
int mlen = strlen(marker);
off_t realend;
ptrdiff_t off;
char *p, *q, *map;
logfd = open(PKGLOG, O_RDONLY);
if (logfd < 0) {
if (errno == ENOENT)
return (0);
progerr(gettext("cannot read "PKGLOG": %s"), strerror(errno));
exit(2);
}
if (fstat(logfd, &stb) != 0) {
progerr(gettext("cannot stat "PKGLOG": %s"), strerror(errno));
exit(2);
}
if (stb.st_size == 0) {
(void) close(logfd);
return (1);
}
map = mmap(0, stb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
logfd, 0);
(void) close(logfd);
if (map == (char *)-1) {
progerr(gettext("Cannot mmap the "PKGLOG": %s"),
strerror(errno));
exit(2);
}
cind = 0;
realend = stb.st_size;
if (memcmp(map + realend - mlen, marker, mlen) != 0) {
progerr(gettext(PKGLOG" is not complete"));
map[stb.st_size - 1] = '\0';
realend = 0;
for (p = map; q = strstr(p, marker); ) {
if (q == map || q[-1] == '\n')
realend = q - map + mlen;
p = q + mlen;
}
progerr(gettext("Ignoring %ld bytes from log"),
(long)(stb.st_size - realend));
}
for (off = 0; off < realend; off += q - p) {
p = map + off;
q = memchr(p, '\n', realend - off);
if (q == NULL)
break;
q++;
num++;
if (p[0] == '#' || p[0] == '\n') {
if (memcmp(marker, p, mlen) == 0)
cind = 0;
else
handle_comments(p, q - p);
continue;
}
ent = parse_line(p + 1, q - (p + 1) - 1, p[0] != '-');
if (ent == NULL)
continue;
look = avl_find(list, ent, &where);
switch (p[0]) {
case '+':
case '=':
if (look != NULL)
swapentry(look, ent);
else
avl_insert(list, ent, where);
break;
case '-':
if (look != NULL) {
avl_remove(list, look);
freeentry(look);
}
freeentry(ent);
break;
default:
freeentry(ent);
progerr(gettext("log %d: bad line"), num);
break;
}
}
(void) munmap(map, stb.st_size);
return (num == 0 ? 1 : num);
}
static char *
file_find(pkgfilter_t *cmd, int *len)
{
pkgentry_t p;
pkgentry_t *look;
p.line = cmd->buf;
p.pathlen = cmd->len;
look = avl_find(list, &p, NULL);
if (look == NULL)
return (NULL);
*len = look->len;
return (look->line);
}
static void
pkgdump(void)
{
FILE *cnts;
int err = 0;
pkgentry_t *p;
if (read_only)
return;
if (sync_needed)
return;
cnts = fopen(TCONTENTS, "w");
if (cnts == NULL)
exit(99);
for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) {
if (fprintf(cnts, "%s\n", p->line) < 0)
err++;
}
if (ccmnt[0] != NULL)
(void) fprintf(cnts, "%s\n", ccmnt[0]);
if (ccmnt[1] != NULL)
(void) fprintf(cnts, "%s\n", ccmnt[1]);
if (err != 0 || fflush(cnts) == EOF || fsync(fileno(cnts)) != 0 ||
fclose(cnts) == EOF || rename(TCONTENTS, CONTENTS) != 0) {
err++;
}
if (err != 0) {
progerr("cannot rewrite the contents file");
exit(2);
}
(void) fclose(log);
(void) unlink(PKGLOG);
log = NULL;
ndumps++;
logcount = 0;
}
static void
freeentry(pkgentry_t *p)
{
umem_free(p->line, p->len);
umem_cache_free(ecache, p);
}
static void
swapentry(pkgentry_t *cur, pkgentry_t *new)
{
if (cur->len == new->len &&
strcmp(cur->line + cur->pathlen,
new->line + new->pathlen) == 0) {
suppressed++;
freeentry(new);
return;
}
umem_free(cur->line, cur->len);
cur->line = new->line;
cur->len = new->len;
cur->pkgoff = new->pkgoff;
umem_cache_free(ecache, new);
}
static int
logentry(char type, pkgentry_t *p)
{
int len;
if (type == '-')
len = fprintf(log, "-%.*s\n", p->pathlen, p->line);
else
len = fprintf(log, "%c%s\n", type, p->line);
loglines++;
if (len < 0) {
logerrcnt++;
return (-1);
}
logcount += len;
return (0);
}
static int
logflush(void)
{
int len;
static int lastflush;
if (log == NULL)
return (0);
if (lastflush == logcount)
return (0);
if (cind == 2) {
(void) fprintf(log, "%s\n", ccmnt[0]);
(void) fprintf(log, "%s\n", ccmnt[1]);
cind = 0;
}
if (flushbeforemark) {
if (fflush(log) == EOF)
logerrcnt++;
}
len = fprintf(log, "%s", marker);
if (len < 0)
logerrcnt++;
else
logcount += len;
if (fflush(log) == EOF)
logerrcnt++;
sync_needed = B_FALSE;
if (logerrcnt > 0 || logcount > MAXLOGFILESIZE)
pkgdump();
if (logerrcnt > 0)
return (-1);
lastflush = logcount;
return (0);
}
static int
avlcmp(const void *ca, const void *cb)
{
const pkgentry_t *a = ca;
const pkgentry_t *b = cb;
int i = memcmp(a->line, b->line,
a->pathlen > b->pathlen ? b->pathlen : a->pathlen);
if (i < 0)
return (-1);
else if (i > 0)
return (1);
else if (a->pathlen == b->pathlen)
return (0);
else if (a->pathlen > b->pathlen)
return (1);
else
return (-1);
}
static int
establish_lock(char *lock)
{
int fd = open(lock, O_RDWR|O_CREAT, 0644);
int i;
if (fd < 0)
return (-1);
for (i = 0; i < 5; i++) {
if (lockf(fd, F_TLOCK, 0) == 0)
return (0);
(void) sleep(1);
}
(void) close(fd);
return (-1);
}
static int
no_memory_abort(void)
{
return (UMEM_CALLBACK_EXIT(99));
}
static void *
thr_pkgfilter(void *v)
{
pkgfilter_t *pf = v;
pkgentry_t *p;
int nums[2];
FILE *cnts;
cnts = fdopen(pf->cmd, "w");
if (cnts == NULL)
goto free;
if (pf->len > 0) {
char *p;
for (p = pf->buf; *p; p++) {
if (*p == '*') {
*p = 0;
if (p > pf->buf && p[-1] == '.')
p[-1] = 0;
break;
}
}
}
(void) mutex_lock(&mtx);
write_locked++;
(void) mutex_unlock(&mtx);
for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) {
if (pf->len > 0 && strstr(p->line, pf->buf) == NULL)
continue;
nums[0] = p->len;
nums[1] = p->pathlen;
if (fwrite(nums, sizeof (int), 2, cnts) != 2)
break;
if (fwrite(p->line, 1, p->len, cnts) != p->len)
break;
}
(void) mutex_lock(&mtx);
lastcall = gethrtime();
write_locked--;
(void) cond_broadcast(&cv);
(void) mutex_unlock(&mtx);
(void) fclose(cnts);
free:
umem_free(pf, sizeof (pkgfilter_t) + pf->len);
return (NULL);
}
static hrtime_t
time_since_(hrtime_t last)
{
return (gethrtime() - last);
}
static void
my_cond_reltimedwait(hrtime_t delta, int sec)
{
hrtime_t wait = sec * LLNANOSEC - delta;
timestruc_t waitfor;
waitfor.tv_nsec = wait % LLNANOSEC;
waitfor.tv_sec = wait / LLNANOSEC;
(void) cond_reltimedwait(&cv, &mtx, &waitfor);
}
static int
pkgfilter(pkgfilter_t *pf, door_desc_t *dp)
{
int p[2];
thread_t tid;
pkgfilter_t *cpf;
if (pipe(p) != 0)
return (-1);
cpf = umem_alloc(sizeof (pkgfilter_t) + pf->len, UMEM_NOFAIL);
(void) memcpy(cpf, pf, sizeof (pkgfilter_t) + pf->len);
cpf->cmd = p[1];
if (thr_create(NULL, 0, thr_pkgfilter, cpf, THR_DETACHED,
&tid) != 0) {
(void) close(p[0]);
(void) close(p[1]);
umem_free(cpf, sizeof (pkgfilter_t) + pf->len);
return (-1);
}
(void) memset(dp, 0, sizeof (*dp));
dp->d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
dp->d_data.d_desc.d_descriptor = p[0];
return (0);
}
static int
pkgaddlines(pkgfilter_t *pf)
{
char *map = pf->buf;
int len = pf->len;
int off;
pkgentry_t *ent, *look;
avl_index_t where;
char *q, *p;
char c;
int r = 0;
if (log == NULL) {
log = fopen(PKGLOG, "w");
if (log == NULL)
return (-1);
}
for (off = 0; off < len; off += q - p) {
p = map + off;
q = memchr(p, '\n', len - off);
if (q == NULL)
break;
q++;
if (p[0] == '#' || p[0] == '\n') {
handle_comments(p, q - p);
continue;
}
if (*p == '-')
ent = parse_line(p + 1, q - (p + 1) - 1, B_FALSE);
else
ent = parse_line(p, q - p - 1, B_TRUE);
if (ent == NULL) {
r++;
continue;
}
look = avl_find(list, ent, &where);
if (look != NULL) {
c = *p == '-' ? '-' : '=';
if (c == '=') {
swapentry(look, ent);
ent = look;
} else {
avl_remove(list, look);
freeentry(look);
}
} else if (*p == '-') {
freeentry(ent);
continue;
} else {
avl_insert(list, ent, where);
c = '+';
}
sync_needed = B_TRUE;
r += logentry(c, ent);
if (c == '-')
freeentry(ent);
}
return (r);
}
static void
finish(void)
{
if (verbose) {
syslog(LOG_DEBUG,
"finished: calls %d, pkgdumps %d, loglines %d "
"(suppressed %d)\n",
ncalls, ndumps, loglines, suppressed);
}
(void) fdetach(door);
if (read_only)
(void) unlink(door);
}
static void
signal_handler(int sig)
{
if (read_only)
exit(0);
want_to_quit = 1;
(void) cond_broadcast(&cv);
}