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