162224350SCasper H.S. Dik /* 262224350SCasper H.S. Dik * CDDL HEADER START 362224350SCasper H.S. Dik * 462224350SCasper H.S. Dik * The contents of this file are subject to the terms of the 562224350SCasper H.S. Dik * Common Development and Distribution License (the "License"). 662224350SCasper H.S. Dik * You may not use this file except in compliance with the License. 762224350SCasper H.S. Dik * 862224350SCasper H.S. Dik * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 962224350SCasper H.S. Dik * or http://www.opensolaris.org/os/licensing. 1062224350SCasper H.S. Dik * See the License for the specific language governing permissions 1162224350SCasper H.S. Dik * and limitations under the License. 1262224350SCasper H.S. Dik * 1362224350SCasper H.S. Dik * When distributing Covered Code, include this CDDL HEADER in each 1462224350SCasper H.S. Dik * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1562224350SCasper H.S. Dik * If applicable, add the following below this CDDL HEADER, with the 1662224350SCasper H.S. Dik * fields enclosed by brackets "[]" replaced with your own identifying 1762224350SCasper H.S. Dik * information: Portions Copyright [yyyy] [name of copyright owner] 1862224350SCasper H.S. Dik * 1962224350SCasper H.S. Dik * CDDL HEADER END 2062224350SCasper H.S. Dik */ 2162224350SCasper H.S. Dik 2262224350SCasper H.S. Dik /* 23*7706a9bfSCasper H.S. Dik * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 2462224350SCasper H.S. Dik * Use is subject to license terms. 2562224350SCasper H.S. Dik */ 2662224350SCasper H.S. Dik 2762224350SCasper H.S. Dik #include <pkglib.h> 2862224350SCasper H.S. Dik 2962224350SCasper H.S. Dik #include <alloca.h> 3062224350SCasper H.S. Dik #include <assert.h> 3162224350SCasper H.S. Dik #include <door.h> 3262224350SCasper H.S. Dik #include <errno.h> 3362224350SCasper H.S. Dik #include <fcntl.h> 3462224350SCasper H.S. Dik #include <pthread.h> 3562224350SCasper H.S. Dik #include <spawn.h> 3662224350SCasper H.S. Dik #include <stdio.h> 3762224350SCasper H.S. Dik #include <stdlib.h> 3862224350SCasper H.S. Dik #include <strings.h> 3962224350SCasper H.S. Dik #include <sys/mman.h> 4062224350SCasper H.S. Dik #include <sys/param.h> 4162224350SCasper H.S. Dik #include <sys/stat.h> 4262224350SCasper H.S. Dik #include <sys/wait.h> 4362224350SCasper H.S. Dik #include <unistd.h> 4462224350SCasper H.S. Dik #include <libintl.h> 45*7706a9bfSCasper H.S. Dik #include <sys/mnttab.h> 46*7706a9bfSCasper H.S. Dik #include <sys/mkdev.h> 4762224350SCasper H.S. Dik 4862224350SCasper H.S. Dik #define PKGADD_MAX (512 * 1024) 4962224350SCasper H.S. Dik 5062224350SCasper H.S. Dik #define SADM_DIR "/var/sadm/install" 5162224350SCasper H.S. Dik 5262224350SCasper H.S. Dik #define PKGSERV_PATH "/usr/sadm/install/bin/pkgserv" 5362224350SCasper H.S. Dik 5462224350SCasper H.S. Dik #define ERR_PATH_TOO_BIG "alternate root path is too long" 5562224350SCasper H.S. Dik #define ERR_OPEN_DOOR "cannot open pkgserv door" 5662224350SCasper H.S. Dik #define ERR_START_SERVER "cannot start pkgserv daemon: %s" 5762224350SCasper H.S. Dik #define ERR_START_FILTER "cannot enumerate database entries" 58*7706a9bfSCasper H.S. Dik #define ERR_FIND_SADM "cannot find sadm directory" 5962224350SCasper H.S. Dik 6062224350SCasper H.S. Dik struct pkg_server { 6162224350SCasper H.S. Dik FILE *fp; 6262224350SCasper H.S. Dik char *curbuf; 6362224350SCasper H.S. Dik int buflen; 6462224350SCasper H.S. Dik int door; 6562224350SCasper H.S. Dik boolean_t onetime; 6662224350SCasper H.S. Dik }; 6762224350SCasper H.S. Dik 6862224350SCasper H.S. Dik static PKGserver current_server; 6962224350SCasper H.S. Dik 7062224350SCasper H.S. Dik static start_mode_t defmode = INVALID; 7162224350SCasper H.S. Dik static boolean_t registered = B_FALSE; 7262224350SCasper H.S. Dik static pid_t master_pid = -1; 7362224350SCasper H.S. Dik 7462224350SCasper H.S. Dik static void 7562224350SCasper H.S. Dik pkgfilename(char path[PATH_MAX], const char *root, const char *sadmdir, 7662224350SCasper H.S. Dik const char *file) 7762224350SCasper H.S. Dik { 7862224350SCasper H.S. Dik if (snprintf(path, PATH_MAX, "%s%s/%s", root == NULL ? "" : root, 7962224350SCasper H.S. Dik sadmdir == NULL ? SADM_DIR : sadmdir, file) >= PATH_MAX) { 8062224350SCasper H.S. Dik progerr(gettext(ERR_PATH_TOO_BIG)); 8162224350SCasper H.S. Dik exit(99); 8262224350SCasper H.S. Dik } 8362224350SCasper H.S. Dik } 8462224350SCasper H.S. Dik 8562224350SCasper H.S. Dik static void 86*7706a9bfSCasper H.S. Dik free_xmnt(struct extmnttab *xmnt) 87*7706a9bfSCasper H.S. Dik { 88*7706a9bfSCasper H.S. Dik free(xmnt->mnt_special); 89*7706a9bfSCasper H.S. Dik free(xmnt->mnt_mountp); 90*7706a9bfSCasper H.S. Dik free(xmnt->mnt_fstype); 91*7706a9bfSCasper H.S. Dik } 92*7706a9bfSCasper H.S. Dik 93*7706a9bfSCasper H.S. Dik static void 94*7706a9bfSCasper H.S. Dik copy_xmnt(const struct extmnttab *xmnt, struct extmnttab *saved) 95*7706a9bfSCasper H.S. Dik { 96*7706a9bfSCasper H.S. Dik 97*7706a9bfSCasper H.S. Dik free_xmnt(saved); 98*7706a9bfSCasper H.S. Dik 99*7706a9bfSCasper H.S. Dik /* 100*7706a9bfSCasper H.S. Dik * Copy everything and then strdup the strings we later use and NULL 101*7706a9bfSCasper H.S. Dik * the ones we don't. 102*7706a9bfSCasper H.S. Dik */ 103*7706a9bfSCasper H.S. Dik *saved = *xmnt; 104*7706a9bfSCasper H.S. Dik 105*7706a9bfSCasper H.S. Dik if (saved->mnt_special != NULL) 106*7706a9bfSCasper H.S. Dik saved->mnt_special = strdup(saved->mnt_special); 107*7706a9bfSCasper H.S. Dik if (saved->mnt_mountp != NULL) 108*7706a9bfSCasper H.S. Dik saved->mnt_mountp = strdup(saved->mnt_mountp); 109*7706a9bfSCasper H.S. Dik if (saved->mnt_fstype != NULL) 110*7706a9bfSCasper H.S. Dik saved->mnt_fstype = strdup(saved->mnt_fstype); 111*7706a9bfSCasper H.S. Dik 112*7706a9bfSCasper H.S. Dik saved->mnt_mntopts = NULL; 113*7706a9bfSCasper H.S. Dik saved->mnt_time = NULL; 114*7706a9bfSCasper H.S. Dik } 115*7706a9bfSCasper H.S. Dik 116*7706a9bfSCasper H.S. Dik static int 117*7706a9bfSCasper H.S. Dik testdoor(char *path) 118*7706a9bfSCasper H.S. Dik { 119*7706a9bfSCasper H.S. Dik int dir; 120*7706a9bfSCasper H.S. Dik int fd; 121*7706a9bfSCasper H.S. Dik struct door_info di; 122*7706a9bfSCasper H.S. Dik int res; 123*7706a9bfSCasper H.S. Dik 124*7706a9bfSCasper H.S. Dik dir = open(path, O_RDONLY); 125*7706a9bfSCasper H.S. Dik 126*7706a9bfSCasper H.S. Dik if (dir == -1) 127*7706a9bfSCasper H.S. Dik return (-1); 128*7706a9bfSCasper H.S. Dik 129*7706a9bfSCasper H.S. Dik fd = openat(dir, PKGDOOR, O_RDWR); 130*7706a9bfSCasper H.S. Dik (void) close(dir); 131*7706a9bfSCasper H.S. Dik if (fd == -1) 132*7706a9bfSCasper H.S. Dik return (-1); 133*7706a9bfSCasper H.S. Dik 134*7706a9bfSCasper H.S. Dik res = door_info(fd, &di); 135*7706a9bfSCasper H.S. Dik (void) close(fd); 136*7706a9bfSCasper H.S. Dik return (res); 137*7706a9bfSCasper H.S. Dik } 138*7706a9bfSCasper H.S. Dik 139*7706a9bfSCasper H.S. Dik /* 140*7706a9bfSCasper H.S. Dik * We need to make sure that we can locate the pkgserv and the door; 141*7706a9bfSCasper H.S. Dik * lofs mounts makes this more difficult: "nosub" mounts don't propagate 142*7706a9bfSCasper H.S. Dik * the door and doors created in lofs mounts are not propagated back to 143*7706a9bfSCasper H.S. Dik * the original filesystem. 144*7706a9bfSCasper H.S. Dik * Here we peel off the lofs mount points until we're 145*7706a9bfSCasper H.S. Dik * at /var/sadm/install or 146*7706a9bfSCasper H.S. Dik * we find a working door or 147*7706a9bfSCasper H.S. Dik * there's nothing more to peel off. 148*7706a9bfSCasper H.S. Dik * The fullpath parameter is used to return the result (stored in *sadmdir), 149*7706a9bfSCasper H.S. Dik * root is used but returned in the computed sadmdir and so the caller should 150*7706a9bfSCasper H.S. Dik * not use "root" any longer or set it to NULL. 151*7706a9bfSCasper H.S. Dik */ 152*7706a9bfSCasper H.S. Dik static void 153*7706a9bfSCasper H.S. Dik pkgfindrealsadmdir(char fullpath[PATH_MAX], const char *root, 154*7706a9bfSCasper H.S. Dik const char **sadmdir) 155*7706a9bfSCasper H.S. Dik { 156*7706a9bfSCasper H.S. Dik struct stat buf; 157*7706a9bfSCasper H.S. Dik struct extmnttab xmnt; 158*7706a9bfSCasper H.S. Dik FILE *mnttab = NULL; 159*7706a9bfSCasper H.S. Dik char temp[PATH_MAX]; 160*7706a9bfSCasper H.S. Dik struct extmnttab saved = {NULL, NULL, NULL, NULL, NULL, 0, 0}; 161*7706a9bfSCasper H.S. Dik 162*7706a9bfSCasper H.S. Dik if (snprintf(temp, PATH_MAX, "%s%s", 163*7706a9bfSCasper H.S. Dik root == NULL ? "" : root, 164*7706a9bfSCasper H.S. Dik *sadmdir == NULL ? SADM_DIR : *sadmdir) >= PATH_MAX) { 165*7706a9bfSCasper H.S. Dik progerr(gettext(ERR_PATH_TOO_BIG)); 166*7706a9bfSCasper H.S. Dik exit(99); 167*7706a9bfSCasper H.S. Dik } 168*7706a9bfSCasper H.S. Dik 169*7706a9bfSCasper H.S. Dik if (stat(temp, &buf) != 0) { 170*7706a9bfSCasper H.S. Dik progerr(gettext(ERR_FIND_SADM)); 171*7706a9bfSCasper H.S. Dik exit(99); 172*7706a9bfSCasper H.S. Dik } 173*7706a9bfSCasper H.S. Dik 174*7706a9bfSCasper H.S. Dik /* 175*7706a9bfSCasper H.S. Dik * To find the underlying mount point, you will need to 176*7706a9bfSCasper H.S. Dik * search the mnttab and find our mountpoint and the underlying 177*7706a9bfSCasper H.S. Dik * filesystem. 178*7706a9bfSCasper H.S. Dik * To find the mount point: use the longest prefix but limit 179*7706a9bfSCasper H.S. Dik * us to the filesystems with the same major/minor numbers. 180*7706a9bfSCasper H.S. Dik * To find the underlying mount point: find a non-lofs file 181*7706a9bfSCasper H.S. Dik * system or a <mnt> <mnt> entry (fake mountpoint for zones). 182*7706a9bfSCasper H.S. Dik */ 183*7706a9bfSCasper H.S. Dik for (;;) { 184*7706a9bfSCasper H.S. Dik size_t max = 0; 185*7706a9bfSCasper H.S. Dik 186*7706a9bfSCasper H.S. Dik if (realpath(temp, fullpath) == NULL) { 187*7706a9bfSCasper H.S. Dik progerr(gettext(ERR_FIND_SADM)); 188*7706a9bfSCasper H.S. Dik exit(99); 189*7706a9bfSCasper H.S. Dik } 190*7706a9bfSCasper H.S. Dik 191*7706a9bfSCasper H.S. Dik if (strcmp(fullpath, SADM_DIR) == 0) 192*7706a9bfSCasper H.S. Dik break; 193*7706a9bfSCasper H.S. Dik 194*7706a9bfSCasper H.S. Dik if (testdoor(fullpath) == 0) 195*7706a9bfSCasper H.S. Dik break; 196*7706a9bfSCasper H.S. Dik 197*7706a9bfSCasper H.S. Dik if (mnttab == NULL) 198*7706a9bfSCasper H.S. Dik mnttab = fopen(MNTTAB, "r"); 199*7706a9bfSCasper H.S. Dik else 200*7706a9bfSCasper H.S. Dik resetmnttab(mnttab); 201*7706a9bfSCasper H.S. Dik 202*7706a9bfSCasper H.S. Dik while (getextmntent(mnttab, &xmnt, 0) == 0) { 203*7706a9bfSCasper H.S. Dik size_t len; 204*7706a9bfSCasper H.S. Dik 205*7706a9bfSCasper H.S. Dik if (major(buf.st_dev) != xmnt.mnt_major || 206*7706a9bfSCasper H.S. Dik minor(buf.st_dev) != xmnt.mnt_minor) 207*7706a9bfSCasper H.S. Dik continue; 208*7706a9bfSCasper H.S. Dik 209*7706a9bfSCasper H.S. Dik len = strlen(xmnt.mnt_mountp); 210*7706a9bfSCasper H.S. Dik if (len < max) 211*7706a9bfSCasper H.S. Dik continue; 212*7706a9bfSCasper H.S. Dik 213*7706a9bfSCasper H.S. Dik if (strncmp(xmnt.mnt_mountp, fullpath, len) == 0 && 214*7706a9bfSCasper H.S. Dik (len == 1 || fullpath[len] == '/' || 215*7706a9bfSCasper H.S. Dik fullpath[len] == '\0')) { 216*7706a9bfSCasper H.S. Dik max = len; 217*7706a9bfSCasper H.S. Dik copy_xmnt(&xmnt, &saved); 218*7706a9bfSCasper H.S. Dik } 219*7706a9bfSCasper H.S. Dik } 220*7706a9bfSCasper H.S. Dik if (strcmp(saved.mnt_fstype, "lofs") != 0 || 221*7706a9bfSCasper H.S. Dik strcmp(saved.mnt_mountp, saved.mnt_special) == 0) { 222*7706a9bfSCasper H.S. Dik break; 223*7706a9bfSCasper H.S. Dik } 224*7706a9bfSCasper H.S. Dik /* Create a new path in the underlying filesystem. */ 225*7706a9bfSCasper H.S. Dik if (snprintf(temp, PATH_MAX, "%s%s", saved.mnt_special, 226*7706a9bfSCasper H.S. Dik &fullpath[max]) >= PATH_MAX) { 227*7706a9bfSCasper H.S. Dik progerr(gettext(ERR_PATH_TOO_BIG)); 228*7706a9bfSCasper H.S. Dik exit(99); 229*7706a9bfSCasper H.S. Dik } 230*7706a9bfSCasper H.S. Dik } 231*7706a9bfSCasper H.S. Dik 232*7706a9bfSCasper H.S. Dik if (mnttab != NULL) { 233*7706a9bfSCasper H.S. Dik free_xmnt(&saved); 234*7706a9bfSCasper H.S. Dik (void) fclose(mnttab); 235*7706a9bfSCasper H.S. Dik } 236*7706a9bfSCasper H.S. Dik *sadmdir = fullpath; 237*7706a9bfSCasper H.S. Dik } 238*7706a9bfSCasper H.S. Dik 239*7706a9bfSCasper H.S. Dik static void 24062224350SCasper H.S. Dik pkgexit_close(void) 24162224350SCasper H.S. Dik { 24262224350SCasper H.S. Dik if (current_server != NULL) 24362224350SCasper H.S. Dik pkgcloseserver(current_server); 24462224350SCasper H.S. Dik } 24562224350SCasper H.S. Dik 24662224350SCasper H.S. Dik static PKGserver 24762224350SCasper H.S. Dik pkgopenserver_i(const char *root, const char *sadmdir, boolean_t readonly, 24862224350SCasper H.S. Dik start_mode_t mode) 24962224350SCasper H.S. Dik { 25062224350SCasper H.S. Dik PKGserver server; 25162224350SCasper H.S. Dik struct door_info di; 25262224350SCasper H.S. Dik pid_t pid; 25362224350SCasper H.S. Dik int stat; 25462224350SCasper H.S. Dik int first = B_TRUE; 25562224350SCasper H.S. Dik char *cmd[16]; 25662224350SCasper H.S. Dik int args; 25762224350SCasper H.S. Dik char pkgdoor[PATH_MAX]; 258*7706a9bfSCasper H.S. Dik char realsadmdir[PATH_MAX]; 25962224350SCasper H.S. Dik extern char **environ; 26062224350SCasper H.S. Dik char *prog; 26162224350SCasper H.S. Dik char pidbuf[12]; 26262224350SCasper H.S. Dik 26362224350SCasper H.S. Dik if (current_server != NULL) 26462224350SCasper H.S. Dik return (current_server); 26562224350SCasper H.S. Dik 26662224350SCasper H.S. Dik if (!registered) { 26762224350SCasper H.S. Dik registered = B_TRUE; 26862224350SCasper H.S. Dik (void) atexit(pkgexit_close); 26962224350SCasper H.S. Dik } 27062224350SCasper H.S. Dik if (readonly) { 27162224350SCasper H.S. Dik int fd; 27262224350SCasper H.S. Dik 27362224350SCasper H.S. Dik (void) strcpy(pkgdoor, "/tmp/pkgdoor.XXXXXX"); 27462224350SCasper H.S. Dik if ((fd = mkstemp(pkgdoor)) < 0) { 27562224350SCasper H.S. Dik progerr(gettext(ERR_OPEN_DOOR)); 27662224350SCasper H.S. Dik return (NULL); 27762224350SCasper H.S. Dik } 27862224350SCasper H.S. Dik (void) close(fd); 27962224350SCasper H.S. Dik } else { 280*7706a9bfSCasper H.S. Dik pkgfindrealsadmdir(realsadmdir, root, &sadmdir); 281*7706a9bfSCasper H.S. Dik root = NULL; 28262224350SCasper H.S. Dik pkgfilename(pkgdoor, root, sadmdir, PKGDOOR); 28362224350SCasper H.S. Dik } 28462224350SCasper H.S. Dik 28562224350SCasper H.S. Dik server = malloc(sizeof (*server)); 28662224350SCasper H.S. Dik 28762224350SCasper H.S. Dik if (server == NULL) 28862224350SCasper H.S. Dik goto return_null; 28962224350SCasper H.S. Dik 29062224350SCasper H.S. Dik server->fp = NULL; 29162224350SCasper H.S. Dik server->onetime = readonly; 29262224350SCasper H.S. Dik 29362224350SCasper H.S. Dik openserver: 29462224350SCasper H.S. Dik server->door = open(pkgdoor, O_RDWR); 29562224350SCasper H.S. Dik 29662224350SCasper H.S. Dik if (server->door >= 0) { 29762224350SCasper H.S. Dik if (door_info(server->door, &di) == 0 && di.di_target >= 0) { 29862224350SCasper H.S. Dik pkgcmd_t n; 29962224350SCasper H.S. Dik n.cmd = PKG_NOP; 30062224350SCasper H.S. Dik server->buflen = 1024; 30162224350SCasper H.S. Dik server->curbuf = malloc(1024); 30262224350SCasper H.S. Dik if (server->curbuf == NULL || 30362224350SCasper H.S. Dik pkgcmd(server, &n, sizeof (n), NULL, NULL, NULL)) { 30462224350SCasper H.S. Dik pkgcloseserver(server); 30562224350SCasper H.S. Dik return (NULL); 30662224350SCasper H.S. Dik } 30762224350SCasper H.S. Dik return (current_server = server); 30862224350SCasper H.S. Dik } 30962224350SCasper H.S. Dik 31062224350SCasper H.S. Dik (void) close(server->door); 31162224350SCasper H.S. Dik } 31262224350SCasper H.S. Dik 31362224350SCasper H.S. Dik if (!first || mode == NEVER) 31462224350SCasper H.S. Dik goto return_null; 31562224350SCasper H.S. Dik 31662224350SCasper H.S. Dik first = B_FALSE; 31762224350SCasper H.S. Dik 31862224350SCasper H.S. Dik args = 0; 31962224350SCasper H.S. Dik cmd[args++] = strrchr(PKGSERV_PATH, '/') + 1; 32062224350SCasper H.S. Dik if (root != NULL && strcmp(root, "/") != 0) { 32162224350SCasper H.S. Dik cmd[args++] = "-R"; 32262224350SCasper H.S. Dik cmd[args++] = (char *)root; 32362224350SCasper H.S. Dik } 32462224350SCasper H.S. Dik if (sadmdir != NULL && strcmp(sadmdir, SADM_DIR) != 0) { 32562224350SCasper H.S. Dik cmd[args++] = "-d"; 32662224350SCasper H.S. Dik cmd[args++] = (char *)sadmdir; 32762224350SCasper H.S. Dik } 32862224350SCasper H.S. Dik if (readonly) { 32962224350SCasper H.S. Dik cmd[args++] = "-r"; 33062224350SCasper H.S. Dik cmd[args++] = pkgdoor; 33162224350SCasper H.S. Dik } 33262224350SCasper H.S. Dik prog = get_prog_name(); 33362224350SCasper H.S. Dik if (prog != NULL) { 33462224350SCasper H.S. Dik cmd[args++] = "-N"; 33562224350SCasper H.S. Dik cmd[args++] = prog; 33662224350SCasper H.S. Dik } 33762224350SCasper H.S. Dik 33862224350SCasper H.S. Dik switch (mode) { 33962224350SCasper H.S. Dik case FLUSH_LOG: 34062224350SCasper H.S. Dik cmd[args++] = "-e"; 34162224350SCasper H.S. Dik break; 34262224350SCasper H.S. Dik case RUN_ONCE: 34362224350SCasper H.S. Dik cmd[args++] = "-o"; 34462224350SCasper H.S. Dik break; 34562224350SCasper H.S. Dik case PERMANENT: 34662224350SCasper H.S. Dik cmd[args++] = "-p"; 34762224350SCasper H.S. Dik break; 34862224350SCasper H.S. Dik default: 34962224350SCasper H.S. Dik break; 35062224350SCasper H.S. Dik } 35162224350SCasper H.S. Dik 35262224350SCasper H.S. Dik if (master_pid != -1) { 35362224350SCasper H.S. Dik cmd[args++] = "-P"; 35462224350SCasper H.S. Dik (void) snprintf(pidbuf, sizeof (pidbuf), "%d", master_pid); 35562224350SCasper H.S. Dik cmd[args++] = pidbuf; 35662224350SCasper H.S. Dik } 35762224350SCasper H.S. Dik cmd[args++] = NULL; 35862224350SCasper H.S. Dik assert(args <= sizeof (cmd)/sizeof (char *)); 35962224350SCasper H.S. Dik 36062224350SCasper H.S. Dik if (posix_spawn(&pid, PKGSERV_PATH, NULL, NULL, cmd, environ) == 0) { 36162224350SCasper H.S. Dik server->onetime |= mode == RUN_ONCE; 36262224350SCasper H.S. Dik while (wait4(pid, &stat, 0, NULL) != -1) { 36362224350SCasper H.S. Dik if (WIFEXITED(stat)) { 36462224350SCasper H.S. Dik int s = WEXITSTATUS(stat); 36562224350SCasper H.S. Dik if (s == 0 || s == 1) 36662224350SCasper H.S. Dik if (mode == FLUSH_LOG) 36762224350SCasper H.S. Dik goto return_null; 36862224350SCasper H.S. Dik else 36962224350SCasper H.S. Dik goto openserver; 37062224350SCasper H.S. Dik if (s == 2) 37162224350SCasper H.S. Dik goto return_null; 37262224350SCasper H.S. Dik break; 37362224350SCasper H.S. Dik } else if (WIFSIGNALED(stat)) { 37462224350SCasper H.S. Dik break; 37562224350SCasper H.S. Dik } 37662224350SCasper H.S. Dik } 37762224350SCasper H.S. Dik } 37862224350SCasper H.S. Dik 37962224350SCasper H.S. Dik progerr(gettext(ERR_START_SERVER), strerror(errno)); 38062224350SCasper H.S. Dik 38162224350SCasper H.S. Dik return_null: 38262224350SCasper H.S. Dik if (readonly) 38362224350SCasper H.S. Dik (void) unlink(pkgdoor); 38462224350SCasper H.S. Dik free(server); 38562224350SCasper H.S. Dik return (NULL); 38662224350SCasper H.S. Dik } 38762224350SCasper H.S. Dik 38862224350SCasper H.S. Dik PKGserver 38962224350SCasper H.S. Dik pkgopenserver(const char *root, const char *sadmdir, boolean_t ro) 39062224350SCasper H.S. Dik { 39162224350SCasper H.S. Dik return (pkgopenserver_i(root, sadmdir, ro, pkgservergetmode())); 39262224350SCasper H.S. Dik } 39362224350SCasper H.S. Dik 39462224350SCasper H.S. Dik start_mode_t 39562224350SCasper H.S. Dik pkgparsemode(const char *mode) 39662224350SCasper H.S. Dik { 39762224350SCasper H.S. Dik if (strcasecmp(mode, MODE_PERMANENT) == 0) { 39862224350SCasper H.S. Dik return (PERMANENT); 39962224350SCasper H.S. Dik } else if (strncasecmp(mode, MODE_TIMEOUT, 40062224350SCasper H.S. Dik sizeof (MODE_TIMEOUT) - 1) == 0) { 40162224350SCasper H.S. Dik const char *pidstr = mode + sizeof (MODE_TIMEOUT) - 1; 40262224350SCasper H.S. Dik if (pidstr[0] != '\0') { 40362224350SCasper H.S. Dik master_pid = atoi(pidstr); 40462224350SCasper H.S. Dik if (master_pid <= 1 || kill(master_pid, 0) != 0) 40562224350SCasper H.S. Dik master_pid = -1; 40662224350SCasper H.S. Dik } 40762224350SCasper H.S. Dik 40862224350SCasper H.S. Dik return (TIMEOUT); 40962224350SCasper H.S. Dik } else if (strcasecmp(mode, MODE_RUN_ONCE) == 0) { 41062224350SCasper H.S. Dik return (RUN_ONCE); 41162224350SCasper H.S. Dik } else { 41262224350SCasper H.S. Dik progerr(gettext("invalid pkgserver mode: %s"), mode); 41362224350SCasper H.S. Dik exit(99); 41462224350SCasper H.S. Dik /*NOTREACHED*/ 41562224350SCasper H.S. Dik } 41662224350SCasper H.S. Dik } 41762224350SCasper H.S. Dik 41862224350SCasper H.S. Dik char * 41962224350SCasper H.S. Dik pkgmodeargument(start_mode_t mode) 42062224350SCasper H.S. Dik { 42162224350SCasper H.S. Dik static char timebuf[sizeof (PKGSERV_MODE) + sizeof (MODE_TIMEOUT) + 10]; 42262224350SCasper H.S. Dik 42362224350SCasper H.S. Dik switch (mode) { 42462224350SCasper H.S. Dik case PERMANENT: 42562224350SCasper H.S. Dik return (PKGSERV_MODE MODE_PERMANENT); 42662224350SCasper H.S. Dik case TIMEOUT: 42762224350SCasper H.S. Dik (void) snprintf(timebuf, sizeof (timebuf), 42862224350SCasper H.S. Dik PKGSERV_MODE MODE_TIMEOUT "%d", 42962224350SCasper H.S. Dik (master_pid > 1 && kill(master_pid, 0) == 0) ? master_pid : 43062224350SCasper H.S. Dik getpid()); 43162224350SCasper H.S. Dik return (timebuf); 43262224350SCasper H.S. Dik case RUN_ONCE: 43362224350SCasper H.S. Dik return (PKGSERV_MODE MODE_RUN_ONCE); 43462224350SCasper H.S. Dik } 43562224350SCasper H.S. Dik progerr(gettext("Bad pkgserv mode: %d"), (int)mode); 43662224350SCasper H.S. Dik exit(99); 43762224350SCasper H.S. Dik } 43862224350SCasper H.S. Dik 43962224350SCasper H.S. Dik void 44062224350SCasper H.S. Dik pkgserversetmode(start_mode_t mode) 44162224350SCasper H.S. Dik { 44262224350SCasper H.S. Dik if (mode == DEFAULTMODE || mode == INVALID) { 44362224350SCasper H.S. Dik char *var = getenv(SUNW_PKG_SERVERMODE); 44462224350SCasper H.S. Dik 44562224350SCasper H.S. Dik if (var != NULL) 44662224350SCasper H.S. Dik defmode = pkgparsemode(var); 44762224350SCasper H.S. Dik else 44862224350SCasper H.S. Dik defmode = DEFAULTMODE; 44962224350SCasper H.S. Dik } else { 45062224350SCasper H.S. Dik defmode = mode; 45162224350SCasper H.S. Dik } 45262224350SCasper H.S. Dik } 45362224350SCasper H.S. Dik 45462224350SCasper H.S. Dik start_mode_t 45562224350SCasper H.S. Dik pkgservergetmode(void) 45662224350SCasper H.S. Dik { 45762224350SCasper H.S. Dik if (defmode == INVALID) 45862224350SCasper H.S. Dik pkgserversetmode(DEFAULTMODE); 45962224350SCasper H.S. Dik return (defmode); 46062224350SCasper H.S. Dik } 46162224350SCasper H.S. Dik 46262224350SCasper H.S. Dik void 46362224350SCasper H.S. Dik pkgcloseserver(PKGserver server) 46462224350SCasper H.S. Dik { 46562224350SCasper H.S. Dik 46662224350SCasper H.S. Dik if (server->fp != NULL) 46762224350SCasper H.S. Dik (void) fclose(server->fp); 46862224350SCasper H.S. Dik free(server->curbuf); 46962224350SCasper H.S. Dik if (server->onetime) { 47062224350SCasper H.S. Dik pkgcmd_t cmd; 47162224350SCasper H.S. Dik cmd.cmd = PKG_EXIT; 47262224350SCasper H.S. Dik (void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL); 47362224350SCasper H.S. Dik } 47462224350SCasper H.S. Dik (void) close(server->door); 47562224350SCasper H.S. Dik if (server == current_server) 47662224350SCasper H.S. Dik current_server = NULL; 47762224350SCasper H.S. Dik free(server); 47862224350SCasper H.S. Dik } 47962224350SCasper H.S. Dik 48062224350SCasper H.S. Dik int 48162224350SCasper H.S. Dik pkgcmd(PKGserver srv, void *cmd, size_t len, char **result, size_t *rlen, 48262224350SCasper H.S. Dik int *fd) 48362224350SCasper H.S. Dik { 48462224350SCasper H.S. Dik door_arg_t da; 48562224350SCasper H.S. Dik 48662224350SCasper H.S. Dik da.data_ptr = cmd; 48762224350SCasper H.S. Dik da.data_size = len; 48862224350SCasper H.S. Dik da.desc_ptr = NULL; 48962224350SCasper H.S. Dik da.desc_num = 0; 49062224350SCasper H.S. Dik da.rbuf = result == NULL ? NULL : *result; 49162224350SCasper H.S. Dik da.rsize = rlen == NULL ? 0 : *rlen; 49262224350SCasper H.S. Dik 49362224350SCasper H.S. Dik if (door_call(srv->door, &da) != 0) { 49462224350SCasper H.S. Dik if (((pkgcmd_t *)cmd)->cmd == PKG_EXIT && errno == EINTR) 49562224350SCasper H.S. Dik return (0); 49662224350SCasper H.S. Dik return (-1); 49762224350SCasper H.S. Dik } 49862224350SCasper H.S. Dik 49962224350SCasper H.S. Dik if (da.desc_ptr != NULL) { 50062224350SCasper H.S. Dik int i = 0; 50162224350SCasper H.S. Dik if (fd != NULL) 50262224350SCasper H.S. Dik *fd = da.desc_ptr[i++].d_data.d_desc.d_descriptor; 50362224350SCasper H.S. Dik for (; i < da.desc_num; i++) 50462224350SCasper H.S. Dik (void) close(da.desc_ptr[i].d_data.d_desc.d_descriptor); 50562224350SCasper H.S. Dik } 50662224350SCasper H.S. Dik /* Error return */ 50762224350SCasper H.S. Dik if (da.data_size == sizeof (int)) { 50862224350SCasper H.S. Dik int x = *(int *)da.data_ptr; 50962224350SCasper H.S. Dik if (x != 0) { 51062224350SCasper H.S. Dik if (result == NULL || da.rbuf != *result) 51162224350SCasper H.S. Dik (void) munmap(da.rbuf, da.rsize); 51262224350SCasper H.S. Dik return (x); 51362224350SCasper H.S. Dik } 51462224350SCasper H.S. Dik } 51562224350SCasper H.S. Dik 51662224350SCasper H.S. Dik /* Other result */ 51762224350SCasper H.S. Dik if (result != NULL) { 51862224350SCasper H.S. Dik /* Make sure that the result is at the start of the buffer. */ 51962224350SCasper H.S. Dik if (da.data_ptr != NULL && da.rbuf != da.data_ptr) 52062224350SCasper H.S. Dik (void) memmove(da.rbuf, da.data_ptr, da.data_size); 52162224350SCasper H.S. Dik *result = da.rbuf; 52262224350SCasper H.S. Dik *rlen = da.data_size; 52362224350SCasper H.S. Dik } else if (da.rbuf != NULL) { 52462224350SCasper H.S. Dik (void) munmap(da.rbuf, da.rsize); 52562224350SCasper H.S. Dik } 52662224350SCasper H.S. Dik return (0); 52762224350SCasper H.S. Dik } 52862224350SCasper H.S. Dik 52962224350SCasper H.S. Dik /* 53062224350SCasper H.S. Dik * Pkgsync: 53162224350SCasper H.S. Dik * If the server is running, make sure that the contents 53262224350SCasper H.S. Dik * file is written. 53362224350SCasper H.S. Dik * If the server is not running, check for the log file; 53462224350SCasper H.S. Dik * if there's a non-empty log file, we need to start the server 53562224350SCasper H.S. Dik * as it will incorporate the log file into the contents file. 53662224350SCasper H.S. Dik * And then check if the door is present. If it doesn't, we don't 53762224350SCasper H.S. Dik * need to call it. 53862224350SCasper H.S. Dik */ 53962224350SCasper H.S. Dik 54062224350SCasper H.S. Dik boolean_t 54162224350SCasper H.S. Dik pkgsync_needed(const char *root, const char *sadmdir, boolean_t want_quit) 54262224350SCasper H.S. Dik { 54362224350SCasper H.S. Dik struct stat pbuf; 54462224350SCasper H.S. Dik char pkgfile[PATH_MAX]; 54562224350SCasper H.S. Dik boolean_t sync_needed, running; 54662224350SCasper H.S. Dik int fd; 54762224350SCasper H.S. Dik struct door_info di; 54862224350SCasper H.S. Dik 54962224350SCasper H.S. Dik pkgfilename(pkgfile, root, sadmdir, PKGLOG); 55062224350SCasper H.S. Dik 55162224350SCasper H.S. Dik sync_needed = stat(pkgfile, &pbuf) == 0 && pbuf.st_size > 0; 55262224350SCasper H.S. Dik 55362224350SCasper H.S. Dik if (!sync_needed && !want_quit) 55462224350SCasper H.S. Dik return (B_FALSE); 55562224350SCasper H.S. Dik 55662224350SCasper H.S. Dik pkgfilename(pkgfile, root, sadmdir, PKGDOOR); 55762224350SCasper H.S. Dik 55862224350SCasper H.S. Dik /* sync_needed == B_TRUE || want_quit == B_TRUE */ 55962224350SCasper H.S. Dik running = B_FALSE; 56062224350SCasper H.S. Dik 56162224350SCasper H.S. Dik fd = open(pkgfile, O_RDWR); 56262224350SCasper H.S. Dik 56362224350SCasper H.S. Dik if (fd >= 0) { 56462224350SCasper H.S. Dik if (door_info(fd, &di) == 0) { 56562224350SCasper H.S. Dik /* It's mounted, so the server is likely there */ 56662224350SCasper H.S. Dik running = B_TRUE; 56762224350SCasper H.S. Dik } 56862224350SCasper H.S. Dik (void) close(fd); 56962224350SCasper H.S. Dik } 57062224350SCasper H.S. Dik return (running || sync_needed); 57162224350SCasper H.S. Dik } 57262224350SCasper H.S. Dik 57362224350SCasper H.S. Dik int 57462224350SCasper H.S. Dik pkgsync(const char *root, const char *sadmdir, boolean_t force_quit) 57562224350SCasper H.S. Dik { 57662224350SCasper H.S. Dik void *server; 57762224350SCasper H.S. Dik pkgcmd_t cmd; 57862224350SCasper H.S. Dik 57962224350SCasper H.S. Dik /* No need to write contents file; don't start if not running */ 58062224350SCasper H.S. Dik if (!pkgsync_needed(root, sadmdir, force_quit)) 58162224350SCasper H.S. Dik return (0); 58262224350SCasper H.S. Dik 58362224350SCasper H.S. Dik server = pkgopenserver_i(root, sadmdir, B_FALSE, FLUSH_LOG); 58462224350SCasper H.S. Dik /* 58562224350SCasper H.S. Dik * We're assuming that it started the server and exited immediately. 58662224350SCasper H.S. Dik * If that didn't work, there's nothing we can do. 58762224350SCasper H.S. Dik */ 58862224350SCasper H.S. Dik if (server == NULL) 58962224350SCasper H.S. Dik return (0); 59062224350SCasper H.S. Dik 59162224350SCasper H.S. Dik cmd.cmd = force_quit ? PKG_EXIT : PKG_DUMP; 59262224350SCasper H.S. Dik 59362224350SCasper H.S. Dik (void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL); 59462224350SCasper H.S. Dik (void) pkgcloseserver(server); 59562224350SCasper H.S. Dik return (0); 59662224350SCasper H.S. Dik } 59762224350SCasper H.S. Dik 59862224350SCasper H.S. Dik int 59962224350SCasper H.S. Dik pkgservercommitfile(VFP_T *a_vfp, PKGserver server) 60062224350SCasper H.S. Dik { 60162224350SCasper H.S. Dik size_t len = vfpGetModifiedLen(a_vfp); 60262224350SCasper H.S. Dik ssize_t rem = len; 60362224350SCasper H.S. Dik size_t off; 60462224350SCasper H.S. Dik pkgfilter_t *pcmd; 60562224350SCasper H.S. Dik char *map = a_vfp->_vfpStart; 60662224350SCasper H.S. Dik 60762224350SCasper H.S. Dik if (len < PKGADD_MAX) 60862224350SCasper H.S. Dik pcmd = alloca(sizeof (*pcmd) + len); 60962224350SCasper H.S. Dik else 61062224350SCasper H.S. Dik pcmd = alloca(sizeof (*pcmd) + PKGADD_MAX); 61162224350SCasper H.S. Dik 61262224350SCasper H.S. Dik 61362224350SCasper H.S. Dik off = 0; 61462224350SCasper H.S. Dik pcmd->cmd = PKG_ADDLINES; 61562224350SCasper H.S. Dik while (rem > 0) { 61662224350SCasper H.S. Dik char *p = map + off; 61762224350SCasper H.S. Dik len = rem; 61862224350SCasper H.S. Dik 61962224350SCasper H.S. Dik if (len >= PKGADD_MAX) { 62062224350SCasper H.S. Dik len = PKGADD_MAX - 1; 62162224350SCasper H.S. Dik while (p[len] != '\n' && len > 0) 62262224350SCasper H.S. Dik len--; 62362224350SCasper H.S. Dik if (p[len] != '\n') 62462224350SCasper H.S. Dik return (-1); 62562224350SCasper H.S. Dik len++; 62662224350SCasper H.S. Dik } 62762224350SCasper H.S. Dik (void) memcpy(&pcmd->buf[0], p, len); 62862224350SCasper H.S. Dik pcmd->len = len; 62962224350SCasper H.S. Dik 63062224350SCasper H.S. Dik if (pkgcmd(server, pcmd, sizeof (*pcmd) + len - 1, 63162224350SCasper H.S. Dik NULL, NULL, NULL) != 0) { 63262224350SCasper H.S. Dik return (-1); 63362224350SCasper H.S. Dik } 63462224350SCasper H.S. Dik rem -= len; 63562224350SCasper H.S. Dik off += len; 63662224350SCasper H.S. Dik } 63762224350SCasper H.S. Dik pcmd->len = 0; 63862224350SCasper H.S. Dik pcmd->cmd = PKG_PKGSYNC; 63962224350SCasper H.S. Dik if (pkgcmd(server, pcmd, sizeof (*pcmd), NULL, NULL, NULL) != 0) 64062224350SCasper H.S. Dik return (-1); 64162224350SCasper H.S. Dik 64262224350SCasper H.S. Dik /* Mark it unmodified. */ 64362224350SCasper H.S. Dik vfpTruncate(a_vfp); 64462224350SCasper H.S. Dik (void) vfpClearModified(a_vfp); 64562224350SCasper H.S. Dik 64662224350SCasper H.S. Dik return (0); 64762224350SCasper H.S. Dik } 64862224350SCasper H.S. Dik 64962224350SCasper H.S. Dik int 65062224350SCasper H.S. Dik pkgopenfilter(PKGserver server, const char *filt) 65162224350SCasper H.S. Dik { 65262224350SCasper H.S. Dik int fd; 65362224350SCasper H.S. Dik pkgfilter_t *pfcmd; 65462224350SCasper H.S. Dik int clen = filt == NULL ? 0 : strlen(filt); 65562224350SCasper H.S. Dik int len = sizeof (*pfcmd) + clen; 65662224350SCasper H.S. Dik 65762224350SCasper H.S. Dik pfcmd = alloca(len); 65862224350SCasper H.S. Dik 65962224350SCasper H.S. Dik if (server->fp != NULL) { 66062224350SCasper H.S. Dik (void) fclose(server->fp); 66162224350SCasper H.S. Dik server->fp = NULL; 66262224350SCasper H.S. Dik } 66362224350SCasper H.S. Dik 66462224350SCasper H.S. Dik pfcmd->cmd = PKG_FILTER; 66562224350SCasper H.S. Dik pfcmd->len = clen; 66662224350SCasper H.S. Dik if (filt != NULL) 66762224350SCasper H.S. Dik (void) strcpy(pfcmd->buf, filt); 66862224350SCasper H.S. Dik 66962224350SCasper H.S. Dik fd = -1; 67062224350SCasper H.S. Dik 67162224350SCasper H.S. Dik if (pkgcmd(server, pfcmd, len, NULL, NULL, &fd) != 0 || fd == -1) { 67262224350SCasper H.S. Dik progerr(gettext(ERR_START_FILTER)); 67362224350SCasper H.S. Dik return (-1); 67462224350SCasper H.S. Dik } 67562224350SCasper H.S. Dik (void) fcntl(fd, F_SETFD, FD_CLOEXEC); 67662224350SCasper H.S. Dik 67762224350SCasper H.S. Dik server->fp = fdopen(fd, "r"); 67862224350SCasper H.S. Dik if (server->fp == NULL) { 67962224350SCasper H.S. Dik (void) close(fd); 68062224350SCasper H.S. Dik progerr(gettext(ERR_START_FILTER)); 68162224350SCasper H.S. Dik return (-1); 68262224350SCasper H.S. Dik } 68362224350SCasper H.S. Dik return (0); 68462224350SCasper H.S. Dik } 68562224350SCasper H.S. Dik 68662224350SCasper H.S. Dik void 68762224350SCasper H.S. Dik pkgclosefilter(PKGserver server) 68862224350SCasper H.S. Dik { 68962224350SCasper H.S. Dik if (server->fp != NULL) { 69062224350SCasper H.S. Dik (void) fclose(server->fp); 69162224350SCasper H.S. Dik server->fp = NULL; 69262224350SCasper H.S. Dik } 69362224350SCasper H.S. Dik } 69462224350SCasper H.S. Dik 69562224350SCasper H.S. Dik /* 69662224350SCasper H.S. Dik * Report the next entry from the contents file. 69762224350SCasper H.S. Dik */ 69862224350SCasper H.S. Dik char * 69962224350SCasper H.S. Dik pkggetentry(PKGserver server, int *len, int *pathlen) 70062224350SCasper H.S. Dik { 70162224350SCasper H.S. Dik int num[2]; 70262224350SCasper H.S. Dik 70362224350SCasper H.S. Dik if (server->fp == NULL) 70462224350SCasper H.S. Dik return (NULL); 70562224350SCasper H.S. Dik 70662224350SCasper H.S. Dik if (feof(server->fp) || ferror(server->fp)) 70762224350SCasper H.S. Dik return (NULL); 70862224350SCasper H.S. Dik 70962224350SCasper H.S. Dik if (fread(num, sizeof (int), 2, server->fp) != 2) 71062224350SCasper H.S. Dik return (NULL); 71162224350SCasper H.S. Dik 71262224350SCasper H.S. Dik if (num[0] > server->buflen) { 71362224350SCasper H.S. Dik free(server->curbuf); 71462224350SCasper H.S. Dik server->buflen = num[0]; 71562224350SCasper H.S. Dik server->curbuf = malloc(server->buflen); 71662224350SCasper H.S. Dik if (server->curbuf == NULL) 71762224350SCasper H.S. Dik return (NULL); 71862224350SCasper H.S. Dik } 71962224350SCasper H.S. Dik if (fread(server->curbuf, 1, num[0], server->fp) != num[0]) 72062224350SCasper H.S. Dik return (NULL); 72162224350SCasper H.S. Dik 72262224350SCasper H.S. Dik *len = num[0]; 72362224350SCasper H.S. Dik *pathlen = num[1]; 72462224350SCasper H.S. Dik 72562224350SCasper H.S. Dik return (server->curbuf); 72662224350SCasper H.S. Dik } 72762224350SCasper H.S. Dik 72862224350SCasper H.S. Dik char * 72962224350SCasper H.S. Dik pkggetentry_named(PKGserver server, const char *path, int *len, int *pathlen) 73062224350SCasper H.S. Dik { 73162224350SCasper H.S. Dik int plen = strlen(path); 73262224350SCasper H.S. Dik pkgfilter_t *pcmd = alloca(sizeof (*pcmd) + plen); 73362224350SCasper H.S. Dik char *result; 73462224350SCasper H.S. Dik unsigned int rlen; 73562224350SCasper H.S. Dik 73662224350SCasper H.S. Dik pcmd->cmd = PKG_FINDFILE; 73762224350SCasper H.S. Dik *pathlen = pcmd->len = plen; 73862224350SCasper H.S. Dik (void) memcpy(pcmd->buf, path, pcmd->len + 1); 73962224350SCasper H.S. Dik 74062224350SCasper H.S. Dik result = server->curbuf; 74162224350SCasper H.S. Dik rlen = server->buflen; 74262224350SCasper H.S. Dik 74362224350SCasper H.S. Dik if (pkgcmd(server, pcmd, sizeof (*pcmd) + pcmd->len, 74462224350SCasper H.S. Dik &result, &rlen, NULL) != 0) { 74562224350SCasper H.S. Dik return (NULL); 74662224350SCasper H.S. Dik } 74762224350SCasper H.S. Dik if (rlen == 0) 74862224350SCasper H.S. Dik return (NULL); 74962224350SCasper H.S. Dik 75062224350SCasper H.S. Dik /* Result too big */ 75162224350SCasper H.S. Dik if (result != server->curbuf) { 75262224350SCasper H.S. Dik free(server->curbuf); 75362224350SCasper H.S. Dik server->buflen = rlen; 75462224350SCasper H.S. Dik server->curbuf = malloc(server->buflen); 75562224350SCasper H.S. Dik if (server->curbuf == NULL) 75662224350SCasper H.S. Dik return (NULL); 75762224350SCasper H.S. Dik (void) memcpy(server->curbuf, result, rlen); 75862224350SCasper H.S. Dik (void) munmap(result, rlen); 75962224350SCasper H.S. Dik } 76062224350SCasper H.S. Dik *len = rlen; 76162224350SCasper H.S. Dik 76262224350SCasper H.S. Dik return (server->curbuf); 76362224350SCasper H.S. Dik } 764