1*62224350SCasper H.S. Dik /* 2*62224350SCasper H.S. Dik * CDDL HEADER START 3*62224350SCasper H.S. Dik * 4*62224350SCasper H.S. Dik * The contents of this file are subject to the terms of the 5*62224350SCasper H.S. Dik * Common Development and Distribution License (the "License"). 6*62224350SCasper H.S. Dik * You may not use this file except in compliance with the License. 7*62224350SCasper H.S. Dik * 8*62224350SCasper H.S. Dik * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*62224350SCasper H.S. Dik * or http://www.opensolaris.org/os/licensing. 10*62224350SCasper H.S. Dik * See the License for the specific language governing permissions 11*62224350SCasper H.S. Dik * and limitations under the License. 12*62224350SCasper H.S. Dik * 13*62224350SCasper H.S. Dik * When distributing Covered Code, include this CDDL HEADER in each 14*62224350SCasper H.S. Dik * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*62224350SCasper H.S. Dik * If applicable, add the following below this CDDL HEADER, with the 16*62224350SCasper H.S. Dik * fields enclosed by brackets "[]" replaced with your own identifying 17*62224350SCasper H.S. Dik * information: Portions Copyright [yyyy] [name of copyright owner] 18*62224350SCasper H.S. Dik * 19*62224350SCasper H.S. Dik * CDDL HEADER END 20*62224350SCasper H.S. Dik */ 21*62224350SCasper H.S. Dik 22*62224350SCasper H.S. Dik /* 23*62224350SCasper H.S. Dik * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24*62224350SCasper H.S. Dik * Use is subject to license terms. 25*62224350SCasper H.S. Dik */ 26*62224350SCasper H.S. Dik 27*62224350SCasper H.S. Dik /* 28*62224350SCasper H.S. Dik * The Solaris package installer in-memory database server. 29*62224350SCasper H.S. Dik * 30*62224350SCasper H.S. Dik * We'll keep the contents file as before; but we cache it 31*62224350SCasper H.S. Dik * and we don't write it as often. Instead, we log all 32*62224350SCasper H.S. Dik * modifications to the log file. 33*62224350SCasper H.S. Dik * Using the contents file and the logfile, the pkgserv can 34*62224350SCasper H.S. Dik * rebuild the up-to-date contents file. 35*62224350SCasper H.S. Dik * The logfile is constructed so that rebuilding the 36*62224350SCasper H.S. Dik * contents file with the logfile is idempotent. 37*62224350SCasper H.S. Dik * 38*62224350SCasper H.S. Dik * The libpkg will start the daemon. 39*62224350SCasper H.S. Dik * 40*62224350SCasper H.S. Dik * The pkgserv will daemonize itself; the parent process 41*62224350SCasper H.S. Dik * waits until the child process has initialized and will 42*62224350SCasper H.S. Dik * start the door server. 43*62224350SCasper H.S. Dik * If any error occurs during start-up, the error messages 44*62224350SCasper H.S. Dik * are printed to stderr and the daemon will exit. 45*62224350SCasper H.S. Dik * After start-up, any further errors are logged to syslog. 46*62224350SCasper H.S. Dik * The parent pkgserv will exit with: 47*62224350SCasper H.S. Dik * 0 - We've started 48*62224350SCasper H.S. Dik * 1 - We couldn't start (locked) 49*62224350SCasper H.S. Dik * 2 - Other problems (error on stderr) 50*62224350SCasper H.S. Dik * 99 - Nothing reported; the caller must report. 51*62224350SCasper H.S. Dik * 52*62224350SCasper H.S. Dik * The daemon will timeout, by default. It will write the 53*62224350SCasper H.S. Dik * contents file after a first timeout; and after a further 54*62224350SCasper H.S. Dik * timeout, the daemon will exit. 55*62224350SCasper H.S. Dik * 56*62224350SCasper H.S. Dik * The daemon will only timeout if the current "client" has exited; 57*62224350SCasper H.S. Dik * to this end, we always look at the pid of the last caller. 58*62224350SCasper H.S. Dik * If the last client is no longer around, we record the new client. 59*62224350SCasper H.S. Dik * In the typical case of running installf/removef from a post/preinstall 60*62224350SCasper H.S. Dik * script, we continue to follow the pkginstall/pkgremove client's pid. 61*62224350SCasper H.S. Dik * 62*62224350SCasper H.S. Dik * In the particular case of install, we make sure the daemon 63*62224350SCasper H.S. Dik * sticks around. (Install == install, (live)upgrade, zone install) 64*62224350SCasper H.S. Dik */ 65*62224350SCasper H.S. Dik 66*62224350SCasper H.S. Dik #ifdef lint 67*62224350SCasper H.S. Dik #undef _FILE_OFFSET_BITS 68*62224350SCasper H.S. Dik #endif 69*62224350SCasper H.S. Dik 70*62224350SCasper H.S. Dik #include <door.h> 71*62224350SCasper H.S. Dik #include <errno.h> 72*62224350SCasper H.S. Dik #include <fcntl.h> 73*62224350SCasper H.S. Dik #include <limits.h> 74*62224350SCasper H.S. Dik #include <pthread.h> 75*62224350SCasper H.S. Dik #include <signal.h> 76*62224350SCasper H.S. Dik #include <stddef.h> 77*62224350SCasper H.S. Dik #include <stdio.h> 78*62224350SCasper H.S. Dik #include <stdlib.h> 79*62224350SCasper H.S. Dik #include <strings.h> 80*62224350SCasper H.S. Dik #include <synch.h> 81*62224350SCasper H.S. Dik #include <sys/avl.h> 82*62224350SCasper H.S. Dik #include <sys/stat.h> 83*62224350SCasper H.S. Dik #include <sys/statvfs.h> 84*62224350SCasper H.S. Dik #include <sys/mman.h> 85*62224350SCasper H.S. Dik #include <sys/time.h> 86*62224350SCasper H.S. Dik #include <sys/wait.h> 87*62224350SCasper H.S. Dik #include <syslog.h> 88*62224350SCasper H.S. Dik #include <limits.h> 89*62224350SCasper H.S. Dik #include <thread.h> 90*62224350SCasper H.S. Dik #include <ucred.h> 91*62224350SCasper H.S. Dik #include <umem.h> 92*62224350SCasper H.S. Dik #include <unistd.h> 93*62224350SCasper H.S. Dik #include <libintl.h> 94*62224350SCasper H.S. Dik #include <locale.h> 95*62224350SCasper H.S. Dik 96*62224350SCasper H.S. Dik #include <pkglib.h> 97*62224350SCasper H.S. Dik 98*62224350SCasper H.S. Dik #define SADM_DIR "/var/sadm/install" 99*62224350SCasper H.S. Dik 100*62224350SCasper H.S. Dik #define LOCK ".pkg.lock" 101*62224350SCasper H.S. Dik #define CLIENTLOCK ".pkg.lock.client" 102*62224350SCasper H.S. Dik #define CONTENTS "contents" 103*62224350SCasper H.S. Dik #define TCONTENTS "t.contents" 104*62224350SCasper H.S. Dik #define BADCONTENTS "contents.badXXXXXX" 105*62224350SCasper H.S. Dik 106*62224350SCasper H.S. Dik #define LLNANOSEC ((int64_t)NANOSEC) 107*62224350SCasper H.S. Dik 108*62224350SCasper H.S. Dik #define DUMPTIMEOUT 60 109*62224350SCasper H.S. Dik #define EXITTIMEOUT 300 110*62224350SCasper H.S. Dik 111*62224350SCasper H.S. Dik /* 112*62224350SCasper H.S. Dik * Contents file storage format. At install time, the amount of memory 113*62224350SCasper H.S. Dik * might be limited, so we make sure that we use as little memory 114*62224350SCasper H.S. Dik * as possible. The package tools modify the entries; so we install the 115*62224350SCasper H.S. Dik * single lines. We also remember the length of the path; this is needed 116*62224350SCasper H.S. Dik * for avlcmp and we return it to the tools. This saves time. 117*62224350SCasper H.S. Dik * 118*62224350SCasper H.S. Dik * All strings are allocated using umem_alloc. 119*62224350SCasper H.S. Dik */ 120*62224350SCasper H.S. Dik typedef struct pkgentry { 121*62224350SCasper H.S. Dik char *line; /* The contents line for the file */ 122*62224350SCasper H.S. Dik avl_node_t avl; /* The avl header */ 123*62224350SCasper H.S. Dik int pkgoff; /* Where the packages live; start with SP */ 124*62224350SCasper H.S. Dik int pathlen; /* The length of the pathname */ 125*62224350SCasper H.S. Dik int len; /* Length of the line (incl NUL) */ 126*62224350SCasper H.S. Dik } pkgentry_t; 127*62224350SCasper H.S. Dik 128*62224350SCasper H.S. Dik static char IS_ST0[256]; 129*62224350SCasper H.S. Dik static char IS_ST0Q[256]; 130*62224350SCasper H.S. Dik 131*62224350SCasper H.S. Dik static void pkg_door_srv(void *, char *, size_t, door_desc_t *, uint_t); 132*62224350SCasper H.S. Dik static char *file_find(pkgfilter_t *, int *); 133*62224350SCasper H.S. Dik static void parse_contents(void); 134*62224350SCasper H.S. Dik static int parse_log(void); 135*62224350SCasper H.S. Dik static void pkgdump(void); 136*62224350SCasper H.S. Dik static int logflush(void); 137*62224350SCasper H.S. Dik static int avlcmp(const void *, const void *); 138*62224350SCasper H.S. Dik static void freeentry(pkgentry_t *); 139*62224350SCasper H.S. Dik static void swapentry(pkgentry_t *, pkgentry_t *); 140*62224350SCasper H.S. Dik static int establish_lock(char *); 141*62224350SCasper H.S. Dik static int no_memory_abort(void); 142*62224350SCasper H.S. Dik static int pkgfilter(pkgfilter_t *, door_desc_t *); 143*62224350SCasper H.S. Dik static int pkgaddlines(pkgfilter_t *); 144*62224350SCasper H.S. Dik static void finish(void); 145*62224350SCasper H.S. Dik static void signal_handler(int); 146*62224350SCasper H.S. Dik static void my_cond_reltimedwait(hrtime_t, int); 147*62224350SCasper H.S. Dik static hrtime_t time_since_(hrtime_t); 148*62224350SCasper H.S. Dik 149*62224350SCasper H.S. Dik /* 150*62224350SCasper H.S. Dik * Server actions 151*62224350SCasper H.S. Dik * - set mode (contents file, log file) 152*62224350SCasper H.S. Dik * - roll log 153*62224350SCasper H.S. Dik * - remove package 154*62224350SCasper H.S. Dik * - merge package entries 155*62224350SCasper H.S. Dik */ 156*62224350SCasper H.S. Dik 157*62224350SCasper H.S. Dik static FILE *log; 158*62224350SCasper H.S. Dik static char *door = PKGDOOR; 159*62224350SCasper H.S. Dik 160*62224350SCasper H.S. Dik static avl_tree_t listp, *list = &listp; 161*62224350SCasper H.S. Dik 162*62224350SCasper H.S. Dik /* Keep the "the last command modified the contents file ... */ 163*62224350SCasper H.S. Dik static char *ccmnt[2]; 164*62224350SCasper H.S. Dik static int cind = 0; 165*62224350SCasper H.S. Dik 166*62224350SCasper H.S. Dik static mutex_t mtx = DEFAULTMUTEX; 167*62224350SCasper H.S. Dik static cond_t cv = DEFAULTCV; 168*62224350SCasper H.S. Dik 169*62224350SCasper H.S. Dik static int flushbeforemark = 1; 170*62224350SCasper H.S. Dik static int logerrcnt = 0; 171*62224350SCasper H.S. Dik static int loglines = 0; 172*62224350SCasper H.S. Dik static int suppressed = 0; 173*62224350SCasper H.S. Dik static int logcount; 174*62224350SCasper H.S. Dik static int ndumps; 175*62224350SCasper H.S. Dik static int ncalls; 176*62224350SCasper H.S. Dik static int changes; 177*62224350SCasper H.S. Dik static hrtime_t lastchange; 178*62224350SCasper H.S. Dik static hrtime_t lastcall; 179*62224350SCasper H.S. Dik static volatile int want_to_quit; 180*62224350SCasper H.S. Dik static boolean_t read_only = B_FALSE; 181*62224350SCasper H.S. Dik static boolean_t permanent = B_FALSE; 182*62224350SCasper H.S. Dik static boolean_t one_shot = B_FALSE; 183*62224350SCasper H.S. Dik static int write_locked; 184*62224350SCasper H.S. Dik static pid_t client_pid; 185*62224350SCasper H.S. Dik static int verbose = 1; 186*62224350SCasper H.S. Dik static hrtime_t dumptimeout = DUMPTIMEOUT; 187*62224350SCasper H.S. Dik static boolean_t sync_needed = B_FALSE; 188*62224350SCasper H.S. Dik 189*62224350SCasper H.S. Dik static uid_t myuid; 190*62224350SCasper H.S. Dik 191*62224350SCasper H.S. Dik static char marker[] = "###Marker\n"; 192*62224350SCasper H.S. Dik 193*62224350SCasper H.S. Dik static umem_cache_t *ecache; 194*62224350SCasper H.S. Dik 195*62224350SCasper H.S. Dik static char pkgdir[PATH_MAX]; 196*62224350SCasper H.S. Dik 197*62224350SCasper H.S. Dik static void 198*62224350SCasper H.S. Dik server_main(int argc, char **argv) 199*62224350SCasper H.S. Dik { 200*62224350SCasper H.S. Dik int did; 201*62224350SCasper H.S. Dik int c; 202*62224350SCasper H.S. Dik struct statvfs vfsbuf; 203*62224350SCasper H.S. Dik int imexit = 0; 204*62224350SCasper H.S. Dik pid_t parent; 205*62224350SCasper H.S. Dik char *root = NULL; 206*62224350SCasper H.S. Dik char *sadmdir = NULL; 207*62224350SCasper H.S. Dik hrtime_t delta; 208*62224350SCasper H.S. Dik int dir = 0; 209*62224350SCasper H.S. Dik int dfd; 210*62224350SCasper H.S. Dik 211*62224350SCasper H.S. Dik (void) set_prog_name("pkgserv"); 212*62224350SCasper H.S. Dik 213*62224350SCasper H.S. Dik openlog("pkgserv", LOG_PID | LOG_ODELAY, LOG_DAEMON); 214*62224350SCasper H.S. Dik 215*62224350SCasper H.S. Dik while ((c = getopt(argc, argv, "d:eoN:pP:R:r:")) != EOF) { 216*62224350SCasper H.S. Dik switch (c) { 217*62224350SCasper H.S. Dik case 'e': 218*62224350SCasper H.S. Dik imexit = 1; 219*62224350SCasper H.S. Dik break; 220*62224350SCasper H.S. Dik case 'd': 221*62224350SCasper H.S. Dik sadmdir = optarg; 222*62224350SCasper H.S. Dik if (*sadmdir != '/' || strlen(sadmdir) >= PATH_MAX || 223*62224350SCasper H.S. Dik access(sadmdir, X_OK) != 0) 224*62224350SCasper H.S. Dik exit(99); 225*62224350SCasper H.S. Dik break; 226*62224350SCasper H.S. Dik case 'N': 227*62224350SCasper H.S. Dik (void) set_prog_name(optarg); 228*62224350SCasper H.S. Dik break; 229*62224350SCasper H.S. Dik case 'o': 230*62224350SCasper H.S. Dik one_shot = B_TRUE; 231*62224350SCasper H.S. Dik verbose = 0; 232*62224350SCasper H.S. Dik break; 233*62224350SCasper H.S. Dik case 'p': 234*62224350SCasper H.S. Dik /* 235*62224350SCasper H.S. Dik * We are updating possibly many zones; so we're not 236*62224350SCasper H.S. Dik * dumping based on a short timeout and we will not 237*62224350SCasper H.S. Dik * exit. 238*62224350SCasper H.S. Dik */ 239*62224350SCasper H.S. Dik permanent = B_TRUE; 240*62224350SCasper H.S. Dik dumptimeout = 3600; 241*62224350SCasper H.S. Dik break; 242*62224350SCasper H.S. Dik case 'P': 243*62224350SCasper H.S. Dik client_pid = atoi(optarg); 244*62224350SCasper H.S. Dik break; 245*62224350SCasper H.S. Dik case 'R': 246*62224350SCasper H.S. Dik root = optarg; 247*62224350SCasper H.S. Dik if (*root != '/' || strlen(root) >= PATH_MAX || 248*62224350SCasper H.S. Dik access(root, X_OK) != 0) 249*62224350SCasper H.S. Dik exit(99); 250*62224350SCasper H.S. Dik break; 251*62224350SCasper H.S. Dik case 'r': 252*62224350SCasper H.S. Dik read_only = B_TRUE; 253*62224350SCasper H.S. Dik one_shot = B_TRUE; 254*62224350SCasper H.S. Dik verbose = 0; 255*62224350SCasper H.S. Dik door = optarg; 256*62224350SCasper H.S. Dik break; 257*62224350SCasper H.S. Dik default: 258*62224350SCasper H.S. Dik exit(99); 259*62224350SCasper H.S. Dik } 260*62224350SCasper H.S. Dik } 261*62224350SCasper H.S. Dik 262*62224350SCasper H.S. Dik if (one_shot && permanent) { 263*62224350SCasper H.S. Dik progerr(gettext("Incorrect Usage")); 264*62224350SCasper H.S. Dik exit(99); 265*62224350SCasper H.S. Dik } 266*62224350SCasper H.S. Dik 267*62224350SCasper H.S. Dik umem_nofail_callback(no_memory_abort); 268*62224350SCasper H.S. Dik 269*62224350SCasper H.S. Dik if (root != NULL && strcmp(root, "/") != 0) { 270*62224350SCasper H.S. Dik if (snprintf(pkgdir, PATH_MAX, "%s%s", root, 271*62224350SCasper H.S. Dik sadmdir == NULL ? SADM_DIR : sadmdir) >= PATH_MAX) { 272*62224350SCasper H.S. Dik exit(99); 273*62224350SCasper H.S. Dik } 274*62224350SCasper H.S. Dik } else { 275*62224350SCasper H.S. Dik if (sadmdir == NULL) 276*62224350SCasper H.S. Dik (void) strcpy(pkgdir, SADM_DIR); 277*62224350SCasper H.S. Dik else 278*62224350SCasper H.S. Dik (void) strcpy(pkgdir, sadmdir); 279*62224350SCasper H.S. Dik } 280*62224350SCasper H.S. Dik 281*62224350SCasper H.S. Dik if (chdir(pkgdir) != 0) { 282*62224350SCasper H.S. Dik progerr(gettext("can't chdir to %s"), pkgdir); 283*62224350SCasper H.S. Dik exit(2); 284*62224350SCasper H.S. Dik } 285*62224350SCasper H.S. Dik 286*62224350SCasper H.S. Dik closefrom(3); 287*62224350SCasper H.S. Dik 288*62224350SCasper H.S. Dik if (!read_only && establish_lock(LOCK) < 0) { 289*62224350SCasper H.S. Dik progerr(gettext( 290*62224350SCasper H.S. Dik "couldn't lock in %s (server running?): %s"), 291*62224350SCasper H.S. Dik pkgdir, strerror(errno)); 292*62224350SCasper H.S. Dik exit(1); 293*62224350SCasper H.S. Dik } 294*62224350SCasper H.S. Dik 295*62224350SCasper H.S. Dik did = door_create(pkg_door_srv, 0, DOOR_REFUSE_DESC); 296*62224350SCasper H.S. Dik if (did == -1) { 297*62224350SCasper H.S. Dik progerr("door_create: %s", strerror(errno)); 298*62224350SCasper H.S. Dik exit(2); 299*62224350SCasper H.S. Dik } 300*62224350SCasper H.S. Dik 301*62224350SCasper H.S. Dik (void) fdetach(door); 302*62224350SCasper H.S. Dik 303*62224350SCasper H.S. Dik if ((dfd = creat(door, 0644)) < 0 || close(dfd) < 0) { 304*62224350SCasper H.S. Dik progerr("door_create: %s", strerror(errno)); 305*62224350SCasper H.S. Dik exit(2); 306*62224350SCasper H.S. Dik } 307*62224350SCasper H.S. Dik 308*62224350SCasper H.S. Dik (void) mutex_lock(&mtx); 309*62224350SCasper H.S. Dik 310*62224350SCasper H.S. Dik myuid = geteuid(); 311*62224350SCasper H.S. Dik 312*62224350SCasper H.S. Dik (void) sigset(SIGHUP, signal_handler); 313*62224350SCasper H.S. Dik (void) sigset(SIGTERM, signal_handler); 314*62224350SCasper H.S. Dik (void) sigset(SIGINT, signal_handler); 315*62224350SCasper H.S. Dik (void) sigset(SIGQUIT, signal_handler); 316*62224350SCasper H.S. Dik 317*62224350SCasper H.S. Dik (void) signal(SIGPIPE, SIG_IGN); 318*62224350SCasper H.S. Dik 319*62224350SCasper H.S. Dik (void) atexit(finish); 320*62224350SCasper H.S. Dik 321*62224350SCasper H.S. Dik if (fattach(did, door) != 0) { 322*62224350SCasper H.S. Dik progerr(gettext("attach door: %s"), strerror(errno)); 323*62224350SCasper H.S. Dik exit(2); 324*62224350SCasper H.S. Dik } 325*62224350SCasper H.S. Dik (void) close(did); 326*62224350SCasper H.S. Dik 327*62224350SCasper H.S. Dik ecache = umem_cache_create("entry", sizeof (pkgentry_t), 328*62224350SCasper H.S. Dik sizeof (char *), NULL, NULL, NULL, NULL, NULL, 0); 329*62224350SCasper H.S. Dik 330*62224350SCasper H.S. Dik avl_create(list, avlcmp, sizeof (pkgentry_t), 331*62224350SCasper H.S. Dik offsetof(pkgentry_t, avl)); 332*62224350SCasper H.S. Dik 333*62224350SCasper H.S. Dik IS_ST0['\0'] = 1; 334*62224350SCasper H.S. Dik IS_ST0[' '] = 1; 335*62224350SCasper H.S. Dik IS_ST0['\t'] = 1; 336*62224350SCasper H.S. Dik 337*62224350SCasper H.S. Dik IS_ST0Q['\0'] = 1; 338*62224350SCasper H.S. Dik IS_ST0Q[' '] = 1; 339*62224350SCasper H.S. Dik IS_ST0Q['\t'] = 1; 340*62224350SCasper H.S. Dik IS_ST0Q['='] = 1; 341*62224350SCasper H.S. Dik 342*62224350SCasper H.S. Dik parse_contents(); 343*62224350SCasper H.S. Dik if (parse_log() > 0) 344*62224350SCasper H.S. Dik pkgdump(); 345*62224350SCasper H.S. Dik 346*62224350SCasper H.S. Dik if (imexit) 347*62224350SCasper H.S. Dik exit(0); 348*62224350SCasper H.S. Dik 349*62224350SCasper H.S. Dik if (statvfs(".", &vfsbuf) != 0) { 350*62224350SCasper H.S. Dik progerr(gettext("statvfs: %s"), strerror(errno)); 351*62224350SCasper H.S. Dik exit(2); 352*62224350SCasper H.S. Dik } 353*62224350SCasper H.S. Dik 354*62224350SCasper H.S. Dik if (strcmp(vfsbuf.f_basetype, "zfs") == 0) 355*62224350SCasper H.S. Dik flushbeforemark = 0; 356*62224350SCasper H.S. Dik 357*62224350SCasper H.S. Dik /* We've started, tell the parent */ 358*62224350SCasper H.S. Dik parent = getppid(); 359*62224350SCasper H.S. Dik if (parent != 1) 360*62224350SCasper H.S. Dik (void) kill(parent, SIGUSR1); 361*62224350SCasper H.S. Dik 362*62224350SCasper H.S. Dik if (!one_shot) { 363*62224350SCasper H.S. Dik int fd; 364*62224350SCasper H.S. Dik (void) setsid(); 365*62224350SCasper H.S. Dik fd = open("/dev/null", O_RDWR, 0); 366*62224350SCasper H.S. Dik if (fd >= 0) { 367*62224350SCasper H.S. Dik (void) dup2(fd, STDIN_FILENO); 368*62224350SCasper H.S. Dik (void) dup2(fd, STDOUT_FILENO); 369*62224350SCasper H.S. Dik (void) dup2(fd, STDERR_FILENO); 370*62224350SCasper H.S. Dik if (fd > 2) 371*62224350SCasper H.S. Dik (void) close(fd); 372*62224350SCasper H.S. Dik } 373*62224350SCasper H.S. Dik } 374*62224350SCasper H.S. Dik 375*62224350SCasper H.S. Dik lastcall = lastchange = gethrtime(); 376*62224350SCasper H.S. Dik 377*62224350SCasper H.S. Dik /* 378*62224350SCasper H.S. Dik * Start the main thread, here is where we unlock the mutex. 379*62224350SCasper H.S. Dik */ 380*62224350SCasper H.S. Dik for (;;) { 381*62224350SCasper H.S. Dik if (want_to_quit) { 382*62224350SCasper H.S. Dik pkgdump(); 383*62224350SCasper H.S. Dik exit(0); 384*62224350SCasper H.S. Dik } 385*62224350SCasper H.S. Dik /* Wait forever when root or when there's a running filter */ 386*62224350SCasper H.S. Dik if (write_locked || 387*62224350SCasper H.S. Dik (!one_shot && permanent && dir == changes)) { 388*62224350SCasper H.S. Dik (void) cond_wait(&cv, &mtx); 389*62224350SCasper H.S. Dik continue; 390*62224350SCasper H.S. Dik } 391*62224350SCasper H.S. Dik delta = time_since_(lastchange); 392*62224350SCasper H.S. Dik /* Wait until DUMPTIMEOUT after last change before we pkgdump */ 393*62224350SCasper H.S. Dik if (delta < dumptimeout * LLNANOSEC) { 394*62224350SCasper H.S. Dik my_cond_reltimedwait(delta, dumptimeout); 395*62224350SCasper H.S. Dik continue; 396*62224350SCasper H.S. Dik } 397*62224350SCasper H.S. Dik /* Client still around? Just wait then. */ 398*62224350SCasper H.S. Dik if (client_pid > 1 && kill(client_pid, 0) == 0) { 399*62224350SCasper H.S. Dik lastchange = lastcall = gethrtime(); 400*62224350SCasper H.S. Dik continue; 401*62224350SCasper H.S. Dik } 402*62224350SCasper H.S. Dik /* Wait for another EXITTIMEOUT seconds before we exit */ 403*62224350SCasper H.S. Dik if ((one_shot || !permanent) && dir == changes) { 404*62224350SCasper H.S. Dik delta = time_since_(lastcall); 405*62224350SCasper H.S. Dik if (delta < EXITTIMEOUT * LLNANOSEC) { 406*62224350SCasper H.S. Dik my_cond_reltimedwait(delta, EXITTIMEOUT); 407*62224350SCasper H.S. Dik continue; 408*62224350SCasper H.S. Dik } 409*62224350SCasper H.S. Dik exit(0); 410*62224350SCasper H.S. Dik } 411*62224350SCasper H.S. Dik pkgdump(); 412*62224350SCasper H.S. Dik dir = changes; 413*62224350SCasper H.S. Dik } 414*62224350SCasper H.S. Dik 415*62224350SCasper H.S. Dik /*NOTREACHED*/ 416*62224350SCasper H.S. Dik } 417*62224350SCasper H.S. Dik 418*62224350SCasper H.S. Dik /*ARGSUSED*/ 419*62224350SCasper H.S. Dik static void 420*62224350SCasper H.S. Dik nothing(int sig) 421*62224350SCasper H.S. Dik { 422*62224350SCasper H.S. Dik } 423*62224350SCasper H.S. Dik 424*62224350SCasper H.S. Dik int 425*62224350SCasper H.S. Dik main(int argc, char **argv) 426*62224350SCasper H.S. Dik { 427*62224350SCasper H.S. Dik int sig; 428*62224350SCasper H.S. Dik sigset_t sset; 429*62224350SCasper H.S. Dik int stat; 430*62224350SCasper H.S. Dik 431*62224350SCasper H.S. Dik /* 432*62224350SCasper H.S. Dik * We're starting the daemon; this process exits when the door 433*62224350SCasper H.S. Dik * server is established or when it fails to establish. 434*62224350SCasper H.S. Dik * We wait until the child process sends a SIGUSR1 or when it 435*62224350SCasper H.S. Dik * exits. 436*62224350SCasper H.S. Dik * We keep around who started us and as long as it lives, we don't 437*62224350SCasper H.S. Dik * exit. 438*62224350SCasper H.S. Dik */ 439*62224350SCasper H.S. Dik 440*62224350SCasper H.S. Dik (void) setlocale(LC_ALL, ""); 441*62224350SCasper H.S. Dik (void) textdomain(TEXT_DOMAIN); 442*62224350SCasper H.S. Dik 443*62224350SCasper H.S. Dik client_pid = getppid(); 444*62224350SCasper H.S. Dik 445*62224350SCasper H.S. Dik (void) sigemptyset(&sset); 446*62224350SCasper H.S. Dik (void) sigaddset(&sset, SIGUSR1); 447*62224350SCasper H.S. Dik (void) sigaddset(&sset, SIGCLD); 448*62224350SCasper H.S. Dik 449*62224350SCasper H.S. Dik /* We need to catch the SIGCLD before we can sigwait for it. */ 450*62224350SCasper H.S. Dik (void) sigset(SIGCLD, nothing); 451*62224350SCasper H.S. Dik /* We need to make sure that SIGUSR1 is not ignored. */ 452*62224350SCasper H.S. Dik (void) sigset(SIGUSR1, SIG_DFL); 453*62224350SCasper H.S. Dik (void) sigprocmask(SIG_BLOCK, &sset, NULL); 454*62224350SCasper H.S. Dik 455*62224350SCasper H.S. Dik /* We install the contents file readable. */ 456*62224350SCasper H.S. Dik (void) umask(022); 457*62224350SCasper H.S. Dik 458*62224350SCasper H.S. Dik switch (fork()) { 459*62224350SCasper H.S. Dik case -1: 460*62224350SCasper H.S. Dik exit(99); 461*62224350SCasper H.S. Dik /*NOTREACHED*/ 462*62224350SCasper H.S. Dik case 0: 463*62224350SCasper H.S. Dik server_main(argc, argv); 464*62224350SCasper H.S. Dik /*NOTREACHED*/ 465*62224350SCasper H.S. Dik default: 466*62224350SCasper H.S. Dik /* In the parent */ 467*62224350SCasper H.S. Dik break; 468*62224350SCasper H.S. Dik } 469*62224350SCasper H.S. Dik 470*62224350SCasper H.S. Dik for (;;) { 471*62224350SCasper H.S. Dik sig = sigwait(&sset); 472*62224350SCasper H.S. Dik 473*62224350SCasper H.S. Dik switch (sig) { 474*62224350SCasper H.S. Dik case SIGCLD: 475*62224350SCasper H.S. Dik if (wait(&stat) > 0) { 476*62224350SCasper H.S. Dik if (WIFEXITED(stat)) 477*62224350SCasper H.S. Dik _exit(WEXITSTATUS(stat)); 478*62224350SCasper H.S. Dik else if (WIFSIGNALED(stat)) 479*62224350SCasper H.S. Dik _exit(99); 480*62224350SCasper H.S. Dik } 481*62224350SCasper H.S. Dik break; 482*62224350SCasper H.S. Dik case SIGUSR1: 483*62224350SCasper H.S. Dik _exit(0); 484*62224350SCasper H.S. Dik } 485*62224350SCasper H.S. Dik } 486*62224350SCasper H.S. Dik } 487*62224350SCasper H.S. Dik 488*62224350SCasper H.S. Dik /*ARGSUSED*/ 489*62224350SCasper H.S. Dik static void 490*62224350SCasper H.S. Dik pkg_door_srv(void *cookie, char *argp, size_t asz, door_desc_t *dp, 491*62224350SCasper H.S. Dik uint_t ndesc) 492*62224350SCasper H.S. Dik { 493*62224350SCasper H.S. Dik char *p = NULL; 494*62224350SCasper H.S. Dik pkgcmd_t *pcmd = (pkgcmd_t *)argp; 495*62224350SCasper H.S. Dik ucred_t *uc = NULL; 496*62224350SCasper H.S. Dik uid_t caller; 497*62224350SCasper H.S. Dik pid_t pcaller; 498*62224350SCasper H.S. Dik door_desc_t ddp; 499*62224350SCasper H.S. Dik int dnum = 0; 500*62224350SCasper H.S. Dik int one = 1; 501*62224350SCasper H.S. Dik int len = -1; 502*62224350SCasper H.S. Dik 503*62224350SCasper H.S. Dik if (asz < sizeof (pkgcmd_t)) { 504*62224350SCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0); 505*62224350SCasper H.S. Dik return; 506*62224350SCasper H.S. Dik } 507*62224350SCasper H.S. Dik 508*62224350SCasper H.S. Dik if (door_ucred(&uc) != 0) { 509*62224350SCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0); 510*62224350SCasper H.S. Dik return; 511*62224350SCasper H.S. Dik } 512*62224350SCasper H.S. Dik 513*62224350SCasper H.S. Dik caller = ucred_geteuid(uc); 514*62224350SCasper H.S. Dik pcaller = ucred_getpid(uc); 515*62224350SCasper H.S. Dik ucred_free(uc); 516*62224350SCasper H.S. Dik 517*62224350SCasper H.S. Dik if (caller != myuid) { 518*62224350SCasper H.S. Dik (void) door_return(NULL, 0, NULL, 0); 519*62224350SCasper H.S. Dik return; 520*62224350SCasper H.S. Dik } 521*62224350SCasper H.S. Dik 522*62224350SCasper H.S. Dik (void) mutex_lock(&mtx); 523*62224350SCasper H.S. Dik ncalls++; 524*62224350SCasper H.S. Dik 525*62224350SCasper H.S. Dik if (pcaller != client_pid && pcaller != -1 && 526*62224350SCasper H.S. Dik (client_pid == 1 || kill(client_pid, 0) != 0)) { 527*62224350SCasper H.S. Dik client_pid = pcaller; 528*62224350SCasper H.S. Dik } 529*62224350SCasper H.S. Dik 530*62224350SCasper H.S. Dik if (PKG_WRITE_COMMAND(pcmd->cmd)) 531*62224350SCasper H.S. Dik while (write_locked > 0) 532*62224350SCasper H.S. Dik (void) cond_wait(&cv, &mtx); 533*62224350SCasper H.S. Dik 534*62224350SCasper H.S. Dik switch (pcmd->cmd) { 535*62224350SCasper H.S. Dik case PKG_FINDFILE: 536*62224350SCasper H.S. Dik p = file_find((pkgfilter_t *)argp, &len); 537*62224350SCasper H.S. Dik break; 538*62224350SCasper H.S. Dik case PKG_DUMP: 539*62224350SCasper H.S. Dik if (read_only) 540*62224350SCasper H.S. Dik goto err; 541*62224350SCasper H.S. Dik if (logcount > 0) 542*62224350SCasper H.S. Dik pkgdump(); 543*62224350SCasper H.S. Dik break; 544*62224350SCasper H.S. Dik case PKG_EXIT: 545*62224350SCasper H.S. Dik if (logcount > 0) 546*62224350SCasper H.S. Dik pkgdump(); 547*62224350SCasper H.S. Dik exit(0); 548*62224350SCasper H.S. Dik /*NOTREACHED*/ 549*62224350SCasper H.S. Dik case PKG_PKGSYNC: 550*62224350SCasper H.S. Dik if (read_only || logflush() != 0) 551*62224350SCasper H.S. Dik goto err; 552*62224350SCasper H.S. Dik break; 553*62224350SCasper H.S. Dik case PKG_FILTER: 554*62224350SCasper H.S. Dik if (pkgfilter((pkgfilter_t *)argp, &ddp) == 0) 555*62224350SCasper H.S. Dik dnum = 1; 556*62224350SCasper H.S. Dik break; 557*62224350SCasper H.S. Dik case PKG_ADDLINES: 558*62224350SCasper H.S. Dik if (read_only) 559*62224350SCasper H.S. Dik goto err; 560*62224350SCasper H.S. Dik changes++; 561*62224350SCasper H.S. Dik 562*62224350SCasper H.S. Dik if (pkgaddlines((pkgfilter_t *)argp) != 0) 563*62224350SCasper H.S. Dik goto err; 564*62224350SCasper H.S. Dik /* If we've updated the database, tell the dump thread */ 565*62224350SCasper H.S. Dik lastchange = gethrtime(); 566*62224350SCasper H.S. Dik (void) cond_broadcast(&cv); 567*62224350SCasper H.S. Dik break; 568*62224350SCasper H.S. Dik case PKG_NOP: 569*62224350SCasper H.S. Dik /* Do nothing but register the current client's pid. */ 570*62224350SCasper H.S. Dik break; 571*62224350SCasper H.S. Dik default: 572*62224350SCasper H.S. Dik goto err; 573*62224350SCasper H.S. Dik } 574*62224350SCasper H.S. Dik 575*62224350SCasper H.S. Dik lastcall = gethrtime(); 576*62224350SCasper H.S. Dik (void) mutex_unlock(&mtx); 577*62224350SCasper H.S. Dik (void) door_return(p, len != -1 ? len : p == NULL ? 0 : strlen(p) + 1, 578*62224350SCasper H.S. Dik dnum == 0 ? NULL : &ddp, dnum); 579*62224350SCasper H.S. Dik return; 580*62224350SCasper H.S. Dik 581*62224350SCasper H.S. Dik err: 582*62224350SCasper H.S. Dik (void) mutex_unlock(&mtx); 583*62224350SCasper H.S. Dik (void) door_return((void *)&one, 4, NULL, NULL); 584*62224350SCasper H.S. Dik } 585*62224350SCasper H.S. Dik 586*62224350SCasper H.S. Dik /* 587*62224350SCasper H.S. Dik * This function returns the length of the string including exactly 588*62224350SCasper H.S. Dik * nf fields. 589*62224350SCasper H.S. Dik */ 590*62224350SCasper H.S. Dik static ptrdiff_t 591*62224350SCasper H.S. Dik fieldoff(char *info, int nf) 592*62224350SCasper H.S. Dik { 593*62224350SCasper H.S. Dik char *q = info; 594*62224350SCasper H.S. Dik 595*62224350SCasper H.S. Dik while (nf > 0) { 596*62224350SCasper H.S. Dik if (IS_ST0[(unsigned char)*q++]) { 597*62224350SCasper H.S. Dik if (q[-1] == 0) 598*62224350SCasper H.S. Dik break; 599*62224350SCasper H.S. Dik nf--; 600*62224350SCasper H.S. Dik } 601*62224350SCasper H.S. Dik } 602*62224350SCasper H.S. Dik return (q - info - 1); 603*62224350SCasper H.S. Dik } 604*62224350SCasper H.S. Dik 605*62224350SCasper H.S. Dik /* 606*62224350SCasper H.S. Dik * The buf points into list of \n delimited lines. We copy it, 607*62224350SCasper H.S. Dik * removing the newline and adding a \0. 608*62224350SCasper H.S. Dik */ 609*62224350SCasper H.S. Dik static char * 610*62224350SCasper H.S. Dik mystrcpy(char *buf, int len) 611*62224350SCasper H.S. Dik { 612*62224350SCasper H.S. Dik char *res = umem_alloc(len, UMEM_NOFAIL); 613*62224350SCasper H.S. Dik 614*62224350SCasper H.S. Dik (void) memcpy(res, buf, len - 1); 615*62224350SCasper H.S. Dik res[len - 1] = '\0'; 616*62224350SCasper H.S. Dik return (res); 617*62224350SCasper H.S. Dik } 618*62224350SCasper H.S. Dik 619*62224350SCasper H.S. Dik /* 620*62224350SCasper H.S. Dik * Entry: a single line without the NEWLINE 621*62224350SCasper H.S. Dik * Return: the package entry with the path determined. 622*62224350SCasper H.S. Dik */ 623*62224350SCasper H.S. Dik static pkgentry_t * 624*62224350SCasper H.S. Dik parse_line(char *buf, int blen, boolean_t full) 625*62224350SCasper H.S. Dik { 626*62224350SCasper H.S. Dik char *t; 627*62224350SCasper H.S. Dik pkgentry_t *p; 628*62224350SCasper H.S. Dik int nfields; 629*62224350SCasper H.S. Dik 630*62224350SCasper H.S. Dik p = umem_cache_alloc(ecache, UMEM_NOFAIL); 631*62224350SCasper H.S. Dik buf = p->line = mystrcpy(buf, blen + 1); 632*62224350SCasper H.S. Dik p->len = blen + 1; 633*62224350SCasper H.S. Dik 634*62224350SCasper H.S. Dik t = buf; 635*62224350SCasper H.S. Dik 636*62224350SCasper H.S. Dik while (!IS_ST0Q[(unsigned char)*t++]) 637*62224350SCasper H.S. Dik ; 638*62224350SCasper H.S. Dik 639*62224350SCasper H.S. Dik p->pathlen = t - buf - 1; 640*62224350SCasper H.S. Dik if (p->pathlen == 0 || p->pathlen >= PATH_MAX) { 641*62224350SCasper H.S. Dik progerr("bad entry read in contents file"); 642*62224350SCasper H.S. Dik logerr("pathname: Unknown"); 643*62224350SCasper H.S. Dik logerr("problem: unable to read pathname field"); 644*62224350SCasper H.S. Dik if (one_shot) 645*62224350SCasper H.S. Dik exit(2); 646*62224350SCasper H.S. Dik } 647*62224350SCasper H.S. Dik if (t[-1] == '=') 648*62224350SCasper H.S. Dik while (!IS_ST0[(unsigned char)*t++]) 649*62224350SCasper H.S. Dik ; 650*62224350SCasper H.S. Dik 651*62224350SCasper H.S. Dik /* Partial as found in the "-" entries for log */ 652*62224350SCasper H.S. Dik if (t[-1] == '\0') { 653*62224350SCasper H.S. Dik if (full) 654*62224350SCasper H.S. Dik goto badline; 655*62224350SCasper H.S. Dik 656*62224350SCasper H.S. Dik p->pkgoff = -1; 657*62224350SCasper H.S. Dik return (p); 658*62224350SCasper H.S. Dik } 659*62224350SCasper H.S. Dik 660*62224350SCasper H.S. Dik switch (*t) { 661*62224350SCasper H.S. Dik case '?': 662*62224350SCasper H.S. Dik nfields = 0; 663*62224350SCasper H.S. Dik break; 664*62224350SCasper H.S. Dik case 's': 665*62224350SCasper H.S. Dik case 'l': 666*62224350SCasper H.S. Dik /* Fields: class */ 667*62224350SCasper H.S. Dik nfields = 1; 668*62224350SCasper H.S. Dik break; 669*62224350SCasper H.S. Dik case 'p': 670*62224350SCasper H.S. Dik case 'x': 671*62224350SCasper H.S. Dik case 'd': 672*62224350SCasper H.S. Dik /* class mode owner group */ 673*62224350SCasper H.S. Dik nfields = 4; 674*62224350SCasper H.S. Dik break; 675*62224350SCasper H.S. Dik case 'f': 676*62224350SCasper H.S. Dik case 'e': 677*62224350SCasper H.S. Dik case 'v': 678*62224350SCasper H.S. Dik /* class mode owner group size csum time */ 679*62224350SCasper H.S. Dik nfields = 7; 680*62224350SCasper H.S. Dik break; 681*62224350SCasper H.S. Dik case 'c': 682*62224350SCasper H.S. Dik case 'b': 683*62224350SCasper H.S. Dik /* class major minor mode owner group */ 684*62224350SCasper H.S. Dik nfields = 6; 685*62224350SCasper H.S. Dik break; 686*62224350SCasper H.S. Dik default: 687*62224350SCasper H.S. Dik progerr("bad entry read in contents file"); 688*62224350SCasper H.S. Dik logerr("pathname: %.*s", p->pathlen, p->line); 689*62224350SCasper H.S. Dik logerr("problem: unknown ftype"); 690*62224350SCasper H.S. Dik freeentry(p); 691*62224350SCasper H.S. Dik if (one_shot) 692*62224350SCasper H.S. Dik exit(2); 693*62224350SCasper H.S. Dik return (NULL); 694*62224350SCasper H.S. Dik } 695*62224350SCasper H.S. Dik 696*62224350SCasper H.S. Dik p->pkgoff = t + fieldoff(t, nfields + 1) - buf; 697*62224350SCasper H.S. Dik 698*62224350SCasper H.S. Dik if (p->line[p->pkgoff] != '\0' || p->pkgoff == p->len - 1) 699*62224350SCasper H.S. Dik return (p); 700*62224350SCasper H.S. Dik 701*62224350SCasper H.S. Dik badline: 702*62224350SCasper H.S. Dik progerr(gettext("bad entry read in contents file")); 703*62224350SCasper H.S. Dik logerr(gettext("pathname: Unknown")); 704*62224350SCasper H.S. Dik logerr(gettext("problem: unknown ftype")); 705*62224350SCasper H.S. Dik freeentry(p); 706*62224350SCasper H.S. Dik if (one_shot) 707*62224350SCasper H.S. Dik exit(2); 708*62224350SCasper H.S. Dik return (NULL); 709*62224350SCasper H.S. Dik } 710*62224350SCasper H.S. Dik 711*62224350SCasper H.S. Dik static void 712*62224350SCasper H.S. Dik handle_comments(char *buf, int len) 713*62224350SCasper H.S. Dik { 714*62224350SCasper H.S. Dik if (cind >= 2) 715*62224350SCasper H.S. Dik return; 716*62224350SCasper H.S. Dik 717*62224350SCasper H.S. Dik if (buf[0] != '#') 718*62224350SCasper H.S. Dik return; 719*62224350SCasper H.S. Dik 720*62224350SCasper H.S. Dik if (ccmnt[cind] != NULL) 721*62224350SCasper H.S. Dik umem_free(ccmnt[cind], strlen(ccmnt[cind]) + 1); 722*62224350SCasper H.S. Dik ccmnt[cind] = mystrcpy(buf, len); 723*62224350SCasper H.S. Dik cind++; 724*62224350SCasper H.S. Dik } 725*62224350SCasper H.S. Dik 726*62224350SCasper H.S. Dik static void 727*62224350SCasper H.S. Dik parse_contents(void) 728*62224350SCasper H.S. Dik { 729*62224350SCasper H.S. Dik int cnt; 730*62224350SCasper H.S. Dik pkgentry_t *ent, *e2; 731*62224350SCasper H.S. Dik avl_index_t where; 732*62224350SCasper H.S. Dik int num = 0; 733*62224350SCasper H.S. Dik struct stat stb; 734*62224350SCasper H.S. Dik ptrdiff_t off; 735*62224350SCasper H.S. Dik char *p, *q, *map; 736*62224350SCasper H.S. Dik pkgentry_t *lastentry = NULL; 737*62224350SCasper H.S. Dik int d; 738*62224350SCasper H.S. Dik int cntserrs = 0; 739*62224350SCasper H.S. Dik 740*62224350SCasper H.S. Dik cnt = open(CONTENTS, O_RDONLY); 741*62224350SCasper H.S. Dik 742*62224350SCasper H.S. Dik cind = 0; 743*62224350SCasper H.S. Dik 744*62224350SCasper H.S. Dik if (cnt == -1) { 745*62224350SCasper H.S. Dik if (errno == ENOENT) 746*62224350SCasper H.S. Dik return; 747*62224350SCasper H.S. Dik exit(99); 748*62224350SCasper H.S. Dik } 749*62224350SCasper H.S. Dik 750*62224350SCasper H.S. Dik if (fstat(cnt, &stb) != 0) { 751*62224350SCasper H.S. Dik (void) close(cnt); 752*62224350SCasper H.S. Dik exit(99); 753*62224350SCasper H.S. Dik } 754*62224350SCasper H.S. Dik if (stb.st_size == 0) { 755*62224350SCasper H.S. Dik (void) close(cnt); 756*62224350SCasper H.S. Dik return; 757*62224350SCasper H.S. Dik } 758*62224350SCasper H.S. Dik 759*62224350SCasper H.S. Dik map = mmap(0, stb.st_size, PROT_READ, MAP_PRIVATE, cnt, 0); 760*62224350SCasper H.S. Dik (void) close(cnt); 761*62224350SCasper H.S. Dik if (map == (char *)-1) 762*62224350SCasper H.S. Dik return; 763*62224350SCasper H.S. Dik 764*62224350SCasper H.S. Dik (void) madvise(map, stb.st_size, MADV_WILLNEED); 765*62224350SCasper H.S. Dik 766*62224350SCasper H.S. Dik for (off = 0; off < stb.st_size; off += q - p) { 767*62224350SCasper H.S. Dik p = map + off; 768*62224350SCasper H.S. Dik q = memchr(p, '\n', stb.st_size - off); 769*62224350SCasper H.S. Dik if (q == NULL) 770*62224350SCasper H.S. Dik break; 771*62224350SCasper H.S. Dik 772*62224350SCasper H.S. Dik q++; 773*62224350SCasper H.S. Dik num++; 774*62224350SCasper H.S. Dik if (p[0] == '#' || p[0] == '\n') { 775*62224350SCasper H.S. Dik handle_comments(p, q - p); 776*62224350SCasper H.S. Dik continue; 777*62224350SCasper H.S. Dik } 778*62224350SCasper H.S. Dik ent = parse_line(p, q - p - 1, B_TRUE); 779*62224350SCasper H.S. Dik 780*62224350SCasper H.S. Dik if (ent == NULL) { 781*62224350SCasper H.S. Dik cntserrs++; 782*62224350SCasper H.S. Dik continue; 783*62224350SCasper H.S. Dik } 784*62224350SCasper H.S. Dik 785*62224350SCasper H.S. Dik /* 786*62224350SCasper H.S. Dik * We save time by assuming the database is sorted; by 787*62224350SCasper H.S. Dik * using avl_insert_here(), building the tree is nearly free. 788*62224350SCasper H.S. Dik * lastentry always contains the last entry in the AVL tree. 789*62224350SCasper H.S. Dik */ 790*62224350SCasper H.S. Dik if (lastentry == NULL) { 791*62224350SCasper H.S. Dik avl_add(list, ent); 792*62224350SCasper H.S. Dik lastentry = ent; 793*62224350SCasper H.S. Dik } else if ((d = avlcmp(ent, lastentry)) == 1) { 794*62224350SCasper H.S. Dik avl_insert_here(list, ent, lastentry, AVL_AFTER); 795*62224350SCasper H.S. Dik lastentry = ent; 796*62224350SCasper H.S. Dik } else if (d == 0 || 797*62224350SCasper H.S. Dik (e2 = avl_find(list, ent, &where)) != NULL) { 798*62224350SCasper H.S. Dik /* 799*62224350SCasper H.S. Dik * This can only happen if the contents file is bad; 800*62224350SCasper H.S. Dik * this can, e.g., happen with the old SQL contents DB, 801*62224350SCasper H.S. Dik * it didn't sort properly. Assume the first one 802*62224350SCasper H.S. Dik * is the correct one, but who knows? 803*62224350SCasper H.S. Dik */ 804*62224350SCasper H.S. Dik if (d == 0) 805*62224350SCasper H.S. Dik e2 = lastentry; 806*62224350SCasper H.S. Dik if (strcmp(ent->line, e2->line) != 0) { 807*62224350SCasper H.S. Dik progerr(gettext("two entries for %.*s"), 808*62224350SCasper H.S. Dik ent->pathlen, ent->line); 809*62224350SCasper H.S. Dik cntserrs++; 810*62224350SCasper H.S. Dik } 811*62224350SCasper H.S. Dik freeentry(ent); 812*62224350SCasper H.S. Dik } else { 813*62224350SCasper H.S. Dik /* Out of order: not an error for us, really. */ 814*62224350SCasper H.S. Dik progerr(gettext("bad read of contents file")); 815*62224350SCasper H.S. Dik logerr(gettext("pathname: Unknown")); 816*62224350SCasper H.S. Dik logerr(gettext( 817*62224350SCasper H.S. Dik "problem: unable to read pathname field")); 818*62224350SCasper H.S. Dik if (one_shot) 819*62224350SCasper H.S. Dik exit(2); 820*62224350SCasper H.S. Dik avl_insert(list, ent, where); 821*62224350SCasper H.S. Dik } 822*62224350SCasper H.S. Dik } 823*62224350SCasper H.S. Dik 824*62224350SCasper H.S. Dik cind = 0; 825*62224350SCasper H.S. Dik 826*62224350SCasper H.S. Dik (void) munmap(map, stb.st_size); 827*62224350SCasper H.S. Dik 828*62224350SCasper H.S. Dik /* By default, we ignore bad lines, keep them in a copy. */ 829*62224350SCasper H.S. Dik if (cntserrs > 0 && stb.st_nlink == 1) { 830*62224350SCasper H.S. Dik char bcf[sizeof (BADCONTENTS)]; 831*62224350SCasper H.S. Dik 832*62224350SCasper H.S. Dik (void) strcpy(bcf, BADCONTENTS); 833*62224350SCasper H.S. Dik if (mktemp(bcf) != NULL) { 834*62224350SCasper H.S. Dik (void) link(CONTENTS, bcf); 835*62224350SCasper H.S. Dik syslog(LOG_WARNING, "A bad contents file was saved: %s", 836*62224350SCasper H.S. Dik bcf); 837*62224350SCasper H.S. Dik } 838*62224350SCasper H.S. Dik } 839*62224350SCasper H.S. Dik } 840*62224350SCasper H.S. Dik 841*62224350SCasper H.S. Dik static int 842*62224350SCasper H.S. Dik parse_log(void) 843*62224350SCasper H.S. Dik { 844*62224350SCasper H.S. Dik pkgentry_t *ent, *look; 845*62224350SCasper H.S. Dik avl_index_t where; 846*62224350SCasper H.S. Dik int num = 0; 847*62224350SCasper H.S. Dik int logfd; 848*62224350SCasper H.S. Dik struct stat stb; 849*62224350SCasper H.S. Dik int mlen = strlen(marker); 850*62224350SCasper H.S. Dik off_t realend; 851*62224350SCasper H.S. Dik ptrdiff_t off; 852*62224350SCasper H.S. Dik char *p, *q, *map; 853*62224350SCasper H.S. Dik 854*62224350SCasper H.S. Dik logfd = open(PKGLOG, O_RDONLY); 855*62224350SCasper H.S. Dik 856*62224350SCasper H.S. Dik if (logfd < 0) { 857*62224350SCasper H.S. Dik if (errno == ENOENT) 858*62224350SCasper H.S. Dik return (0); 859*62224350SCasper H.S. Dik progerr(gettext("cannot read "PKGLOG": %s"), strerror(errno)); 860*62224350SCasper H.S. Dik exit(2); 861*62224350SCasper H.S. Dik } 862*62224350SCasper H.S. Dik 863*62224350SCasper H.S. Dik if (fstat(logfd, &stb) != 0) { 864*62224350SCasper H.S. Dik progerr(gettext("cannot stat "PKGLOG": %s"), strerror(errno)); 865*62224350SCasper H.S. Dik exit(2); 866*62224350SCasper H.S. Dik } 867*62224350SCasper H.S. Dik 868*62224350SCasper H.S. Dik if (stb.st_size == 0) { 869*62224350SCasper H.S. Dik (void) close(logfd); 870*62224350SCasper H.S. Dik /* Force pkgdump && remove of the logfile. */ 871*62224350SCasper H.S. Dik return (1); 872*62224350SCasper H.S. Dik } 873*62224350SCasper H.S. Dik 874*62224350SCasper H.S. Dik /* We're making sure that we end with a NUL or more for strstr() */ 875*62224350SCasper H.S. Dik map = mmap(0, stb.st_size + getpagesize(), PROT_READ, MAP_PRIVATE, 876*62224350SCasper H.S. Dik logfd, 0); 877*62224350SCasper H.S. Dik (void) close(logfd); 878*62224350SCasper H.S. Dik if (map == (char *)-1) { 879*62224350SCasper H.S. Dik progerr(gettext("Cannot mmap the "PKGLOG": %s"), 880*62224350SCasper H.S. Dik strerror(errno)); 881*62224350SCasper H.S. Dik exit(2); 882*62224350SCasper H.S. Dik } 883*62224350SCasper H.S. Dik 884*62224350SCasper H.S. Dik cind = 0; 885*62224350SCasper H.S. Dik 886*62224350SCasper H.S. Dik realend = stb.st_size; 887*62224350SCasper H.S. Dik 888*62224350SCasper H.S. Dik if (memcmp(map + realend - mlen, marker, mlen) != 0) { 889*62224350SCasper H.S. Dik progerr(gettext(PKGLOG" is not complete")); 890*62224350SCasper H.S. Dik 891*62224350SCasper H.S. Dik realend = 0; 892*62224350SCasper H.S. Dik for (p = map; q = strstr(p, marker); ) { 893*62224350SCasper H.S. Dik if (q == map || q[-1] == '\n') 894*62224350SCasper H.S. Dik realend = q - map + mlen; 895*62224350SCasper H.S. Dik p = q + mlen; 896*62224350SCasper H.S. Dik } 897*62224350SCasper H.S. Dik progerr(gettext("Ignoring %ld bytes from log"), 898*62224350SCasper H.S. Dik (long)(stb.st_size - realend)); 899*62224350SCasper H.S. Dik } 900*62224350SCasper H.S. Dik 901*62224350SCasper H.S. Dik for (off = 0; off < realend; off += q - p) { 902*62224350SCasper H.S. Dik p = map + off; 903*62224350SCasper H.S. Dik q = memchr(p, '\n', realend - off); 904*62224350SCasper H.S. Dik if (q == NULL) 905*62224350SCasper H.S. Dik break; 906*62224350SCasper H.S. Dik 907*62224350SCasper H.S. Dik q++; 908*62224350SCasper H.S. Dik num++; 909*62224350SCasper H.S. Dik if (p[0] == '#' || p[0] == '\n') { 910*62224350SCasper H.S. Dik if (memcmp(marker, p, mlen) == 0) 911*62224350SCasper H.S. Dik cind = 0; 912*62224350SCasper H.S. Dik else 913*62224350SCasper H.S. Dik handle_comments(p, q - p); 914*62224350SCasper H.S. Dik continue; 915*62224350SCasper H.S. Dik } 916*62224350SCasper H.S. Dik 917*62224350SCasper H.S. Dik ent = parse_line(p + 1, q - (p + 1) - 1, p[0] != '-'); 918*62224350SCasper H.S. Dik if (ent == NULL) 919*62224350SCasper H.S. Dik continue; 920*62224350SCasper H.S. Dik look = avl_find(list, ent, &where); 921*62224350SCasper H.S. Dik /* 922*62224350SCasper H.S. Dik * The log can be replayed; so any value of "look" is 923*62224350SCasper H.S. Dik * not unexpected. 924*62224350SCasper H.S. Dik */ 925*62224350SCasper H.S. Dik switch (p[0]) { 926*62224350SCasper H.S. Dik case '+': 927*62224350SCasper H.S. Dik case '=': 928*62224350SCasper H.S. Dik if (look != NULL) 929*62224350SCasper H.S. Dik swapentry(look, ent); 930*62224350SCasper H.S. Dik else 931*62224350SCasper H.S. Dik avl_insert(list, ent, where); 932*62224350SCasper H.S. Dik break; 933*62224350SCasper H.S. Dik case '-': 934*62224350SCasper H.S. Dik if (look != NULL) { 935*62224350SCasper H.S. Dik avl_remove(list, look); 936*62224350SCasper H.S. Dik freeentry(look); 937*62224350SCasper H.S. Dik } 938*62224350SCasper H.S. Dik freeentry(ent); 939*62224350SCasper H.S. Dik break; 940*62224350SCasper H.S. Dik default: 941*62224350SCasper H.S. Dik freeentry(ent); 942*62224350SCasper H.S. Dik progerr(gettext("log %d: bad line"), num); 943*62224350SCasper H.S. Dik break; 944*62224350SCasper H.S. Dik } 945*62224350SCasper H.S. Dik } 946*62224350SCasper H.S. Dik (void) munmap(map, stb.st_size); 947*62224350SCasper H.S. Dik 948*62224350SCasper H.S. Dik /* Force pkgdump && remove of the logfile if there are no valid mods. */ 949*62224350SCasper H.S. Dik return (num == 0 ? 1 : num); 950*62224350SCasper H.S. Dik } 951*62224350SCasper H.S. Dik 952*62224350SCasper H.S. Dik static char * 953*62224350SCasper H.S. Dik file_find(pkgfilter_t *cmd, int *len) 954*62224350SCasper H.S. Dik { 955*62224350SCasper H.S. Dik pkgentry_t p; 956*62224350SCasper H.S. Dik pkgentry_t *look; 957*62224350SCasper H.S. Dik 958*62224350SCasper H.S. Dik p.line = cmd->buf; 959*62224350SCasper H.S. Dik p.pathlen = cmd->len; 960*62224350SCasper H.S. Dik 961*62224350SCasper H.S. Dik look = avl_find(list, &p, NULL); 962*62224350SCasper H.S. Dik 963*62224350SCasper H.S. Dik if (look == NULL) 964*62224350SCasper H.S. Dik return (NULL); 965*62224350SCasper H.S. Dik 966*62224350SCasper H.S. Dik *len = look->len; 967*62224350SCasper H.S. Dik return (look->line); 968*62224350SCasper H.S. Dik } 969*62224350SCasper H.S. Dik 970*62224350SCasper H.S. Dik static void 971*62224350SCasper H.S. Dik pkgdump(void) 972*62224350SCasper H.S. Dik { 973*62224350SCasper H.S. Dik FILE *cnts; 974*62224350SCasper H.S. Dik int err = 0; 975*62224350SCasper H.S. Dik pkgentry_t *p; 976*62224350SCasper H.S. Dik 977*62224350SCasper H.S. Dik if (read_only) 978*62224350SCasper H.S. Dik return; 979*62224350SCasper H.S. Dik 980*62224350SCasper H.S. Dik /* We cannot dump when the current transaction is not complete. */ 981*62224350SCasper H.S. Dik if (sync_needed) 982*62224350SCasper H.S. Dik return; 983*62224350SCasper H.S. Dik 984*62224350SCasper H.S. Dik cnts = fopen(TCONTENTS, "w"); 985*62224350SCasper H.S. Dik 986*62224350SCasper H.S. Dik if (cnts == NULL) 987*62224350SCasper H.S. Dik exit(99); 988*62224350SCasper H.S. Dik 989*62224350SCasper H.S. Dik for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) { 990*62224350SCasper H.S. Dik if (fprintf(cnts, "%s\n", p->line) < 0) 991*62224350SCasper H.S. Dik err++; 992*62224350SCasper H.S. Dik } 993*62224350SCasper H.S. Dik 994*62224350SCasper H.S. Dik if (ccmnt[0] != NULL) 995*62224350SCasper H.S. Dik (void) fprintf(cnts, "%s\n", ccmnt[0]); 996*62224350SCasper H.S. Dik if (ccmnt[1] != NULL) 997*62224350SCasper H.S. Dik (void) fprintf(cnts, "%s\n", ccmnt[1]); 998*62224350SCasper H.S. Dik 999*62224350SCasper H.S. Dik if (err != 0 || fflush(cnts) == EOF || fsync(fileno(cnts)) != 0 || 1000*62224350SCasper H.S. Dik fclose(cnts) == EOF || rename(TCONTENTS, CONTENTS) != 0) { 1001*62224350SCasper H.S. Dik err++; 1002*62224350SCasper H.S. Dik } 1003*62224350SCasper H.S. Dik 1004*62224350SCasper H.S. Dik if (err != 0) { 1005*62224350SCasper H.S. Dik progerr("cannot rewrite the contents file"); 1006*62224350SCasper H.S. Dik exit(2); 1007*62224350SCasper H.S. Dik } 1008*62224350SCasper H.S. Dik 1009*62224350SCasper H.S. Dik (void) fclose(log); 1010*62224350SCasper H.S. Dik (void) unlink(PKGLOG); 1011*62224350SCasper H.S. Dik log = NULL; 1012*62224350SCasper H.S. Dik ndumps++; 1013*62224350SCasper H.S. Dik logcount = 0; 1014*62224350SCasper H.S. Dik } 1015*62224350SCasper H.S. Dik 1016*62224350SCasper H.S. Dik static void 1017*62224350SCasper H.S. Dik freeentry(pkgentry_t *p) 1018*62224350SCasper H.S. Dik { 1019*62224350SCasper H.S. Dik umem_free(p->line, p->len); 1020*62224350SCasper H.S. Dik umem_cache_free(ecache, p); 1021*62224350SCasper H.S. Dik } 1022*62224350SCasper H.S. Dik 1023*62224350SCasper H.S. Dik static void 1024*62224350SCasper H.S. Dik swapentry(pkgentry_t *cur, pkgentry_t *new) 1025*62224350SCasper H.S. Dik { 1026*62224350SCasper H.S. Dik if (cur->len == new->len && 1027*62224350SCasper H.S. Dik strcmp(cur->line + cur->pathlen, 1028*62224350SCasper H.S. Dik new->line + new->pathlen) == 0) { 1029*62224350SCasper H.S. Dik suppressed++; 1030*62224350SCasper H.S. Dik freeentry(new); 1031*62224350SCasper H.S. Dik return; 1032*62224350SCasper H.S. Dik } 1033*62224350SCasper H.S. Dik 1034*62224350SCasper H.S. Dik /* Free old line */ 1035*62224350SCasper H.S. Dik umem_free(cur->line, cur->len); 1036*62224350SCasper H.S. Dik 1037*62224350SCasper H.S. Dik /* Copy new value: pathlen is the same and avl is kept */ 1038*62224350SCasper H.S. Dik cur->line = new->line; 1039*62224350SCasper H.S. Dik cur->len = new->len; 1040*62224350SCasper H.S. Dik cur->pkgoff = new->pkgoff; 1041*62224350SCasper H.S. Dik 1042*62224350SCasper H.S. Dik umem_cache_free(ecache, new); 1043*62224350SCasper H.S. Dik } 1044*62224350SCasper H.S. Dik 1045*62224350SCasper H.S. Dik static int 1046*62224350SCasper H.S. Dik logentry(char type, pkgentry_t *p) 1047*62224350SCasper H.S. Dik { 1048*62224350SCasper H.S. Dik int len; 1049*62224350SCasper H.S. Dik 1050*62224350SCasper H.S. Dik if (type == '-') 1051*62224350SCasper H.S. Dik len = fprintf(log, "-%.*s\n", p->pathlen, p->line); 1052*62224350SCasper H.S. Dik else 1053*62224350SCasper H.S. Dik len = fprintf(log, "%c%s\n", type, p->line); 1054*62224350SCasper H.S. Dik 1055*62224350SCasper H.S. Dik loglines++; 1056*62224350SCasper H.S. Dik if (len < 0) { 1057*62224350SCasper H.S. Dik logerrcnt++; 1058*62224350SCasper H.S. Dik return (-1); 1059*62224350SCasper H.S. Dik } 1060*62224350SCasper H.S. Dik logcount += len; 1061*62224350SCasper H.S. Dik return (0); 1062*62224350SCasper H.S. Dik } 1063*62224350SCasper H.S. Dik 1064*62224350SCasper H.S. Dik static int 1065*62224350SCasper H.S. Dik logflush(void) 1066*62224350SCasper H.S. Dik { 1067*62224350SCasper H.S. Dik int len; 1068*62224350SCasper H.S. Dik static int lastflush; 1069*62224350SCasper H.S. Dik 1070*62224350SCasper H.S. Dik if (log == NULL) 1071*62224350SCasper H.S. Dik return (0); 1072*62224350SCasper H.S. Dik 1073*62224350SCasper H.S. Dik if (lastflush == logcount) 1074*62224350SCasper H.S. Dik return (0); 1075*62224350SCasper H.S. Dik 1076*62224350SCasper H.S. Dik if (cind == 2) { 1077*62224350SCasper H.S. Dik (void) fprintf(log, "%s\n", ccmnt[0]); 1078*62224350SCasper H.S. Dik (void) fprintf(log, "%s\n", ccmnt[1]); 1079*62224350SCasper H.S. Dik cind = 0; 1080*62224350SCasper H.S. Dik } 1081*62224350SCasper H.S. Dik 1082*62224350SCasper H.S. Dik /* 1083*62224350SCasper H.S. Dik * When using zfs, if the mark is there, then so is the rest before 1084*62224350SCasper H.S. Dik * it. But with ufs, we need to flush twice. 1085*62224350SCasper H.S. Dik */ 1086*62224350SCasper H.S. Dik if (flushbeforemark) { 1087*62224350SCasper H.S. Dik if (fflush(log) == EOF) 1088*62224350SCasper H.S. Dik logerrcnt++; 1089*62224350SCasper H.S. Dik } 1090*62224350SCasper H.S. Dik /* Anything before the last marker found in the log will be valid */ 1091*62224350SCasper H.S. Dik len = fprintf(log, "%s", marker); 1092*62224350SCasper H.S. Dik if (len < 0) 1093*62224350SCasper H.S. Dik logerrcnt++; 1094*62224350SCasper H.S. Dik else 1095*62224350SCasper H.S. Dik logcount += len; 1096*62224350SCasper H.S. Dik 1097*62224350SCasper H.S. Dik if (fflush(log) == EOF) 1098*62224350SCasper H.S. Dik logerrcnt++; 1099*62224350SCasper H.S. Dik 1100*62224350SCasper H.S. Dik sync_needed = B_FALSE; 1101*62224350SCasper H.S. Dik 1102*62224350SCasper H.S. Dik if (logerrcnt > 0 || logcount > MAXLOGFILESIZE) 1103*62224350SCasper H.S. Dik pkgdump(); 1104*62224350SCasper H.S. Dik 1105*62224350SCasper H.S. Dik if (logerrcnt > 0) 1106*62224350SCasper H.S. Dik return (-1); 1107*62224350SCasper H.S. Dik 1108*62224350SCasper H.S. Dik lastflush = logcount; 1109*62224350SCasper H.S. Dik 1110*62224350SCasper H.S. Dik return (0); 1111*62224350SCasper H.S. Dik } 1112*62224350SCasper H.S. Dik 1113*62224350SCasper H.S. Dik static int 1114*62224350SCasper H.S. Dik avlcmp(const void *ca, const void *cb) 1115*62224350SCasper H.S. Dik { 1116*62224350SCasper H.S. Dik const pkgentry_t *a = ca; 1117*62224350SCasper H.S. Dik const pkgentry_t *b = cb; 1118*62224350SCasper H.S. Dik int i = memcmp(a->line, b->line, 1119*62224350SCasper H.S. Dik a->pathlen > b->pathlen ? b->pathlen : a->pathlen); 1120*62224350SCasper H.S. Dik 1121*62224350SCasper H.S. Dik if (i < 0) 1122*62224350SCasper H.S. Dik return (-1); 1123*62224350SCasper H.S. Dik else if (i > 0) 1124*62224350SCasper H.S. Dik return (1); 1125*62224350SCasper H.S. Dik else if (a->pathlen == b->pathlen) 1126*62224350SCasper H.S. Dik return (0); 1127*62224350SCasper H.S. Dik else if (a->pathlen > b->pathlen) 1128*62224350SCasper H.S. Dik return (1); 1129*62224350SCasper H.S. Dik else 1130*62224350SCasper H.S. Dik return (-1); 1131*62224350SCasper H.S. Dik } 1132*62224350SCasper H.S. Dik 1133*62224350SCasper H.S. Dik /* 1134*62224350SCasper H.S. Dik * Returns: 1135*62224350SCasper H.S. Dik * 0 - if we can get the lock 1136*62224350SCasper H.S. Dik * -1 - we can't lock 1137*62224350SCasper H.S. Dik */ 1138*62224350SCasper H.S. Dik 1139*62224350SCasper H.S. Dik static int 1140*62224350SCasper H.S. Dik establish_lock(char *lock) 1141*62224350SCasper H.S. Dik { 1142*62224350SCasper H.S. Dik int fd = open(lock, O_RDWR|O_CREAT, 0644); 1143*62224350SCasper H.S. Dik int i; 1144*62224350SCasper H.S. Dik 1145*62224350SCasper H.S. Dik if (fd < 0) 1146*62224350SCasper H.S. Dik return (-1); 1147*62224350SCasper H.S. Dik 1148*62224350SCasper H.S. Dik for (i = 0; i < 5; i++) { 1149*62224350SCasper H.S. Dik if (lockf(fd, F_TLOCK, 0) == 0) 1150*62224350SCasper H.S. Dik return (0); 1151*62224350SCasper H.S. Dik (void) sleep(1); 1152*62224350SCasper H.S. Dik } 1153*62224350SCasper H.S. Dik 1154*62224350SCasper H.S. Dik (void) close(fd); 1155*62224350SCasper H.S. Dik return (-1); 1156*62224350SCasper H.S. Dik } 1157*62224350SCasper H.S. Dik 1158*62224350SCasper H.S. Dik static int 1159*62224350SCasper H.S. Dik no_memory_abort(void) 1160*62224350SCasper H.S. Dik { 1161*62224350SCasper H.S. Dik return (UMEM_CALLBACK_EXIT(99)); 1162*62224350SCasper H.S. Dik } 1163*62224350SCasper H.S. Dik 1164*62224350SCasper H.S. Dik /* 1165*62224350SCasper H.S. Dik * Dump a part of the contents file in a pipe; grep for the "filter". 1166*62224350SCasper H.S. Dik * It doesn't matter if we return too much. 1167*62224350SCasper H.S. Dik */ 1168*62224350SCasper H.S. Dik 1169*62224350SCasper H.S. Dik static void * 1170*62224350SCasper H.S. Dik thr_pkgfilter(void *v) 1171*62224350SCasper H.S. Dik { 1172*62224350SCasper H.S. Dik pkgfilter_t *pf = v; 1173*62224350SCasper H.S. Dik pkgentry_t *p; 1174*62224350SCasper H.S. Dik int nums[2]; 1175*62224350SCasper H.S. Dik FILE *cnts; 1176*62224350SCasper H.S. Dik 1177*62224350SCasper H.S. Dik cnts = fdopen(pf->cmd, "w"); 1178*62224350SCasper H.S. Dik if (cnts == NULL) 1179*62224350SCasper H.S. Dik goto free; 1180*62224350SCasper H.S. Dik 1181*62224350SCasper H.S. Dik /* Remove wild card: don't care about extra matches */ 1182*62224350SCasper H.S. Dik if (pf->len > 0) { 1183*62224350SCasper H.S. Dik char *p; 1184*62224350SCasper H.S. Dik 1185*62224350SCasper H.S. Dik for (p = pf->buf; *p; p++) { 1186*62224350SCasper H.S. Dik if (*p == '*') { 1187*62224350SCasper H.S. Dik *p = 0; 1188*62224350SCasper H.S. Dik break; 1189*62224350SCasper H.S. Dik } 1190*62224350SCasper H.S. Dik } 1191*62224350SCasper H.S. Dik } 1192*62224350SCasper H.S. Dik 1193*62224350SCasper H.S. Dik /* Disable modifications while the filter is running */ 1194*62224350SCasper H.S. Dik (void) mutex_lock(&mtx); 1195*62224350SCasper H.S. Dik write_locked++; 1196*62224350SCasper H.S. Dik (void) mutex_unlock(&mtx); 1197*62224350SCasper H.S. Dik /* 1198*62224350SCasper H.S. Dik * The protocol for the contents file for the clients: 1199*62224350SCasper H.S. Dik * <int:len><int:pathlen><line + 0> 1200*62224350SCasper H.S. Dik */ 1201*62224350SCasper H.S. Dik 1202*62224350SCasper H.S. Dik for (p = avl_first(list); p != NULL; p = AVL_NEXT(list, p)) { 1203*62224350SCasper H.S. Dik if (pf->len > 0 && strstr(p->line, pf->buf) == NULL) 1204*62224350SCasper H.S. Dik continue; 1205*62224350SCasper H.S. Dik 1206*62224350SCasper H.S. Dik nums[0] = p->len; 1207*62224350SCasper H.S. Dik nums[1] = p->pathlen; 1208*62224350SCasper H.S. Dik if (fwrite(nums, sizeof (int), 2, cnts) != 2) 1209*62224350SCasper H.S. Dik break; 1210*62224350SCasper H.S. Dik if (fwrite(p->line, 1, p->len, cnts) != p->len) 1211*62224350SCasper H.S. Dik break; 1212*62224350SCasper H.S. Dik } 1213*62224350SCasper H.S. Dik 1214*62224350SCasper H.S. Dik (void) mutex_lock(&mtx); 1215*62224350SCasper H.S. Dik lastcall = gethrtime(); 1216*62224350SCasper H.S. Dik write_locked--; 1217*62224350SCasper H.S. Dik (void) cond_broadcast(&cv); 1218*62224350SCasper H.S. Dik (void) mutex_unlock(&mtx); 1219*62224350SCasper H.S. Dik (void) fclose(cnts); 1220*62224350SCasper H.S. Dik 1221*62224350SCasper H.S. Dik free: 1222*62224350SCasper H.S. Dik umem_free(pf, sizeof (pkgfilter_t) + pf->len); 1223*62224350SCasper H.S. Dik return (NULL); 1224*62224350SCasper H.S. Dik } 1225*62224350SCasper H.S. Dik 1226*62224350SCasper H.S. Dik static hrtime_t 1227*62224350SCasper H.S. Dik time_since_(hrtime_t last) 1228*62224350SCasper H.S. Dik { 1229*62224350SCasper H.S. Dik return (gethrtime() - last); 1230*62224350SCasper H.S. Dik } 1231*62224350SCasper H.S. Dik 1232*62224350SCasper H.S. Dik static void 1233*62224350SCasper H.S. Dik my_cond_reltimedwait(hrtime_t delta, int sec) 1234*62224350SCasper H.S. Dik { 1235*62224350SCasper H.S. Dik hrtime_t wait = sec * LLNANOSEC - delta; 1236*62224350SCasper H.S. Dik timestruc_t waitfor; 1237*62224350SCasper H.S. Dik 1238*62224350SCasper H.S. Dik waitfor.tv_nsec = wait % LLNANOSEC; 1239*62224350SCasper H.S. Dik waitfor.tv_sec = wait / LLNANOSEC; 1240*62224350SCasper H.S. Dik (void) cond_reltimedwait(&cv, &mtx, &waitfor); 1241*62224350SCasper H.S. Dik } 1242*62224350SCasper H.S. Dik 1243*62224350SCasper H.S. Dik static int 1244*62224350SCasper H.S. Dik pkgfilter(pkgfilter_t *pf, door_desc_t *dp) 1245*62224350SCasper H.S. Dik { 1246*62224350SCasper H.S. Dik 1247*62224350SCasper H.S. Dik int p[2]; 1248*62224350SCasper H.S. Dik thread_t tid; 1249*62224350SCasper H.S. Dik pkgfilter_t *cpf; 1250*62224350SCasper H.S. Dik 1251*62224350SCasper H.S. Dik if (pipe(p) != 0) 1252*62224350SCasper H.S. Dik return (-1); 1253*62224350SCasper H.S. Dik 1254*62224350SCasper H.S. Dik cpf = umem_alloc(sizeof (pkgfilter_t) + pf->len, UMEM_NOFAIL); 1255*62224350SCasper H.S. Dik 1256*62224350SCasper H.S. Dik (void) memcpy(cpf, pf, sizeof (pkgfilter_t) + pf->len); 1257*62224350SCasper H.S. Dik 1258*62224350SCasper H.S. Dik /* Copy the file descriptor in the command field */ 1259*62224350SCasper H.S. Dik cpf->cmd = p[1]; 1260*62224350SCasper H.S. Dik 1261*62224350SCasper H.S. Dik if (thr_create(NULL, NULL, thr_pkgfilter, cpf, THR_DETACHED, 1262*62224350SCasper H.S. Dik &tid) != 0) { 1263*62224350SCasper H.S. Dik (void) close(p[0]); 1264*62224350SCasper H.S. Dik (void) close(p[1]); 1265*62224350SCasper H.S. Dik umem_free(cpf, sizeof (pkgfilter_t) + pf->len); 1266*62224350SCasper H.S. Dik return (-1); 1267*62224350SCasper H.S. Dik } 1268*62224350SCasper H.S. Dik (void) memset(dp, 0, sizeof (*dp)); 1269*62224350SCasper H.S. Dik dp->d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE; 1270*62224350SCasper H.S. Dik dp->d_data.d_desc.d_descriptor = p[0]; 1271*62224350SCasper H.S. Dik 1272*62224350SCasper H.S. Dik return (0); 1273*62224350SCasper H.S. Dik } 1274*62224350SCasper H.S. Dik 1275*62224350SCasper H.S. Dik static int 1276*62224350SCasper H.S. Dik pkgaddlines(pkgfilter_t *pf) 1277*62224350SCasper H.S. Dik { 1278*62224350SCasper H.S. Dik char *map = pf->buf; 1279*62224350SCasper H.S. Dik int len = pf->len; 1280*62224350SCasper H.S. Dik int off; 1281*62224350SCasper H.S. Dik pkgentry_t *ent, *look; 1282*62224350SCasper H.S. Dik avl_index_t where; 1283*62224350SCasper H.S. Dik char *q, *p; 1284*62224350SCasper H.S. Dik char c; 1285*62224350SCasper H.S. Dik int r = 0; 1286*62224350SCasper H.S. Dik 1287*62224350SCasper H.S. Dik if (log == NULL) { 1288*62224350SCasper H.S. Dik log = fopen(PKGLOG, "w"); 1289*62224350SCasper H.S. Dik if (log == NULL) 1290*62224350SCasper H.S. Dik return (-1); 1291*62224350SCasper H.S. Dik } 1292*62224350SCasper H.S. Dik 1293*62224350SCasper H.S. Dik for (off = 0; off < len; off += q - p) { 1294*62224350SCasper H.S. Dik p = map + off; 1295*62224350SCasper H.S. Dik q = memchr(p, '\n', len - off); 1296*62224350SCasper H.S. Dik 1297*62224350SCasper H.S. Dik if (q == NULL) 1298*62224350SCasper H.S. Dik break; 1299*62224350SCasper H.S. Dik 1300*62224350SCasper H.S. Dik q++; 1301*62224350SCasper H.S. Dik 1302*62224350SCasper H.S. Dik if (p[0] == '#' || p[0] == '\n') { 1303*62224350SCasper H.S. Dik handle_comments(p, q - p); 1304*62224350SCasper H.S. Dik continue; 1305*62224350SCasper H.S. Dik } 1306*62224350SCasper H.S. Dik 1307*62224350SCasper H.S. Dik if (*p == '-') 1308*62224350SCasper H.S. Dik ent = parse_line(p + 1, q - (p + 1) - 1, B_FALSE); 1309*62224350SCasper H.S. Dik else 1310*62224350SCasper H.S. Dik ent = parse_line(p, q - p - 1, B_TRUE); 1311*62224350SCasper H.S. Dik 1312*62224350SCasper H.S. Dik if (ent == NULL) { 1313*62224350SCasper H.S. Dik r++; 1314*62224350SCasper H.S. Dik continue; 1315*62224350SCasper H.S. Dik } 1316*62224350SCasper H.S. Dik 1317*62224350SCasper H.S. Dik look = avl_find(list, ent, &where); 1318*62224350SCasper H.S. Dik if (look != NULL) { 1319*62224350SCasper H.S. Dik c = *p == '-' ? '-' : '='; 1320*62224350SCasper H.S. Dik if (c == '=') { 1321*62224350SCasper H.S. Dik swapentry(look, ent); 1322*62224350SCasper H.S. Dik ent = look; 1323*62224350SCasper H.S. Dik } else { 1324*62224350SCasper H.S. Dik avl_remove(list, look); 1325*62224350SCasper H.S. Dik freeentry(look); 1326*62224350SCasper H.S. Dik } 1327*62224350SCasper H.S. Dik } else if (*p == '-') { 1328*62224350SCasper H.S. Dik /* Remove something which isn't there: no-op */ 1329*62224350SCasper H.S. Dik freeentry(ent); 1330*62224350SCasper H.S. Dik continue; 1331*62224350SCasper H.S. Dik } else { 1332*62224350SCasper H.S. Dik avl_insert(list, ent, where); 1333*62224350SCasper H.S. Dik c = '+'; 1334*62224350SCasper H.S. Dik } 1335*62224350SCasper H.S. Dik 1336*62224350SCasper H.S. Dik sync_needed = B_TRUE; 1337*62224350SCasper H.S. Dik r += logentry(c, ent); 1338*62224350SCasper H.S. Dik if (c == '-') 1339*62224350SCasper H.S. Dik freeentry(ent); 1340*62224350SCasper H.S. Dik } 1341*62224350SCasper H.S. Dik 1342*62224350SCasper H.S. Dik return (r); 1343*62224350SCasper H.S. Dik } 1344*62224350SCasper H.S. Dik 1345*62224350SCasper H.S. Dik static void 1346*62224350SCasper H.S. Dik finish(void) 1347*62224350SCasper H.S. Dik { 1348*62224350SCasper H.S. Dik if (verbose) { 1349*62224350SCasper H.S. Dik syslog(LOG_DEBUG, 1350*62224350SCasper H.S. Dik "finished: calls %d, pkgdumps %d, loglines %d " 1351*62224350SCasper H.S. Dik "(suppressed %d)\n", 1352*62224350SCasper H.S. Dik ncalls, ndumps, loglines, suppressed); 1353*62224350SCasper H.S. Dik } 1354*62224350SCasper H.S. Dik (void) fdetach(door); 1355*62224350SCasper H.S. Dik if (read_only) 1356*62224350SCasper H.S. Dik (void) unlink(door); 1357*62224350SCasper H.S. Dik } 1358*62224350SCasper H.S. Dik 1359*62224350SCasper H.S. Dik /* 1360*62224350SCasper H.S. Dik * Tell the wait thread to wake up and quit. 1361*62224350SCasper H.S. Dik */ 1362*62224350SCasper H.S. Dik /* ARGSUSED */ 1363*62224350SCasper H.S. Dik static void 1364*62224350SCasper H.S. Dik signal_handler(int sig) 1365*62224350SCasper H.S. Dik { 1366*62224350SCasper H.S. Dik if (read_only) 1367*62224350SCasper H.S. Dik exit(0); 1368*62224350SCasper H.S. Dik want_to_quit = 1; 1369*62224350SCasper H.S. Dik (void) cond_broadcast(&cv); 1370*62224350SCasper H.S. Dik } 1371