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