162224350SCasper H.S. Dik /*
262224350SCasper H.S. Dik * CDDL HEADER START
362224350SCasper H.S. Dik *
462224350SCasper H.S. Dik * The contents of this file are subject to the terms of the
562224350SCasper H.S. Dik * Common Development and Distribution License (the "License").
662224350SCasper H.S. Dik * You may not use this file except in compliance with the License.
762224350SCasper H.S. Dik *
862224350SCasper H.S. Dik * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
962224350SCasper H.S. Dik * or http://www.opensolaris.org/os/licensing.
1062224350SCasper H.S. Dik * See the License for the specific language governing permissions
1162224350SCasper H.S. Dik * and limitations under the License.
1262224350SCasper H.S. Dik *
1362224350SCasper H.S. Dik * When distributing Covered Code, include this CDDL HEADER in each
1462224350SCasper H.S. Dik * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1562224350SCasper H.S. Dik * If applicable, add the following below this CDDL HEADER, with the
1662224350SCasper H.S. Dik * fields enclosed by brackets "[]" replaced with your own identifying
1762224350SCasper H.S. Dik * information: Portions Copyright [yyyy] [name of copyright owner]
1862224350SCasper H.S. Dik *
1962224350SCasper H.S. Dik * CDDL HEADER END
2062224350SCasper H.S. Dik */
2162224350SCasper H.S. Dik
2262224350SCasper H.S. Dik /*
23*7706a9bfSCasper H.S. Dik * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2462224350SCasper H.S. Dik * Use is subject to license terms.
2562224350SCasper H.S. Dik */
2662224350SCasper H.S. Dik
2762224350SCasper H.S. Dik /*
2862224350SCasper H.S. Dik * The Solaris package installer in-memory database server.
2962224350SCasper H.S. Dik *
3062224350SCasper H.S. Dik * We'll keep the contents file as before; but we cache it
3162224350SCasper H.S. Dik * and we don't write it as often. Instead, we log all
3262224350SCasper H.S. Dik * modifications to the log file.
3362224350SCasper H.S. Dik * Using the contents file and the logfile, the pkgserv can
3462224350SCasper H.S. Dik * rebuild the up-to-date contents file.
3562224350SCasper H.S. Dik * The logfile is constructed so that rebuilding the
3662224350SCasper H.S. Dik * contents file with the logfile is idempotent.
3762224350SCasper H.S. Dik *
3862224350SCasper H.S. Dik * The libpkg will start the daemon.
3962224350SCasper H.S. Dik *
4062224350SCasper H.S. Dik * The pkgserv will daemonize itself; the parent process
4162224350SCasper H.S. Dik * waits until the child process has initialized and will
4262224350SCasper H.S. Dik * start the door server.
4362224350SCasper H.S. Dik * If any error occurs during start-up, the error messages
4462224350SCasper H.S. Dik * are printed to stderr and the daemon will exit.
4562224350SCasper H.S. Dik * After start-up, any further errors are logged to syslog.
4662224350SCasper H.S. Dik * The parent pkgserv will exit with:
4762224350SCasper H.S. Dik * 0 - We've started
4862224350SCasper H.S. Dik * 1 - We couldn't start (locked)
4962224350SCasper H.S. Dik * 2 - Other problems (error on stderr)
5062224350SCasper H.S. Dik * 99 - Nothing reported; the caller must report.
5162224350SCasper H.S. Dik *
5262224350SCasper H.S. Dik * The daemon will timeout, by default. It will write the
5362224350SCasper H.S. Dik * contents file after a first timeout; and after a further
5462224350SCasper H.S. Dik * timeout, the daemon will exit.
5562224350SCasper H.S. Dik *
5662224350SCasper H.S. Dik * The daemon will only timeout if the current "client" has exited;
5762224350SCasper H.S. Dik * to this end, we always look at the pid of the last caller.
5862224350SCasper H.S. Dik * If the last client is no longer around, we record the new client.
5962224350SCasper H.S. Dik * In the typical case of running installf/removef from a post/preinstall
6062224350SCasper H.S. Dik * script, we continue to follow the pkginstall/pkgremove client's pid.
6162224350SCasper H.S. Dik *
6262224350SCasper H.S. Dik * In the particular case of install, we make sure the daemon
6362224350SCasper H.S. Dik * sticks around. (Install == install, (live)upgrade, zone install)
6462224350SCasper H.S. Dik */
6562224350SCasper H.S. Dik
6662224350SCasper H.S. Dik #ifdef lint
6762224350SCasper H.S. Dik #undef _FILE_OFFSET_BITS
6862224350SCasper H.S. Dik #endif
6962224350SCasper H.S. Dik
7062224350SCasper H.S. Dik #include <door.h>
7162224350SCasper H.S. Dik #include <errno.h>
7262224350SCasper H.S. Dik #include <fcntl.h>
7362224350SCasper H.S. Dik #include <limits.h>
7462224350SCasper H.S. Dik #include <pthread.h>
7562224350SCasper H.S. Dik #include <signal.h>
7662224350SCasper H.S. Dik #include <stddef.h>
7762224350SCasper H.S. Dik #include <stdio.h>
7862224350SCasper H.S. Dik #include <stdlib.h>
7962224350SCasper H.S. Dik #include <strings.h>
8062224350SCasper H.S. Dik #include <synch.h>
8162224350SCasper H.S. Dik #include <sys/avl.h>
8262224350SCasper H.S. Dik #include <sys/stat.h>
8362224350SCasper H.S. Dik #include <sys/statvfs.h>
8462224350SCasper H.S. Dik #include <sys/mman.h>
8562224350SCasper H.S. Dik #include <sys/time.h>
8662224350SCasper H.S. Dik #include <sys/wait.h>
8762224350SCasper H.S. Dik #include <syslog.h>
8862224350SCasper H.S. Dik #include <limits.h>
8962224350SCasper H.S. Dik #include <thread.h>
9062224350SCasper H.S. Dik #include <ucred.h>
9162224350SCasper H.S. Dik #include <umem.h>
9262224350SCasper H.S. Dik #include <unistd.h>
9362224350SCasper H.S. Dik #include <libintl.h>
9462224350SCasper H.S. Dik #include <locale.h>
9562224350SCasper H.S. Dik
9662224350SCasper H.S. Dik #include <pkglib.h>
9762224350SCasper H.S. Dik
9862224350SCasper H.S. Dik #define SADM_DIR "/var/sadm/install"
9962224350SCasper H.S. Dik
10062224350SCasper H.S. Dik #define LOCK ".pkg.lock"
10162224350SCasper H.S. Dik #define CLIENTLOCK ".pkg.lock.client"
10262224350SCasper H.S. Dik #define CONTENTS "contents"
10362224350SCasper H.S. Dik #define TCONTENTS "t.contents"
10462224350SCasper H.S. Dik #define BADCONTENTS "contents.badXXXXXX"
10562224350SCasper H.S. Dik
10662224350SCasper H.S. Dik #define LLNANOSEC ((int64_t)NANOSEC)
10762224350SCasper H.S. Dik
10862224350SCasper H.S. Dik #define DUMPTIMEOUT 60
10962224350SCasper H.S. Dik #define EXITTIMEOUT 300
11062224350SCasper H.S. Dik
11162224350SCasper H.S. Dik /*
11262224350SCasper H.S. Dik * Contents file storage format. At install time, the amount of memory
11362224350SCasper H.S. Dik * might be limited, so we make sure that we use as little memory
11462224350SCasper H.S. Dik * as possible. The package tools modify the entries; so we install the
11562224350SCasper H.S. Dik * single lines. We also remember the length of the path; this is needed
11662224350SCasper H.S. Dik * for avlcmp and we return it to the tools. This saves time.
11762224350SCasper H.S. Dik *
11862224350SCasper H.S. Dik * All strings are allocated using umem_alloc.
11962224350SCasper H.S. Dik */
12062224350SCasper H.S. Dik typedef struct pkgentry {
12162224350SCasper H.S. Dik char *line; /* The contents line for the file */
12262224350SCasper H.S. Dik avl_node_t avl; /* The avl header */
12362224350SCasper H.S. Dik int pkgoff; /* Where the packages live; start with SP */
12462224350SCasper H.S. Dik int pathlen; /* The length of the pathname */
12562224350SCasper H.S. Dik int len; /* Length of the line (incl NUL) */
12662224350SCasper H.S. Dik } pkgentry_t;
12762224350SCasper H.S. Dik
12862224350SCasper H.S. Dik static char IS_ST0[256];
12962224350SCasper H.S. Dik static char IS_ST0Q[256];
13062224350SCasper H.S. Dik
13162224350SCasper H.S. Dik static void pkg_door_srv(void *, char *, size_t, door_desc_t *, uint_t);
13262224350SCasper H.S. Dik static char *file_find(pkgfilter_t *, int *);
13362224350SCasper H.S. Dik static void parse_contents(void);
13462224350SCasper H.S. Dik static int parse_log(void);
13562224350SCasper H.S. Dik static void pkgdump(void);
13662224350SCasper H.S. Dik static int logflush(void);
13762224350SCasper H.S. Dik static int avlcmp(const void *, const void *);
13862224350SCasper H.S. Dik static void freeentry(pkgentry_t *);
13962224350SCasper H.S. Dik static void swapentry(pkgentry_t *, pkgentry_t *);
14062224350SCasper H.S. Dik static int establish_lock(char *);
14162224350SCasper H.S. Dik static int no_memory_abort(void);
14262224350SCasper H.S. Dik static int pkgfilter(pkgfilter_t *, door_desc_t *);
14362224350SCasper H.S. Dik static int pkgaddlines(pkgfilter_t *);
14462224350SCasper H.S. Dik static void finish(void);
14562224350SCasper H.S. Dik static void signal_handler(int);
14662224350SCasper H.S. Dik static void my_cond_reltimedwait(hrtime_t, int);
14762224350SCasper H.S. Dik static hrtime_t time_since_(hrtime_t);
14862224350SCasper H.S. Dik
14962224350SCasper H.S. Dik /*
15062224350SCasper H.S. Dik * Server actions
15162224350SCasper H.S. Dik * - set mode (contents file, log file)
15262224350SCasper H.S. Dik * - roll log
15362224350SCasper H.S. Dik * - remove package
15462224350SCasper H.S. Dik * - merge package entries
15562224350SCasper H.S. Dik */
15662224350SCasper H.S. Dik
15762224350SCasper H.S. Dik static FILE *log;
15862224350SCasper H.S. Dik static char *door = PKGDOOR;
15962224350SCasper H.S. Dik
16062224350SCasper H.S. Dik static avl_tree_t listp, *list = &listp;
16162224350SCasper H.S. Dik
16262224350SCasper H.S. Dik /* Keep the "the last command modified the contents file ... */
16362224350SCasper H.S. Dik static char *ccmnt[2];
16462224350SCasper H.S. Dik static int cind = 0;
16562224350SCasper H.S. Dik
16662224350SCasper H.S. Dik static mutex_t mtx = DEFAULTMUTEX;
16762224350SCasper H.S. Dik static cond_t cv = DEFAULTCV;
16862224350SCasper H.S. Dik
16962224350SCasper H.S. Dik static int flushbeforemark = 1;
17062224350SCasper H.S. Dik static int logerrcnt = 0;
17162224350SCasper H.S. Dik static int loglines = 0;
17262224350SCasper H.S. Dik static int suppressed = 0;
17362224350SCasper H.S. Dik static int logcount;
17462224350SCasper H.S. Dik static int ndumps;
17562224350SCasper H.S. Dik static int ncalls;
17662224350SCasper H.S. Dik static int changes;
17762224350SCasper H.S. Dik static hrtime_t lastchange;
17862224350SCasper H.S. Dik static hrtime_t lastcall;
17962224350SCasper H.S. Dik static volatile int want_to_quit;
18062224350SCasper H.S. Dik static boolean_t read_only = B_FALSE;
18162224350SCasper H.S. Dik static boolean_t permanent = B_FALSE;
18262224350SCasper H.S. Dik static boolean_t one_shot = B_FALSE;
18362224350SCasper H.S. Dik static int write_locked;
18462224350SCasper H.S. Dik static pid_t client_pid;
18562224350SCasper H.S. Dik static int verbose = 1;
18662224350SCasper H.S. Dik static hrtime_t dumptimeout = DUMPTIMEOUT;
18762224350SCasper H.S. Dik static boolean_t sync_needed = B_FALSE;
18862224350SCasper H.S. Dik
18962224350SCasper H.S. Dik static uid_t myuid;
19062224350SCasper H.S. Dik
19162224350SCasper H.S. Dik static char marker[] = "###Marker\n";
19262224350SCasper H.S. Dik
19362224350SCasper H.S. Dik static umem_cache_t *ecache;
19462224350SCasper H.S. Dik
19562224350SCasper H.S. Dik static char pkgdir[PATH_MAX];
19662224350SCasper H.S. Dik
19762224350SCasper H.S. Dik static void
server_main(int argc,char ** argv)19862224350SCasper H.S. Dik server_main(int argc, char **argv)
19962224350SCasper H.S. Dik {
20062224350SCasper H.S. Dik int did;
20162224350SCasper H.S. Dik int c;
20262224350SCasper H.S. Dik struct statvfs vfsbuf;
20362224350SCasper H.S. Dik int imexit = 0;
20462224350SCasper H.S. Dik pid_t parent;
20562224350SCasper H.S. Dik char *root = NULL;
20662224350SCasper H.S. Dik char *sadmdir = NULL;
20762224350SCasper H.S. Dik hrtime_t delta;
20862224350SCasper H.S. Dik int dir = 0;
20962224350SCasper H.S. Dik int dfd;
21062224350SCasper H.S. Dik
21162224350SCasper H.S. Dik (void) set_prog_name("pkgserv");
21262224350SCasper H.S. Dik
21362224350SCasper H.S. Dik openlog("pkgserv", LOG_PID | LOG_ODELAY, LOG_DAEMON);
21462224350SCasper H.S. Dik
21562224350SCasper H.S. Dik while ((c = getopt(argc, argv, "d:eoN:pP:R:r:")) != EOF) {
21662224350SCasper H.S. Dik switch (c) {
21762224350SCasper H.S. Dik case 'e':
21862224350SCasper H.S. Dik imexit = 1;
21962224350SCasper H.S. Dik break;
22062224350SCasper H.S. Dik case 'd':
22162224350SCasper H.S. Dik sadmdir = optarg;
22262224350SCasper H.S. Dik if (*sadmdir != '/' || strlen(sadmdir) >= PATH_MAX ||
22362224350SCasper H.S. Dik access(sadmdir, X_OK) != 0)
22462224350SCasper H.S. Dik exit(99);
22562224350SCasper H.S. Dik break;
22662224350SCasper H.S. Dik case 'N':
22762224350SCasper H.S. Dik (void) set_prog_name(optarg);
22862224350SCasper H.S. Dik break;
22962224350SCasper H.S. Dik case 'o':
23062224350SCasper H.S. Dik one_shot = B_TRUE;
23162224350SCasper H.S. Dik verbose = 0;
23262224350SCasper H.S. Dik break;
23362224350SCasper H.S. Dik case 'p':
23462224350SCasper H.S. Dik /*
23562224350SCasper H.S. Dik * We are updating possibly many zones; so we're not
23662224350SCasper H.S. Dik * dumping based on a short timeout and we will not
23762224350SCasper H.S. Dik * exit.
23862224350SCasper H.S. Dik */
23962224350SCasper H.S. Dik permanent = B_TRUE;
24062224350SCasper H.S. Dik dumptimeout = 3600;
24162224350SCasper H.S. Dik break;
24262224350SCasper H.S. Dik case 'P':
24362224350SCasper H.S. Dik client_pid = atoi(optarg);
24462224350SCasper H.S. Dik break;
24562224350SCasper H.S. Dik case 'R':
24662224350SCasper H.S. Dik root = optarg;
24762224350SCasper H.S. Dik if (*root != '/' || strlen(root) >= PATH_MAX ||
24862224350SCasper H.S. Dik access(root, X_OK) != 0)
24962224350SCasper H.S. Dik exit(99);
25062224350SCasper H.S. Dik break;
25162224350SCasper H.S. Dik case 'r':
25262224350SCasper H.S. Dik read_only = B_TRUE;
25362224350SCasper H.S. Dik one_shot = B_TRUE;
25462224350SCasper H.S. Dik verbose = 0;
25562224350SCasper H.S. Dik door = optarg;
25662224350SCasper H.S. Dik break;
25762224350SCasper H.S. Dik default:
25862224350SCasper H.S. Dik exit(99);
25962224350SCasper H.S. Dik }
26062224350SCasper H.S. Dik }
26162224350SCasper H.S. Dik
26262224350SCasper H.S. Dik if (one_shot && permanent) {
26362224350SCasper H.S. Dik progerr(gettext("Incorrect Usage"));
26462224350SCasper H.S. Dik exit(99);
26562224350SCasper H.S. Dik }
26662224350SCasper H.S. Dik
26762224350SCasper H.S. Dik umem_nofail_callback(no_memory_abort);
26862224350SCasper H.S. Dik
26962224350SCasper H.S. Dik if (root != NULL && strcmp(root, "/") != 0) {
27062224350SCasper H.S. Dik if (snprintf(pkgdir, PATH_MAX, "%s%s", root,
27162224350SCasper H.S. Dik sadmdir == NULL ? SADM_DIR : sadmdir) >= PATH_MAX) {
27262224350SCasper H.S. Dik exit(99);
27362224350SCasper H.S. Dik }
27462224350SCasper H.S. Dik } else {
27562224350SCasper H.S. Dik if (sadmdir == NULL)
27662224350SCasper H.S. Dik (void) strcpy(pkgdir, SADM_DIR);
27762224350SCasper H.S. Dik else
27862224350SCasper H.S. Dik (void) strcpy(pkgdir, sadmdir);
27962224350SCasper H.S. Dik }
28062224350SCasper H.S. Dik
28162224350SCasper H.S. Dik if (chdir(pkgdir) != 0) {
28262224350SCasper H.S. Dik progerr(gettext("can't chdir to %s"), pkgdir);
28362224350SCasper H.S. Dik exit(2);
28462224350SCasper H.S. Dik }
28562224350SCasper H.S. Dik
28662224350SCasper H.S. Dik closefrom(3);
28762224350SCasper H.S. Dik
28862224350SCasper H.S. Dik if (!read_only && establish_lock(LOCK) < 0) {
28962224350SCasper H.S. Dik progerr(gettext(
29062224350SCasper H.S. Dik "couldn't lock in %s (server running?): %s"),
29162224350SCasper H.S. Dik pkgdir, strerror(errno));
29262224350SCasper H.S. Dik exit(1);
29362224350SCasper H.S. Dik }
29462224350SCasper H.S. Dik
29562224350SCasper H.S. Dik did = door_create(pkg_door_srv, 0, DOOR_REFUSE_DESC);
29662224350SCasper H.S. Dik if (did == -1) {
29762224350SCasper H.S. Dik progerr("door_create: %s", strerror(errno));
29862224350SCasper H.S. Dik exit(2);
29962224350SCasper H.S. Dik }
30062224350SCasper H.S. Dik
30162224350SCasper H.S. Dik (void) fdetach(door);
30262224350SCasper H.S. Dik
30362224350SCasper H.S. Dik if ((dfd = creat(door, 0644)) < 0 || close(dfd) < 0) {
30462224350SCasper H.S. Dik progerr("door_create: %s", strerror(errno));
30562224350SCasper H.S. Dik exit(2);
30662224350SCasper H.S. Dik }
30762224350SCasper H.S. Dik
30862224350SCasper H.S. Dik (void) mutex_lock(&mtx);
30962224350SCasper H.S. Dik
31062224350SCasper H.S. Dik myuid = geteuid();
31162224350SCasper H.S. Dik
31262224350SCasper H.S. Dik (void) sigset(SIGHUP, signal_handler);
31362224350SCasper H.S. Dik (void) sigset(SIGTERM, signal_handler);
31462224350SCasper H.S. Dik (void) sigset(SIGINT, signal_handler);
31562224350SCasper H.S. Dik (void) sigset(SIGQUIT, signal_handler);
31662224350SCasper H.S. Dik
31762224350SCasper H.S. Dik (void) signal(SIGPIPE, SIG_IGN);
31862224350SCasper H.S. Dik
31962224350SCasper H.S. Dik (void) atexit(finish);
32062224350SCasper H.S. Dik
32162224350SCasper H.S. Dik if (fattach(did, door) != 0) {
32262224350SCasper H.S. Dik progerr(gettext("attach door: %s"), strerror(errno));
32362224350SCasper H.S. Dik exit(2);
32462224350SCasper H.S. Dik }
32562224350SCasper H.S. Dik (void) close(did);
32662224350SCasper H.S. Dik
32762224350SCasper H.S. Dik ecache = umem_cache_create("entry", sizeof (pkgentry_t),
32862224350SCasper H.S. Dik sizeof (char *), NULL, NULL, NULL, NULL, NULL, 0);
32962224350SCasper H.S. Dik
33062224350SCasper H.S. Dik avl_create(list, avlcmp, sizeof (pkgentry_t),
33162224350SCasper H.S. Dik offsetof(pkgentry_t, avl));
33262224350SCasper H.S. Dik
33362224350SCasper H.S. Dik IS_ST0['\0'] = 1;
33462224350SCasper H.S. Dik IS_ST0[' '] = 1;
33562224350SCasper H.S. Dik IS_ST0['\t'] = 1;
33662224350SCasper H.S. Dik
33762224350SCasper H.S. Dik IS_ST0Q['\0'] = 1;
33862224350SCasper H.S. Dik IS_ST0Q[' '] = 1;
33962224350SCasper H.S. Dik IS_ST0Q['\t'] = 1;
34062224350SCasper H.S. Dik IS_ST0Q['='] = 1;
34162224350SCasper H.S. Dik
34262224350SCasper H.S. Dik parse_contents();
34362224350SCasper H.S. Dik if (parse_log() > 0)
34462224350SCasper H.S. Dik pkgdump();
34562224350SCasper H.S. Dik
34662224350SCasper H.S. Dik if (imexit)
34762224350SCasper H.S. Dik exit(0);
34862224350SCasper H.S. Dik
34962224350SCasper H.S. Dik if (statvfs(".", &vfsbuf) != 0) {
35062224350SCasper H.S. Dik progerr(gettext("statvfs: %s"), strerror(errno));
35162224350SCasper H.S. Dik exit(2);
35262224350SCasper H.S. Dik }
35362224350SCasper H.S. Dik
35462224350SCasper H.S. Dik if (strcmp(vfsbuf.f_basetype, "zfs") == 0)
35562224350SCasper H.S. Dik flushbeforemark = 0;
35662224350SCasper H.S. Dik
35762224350SCasper H.S. Dik /* We've started, tell the parent */
35862224350SCasper H.S. Dik parent = getppid();
35962224350SCasper H.S. Dik if (parent != 1)
36062224350SCasper H.S. Dik (void) kill(parent, SIGUSR1);
36162224350SCasper H.S. Dik
36262224350SCasper H.S. Dik if (!one_shot) {
36362224350SCasper H.S. Dik int fd;
36462224350SCasper H.S. Dik (void) setsid();
36562224350SCasper H.S. Dik fd = open("/dev/null", O_RDWR, 0);
36662224350SCasper H.S. Dik if (fd >= 0) {
36762224350SCasper H.S. Dik (void) dup2(fd, STDIN_FILENO);
36862224350SCasper H.S. Dik (void) dup2(fd, STDOUT_FILENO);
36962224350SCasper H.S. Dik (void) dup2(fd, STDERR_FILENO);
37062224350SCasper H.S. Dik if (fd > 2)
37162224350SCasper H.S. Dik (void) close(fd);
37262224350SCasper H.S. Dik }
37362224350SCasper H.S. Dik }
37462224350SCasper H.S. Dik
37562224350SCasper H.S. Dik lastcall = lastchange = gethrtime();
37662224350SCasper H.S. Dik
37762224350SCasper H.S. Dik /*
37862224350SCasper H.S. Dik * Start the main thread, here is where we unlock the mutex.
37962224350SCasper H.S. Dik */
38062224350SCasper H.S. Dik for (;;) {
38162224350SCasper H.S. Dik if (want_to_quit) {
38262224350SCasper H.S. Dik pkgdump();
38362224350SCasper H.S. Dik exit(0);
38462224350SCasper H.S. Dik }
38562224350SCasper H.S. Dik /* Wait forever when root or when there's a running filter */
38662224350SCasper H.S. Dik if (write_locked ||
38762224350SCasper H.S. Dik (!one_shot && permanent && dir == changes)) {
38862224350SCasper H.S. Dik (void) cond_wait(&cv, &mtx);
38962224350SCasper H.S. Dik continue;
39062224350SCasper H.S. Dik }
39162224350SCasper H.S. Dik delta = time_since_(lastchange);
39262224350SCasper H.S. Dik /* Wait until DUMPTIMEOUT after last change before we pkgdump */
39362224350SCasper H.S. Dik if (delta < dumptimeout * LLNANOSEC) {
39462224350SCasper H.S. Dik my_cond_reltimedwait(delta, dumptimeout);
39562224350SCasper H.S. Dik continue;
39662224350SCasper H.S. Dik }
39762224350SCasper H.S. Dik /* Client still around? Just wait then. */
39862224350SCasper H.S. Dik if (client_pid > 1 && kill(client_pid, 0) == 0) {
39962224350SCasper H.S. Dik lastchange = lastcall = gethrtime();
40062224350SCasper H.S. Dik continue;
40162224350SCasper H.S. Dik }
40262224350SCasper H.S. Dik /* Wait for another EXITTIMEOUT seconds before we exit */
40362224350SCasper H.S. Dik if ((one_shot || !permanent) && dir == changes) {
40462224350SCasper H.S. Dik delta = time_since_(lastcall);
40562224350SCasper H.S. Dik if (delta < EXITTIMEOUT * LLNANOSEC) {
40662224350SCasper H.S. Dik my_cond_reltimedwait(delta, EXITTIMEOUT);
40762224350SCasper H.S. Dik continue;
40862224350SCasper H.S. Dik }
40962224350SCasper H.S. Dik exit(0);
41062224350SCasper H.S. Dik }
41162224350SCasper H.S. Dik pkgdump();
41262224350SCasper H.S. Dik dir = changes;
41362224350SCasper H.S. Dik }
41462224350SCasper H.S. Dik
41562224350SCasper H.S. Dik /*NOTREACHED*/
41662224350SCasper H.S. Dik }
41762224350SCasper H.S. Dik
41862224350SCasper H.S. Dik /*ARGSUSED*/
41962224350SCasper H.S. Dik static void
nothing(int sig)42062224350SCasper H.S. Dik nothing(int sig)
42162224350SCasper H.S. Dik {
42262224350SCasper H.S. Dik }
42362224350SCasper H.S. Dik
42462224350SCasper H.S. Dik int
main(int argc,char ** argv)42562224350SCasper H.S. Dik main(int argc, char **argv)
42662224350SCasper H.S. Dik {
42762224350SCasper H.S. Dik int sig;
42862224350SCasper H.S. Dik sigset_t sset;
42962224350SCasper H.S. Dik int stat;
43062224350SCasper H.S. Dik
43162224350SCasper H.S. Dik /*
43262224350SCasper H.S. Dik * We're starting the daemon; this process exits when the door
43362224350SCasper H.S. Dik * server is established or when it fails to establish.
43462224350SCasper H.S. Dik * We wait until the child process sends a SIGUSR1 or when it
43562224350SCasper H.S. Dik * exits.
43662224350SCasper H.S. Dik * We keep around who started us and as long as it lives, we don't
43762224350SCasper H.S. Dik * exit.
43862224350SCasper H.S. Dik */
43962224350SCasper H.S. Dik
44062224350SCasper H.S. Dik (void) setlocale(LC_ALL, "");
44162224350SCasper H.S. Dik (void) textdomain(TEXT_DOMAIN);
44262224350SCasper H.S. Dik
44362224350SCasper H.S. Dik client_pid = getppid();
44462224350SCasper H.S. Dik
44562224350SCasper H.S. Dik (void) sigemptyset(&sset);
44662224350SCasper H.S. Dik (void) sigaddset(&sset, SIGUSR1);
44762224350SCasper H.S. Dik (void) sigaddset(&sset, SIGCLD);
44862224350SCasper H.S. Dik
44962224350SCasper H.S. Dik /* We need to catch the SIGCLD before we can sigwait for it. */
45062224350SCasper H.S. Dik (void) sigset(SIGCLD, nothing);
45162224350SCasper H.S. Dik /* We need to make sure that SIGUSR1 is not ignored. */
45262224350SCasper H.S. Dik (void) sigset(SIGUSR1, SIG_DFL);
45362224350SCasper H.S. Dik (void) sigprocmask(SIG_BLOCK, &sset, NULL);
45462224350SCasper H.S. Dik
45562224350SCasper H.S. Dik /* We install the contents file readable. */
45662224350SCasper H.S. Dik (void) umask(022);
45762224350SCasper H.S. Dik
45862224350SCasper H.S. Dik switch (fork()) {
45962224350SCasper H.S. Dik case -1:
46062224350SCasper H.S. Dik exit(99);
46162224350SCasper H.S. Dik /*NOTREACHED*/
46262224350SCasper H.S. Dik case 0:
46362224350SCasper H.S. Dik server_main(argc, argv);
46462224350SCasper H.S. Dik /*NOTREACHED*/
46562224350SCasper H.S. Dik default:
46662224350SCasper H.S. Dik /* In the parent */
46762224350SCasper H.S. Dik break;
46862224350SCasper H.S. Dik }
46962224350SCasper H.S. Dik
47062224350SCasper H.S. Dik for (;;) {
47162224350SCasper H.S. Dik sig = sigwait(&sset);
47262224350SCasper H.S. Dik
47362224350SCasper H.S. Dik switch (sig) {
47462224350SCasper H.S. Dik case SIGCLD:
47562224350SCasper H.S. Dik if (wait(&stat) > 0) {
47662224350SCasper H.S. Dik if (WIFEXITED(stat))
47762224350SCasper H.S. Dik _exit(WEXITSTATUS(stat));
47862224350SCasper H.S. Dik else if (WIFSIGNALED(stat))
47962224350SCasper H.S. Dik _exit(99);
48062224350SCasper H.S. Dik }
48162224350SCasper H.S. Dik break;
48262224350SCasper H.S. Dik case SIGUSR1:
48362224350SCasper H.S. Dik _exit(0);
48462224350SCasper H.S. Dik }
48562224350SCasper H.S. Dik }
48662224350SCasper H.S. Dik }
48762224350SCasper H.S. Dik
48862224350SCasper H.S. Dik /*ARGSUSED*/
48962224350SCasper H.S. Dik static void
pkg_door_srv(void * cookie,char * argp,size_t asz,door_desc_t * dp,uint_t ndesc)49062224350SCasper H.S. Dik pkg_door_srv(void *cookie, char *argp, size_t asz, door_desc_t *dp,
49162224350SCasper H.S. Dik uint_t ndesc)
49262224350SCasper H.S. Dik {
49362224350SCasper H.S. Dik char *p = NULL;
49462224350SCasper H.S. Dik pkgcmd_t *pcmd = (pkgcmd_t *)argp;
49562224350SCasper H.S. Dik ucred_t *uc = NULL;
49662224350SCasper H.S. Dik uid_t caller;
49762224350SCasper H.S. Dik pid_t pcaller;
49862224350SCasper H.S. Dik door_desc_t ddp;
49962224350SCasper H.S. Dik int dnum = 0;
50062224350SCasper H.S. Dik int one = 1;
50162224350SCasper H.S. Dik int len = -1;
50262224350SCasper H.S. Dik
50362224350SCasper H.S. Dik if (asz < sizeof (pkgcmd_t)) {
50462224350SCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0);
50562224350SCasper H.S. Dik return;
50662224350SCasper H.S. Dik }
50762224350SCasper H.S. Dik
50862224350SCasper H.S. Dik if (door_ucred(&uc) != 0) {
50962224350SCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0);
51062224350SCasper H.S. Dik return;
51162224350SCasper H.S. Dik }
51262224350SCasper H.S. Dik
51362224350SCasper H.S. Dik caller = ucred_geteuid(uc);
51462224350SCasper H.S. Dik pcaller = ucred_getpid(uc);
51562224350SCasper H.S. Dik ucred_free(uc);
51662224350SCasper H.S. Dik
51762224350SCasper H.S. Dik if (caller != myuid) {
51862224350SCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0);
51962224350SCasper H.S. Dik return;
52062224350SCasper H.S. Dik }
52162224350SCasper H.S. Dik
52262224350SCasper H.S. Dik (void) mutex_lock(&mtx);
52362224350SCasper H.S. Dik ncalls++;
52462224350SCasper H.S. Dik
52562224350SCasper H.S. Dik if (pcaller != client_pid && pcaller != -1 &&
52662224350SCasper H.S. Dik (client_pid == 1 || kill(client_pid, 0) != 0)) {
52762224350SCasper H.S. Dik client_pid = pcaller;
52862224350SCasper H.S. Dik }
52962224350SCasper H.S. Dik
53062224350SCasper H.S. Dik if (PKG_WRITE_COMMAND(pcmd->cmd))
53162224350SCasper H.S. Dik while (write_locked > 0)
53262224350SCasper H.S. Dik (void) cond_wait(&cv, &mtx);
53362224350SCasper H.S. Dik
53462224350SCasper H.S. Dik switch (pcmd->cmd) {
53562224350SCasper H.S. Dik case PKG_FINDFILE:
53662224350SCasper H.S. Dik p = file_find((pkgfilter_t *)argp, &len);
53762224350SCasper H.S. Dik break;
53862224350SCasper H.S. Dik case PKG_DUMP:
53962224350SCasper H.S. Dik if (read_only)
54062224350SCasper H.S. Dik goto err;
54162224350SCasper H.S. Dik if (logcount > 0)
54262224350SCasper H.S. Dik pkgdump();
54362224350SCasper H.S. Dik break;
54462224350SCasper H.S. Dik case PKG_EXIT:
54562224350SCasper H.S. Dik if (logcount > 0)
54662224350SCasper H.S. Dik pkgdump();
54762224350SCasper H.S. Dik exit(0);
54862224350SCasper H.S. Dik /*NOTREACHED*/
54962224350SCasper H.S. Dik case PKG_PKGSYNC:
55062224350SCasper H.S. Dik if (read_only || logflush() != 0)
55162224350SCasper H.S. Dik goto err;
55262224350SCasper H.S. Dik break;
55362224350SCasper H.S. Dik case PKG_FILTER:
55462224350SCasper H.S. Dik if (pkgfilter((pkgfilter_t *)argp, &ddp) == 0)
55562224350SCasper H.S. Dik dnum = 1;
55662224350SCasper H.S. Dik break;
55762224350SCasper H.S. Dik case PKG_ADDLINES:
55862224350SCasper H.S. Dik if (read_only)
55962224350SCasper H.S. Dik goto err;
56062224350SCasper H.S. Dik changes++;
56162224350SCasper H.S. Dik
56262224350SCasper H.S. Dik if (pkgaddlines((pkgfilter_t *)argp) != 0)
56362224350SCasper H.S. Dik goto err;
56462224350SCasper H.S. Dik /* If we've updated the database, tell the dump thread */
56562224350SCasper H.S. Dik lastchange = gethrtime();
56662224350SCasper H.S. Dik (void) cond_broadcast(&cv);
56762224350SCasper H.S. Dik break;
56862224350SCasper H.S. Dik case PKG_NOP:
56962224350SCasper H.S. Dik /* Do nothing but register the current client's pid. */
57062224350SCasper H.S. Dik break;
57162224350SCasper H.S. Dik default:
57262224350SCasper H.S. Dik goto err;
57362224350SCasper H.S. Dik }
57462224350SCasper H.S. Dik
57562224350SCasper H.S. Dik lastcall = gethrtime();
57662224350SCasper H.S. Dik (void) mutex_unlock(&mtx);
57762224350SCasper H.S. Dik (void) door_return(p, len != -1 ? len : p == NULL ? 0 : strlen(p) + 1,
57862224350SCasper H.S. Dik dnum == 0 ? NULL : &ddp, dnum);
57962224350SCasper H.S. Dik return;
58062224350SCasper H.S. Dik
58162224350SCasper H.S. Dik err:
58262224350SCasper H.S. Dik (void) mutex_unlock(&mtx);
58362224350SCasper H.S. Dik (void) door_return((void *)&one, 4, NULL, NULL);
58462224350SCasper H.S. Dik }
58562224350SCasper H.S. Dik
58662224350SCasper H.S. Dik /*
58762224350SCasper H.S. Dik * This function returns the length of the string including exactly
58862224350SCasper H.S. Dik * nf fields.
58962224350SCasper H.S. Dik */
59062224350SCasper H.S. Dik static ptrdiff_t
fieldoff(char * info,int nf)59162224350SCasper H.S. Dik fieldoff(char *info, int nf)
59262224350SCasper H.S. Dik {
59362224350SCasper H.S. Dik char *q = info;
59462224350SCasper H.S. Dik
59562224350SCasper H.S. Dik while (nf > 0) {
59662224350SCasper H.S. Dik if (IS_ST0[(unsigned char)*q++]) {
59762224350SCasper H.S. Dik if (q[-1] == 0)
59862224350SCasper H.S. Dik break;
59962224350SCasper H.S. Dik nf--;
60062224350SCasper H.S. Dik }
60162224350SCasper H.S. Dik }
60262224350SCasper H.S. Dik return (q - info - 1);
60362224350SCasper H.S. Dik }
60462224350SCasper H.S. Dik
60562224350SCasper H.S. Dik /*
60662224350SCasper H.S. Dik * The buf points into list of \n delimited lines. We copy it,
60762224350SCasper H.S. Dik * removing the newline and adding a \0.
60862224350SCasper H.S. Dik */
60962224350SCasper H.S. Dik static char *
mystrcpy(char * buf,int len)61062224350SCasper H.S. Dik mystrcpy(char *buf, int len)
61162224350SCasper H.S. Dik {
61262224350SCasper H.S. Dik char *res = umem_alloc(len, UMEM_NOFAIL);
61362224350SCasper H.S. Dik
61462224350SCasper H.S. Dik (void) memcpy(res, buf, len - 1);
61562224350SCasper H.S. Dik res[len - 1] = '\0';
61662224350SCasper H.S. Dik return (res);
61762224350SCasper H.S. Dik }
61862224350SCasper H.S. Dik
61962224350SCasper H.S. Dik /*
62062224350SCasper H.S. Dik * Entry: a single line without the NEWLINE
62162224350SCasper H.S. Dik * Return: the package entry with the path determined.
62262224350SCasper H.S. Dik */
62362224350SCasper H.S. Dik static pkgentry_t *
parse_line(char * buf,int blen,boolean_t full)62462224350SCasper H.S. Dik parse_line(char *buf, int blen, boolean_t full)
62562224350SCasper H.S. Dik {
62662224350SCasper H.S. Dik char *t;
62762224350SCasper H.S. Dik pkgentry_t *p;
62862224350SCasper H.S. Dik int nfields;
62962224350SCasper H.S. Dik
63062224350SCasper H.S. Dik p = umem_cache_alloc(ecache, UMEM_NOFAIL);
63162224350SCasper H.S. Dik buf = p->line = mystrcpy(buf, blen + 1);
63262224350SCasper H.S. Dik p->len = blen + 1;
63362224350SCasper H.S. Dik
63462224350SCasper H.S. Dik t = buf;
63562224350SCasper H.S. Dik
63662224350SCasper H.S. Dik while (!IS_ST0Q[(unsigned char)*t++])
63762224350SCasper H.S. Dik ;
63862224350SCasper H.S. Dik
63962224350SCasper H.S. Dik p->pathlen = t - buf - 1;
64062224350SCasper H.S. Dik if (p->pathlen == 0 || p->pathlen >= PATH_MAX) {
64162224350SCasper H.S. Dik progerr("bad entry read in contents file");
64262224350SCasper H.S. Dik logerr("pathname: Unknown");
64362224350SCasper H.S. Dik logerr("problem: unable to read pathname field");
64462224350SCasper H.S. Dik if (one_shot)
64562224350SCasper H.S. Dik exit(2);
64662224350SCasper H.S. Dik }
64762224350SCasper H.S. Dik if (t[-1] == '=')
64862224350SCasper H.S. Dik while (!IS_ST0[(unsigned char)*t++])
64962224350SCasper H.S. Dik ;
65062224350SCasper H.S. Dik
65162224350SCasper H.S. Dik /* Partial as found in the "-" entries for log */
65262224350SCasper H.S. Dik if (t[-1] == '\0') {
65362224350SCasper H.S. Dik if (full)
65462224350SCasper H.S. Dik goto badline;
65562224350SCasper H.S. Dik
65662224350SCasper H.S. Dik p->pkgoff = -1;
65762224350SCasper H.S. Dik return (p);
65862224350SCasper H.S. Dik }
65962224350SCasper H.S. Dik
66062224350SCasper H.S. Dik switch (*t) {
66162224350SCasper H.S. Dik case '?':
66262224350SCasper H.S. Dik nfields = 0;
66362224350SCasper H.S. Dik break;
66462224350SCasper H.S. Dik case 's':
66562224350SCasper H.S. Dik case 'l':
66662224350SCasper H.S. Dik /* Fields: class */
66762224350SCasper H.S. Dik nfields = 1;
66862224350SCasper H.S. Dik break;
66962224350SCasper H.S. Dik case 'p':
67062224350SCasper H.S. Dik case 'x':
67162224350SCasper H.S. Dik case 'd':
67262224350SCasper H.S. Dik /* class mode owner group */
67362224350SCasper H.S. Dik nfields = 4;
67462224350SCasper H.S. Dik break;
67562224350SCasper H.S. Dik case 'f':
67662224350SCasper H.S. Dik case 'e':
67762224350SCasper H.S. Dik case 'v':
67862224350SCasper H.S. Dik /* class mode owner group size csum time */
67962224350SCasper H.S. Dik nfields = 7;
68062224350SCasper H.S. Dik break;
68162224350SCasper H.S. Dik case 'c':
68262224350SCasper H.S. Dik case 'b':
68362224350SCasper H.S. Dik /* class major minor mode owner group */
68462224350SCasper H.S. Dik nfields = 6;
68562224350SCasper H.S. Dik break;
68662224350SCasper H.S. Dik default:
68762224350SCasper H.S. Dik progerr("bad entry read in contents file");
68862224350SCasper H.S. Dik logerr("pathname: %.*s", p->pathlen, p->line);
68962224350SCasper H.S. Dik logerr("problem: unknown ftype");
69062224350SCasper H.S. Dik freeentry(p);
69162224350SCasper H.S. Dik if (one_shot)
69262224350SCasper H.S. Dik exit(2);
69362224350SCasper H.S. Dik return (NULL);
69462224350SCasper H.S. Dik }
69562224350SCasper H.S. Dik
69662224350SCasper H.S. Dik p->pkgoff = t + fieldoff(t, nfields + 1) - buf;
69762224350SCasper H.S. Dik
69862224350SCasper H.S. Dik if (p->line[p->pkgoff] != '\0' || p->pkgoff == p->len - 1)
69962224350SCasper H.S. Dik return (p);
70062224350SCasper H.S. Dik
70162224350SCasper H.S. Dik badline:
70262224350SCasper H.S. Dik progerr(gettext("bad entry read in contents file"));
70362224350SCasper H.S. Dik logerr(gettext("pathname: Unknown"));
70462224350SCasper H.S. Dik logerr(gettext("problem: unknown ftype"));
70562224350SCasper H.S. Dik freeentry(p);
70662224350SCasper H.S. Dik if (one_shot)
70762224350SCasper H.S. Dik exit(2);
70862224350SCasper H.S. Dik return (NULL);
70962224350SCasper H.S. Dik }
71062224350SCasper H.S. Dik
71162224350SCasper H.S. Dik static void
handle_comments(char * buf,int len)71262224350SCasper H.S. Dik handle_comments(char *buf, int len)
71362224350SCasper H.S. Dik {
71462224350SCasper H.S. Dik if (cind >= 2)
71562224350SCasper H.S. Dik return;
71662224350SCasper H.S. Dik
71762224350SCasper H.S. Dik if (buf[0] != '#')
71862224350SCasper H.S. Dik return;
71962224350SCasper H.S. Dik
72062224350SCasper H.S. Dik if (ccmnt[cind] != NULL)
72162224350SCasper H.S. Dik umem_free(ccmnt[cind], strlen(ccmnt[cind]) + 1);
72262224350SCasper H.S. Dik ccmnt[cind] = mystrcpy(buf, len);
72362224350SCasper H.S. Dik cind++;
72462224350SCasper H.S. Dik }
72562224350SCasper H.S. Dik
72662224350SCasper H.S. Dik static void
parse_contents(void)72762224350SCasper H.S. Dik parse_contents(void)
72862224350SCasper H.S. Dik {
72962224350SCasper H.S. Dik int cnt;
73062224350SCasper H.S. Dik pkgentry_t *ent, *e2;
73162224350SCasper H.S. Dik avl_index_t where;
73262224350SCasper H.S. Dik int num = 0;
73362224350SCasper H.S. Dik struct stat stb;
73462224350SCasper H.S. Dik ptrdiff_t off;
73562224350SCasper H.S. Dik char *p, *q, *map;
73662224350SCasper H.S. Dik pkgentry_t *lastentry = NULL;
73762224350SCasper H.S. Dik int d;
73862224350SCasper H.S. Dik int cntserrs = 0;
73962224350SCasper H.S. Dik
74062224350SCasper H.S. Dik cnt = open(CONTENTS, O_RDONLY);
74162224350SCasper H.S. Dik
74262224350SCasper H.S. Dik cind = 0;
74362224350SCasper H.S. Dik
74462224350SCasper H.S. Dik if (cnt == -1) {
74562224350SCasper H.S. Dik if (errno == ENOENT)
74662224350SCasper H.S. Dik return;
74762224350SCasper H.S. Dik exit(99);
74862224350SCasper H.S. Dik }
74962224350SCasper H.S. Dik
75062224350SCasper H.S. Dik if (fstat(cnt, &stb) != 0) {
75162224350SCasper H.S. Dik (void) close(cnt);
75262224350SCasper H.S. Dik exit(99);
75362224350SCasper H.S. Dik }
75462224350SCasper H.S. Dik if (stb.st_size == 0) {
75562224350SCasper H.S. Dik (void) close(cnt);
75662224350SCasper H.S. Dik return;
75762224350SCasper H.S. Dik }
75862224350SCasper H.S. Dik
75962224350SCasper H.S. Dik map = mmap(0, stb.st_size, PROT_READ, MAP_PRIVATE, cnt, 0);
76062224350SCasper H.S. Dik (void) close(cnt);
76162224350SCasper H.S. Dik if (map == (char *)-1)
76262224350SCasper H.S. Dik return;
76362224350SCasper H.S. Dik
76462224350SCasper H.S. Dik (void) madvise(map, stb.st_size, MADV_WILLNEED);
76562224350SCasper H.S. Dik
76662224350SCasper H.S. Dik for (off = 0; off < stb.st_size; off += q - p) {
76762224350SCasper H.S. Dik p = map + off;
76862224350SCasper H.S. Dik q = memchr(p, '\n', stb.st_size - off);
76962224350SCasper H.S. Dik if (q == NULL)
77062224350SCasper H.S. Dik break;
77162224350SCasper H.S. Dik
77262224350SCasper H.S. Dik q++;
77362224350SCasper H.S. Dik num++;
77462224350SCasper H.S. Dik if (p[0] == '#' || p[0] == '\n') {
77562224350SCasper H.S. Dik handle_comments(p, q - p);
77662224350SCasper H.S. Dik continue;
77762224350SCasper H.S. Dik }
77862224350SCasper H.S. Dik ent = parse_line(p, q - p - 1, B_TRUE);
77962224350SCasper H.S. Dik
78062224350SCasper H.S. Dik if (ent == NULL) {
78162224350SCasper H.S. Dik cntserrs++;
78262224350SCasper H.S. Dik continue;
78362224350SCasper H.S. Dik }
78462224350SCasper H.S. Dik
78562224350SCasper H.S. Dik /*
78662224350SCasper H.S. Dik * We save time by assuming the database is sorted; by
78762224350SCasper H.S. Dik * using avl_insert_here(), building the tree is nearly free.
78862224350SCasper H.S. Dik * lastentry always contains the last entry in the AVL tree.
78962224350SCasper H.S. Dik */
79062224350SCasper H.S. Dik if (lastentry == NULL) {
79162224350SCasper H.S. Dik avl_add(list, ent);
79262224350SCasper H.S. Dik lastentry = ent;
79362224350SCasper H.S. Dik } else if ((d = avlcmp(ent, lastentry)) == 1) {
79462224350SCasper H.S. Dik avl_insert_here(list, ent, lastentry, AVL_AFTER);
79562224350SCasper H.S. Dik lastentry = ent;
79662224350SCasper H.S. Dik } else if (d == 0 ||
79762224350SCasper H.S. Dik (e2 = avl_find(list, ent, &where)) != NULL) {
79862224350SCasper H.S. Dik /*
79962224350SCasper H.S. Dik * This can only happen if the contents file is bad;
80062224350SCasper H.S. Dik * this can, e.g., happen with the old SQL contents DB,
80162224350SCasper H.S. Dik * it didn't sort properly. Assume the first one
80262224350SCasper H.S. Dik * is the correct one, but who knows?
80362224350SCasper H.S. Dik */
80462224350SCasper H.S. Dik if (d == 0)
80562224350SCasper H.S. Dik e2 = lastentry;
80662224350SCasper H.S. Dik if (strcmp(ent->line, e2->line) != 0) {
80762224350SCasper H.S. Dik progerr(gettext("two entries for %.*s"),
80862224350SCasper H.S. Dik ent->pathlen, ent->line);
80962224350SCasper H.S. Dik cntserrs++;
81062224350SCasper H.S. Dik }
81162224350SCasper H.S. Dik freeentry(ent);
81262224350SCasper H.S. Dik } else {
81362224350SCasper H.S. Dik /* Out of order: not an error for us, really. */
81462224350SCasper H.S. Dik progerr(gettext("bad read of contents file"));
81562224350SCasper H.S. Dik logerr(gettext("pathname: Unknown"));
81662224350SCasper H.S. Dik logerr(gettext(
81762224350SCasper H.S. Dik "problem: unable to read pathname field"));
81862224350SCasper H.S. Dik if (one_shot)
81962224350SCasper H.S. Dik exit(2);
82062224350SCasper H.S. Dik avl_insert(list, ent, where);
82162224350SCasper H.S. Dik }
82262224350SCasper H.S. Dik }
82362224350SCasper H.S. Dik
82462224350SCasper H.S. Dik cind = 0;
82562224350SCasper H.S. Dik
82662224350SCasper H.S. Dik (void) munmap(map, stb.st_size);
82762224350SCasper H.S. Dik
82862224350SCasper H.S. Dik /* By default, we ignore bad lines, keep them in a copy. */
82962224350SCasper H.S. Dik if (cntserrs > 0 && stb.st_nlink == 1) {
83062224350SCasper H.S. Dik char bcf[sizeof (BADCONTENTS)];
83162224350SCasper H.S. Dik
83262224350SCasper H.S. Dik (void) strcpy(bcf, BADCONTENTS);
83362224350SCasper H.S. Dik if (mktemp(bcf) != NULL) {
83462224350SCasper H.S. Dik (void) link(CONTENTS, bcf);
83562224350SCasper H.S. Dik syslog(LOG_WARNING, "A bad contents file was saved: %s",
83662224350SCasper H.S. Dik bcf);
83762224350SCasper H.S. Dik }
83862224350SCasper H.S. Dik }
83962224350SCasper H.S. Dik }
84062224350SCasper H.S. Dik
84162224350SCasper H.S. Dik static int
parse_log(void)84262224350SCasper H.S. Dik parse_log(void)
84362224350SCasper H.S. Dik {
84462224350SCasper H.S. Dik pkgentry_t *ent, *look;
84562224350SCasper H.S. Dik avl_index_t where;
84662224350SCasper H.S. Dik int num = 0;
84762224350SCasper H.S. Dik int logfd;
84862224350SCasper H.S. Dik struct stat stb;
84962224350SCasper H.S. Dik int mlen = strlen(marker);
85062224350SCasper H.S. Dik off_t realend;
85162224350SCasper H.S. Dik ptrdiff_t off;
85262224350SCasper H.S. Dik char *p, *q, *map;
85362224350SCasper H.S. Dik
85462224350SCasper H.S. Dik logfd = open(PKGLOG, O_RDONLY);
85562224350SCasper H.S. Dik
85662224350SCasper H.S. Dik if (logfd < 0) {
85762224350SCasper H.S. Dik if (errno == ENOENT)
85862224350SCasper H.S. Dik return (0);
85962224350SCasper H.S. Dik progerr(gettext("cannot read "PKGLOG": %s"), strerror(errno));
86062224350SCasper H.S. Dik exit(2);
86162224350SCasper H.S. Dik }
86262224350SCasper H.S. Dik
86362224350SCasper H.S. Dik if (fstat(logfd, &stb) != 0) {
86462224350SCasper H.S. Dik progerr(gettext("cannot stat "PKGLOG": %s"), strerror(errno));
86562224350SCasper H.S. Dik exit(2);
86662224350SCasper H.S. Dik }
86762224350SCasper H.S. Dik
86862224350SCasper H.S. Dik if (stb.st_size == 0) {
86962224350SCasper H.S. Dik (void) close(logfd);
87062224350SCasper H.S. Dik /* Force pkgdump && remove of the logfile. */
87162224350SCasper H.S. Dik return (1);
87262224350SCasper H.S. Dik }
87362224350SCasper H.S. Dik
874*7706a9bfSCasper H.S. Dik map = mmap(0, stb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
87562224350SCasper H.S. Dik logfd, 0);
87662224350SCasper H.S. Dik (void) close(logfd);
87762224350SCasper H.S. Dik if (map == (char *)-1) {
87862224350SCasper H.S. Dik progerr(gettext("Cannot mmap the "PKGLOG": %s"),
87962224350SCasper H.S. Dik strerror(errno));
88062224350SCasper H.S. Dik exit(2);
88162224350SCasper H.S. Dik }
88262224350SCasper H.S. Dik
88362224350SCasper H.S. Dik cind = 0;
88462224350SCasper H.S. Dik
88562224350SCasper H.S. Dik realend = stb.st_size;
88662224350SCasper H.S. Dik
88762224350SCasper H.S. Dik if (memcmp(map + realend - mlen, marker, mlen) != 0) {
88862224350SCasper H.S. Dik progerr(gettext(PKGLOG" is not complete"));
88962224350SCasper H.S. Dik
890*7706a9bfSCasper H.S. Dik map[stb.st_size - 1] = '\0'; /* for strstr() */
89162224350SCasper H.S. Dik realend = 0;
89262224350SCasper H.S. Dik for (p = map; q = strstr(p, marker); ) {
89362224350SCasper H.S. Dik if (q == map || q[-1] == '\n')
89462224350SCasper H.S. Dik realend = q - map + mlen;
89562224350SCasper H.S. Dik p = q + mlen;
89662224350SCasper H.S. Dik }
89762224350SCasper H.S. Dik progerr(gettext("Ignoring %ld bytes from log"),
89862224350SCasper H.S. Dik (long)(stb.st_size - realend));
89962224350SCasper H.S. Dik }
90062224350SCasper H.S. Dik
90162224350SCasper H.S. Dik for (off = 0; off < realend; off += q - p) {
90262224350SCasper H.S. Dik p = map + off;
90362224350SCasper H.S. Dik q = memchr(p, '\n', realend - off);
90462224350SCasper H.S. Dik if (q == NULL)
90562224350SCasper H.S. Dik break;
90662224350SCasper H.S. Dik
90762224350SCasper H.S. Dik q++;
90862224350SCasper H.S. Dik num++;
90962224350SCasper H.S. Dik if (p[0] == '#' || p[0] == '\n') {
91062224350SCasper H.S. Dik if (memcmp(marker, p, mlen) == 0)
91162224350SCasper H.S. Dik cind = 0;
91262224350SCasper H.S. Dik else
91362224350SCasper H.S. Dik handle_comments(p, q - p);
91462224350SCasper H.S. Dik continue;
91562224350SCasper H.S. Dik }
91662224350SCasper H.S. Dik
91762224350SCasper H.S. Dik ent = parse_line(p + 1, q - (p + 1) - 1, p[0] != '-');
91862224350SCasper H.S. Dik if (ent == NULL)
91962224350SCasper H.S. Dik continue;
92062224350SCasper H.S. Dik look = avl_find(list, ent, &where);
92162224350SCasper H.S. Dik /*
92262224350SCasper H.S. Dik * The log can be replayed; so any value of "look" is
92362224350SCasper H.S. Dik * not unexpected.
92462224350SCasper H.S. Dik */
92562224350SCasper H.S. Dik switch (p[0]) {
92662224350SCasper H.S. Dik case '+':
92762224350SCasper H.S. Dik case '=':
92862224350SCasper H.S. Dik if (look != NULL)
92962224350SCasper H.S. Dik swapentry(look, ent);
93062224350SCasper H.S. Dik else
93162224350SCasper H.S. Dik avl_insert(list, ent, where);
93262224350SCasper H.S. Dik break;
93362224350SCasper H.S. Dik case '-':
93462224350SCasper H.S. Dik if (look != NULL) {
93562224350SCasper H.S. Dik avl_remove(list, look);
93662224350SCasper H.S. Dik freeentry(look);
93762224350SCasper H.S. Dik }
93862224350SCasper H.S. Dik freeentry(ent);
93962224350SCasper H.S. Dik break;
94062224350SCasper H.S. Dik default:
94162224350SCasper H.S. Dik freeentry(ent);
94262224350SCasper H.S. Dik progerr(gettext("log %d: bad line"), num);
94362224350SCasper H.S. Dik break;
94462224350SCasper H.S. Dik }
94562224350SCasper H.S. Dik }
94662224350SCasper H.S. Dik (void) munmap(map, stb.st_size);
94762224350SCasper H.S. Dik
94862224350SCasper H.S. Dik /* Force pkgdump && remove of the logfile if there are no valid mods. */
94962224350SCasper H.S. Dik return (num == 0 ? 1 : num);
95062224350SCasper H.S. Dik }
95162224350SCasper H.S. Dik
95262224350SCasper H.S. Dik static char *
file_find(pkgfilter_t * cmd,int * len)95362224350SCasper H.S. Dik file_find(pkgfilter_t *cmd, int *len)
95462224350SCasper H.S. Dik {
95562224350SCasper H.S. Dik pkgentry_t p;
95662224350SCasper H.S. Dik pkgentry_t *look;
95762224350SCasper H.S. Dik
95862224350SCasper H.S. Dik p.line = cmd->buf;
95962224350SCasper H.S. Dik p.pathlen = cmd->len;
96062224350SCasper H.S. Dik
96162224350SCasper H.S. Dik look = avl_find(list, &p, NULL);
96262224350SCasper H.S. Dik
96362224350SCasper H.S. Dik if (look == NULL)
96462224350SCasper H.S. Dik return (NULL);
96562224350SCasper H.S. Dik
96662224350SCasper H.S. Dik *len = look->len;
96762224350SCasper H.S. Dik return (look->line);
96862224350SCasper H.S. Dik }
96962224350SCasper H.S. Dik
97062224350SCasper H.S. Dik static void
pkgdump(void)97162224350SCasper H.S. Dik pkgdump(void)
97262224350SCasper H.S. Dik {
97362224350SCasper H.S. Dik FILE *cnts;
97462224350SCasper H.S. Dik int err = 0;
97562224350SCasper H.S. Dik pkgentry_t *p;
97662224350SCasper H.S. Dik
97762224350SCasper H.S. Dik if (read_only)
97862224350SCasper H.S. Dik return;
97962224350SCasper H.S. Dik
98062224350SCasper H.S. Dik /* We cannot dump when the current transaction is not complete. */
98162224350SCasper H.S. Dik if (sync_needed)
98262224350SCasper H.S. Dik return;
98362224350SCasper H.S. Dik
98462224350SCasper H.S. Dik cnts = fopen(TCONTENTS, "w");
98562224350SCasper H.S. Dik
98662224350SCasper H.S. Dik if (cnts == NULL)
98762224350SCasper H.S. Dik exit(99);
98862224350SCasper H.S. Dik
98962224350SCasper H.S. Dik for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) {
99062224350SCasper H.S. Dik if (fprintf(cnts, "%s\n", p->line) < 0)
99162224350SCasper H.S. Dik err++;
99262224350SCasper H.S. Dik }
99362224350SCasper H.S. Dik
99462224350SCasper H.S. Dik if (ccmnt[0] != NULL)
99562224350SCasper H.S. Dik (void) fprintf(cnts, "%s\n", ccmnt[0]);
99662224350SCasper H.S. Dik if (ccmnt[1] != NULL)
99762224350SCasper H.S. Dik (void) fprintf(cnts, "%s\n", ccmnt[1]);
99862224350SCasper H.S. Dik
99962224350SCasper H.S. Dik if (err != 0 || fflush(cnts) == EOF || fsync(fileno(cnts)) != 0 ||
100062224350SCasper H.S. Dik fclose(cnts) == EOF || rename(TCONTENTS, CONTENTS) != 0) {
100162224350SCasper H.S. Dik err++;
100262224350SCasper H.S. Dik }
100362224350SCasper H.S. Dik
100462224350SCasper H.S. Dik if (err != 0) {
100562224350SCasper H.S. Dik progerr("cannot rewrite the contents file");
100662224350SCasper H.S. Dik exit(2);
100762224350SCasper H.S. Dik }
100862224350SCasper H.S. Dik
100962224350SCasper H.S. Dik (void) fclose(log);
101062224350SCasper H.S. Dik (void) unlink(PKGLOG);
101162224350SCasper H.S. Dik log = NULL;
101262224350SCasper H.S. Dik ndumps++;
101362224350SCasper H.S. Dik logcount = 0;
101462224350SCasper H.S. Dik }
101562224350SCasper H.S. Dik
101662224350SCasper H.S. Dik static void
freeentry(pkgentry_t * p)101762224350SCasper H.S. Dik freeentry(pkgentry_t *p)
101862224350SCasper H.S. Dik {
101962224350SCasper H.S. Dik umem_free(p->line, p->len);
102062224350SCasper H.S. Dik umem_cache_free(ecache, p);
102162224350SCasper H.S. Dik }
102262224350SCasper H.S. Dik
102362224350SCasper H.S. Dik static void
swapentry(pkgentry_t * cur,pkgentry_t * new)102462224350SCasper H.S. Dik swapentry(pkgentry_t *cur, pkgentry_t *new)
102562224350SCasper H.S. Dik {
102662224350SCasper H.S. Dik if (cur->len == new->len &&
102762224350SCasper H.S. Dik strcmp(cur->line + cur->pathlen,
102862224350SCasper H.S. Dik new->line + new->pathlen) == 0) {
102962224350SCasper H.S. Dik suppressed++;
103062224350SCasper H.S. Dik freeentry(new);
103162224350SCasper H.S. Dik return;
103262224350SCasper H.S. Dik }
103362224350SCasper H.S. Dik
103462224350SCasper H.S. Dik /* Free old line */
103562224350SCasper H.S. Dik umem_free(cur->line, cur->len);
103662224350SCasper H.S. Dik
103762224350SCasper H.S. Dik /* Copy new value: pathlen is the same and avl is kept */
103862224350SCasper H.S. Dik cur->line = new->line;
103962224350SCasper H.S. Dik cur->len = new->len;
104062224350SCasper H.S. Dik cur->pkgoff = new->pkgoff;
104162224350SCasper H.S. Dik
104262224350SCasper H.S. Dik umem_cache_free(ecache, new);
104362224350SCasper H.S. Dik }
104462224350SCasper H.S. Dik
104562224350SCasper H.S. Dik static int
logentry(char type,pkgentry_t * p)104662224350SCasper H.S. Dik logentry(char type, pkgentry_t *p)
104762224350SCasper H.S. Dik {
104862224350SCasper H.S. Dik int len;
104962224350SCasper H.S. Dik
105062224350SCasper H.S. Dik if (type == '-')
105162224350SCasper H.S. Dik len = fprintf(log, "-%.*s\n", p->pathlen, p->line);
105262224350SCasper H.S. Dik else
105362224350SCasper H.S. Dik len = fprintf(log, "%c%s\n", type, p->line);
105462224350SCasper H.S. Dik
105562224350SCasper H.S. Dik loglines++;
105662224350SCasper H.S. Dik if (len < 0) {
105762224350SCasper H.S. Dik logerrcnt++;
105862224350SCasper H.S. Dik return (-1);
105962224350SCasper H.S. Dik }
106062224350SCasper H.S. Dik logcount += len;
106162224350SCasper H.S. Dik return (0);
106262224350SCasper H.S. Dik }
106362224350SCasper H.S. Dik
106462224350SCasper H.S. Dik static int
logflush(void)106562224350SCasper H.S. Dik logflush(void)
106662224350SCasper H.S. Dik {
106762224350SCasper H.S. Dik int len;
106862224350SCasper H.S. Dik static int lastflush;
106962224350SCasper H.S. Dik
107062224350SCasper H.S. Dik if (log == NULL)
107162224350SCasper H.S. Dik return (0);
107262224350SCasper H.S. Dik
107362224350SCasper H.S. Dik if (lastflush == logcount)
107462224350SCasper H.S. Dik return (0);
107562224350SCasper H.S. Dik
107662224350SCasper H.S. Dik if (cind == 2) {
107762224350SCasper H.S. Dik (void) fprintf(log, "%s\n", ccmnt[0]);
107862224350SCasper H.S. Dik (void) fprintf(log, "%s\n", ccmnt[1]);
107962224350SCasper H.S. Dik cind = 0;
108062224350SCasper H.S. Dik }
108162224350SCasper H.S. Dik
108262224350SCasper H.S. Dik /*
108362224350SCasper H.S. Dik * When using zfs, if the mark is there, then so is the rest before
108462224350SCasper H.S. Dik * it. But with ufs, we need to flush twice.
108562224350SCasper H.S. Dik */
108662224350SCasper H.S. Dik if (flushbeforemark) {
108762224350SCasper H.S. Dik if (fflush(log) == EOF)
108862224350SCasper H.S. Dik logerrcnt++;
108962224350SCasper H.S. Dik }
109062224350SCasper H.S. Dik /* Anything before the last marker found in the log will be valid */
109162224350SCasper H.S. Dik len = fprintf(log, "%s", marker);
109262224350SCasper H.S. Dik if (len < 0)
109362224350SCasper H.S. Dik logerrcnt++;
109462224350SCasper H.S. Dik else
109562224350SCasper H.S. Dik logcount += len;
109662224350SCasper H.S. Dik
109762224350SCasper H.S. Dik if (fflush(log) == EOF)
109862224350SCasper H.S. Dik logerrcnt++;
109962224350SCasper H.S. Dik
110062224350SCasper H.S. Dik sync_needed = B_FALSE;
110162224350SCasper H.S. Dik
110262224350SCasper H.S. Dik if (logerrcnt > 0 || logcount > MAXLOGFILESIZE)
110362224350SCasper H.S. Dik pkgdump();
110462224350SCasper H.S. Dik
110562224350SCasper H.S. Dik if (logerrcnt > 0)
110662224350SCasper H.S. Dik return (-1);
110762224350SCasper H.S. Dik
110862224350SCasper H.S. Dik lastflush = logcount;
110962224350SCasper H.S. Dik
111062224350SCasper H.S. Dik return (0);
111162224350SCasper H.S. Dik }
111262224350SCasper H.S. Dik
111362224350SCasper H.S. Dik static int
avlcmp(const void * ca,const void * cb)111462224350SCasper H.S. Dik avlcmp(const void *ca, const void *cb)
111562224350SCasper H.S. Dik {
111662224350SCasper H.S. Dik const pkgentry_t *a = ca;
111762224350SCasper H.S. Dik const pkgentry_t *b = cb;
111862224350SCasper H.S. Dik int i = memcmp(a->line, b->line,
111962224350SCasper H.S. Dik a->pathlen > b->pathlen ? b->pathlen : a->pathlen);
112062224350SCasper H.S. Dik
112162224350SCasper H.S. Dik if (i < 0)
112262224350SCasper H.S. Dik return (-1);
112362224350SCasper H.S. Dik else if (i > 0)
112462224350SCasper H.S. Dik return (1);
112562224350SCasper H.S. Dik else if (a->pathlen == b->pathlen)
112662224350SCasper H.S. Dik return (0);
112762224350SCasper H.S. Dik else if (a->pathlen > b->pathlen)
112862224350SCasper H.S. Dik return (1);
112962224350SCasper H.S. Dik else
113062224350SCasper H.S. Dik return (-1);
113162224350SCasper H.S. Dik }
113262224350SCasper H.S. Dik
113362224350SCasper H.S. Dik /*
113462224350SCasper H.S. Dik * Returns:
113562224350SCasper H.S. Dik * 0 - if we can get the lock
113662224350SCasper H.S. Dik * -1 - we can't lock
113762224350SCasper H.S. Dik */
113862224350SCasper H.S. Dik
113962224350SCasper H.S. Dik static int
establish_lock(char * lock)114062224350SCasper H.S. Dik establish_lock(char *lock)
114162224350SCasper H.S. Dik {
114262224350SCasper H.S. Dik int fd = open(lock, O_RDWR|O_CREAT, 0644);
114362224350SCasper H.S. Dik int i;
114462224350SCasper H.S. Dik
114562224350SCasper H.S. Dik if (fd < 0)
114662224350SCasper H.S. Dik return (-1);
114762224350SCasper H.S. Dik
114862224350SCasper H.S. Dik for (i = 0; i < 5; i++) {
114962224350SCasper H.S. Dik if (lockf(fd, F_TLOCK, 0) == 0)
115062224350SCasper H.S. Dik return (0);
115162224350SCasper H.S. Dik (void) sleep(1);
115262224350SCasper H.S. Dik }
115362224350SCasper H.S. Dik
115462224350SCasper H.S. Dik (void) close(fd);
115562224350SCasper H.S. Dik return (-1);
115662224350SCasper H.S. Dik }
115762224350SCasper H.S. Dik
115862224350SCasper H.S. Dik static int
no_memory_abort(void)115962224350SCasper H.S. Dik no_memory_abort(void)
116062224350SCasper H.S. Dik {
116162224350SCasper H.S. Dik return (UMEM_CALLBACK_EXIT(99));
116262224350SCasper H.S. Dik }
116362224350SCasper H.S. Dik
116462224350SCasper H.S. Dik /*
116562224350SCasper H.S. Dik * Dump a part of the contents file in a pipe; grep for the "filter".
116662224350SCasper H.S. Dik * It doesn't matter if we return too much.
116762224350SCasper H.S. Dik */
116862224350SCasper H.S. Dik
116962224350SCasper H.S. Dik static void *
thr_pkgfilter(void * v)117062224350SCasper H.S. Dik thr_pkgfilter(void *v)
117162224350SCasper H.S. Dik {
117262224350SCasper H.S. Dik pkgfilter_t *pf = v;
117362224350SCasper H.S. Dik pkgentry_t *p;
117462224350SCasper H.S. Dik int nums[2];
117562224350SCasper H.S. Dik FILE *cnts;
117662224350SCasper H.S. Dik
117762224350SCasper H.S. Dik cnts = fdopen(pf->cmd, "w");
117862224350SCasper H.S. Dik if (cnts == NULL)
117962224350SCasper H.S. Dik goto free;
118062224350SCasper H.S. Dik
1181*7706a9bfSCasper H.S. Dik /*
1182*7706a9bfSCasper H.S. Dik * Remove wild card: don't care about extra matches; make sure
1183*7706a9bfSCasper H.S. Dik * we remove both the "*" and the "." in front of it.
1184*7706a9bfSCasper H.S. Dik */
118562224350SCasper H.S. Dik if (pf->len > 0) {
118662224350SCasper H.S. Dik char *p;
118762224350SCasper H.S. Dik
118862224350SCasper H.S. Dik for (p = pf->buf; *p; p++) {
118962224350SCasper H.S. Dik if (*p == '*') {
119062224350SCasper H.S. Dik *p = 0;
1191*7706a9bfSCasper H.S. Dik if (p > pf->buf && p[-1] == '.')
1192*7706a9bfSCasper H.S. Dik p[-1] = 0;
119362224350SCasper H.S. Dik break;
119462224350SCasper H.S. Dik }
119562224350SCasper H.S. Dik }
119662224350SCasper H.S. Dik }
119762224350SCasper H.S. Dik
119862224350SCasper H.S. Dik /* Disable modifications while the filter is running */
119962224350SCasper H.S. Dik (void) mutex_lock(&mtx);
120062224350SCasper H.S. Dik write_locked++;
120162224350SCasper H.S. Dik (void) mutex_unlock(&mtx);
120262224350SCasper H.S. Dik /*
120362224350SCasper H.S. Dik * The protocol for the contents file for the clients:
120462224350SCasper H.S. Dik * <int:len><int:pathlen><line + 0>
120562224350SCasper H.S. Dik */
120662224350SCasper H.S. Dik
120762224350SCasper H.S. Dik for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) {
120862224350SCasper H.S. Dik if (pf->len > 0 && strstr(p->line, pf->buf) == NULL)
120962224350SCasper H.S. Dik continue;
121062224350SCasper H.S. Dik
121162224350SCasper H.S. Dik nums[0] = p->len;
121262224350SCasper H.S. Dik nums[1] = p->pathlen;
121362224350SCasper H.S. Dik if (fwrite(nums, sizeof (int), 2, cnts) != 2)
121462224350SCasper H.S. Dik break;
121562224350SCasper H.S. Dik if (fwrite(p->line, 1, p->len, cnts) != p->len)
121662224350SCasper H.S. Dik break;
121762224350SCasper H.S. Dik }
121862224350SCasper H.S. Dik
121962224350SCasper H.S. Dik (void) mutex_lock(&mtx);
122062224350SCasper H.S. Dik lastcall = gethrtime();
122162224350SCasper H.S. Dik write_locked--;
122262224350SCasper H.S. Dik (void) cond_broadcast(&cv);
122362224350SCasper H.S. Dik (void) mutex_unlock(&mtx);
122462224350SCasper H.S. Dik (void) fclose(cnts);
122562224350SCasper H.S. Dik
122662224350SCasper H.S. Dik free:
122762224350SCasper H.S. Dik umem_free(pf, sizeof (pkgfilter_t) + pf->len);
122862224350SCasper H.S. Dik return (NULL);
122962224350SCasper H.S. Dik }
123062224350SCasper H.S. Dik
123162224350SCasper H.S. Dik static hrtime_t
time_since_(hrtime_t last)123262224350SCasper H.S. Dik time_since_(hrtime_t last)
123362224350SCasper H.S. Dik {
123462224350SCasper H.S. Dik return (gethrtime() - last);
123562224350SCasper H.S. Dik }
123662224350SCasper H.S. Dik
123762224350SCasper H.S. Dik static void
my_cond_reltimedwait(hrtime_t delta,int sec)123862224350SCasper H.S. Dik my_cond_reltimedwait(hrtime_t delta, int sec)
123962224350SCasper H.S. Dik {
124062224350SCasper H.S. Dik hrtime_t wait = sec * LLNANOSEC - delta;
124162224350SCasper H.S. Dik timestruc_t waitfor;
124262224350SCasper H.S. Dik
124362224350SCasper H.S. Dik waitfor.tv_nsec = wait % LLNANOSEC;
124462224350SCasper H.S. Dik waitfor.tv_sec = wait / LLNANOSEC;
124562224350SCasper H.S. Dik (void) cond_reltimedwait(&cv, &mtx, &waitfor);
124662224350SCasper H.S. Dik }
124762224350SCasper H.S. Dik
124862224350SCasper H.S. Dik static int
pkgfilter(pkgfilter_t * pf,door_desc_t * dp)124962224350SCasper H.S. Dik pkgfilter(pkgfilter_t *pf, door_desc_t *dp)
125062224350SCasper H.S. Dik {
125162224350SCasper H.S. Dik
125262224350SCasper H.S. Dik int p[2];
125362224350SCasper H.S. Dik thread_t tid;
125462224350SCasper H.S. Dik pkgfilter_t *cpf;
125562224350SCasper H.S. Dik
125662224350SCasper H.S. Dik if (pipe(p) != 0)
125762224350SCasper H.S. Dik return (-1);
125862224350SCasper H.S. Dik
125962224350SCasper H.S. Dik cpf = umem_alloc(sizeof (pkgfilter_t) + pf->len, UMEM_NOFAIL);
126062224350SCasper H.S. Dik
126162224350SCasper H.S. Dik (void) memcpy(cpf, pf, sizeof (pkgfilter_t) + pf->len);
126262224350SCasper H.S. Dik
126362224350SCasper H.S. Dik /* Copy the file descriptor in the command field */
126462224350SCasper H.S. Dik cpf->cmd = p[1];
126562224350SCasper H.S. Dik
126662224350SCasper H.S. Dik if (thr_create(NULL, NULL, thr_pkgfilter, cpf, THR_DETACHED,
126762224350SCasper H.S. Dik &tid) != 0) {
126862224350SCasper H.S. Dik (void) close(p[0]);
126962224350SCasper H.S. Dik (void) close(p[1]);
127062224350SCasper H.S. Dik umem_free(cpf, sizeof (pkgfilter_t) + pf->len);
127162224350SCasper H.S. Dik return (-1);
127262224350SCasper H.S. Dik }
127362224350SCasper H.S. Dik (void) memset(dp, 0, sizeof (*dp));
127462224350SCasper H.S. Dik dp->d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
127562224350SCasper H.S. Dik dp->d_data.d_desc.d_descriptor = p[0];
127662224350SCasper H.S. Dik
127762224350SCasper H.S. Dik return (0);
127862224350SCasper H.S. Dik }
127962224350SCasper H.S. Dik
128062224350SCasper H.S. Dik static int
pkgaddlines(pkgfilter_t * pf)128162224350SCasper H.S. Dik pkgaddlines(pkgfilter_t *pf)
128262224350SCasper H.S. Dik {
128362224350SCasper H.S. Dik char *map = pf->buf;
128462224350SCasper H.S. Dik int len = pf->len;
128562224350SCasper H.S. Dik int off;
128662224350SCasper H.S. Dik pkgentry_t *ent, *look;
128762224350SCasper H.S. Dik avl_index_t where;
128862224350SCasper H.S. Dik char *q, *p;
128962224350SCasper H.S. Dik char c;
129062224350SCasper H.S. Dik int r = 0;
129162224350SCasper H.S. Dik
129262224350SCasper H.S. Dik if (log == NULL) {
129362224350SCasper H.S. Dik log = fopen(PKGLOG, "w");
129462224350SCasper H.S. Dik if (log == NULL)
129562224350SCasper H.S. Dik return (-1);
129662224350SCasper H.S. Dik }
129762224350SCasper H.S. Dik
129862224350SCasper H.S. Dik for (off = 0; off < len; off += q - p) {
129962224350SCasper H.S. Dik p = map + off;
130062224350SCasper H.S. Dik q = memchr(p, '\n', len - off);
130162224350SCasper H.S. Dik
130262224350SCasper H.S. Dik if (q == NULL)
130362224350SCasper H.S. Dik break;
130462224350SCasper H.S. Dik
130562224350SCasper H.S. Dik q++;
130662224350SCasper H.S. Dik
130762224350SCasper H.S. Dik if (p[0] == '#' || p[0] == '\n') {
130862224350SCasper H.S. Dik handle_comments(p, q - p);
130962224350SCasper H.S. Dik continue;
131062224350SCasper H.S. Dik }
131162224350SCasper H.S. Dik
131262224350SCasper H.S. Dik if (*p == '-')
131362224350SCasper H.S. Dik ent = parse_line(p + 1, q - (p + 1) - 1, B_FALSE);
131462224350SCasper H.S. Dik else
131562224350SCasper H.S. Dik ent = parse_line(p, q - p - 1, B_TRUE);
131662224350SCasper H.S. Dik
131762224350SCasper H.S. Dik if (ent == NULL) {
131862224350SCasper H.S. Dik r++;
131962224350SCasper H.S. Dik continue;
132062224350SCasper H.S. Dik }
132162224350SCasper H.S. Dik
132262224350SCasper H.S. Dik look = avl_find(list, ent, &where);
132362224350SCasper H.S. Dik if (look != NULL) {
132462224350SCasper H.S. Dik c = *p == '-' ? '-' : '=';
132562224350SCasper H.S. Dik if (c == '=') {
132662224350SCasper H.S. Dik swapentry(look, ent);
132762224350SCasper H.S. Dik ent = look;
132862224350SCasper H.S. Dik } else {
132962224350SCasper H.S. Dik avl_remove(list, look);
133062224350SCasper H.S. Dik freeentry(look);
133162224350SCasper H.S. Dik }
133262224350SCasper H.S. Dik } else if (*p == '-') {
133362224350SCasper H.S. Dik /* Remove something which isn't there: no-op */
133462224350SCasper H.S. Dik freeentry(ent);
133562224350SCasper H.S. Dik continue;
133662224350SCasper H.S. Dik } else {
133762224350SCasper H.S. Dik avl_insert(list, ent, where);
133862224350SCasper H.S. Dik c = '+';
133962224350SCasper H.S. Dik }
134062224350SCasper H.S. Dik
134162224350SCasper H.S. Dik sync_needed = B_TRUE;
134262224350SCasper H.S. Dik r += logentry(c, ent);
134362224350SCasper H.S. Dik if (c == '-')
134462224350SCasper H.S. Dik freeentry(ent);
134562224350SCasper H.S. Dik }
134662224350SCasper H.S. Dik
134762224350SCasper H.S. Dik return (r);
134862224350SCasper H.S. Dik }
134962224350SCasper H.S. Dik
135062224350SCasper H.S. Dik static void
finish(void)135162224350SCasper H.S. Dik finish(void)
135262224350SCasper H.S. Dik {
135362224350SCasper H.S. Dik if (verbose) {
135462224350SCasper H.S. Dik syslog(LOG_DEBUG,
135562224350SCasper H.S. Dik "finished: calls %d, pkgdumps %d, loglines %d "
135662224350SCasper H.S. Dik "(suppressed %d)\n",
135762224350SCasper H.S. Dik ncalls, ndumps, loglines, suppressed);
135862224350SCasper H.S. Dik }
135962224350SCasper H.S. Dik (void) fdetach(door);
136062224350SCasper H.S. Dik if (read_only)
136162224350SCasper H.S. Dik (void) unlink(door);
136262224350SCasper H.S. Dik }
136362224350SCasper H.S. Dik
136462224350SCasper H.S. Dik /*
136562224350SCasper H.S. Dik * Tell the wait thread to wake up and quit.
136662224350SCasper H.S. Dik */
136762224350SCasper H.S. Dik /* ARGSUSED */
136862224350SCasper H.S. Dik static void
signal_handler(int sig)136962224350SCasper H.S. Dik signal_handler(int sig)
137062224350SCasper H.S. Dik {
137162224350SCasper H.S. Dik if (read_only)
137262224350SCasper H.S. Dik exit(0);
137362224350SCasper H.S. Dik want_to_quit = 1;
137462224350SCasper H.S. Dik (void) cond_broadcast(&cv);
137562224350SCasper H.S. Dik }
1376