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 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 42062224350SCasper H.S. Dik nothing(int sig) 42162224350SCasper H.S. Dik { 42262224350SCasper H.S. Dik } 42362224350SCasper H.S. Dik 42462224350SCasper H.S. Dik int 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 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 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 * 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 * 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 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 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 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 * 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 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 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 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 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 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 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 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 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 * 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 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 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 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 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 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 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