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*32991bedSPeter Tribble * Copyright (c) 2017 Peter Tribble.
24*32991bedSPeter Tribble */
25*32991bedSPeter Tribble
26*32991bedSPeter Tribble /*
277706a9bfSCasper H.S. Dik * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
2862224350SCasper H.S. Dik * Use is subject to license terms.
2962224350SCasper H.S. Dik */
3062224350SCasper H.S. Dik
3162224350SCasper H.S. Dik #include <pkglib.h>
3262224350SCasper H.S. Dik
3362224350SCasper H.S. Dik #include <alloca.h>
3462224350SCasper H.S. Dik #include <assert.h>
3562224350SCasper H.S. Dik #include <door.h>
3662224350SCasper H.S. Dik #include <errno.h>
3762224350SCasper H.S. Dik #include <fcntl.h>
3862224350SCasper H.S. Dik #include <pthread.h>
3962224350SCasper H.S. Dik #include <spawn.h>
4062224350SCasper H.S. Dik #include <stdio.h>
4162224350SCasper H.S. Dik #include <stdlib.h>
4262224350SCasper H.S. Dik #include <strings.h>
4362224350SCasper H.S. Dik #include <sys/mman.h>
4462224350SCasper H.S. Dik #include <sys/param.h>
4562224350SCasper H.S. Dik #include <sys/stat.h>
4662224350SCasper H.S. Dik #include <sys/wait.h>
4762224350SCasper H.S. Dik #include <unistd.h>
4862224350SCasper H.S. Dik #include <libintl.h>
497706a9bfSCasper H.S. Dik #include <sys/mnttab.h>
507706a9bfSCasper H.S. Dik #include <sys/mkdev.h>
5162224350SCasper H.S. Dik
5262224350SCasper H.S. Dik #define PKGADD_MAX (512 * 1024)
5362224350SCasper H.S. Dik
5462224350SCasper H.S. Dik #define SADM_DIR "/var/sadm/install"
5562224350SCasper H.S. Dik
5662224350SCasper H.S. Dik #define PKGSERV_PATH "/usr/sadm/install/bin/pkgserv"
5762224350SCasper H.S. Dik
5862224350SCasper H.S. Dik #define ERR_PATH_TOO_BIG "alternate root path is too long"
5962224350SCasper H.S. Dik #define ERR_OPEN_DOOR "cannot open pkgserv door"
6062224350SCasper H.S. Dik #define ERR_START_SERVER "cannot start pkgserv daemon: %s"
6162224350SCasper H.S. Dik #define ERR_START_FILTER "cannot enumerate database entries"
627706a9bfSCasper H.S. Dik #define ERR_FIND_SADM "cannot find sadm directory"
6362224350SCasper H.S. Dik
6462224350SCasper H.S. Dik struct pkg_server {
6562224350SCasper H.S. Dik FILE *fp;
6662224350SCasper H.S. Dik char *curbuf;
6762224350SCasper H.S. Dik int buflen;
6862224350SCasper H.S. Dik int door;
6962224350SCasper H.S. Dik boolean_t onetime;
7062224350SCasper H.S. Dik };
7162224350SCasper H.S. Dik
7262224350SCasper H.S. Dik static PKGserver current_server;
7362224350SCasper H.S. Dik
7462224350SCasper H.S. Dik static start_mode_t defmode = INVALID;
7562224350SCasper H.S. Dik static boolean_t registered = B_FALSE;
7662224350SCasper H.S. Dik static pid_t master_pid = -1;
7762224350SCasper H.S. Dik
7862224350SCasper H.S. Dik static void
pkgfilename(char path[PATH_MAX],const char * root,const char * sadmdir,const char * file)7962224350SCasper H.S. Dik pkgfilename(char path[PATH_MAX], const char *root, const char *sadmdir,
8062224350SCasper H.S. Dik const char *file)
8162224350SCasper H.S. Dik {
8262224350SCasper H.S. Dik if (snprintf(path, PATH_MAX, "%s%s/%s", root == NULL ? "" : root,
8362224350SCasper H.S. Dik sadmdir == NULL ? SADM_DIR : sadmdir, file) >= PATH_MAX) {
8462224350SCasper H.S. Dik progerr(gettext(ERR_PATH_TOO_BIG));
8562224350SCasper H.S. Dik exit(99);
8662224350SCasper H.S. Dik }
8762224350SCasper H.S. Dik }
8862224350SCasper H.S. Dik
8962224350SCasper H.S. Dik static void
free_xmnt(struct extmnttab * xmnt)907706a9bfSCasper H.S. Dik free_xmnt(struct extmnttab *xmnt)
917706a9bfSCasper H.S. Dik {
927706a9bfSCasper H.S. Dik free(xmnt->mnt_special);
937706a9bfSCasper H.S. Dik free(xmnt->mnt_mountp);
947706a9bfSCasper H.S. Dik free(xmnt->mnt_fstype);
957706a9bfSCasper H.S. Dik }
967706a9bfSCasper H.S. Dik
977706a9bfSCasper H.S. Dik static void
copy_xmnt(const struct extmnttab * xmnt,struct extmnttab * saved)987706a9bfSCasper H.S. Dik copy_xmnt(const struct extmnttab *xmnt, struct extmnttab *saved)
997706a9bfSCasper H.S. Dik {
1007706a9bfSCasper H.S. Dik
1017706a9bfSCasper H.S. Dik free_xmnt(saved);
1027706a9bfSCasper H.S. Dik
1037706a9bfSCasper H.S. Dik /*
1047706a9bfSCasper H.S. Dik * Copy everything and then strdup the strings we later use and NULL
1057706a9bfSCasper H.S. Dik * the ones we don't.
1067706a9bfSCasper H.S. Dik */
1077706a9bfSCasper H.S. Dik *saved = *xmnt;
1087706a9bfSCasper H.S. Dik
1097706a9bfSCasper H.S. Dik if (saved->mnt_special != NULL)
1107706a9bfSCasper H.S. Dik saved->mnt_special = strdup(saved->mnt_special);
1117706a9bfSCasper H.S. Dik if (saved->mnt_mountp != NULL)
1127706a9bfSCasper H.S. Dik saved->mnt_mountp = strdup(saved->mnt_mountp);
1137706a9bfSCasper H.S. Dik if (saved->mnt_fstype != NULL)
1147706a9bfSCasper H.S. Dik saved->mnt_fstype = strdup(saved->mnt_fstype);
1157706a9bfSCasper H.S. Dik
1167706a9bfSCasper H.S. Dik saved->mnt_mntopts = NULL;
1177706a9bfSCasper H.S. Dik saved->mnt_time = NULL;
1187706a9bfSCasper H.S. Dik }
1197706a9bfSCasper H.S. Dik
1207706a9bfSCasper H.S. Dik static int
testdoor(char * path)1217706a9bfSCasper H.S. Dik testdoor(char *path)
1227706a9bfSCasper H.S. Dik {
1237706a9bfSCasper H.S. Dik int dir;
1247706a9bfSCasper H.S. Dik int fd;
1257706a9bfSCasper H.S. Dik struct door_info di;
1267706a9bfSCasper H.S. Dik int res;
1277706a9bfSCasper H.S. Dik
1287706a9bfSCasper H.S. Dik dir = open(path, O_RDONLY);
1297706a9bfSCasper H.S. Dik
1307706a9bfSCasper H.S. Dik if (dir == -1)
1317706a9bfSCasper H.S. Dik return (-1);
1327706a9bfSCasper H.S. Dik
1337706a9bfSCasper H.S. Dik fd = openat(dir, PKGDOOR, O_RDWR);
1347706a9bfSCasper H.S. Dik (void) close(dir);
1357706a9bfSCasper H.S. Dik if (fd == -1)
1367706a9bfSCasper H.S. Dik return (-1);
1377706a9bfSCasper H.S. Dik
1387706a9bfSCasper H.S. Dik res = door_info(fd, &di);
1397706a9bfSCasper H.S. Dik (void) close(fd);
1407706a9bfSCasper H.S. Dik return (res);
1417706a9bfSCasper H.S. Dik }
1427706a9bfSCasper H.S. Dik
1437706a9bfSCasper H.S. Dik /*
1447706a9bfSCasper H.S. Dik * We need to make sure that we can locate the pkgserv and the door;
1457706a9bfSCasper H.S. Dik * lofs mounts makes this more difficult: "nosub" mounts don't propagate
1467706a9bfSCasper H.S. Dik * the door and doors created in lofs mounts are not propagated back to
1477706a9bfSCasper H.S. Dik * the original filesystem.
1487706a9bfSCasper H.S. Dik * Here we peel off the lofs mount points until we're
1497706a9bfSCasper H.S. Dik * at /var/sadm/install or
1507706a9bfSCasper H.S. Dik * we find a working door or
1517706a9bfSCasper H.S. Dik * there's nothing more to peel off.
1527706a9bfSCasper H.S. Dik * The fullpath parameter is used to return the result (stored in *sadmdir),
1537706a9bfSCasper H.S. Dik * root is used but returned in the computed sadmdir and so the caller should
1547706a9bfSCasper H.S. Dik * not use "root" any longer or set it to NULL.
1557706a9bfSCasper H.S. Dik */
1567706a9bfSCasper H.S. Dik static void
pkgfindrealsadmdir(char fullpath[PATH_MAX],const char * root,const char ** sadmdir)1577706a9bfSCasper H.S. Dik pkgfindrealsadmdir(char fullpath[PATH_MAX], const char *root,
1587706a9bfSCasper H.S. Dik const char **sadmdir)
1597706a9bfSCasper H.S. Dik {
1607706a9bfSCasper H.S. Dik struct stat buf;
1617706a9bfSCasper H.S. Dik struct extmnttab xmnt;
1627706a9bfSCasper H.S. Dik FILE *mnttab = NULL;
1637706a9bfSCasper H.S. Dik char temp[PATH_MAX];
1647706a9bfSCasper H.S. Dik struct extmnttab saved = {NULL, NULL, NULL, NULL, NULL, 0, 0};
1657706a9bfSCasper H.S. Dik
1667706a9bfSCasper H.S. Dik if (snprintf(temp, PATH_MAX, "%s%s",
1677706a9bfSCasper H.S. Dik root == NULL ? "" : root,
1687706a9bfSCasper H.S. Dik *sadmdir == NULL ? SADM_DIR : *sadmdir) >= PATH_MAX) {
1697706a9bfSCasper H.S. Dik progerr(gettext(ERR_PATH_TOO_BIG));
1707706a9bfSCasper H.S. Dik exit(99);
1717706a9bfSCasper H.S. Dik }
1727706a9bfSCasper H.S. Dik
1737706a9bfSCasper H.S. Dik if (stat(temp, &buf) != 0) {
1747706a9bfSCasper H.S. Dik progerr(gettext(ERR_FIND_SADM));
1757706a9bfSCasper H.S. Dik exit(99);
1767706a9bfSCasper H.S. Dik }
1777706a9bfSCasper H.S. Dik
1787706a9bfSCasper H.S. Dik /*
1797706a9bfSCasper H.S. Dik * To find the underlying mount point, you will need to
1807706a9bfSCasper H.S. Dik * search the mnttab and find our mountpoint and the underlying
1817706a9bfSCasper H.S. Dik * filesystem.
1827706a9bfSCasper H.S. Dik * To find the mount point: use the longest prefix but limit
1837706a9bfSCasper H.S. Dik * us to the filesystems with the same major/minor numbers.
1847706a9bfSCasper H.S. Dik * To find the underlying mount point: find a non-lofs file
1857706a9bfSCasper H.S. Dik * system or a <mnt> <mnt> entry (fake mountpoint for zones).
1867706a9bfSCasper H.S. Dik */
1877706a9bfSCasper H.S. Dik for (;;) {
1887706a9bfSCasper H.S. Dik size_t max = 0;
1897706a9bfSCasper H.S. Dik
1907706a9bfSCasper H.S. Dik if (realpath(temp, fullpath) == NULL) {
1917706a9bfSCasper H.S. Dik progerr(gettext(ERR_FIND_SADM));
1927706a9bfSCasper H.S. Dik exit(99);
1937706a9bfSCasper H.S. Dik }
1947706a9bfSCasper H.S. Dik
1957706a9bfSCasper H.S. Dik if (strcmp(fullpath, SADM_DIR) == 0)
1967706a9bfSCasper H.S. Dik break;
1977706a9bfSCasper H.S. Dik
1987706a9bfSCasper H.S. Dik if (testdoor(fullpath) == 0)
1997706a9bfSCasper H.S. Dik break;
2007706a9bfSCasper H.S. Dik
2017706a9bfSCasper H.S. Dik if (mnttab == NULL)
2027706a9bfSCasper H.S. Dik mnttab = fopen(MNTTAB, "r");
2037706a9bfSCasper H.S. Dik else
2047706a9bfSCasper H.S. Dik resetmnttab(mnttab);
2057706a9bfSCasper H.S. Dik
2067706a9bfSCasper H.S. Dik while (getextmntent(mnttab, &xmnt, 0) == 0) {
2077706a9bfSCasper H.S. Dik size_t len;
2087706a9bfSCasper H.S. Dik
2097706a9bfSCasper H.S. Dik if (major(buf.st_dev) != xmnt.mnt_major ||
2107706a9bfSCasper H.S. Dik minor(buf.st_dev) != xmnt.mnt_minor)
2117706a9bfSCasper H.S. Dik continue;
2127706a9bfSCasper H.S. Dik
2137706a9bfSCasper H.S. Dik len = strlen(xmnt.mnt_mountp);
2147706a9bfSCasper H.S. Dik if (len < max)
2157706a9bfSCasper H.S. Dik continue;
2167706a9bfSCasper H.S. Dik
2177706a9bfSCasper H.S. Dik if (strncmp(xmnt.mnt_mountp, fullpath, len) == 0 &&
2187706a9bfSCasper H.S. Dik (len == 1 || fullpath[len] == '/' ||
2197706a9bfSCasper H.S. Dik fullpath[len] == '\0')) {
2207706a9bfSCasper H.S. Dik max = len;
2217706a9bfSCasper H.S. Dik copy_xmnt(&xmnt, &saved);
2227706a9bfSCasper H.S. Dik }
2237706a9bfSCasper H.S. Dik }
2247706a9bfSCasper H.S. Dik if (strcmp(saved.mnt_fstype, "lofs") != 0 ||
2257706a9bfSCasper H.S. Dik strcmp(saved.mnt_mountp, saved.mnt_special) == 0) {
2267706a9bfSCasper H.S. Dik break;
2277706a9bfSCasper H.S. Dik }
2287706a9bfSCasper H.S. Dik /* Create a new path in the underlying filesystem. */
2297706a9bfSCasper H.S. Dik if (snprintf(temp, PATH_MAX, "%s%s", saved.mnt_special,
2307706a9bfSCasper H.S. Dik &fullpath[max]) >= PATH_MAX) {
2317706a9bfSCasper H.S. Dik progerr(gettext(ERR_PATH_TOO_BIG));
2327706a9bfSCasper H.S. Dik exit(99);
2337706a9bfSCasper H.S. Dik }
2347706a9bfSCasper H.S. Dik }
2357706a9bfSCasper H.S. Dik
2367706a9bfSCasper H.S. Dik if (mnttab != NULL) {
2377706a9bfSCasper H.S. Dik free_xmnt(&saved);
2387706a9bfSCasper H.S. Dik (void) fclose(mnttab);
2397706a9bfSCasper H.S. Dik }
2407706a9bfSCasper H.S. Dik *sadmdir = fullpath;
2417706a9bfSCasper H.S. Dik }
2427706a9bfSCasper H.S. Dik
2437706a9bfSCasper H.S. Dik static void
pkgexit_close(void)24462224350SCasper H.S. Dik pkgexit_close(void)
24562224350SCasper H.S. Dik {
24662224350SCasper H.S. Dik if (current_server != NULL)
24762224350SCasper H.S. Dik pkgcloseserver(current_server);
24862224350SCasper H.S. Dik }
24962224350SCasper H.S. Dik
25062224350SCasper H.S. Dik static PKGserver
pkgopenserver_i(const char * root,const char * sadmdir,boolean_t readonly,start_mode_t mode)25162224350SCasper H.S. Dik pkgopenserver_i(const char *root, const char *sadmdir, boolean_t readonly,
25262224350SCasper H.S. Dik start_mode_t mode)
25362224350SCasper H.S. Dik {
25462224350SCasper H.S. Dik PKGserver server;
25562224350SCasper H.S. Dik struct door_info di;
25662224350SCasper H.S. Dik pid_t pid;
25762224350SCasper H.S. Dik int stat;
25862224350SCasper H.S. Dik int first = B_TRUE;
25962224350SCasper H.S. Dik char *cmd[16];
26062224350SCasper H.S. Dik int args;
26162224350SCasper H.S. Dik char pkgdoor[PATH_MAX];
2627706a9bfSCasper H.S. Dik char realsadmdir[PATH_MAX];
26362224350SCasper H.S. Dik extern char **environ;
26462224350SCasper H.S. Dik char *prog;
26562224350SCasper H.S. Dik char pidbuf[12];
26662224350SCasper H.S. Dik
26762224350SCasper H.S. Dik if (current_server != NULL)
26862224350SCasper H.S. Dik return (current_server);
26962224350SCasper H.S. Dik
27062224350SCasper H.S. Dik if (!registered) {
27162224350SCasper H.S. Dik registered = B_TRUE;
27262224350SCasper H.S. Dik (void) atexit(pkgexit_close);
27362224350SCasper H.S. Dik }
27462224350SCasper H.S. Dik if (readonly) {
27562224350SCasper H.S. Dik int fd;
27662224350SCasper H.S. Dik
27762224350SCasper H.S. Dik (void) strcpy(pkgdoor, "/tmp/pkgdoor.XXXXXX");
27862224350SCasper H.S. Dik if ((fd = mkstemp(pkgdoor)) < 0) {
27962224350SCasper H.S. Dik progerr(gettext(ERR_OPEN_DOOR));
28062224350SCasper H.S. Dik return (NULL);
28162224350SCasper H.S. Dik }
28262224350SCasper H.S. Dik (void) close(fd);
28362224350SCasper H.S. Dik } else {
2847706a9bfSCasper H.S. Dik pkgfindrealsadmdir(realsadmdir, root, &sadmdir);
2857706a9bfSCasper H.S. Dik root = NULL;
28662224350SCasper H.S. Dik pkgfilename(pkgdoor, root, sadmdir, PKGDOOR);
28762224350SCasper H.S. Dik }
28862224350SCasper H.S. Dik
28962224350SCasper H.S. Dik server = malloc(sizeof (*server));
29062224350SCasper H.S. Dik
29162224350SCasper H.S. Dik if (server == NULL)
29262224350SCasper H.S. Dik goto return_null;
29362224350SCasper H.S. Dik
29462224350SCasper H.S. Dik server->fp = NULL;
29562224350SCasper H.S. Dik server->onetime = readonly;
29662224350SCasper H.S. Dik
29762224350SCasper H.S. Dik openserver:
29862224350SCasper H.S. Dik server->door = open(pkgdoor, O_RDWR);
29962224350SCasper H.S. Dik
30062224350SCasper H.S. Dik if (server->door >= 0) {
30162224350SCasper H.S. Dik if (door_info(server->door, &di) == 0 && di.di_target >= 0) {
30262224350SCasper H.S. Dik pkgcmd_t n;
30362224350SCasper H.S. Dik n.cmd = PKG_NOP;
30462224350SCasper H.S. Dik server->buflen = 1024;
30562224350SCasper H.S. Dik server->curbuf = malloc(1024);
30662224350SCasper H.S. Dik if (server->curbuf == NULL ||
30762224350SCasper H.S. Dik pkgcmd(server, &n, sizeof (n), NULL, NULL, NULL)) {
30862224350SCasper H.S. Dik pkgcloseserver(server);
30962224350SCasper H.S. Dik return (NULL);
31062224350SCasper H.S. Dik }
31162224350SCasper H.S. Dik return (current_server = server);
31262224350SCasper H.S. Dik }
31362224350SCasper H.S. Dik
31462224350SCasper H.S. Dik (void) close(server->door);
31562224350SCasper H.S. Dik }
31662224350SCasper H.S. Dik
31762224350SCasper H.S. Dik if (!first || mode == NEVER)
31862224350SCasper H.S. Dik goto return_null;
31962224350SCasper H.S. Dik
32062224350SCasper H.S. Dik first = B_FALSE;
32162224350SCasper H.S. Dik
32262224350SCasper H.S. Dik args = 0;
32362224350SCasper H.S. Dik cmd[args++] = strrchr(PKGSERV_PATH, '/') + 1;
32462224350SCasper H.S. Dik if (root != NULL && strcmp(root, "/") != 0) {
32562224350SCasper H.S. Dik cmd[args++] = "-R";
32662224350SCasper H.S. Dik cmd[args++] = (char *)root;
32762224350SCasper H.S. Dik }
32862224350SCasper H.S. Dik if (sadmdir != NULL && strcmp(sadmdir, SADM_DIR) != 0) {
32962224350SCasper H.S. Dik cmd[args++] = "-d";
33062224350SCasper H.S. Dik cmd[args++] = (char *)sadmdir;
33162224350SCasper H.S. Dik }
33262224350SCasper H.S. Dik if (readonly) {
33362224350SCasper H.S. Dik cmd[args++] = "-r";
33462224350SCasper H.S. Dik cmd[args++] = pkgdoor;
33562224350SCasper H.S. Dik }
33662224350SCasper H.S. Dik prog = get_prog_name();
33762224350SCasper H.S. Dik if (prog != NULL) {
33862224350SCasper H.S. Dik cmd[args++] = "-N";
33962224350SCasper H.S. Dik cmd[args++] = prog;
34062224350SCasper H.S. Dik }
34162224350SCasper H.S. Dik
34262224350SCasper H.S. Dik switch (mode) {
34362224350SCasper H.S. Dik case FLUSH_LOG:
34462224350SCasper H.S. Dik cmd[args++] = "-e";
34562224350SCasper H.S. Dik break;
34662224350SCasper H.S. Dik case RUN_ONCE:
34762224350SCasper H.S. Dik cmd[args++] = "-o";
34862224350SCasper H.S. Dik break;
34962224350SCasper H.S. Dik case PERMANENT:
35062224350SCasper H.S. Dik cmd[args++] = "-p";
35162224350SCasper H.S. Dik break;
35262224350SCasper H.S. Dik default:
35362224350SCasper H.S. Dik break;
35462224350SCasper H.S. Dik }
35562224350SCasper H.S. Dik
35662224350SCasper H.S. Dik if (master_pid != -1) {
35762224350SCasper H.S. Dik cmd[args++] = "-P";
35862224350SCasper H.S. Dik (void) snprintf(pidbuf, sizeof (pidbuf), "%d", master_pid);
35962224350SCasper H.S. Dik cmd[args++] = pidbuf;
36062224350SCasper H.S. Dik }
36162224350SCasper H.S. Dik cmd[args++] = NULL;
36262224350SCasper H.S. Dik assert(args <= sizeof (cmd)/sizeof (char *));
36362224350SCasper H.S. Dik
36462224350SCasper H.S. Dik if (posix_spawn(&pid, PKGSERV_PATH, NULL, NULL, cmd, environ) == 0) {
3654656d474SGarrett D'Amore server->onetime |= (mode == RUN_ONCE);
36662224350SCasper H.S. Dik while (wait4(pid, &stat, 0, NULL) != -1) {
36762224350SCasper H.S. Dik if (WIFEXITED(stat)) {
36862224350SCasper H.S. Dik int s = WEXITSTATUS(stat);
36962224350SCasper H.S. Dik if (s == 0 || s == 1)
37062224350SCasper H.S. Dik if (mode == FLUSH_LOG)
37162224350SCasper H.S. Dik goto return_null;
37262224350SCasper H.S. Dik else
37362224350SCasper H.S. Dik goto openserver;
37462224350SCasper H.S. Dik if (s == 2)
37562224350SCasper H.S. Dik goto return_null;
37662224350SCasper H.S. Dik break;
37762224350SCasper H.S. Dik } else if (WIFSIGNALED(stat)) {
37862224350SCasper H.S. Dik break;
37962224350SCasper H.S. Dik }
38062224350SCasper H.S. Dik }
38162224350SCasper H.S. Dik }
38262224350SCasper H.S. Dik
38362224350SCasper H.S. Dik progerr(gettext(ERR_START_SERVER), strerror(errno));
38462224350SCasper H.S. Dik
38562224350SCasper H.S. Dik return_null:
38662224350SCasper H.S. Dik if (readonly)
38762224350SCasper H.S. Dik (void) unlink(pkgdoor);
38862224350SCasper H.S. Dik free(server);
38962224350SCasper H.S. Dik return (NULL);
39062224350SCasper H.S. Dik }
39162224350SCasper H.S. Dik
39262224350SCasper H.S. Dik PKGserver
pkgopenserver(const char * root,const char * sadmdir,boolean_t ro)39362224350SCasper H.S. Dik pkgopenserver(const char *root, const char *sadmdir, boolean_t ro)
39462224350SCasper H.S. Dik {
39562224350SCasper H.S. Dik return (pkgopenserver_i(root, sadmdir, ro, pkgservergetmode()));
39662224350SCasper H.S. Dik }
39762224350SCasper H.S. Dik
39862224350SCasper H.S. Dik start_mode_t
pkgparsemode(const char * mode)39962224350SCasper H.S. Dik pkgparsemode(const char *mode)
40062224350SCasper H.S. Dik {
40162224350SCasper H.S. Dik if (strcasecmp(mode, MODE_PERMANENT) == 0) {
40262224350SCasper H.S. Dik return (PERMANENT);
40362224350SCasper H.S. Dik } else if (strncasecmp(mode, MODE_TIMEOUT,
40462224350SCasper H.S. Dik sizeof (MODE_TIMEOUT) - 1) == 0) {
40562224350SCasper H.S. Dik const char *pidstr = mode + sizeof (MODE_TIMEOUT) - 1;
40662224350SCasper H.S. Dik if (pidstr[0] != '\0') {
40762224350SCasper H.S. Dik master_pid = atoi(pidstr);
40862224350SCasper H.S. Dik if (master_pid <= 1 || kill(master_pid, 0) != 0)
40962224350SCasper H.S. Dik master_pid = -1;
41062224350SCasper H.S. Dik }
41162224350SCasper H.S. Dik
41262224350SCasper H.S. Dik return (TIMEOUT);
41362224350SCasper H.S. Dik } else if (strcasecmp(mode, MODE_RUN_ONCE) == 0) {
41462224350SCasper H.S. Dik return (RUN_ONCE);
41562224350SCasper H.S. Dik } else {
41662224350SCasper H.S. Dik progerr(gettext("invalid pkgserver mode: %s"), mode);
41762224350SCasper H.S. Dik exit(99);
41862224350SCasper H.S. Dik /*NOTREACHED*/
41962224350SCasper H.S. Dik }
42062224350SCasper H.S. Dik }
42162224350SCasper H.S. Dik
42262224350SCasper H.S. Dik char *
pkgmodeargument(start_mode_t mode)42362224350SCasper H.S. Dik pkgmodeargument(start_mode_t mode)
42462224350SCasper H.S. Dik {
42562224350SCasper H.S. Dik static char timebuf[sizeof (PKGSERV_MODE) + sizeof (MODE_TIMEOUT) + 10];
42662224350SCasper H.S. Dik
42762224350SCasper H.S. Dik switch (mode) {
42862224350SCasper H.S. Dik case PERMANENT:
42962224350SCasper H.S. Dik return (PKGSERV_MODE MODE_PERMANENT);
43062224350SCasper H.S. Dik case TIMEOUT:
43162224350SCasper H.S. Dik (void) snprintf(timebuf, sizeof (timebuf),
43262224350SCasper H.S. Dik PKGSERV_MODE MODE_TIMEOUT "%d",
43362224350SCasper H.S. Dik (master_pid > 1 && kill(master_pid, 0) == 0) ? master_pid :
43462224350SCasper H.S. Dik getpid());
43562224350SCasper H.S. Dik return (timebuf);
43662224350SCasper H.S. Dik case RUN_ONCE:
43762224350SCasper H.S. Dik return (PKGSERV_MODE MODE_RUN_ONCE);
43862224350SCasper H.S. Dik }
43962224350SCasper H.S. Dik progerr(gettext("Bad pkgserv mode: %d"), (int)mode);
44062224350SCasper H.S. Dik exit(99);
4414656d474SGarrett D'Amore /*NOTREACHED*/
44262224350SCasper H.S. Dik }
44362224350SCasper H.S. Dik
44462224350SCasper H.S. Dik void
pkgserversetmode(start_mode_t mode)44562224350SCasper H.S. Dik pkgserversetmode(start_mode_t mode)
44662224350SCasper H.S. Dik {
44762224350SCasper H.S. Dik if (mode == DEFAULTMODE || mode == INVALID) {
44862224350SCasper H.S. Dik char *var = getenv(SUNW_PKG_SERVERMODE);
44962224350SCasper H.S. Dik
45062224350SCasper H.S. Dik if (var != NULL)
45162224350SCasper H.S. Dik defmode = pkgparsemode(var);
45262224350SCasper H.S. Dik else
45362224350SCasper H.S. Dik defmode = DEFAULTMODE;
45462224350SCasper H.S. Dik } else {
45562224350SCasper H.S. Dik defmode = mode;
45662224350SCasper H.S. Dik }
45762224350SCasper H.S. Dik }
45862224350SCasper H.S. Dik
45962224350SCasper H.S. Dik start_mode_t
pkgservergetmode(void)46062224350SCasper H.S. Dik pkgservergetmode(void)
46162224350SCasper H.S. Dik {
46262224350SCasper H.S. Dik if (defmode == INVALID)
46362224350SCasper H.S. Dik pkgserversetmode(DEFAULTMODE);
46462224350SCasper H.S. Dik return (defmode);
46562224350SCasper H.S. Dik }
46662224350SCasper H.S. Dik
46762224350SCasper H.S. Dik void
pkgcloseserver(PKGserver server)46862224350SCasper H.S. Dik pkgcloseserver(PKGserver server)
46962224350SCasper H.S. Dik {
47062224350SCasper H.S. Dik
47162224350SCasper H.S. Dik if (server->fp != NULL)
47262224350SCasper H.S. Dik (void) fclose(server->fp);
47362224350SCasper H.S. Dik free(server->curbuf);
47462224350SCasper H.S. Dik if (server->onetime) {
47562224350SCasper H.S. Dik pkgcmd_t cmd;
47662224350SCasper H.S. Dik cmd.cmd = PKG_EXIT;
47762224350SCasper H.S. Dik (void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL);
47862224350SCasper H.S. Dik }
47962224350SCasper H.S. Dik (void) close(server->door);
48062224350SCasper H.S. Dik if (server == current_server)
48162224350SCasper H.S. Dik current_server = NULL;
48262224350SCasper H.S. Dik free(server);
48362224350SCasper H.S. Dik }
48462224350SCasper H.S. Dik
48562224350SCasper H.S. Dik int
pkgcmd(PKGserver srv,void * cmd,size_t len,char ** result,size_t * rlen,int * fd)48662224350SCasper H.S. Dik pkgcmd(PKGserver srv, void *cmd, size_t len, char **result, size_t *rlen,
48762224350SCasper H.S. Dik int *fd)
48862224350SCasper H.S. Dik {
48962224350SCasper H.S. Dik door_arg_t da;
49062224350SCasper H.S. Dik
49162224350SCasper H.S. Dik da.data_ptr = cmd;
49262224350SCasper H.S. Dik da.data_size = len;
49362224350SCasper H.S. Dik da.desc_ptr = NULL;
49462224350SCasper H.S. Dik da.desc_num = 0;
49562224350SCasper H.S. Dik da.rbuf = result == NULL ? NULL : *result;
49662224350SCasper H.S. Dik da.rsize = rlen == NULL ? 0 : *rlen;
49762224350SCasper H.S. Dik
49862224350SCasper H.S. Dik if (door_call(srv->door, &da) != 0) {
49962224350SCasper H.S. Dik if (((pkgcmd_t *)cmd)->cmd == PKG_EXIT && errno == EINTR)
50062224350SCasper H.S. Dik return (0);
50162224350SCasper H.S. Dik return (-1);
50262224350SCasper H.S. Dik }
50362224350SCasper H.S. Dik
50462224350SCasper H.S. Dik if (da.desc_ptr != NULL) {
50562224350SCasper H.S. Dik int i = 0;
50662224350SCasper H.S. Dik if (fd != NULL)
50762224350SCasper H.S. Dik *fd = da.desc_ptr[i++].d_data.d_desc.d_descriptor;
50862224350SCasper H.S. Dik for (; i < da.desc_num; i++)
50962224350SCasper H.S. Dik (void) close(da.desc_ptr[i].d_data.d_desc.d_descriptor);
51062224350SCasper H.S. Dik }
51162224350SCasper H.S. Dik /* Error return */
51262224350SCasper H.S. Dik if (da.data_size == sizeof (int)) {
513*32991bedSPeter Tribble /* LINTED */
51462224350SCasper H.S. Dik int x = *(int *)da.data_ptr;
51562224350SCasper H.S. Dik if (x != 0) {
51662224350SCasper H.S. Dik if (result == NULL || da.rbuf != *result)
51762224350SCasper H.S. Dik (void) munmap(da.rbuf, da.rsize);
51862224350SCasper H.S. Dik return (x);
51962224350SCasper H.S. Dik }
52062224350SCasper H.S. Dik }
52162224350SCasper H.S. Dik
52262224350SCasper H.S. Dik /* Other result */
52362224350SCasper H.S. Dik if (result != NULL) {
52462224350SCasper H.S. Dik /* Make sure that the result is at the start of the buffer. */
52562224350SCasper H.S. Dik if (da.data_ptr != NULL && da.rbuf != da.data_ptr)
52662224350SCasper H.S. Dik (void) memmove(da.rbuf, da.data_ptr, da.data_size);
52762224350SCasper H.S. Dik *result = da.rbuf;
52862224350SCasper H.S. Dik *rlen = da.data_size;
52962224350SCasper H.S. Dik } else if (da.rbuf != NULL) {
53062224350SCasper H.S. Dik (void) munmap(da.rbuf, da.rsize);
53162224350SCasper H.S. Dik }
53262224350SCasper H.S. Dik return (0);
53362224350SCasper H.S. Dik }
53462224350SCasper H.S. Dik
53562224350SCasper H.S. Dik /*
53662224350SCasper H.S. Dik * Pkgsync:
53762224350SCasper H.S. Dik * If the server is running, make sure that the contents
53862224350SCasper H.S. Dik * file is written.
53962224350SCasper H.S. Dik * If the server is not running, check for the log file;
54062224350SCasper H.S. Dik * if there's a non-empty log file, we need to start the server
54162224350SCasper H.S. Dik * as it will incorporate the log file into the contents file.
54262224350SCasper H.S. Dik * And then check if the door is present. If it doesn't, we don't
54362224350SCasper H.S. Dik * need to call it.
54462224350SCasper H.S. Dik */
54562224350SCasper H.S. Dik
54662224350SCasper H.S. Dik boolean_t
pkgsync_needed(const char * root,const char * sadmdir,boolean_t want_quit)54762224350SCasper H.S. Dik pkgsync_needed(const char *root, const char *sadmdir, boolean_t want_quit)
54862224350SCasper H.S. Dik {
54962224350SCasper H.S. Dik struct stat pbuf;
55062224350SCasper H.S. Dik char pkgfile[PATH_MAX];
55162224350SCasper H.S. Dik boolean_t sync_needed, running;
55262224350SCasper H.S. Dik int fd;
55362224350SCasper H.S. Dik struct door_info di;
55462224350SCasper H.S. Dik
55562224350SCasper H.S. Dik pkgfilename(pkgfile, root, sadmdir, PKGLOG);
55662224350SCasper H.S. Dik
55762224350SCasper H.S. Dik sync_needed = stat(pkgfile, &pbuf) == 0 && pbuf.st_size > 0;
55862224350SCasper H.S. Dik
55962224350SCasper H.S. Dik if (!sync_needed && !want_quit)
56062224350SCasper H.S. Dik return (B_FALSE);
56162224350SCasper H.S. Dik
56262224350SCasper H.S. Dik pkgfilename(pkgfile, root, sadmdir, PKGDOOR);
56362224350SCasper H.S. Dik
56462224350SCasper H.S. Dik /* sync_needed == B_TRUE || want_quit == B_TRUE */
56562224350SCasper H.S. Dik running = B_FALSE;
56662224350SCasper H.S. Dik
56762224350SCasper H.S. Dik fd = open(pkgfile, O_RDWR);
56862224350SCasper H.S. Dik
56962224350SCasper H.S. Dik if (fd >= 0) {
57062224350SCasper H.S. Dik if (door_info(fd, &di) == 0) {
57162224350SCasper H.S. Dik /* It's mounted, so the server is likely there */
57262224350SCasper H.S. Dik running = B_TRUE;
57362224350SCasper H.S. Dik }
57462224350SCasper H.S. Dik (void) close(fd);
57562224350SCasper H.S. Dik }
57662224350SCasper H.S. Dik return (running || sync_needed);
57762224350SCasper H.S. Dik }
57862224350SCasper H.S. Dik
57962224350SCasper H.S. Dik int
pkgsync(const char * root,const char * sadmdir,boolean_t force_quit)58062224350SCasper H.S. Dik pkgsync(const char *root, const char *sadmdir, boolean_t force_quit)
58162224350SCasper H.S. Dik {
58262224350SCasper H.S. Dik void *server;
58362224350SCasper H.S. Dik pkgcmd_t cmd;
58462224350SCasper H.S. Dik
58562224350SCasper H.S. Dik /* No need to write contents file; don't start if not running */
58662224350SCasper H.S. Dik if (!pkgsync_needed(root, sadmdir, force_quit))
58762224350SCasper H.S. Dik return (0);
58862224350SCasper H.S. Dik
58962224350SCasper H.S. Dik server = pkgopenserver_i(root, sadmdir, B_FALSE, FLUSH_LOG);
59062224350SCasper H.S. Dik /*
59162224350SCasper H.S. Dik * We're assuming that it started the server and exited immediately.
59262224350SCasper H.S. Dik * If that didn't work, there's nothing we can do.
59362224350SCasper H.S. Dik */
59462224350SCasper H.S. Dik if (server == NULL)
59562224350SCasper H.S. Dik return (0);
59662224350SCasper H.S. Dik
59762224350SCasper H.S. Dik cmd.cmd = force_quit ? PKG_EXIT : PKG_DUMP;
59862224350SCasper H.S. Dik
59962224350SCasper H.S. Dik (void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL);
60062224350SCasper H.S. Dik (void) pkgcloseserver(server);
60162224350SCasper H.S. Dik return (0);
60262224350SCasper H.S. Dik }
60362224350SCasper H.S. Dik
60462224350SCasper H.S. Dik int
pkgservercommitfile(VFP_T * a_vfp,PKGserver server)60562224350SCasper H.S. Dik pkgservercommitfile(VFP_T *a_vfp, PKGserver server)
60662224350SCasper H.S. Dik {
60762224350SCasper H.S. Dik size_t len = vfpGetModifiedLen(a_vfp);
60862224350SCasper H.S. Dik ssize_t rem = len;
60962224350SCasper H.S. Dik size_t off;
61062224350SCasper H.S. Dik pkgfilter_t *pcmd;
61162224350SCasper H.S. Dik char *map = a_vfp->_vfpStart;
61262224350SCasper H.S. Dik
61362224350SCasper H.S. Dik if (len < PKGADD_MAX)
61462224350SCasper H.S. Dik pcmd = alloca(sizeof (*pcmd) + len);
61562224350SCasper H.S. Dik else
61662224350SCasper H.S. Dik pcmd = alloca(sizeof (*pcmd) + PKGADD_MAX);
61762224350SCasper H.S. Dik
61862224350SCasper H.S. Dik
61962224350SCasper H.S. Dik off = 0;
62062224350SCasper H.S. Dik pcmd->cmd = PKG_ADDLINES;
62162224350SCasper H.S. Dik while (rem > 0) {
62262224350SCasper H.S. Dik char *p = map + off;
62362224350SCasper H.S. Dik len = rem;
62462224350SCasper H.S. Dik
62562224350SCasper H.S. Dik if (len >= PKGADD_MAX) {
62662224350SCasper H.S. Dik len = PKGADD_MAX - 1;
62762224350SCasper H.S. Dik while (p[len] != '\n' && len > 0)
62862224350SCasper H.S. Dik len--;
62962224350SCasper H.S. Dik if (p[len] != '\n')
63062224350SCasper H.S. Dik return (-1);
63162224350SCasper H.S. Dik len++;
63262224350SCasper H.S. Dik }
63362224350SCasper H.S. Dik (void) memcpy(&pcmd->buf[0], p, len);
63462224350SCasper H.S. Dik pcmd->len = len;
63562224350SCasper H.S. Dik
63662224350SCasper H.S. Dik if (pkgcmd(server, pcmd, sizeof (*pcmd) + len - 1,
63762224350SCasper H.S. Dik NULL, NULL, NULL) != 0) {
63862224350SCasper H.S. Dik return (-1);
63962224350SCasper H.S. Dik }
64062224350SCasper H.S. Dik rem -= len;
64162224350SCasper H.S. Dik off += len;
64262224350SCasper H.S. Dik }
64362224350SCasper H.S. Dik pcmd->len = 0;
64462224350SCasper H.S. Dik pcmd->cmd = PKG_PKGSYNC;
64562224350SCasper H.S. Dik if (pkgcmd(server, pcmd, sizeof (*pcmd), NULL, NULL, NULL) != 0)
64662224350SCasper H.S. Dik return (-1);
64762224350SCasper H.S. Dik
64862224350SCasper H.S. Dik /* Mark it unmodified. */
64962224350SCasper H.S. Dik vfpTruncate(a_vfp);
65062224350SCasper H.S. Dik (void) vfpClearModified(a_vfp);
65162224350SCasper H.S. Dik
65262224350SCasper H.S. Dik return (0);
65362224350SCasper H.S. Dik }
65462224350SCasper H.S. Dik
65562224350SCasper H.S. Dik int
pkgopenfilter(PKGserver server,const char * filt)65662224350SCasper H.S. Dik pkgopenfilter(PKGserver server, const char *filt)
65762224350SCasper H.S. Dik {
65862224350SCasper H.S. Dik int fd;
65962224350SCasper H.S. Dik pkgfilter_t *pfcmd;
66062224350SCasper H.S. Dik int clen = filt == NULL ? 0 : strlen(filt);
66162224350SCasper H.S. Dik int len = sizeof (*pfcmd) + clen;
66262224350SCasper H.S. Dik
66362224350SCasper H.S. Dik pfcmd = alloca(len);
66462224350SCasper H.S. Dik
66562224350SCasper H.S. Dik if (server->fp != NULL) {
66662224350SCasper H.S. Dik (void) fclose(server->fp);
66762224350SCasper H.S. Dik server->fp = NULL;
66862224350SCasper H.S. Dik }
66962224350SCasper H.S. Dik
67062224350SCasper H.S. Dik pfcmd->cmd = PKG_FILTER;
67162224350SCasper H.S. Dik pfcmd->len = clen;
67262224350SCasper H.S. Dik if (filt != NULL)
67362224350SCasper H.S. Dik (void) strcpy(pfcmd->buf, filt);
67462224350SCasper H.S. Dik
67562224350SCasper H.S. Dik fd = -1;
67662224350SCasper H.S. Dik
67762224350SCasper H.S. Dik if (pkgcmd(server, pfcmd, len, NULL, NULL, &fd) != 0 || fd == -1) {
67862224350SCasper H.S. Dik progerr(gettext(ERR_START_FILTER));
67962224350SCasper H.S. Dik return (-1);
68062224350SCasper H.S. Dik }
68162224350SCasper H.S. Dik (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
68262224350SCasper H.S. Dik
68362224350SCasper H.S. Dik server->fp = fdopen(fd, "r");
68462224350SCasper H.S. Dik if (server->fp == NULL) {
68562224350SCasper H.S. Dik (void) close(fd);
68662224350SCasper H.S. Dik progerr(gettext(ERR_START_FILTER));
68762224350SCasper H.S. Dik return (-1);
68862224350SCasper H.S. Dik }
68962224350SCasper H.S. Dik return (0);
69062224350SCasper H.S. Dik }
69162224350SCasper H.S. Dik
69262224350SCasper H.S. Dik void
pkgclosefilter(PKGserver server)69362224350SCasper H.S. Dik pkgclosefilter(PKGserver server)
69462224350SCasper H.S. Dik {
69562224350SCasper H.S. Dik if (server->fp != NULL) {
69662224350SCasper H.S. Dik (void) fclose(server->fp);
69762224350SCasper H.S. Dik server->fp = NULL;
69862224350SCasper H.S. Dik }
69962224350SCasper H.S. Dik }
70062224350SCasper H.S. Dik
70162224350SCasper H.S. Dik /*
70262224350SCasper H.S. Dik * Report the next entry from the contents file.
70362224350SCasper H.S. Dik */
70462224350SCasper H.S. Dik char *
pkggetentry(PKGserver server,int * len,int * pathlen)70562224350SCasper H.S. Dik pkggetentry(PKGserver server, int *len, int *pathlen)
70662224350SCasper H.S. Dik {
70762224350SCasper H.S. Dik int num[2];
70862224350SCasper H.S. Dik
70962224350SCasper H.S. Dik if (server->fp == NULL)
71062224350SCasper H.S. Dik return (NULL);
71162224350SCasper H.S. Dik
71262224350SCasper H.S. Dik if (feof(server->fp) || ferror(server->fp))
71362224350SCasper H.S. Dik return (NULL);
71462224350SCasper H.S. Dik
71562224350SCasper H.S. Dik if (fread(num, sizeof (int), 2, server->fp) != 2)
71662224350SCasper H.S. Dik return (NULL);
71762224350SCasper H.S. Dik
71862224350SCasper H.S. Dik if (num[0] > server->buflen) {
71962224350SCasper H.S. Dik free(server->curbuf);
72062224350SCasper H.S. Dik server->buflen = num[0];
72162224350SCasper H.S. Dik server->curbuf = malloc(server->buflen);
72262224350SCasper H.S. Dik if (server->curbuf == NULL)
72362224350SCasper H.S. Dik return (NULL);
72462224350SCasper H.S. Dik }
72562224350SCasper H.S. Dik if (fread(server->curbuf, 1, num[0], server->fp) != num[0])
72662224350SCasper H.S. Dik return (NULL);
72762224350SCasper H.S. Dik
72862224350SCasper H.S. Dik *len = num[0];
72962224350SCasper H.S. Dik *pathlen = num[1];
73062224350SCasper H.S. Dik
73162224350SCasper H.S. Dik return (server->curbuf);
73262224350SCasper H.S. Dik }
73362224350SCasper H.S. Dik
73462224350SCasper H.S. Dik char *
pkggetentry_named(PKGserver server,const char * path,int * len,int * pathlen)73562224350SCasper H.S. Dik pkggetentry_named(PKGserver server, const char *path, int *len, int *pathlen)
73662224350SCasper H.S. Dik {
73762224350SCasper H.S. Dik int plen = strlen(path);
73862224350SCasper H.S. Dik pkgfilter_t *pcmd = alloca(sizeof (*pcmd) + plen);
73962224350SCasper H.S. Dik char *result;
74062224350SCasper H.S. Dik unsigned int rlen;
74162224350SCasper H.S. Dik
74262224350SCasper H.S. Dik pcmd->cmd = PKG_FINDFILE;
74362224350SCasper H.S. Dik *pathlen = pcmd->len = plen;
74462224350SCasper H.S. Dik (void) memcpy(pcmd->buf, path, pcmd->len + 1);
74562224350SCasper H.S. Dik
74662224350SCasper H.S. Dik result = server->curbuf;
74762224350SCasper H.S. Dik rlen = server->buflen;
74862224350SCasper H.S. Dik
74962224350SCasper H.S. Dik if (pkgcmd(server, pcmd, sizeof (*pcmd) + pcmd->len,
75062224350SCasper H.S. Dik &result, &rlen, NULL) != 0) {
75162224350SCasper H.S. Dik return (NULL);
75262224350SCasper H.S. Dik }
75362224350SCasper H.S. Dik if (rlen == 0)
75462224350SCasper H.S. Dik return (NULL);
75562224350SCasper H.S. Dik
75662224350SCasper H.S. Dik /* Result too big */
75762224350SCasper H.S. Dik if (result != server->curbuf) {
75862224350SCasper H.S. Dik free(server->curbuf);
75962224350SCasper H.S. Dik server->buflen = rlen;
76062224350SCasper H.S. Dik server->curbuf = malloc(server->buflen);
76162224350SCasper H.S. Dik if (server->curbuf == NULL)
76262224350SCasper H.S. Dik return (NULL);
76362224350SCasper H.S. Dik (void) memcpy(server->curbuf, result, rlen);
76462224350SCasper H.S. Dik (void) munmap(result, rlen);
76562224350SCasper H.S. Dik }
76662224350SCasper H.S. Dik *len = rlen;
76762224350SCasper H.S. Dik
76862224350SCasper H.S. Dik return (server->curbuf);
76962224350SCasper H.S. Dik }
770