xref: /titanic_50/usr/src/lib/libpkg/common/pkgserv.c (revision 7706a9bf5155da553880e1d88bef039daa6fc46c)
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