19869SCasper.Dik@Sun.COM /*
29869SCasper.Dik@Sun.COM * CDDL HEADER START
39869SCasper.Dik@Sun.COM *
49869SCasper.Dik@Sun.COM * The contents of this file are subject to the terms of the
59869SCasper.Dik@Sun.COM * Common Development and Distribution License (the "License").
69869SCasper.Dik@Sun.COM * You may not use this file except in compliance with the License.
79869SCasper.Dik@Sun.COM *
89869SCasper.Dik@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99869SCasper.Dik@Sun.COM * or http://www.opensolaris.org/os/licensing.
109869SCasper.Dik@Sun.COM * See the License for the specific language governing permissions
119869SCasper.Dik@Sun.COM * and limitations under the License.
129869SCasper.Dik@Sun.COM *
139869SCasper.Dik@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
149869SCasper.Dik@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159869SCasper.Dik@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
169869SCasper.Dik@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
179869SCasper.Dik@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
189869SCasper.Dik@Sun.COM *
199869SCasper.Dik@Sun.COM * CDDL HEADER END
209869SCasper.Dik@Sun.COM */
219869SCasper.Dik@Sun.COM
229869SCasper.Dik@Sun.COM /*
23*11770SCasper.Dik@Sun.COM * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
249869SCasper.Dik@Sun.COM * Use is subject to license terms.
259869SCasper.Dik@Sun.COM */
269869SCasper.Dik@Sun.COM
279869SCasper.Dik@Sun.COM /*
289869SCasper.Dik@Sun.COM * The Solaris package installer in-memory database server.
299869SCasper.Dik@Sun.COM *
309869SCasper.Dik@Sun.COM * We'll keep the contents file as before; but we cache it
319869SCasper.Dik@Sun.COM * and we don't write it as often. Instead, we log all
329869SCasper.Dik@Sun.COM * modifications to the log file.
339869SCasper.Dik@Sun.COM * Using the contents file and the logfile, the pkgserv can
349869SCasper.Dik@Sun.COM * rebuild the up-to-date contents file.
359869SCasper.Dik@Sun.COM * The logfile is constructed so that rebuilding the
369869SCasper.Dik@Sun.COM * contents file with the logfile is idempotent.
379869SCasper.Dik@Sun.COM *
389869SCasper.Dik@Sun.COM * The libpkg will start the daemon.
399869SCasper.Dik@Sun.COM *
409869SCasper.Dik@Sun.COM * The pkgserv will daemonize itself; the parent process
419869SCasper.Dik@Sun.COM * waits until the child process has initialized and will
429869SCasper.Dik@Sun.COM * start the door server.
439869SCasper.Dik@Sun.COM * If any error occurs during start-up, the error messages
449869SCasper.Dik@Sun.COM * are printed to stderr and the daemon will exit.
459869SCasper.Dik@Sun.COM * After start-up, any further errors are logged to syslog.
469869SCasper.Dik@Sun.COM * The parent pkgserv will exit with:
479869SCasper.Dik@Sun.COM * 0 - We've started
489869SCasper.Dik@Sun.COM * 1 - We couldn't start (locked)
499869SCasper.Dik@Sun.COM * 2 - Other problems (error on stderr)
509869SCasper.Dik@Sun.COM * 99 - Nothing reported; the caller must report.
519869SCasper.Dik@Sun.COM *
529869SCasper.Dik@Sun.COM * The daemon will timeout, by default. It will write the
539869SCasper.Dik@Sun.COM * contents file after a first timeout; and after a further
549869SCasper.Dik@Sun.COM * timeout, the daemon will exit.
559869SCasper.Dik@Sun.COM *
569869SCasper.Dik@Sun.COM * The daemon will only timeout if the current "client" has exited;
579869SCasper.Dik@Sun.COM * to this end, we always look at the pid of the last caller.
589869SCasper.Dik@Sun.COM * If the last client is no longer around, we record the new client.
599869SCasper.Dik@Sun.COM * In the typical case of running installf/removef from a post/preinstall
609869SCasper.Dik@Sun.COM * script, we continue to follow the pkginstall/pkgremove client's pid.
619869SCasper.Dik@Sun.COM *
629869SCasper.Dik@Sun.COM * In the particular case of install, we make sure the daemon
639869SCasper.Dik@Sun.COM * sticks around. (Install == install, (live)upgrade, zone install)
649869SCasper.Dik@Sun.COM */
659869SCasper.Dik@Sun.COM
669869SCasper.Dik@Sun.COM #ifdef lint
679869SCasper.Dik@Sun.COM #undef _FILE_OFFSET_BITS
689869SCasper.Dik@Sun.COM #endif
699869SCasper.Dik@Sun.COM
709869SCasper.Dik@Sun.COM #include <door.h>
719869SCasper.Dik@Sun.COM #include <errno.h>
729869SCasper.Dik@Sun.COM #include <fcntl.h>
739869SCasper.Dik@Sun.COM #include <limits.h>
749869SCasper.Dik@Sun.COM #include <pthread.h>
759869SCasper.Dik@Sun.COM #include <signal.h>
769869SCasper.Dik@Sun.COM #include <stddef.h>
779869SCasper.Dik@Sun.COM #include <stdio.h>
789869SCasper.Dik@Sun.COM #include <stdlib.h>
799869SCasper.Dik@Sun.COM #include <strings.h>
809869SCasper.Dik@Sun.COM #include <synch.h>
819869SCasper.Dik@Sun.COM #include <sys/avl.h>
829869SCasper.Dik@Sun.COM #include <sys/stat.h>
839869SCasper.Dik@Sun.COM #include <sys/statvfs.h>
849869SCasper.Dik@Sun.COM #include <sys/mman.h>
859869SCasper.Dik@Sun.COM #include <sys/time.h>
869869SCasper.Dik@Sun.COM #include <sys/wait.h>
879869SCasper.Dik@Sun.COM #include <syslog.h>
889869SCasper.Dik@Sun.COM #include <limits.h>
899869SCasper.Dik@Sun.COM #include <thread.h>
909869SCasper.Dik@Sun.COM #include <ucred.h>
919869SCasper.Dik@Sun.COM #include <umem.h>
929869SCasper.Dik@Sun.COM #include <unistd.h>
939869SCasper.Dik@Sun.COM #include <libintl.h>
949869SCasper.Dik@Sun.COM #include <locale.h>
959869SCasper.Dik@Sun.COM
969869SCasper.Dik@Sun.COM #include <pkglib.h>
979869SCasper.Dik@Sun.COM
989869SCasper.Dik@Sun.COM #define SADM_DIR "/var/sadm/install"
999869SCasper.Dik@Sun.COM
1009869SCasper.Dik@Sun.COM #define LOCK ".pkg.lock"
1019869SCasper.Dik@Sun.COM #define CLIENTLOCK ".pkg.lock.client"
1029869SCasper.Dik@Sun.COM #define CONTENTS "contents"
1039869SCasper.Dik@Sun.COM #define TCONTENTS "t.contents"
1049869SCasper.Dik@Sun.COM #define BADCONTENTS "contents.badXXXXXX"
1059869SCasper.Dik@Sun.COM
1069869SCasper.Dik@Sun.COM #define LLNANOSEC ((int64_t)NANOSEC)
1079869SCasper.Dik@Sun.COM
1089869SCasper.Dik@Sun.COM #define DUMPTIMEOUT 60
1099869SCasper.Dik@Sun.COM #define EXITTIMEOUT 300
1109869SCasper.Dik@Sun.COM
1119869SCasper.Dik@Sun.COM /*
1129869SCasper.Dik@Sun.COM * Contents file storage format. At install time, the amount of memory
1139869SCasper.Dik@Sun.COM * might be limited, so we make sure that we use as little memory
1149869SCasper.Dik@Sun.COM * as possible. The package tools modify the entries; so we install the
1159869SCasper.Dik@Sun.COM * single lines. We also remember the length of the path; this is needed
1169869SCasper.Dik@Sun.COM * for avlcmp and we return it to the tools. This saves time.
1179869SCasper.Dik@Sun.COM *
1189869SCasper.Dik@Sun.COM * All strings are allocated using umem_alloc.
1199869SCasper.Dik@Sun.COM */
1209869SCasper.Dik@Sun.COM typedef struct pkgentry {
1219869SCasper.Dik@Sun.COM char *line; /* The contents line for the file */
1229869SCasper.Dik@Sun.COM avl_node_t avl; /* The avl header */
1239869SCasper.Dik@Sun.COM int pkgoff; /* Where the packages live; start with SP */
1249869SCasper.Dik@Sun.COM int pathlen; /* The length of the pathname */
1259869SCasper.Dik@Sun.COM int len; /* Length of the line (incl NUL) */
1269869SCasper.Dik@Sun.COM } pkgentry_t;
1279869SCasper.Dik@Sun.COM
1289869SCasper.Dik@Sun.COM static char IS_ST0[256];
1299869SCasper.Dik@Sun.COM static char IS_ST0Q[256];
1309869SCasper.Dik@Sun.COM
1319869SCasper.Dik@Sun.COM static void pkg_door_srv(void *, char *, size_t, door_desc_t *, uint_t);
1329869SCasper.Dik@Sun.COM static char *file_find(pkgfilter_t *, int *);
1339869SCasper.Dik@Sun.COM static void parse_contents(void);
1349869SCasper.Dik@Sun.COM static int parse_log(void);
1359869SCasper.Dik@Sun.COM static void pkgdump(void);
1369869SCasper.Dik@Sun.COM static int logflush(void);
1379869SCasper.Dik@Sun.COM static int avlcmp(const void *, const void *);
1389869SCasper.Dik@Sun.COM static void freeentry(pkgentry_t *);
1399869SCasper.Dik@Sun.COM static void swapentry(pkgentry_t *, pkgentry_t *);
1409869SCasper.Dik@Sun.COM static int establish_lock(char *);
1419869SCasper.Dik@Sun.COM static int no_memory_abort(void);
1429869SCasper.Dik@Sun.COM static int pkgfilter(pkgfilter_t *, door_desc_t *);
1439869SCasper.Dik@Sun.COM static int pkgaddlines(pkgfilter_t *);
1449869SCasper.Dik@Sun.COM static void finish(void);
1459869SCasper.Dik@Sun.COM static void signal_handler(int);
1469869SCasper.Dik@Sun.COM static void my_cond_reltimedwait(hrtime_t, int);
1479869SCasper.Dik@Sun.COM static hrtime_t time_since_(hrtime_t);
1489869SCasper.Dik@Sun.COM
1499869SCasper.Dik@Sun.COM /*
1509869SCasper.Dik@Sun.COM * Server actions
1519869SCasper.Dik@Sun.COM * - set mode (contents file, log file)
1529869SCasper.Dik@Sun.COM * - roll log
1539869SCasper.Dik@Sun.COM * - remove package
1549869SCasper.Dik@Sun.COM * - merge package entries
1559869SCasper.Dik@Sun.COM */
1569869SCasper.Dik@Sun.COM
1579869SCasper.Dik@Sun.COM static FILE *log;
1589869SCasper.Dik@Sun.COM static char *door = PKGDOOR;
1599869SCasper.Dik@Sun.COM
1609869SCasper.Dik@Sun.COM static avl_tree_t listp, *list = &listp;
1619869SCasper.Dik@Sun.COM
1629869SCasper.Dik@Sun.COM /* Keep the "the last command modified the contents file ... */
1639869SCasper.Dik@Sun.COM static char *ccmnt[2];
1649869SCasper.Dik@Sun.COM static int cind = 0;
1659869SCasper.Dik@Sun.COM
1669869SCasper.Dik@Sun.COM static mutex_t mtx = DEFAULTMUTEX;
1679869SCasper.Dik@Sun.COM static cond_t cv = DEFAULTCV;
1689869SCasper.Dik@Sun.COM
1699869SCasper.Dik@Sun.COM static int flushbeforemark = 1;
1709869SCasper.Dik@Sun.COM static int logerrcnt = 0;
1719869SCasper.Dik@Sun.COM static int loglines = 0;
1729869SCasper.Dik@Sun.COM static int suppressed = 0;
1739869SCasper.Dik@Sun.COM static int logcount;
1749869SCasper.Dik@Sun.COM static int ndumps;
1759869SCasper.Dik@Sun.COM static int ncalls;
1769869SCasper.Dik@Sun.COM static int changes;
1779869SCasper.Dik@Sun.COM static hrtime_t lastchange;
1789869SCasper.Dik@Sun.COM static hrtime_t lastcall;
1799869SCasper.Dik@Sun.COM static volatile int want_to_quit;
1809869SCasper.Dik@Sun.COM static boolean_t read_only = B_FALSE;
1819869SCasper.Dik@Sun.COM static boolean_t permanent = B_FALSE;
1829869SCasper.Dik@Sun.COM static boolean_t one_shot = B_FALSE;
1839869SCasper.Dik@Sun.COM static int write_locked;
1849869SCasper.Dik@Sun.COM static pid_t client_pid;
1859869SCasper.Dik@Sun.COM static int verbose = 1;
1869869SCasper.Dik@Sun.COM static hrtime_t dumptimeout = DUMPTIMEOUT;
1879869SCasper.Dik@Sun.COM static boolean_t sync_needed = B_FALSE;
1889869SCasper.Dik@Sun.COM
1899869SCasper.Dik@Sun.COM static uid_t myuid;
1909869SCasper.Dik@Sun.COM
1919869SCasper.Dik@Sun.COM static char marker[] = "###Marker\n";
1929869SCasper.Dik@Sun.COM
1939869SCasper.Dik@Sun.COM static umem_cache_t *ecache;
1949869SCasper.Dik@Sun.COM
1959869SCasper.Dik@Sun.COM static char pkgdir[PATH_MAX];
1969869SCasper.Dik@Sun.COM
1979869SCasper.Dik@Sun.COM static void
server_main(int argc,char ** argv)1989869SCasper.Dik@Sun.COM server_main(int argc, char **argv)
1999869SCasper.Dik@Sun.COM {
2009869SCasper.Dik@Sun.COM int did;
2019869SCasper.Dik@Sun.COM int c;
2029869SCasper.Dik@Sun.COM struct statvfs vfsbuf;
2039869SCasper.Dik@Sun.COM int imexit = 0;
2049869SCasper.Dik@Sun.COM pid_t parent;
2059869SCasper.Dik@Sun.COM char *root = NULL;
2069869SCasper.Dik@Sun.COM char *sadmdir = NULL;
2079869SCasper.Dik@Sun.COM hrtime_t delta;
2089869SCasper.Dik@Sun.COM int dir = 0;
2099869SCasper.Dik@Sun.COM int dfd;
2109869SCasper.Dik@Sun.COM
2119869SCasper.Dik@Sun.COM (void) set_prog_name("pkgserv");
2129869SCasper.Dik@Sun.COM
2139869SCasper.Dik@Sun.COM openlog("pkgserv", LOG_PID | LOG_ODELAY, LOG_DAEMON);
2149869SCasper.Dik@Sun.COM
2159869SCasper.Dik@Sun.COM while ((c = getopt(argc, argv, "d:eoN:pP:R:r:")) != EOF) {
2169869SCasper.Dik@Sun.COM switch (c) {
2179869SCasper.Dik@Sun.COM case 'e':
2189869SCasper.Dik@Sun.COM imexit = 1;
2199869SCasper.Dik@Sun.COM break;
2209869SCasper.Dik@Sun.COM case 'd':
2219869SCasper.Dik@Sun.COM sadmdir = optarg;
2229869SCasper.Dik@Sun.COM if (*sadmdir != '/' || strlen(sadmdir) >= PATH_MAX ||
2239869SCasper.Dik@Sun.COM access(sadmdir, X_OK) != 0)
2249869SCasper.Dik@Sun.COM exit(99);
2259869SCasper.Dik@Sun.COM break;
2269869SCasper.Dik@Sun.COM case 'N':
2279869SCasper.Dik@Sun.COM (void) set_prog_name(optarg);
2289869SCasper.Dik@Sun.COM break;
2299869SCasper.Dik@Sun.COM case 'o':
2309869SCasper.Dik@Sun.COM one_shot = B_TRUE;
2319869SCasper.Dik@Sun.COM verbose = 0;
2329869SCasper.Dik@Sun.COM break;
2339869SCasper.Dik@Sun.COM case 'p':
2349869SCasper.Dik@Sun.COM /*
2359869SCasper.Dik@Sun.COM * We are updating possibly many zones; so we're not
2369869SCasper.Dik@Sun.COM * dumping based on a short timeout and we will not
2379869SCasper.Dik@Sun.COM * exit.
2389869SCasper.Dik@Sun.COM */
2399869SCasper.Dik@Sun.COM permanent = B_TRUE;
2409869SCasper.Dik@Sun.COM dumptimeout = 3600;
2419869SCasper.Dik@Sun.COM break;
2429869SCasper.Dik@Sun.COM case 'P':
2439869SCasper.Dik@Sun.COM client_pid = atoi(optarg);
2449869SCasper.Dik@Sun.COM break;
2459869SCasper.Dik@Sun.COM case 'R':
2469869SCasper.Dik@Sun.COM root = optarg;
2479869SCasper.Dik@Sun.COM if (*root != '/' || strlen(root) >= PATH_MAX ||
2489869SCasper.Dik@Sun.COM access(root, X_OK) != 0)
2499869SCasper.Dik@Sun.COM exit(99);
2509869SCasper.Dik@Sun.COM break;
2519869SCasper.Dik@Sun.COM case 'r':
2529869SCasper.Dik@Sun.COM read_only = B_TRUE;
2539869SCasper.Dik@Sun.COM one_shot = B_TRUE;
2549869SCasper.Dik@Sun.COM verbose = 0;
2559869SCasper.Dik@Sun.COM door = optarg;
2569869SCasper.Dik@Sun.COM break;
2579869SCasper.Dik@Sun.COM default:
2589869SCasper.Dik@Sun.COM exit(99);
2599869SCasper.Dik@Sun.COM }
2609869SCasper.Dik@Sun.COM }
2619869SCasper.Dik@Sun.COM
2629869SCasper.Dik@Sun.COM if (one_shot && permanent) {
2639869SCasper.Dik@Sun.COM progerr(gettext("Incorrect Usage"));
2649869SCasper.Dik@Sun.COM exit(99);
2659869SCasper.Dik@Sun.COM }
2669869SCasper.Dik@Sun.COM
2679869SCasper.Dik@Sun.COM umem_nofail_callback(no_memory_abort);
2689869SCasper.Dik@Sun.COM
2699869SCasper.Dik@Sun.COM if (root != NULL && strcmp(root, "/") != 0) {
2709869SCasper.Dik@Sun.COM if (snprintf(pkgdir, PATH_MAX, "%s%s", root,
2719869SCasper.Dik@Sun.COM sadmdir == NULL ? SADM_DIR : sadmdir) >= PATH_MAX) {
2729869SCasper.Dik@Sun.COM exit(99);
2739869SCasper.Dik@Sun.COM }
2749869SCasper.Dik@Sun.COM } else {
2759869SCasper.Dik@Sun.COM if (sadmdir == NULL)
2769869SCasper.Dik@Sun.COM (void) strcpy(pkgdir, SADM_DIR);
2779869SCasper.Dik@Sun.COM else
2789869SCasper.Dik@Sun.COM (void) strcpy(pkgdir, sadmdir);
2799869SCasper.Dik@Sun.COM }
2809869SCasper.Dik@Sun.COM
2819869SCasper.Dik@Sun.COM if (chdir(pkgdir) != 0) {
2829869SCasper.Dik@Sun.COM progerr(gettext("can't chdir to %s"), pkgdir);
2839869SCasper.Dik@Sun.COM exit(2);
2849869SCasper.Dik@Sun.COM }
2859869SCasper.Dik@Sun.COM
2869869SCasper.Dik@Sun.COM closefrom(3);
2879869SCasper.Dik@Sun.COM
2889869SCasper.Dik@Sun.COM if (!read_only && establish_lock(LOCK) < 0) {
2899869SCasper.Dik@Sun.COM progerr(gettext(
2909869SCasper.Dik@Sun.COM "couldn't lock in %s (server running?): %s"),
2919869SCasper.Dik@Sun.COM pkgdir, strerror(errno));
2929869SCasper.Dik@Sun.COM exit(1);
2939869SCasper.Dik@Sun.COM }
2949869SCasper.Dik@Sun.COM
2959869SCasper.Dik@Sun.COM did = door_create(pkg_door_srv, 0, DOOR_REFUSE_DESC);
2969869SCasper.Dik@Sun.COM if (did == -1) {
2979869SCasper.Dik@Sun.COM progerr("door_create: %s", strerror(errno));
2989869SCasper.Dik@Sun.COM exit(2);
2999869SCasper.Dik@Sun.COM }
3009869SCasper.Dik@Sun.COM
3019869SCasper.Dik@Sun.COM (void) fdetach(door);
3029869SCasper.Dik@Sun.COM
3039869SCasper.Dik@Sun.COM if ((dfd = creat(door, 0644)) < 0 || close(dfd) < 0) {
3049869SCasper.Dik@Sun.COM progerr("door_create: %s", strerror(errno));
3059869SCasper.Dik@Sun.COM exit(2);
3069869SCasper.Dik@Sun.COM }
3079869SCasper.Dik@Sun.COM
3089869SCasper.Dik@Sun.COM (void) mutex_lock(&mtx);
3099869SCasper.Dik@Sun.COM
3109869SCasper.Dik@Sun.COM myuid = geteuid();
3119869SCasper.Dik@Sun.COM
3129869SCasper.Dik@Sun.COM (void) sigset(SIGHUP, signal_handler);
3139869SCasper.Dik@Sun.COM (void) sigset(SIGTERM, signal_handler);
3149869SCasper.Dik@Sun.COM (void) sigset(SIGINT, signal_handler);
3159869SCasper.Dik@Sun.COM (void) sigset(SIGQUIT, signal_handler);
3169869SCasper.Dik@Sun.COM
3179869SCasper.Dik@Sun.COM (void) signal(SIGPIPE, SIG_IGN);
3189869SCasper.Dik@Sun.COM
3199869SCasper.Dik@Sun.COM (void) atexit(finish);
3209869SCasper.Dik@Sun.COM
3219869SCasper.Dik@Sun.COM if (fattach(did, door) != 0) {
3229869SCasper.Dik@Sun.COM progerr(gettext("attach door: %s"), strerror(errno));
3239869SCasper.Dik@Sun.COM exit(2);
3249869SCasper.Dik@Sun.COM }
3259869SCasper.Dik@Sun.COM (void) close(did);
3269869SCasper.Dik@Sun.COM
3279869SCasper.Dik@Sun.COM ecache = umem_cache_create("entry", sizeof (pkgentry_t),
3289869SCasper.Dik@Sun.COM sizeof (char *), NULL, NULL, NULL, NULL, NULL, 0);
3299869SCasper.Dik@Sun.COM
3309869SCasper.Dik@Sun.COM avl_create(list, avlcmp, sizeof (pkgentry_t),
3319869SCasper.Dik@Sun.COM offsetof(pkgentry_t, avl));
3329869SCasper.Dik@Sun.COM
3339869SCasper.Dik@Sun.COM IS_ST0['\0'] = 1;
3349869SCasper.Dik@Sun.COM IS_ST0[' '] = 1;
3359869SCasper.Dik@Sun.COM IS_ST0['\t'] = 1;
3369869SCasper.Dik@Sun.COM
3379869SCasper.Dik@Sun.COM IS_ST0Q['\0'] = 1;
3389869SCasper.Dik@Sun.COM IS_ST0Q[' '] = 1;
3399869SCasper.Dik@Sun.COM IS_ST0Q['\t'] = 1;
3409869SCasper.Dik@Sun.COM IS_ST0Q['='] = 1;
3419869SCasper.Dik@Sun.COM
3429869SCasper.Dik@Sun.COM parse_contents();
3439869SCasper.Dik@Sun.COM if (parse_log() > 0)
3449869SCasper.Dik@Sun.COM pkgdump();
3459869SCasper.Dik@Sun.COM
3469869SCasper.Dik@Sun.COM if (imexit)
3479869SCasper.Dik@Sun.COM exit(0);
3489869SCasper.Dik@Sun.COM
3499869SCasper.Dik@Sun.COM if (statvfs(".", &vfsbuf) != 0) {
3509869SCasper.Dik@Sun.COM progerr(gettext("statvfs: %s"), strerror(errno));
3519869SCasper.Dik@Sun.COM exit(2);
3529869SCasper.Dik@Sun.COM }
3539869SCasper.Dik@Sun.COM
3549869SCasper.Dik@Sun.COM if (strcmp(vfsbuf.f_basetype, "zfs") == 0)
3559869SCasper.Dik@Sun.COM flushbeforemark = 0;
3569869SCasper.Dik@Sun.COM
3579869SCasper.Dik@Sun.COM /* We've started, tell the parent */
3589869SCasper.Dik@Sun.COM parent = getppid();
3599869SCasper.Dik@Sun.COM if (parent != 1)
3609869SCasper.Dik@Sun.COM (void) kill(parent, SIGUSR1);
3619869SCasper.Dik@Sun.COM
3629869SCasper.Dik@Sun.COM if (!one_shot) {
3639869SCasper.Dik@Sun.COM int fd;
3649869SCasper.Dik@Sun.COM (void) setsid();
3659869SCasper.Dik@Sun.COM fd = open("/dev/null", O_RDWR, 0);
3669869SCasper.Dik@Sun.COM if (fd >= 0) {
3679869SCasper.Dik@Sun.COM (void) dup2(fd, STDIN_FILENO);
3689869SCasper.Dik@Sun.COM (void) dup2(fd, STDOUT_FILENO);
3699869SCasper.Dik@Sun.COM (void) dup2(fd, STDERR_FILENO);
3709869SCasper.Dik@Sun.COM if (fd > 2)
3719869SCasper.Dik@Sun.COM (void) close(fd);
3729869SCasper.Dik@Sun.COM }
3739869SCasper.Dik@Sun.COM }
3749869SCasper.Dik@Sun.COM
3759869SCasper.Dik@Sun.COM lastcall = lastchange = gethrtime();
3769869SCasper.Dik@Sun.COM
3779869SCasper.Dik@Sun.COM /*
3789869SCasper.Dik@Sun.COM * Start the main thread, here is where we unlock the mutex.
3799869SCasper.Dik@Sun.COM */
3809869SCasper.Dik@Sun.COM for (;;) {
3819869SCasper.Dik@Sun.COM if (want_to_quit) {
3829869SCasper.Dik@Sun.COM pkgdump();
3839869SCasper.Dik@Sun.COM exit(0);
3849869SCasper.Dik@Sun.COM }
3859869SCasper.Dik@Sun.COM /* Wait forever when root or when there's a running filter */
3869869SCasper.Dik@Sun.COM if (write_locked ||
3879869SCasper.Dik@Sun.COM (!one_shot && permanent && dir == changes)) {
3889869SCasper.Dik@Sun.COM (void) cond_wait(&cv, &mtx);
3899869SCasper.Dik@Sun.COM continue;
3909869SCasper.Dik@Sun.COM }
3919869SCasper.Dik@Sun.COM delta = time_since_(lastchange);
3929869SCasper.Dik@Sun.COM /* Wait until DUMPTIMEOUT after last change before we pkgdump */
3939869SCasper.Dik@Sun.COM if (delta < dumptimeout * LLNANOSEC) {
3949869SCasper.Dik@Sun.COM my_cond_reltimedwait(delta, dumptimeout);
3959869SCasper.Dik@Sun.COM continue;
3969869SCasper.Dik@Sun.COM }
3979869SCasper.Dik@Sun.COM /* Client still around? Just wait then. */
3989869SCasper.Dik@Sun.COM if (client_pid > 1 && kill(client_pid, 0) == 0) {
3999869SCasper.Dik@Sun.COM lastchange = lastcall = gethrtime();
4009869SCasper.Dik@Sun.COM continue;
4019869SCasper.Dik@Sun.COM }
4029869SCasper.Dik@Sun.COM /* Wait for another EXITTIMEOUT seconds before we exit */
4039869SCasper.Dik@Sun.COM if ((one_shot || !permanent) && dir == changes) {
4049869SCasper.Dik@Sun.COM delta = time_since_(lastcall);
4059869SCasper.Dik@Sun.COM if (delta < EXITTIMEOUT * LLNANOSEC) {
4069869SCasper.Dik@Sun.COM my_cond_reltimedwait(delta, EXITTIMEOUT);
4079869SCasper.Dik@Sun.COM continue;
4089869SCasper.Dik@Sun.COM }
4099869SCasper.Dik@Sun.COM exit(0);
4109869SCasper.Dik@Sun.COM }
4119869SCasper.Dik@Sun.COM pkgdump();
4129869SCasper.Dik@Sun.COM dir = changes;
4139869SCasper.Dik@Sun.COM }
4149869SCasper.Dik@Sun.COM
4159869SCasper.Dik@Sun.COM /*NOTREACHED*/
4169869SCasper.Dik@Sun.COM }
4179869SCasper.Dik@Sun.COM
4189869SCasper.Dik@Sun.COM /*ARGSUSED*/
4199869SCasper.Dik@Sun.COM static void
nothing(int sig)4209869SCasper.Dik@Sun.COM nothing(int sig)
4219869SCasper.Dik@Sun.COM {
4229869SCasper.Dik@Sun.COM }
4239869SCasper.Dik@Sun.COM
4249869SCasper.Dik@Sun.COM int
main(int argc,char ** argv)4259869SCasper.Dik@Sun.COM main(int argc, char **argv)
4269869SCasper.Dik@Sun.COM {
4279869SCasper.Dik@Sun.COM int sig;
4289869SCasper.Dik@Sun.COM sigset_t sset;
4299869SCasper.Dik@Sun.COM int stat;
4309869SCasper.Dik@Sun.COM
4319869SCasper.Dik@Sun.COM /*
4329869SCasper.Dik@Sun.COM * We're starting the daemon; this process exits when the door
4339869SCasper.Dik@Sun.COM * server is established or when it fails to establish.
4349869SCasper.Dik@Sun.COM * We wait until the child process sends a SIGUSR1 or when it
4359869SCasper.Dik@Sun.COM * exits.
4369869SCasper.Dik@Sun.COM * We keep around who started us and as long as it lives, we don't
4379869SCasper.Dik@Sun.COM * exit.
4389869SCasper.Dik@Sun.COM */
4399869SCasper.Dik@Sun.COM
4409869SCasper.Dik@Sun.COM (void) setlocale(LC_ALL, "");
4419869SCasper.Dik@Sun.COM (void) textdomain(TEXT_DOMAIN);
4429869SCasper.Dik@Sun.COM
4439869SCasper.Dik@Sun.COM client_pid = getppid();
4449869SCasper.Dik@Sun.COM
4459869SCasper.Dik@Sun.COM (void) sigemptyset(&sset);
4469869SCasper.Dik@Sun.COM (void) sigaddset(&sset, SIGUSR1);
4479869SCasper.Dik@Sun.COM (void) sigaddset(&sset, SIGCLD);
4489869SCasper.Dik@Sun.COM
4499869SCasper.Dik@Sun.COM /* We need to catch the SIGCLD before we can sigwait for it. */
4509869SCasper.Dik@Sun.COM (void) sigset(SIGCLD, nothing);
4519869SCasper.Dik@Sun.COM /* We need to make sure that SIGUSR1 is not ignored. */
4529869SCasper.Dik@Sun.COM (void) sigset(SIGUSR1, SIG_DFL);
4539869SCasper.Dik@Sun.COM (void) sigprocmask(SIG_BLOCK, &sset, NULL);
4549869SCasper.Dik@Sun.COM
4559869SCasper.Dik@Sun.COM /* We install the contents file readable. */
4569869SCasper.Dik@Sun.COM (void) umask(022);
4579869SCasper.Dik@Sun.COM
4589869SCasper.Dik@Sun.COM switch (fork()) {
4599869SCasper.Dik@Sun.COM case -1:
4609869SCasper.Dik@Sun.COM exit(99);
4619869SCasper.Dik@Sun.COM /*NOTREACHED*/
4629869SCasper.Dik@Sun.COM case 0:
4639869SCasper.Dik@Sun.COM server_main(argc, argv);
4649869SCasper.Dik@Sun.COM /*NOTREACHED*/
4659869SCasper.Dik@Sun.COM default:
4669869SCasper.Dik@Sun.COM /* In the parent */
4679869SCasper.Dik@Sun.COM break;
4689869SCasper.Dik@Sun.COM }
4699869SCasper.Dik@Sun.COM
4709869SCasper.Dik@Sun.COM for (;;) {
4719869SCasper.Dik@Sun.COM sig = sigwait(&sset);
4729869SCasper.Dik@Sun.COM
4739869SCasper.Dik@Sun.COM switch (sig) {
4749869SCasper.Dik@Sun.COM case SIGCLD:
4759869SCasper.Dik@Sun.COM if (wait(&stat) > 0) {
4769869SCasper.Dik@Sun.COM if (WIFEXITED(stat))
4779869SCasper.Dik@Sun.COM _exit(WEXITSTATUS(stat));
4789869SCasper.Dik@Sun.COM else if (WIFSIGNALED(stat))
4799869SCasper.Dik@Sun.COM _exit(99);
4809869SCasper.Dik@Sun.COM }
4819869SCasper.Dik@Sun.COM break;
4829869SCasper.Dik@Sun.COM case SIGUSR1:
4839869SCasper.Dik@Sun.COM _exit(0);
4849869SCasper.Dik@Sun.COM }
4859869SCasper.Dik@Sun.COM }
4869869SCasper.Dik@Sun.COM }
4879869SCasper.Dik@Sun.COM
4889869SCasper.Dik@Sun.COM /*ARGSUSED*/
4899869SCasper.Dik@Sun.COM static void
pkg_door_srv(void * cookie,char * argp,size_t asz,door_desc_t * dp,uint_t ndesc)4909869SCasper.Dik@Sun.COM pkg_door_srv(void *cookie, char *argp, size_t asz, door_desc_t *dp,
4919869SCasper.Dik@Sun.COM uint_t ndesc)
4929869SCasper.Dik@Sun.COM {
4939869SCasper.Dik@Sun.COM char *p = NULL;
4949869SCasper.Dik@Sun.COM pkgcmd_t *pcmd = (pkgcmd_t *)argp;
4959869SCasper.Dik@Sun.COM ucred_t *uc = NULL;
4969869SCasper.Dik@Sun.COM uid_t caller;
4979869SCasper.Dik@Sun.COM pid_t pcaller;
4989869SCasper.Dik@Sun.COM door_desc_t ddp;
4999869SCasper.Dik@Sun.COM int dnum = 0;
5009869SCasper.Dik@Sun.COM int one = 1;
5019869SCasper.Dik@Sun.COM int len = -1;
5029869SCasper.Dik@Sun.COM
5039869SCasper.Dik@Sun.COM if (asz < sizeof (pkgcmd_t)) {
5049869SCasper.Dik@Sun.COM (void) door_return(NULL, 0, NULL, 0);
5059869SCasper.Dik@Sun.COM return;
5069869SCasper.Dik@Sun.COM }
5079869SCasper.Dik@Sun.COM
5089869SCasper.Dik@Sun.COM if (door_ucred(&uc) != 0) {
5099869SCasper.Dik@Sun.COM (void) door_return(NULL, 0, NULL, 0);
5109869SCasper.Dik@Sun.COM return;
5119869SCasper.Dik@Sun.COM }
5129869SCasper.Dik@Sun.COM
5139869SCasper.Dik@Sun.COM caller = ucred_geteuid(uc);
5149869SCasper.Dik@Sun.COM pcaller = ucred_getpid(uc);
5159869SCasper.Dik@Sun.COM ucred_free(uc);
5169869SCasper.Dik@Sun.COM
5179869SCasper.Dik@Sun.COM if (caller != myuid) {
5189869SCasper.Dik@Sun.COM (void) door_return(NULL, 0, NULL, 0);
5199869SCasper.Dik@Sun.COM return;
5209869SCasper.Dik@Sun.COM }
5219869SCasper.Dik@Sun.COM
5229869SCasper.Dik@Sun.COM (void) mutex_lock(&mtx);
5239869SCasper.Dik@Sun.COM ncalls++;
5249869SCasper.Dik@Sun.COM
5259869SCasper.Dik@Sun.COM if (pcaller != client_pid && pcaller != -1 &&
5269869SCasper.Dik@Sun.COM (client_pid == 1 || kill(client_pid, 0) != 0)) {
5279869SCasper.Dik@Sun.COM client_pid = pcaller;
5289869SCasper.Dik@Sun.COM }
5299869SCasper.Dik@Sun.COM
5309869SCasper.Dik@Sun.COM if (PKG_WRITE_COMMAND(pcmd->cmd))
5319869SCasper.Dik@Sun.COM while (write_locked > 0)
5329869SCasper.Dik@Sun.COM (void) cond_wait(&cv, &mtx);
5339869SCasper.Dik@Sun.COM
5349869SCasper.Dik@Sun.COM switch (pcmd->cmd) {
5359869SCasper.Dik@Sun.COM case PKG_FINDFILE:
5369869SCasper.Dik@Sun.COM p = file_find((pkgfilter_t *)argp, &len);
5379869SCasper.Dik@Sun.COM break;
5389869SCasper.Dik@Sun.COM case PKG_DUMP:
5399869SCasper.Dik@Sun.COM if (read_only)
5409869SCasper.Dik@Sun.COM goto err;
5419869SCasper.Dik@Sun.COM if (logcount > 0)
5429869SCasper.Dik@Sun.COM pkgdump();
5439869SCasper.Dik@Sun.COM break;
5449869SCasper.Dik@Sun.COM case PKG_EXIT:
5459869SCasper.Dik@Sun.COM if (logcount > 0)
5469869SCasper.Dik@Sun.COM pkgdump();
5479869SCasper.Dik@Sun.COM exit(0);
5489869SCasper.Dik@Sun.COM /*NOTREACHED*/
5499869SCasper.Dik@Sun.COM case PKG_PKGSYNC:
5509869SCasper.Dik@Sun.COM if (read_only || logflush() != 0)
5519869SCasper.Dik@Sun.COM goto err;
5529869SCasper.Dik@Sun.COM break;
5539869SCasper.Dik@Sun.COM case PKG_FILTER:
5549869SCasper.Dik@Sun.COM if (pkgfilter((pkgfilter_t *)argp, &ddp) == 0)
5559869SCasper.Dik@Sun.COM dnum = 1;
5569869SCasper.Dik@Sun.COM break;
5579869SCasper.Dik@Sun.COM case PKG_ADDLINES:
5589869SCasper.Dik@Sun.COM if (read_only)
5599869SCasper.Dik@Sun.COM goto err;
5609869SCasper.Dik@Sun.COM changes++;
5619869SCasper.Dik@Sun.COM
5629869SCasper.Dik@Sun.COM if (pkgaddlines((pkgfilter_t *)argp) != 0)
5639869SCasper.Dik@Sun.COM goto err;
5649869SCasper.Dik@Sun.COM /* If we've updated the database, tell the dump thread */
5659869SCasper.Dik@Sun.COM lastchange = gethrtime();
5669869SCasper.Dik@Sun.COM (void) cond_broadcast(&cv);
5679869SCasper.Dik@Sun.COM break;
5689869SCasper.Dik@Sun.COM case PKG_NOP:
5699869SCasper.Dik@Sun.COM /* Do nothing but register the current client's pid. */
5709869SCasper.Dik@Sun.COM break;
5719869SCasper.Dik@Sun.COM default:
5729869SCasper.Dik@Sun.COM goto err;
5739869SCasper.Dik@Sun.COM }
5749869SCasper.Dik@Sun.COM
5759869SCasper.Dik@Sun.COM lastcall = gethrtime();
5769869SCasper.Dik@Sun.COM (void) mutex_unlock(&mtx);
5779869SCasper.Dik@Sun.COM (void) door_return(p, len != -1 ? len : p == NULL ? 0 : strlen(p) + 1,
5789869SCasper.Dik@Sun.COM dnum == 0 ? NULL : &ddp, dnum);
5799869SCasper.Dik@Sun.COM return;
5809869SCasper.Dik@Sun.COM
5819869SCasper.Dik@Sun.COM err:
5829869SCasper.Dik@Sun.COM (void) mutex_unlock(&mtx);
5839869SCasper.Dik@Sun.COM (void) door_return((void *)&one, 4, NULL, NULL);
5849869SCasper.Dik@Sun.COM }
5859869SCasper.Dik@Sun.COM
5869869SCasper.Dik@Sun.COM /*
5879869SCasper.Dik@Sun.COM * This function returns the length of the string including exactly
5889869SCasper.Dik@Sun.COM * nf fields.
5899869SCasper.Dik@Sun.COM */
5909869SCasper.Dik@Sun.COM static ptrdiff_t
fieldoff(char * info,int nf)5919869SCasper.Dik@Sun.COM fieldoff(char *info, int nf)
5929869SCasper.Dik@Sun.COM {
5939869SCasper.Dik@Sun.COM char *q = info;
5949869SCasper.Dik@Sun.COM
5959869SCasper.Dik@Sun.COM while (nf > 0) {
5969869SCasper.Dik@Sun.COM if (IS_ST0[(unsigned char)*q++]) {
5979869SCasper.Dik@Sun.COM if (q[-1] == 0)
5989869SCasper.Dik@Sun.COM break;
5999869SCasper.Dik@Sun.COM nf--;
6009869SCasper.Dik@Sun.COM }
6019869SCasper.Dik@Sun.COM }
6029869SCasper.Dik@Sun.COM return (q - info - 1);
6039869SCasper.Dik@Sun.COM }
6049869SCasper.Dik@Sun.COM
6059869SCasper.Dik@Sun.COM /*
6069869SCasper.Dik@Sun.COM * The buf points into list of \n delimited lines. We copy it,
6079869SCasper.Dik@Sun.COM * removing the newline and adding a \0.
6089869SCasper.Dik@Sun.COM */
6099869SCasper.Dik@Sun.COM static char *
mystrcpy(char * buf,int len)6109869SCasper.Dik@Sun.COM mystrcpy(char *buf, int len)
6119869SCasper.Dik@Sun.COM {
6129869SCasper.Dik@Sun.COM char *res = umem_alloc(len, UMEM_NOFAIL);
6139869SCasper.Dik@Sun.COM
6149869SCasper.Dik@Sun.COM (void) memcpy(res, buf, len - 1);
6159869SCasper.Dik@Sun.COM res[len - 1] = '\0';
6169869SCasper.Dik@Sun.COM return (res);
6179869SCasper.Dik@Sun.COM }
6189869SCasper.Dik@Sun.COM
6199869SCasper.Dik@Sun.COM /*
6209869SCasper.Dik@Sun.COM * Entry: a single line without the NEWLINE
6219869SCasper.Dik@Sun.COM * Return: the package entry with the path determined.
6229869SCasper.Dik@Sun.COM */
6239869SCasper.Dik@Sun.COM static pkgentry_t *
parse_line(char * buf,int blen,boolean_t full)6249869SCasper.Dik@Sun.COM parse_line(char *buf, int blen, boolean_t full)
6259869SCasper.Dik@Sun.COM {
6269869SCasper.Dik@Sun.COM char *t;
6279869SCasper.Dik@Sun.COM pkgentry_t *p;
6289869SCasper.Dik@Sun.COM int nfields;
6299869SCasper.Dik@Sun.COM
6309869SCasper.Dik@Sun.COM p = umem_cache_alloc(ecache, UMEM_NOFAIL);
6319869SCasper.Dik@Sun.COM buf = p->line = mystrcpy(buf, blen + 1);
6329869SCasper.Dik@Sun.COM p->len = blen + 1;
6339869SCasper.Dik@Sun.COM
6349869SCasper.Dik@Sun.COM t = buf;
6359869SCasper.Dik@Sun.COM
6369869SCasper.Dik@Sun.COM while (!IS_ST0Q[(unsigned char)*t++])
6379869SCasper.Dik@Sun.COM ;
6389869SCasper.Dik@Sun.COM
6399869SCasper.Dik@Sun.COM p->pathlen = t - buf - 1;
6409869SCasper.Dik@Sun.COM if (p->pathlen == 0 || p->pathlen >= PATH_MAX) {
6419869SCasper.Dik@Sun.COM progerr("bad entry read in contents file");
6429869SCasper.Dik@Sun.COM logerr("pathname: Unknown");
6439869SCasper.Dik@Sun.COM logerr("problem: unable to read pathname field");
6449869SCasper.Dik@Sun.COM if (one_shot)
6459869SCasper.Dik@Sun.COM exit(2);
6469869SCasper.Dik@Sun.COM }
6479869SCasper.Dik@Sun.COM if (t[-1] == '=')
6489869SCasper.Dik@Sun.COM while (!IS_ST0[(unsigned char)*t++])
6499869SCasper.Dik@Sun.COM ;
6509869SCasper.Dik@Sun.COM
6519869SCasper.Dik@Sun.COM /* Partial as found in the "-" entries for log */
6529869SCasper.Dik@Sun.COM if (t[-1] == '\0') {
6539869SCasper.Dik@Sun.COM if (full)
6549869SCasper.Dik@Sun.COM goto badline;
6559869SCasper.Dik@Sun.COM
6569869SCasper.Dik@Sun.COM p->pkgoff = -1;
6579869SCasper.Dik@Sun.COM return (p);
6589869SCasper.Dik@Sun.COM }
6599869SCasper.Dik@Sun.COM
6609869SCasper.Dik@Sun.COM switch (*t) {
6619869SCasper.Dik@Sun.COM case '?':
6629869SCasper.Dik@Sun.COM nfields = 0;
6639869SCasper.Dik@Sun.COM break;
6649869SCasper.Dik@Sun.COM case 's':
6659869SCasper.Dik@Sun.COM case 'l':
6669869SCasper.Dik@Sun.COM /* Fields: class */
6679869SCasper.Dik@Sun.COM nfields = 1;
6689869SCasper.Dik@Sun.COM break;
6699869SCasper.Dik@Sun.COM case 'p':
6709869SCasper.Dik@Sun.COM case 'x':
6719869SCasper.Dik@Sun.COM case 'd':
6729869SCasper.Dik@Sun.COM /* class mode owner group */
6739869SCasper.Dik@Sun.COM nfields = 4;
6749869SCasper.Dik@Sun.COM break;
6759869SCasper.Dik@Sun.COM case 'f':
6769869SCasper.Dik@Sun.COM case 'e':
6779869SCasper.Dik@Sun.COM case 'v':
6789869SCasper.Dik@Sun.COM /* class mode owner group size csum time */
6799869SCasper.Dik@Sun.COM nfields = 7;
6809869SCasper.Dik@Sun.COM break;
6819869SCasper.Dik@Sun.COM case 'c':
6829869SCasper.Dik@Sun.COM case 'b':
6839869SCasper.Dik@Sun.COM /* class major minor mode owner group */
6849869SCasper.Dik@Sun.COM nfields = 6;
6859869SCasper.Dik@Sun.COM break;
6869869SCasper.Dik@Sun.COM default:
6879869SCasper.Dik@Sun.COM progerr("bad entry read in contents file");
6889869SCasper.Dik@Sun.COM logerr("pathname: %.*s", p->pathlen, p->line);
6899869SCasper.Dik@Sun.COM logerr("problem: unknown ftype");
6909869SCasper.Dik@Sun.COM freeentry(p);
6919869SCasper.Dik@Sun.COM if (one_shot)
6929869SCasper.Dik@Sun.COM exit(2);
6939869SCasper.Dik@Sun.COM return (NULL);
6949869SCasper.Dik@Sun.COM }
6959869SCasper.Dik@Sun.COM
6969869SCasper.Dik@Sun.COM p->pkgoff = t + fieldoff(t, nfields + 1) - buf;
6979869SCasper.Dik@Sun.COM
6989869SCasper.Dik@Sun.COM if (p->line[p->pkgoff] != '\0' || p->pkgoff == p->len - 1)
6999869SCasper.Dik@Sun.COM return (p);
7009869SCasper.Dik@Sun.COM
7019869SCasper.Dik@Sun.COM badline:
7029869SCasper.Dik@Sun.COM progerr(gettext("bad entry read in contents file"));
7039869SCasper.Dik@Sun.COM logerr(gettext("pathname: Unknown"));
7049869SCasper.Dik@Sun.COM logerr(gettext("problem: unknown ftype"));
7059869SCasper.Dik@Sun.COM freeentry(p);
7069869SCasper.Dik@Sun.COM if (one_shot)
7079869SCasper.Dik@Sun.COM exit(2);
7089869SCasper.Dik@Sun.COM return (NULL);
7099869SCasper.Dik@Sun.COM }
7109869SCasper.Dik@Sun.COM
7119869SCasper.Dik@Sun.COM static void
handle_comments(char * buf,int len)7129869SCasper.Dik@Sun.COM handle_comments(char *buf, int len)
7139869SCasper.Dik@Sun.COM {
7149869SCasper.Dik@Sun.COM if (cind >= 2)
7159869SCasper.Dik@Sun.COM return;
7169869SCasper.Dik@Sun.COM
7179869SCasper.Dik@Sun.COM if (buf[0] != '#')
7189869SCasper.Dik@Sun.COM return;
7199869SCasper.Dik@Sun.COM
7209869SCasper.Dik@Sun.COM if (ccmnt[cind] != NULL)
7219869SCasper.Dik@Sun.COM umem_free(ccmnt[cind], strlen(ccmnt[cind]) + 1);
7229869SCasper.Dik@Sun.COM ccmnt[cind] = mystrcpy(buf, len);
7239869SCasper.Dik@Sun.COM cind++;
7249869SCasper.Dik@Sun.COM }
7259869SCasper.Dik@Sun.COM
7269869SCasper.Dik@Sun.COM static void
parse_contents(void)7279869SCasper.Dik@Sun.COM parse_contents(void)
7289869SCasper.Dik@Sun.COM {
7299869SCasper.Dik@Sun.COM int cnt;
7309869SCasper.Dik@Sun.COM pkgentry_t *ent, *e2;
7319869SCasper.Dik@Sun.COM avl_index_t where;
7329869SCasper.Dik@Sun.COM int num = 0;
7339869SCasper.Dik@Sun.COM struct stat stb;
7349869SCasper.Dik@Sun.COM ptrdiff_t off;
7359869SCasper.Dik@Sun.COM char *p, *q, *map;
7369869SCasper.Dik@Sun.COM pkgentry_t *lastentry = NULL;
7379869SCasper.Dik@Sun.COM int d;
7389869SCasper.Dik@Sun.COM int cntserrs = 0;
7399869SCasper.Dik@Sun.COM
7409869SCasper.Dik@Sun.COM cnt = open(CONTENTS, O_RDONLY);
7419869SCasper.Dik@Sun.COM
7429869SCasper.Dik@Sun.COM cind = 0;
7439869SCasper.Dik@Sun.COM
7449869SCasper.Dik@Sun.COM if (cnt == -1) {
7459869SCasper.Dik@Sun.COM if (errno == ENOENT)
7469869SCasper.Dik@Sun.COM return;
7479869SCasper.Dik@Sun.COM exit(99);
7489869SCasper.Dik@Sun.COM }
7499869SCasper.Dik@Sun.COM
7509869SCasper.Dik@Sun.COM if (fstat(cnt, &stb) != 0) {
7519869SCasper.Dik@Sun.COM (void) close(cnt);
7529869SCasper.Dik@Sun.COM exit(99);
7539869SCasper.Dik@Sun.COM }
7549869SCasper.Dik@Sun.COM if (stb.st_size == 0) {
7559869SCasper.Dik@Sun.COM (void) close(cnt);
7569869SCasper.Dik@Sun.COM return;
7579869SCasper.Dik@Sun.COM }
7589869SCasper.Dik@Sun.COM
7599869SCasper.Dik@Sun.COM map = mmap(0, stb.st_size, PROT_READ, MAP_PRIVATE, cnt, 0);
7609869SCasper.Dik@Sun.COM (void) close(cnt);
7619869SCasper.Dik@Sun.COM if (map == (char *)-1)
7629869SCasper.Dik@Sun.COM return;
7639869SCasper.Dik@Sun.COM
7649869SCasper.Dik@Sun.COM (void) madvise(map, stb.st_size, MADV_WILLNEED);
7659869SCasper.Dik@Sun.COM
7669869SCasper.Dik@Sun.COM for (off = 0; off < stb.st_size; off += q - p) {
7679869SCasper.Dik@Sun.COM p = map + off;
7689869SCasper.Dik@Sun.COM q = memchr(p, '\n', stb.st_size - off);
7699869SCasper.Dik@Sun.COM if (q == NULL)
7709869SCasper.Dik@Sun.COM break;
7719869SCasper.Dik@Sun.COM
7729869SCasper.Dik@Sun.COM q++;
7739869SCasper.Dik@Sun.COM num++;
7749869SCasper.Dik@Sun.COM if (p[0] == '#' || p[0] == '\n') {
7759869SCasper.Dik@Sun.COM handle_comments(p, q - p);
7769869SCasper.Dik@Sun.COM continue;
7779869SCasper.Dik@Sun.COM }
7789869SCasper.Dik@Sun.COM ent = parse_line(p, q - p - 1, B_TRUE);
7799869SCasper.Dik@Sun.COM
7809869SCasper.Dik@Sun.COM if (ent == NULL) {
7819869SCasper.Dik@Sun.COM cntserrs++;
7829869SCasper.Dik@Sun.COM continue;
7839869SCasper.Dik@Sun.COM }
7849869SCasper.Dik@Sun.COM
7859869SCasper.Dik@Sun.COM /*
7869869SCasper.Dik@Sun.COM * We save time by assuming the database is sorted; by
7879869SCasper.Dik@Sun.COM * using avl_insert_here(), building the tree is nearly free.
7889869SCasper.Dik@Sun.COM * lastentry always contains the last entry in the AVL tree.
7899869SCasper.Dik@Sun.COM */
7909869SCasper.Dik@Sun.COM if (lastentry == NULL) {
7919869SCasper.Dik@Sun.COM avl_add(list, ent);
7929869SCasper.Dik@Sun.COM lastentry = ent;
7939869SCasper.Dik@Sun.COM } else if ((d = avlcmp(ent, lastentry)) == 1) {
7949869SCasper.Dik@Sun.COM avl_insert_here(list, ent, lastentry, AVL_AFTER);
7959869SCasper.Dik@Sun.COM lastentry = ent;
7969869SCasper.Dik@Sun.COM } else if (d == 0 ||
7979869SCasper.Dik@Sun.COM (e2 = avl_find(list, ent, &where)) != NULL) {
7989869SCasper.Dik@Sun.COM /*
7999869SCasper.Dik@Sun.COM * This can only happen if the contents file is bad;
8009869SCasper.Dik@Sun.COM * this can, e.g., happen with the old SQL contents DB,
8019869SCasper.Dik@Sun.COM * it didn't sort properly. Assume the first one
8029869SCasper.Dik@Sun.COM * is the correct one, but who knows?
8039869SCasper.Dik@Sun.COM */
8049869SCasper.Dik@Sun.COM if (d == 0)
8059869SCasper.Dik@Sun.COM e2 = lastentry;
8069869SCasper.Dik@Sun.COM if (strcmp(ent->line, e2->line) != 0) {
8079869SCasper.Dik@Sun.COM progerr(gettext("two entries for %.*s"),
8089869SCasper.Dik@Sun.COM ent->pathlen, ent->line);
8099869SCasper.Dik@Sun.COM cntserrs++;
8109869SCasper.Dik@Sun.COM }
8119869SCasper.Dik@Sun.COM freeentry(ent);
8129869SCasper.Dik@Sun.COM } else {
8139869SCasper.Dik@Sun.COM /* Out of order: not an error for us, really. */
8149869SCasper.Dik@Sun.COM progerr(gettext("bad read of contents file"));
8159869SCasper.Dik@Sun.COM logerr(gettext("pathname: Unknown"));
8169869SCasper.Dik@Sun.COM logerr(gettext(
8179869SCasper.Dik@Sun.COM "problem: unable to read pathname field"));
8189869SCasper.Dik@Sun.COM if (one_shot)
8199869SCasper.Dik@Sun.COM exit(2);
8209869SCasper.Dik@Sun.COM avl_insert(list, ent, where);
8219869SCasper.Dik@Sun.COM }
8229869SCasper.Dik@Sun.COM }
8239869SCasper.Dik@Sun.COM
8249869SCasper.Dik@Sun.COM cind = 0;
8259869SCasper.Dik@Sun.COM
8269869SCasper.Dik@Sun.COM (void) munmap(map, stb.st_size);
8279869SCasper.Dik@Sun.COM
8289869SCasper.Dik@Sun.COM /* By default, we ignore bad lines, keep them in a copy. */
8299869SCasper.Dik@Sun.COM if (cntserrs > 0 && stb.st_nlink == 1) {
8309869SCasper.Dik@Sun.COM char bcf[sizeof (BADCONTENTS)];
8319869SCasper.Dik@Sun.COM
8329869SCasper.Dik@Sun.COM (void) strcpy(bcf, BADCONTENTS);
8339869SCasper.Dik@Sun.COM if (mktemp(bcf) != NULL) {
8349869SCasper.Dik@Sun.COM (void) link(CONTENTS, bcf);
8359869SCasper.Dik@Sun.COM syslog(LOG_WARNING, "A bad contents file was saved: %s",
8369869SCasper.Dik@Sun.COM bcf);
8379869SCasper.Dik@Sun.COM }
8389869SCasper.Dik@Sun.COM }
8399869SCasper.Dik@Sun.COM }
8409869SCasper.Dik@Sun.COM
8419869SCasper.Dik@Sun.COM static int
parse_log(void)8429869SCasper.Dik@Sun.COM parse_log(void)
8439869SCasper.Dik@Sun.COM {
8449869SCasper.Dik@Sun.COM pkgentry_t *ent, *look;
8459869SCasper.Dik@Sun.COM avl_index_t where;
8469869SCasper.Dik@Sun.COM int num = 0;
8479869SCasper.Dik@Sun.COM int logfd;
8489869SCasper.Dik@Sun.COM struct stat stb;
8499869SCasper.Dik@Sun.COM int mlen = strlen(marker);
8509869SCasper.Dik@Sun.COM off_t realend;
8519869SCasper.Dik@Sun.COM ptrdiff_t off;
8529869SCasper.Dik@Sun.COM char *p, *q, *map;
8539869SCasper.Dik@Sun.COM
8549869SCasper.Dik@Sun.COM logfd = open(PKGLOG, O_RDONLY);
8559869SCasper.Dik@Sun.COM
8569869SCasper.Dik@Sun.COM if (logfd < 0) {
8579869SCasper.Dik@Sun.COM if (errno == ENOENT)
8589869SCasper.Dik@Sun.COM return (0);
8599869SCasper.Dik@Sun.COM progerr(gettext("cannot read "PKGLOG": %s"), strerror(errno));
8609869SCasper.Dik@Sun.COM exit(2);
8619869SCasper.Dik@Sun.COM }
8629869SCasper.Dik@Sun.COM
8639869SCasper.Dik@Sun.COM if (fstat(logfd, &stb) != 0) {
8649869SCasper.Dik@Sun.COM progerr(gettext("cannot stat "PKGLOG": %s"), strerror(errno));
8659869SCasper.Dik@Sun.COM exit(2);
8669869SCasper.Dik@Sun.COM }
8679869SCasper.Dik@Sun.COM
8689869SCasper.Dik@Sun.COM if (stb.st_size == 0) {
8699869SCasper.Dik@Sun.COM (void) close(logfd);
8709869SCasper.Dik@Sun.COM /* Force pkgdump && remove of the logfile. */
8719869SCasper.Dik@Sun.COM return (1);
8729869SCasper.Dik@Sun.COM }
8739869SCasper.Dik@Sun.COM
874*11770SCasper.Dik@Sun.COM map = mmap(0, stb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE,
8759869SCasper.Dik@Sun.COM logfd, 0);
8769869SCasper.Dik@Sun.COM (void) close(logfd);
8779869SCasper.Dik@Sun.COM if (map == (char *)-1) {
8789869SCasper.Dik@Sun.COM progerr(gettext("Cannot mmap the "PKGLOG": %s"),
8799869SCasper.Dik@Sun.COM strerror(errno));
8809869SCasper.Dik@Sun.COM exit(2);
8819869SCasper.Dik@Sun.COM }
8829869SCasper.Dik@Sun.COM
8839869SCasper.Dik@Sun.COM cind = 0;
8849869SCasper.Dik@Sun.COM
8859869SCasper.Dik@Sun.COM realend = stb.st_size;
8869869SCasper.Dik@Sun.COM
8879869SCasper.Dik@Sun.COM if (memcmp(map + realend - mlen, marker, mlen) != 0) {
8889869SCasper.Dik@Sun.COM progerr(gettext(PKGLOG" is not complete"));
8899869SCasper.Dik@Sun.COM
890*11770SCasper.Dik@Sun.COM map[stb.st_size - 1] = '\0'; /* for strstr() */
8919869SCasper.Dik@Sun.COM realend = 0;
8929869SCasper.Dik@Sun.COM for (p = map; q = strstr(p, marker); ) {
8939869SCasper.Dik@Sun.COM if (q == map || q[-1] == '\n')
8949869SCasper.Dik@Sun.COM realend = q - map + mlen;
8959869SCasper.Dik@Sun.COM p = q + mlen;
8969869SCasper.Dik@Sun.COM }
8979869SCasper.Dik@Sun.COM progerr(gettext("Ignoring %ld bytes from log"),
8989869SCasper.Dik@Sun.COM (long)(stb.st_size - realend));
8999869SCasper.Dik@Sun.COM }
9009869SCasper.Dik@Sun.COM
9019869SCasper.Dik@Sun.COM for (off = 0; off < realend; off += q - p) {
9029869SCasper.Dik@Sun.COM p = map + off;
9039869SCasper.Dik@Sun.COM q = memchr(p, '\n', realend - off);
9049869SCasper.Dik@Sun.COM if (q == NULL)
9059869SCasper.Dik@Sun.COM break;
9069869SCasper.Dik@Sun.COM
9079869SCasper.Dik@Sun.COM q++;
9089869SCasper.Dik@Sun.COM num++;
9099869SCasper.Dik@Sun.COM if (p[0] == '#' || p[0] == '\n') {
9109869SCasper.Dik@Sun.COM if (memcmp(marker, p, mlen) == 0)
9119869SCasper.Dik@Sun.COM cind = 0;
9129869SCasper.Dik@Sun.COM else
9139869SCasper.Dik@Sun.COM handle_comments(p, q - p);
9149869SCasper.Dik@Sun.COM continue;
9159869SCasper.Dik@Sun.COM }
9169869SCasper.Dik@Sun.COM
9179869SCasper.Dik@Sun.COM ent = parse_line(p + 1, q - (p + 1) - 1, p[0] != '-');
9189869SCasper.Dik@Sun.COM if (ent == NULL)
9199869SCasper.Dik@Sun.COM continue;
9209869SCasper.Dik@Sun.COM look = avl_find(list, ent, &where);
9219869SCasper.Dik@Sun.COM /*
9229869SCasper.Dik@Sun.COM * The log can be replayed; so any value of "look" is
9239869SCasper.Dik@Sun.COM * not unexpected.
9249869SCasper.Dik@Sun.COM */
9259869SCasper.Dik@Sun.COM switch (p[0]) {
9269869SCasper.Dik@Sun.COM case '+':
9279869SCasper.Dik@Sun.COM case '=':
9289869SCasper.Dik@Sun.COM if (look != NULL)
9299869SCasper.Dik@Sun.COM swapentry(look, ent);
9309869SCasper.Dik@Sun.COM else
9319869SCasper.Dik@Sun.COM avl_insert(list, ent, where);
9329869SCasper.Dik@Sun.COM break;
9339869SCasper.Dik@Sun.COM case '-':
9349869SCasper.Dik@Sun.COM if (look != NULL) {
9359869SCasper.Dik@Sun.COM avl_remove(list, look);
9369869SCasper.Dik@Sun.COM freeentry(look);
9379869SCasper.Dik@Sun.COM }
9389869SCasper.Dik@Sun.COM freeentry(ent);
9399869SCasper.Dik@Sun.COM break;
9409869SCasper.Dik@Sun.COM default:
9419869SCasper.Dik@Sun.COM freeentry(ent);
9429869SCasper.Dik@Sun.COM progerr(gettext("log %d: bad line"), num);
9439869SCasper.Dik@Sun.COM break;
9449869SCasper.Dik@Sun.COM }
9459869SCasper.Dik@Sun.COM }
9469869SCasper.Dik@Sun.COM (void) munmap(map, stb.st_size);
9479869SCasper.Dik@Sun.COM
9489869SCasper.Dik@Sun.COM /* Force pkgdump && remove of the logfile if there are no valid mods. */
9499869SCasper.Dik@Sun.COM return (num == 0 ? 1 : num);
9509869SCasper.Dik@Sun.COM }
9519869SCasper.Dik@Sun.COM
9529869SCasper.Dik@Sun.COM static char *
file_find(pkgfilter_t * cmd,int * len)9539869SCasper.Dik@Sun.COM file_find(pkgfilter_t *cmd, int *len)
9549869SCasper.Dik@Sun.COM {
9559869SCasper.Dik@Sun.COM pkgentry_t p;
9569869SCasper.Dik@Sun.COM pkgentry_t *look;
9579869SCasper.Dik@Sun.COM
9589869SCasper.Dik@Sun.COM p.line = cmd->buf;
9599869SCasper.Dik@Sun.COM p.pathlen = cmd->len;
9609869SCasper.Dik@Sun.COM
9619869SCasper.Dik@Sun.COM look = avl_find(list, &p, NULL);
9629869SCasper.Dik@Sun.COM
9639869SCasper.Dik@Sun.COM if (look == NULL)
9649869SCasper.Dik@Sun.COM return (NULL);
9659869SCasper.Dik@Sun.COM
9669869SCasper.Dik@Sun.COM *len = look->len;
9679869SCasper.Dik@Sun.COM return (look->line);
9689869SCasper.Dik@Sun.COM }
9699869SCasper.Dik@Sun.COM
9709869SCasper.Dik@Sun.COM static void
pkgdump(void)9719869SCasper.Dik@Sun.COM pkgdump(void)
9729869SCasper.Dik@Sun.COM {
9739869SCasper.Dik@Sun.COM FILE *cnts;
9749869SCasper.Dik@Sun.COM int err = 0;
9759869SCasper.Dik@Sun.COM pkgentry_t *p;
9769869SCasper.Dik@Sun.COM
9779869SCasper.Dik@Sun.COM if (read_only)
9789869SCasper.Dik@Sun.COM return;
9799869SCasper.Dik@Sun.COM
9809869SCasper.Dik@Sun.COM /* We cannot dump when the current transaction is not complete. */
9819869SCasper.Dik@Sun.COM if (sync_needed)
9829869SCasper.Dik@Sun.COM return;
9839869SCasper.Dik@Sun.COM
9849869SCasper.Dik@Sun.COM cnts = fopen(TCONTENTS, "w");
9859869SCasper.Dik@Sun.COM
9869869SCasper.Dik@Sun.COM if (cnts == NULL)
9879869SCasper.Dik@Sun.COM exit(99);
9889869SCasper.Dik@Sun.COM
9899869SCasper.Dik@Sun.COM for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) {
9909869SCasper.Dik@Sun.COM if (fprintf(cnts, "%s\n", p->line) < 0)
9919869SCasper.Dik@Sun.COM err++;
9929869SCasper.Dik@Sun.COM }
9939869SCasper.Dik@Sun.COM
9949869SCasper.Dik@Sun.COM if (ccmnt[0] != NULL)
9959869SCasper.Dik@Sun.COM (void) fprintf(cnts, "%s\n", ccmnt[0]);
9969869SCasper.Dik@Sun.COM if (ccmnt[1] != NULL)
9979869SCasper.Dik@Sun.COM (void) fprintf(cnts, "%s\n", ccmnt[1]);
9989869SCasper.Dik@Sun.COM
9999869SCasper.Dik@Sun.COM if (err != 0 || fflush(cnts) == EOF || fsync(fileno(cnts)) != 0 ||
10009869SCasper.Dik@Sun.COM fclose(cnts) == EOF || rename(TCONTENTS, CONTENTS) != 0) {
10019869SCasper.Dik@Sun.COM err++;
10029869SCasper.Dik@Sun.COM }
10039869SCasper.Dik@Sun.COM
10049869SCasper.Dik@Sun.COM if (err != 0) {
10059869SCasper.Dik@Sun.COM progerr("cannot rewrite the contents file");
10069869SCasper.Dik@Sun.COM exit(2);
10079869SCasper.Dik@Sun.COM }
10089869SCasper.Dik@Sun.COM
10099869SCasper.Dik@Sun.COM (void) fclose(log);
10109869SCasper.Dik@Sun.COM (void) unlink(PKGLOG);
10119869SCasper.Dik@Sun.COM log = NULL;
10129869SCasper.Dik@Sun.COM ndumps++;
10139869SCasper.Dik@Sun.COM logcount = 0;
10149869SCasper.Dik@Sun.COM }
10159869SCasper.Dik@Sun.COM
10169869SCasper.Dik@Sun.COM static void
freeentry(pkgentry_t * p)10179869SCasper.Dik@Sun.COM freeentry(pkgentry_t *p)
10189869SCasper.Dik@Sun.COM {
10199869SCasper.Dik@Sun.COM umem_free(p->line, p->len);
10209869SCasper.Dik@Sun.COM umem_cache_free(ecache, p);
10219869SCasper.Dik@Sun.COM }
10229869SCasper.Dik@Sun.COM
10239869SCasper.Dik@Sun.COM static void
swapentry(pkgentry_t * cur,pkgentry_t * new)10249869SCasper.Dik@Sun.COM swapentry(pkgentry_t *cur, pkgentry_t *new)
10259869SCasper.Dik@Sun.COM {
10269869SCasper.Dik@Sun.COM if (cur->len == new->len &&
10279869SCasper.Dik@Sun.COM strcmp(cur->line + cur->pathlen,
10289869SCasper.Dik@Sun.COM new->line + new->pathlen) == 0) {
10299869SCasper.Dik@Sun.COM suppressed++;
10309869SCasper.Dik@Sun.COM freeentry(new);
10319869SCasper.Dik@Sun.COM return;
10329869SCasper.Dik@Sun.COM }
10339869SCasper.Dik@Sun.COM
10349869SCasper.Dik@Sun.COM /* Free old line */
10359869SCasper.Dik@Sun.COM umem_free(cur->line, cur->len);
10369869SCasper.Dik@Sun.COM
10379869SCasper.Dik@Sun.COM /* Copy new value: pathlen is the same and avl is kept */
10389869SCasper.Dik@Sun.COM cur->line = new->line;
10399869SCasper.Dik@Sun.COM cur->len = new->len;
10409869SCasper.Dik@Sun.COM cur->pkgoff = new->pkgoff;
10419869SCasper.Dik@Sun.COM
10429869SCasper.Dik@Sun.COM umem_cache_free(ecache, new);
10439869SCasper.Dik@Sun.COM }
10449869SCasper.Dik@Sun.COM
10459869SCasper.Dik@Sun.COM static int
logentry(char type,pkgentry_t * p)10469869SCasper.Dik@Sun.COM logentry(char type, pkgentry_t *p)
10479869SCasper.Dik@Sun.COM {
10489869SCasper.Dik@Sun.COM int len;
10499869SCasper.Dik@Sun.COM
10509869SCasper.Dik@Sun.COM if (type == '-')
10519869SCasper.Dik@Sun.COM len = fprintf(log, "-%.*s\n", p->pathlen, p->line);
10529869SCasper.Dik@Sun.COM else
10539869SCasper.Dik@Sun.COM len = fprintf(log, "%c%s\n", type, p->line);
10549869SCasper.Dik@Sun.COM
10559869SCasper.Dik@Sun.COM loglines++;
10569869SCasper.Dik@Sun.COM if (len < 0) {
10579869SCasper.Dik@Sun.COM logerrcnt++;
10589869SCasper.Dik@Sun.COM return (-1);
10599869SCasper.Dik@Sun.COM }
10609869SCasper.Dik@Sun.COM logcount += len;
10619869SCasper.Dik@Sun.COM return (0);
10629869SCasper.Dik@Sun.COM }
10639869SCasper.Dik@Sun.COM
10649869SCasper.Dik@Sun.COM static int
logflush(void)10659869SCasper.Dik@Sun.COM logflush(void)
10669869SCasper.Dik@Sun.COM {
10679869SCasper.Dik@Sun.COM int len;
10689869SCasper.Dik@Sun.COM static int lastflush;
10699869SCasper.Dik@Sun.COM
10709869SCasper.Dik@Sun.COM if (log == NULL)
10719869SCasper.Dik@Sun.COM return (0);
10729869SCasper.Dik@Sun.COM
10739869SCasper.Dik@Sun.COM if (lastflush == logcount)
10749869SCasper.Dik@Sun.COM return (0);
10759869SCasper.Dik@Sun.COM
10769869SCasper.Dik@Sun.COM if (cind == 2) {
10779869SCasper.Dik@Sun.COM (void) fprintf(log, "%s\n", ccmnt[0]);
10789869SCasper.Dik@Sun.COM (void) fprintf(log, "%s\n", ccmnt[1]);
10799869SCasper.Dik@Sun.COM cind = 0;
10809869SCasper.Dik@Sun.COM }
10819869SCasper.Dik@Sun.COM
10829869SCasper.Dik@Sun.COM /*
10839869SCasper.Dik@Sun.COM * When using zfs, if the mark is there, then so is the rest before
10849869SCasper.Dik@Sun.COM * it. But with ufs, we need to flush twice.
10859869SCasper.Dik@Sun.COM */
10869869SCasper.Dik@Sun.COM if (flushbeforemark) {
10879869SCasper.Dik@Sun.COM if (fflush(log) == EOF)
10889869SCasper.Dik@Sun.COM logerrcnt++;
10899869SCasper.Dik@Sun.COM }
10909869SCasper.Dik@Sun.COM /* Anything before the last marker found in the log will be valid */
10919869SCasper.Dik@Sun.COM len = fprintf(log, "%s", marker);
10929869SCasper.Dik@Sun.COM if (len < 0)
10939869SCasper.Dik@Sun.COM logerrcnt++;
10949869SCasper.Dik@Sun.COM else
10959869SCasper.Dik@Sun.COM logcount += len;
10969869SCasper.Dik@Sun.COM
10979869SCasper.Dik@Sun.COM if (fflush(log) == EOF)
10989869SCasper.Dik@Sun.COM logerrcnt++;
10999869SCasper.Dik@Sun.COM
11009869SCasper.Dik@Sun.COM sync_needed = B_FALSE;
11019869SCasper.Dik@Sun.COM
11029869SCasper.Dik@Sun.COM if (logerrcnt > 0 || logcount > MAXLOGFILESIZE)
11039869SCasper.Dik@Sun.COM pkgdump();
11049869SCasper.Dik@Sun.COM
11059869SCasper.Dik@Sun.COM if (logerrcnt > 0)
11069869SCasper.Dik@Sun.COM return (-1);
11079869SCasper.Dik@Sun.COM
11089869SCasper.Dik@Sun.COM lastflush = logcount;
11099869SCasper.Dik@Sun.COM
11109869SCasper.Dik@Sun.COM return (0);
11119869SCasper.Dik@Sun.COM }
11129869SCasper.Dik@Sun.COM
11139869SCasper.Dik@Sun.COM static int
avlcmp(const void * ca,const void * cb)11149869SCasper.Dik@Sun.COM avlcmp(const void *ca, const void *cb)
11159869SCasper.Dik@Sun.COM {
11169869SCasper.Dik@Sun.COM const pkgentry_t *a = ca;
11179869SCasper.Dik@Sun.COM const pkgentry_t *b = cb;
11189869SCasper.Dik@Sun.COM int i = memcmp(a->line, b->line,
11199869SCasper.Dik@Sun.COM a->pathlen > b->pathlen ? b->pathlen : a->pathlen);
11209869SCasper.Dik@Sun.COM
11219869SCasper.Dik@Sun.COM if (i < 0)
11229869SCasper.Dik@Sun.COM return (-1);
11239869SCasper.Dik@Sun.COM else if (i > 0)
11249869SCasper.Dik@Sun.COM return (1);
11259869SCasper.Dik@Sun.COM else if (a->pathlen == b->pathlen)
11269869SCasper.Dik@Sun.COM return (0);
11279869SCasper.Dik@Sun.COM else if (a->pathlen > b->pathlen)
11289869SCasper.Dik@Sun.COM return (1);
11299869SCasper.Dik@Sun.COM else
11309869SCasper.Dik@Sun.COM return (-1);
11319869SCasper.Dik@Sun.COM }
11329869SCasper.Dik@Sun.COM
11339869SCasper.Dik@Sun.COM /*
11349869SCasper.Dik@Sun.COM * Returns:
11359869SCasper.Dik@Sun.COM * 0 - if we can get the lock
11369869SCasper.Dik@Sun.COM * -1 - we can't lock
11379869SCasper.Dik@Sun.COM */
11389869SCasper.Dik@Sun.COM
11399869SCasper.Dik@Sun.COM static int
establish_lock(char * lock)11409869SCasper.Dik@Sun.COM establish_lock(char *lock)
11419869SCasper.Dik@Sun.COM {
11429869SCasper.Dik@Sun.COM int fd = open(lock, O_RDWR|O_CREAT, 0644);
11439869SCasper.Dik@Sun.COM int i;
11449869SCasper.Dik@Sun.COM
11459869SCasper.Dik@Sun.COM if (fd < 0)
11469869SCasper.Dik@Sun.COM return (-1);
11479869SCasper.Dik@Sun.COM
11489869SCasper.Dik@Sun.COM for (i = 0; i < 5; i++) {
11499869SCasper.Dik@Sun.COM if (lockf(fd, F_TLOCK, 0) == 0)
11509869SCasper.Dik@Sun.COM return (0);
11519869SCasper.Dik@Sun.COM (void) sleep(1);
11529869SCasper.Dik@Sun.COM }
11539869SCasper.Dik@Sun.COM
11549869SCasper.Dik@Sun.COM (void) close(fd);
11559869SCasper.Dik@Sun.COM return (-1);
11569869SCasper.Dik@Sun.COM }
11579869SCasper.Dik@Sun.COM
11589869SCasper.Dik@Sun.COM static int
no_memory_abort(void)11599869SCasper.Dik@Sun.COM no_memory_abort(void)
11609869SCasper.Dik@Sun.COM {
11619869SCasper.Dik@Sun.COM return (UMEM_CALLBACK_EXIT(99));
11629869SCasper.Dik@Sun.COM }
11639869SCasper.Dik@Sun.COM
11649869SCasper.Dik@Sun.COM /*
11659869SCasper.Dik@Sun.COM * Dump a part of the contents file in a pipe; grep for the "filter".
11669869SCasper.Dik@Sun.COM * It doesn't matter if we return too much.
11679869SCasper.Dik@Sun.COM */
11689869SCasper.Dik@Sun.COM
11699869SCasper.Dik@Sun.COM static void *
thr_pkgfilter(void * v)11709869SCasper.Dik@Sun.COM thr_pkgfilter(void *v)
11719869SCasper.Dik@Sun.COM {
11729869SCasper.Dik@Sun.COM pkgfilter_t *pf = v;
11739869SCasper.Dik@Sun.COM pkgentry_t *p;
11749869SCasper.Dik@Sun.COM int nums[2];
11759869SCasper.Dik@Sun.COM FILE *cnts;
11769869SCasper.Dik@Sun.COM
11779869SCasper.Dik@Sun.COM cnts = fdopen(pf->cmd, "w");
11789869SCasper.Dik@Sun.COM if (cnts == NULL)
11799869SCasper.Dik@Sun.COM goto free;
11809869SCasper.Dik@Sun.COM
1181*11770SCasper.Dik@Sun.COM /*
1182*11770SCasper.Dik@Sun.COM * Remove wild card: don't care about extra matches; make sure
1183*11770SCasper.Dik@Sun.COM * we remove both the "*" and the "." in front of it.
1184*11770SCasper.Dik@Sun.COM */
11859869SCasper.Dik@Sun.COM if (pf->len > 0) {
11869869SCasper.Dik@Sun.COM char *p;
11879869SCasper.Dik@Sun.COM
11889869SCasper.Dik@Sun.COM for (p = pf->buf; *p; p++) {
11899869SCasper.Dik@Sun.COM if (*p == '*') {
11909869SCasper.Dik@Sun.COM *p = 0;
1191*11770SCasper.Dik@Sun.COM if (p > pf->buf && p[-1] == '.')
1192*11770SCasper.Dik@Sun.COM p[-1] = 0;
11939869SCasper.Dik@Sun.COM break;
11949869SCasper.Dik@Sun.COM }
11959869SCasper.Dik@Sun.COM }
11969869SCasper.Dik@Sun.COM }
11979869SCasper.Dik@Sun.COM
11989869SCasper.Dik@Sun.COM /* Disable modifications while the filter is running */
11999869SCasper.Dik@Sun.COM (void) mutex_lock(&mtx);
12009869SCasper.Dik@Sun.COM write_locked++;
12019869SCasper.Dik@Sun.COM (void) mutex_unlock(&mtx);
12029869SCasper.Dik@Sun.COM /*
12039869SCasper.Dik@Sun.COM * The protocol for the contents file for the clients:
12049869SCasper.Dik@Sun.COM * <int:len><int:pathlen><line + 0>
12059869SCasper.Dik@Sun.COM */
12069869SCasper.Dik@Sun.COM
12079869SCasper.Dik@Sun.COM for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) {
12089869SCasper.Dik@Sun.COM if (pf->len > 0 && strstr(p->line, pf->buf) == NULL)
12099869SCasper.Dik@Sun.COM continue;
12109869SCasper.Dik@Sun.COM
12119869SCasper.Dik@Sun.COM nums[0] = p->len;
12129869SCasper.Dik@Sun.COM nums[1] = p->pathlen;
12139869SCasper.Dik@Sun.COM if (fwrite(nums, sizeof (int), 2, cnts) != 2)
12149869SCasper.Dik@Sun.COM break;
12159869SCasper.Dik@Sun.COM if (fwrite(p->line, 1, p->len, cnts) != p->len)
12169869SCasper.Dik@Sun.COM break;
12179869SCasper.Dik@Sun.COM }
12189869SCasper.Dik@Sun.COM
12199869SCasper.Dik@Sun.COM (void) mutex_lock(&mtx);
12209869SCasper.Dik@Sun.COM lastcall = gethrtime();
12219869SCasper.Dik@Sun.COM write_locked--;
12229869SCasper.Dik@Sun.COM (void) cond_broadcast(&cv);
12239869SCasper.Dik@Sun.COM (void) mutex_unlock(&mtx);
12249869SCasper.Dik@Sun.COM (void) fclose(cnts);
12259869SCasper.Dik@Sun.COM
12269869SCasper.Dik@Sun.COM free:
12279869SCasper.Dik@Sun.COM umem_free(pf, sizeof (pkgfilter_t) + pf->len);
12289869SCasper.Dik@Sun.COM return (NULL);
12299869SCasper.Dik@Sun.COM }
12309869SCasper.Dik@Sun.COM
12319869SCasper.Dik@Sun.COM static hrtime_t
time_since_(hrtime_t last)12329869SCasper.Dik@Sun.COM time_since_(hrtime_t last)
12339869SCasper.Dik@Sun.COM {
12349869SCasper.Dik@Sun.COM return (gethrtime() - last);
12359869SCasper.Dik@Sun.COM }
12369869SCasper.Dik@Sun.COM
12379869SCasper.Dik@Sun.COM static void
my_cond_reltimedwait(hrtime_t delta,int sec)12389869SCasper.Dik@Sun.COM my_cond_reltimedwait(hrtime_t delta, int sec)
12399869SCasper.Dik@Sun.COM {
12409869SCasper.Dik@Sun.COM hrtime_t wait = sec * LLNANOSEC - delta;
12419869SCasper.Dik@Sun.COM timestruc_t waitfor;
12429869SCasper.Dik@Sun.COM
12439869SCasper.Dik@Sun.COM waitfor.tv_nsec = wait % LLNANOSEC;
12449869SCasper.Dik@Sun.COM waitfor.tv_sec = wait / LLNANOSEC;
12459869SCasper.Dik@Sun.COM (void) cond_reltimedwait(&cv, &mtx, &waitfor);
12469869SCasper.Dik@Sun.COM }
12479869SCasper.Dik@Sun.COM
12489869SCasper.Dik@Sun.COM static int
pkgfilter(pkgfilter_t * pf,door_desc_t * dp)12499869SCasper.Dik@Sun.COM pkgfilter(pkgfilter_t *pf, door_desc_t *dp)
12509869SCasper.Dik@Sun.COM {
12519869SCasper.Dik@Sun.COM
12529869SCasper.Dik@Sun.COM int p[2];
12539869SCasper.Dik@Sun.COM thread_t tid;
12549869SCasper.Dik@Sun.COM pkgfilter_t *cpf;
12559869SCasper.Dik@Sun.COM
12569869SCasper.Dik@Sun.COM if (pipe(p) != 0)
12579869SCasper.Dik@Sun.COM return (-1);
12589869SCasper.Dik@Sun.COM
12599869SCasper.Dik@Sun.COM cpf = umem_alloc(sizeof (pkgfilter_t) + pf->len, UMEM_NOFAIL);
12609869SCasper.Dik@Sun.COM
12619869SCasper.Dik@Sun.COM (void) memcpy(cpf, pf, sizeof (pkgfilter_t) + pf->len);
12629869SCasper.Dik@Sun.COM
12639869SCasper.Dik@Sun.COM /* Copy the file descriptor in the command field */
12649869SCasper.Dik@Sun.COM cpf->cmd = p[1];
12659869SCasper.Dik@Sun.COM
12669869SCasper.Dik@Sun.COM if (thr_create(NULL, NULL, thr_pkgfilter, cpf, THR_DETACHED,
12679869SCasper.Dik@Sun.COM &tid) != 0) {
12689869SCasper.Dik@Sun.COM (void) close(p[0]);
12699869SCasper.Dik@Sun.COM (void) close(p[1]);
12709869SCasper.Dik@Sun.COM umem_free(cpf, sizeof (pkgfilter_t) + pf->len);
12719869SCasper.Dik@Sun.COM return (-1);
12729869SCasper.Dik@Sun.COM }
12739869SCasper.Dik@Sun.COM (void) memset(dp, 0, sizeof (*dp));
12749869SCasper.Dik@Sun.COM dp->d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
12759869SCasper.Dik@Sun.COM dp->d_data.d_desc.d_descriptor = p[0];
12769869SCasper.Dik@Sun.COM
12779869SCasper.Dik@Sun.COM return (0);
12789869SCasper.Dik@Sun.COM }
12799869SCasper.Dik@Sun.COM
12809869SCasper.Dik@Sun.COM static int
pkgaddlines(pkgfilter_t * pf)12819869SCasper.Dik@Sun.COM pkgaddlines(pkgfilter_t *pf)
12829869SCasper.Dik@Sun.COM {
12839869SCasper.Dik@Sun.COM char *map = pf->buf;
12849869SCasper.Dik@Sun.COM int len = pf->len;
12859869SCasper.Dik@Sun.COM int off;
12869869SCasper.Dik@Sun.COM pkgentry_t *ent, *look;
12879869SCasper.Dik@Sun.COM avl_index_t where;
12889869SCasper.Dik@Sun.COM char *q, *p;
12899869SCasper.Dik@Sun.COM char c;
12909869SCasper.Dik@Sun.COM int r = 0;
12919869SCasper.Dik@Sun.COM
12929869SCasper.Dik@Sun.COM if (log == NULL) {
12939869SCasper.Dik@Sun.COM log = fopen(PKGLOG, "w");
12949869SCasper.Dik@Sun.COM if (log == NULL)
12959869SCasper.Dik@Sun.COM return (-1);
12969869SCasper.Dik@Sun.COM }
12979869SCasper.Dik@Sun.COM
12989869SCasper.Dik@Sun.COM for (off = 0; off < len; off += q - p) {
12999869SCasper.Dik@Sun.COM p = map + off;
13009869SCasper.Dik@Sun.COM q = memchr(p, '\n', len - off);
13019869SCasper.Dik@Sun.COM
13029869SCasper.Dik@Sun.COM if (q == NULL)
13039869SCasper.Dik@Sun.COM break;
13049869SCasper.Dik@Sun.COM
13059869SCasper.Dik@Sun.COM q++;
13069869SCasper.Dik@Sun.COM
13079869SCasper.Dik@Sun.COM if (p[0] == '#' || p[0] == '\n') {
13089869SCasper.Dik@Sun.COM handle_comments(p, q - p);
13099869SCasper.Dik@Sun.COM continue;
13109869SCasper.Dik@Sun.COM }
13119869SCasper.Dik@Sun.COM
13129869SCasper.Dik@Sun.COM if (*p == '-')
13139869SCasper.Dik@Sun.COM ent = parse_line(p + 1, q - (p + 1) - 1, B_FALSE);
13149869SCasper.Dik@Sun.COM else
13159869SCasper.Dik@Sun.COM ent = parse_line(p, q - p - 1, B_TRUE);
13169869SCasper.Dik@Sun.COM
13179869SCasper.Dik@Sun.COM if (ent == NULL) {
13189869SCasper.Dik@Sun.COM r++;
13199869SCasper.Dik@Sun.COM continue;
13209869SCasper.Dik@Sun.COM }
13219869SCasper.Dik@Sun.COM
13229869SCasper.Dik@Sun.COM look = avl_find(list, ent, &where);
13239869SCasper.Dik@Sun.COM if (look != NULL) {
13249869SCasper.Dik@Sun.COM c = *p == '-' ? '-' : '=';
13259869SCasper.Dik@Sun.COM if (c == '=') {
13269869SCasper.Dik@Sun.COM swapentry(look, ent);
13279869SCasper.Dik@Sun.COM ent = look;
13289869SCasper.Dik@Sun.COM } else {
13299869SCasper.Dik@Sun.COM avl_remove(list, look);
13309869SCasper.Dik@Sun.COM freeentry(look);
13319869SCasper.Dik@Sun.COM }
13329869SCasper.Dik@Sun.COM } else if (*p == '-') {
13339869SCasper.Dik@Sun.COM /* Remove something which isn't there: no-op */
13349869SCasper.Dik@Sun.COM freeentry(ent);
13359869SCasper.Dik@Sun.COM continue;
13369869SCasper.Dik@Sun.COM } else {
13379869SCasper.Dik@Sun.COM avl_insert(list, ent, where);
13389869SCasper.Dik@Sun.COM c = '+';
13399869SCasper.Dik@Sun.COM }
13409869SCasper.Dik@Sun.COM
13419869SCasper.Dik@Sun.COM sync_needed = B_TRUE;
13429869SCasper.Dik@Sun.COM r += logentry(c, ent);
13439869SCasper.Dik@Sun.COM if (c == '-')
13449869SCasper.Dik@Sun.COM freeentry(ent);
13459869SCasper.Dik@Sun.COM }
13469869SCasper.Dik@Sun.COM
13479869SCasper.Dik@Sun.COM return (r);
13489869SCasper.Dik@Sun.COM }
13499869SCasper.Dik@Sun.COM
13509869SCasper.Dik@Sun.COM static void
finish(void)13519869SCasper.Dik@Sun.COM finish(void)
13529869SCasper.Dik@Sun.COM {
13539869SCasper.Dik@Sun.COM if (verbose) {
13549869SCasper.Dik@Sun.COM syslog(LOG_DEBUG,
13559869SCasper.Dik@Sun.COM "finished: calls %d, pkgdumps %d, loglines %d "
13569869SCasper.Dik@Sun.COM "(suppressed %d)\n",
13579869SCasper.Dik@Sun.COM ncalls, ndumps, loglines, suppressed);
13589869SCasper.Dik@Sun.COM }
13599869SCasper.Dik@Sun.COM (void) fdetach(door);
13609869SCasper.Dik@Sun.COM if (read_only)
13619869SCasper.Dik@Sun.COM (void) unlink(door);
13629869SCasper.Dik@Sun.COM }
13639869SCasper.Dik@Sun.COM
13649869SCasper.Dik@Sun.COM /*
13659869SCasper.Dik@Sun.COM * Tell the wait thread to wake up and quit.
13669869SCasper.Dik@Sun.COM */
13679869SCasper.Dik@Sun.COM /* ARGSUSED */
13689869SCasper.Dik@Sun.COM static void
signal_handler(int sig)13699869SCasper.Dik@Sun.COM signal_handler(int sig)
13709869SCasper.Dik@Sun.COM {
13719869SCasper.Dik@Sun.COM if (read_only)
13729869SCasper.Dik@Sun.COM exit(0);
13739869SCasper.Dik@Sun.COM want_to_quit = 1;
13749869SCasper.Dik@Sun.COM (void) cond_broadcast(&cv);
13759869SCasper.Dik@Sun.COM }
1376