xref: /onnv-gate/usr/src/lib/libpkg/common/pkgserv.c (revision 11770:02193b138d85)
19869SCasper.Dik@Sun.COM /*
29869SCasper.Dik@Sun.COM  * CDDL HEADER START
39869SCasper.Dik@Sun.COM  *
49869SCasper.Dik@Sun.COM  * The contents of this file are subject to the terms of the
59869SCasper.Dik@Sun.COM  * Common Development and Distribution License (the "License").
69869SCasper.Dik@Sun.COM  * You may not use this file except in compliance with the License.
79869SCasper.Dik@Sun.COM  *
89869SCasper.Dik@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99869SCasper.Dik@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109869SCasper.Dik@Sun.COM  * See the License for the specific language governing permissions
119869SCasper.Dik@Sun.COM  * and limitations under the License.
129869SCasper.Dik@Sun.COM  *
139869SCasper.Dik@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149869SCasper.Dik@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159869SCasper.Dik@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169869SCasper.Dik@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179869SCasper.Dik@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189869SCasper.Dik@Sun.COM  *
199869SCasper.Dik@Sun.COM  * CDDL HEADER END
209869SCasper.Dik@Sun.COM  */
219869SCasper.Dik@Sun.COM 
229869SCasper.Dik@Sun.COM /*
23*11770SCasper.Dik@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
249869SCasper.Dik@Sun.COM  * Use is subject to license terms.
259869SCasper.Dik@Sun.COM  */
269869SCasper.Dik@Sun.COM 
279869SCasper.Dik@Sun.COM #include <pkglib.h>
289869SCasper.Dik@Sun.COM 
299869SCasper.Dik@Sun.COM #include <alloca.h>
309869SCasper.Dik@Sun.COM #include <assert.h>
319869SCasper.Dik@Sun.COM #include <door.h>
329869SCasper.Dik@Sun.COM #include <errno.h>
339869SCasper.Dik@Sun.COM #include <fcntl.h>
349869SCasper.Dik@Sun.COM #include <pthread.h>
359869SCasper.Dik@Sun.COM #include <spawn.h>
369869SCasper.Dik@Sun.COM #include <stdio.h>
379869SCasper.Dik@Sun.COM #include <stdlib.h>
389869SCasper.Dik@Sun.COM #include <strings.h>
399869SCasper.Dik@Sun.COM #include <sys/mman.h>
409869SCasper.Dik@Sun.COM #include <sys/param.h>
419869SCasper.Dik@Sun.COM #include <sys/stat.h>
429869SCasper.Dik@Sun.COM #include <sys/wait.h>
439869SCasper.Dik@Sun.COM #include <unistd.h>
449869SCasper.Dik@Sun.COM #include <libintl.h>
45*11770SCasper.Dik@Sun.COM #include <sys/mnttab.h>
46*11770SCasper.Dik@Sun.COM #include <sys/mkdev.h>
479869SCasper.Dik@Sun.COM 
489869SCasper.Dik@Sun.COM #define	PKGADD_MAX	(512 * 1024)
499869SCasper.Dik@Sun.COM 
509869SCasper.Dik@Sun.COM #define	SADM_DIR	"/var/sadm/install"
519869SCasper.Dik@Sun.COM 
529869SCasper.Dik@Sun.COM #define	PKGSERV_PATH	"/usr/sadm/install/bin/pkgserv"
539869SCasper.Dik@Sun.COM 
549869SCasper.Dik@Sun.COM #define	ERR_PATH_TOO_BIG	"alternate root path is too long"
559869SCasper.Dik@Sun.COM #define	ERR_OPEN_DOOR		"cannot open pkgserv door"
569869SCasper.Dik@Sun.COM #define	ERR_START_SERVER	"cannot start pkgserv daemon: %s"
579869SCasper.Dik@Sun.COM #define	ERR_START_FILTER	"cannot enumerate database entries"
58*11770SCasper.Dik@Sun.COM #define	ERR_FIND_SADM		"cannot find sadm directory"
599869SCasper.Dik@Sun.COM 
609869SCasper.Dik@Sun.COM struct pkg_server {
619869SCasper.Dik@Sun.COM 	FILE		*fp;
629869SCasper.Dik@Sun.COM 	char		*curbuf;
639869SCasper.Dik@Sun.COM 	int		buflen;
649869SCasper.Dik@Sun.COM 	int		door;
659869SCasper.Dik@Sun.COM 	boolean_t	onetime;
669869SCasper.Dik@Sun.COM };
679869SCasper.Dik@Sun.COM 
689869SCasper.Dik@Sun.COM static PKGserver current_server;
699869SCasper.Dik@Sun.COM 
709869SCasper.Dik@Sun.COM static start_mode_t defmode = INVALID;
719869SCasper.Dik@Sun.COM static boolean_t registered = B_FALSE;
729869SCasper.Dik@Sun.COM static pid_t master_pid = -1;
739869SCasper.Dik@Sun.COM 
749869SCasper.Dik@Sun.COM static void
pkgfilename(char path[PATH_MAX],const char * root,const char * sadmdir,const char * file)759869SCasper.Dik@Sun.COM pkgfilename(char path[PATH_MAX], const char *root, const char *sadmdir,
769869SCasper.Dik@Sun.COM     const char *file)
779869SCasper.Dik@Sun.COM {
789869SCasper.Dik@Sun.COM 	if (snprintf(path, PATH_MAX, "%s%s/%s", root == NULL ? "" : root,
799869SCasper.Dik@Sun.COM 	    sadmdir == NULL ? SADM_DIR : sadmdir, file) >= PATH_MAX) {
809869SCasper.Dik@Sun.COM 		progerr(gettext(ERR_PATH_TOO_BIG));
819869SCasper.Dik@Sun.COM 		exit(99);
829869SCasper.Dik@Sun.COM 	}
839869SCasper.Dik@Sun.COM }
849869SCasper.Dik@Sun.COM 
859869SCasper.Dik@Sun.COM static void
free_xmnt(struct extmnttab * xmnt)86*11770SCasper.Dik@Sun.COM free_xmnt(struct extmnttab *xmnt)
87*11770SCasper.Dik@Sun.COM {
88*11770SCasper.Dik@Sun.COM 	free(xmnt->mnt_special);
89*11770SCasper.Dik@Sun.COM 	free(xmnt->mnt_mountp);
90*11770SCasper.Dik@Sun.COM 	free(xmnt->mnt_fstype);
91*11770SCasper.Dik@Sun.COM }
92*11770SCasper.Dik@Sun.COM 
93*11770SCasper.Dik@Sun.COM static void
copy_xmnt(const struct extmnttab * xmnt,struct extmnttab * saved)94*11770SCasper.Dik@Sun.COM copy_xmnt(const struct extmnttab *xmnt, struct extmnttab *saved)
95*11770SCasper.Dik@Sun.COM {
96*11770SCasper.Dik@Sun.COM 
97*11770SCasper.Dik@Sun.COM 	free_xmnt(saved);
98*11770SCasper.Dik@Sun.COM 
99*11770SCasper.Dik@Sun.COM 	/*
100*11770SCasper.Dik@Sun.COM 	 * Copy everything and then strdup the strings we later use and NULL
101*11770SCasper.Dik@Sun.COM 	 * the ones we don't.
102*11770SCasper.Dik@Sun.COM 	 */
103*11770SCasper.Dik@Sun.COM 	*saved = *xmnt;
104*11770SCasper.Dik@Sun.COM 
105*11770SCasper.Dik@Sun.COM 	if (saved->mnt_special != NULL)
106*11770SCasper.Dik@Sun.COM 		saved->mnt_special = strdup(saved->mnt_special);
107*11770SCasper.Dik@Sun.COM 	if (saved->mnt_mountp != NULL)
108*11770SCasper.Dik@Sun.COM 		saved->mnt_mountp = strdup(saved->mnt_mountp);
109*11770SCasper.Dik@Sun.COM 	if (saved->mnt_fstype != NULL)
110*11770SCasper.Dik@Sun.COM 		saved->mnt_fstype = strdup(saved->mnt_fstype);
111*11770SCasper.Dik@Sun.COM 
112*11770SCasper.Dik@Sun.COM 	saved->mnt_mntopts = NULL;
113*11770SCasper.Dik@Sun.COM 	saved->mnt_time = NULL;
114*11770SCasper.Dik@Sun.COM }
115*11770SCasper.Dik@Sun.COM 
116*11770SCasper.Dik@Sun.COM static int
testdoor(char * path)117*11770SCasper.Dik@Sun.COM testdoor(char *path)
118*11770SCasper.Dik@Sun.COM {
119*11770SCasper.Dik@Sun.COM 	int dir;
120*11770SCasper.Dik@Sun.COM 	int fd;
121*11770SCasper.Dik@Sun.COM 	struct door_info di;
122*11770SCasper.Dik@Sun.COM 	int res;
123*11770SCasper.Dik@Sun.COM 
124*11770SCasper.Dik@Sun.COM 	dir = open(path, O_RDONLY);
125*11770SCasper.Dik@Sun.COM 
126*11770SCasper.Dik@Sun.COM 	if (dir == -1)
127*11770SCasper.Dik@Sun.COM 		return (-1);
128*11770SCasper.Dik@Sun.COM 
129*11770SCasper.Dik@Sun.COM 	fd = openat(dir, PKGDOOR, O_RDWR);
130*11770SCasper.Dik@Sun.COM 	(void) close(dir);
131*11770SCasper.Dik@Sun.COM 	if (fd == -1)
132*11770SCasper.Dik@Sun.COM 		return (-1);
133*11770SCasper.Dik@Sun.COM 
134*11770SCasper.Dik@Sun.COM 	res = door_info(fd, &di);
135*11770SCasper.Dik@Sun.COM 	(void) close(fd);
136*11770SCasper.Dik@Sun.COM 	return (res);
137*11770SCasper.Dik@Sun.COM }
138*11770SCasper.Dik@Sun.COM 
139*11770SCasper.Dik@Sun.COM /*
140*11770SCasper.Dik@Sun.COM  * We need to make sure that we can locate the pkgserv and the door;
141*11770SCasper.Dik@Sun.COM  * lofs mounts makes this more difficult: "nosub" mounts don't propagate
142*11770SCasper.Dik@Sun.COM  * the door and doors created in lofs mounts are not propagated back to
143*11770SCasper.Dik@Sun.COM  * the original filesystem.
144*11770SCasper.Dik@Sun.COM  * Here we peel off the lofs mount points until we're
145*11770SCasper.Dik@Sun.COM  *	at /var/sadm/install or
146*11770SCasper.Dik@Sun.COM  *	we find a working door or
147*11770SCasper.Dik@Sun.COM  *	there's nothing more to peel off.
148*11770SCasper.Dik@Sun.COM  * The fullpath parameter is used to return the result (stored in *sadmdir),
149*11770SCasper.Dik@Sun.COM  * root is used but returned in the computed sadmdir and so the caller should
150*11770SCasper.Dik@Sun.COM  * not use "root" any longer or set it to NULL.
151*11770SCasper.Dik@Sun.COM  */
152*11770SCasper.Dik@Sun.COM static void
pkgfindrealsadmdir(char fullpath[PATH_MAX],const char * root,const char ** sadmdir)153*11770SCasper.Dik@Sun.COM pkgfindrealsadmdir(char fullpath[PATH_MAX], const char *root,
154*11770SCasper.Dik@Sun.COM     const char **sadmdir)
155*11770SCasper.Dik@Sun.COM {
156*11770SCasper.Dik@Sun.COM 	struct stat buf;
157*11770SCasper.Dik@Sun.COM 	struct extmnttab xmnt;
158*11770SCasper.Dik@Sun.COM 	FILE *mnttab = NULL;
159*11770SCasper.Dik@Sun.COM 	char temp[PATH_MAX];
160*11770SCasper.Dik@Sun.COM 	struct extmnttab saved = {NULL, NULL, NULL, NULL, NULL, 0, 0};
161*11770SCasper.Dik@Sun.COM 
162*11770SCasper.Dik@Sun.COM 	if (snprintf(temp, PATH_MAX, "%s%s",
163*11770SCasper.Dik@Sun.COM 	    root == NULL ? "" : root,
164*11770SCasper.Dik@Sun.COM 	    *sadmdir == NULL ? SADM_DIR : *sadmdir) >= PATH_MAX) {
165*11770SCasper.Dik@Sun.COM 		progerr(gettext(ERR_PATH_TOO_BIG));
166*11770SCasper.Dik@Sun.COM 		exit(99);
167*11770SCasper.Dik@Sun.COM 	}
168*11770SCasper.Dik@Sun.COM 
169*11770SCasper.Dik@Sun.COM 	if (stat(temp, &buf) != 0) {
170*11770SCasper.Dik@Sun.COM 		progerr(gettext(ERR_FIND_SADM));
171*11770SCasper.Dik@Sun.COM 		exit(99);
172*11770SCasper.Dik@Sun.COM 	}
173*11770SCasper.Dik@Sun.COM 
174*11770SCasper.Dik@Sun.COM 	/*
175*11770SCasper.Dik@Sun.COM 	 * To find the underlying mount point, you will need to
176*11770SCasper.Dik@Sun.COM 	 * search the mnttab and find our mountpoint and the underlying
177*11770SCasper.Dik@Sun.COM 	 * filesystem.
178*11770SCasper.Dik@Sun.COM 	 * To find the mount point: use the longest prefix but limit
179*11770SCasper.Dik@Sun.COM 	 * us to the filesystems with the same major/minor numbers.
180*11770SCasper.Dik@Sun.COM 	 * To find the underlying mount point: find a non-lofs file
181*11770SCasper.Dik@Sun.COM 	 * system or a <mnt> <mnt> entry (fake mountpoint for zones).
182*11770SCasper.Dik@Sun.COM 	 */
183*11770SCasper.Dik@Sun.COM 	for (;;) {
184*11770SCasper.Dik@Sun.COM 		size_t max = 0;
185*11770SCasper.Dik@Sun.COM 
186*11770SCasper.Dik@Sun.COM 		if (realpath(temp, fullpath) == NULL) {
187*11770SCasper.Dik@Sun.COM 			progerr(gettext(ERR_FIND_SADM));
188*11770SCasper.Dik@Sun.COM 			exit(99);
189*11770SCasper.Dik@Sun.COM 		}
190*11770SCasper.Dik@Sun.COM 
191*11770SCasper.Dik@Sun.COM 		if (strcmp(fullpath, SADM_DIR) == 0)
192*11770SCasper.Dik@Sun.COM 			break;
193*11770SCasper.Dik@Sun.COM 
194*11770SCasper.Dik@Sun.COM 		if (testdoor(fullpath) == 0)
195*11770SCasper.Dik@Sun.COM 			break;
196*11770SCasper.Dik@Sun.COM 
197*11770SCasper.Dik@Sun.COM 		if (mnttab == NULL)
198*11770SCasper.Dik@Sun.COM 			mnttab = fopen(MNTTAB, "r");
199*11770SCasper.Dik@Sun.COM 		else
200*11770SCasper.Dik@Sun.COM 			resetmnttab(mnttab);
201*11770SCasper.Dik@Sun.COM 
202*11770SCasper.Dik@Sun.COM 		while (getextmntent(mnttab, &xmnt, 0) == 0) {
203*11770SCasper.Dik@Sun.COM 			size_t len;
204*11770SCasper.Dik@Sun.COM 
205*11770SCasper.Dik@Sun.COM 			if (major(buf.st_dev) != xmnt.mnt_major ||
206*11770SCasper.Dik@Sun.COM 			    minor(buf.st_dev) != xmnt.mnt_minor)
207*11770SCasper.Dik@Sun.COM 				continue;
208*11770SCasper.Dik@Sun.COM 
209*11770SCasper.Dik@Sun.COM 			len = strlen(xmnt.mnt_mountp);
210*11770SCasper.Dik@Sun.COM 			if (len < max)
211*11770SCasper.Dik@Sun.COM 				continue;
212*11770SCasper.Dik@Sun.COM 
213*11770SCasper.Dik@Sun.COM 			if (strncmp(xmnt.mnt_mountp, fullpath, len) == 0 &&
214*11770SCasper.Dik@Sun.COM 			    (len == 1 || fullpath[len] == '/' ||
215*11770SCasper.Dik@Sun.COM 			    fullpath[len] == '\0')) {
216*11770SCasper.Dik@Sun.COM 				max = len;
217*11770SCasper.Dik@Sun.COM 				copy_xmnt(&xmnt, &saved);
218*11770SCasper.Dik@Sun.COM 			}
219*11770SCasper.Dik@Sun.COM 		}
220*11770SCasper.Dik@Sun.COM 		if (strcmp(saved.mnt_fstype, "lofs") != 0 ||
221*11770SCasper.Dik@Sun.COM 		    strcmp(saved.mnt_mountp, saved.mnt_special) == 0) {
222*11770SCasper.Dik@Sun.COM 			break;
223*11770SCasper.Dik@Sun.COM 		}
224*11770SCasper.Dik@Sun.COM 		/* Create a new path in the underlying filesystem. */
225*11770SCasper.Dik@Sun.COM 		if (snprintf(temp, PATH_MAX, "%s%s", saved.mnt_special,
226*11770SCasper.Dik@Sun.COM 		    &fullpath[max]) >= PATH_MAX) {
227*11770SCasper.Dik@Sun.COM 			progerr(gettext(ERR_PATH_TOO_BIG));
228*11770SCasper.Dik@Sun.COM 			exit(99);
229*11770SCasper.Dik@Sun.COM 		}
230*11770SCasper.Dik@Sun.COM 	}
231*11770SCasper.Dik@Sun.COM 
232*11770SCasper.Dik@Sun.COM 	if (mnttab != NULL) {
233*11770SCasper.Dik@Sun.COM 		free_xmnt(&saved);
234*11770SCasper.Dik@Sun.COM 		(void) fclose(mnttab);
235*11770SCasper.Dik@Sun.COM 	}
236*11770SCasper.Dik@Sun.COM 	*sadmdir = fullpath;
237*11770SCasper.Dik@Sun.COM }
238*11770SCasper.Dik@Sun.COM 
239*11770SCasper.Dik@Sun.COM static void
pkgexit_close(void)2409869SCasper.Dik@Sun.COM pkgexit_close(void)
2419869SCasper.Dik@Sun.COM {
2429869SCasper.Dik@Sun.COM 	if (current_server != NULL)
2439869SCasper.Dik@Sun.COM 		pkgcloseserver(current_server);
2449869SCasper.Dik@Sun.COM }
2459869SCasper.Dik@Sun.COM 
2469869SCasper.Dik@Sun.COM static PKGserver
pkgopenserver_i(const char * root,const char * sadmdir,boolean_t readonly,start_mode_t mode)2479869SCasper.Dik@Sun.COM pkgopenserver_i(const char *root, const char *sadmdir, boolean_t readonly,
2489869SCasper.Dik@Sun.COM 	start_mode_t mode)
2499869SCasper.Dik@Sun.COM {
2509869SCasper.Dik@Sun.COM 	PKGserver server;
2519869SCasper.Dik@Sun.COM 	struct door_info di;
2529869SCasper.Dik@Sun.COM 	pid_t pid;
2539869SCasper.Dik@Sun.COM 	int stat;
2549869SCasper.Dik@Sun.COM 	int first = B_TRUE;
2559869SCasper.Dik@Sun.COM 	char *cmd[16];
2569869SCasper.Dik@Sun.COM 	int args;
2579869SCasper.Dik@Sun.COM 	char pkgdoor[PATH_MAX];
258*11770SCasper.Dik@Sun.COM 	char realsadmdir[PATH_MAX];
2599869SCasper.Dik@Sun.COM 	extern char **environ;
2609869SCasper.Dik@Sun.COM 	char *prog;
2619869SCasper.Dik@Sun.COM 	char pidbuf[12];
2629869SCasper.Dik@Sun.COM 
2639869SCasper.Dik@Sun.COM 	if (current_server != NULL)
2649869SCasper.Dik@Sun.COM 		return (current_server);
2659869SCasper.Dik@Sun.COM 
2669869SCasper.Dik@Sun.COM 	if (!registered) {
2679869SCasper.Dik@Sun.COM 		registered = B_TRUE;
2689869SCasper.Dik@Sun.COM 		(void) atexit(pkgexit_close);
2699869SCasper.Dik@Sun.COM 	}
2709869SCasper.Dik@Sun.COM 	if (readonly) {
2719869SCasper.Dik@Sun.COM 		int fd;
2729869SCasper.Dik@Sun.COM 
2739869SCasper.Dik@Sun.COM 		(void) strcpy(pkgdoor, "/tmp/pkgdoor.XXXXXX");
2749869SCasper.Dik@Sun.COM 		if ((fd = mkstemp(pkgdoor)) < 0) {
2759869SCasper.Dik@Sun.COM 			progerr(gettext(ERR_OPEN_DOOR));
2769869SCasper.Dik@Sun.COM 			return (NULL);
2779869SCasper.Dik@Sun.COM 		}
2789869SCasper.Dik@Sun.COM 		(void) close(fd);
2799869SCasper.Dik@Sun.COM 	} else {
280*11770SCasper.Dik@Sun.COM 		pkgfindrealsadmdir(realsadmdir, root, &sadmdir);
281*11770SCasper.Dik@Sun.COM 		root = NULL;
2829869SCasper.Dik@Sun.COM 		pkgfilename(pkgdoor, root, sadmdir, PKGDOOR);
2839869SCasper.Dik@Sun.COM 	}
2849869SCasper.Dik@Sun.COM 
2859869SCasper.Dik@Sun.COM 	server = malloc(sizeof (*server));
2869869SCasper.Dik@Sun.COM 
2879869SCasper.Dik@Sun.COM 	if (server == NULL)
2889869SCasper.Dik@Sun.COM 		goto return_null;
2899869SCasper.Dik@Sun.COM 
2909869SCasper.Dik@Sun.COM 	server->fp = NULL;
2919869SCasper.Dik@Sun.COM 	server->onetime = readonly;
2929869SCasper.Dik@Sun.COM 
2939869SCasper.Dik@Sun.COM openserver:
2949869SCasper.Dik@Sun.COM 	server->door = open(pkgdoor, O_RDWR);
2959869SCasper.Dik@Sun.COM 
2969869SCasper.Dik@Sun.COM 	if (server->door >= 0) {
2979869SCasper.Dik@Sun.COM 		if (door_info(server->door, &di) == 0 && di.di_target >= 0) {
2989869SCasper.Dik@Sun.COM 			pkgcmd_t n;
2999869SCasper.Dik@Sun.COM 			n.cmd = PKG_NOP;
3009869SCasper.Dik@Sun.COM 			server->buflen = 1024;
3019869SCasper.Dik@Sun.COM 			server->curbuf = malloc(1024);
3029869SCasper.Dik@Sun.COM 			if (server->curbuf == NULL ||
3039869SCasper.Dik@Sun.COM 			    pkgcmd(server, &n, sizeof (n), NULL, NULL, NULL)) {
3049869SCasper.Dik@Sun.COM 				pkgcloseserver(server);
3059869SCasper.Dik@Sun.COM 				return (NULL);
3069869SCasper.Dik@Sun.COM 			}
3079869SCasper.Dik@Sun.COM 			return (current_server = server);
3089869SCasper.Dik@Sun.COM 		}
3099869SCasper.Dik@Sun.COM 
3109869SCasper.Dik@Sun.COM 		(void) close(server->door);
3119869SCasper.Dik@Sun.COM 	}
3129869SCasper.Dik@Sun.COM 
3139869SCasper.Dik@Sun.COM 	if (!first || mode == NEVER)
3149869SCasper.Dik@Sun.COM 		goto return_null;
3159869SCasper.Dik@Sun.COM 
3169869SCasper.Dik@Sun.COM 	first = B_FALSE;
3179869SCasper.Dik@Sun.COM 
3189869SCasper.Dik@Sun.COM 	args = 0;
3199869SCasper.Dik@Sun.COM 	cmd[args++] = strrchr(PKGSERV_PATH, '/') + 1;
3209869SCasper.Dik@Sun.COM 	if (root != NULL && strcmp(root, "/") != 0) {
3219869SCasper.Dik@Sun.COM 		cmd[args++] = "-R";
3229869SCasper.Dik@Sun.COM 		cmd[args++] = (char *)root;
3239869SCasper.Dik@Sun.COM 	}
3249869SCasper.Dik@Sun.COM 	if (sadmdir != NULL && strcmp(sadmdir, SADM_DIR) != 0) {
3259869SCasper.Dik@Sun.COM 		cmd[args++] = "-d";
3269869SCasper.Dik@Sun.COM 		cmd[args++] = (char *)sadmdir;
3279869SCasper.Dik@Sun.COM 	}
3289869SCasper.Dik@Sun.COM 	if (readonly) {
3299869SCasper.Dik@Sun.COM 		cmd[args++] = "-r";
3309869SCasper.Dik@Sun.COM 		cmd[args++] = pkgdoor;
3319869SCasper.Dik@Sun.COM 	}
3329869SCasper.Dik@Sun.COM 	prog = get_prog_name();
3339869SCasper.Dik@Sun.COM 	if (prog != NULL) {
3349869SCasper.Dik@Sun.COM 		cmd[args++] = "-N";
3359869SCasper.Dik@Sun.COM 		cmd[args++] = prog;
3369869SCasper.Dik@Sun.COM 	}
3379869SCasper.Dik@Sun.COM 
3389869SCasper.Dik@Sun.COM 	switch (mode) {
3399869SCasper.Dik@Sun.COM 	case FLUSH_LOG:
3409869SCasper.Dik@Sun.COM 		cmd[args++] = "-e";
3419869SCasper.Dik@Sun.COM 		break;
3429869SCasper.Dik@Sun.COM 	case RUN_ONCE:
3439869SCasper.Dik@Sun.COM 		cmd[args++] = "-o";
3449869SCasper.Dik@Sun.COM 		break;
3459869SCasper.Dik@Sun.COM 	case PERMANENT:
3469869SCasper.Dik@Sun.COM 		cmd[args++] = "-p";
3479869SCasper.Dik@Sun.COM 		break;
3489869SCasper.Dik@Sun.COM 	default:
3499869SCasper.Dik@Sun.COM 		break;
3509869SCasper.Dik@Sun.COM 	}
3519869SCasper.Dik@Sun.COM 
3529869SCasper.Dik@Sun.COM 	if (master_pid != -1) {
3539869SCasper.Dik@Sun.COM 		cmd[args++] = "-P";
3549869SCasper.Dik@Sun.COM 		(void) snprintf(pidbuf, sizeof (pidbuf), "%d", master_pid);
3559869SCasper.Dik@Sun.COM 		cmd[args++] = pidbuf;
3569869SCasper.Dik@Sun.COM 	}
3579869SCasper.Dik@Sun.COM 	cmd[args++] = NULL;
3589869SCasper.Dik@Sun.COM 	assert(args <= sizeof (cmd)/sizeof (char *));
3599869SCasper.Dik@Sun.COM 
3609869SCasper.Dik@Sun.COM 	if (posix_spawn(&pid, PKGSERV_PATH, NULL, NULL, cmd, environ) == 0) {
3619869SCasper.Dik@Sun.COM 		server->onetime |= mode == RUN_ONCE;
3629869SCasper.Dik@Sun.COM 		while (wait4(pid, &stat, 0, NULL) != -1) {
3639869SCasper.Dik@Sun.COM 			if (WIFEXITED(stat)) {
3649869SCasper.Dik@Sun.COM 				int s = WEXITSTATUS(stat);
3659869SCasper.Dik@Sun.COM 				if (s == 0 || s == 1)
3669869SCasper.Dik@Sun.COM 					if (mode == FLUSH_LOG)
3679869SCasper.Dik@Sun.COM 						goto return_null;
3689869SCasper.Dik@Sun.COM 					else
3699869SCasper.Dik@Sun.COM 						goto openserver;
3709869SCasper.Dik@Sun.COM 				if (s == 2)
3719869SCasper.Dik@Sun.COM 					goto return_null;
3729869SCasper.Dik@Sun.COM 				break;
3739869SCasper.Dik@Sun.COM 			} else if (WIFSIGNALED(stat)) {
3749869SCasper.Dik@Sun.COM 				break;
3759869SCasper.Dik@Sun.COM 			}
3769869SCasper.Dik@Sun.COM 		}
3779869SCasper.Dik@Sun.COM 	}
3789869SCasper.Dik@Sun.COM 
3799869SCasper.Dik@Sun.COM 	progerr(gettext(ERR_START_SERVER), strerror(errno));
3809869SCasper.Dik@Sun.COM 
3819869SCasper.Dik@Sun.COM return_null:
3829869SCasper.Dik@Sun.COM 	if (readonly)
3839869SCasper.Dik@Sun.COM 		(void) unlink(pkgdoor);
3849869SCasper.Dik@Sun.COM 	free(server);
3859869SCasper.Dik@Sun.COM 	return (NULL);
3869869SCasper.Dik@Sun.COM }
3879869SCasper.Dik@Sun.COM 
3889869SCasper.Dik@Sun.COM PKGserver
pkgopenserver(const char * root,const char * sadmdir,boolean_t ro)3899869SCasper.Dik@Sun.COM pkgopenserver(const char *root, const char *sadmdir, boolean_t ro)
3909869SCasper.Dik@Sun.COM {
3919869SCasper.Dik@Sun.COM 	return (pkgopenserver_i(root, sadmdir, ro, pkgservergetmode()));
3929869SCasper.Dik@Sun.COM }
3939869SCasper.Dik@Sun.COM 
3949869SCasper.Dik@Sun.COM start_mode_t
pkgparsemode(const char * mode)3959869SCasper.Dik@Sun.COM pkgparsemode(const char *mode)
3969869SCasper.Dik@Sun.COM {
3979869SCasper.Dik@Sun.COM 	if (strcasecmp(mode, MODE_PERMANENT) == 0) {
3989869SCasper.Dik@Sun.COM 		return (PERMANENT);
3999869SCasper.Dik@Sun.COM 	} else if (strncasecmp(mode, MODE_TIMEOUT,
4009869SCasper.Dik@Sun.COM 	    sizeof (MODE_TIMEOUT) - 1) == 0) {
4019869SCasper.Dik@Sun.COM 		const char *pidstr = mode + sizeof (MODE_TIMEOUT) - 1;
4029869SCasper.Dik@Sun.COM 		if (pidstr[0] != '\0') {
4039869SCasper.Dik@Sun.COM 			master_pid = atoi(pidstr);
4049869SCasper.Dik@Sun.COM 			if (master_pid <= 1 || kill(master_pid, 0) != 0)
4059869SCasper.Dik@Sun.COM 				master_pid = -1;
4069869SCasper.Dik@Sun.COM 		}
4079869SCasper.Dik@Sun.COM 
4089869SCasper.Dik@Sun.COM 		return (TIMEOUT);
4099869SCasper.Dik@Sun.COM 	} else if (strcasecmp(mode, MODE_RUN_ONCE) == 0) {
4109869SCasper.Dik@Sun.COM 		return (RUN_ONCE);
4119869SCasper.Dik@Sun.COM 	} else {
4129869SCasper.Dik@Sun.COM 		progerr(gettext("invalid pkgserver mode: %s"), mode);
4139869SCasper.Dik@Sun.COM 		exit(99);
4149869SCasper.Dik@Sun.COM 		/*NOTREACHED*/
4159869SCasper.Dik@Sun.COM 	}
4169869SCasper.Dik@Sun.COM }
4179869SCasper.Dik@Sun.COM 
4189869SCasper.Dik@Sun.COM char *
pkgmodeargument(start_mode_t mode)4199869SCasper.Dik@Sun.COM pkgmodeargument(start_mode_t mode)
4209869SCasper.Dik@Sun.COM {
4219869SCasper.Dik@Sun.COM 	static char timebuf[sizeof (PKGSERV_MODE) + sizeof (MODE_TIMEOUT) + 10];
4229869SCasper.Dik@Sun.COM 
4239869SCasper.Dik@Sun.COM 	switch (mode) {
4249869SCasper.Dik@Sun.COM 	case PERMANENT:
4259869SCasper.Dik@Sun.COM 		return (PKGSERV_MODE MODE_PERMANENT);
4269869SCasper.Dik@Sun.COM 	case TIMEOUT:
4279869SCasper.Dik@Sun.COM 		(void) snprintf(timebuf, sizeof (timebuf),
4289869SCasper.Dik@Sun.COM 		    PKGSERV_MODE MODE_TIMEOUT "%d",
4299869SCasper.Dik@Sun.COM 		    (master_pid > 1 && kill(master_pid, 0) == 0) ? master_pid :
4309869SCasper.Dik@Sun.COM 		    getpid());
4319869SCasper.Dik@Sun.COM 		return (timebuf);
4329869SCasper.Dik@Sun.COM 	case RUN_ONCE:
4339869SCasper.Dik@Sun.COM 		return (PKGSERV_MODE MODE_RUN_ONCE);
4349869SCasper.Dik@Sun.COM 	}
4359869SCasper.Dik@Sun.COM 	progerr(gettext("Bad pkgserv mode: %d"), (int)mode);
4369869SCasper.Dik@Sun.COM 	exit(99);
4379869SCasper.Dik@Sun.COM }
4389869SCasper.Dik@Sun.COM 
4399869SCasper.Dik@Sun.COM void
pkgserversetmode(start_mode_t mode)4409869SCasper.Dik@Sun.COM pkgserversetmode(start_mode_t mode)
4419869SCasper.Dik@Sun.COM {
4429869SCasper.Dik@Sun.COM 	if (mode == DEFAULTMODE || mode == INVALID) {
4439869SCasper.Dik@Sun.COM 		char *var = getenv(SUNW_PKG_SERVERMODE);
4449869SCasper.Dik@Sun.COM 
4459869SCasper.Dik@Sun.COM 		if (var != NULL)
4469869SCasper.Dik@Sun.COM 			defmode = pkgparsemode(var);
4479869SCasper.Dik@Sun.COM 		else
4489869SCasper.Dik@Sun.COM 			defmode = DEFAULTMODE;
4499869SCasper.Dik@Sun.COM 	} else {
4509869SCasper.Dik@Sun.COM 		defmode = mode;
4519869SCasper.Dik@Sun.COM 	}
4529869SCasper.Dik@Sun.COM }
4539869SCasper.Dik@Sun.COM 
4549869SCasper.Dik@Sun.COM start_mode_t
pkgservergetmode(void)4559869SCasper.Dik@Sun.COM pkgservergetmode(void)
4569869SCasper.Dik@Sun.COM {
4579869SCasper.Dik@Sun.COM 	if (defmode == INVALID)
4589869SCasper.Dik@Sun.COM 		pkgserversetmode(DEFAULTMODE);
4599869SCasper.Dik@Sun.COM 	return (defmode);
4609869SCasper.Dik@Sun.COM }
4619869SCasper.Dik@Sun.COM 
4629869SCasper.Dik@Sun.COM void
pkgcloseserver(PKGserver server)4639869SCasper.Dik@Sun.COM pkgcloseserver(PKGserver server)
4649869SCasper.Dik@Sun.COM {
4659869SCasper.Dik@Sun.COM 
4669869SCasper.Dik@Sun.COM 	if (server->fp != NULL)
4679869SCasper.Dik@Sun.COM 		(void) fclose(server->fp);
4689869SCasper.Dik@Sun.COM 	free(server->curbuf);
4699869SCasper.Dik@Sun.COM 	if (server->onetime) {
4709869SCasper.Dik@Sun.COM 		pkgcmd_t cmd;
4719869SCasper.Dik@Sun.COM 		cmd.cmd = PKG_EXIT;
4729869SCasper.Dik@Sun.COM 		(void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL);
4739869SCasper.Dik@Sun.COM 	}
4749869SCasper.Dik@Sun.COM 	(void) close(server->door);
4759869SCasper.Dik@Sun.COM 	if (server == current_server)
4769869SCasper.Dik@Sun.COM 		current_server = NULL;
4779869SCasper.Dik@Sun.COM 	free(server);
4789869SCasper.Dik@Sun.COM }
4799869SCasper.Dik@Sun.COM 
4809869SCasper.Dik@Sun.COM int
pkgcmd(PKGserver srv,void * cmd,size_t len,char ** result,size_t * rlen,int * fd)4819869SCasper.Dik@Sun.COM pkgcmd(PKGserver srv, void *cmd, size_t len, char **result, size_t *rlen,
4829869SCasper.Dik@Sun.COM     int *fd)
4839869SCasper.Dik@Sun.COM {
4849869SCasper.Dik@Sun.COM 	door_arg_t da;
4859869SCasper.Dik@Sun.COM 
4869869SCasper.Dik@Sun.COM 	da.data_ptr = cmd;
4879869SCasper.Dik@Sun.COM 	da.data_size = len;
4889869SCasper.Dik@Sun.COM 	da.desc_ptr = NULL;
4899869SCasper.Dik@Sun.COM 	da.desc_num = 0;
4909869SCasper.Dik@Sun.COM 	da.rbuf = result == NULL ? NULL : *result;
4919869SCasper.Dik@Sun.COM 	da.rsize = rlen == NULL ? 0 : *rlen;
4929869SCasper.Dik@Sun.COM 
4939869SCasper.Dik@Sun.COM 	if (door_call(srv->door, &da) != 0) {
4949869SCasper.Dik@Sun.COM 		if (((pkgcmd_t *)cmd)->cmd == PKG_EXIT && errno == EINTR)
4959869SCasper.Dik@Sun.COM 			return (0);
4969869SCasper.Dik@Sun.COM 		return (-1);
4979869SCasper.Dik@Sun.COM 	}
4989869SCasper.Dik@Sun.COM 
4999869SCasper.Dik@Sun.COM 	if (da.desc_ptr != NULL) {
5009869SCasper.Dik@Sun.COM 		int i = 0;
5019869SCasper.Dik@Sun.COM 		if (fd != NULL)
5029869SCasper.Dik@Sun.COM 			*fd = da.desc_ptr[i++].d_data.d_desc.d_descriptor;
5039869SCasper.Dik@Sun.COM 		for (; i < da.desc_num; i++)
5049869SCasper.Dik@Sun.COM 			(void) close(da.desc_ptr[i].d_data.d_desc.d_descriptor);
5059869SCasper.Dik@Sun.COM 	}
5069869SCasper.Dik@Sun.COM 	/* Error return */
5079869SCasper.Dik@Sun.COM 	if (da.data_size == sizeof (int)) {
5089869SCasper.Dik@Sun.COM 		int x = *(int *)da.data_ptr;
5099869SCasper.Dik@Sun.COM 		if (x != 0) {
5109869SCasper.Dik@Sun.COM 			if (result == NULL || da.rbuf != *result)
5119869SCasper.Dik@Sun.COM 				(void) munmap(da.rbuf, da.rsize);
5129869SCasper.Dik@Sun.COM 			return (x);
5139869SCasper.Dik@Sun.COM 		}
5149869SCasper.Dik@Sun.COM 	}
5159869SCasper.Dik@Sun.COM 
5169869SCasper.Dik@Sun.COM 	/* Other result */
5179869SCasper.Dik@Sun.COM 	if (result != NULL) {
5189869SCasper.Dik@Sun.COM 		/* Make sure that the result is at the start of the buffer. */
5199869SCasper.Dik@Sun.COM 		if (da.data_ptr != NULL && da.rbuf != da.data_ptr)
5209869SCasper.Dik@Sun.COM 			(void) memmove(da.rbuf, da.data_ptr, da.data_size);
5219869SCasper.Dik@Sun.COM 		*result = da.rbuf;
5229869SCasper.Dik@Sun.COM 		*rlen = da.data_size;
5239869SCasper.Dik@Sun.COM 	} else if (da.rbuf != NULL) {
5249869SCasper.Dik@Sun.COM 		(void) munmap(da.rbuf, da.rsize);
5259869SCasper.Dik@Sun.COM 	}
5269869SCasper.Dik@Sun.COM 	return (0);
5279869SCasper.Dik@Sun.COM }
5289869SCasper.Dik@Sun.COM 
5299869SCasper.Dik@Sun.COM /*
5309869SCasper.Dik@Sun.COM  * Pkgsync:
5319869SCasper.Dik@Sun.COM  *	If the server is running, make sure that the contents
5329869SCasper.Dik@Sun.COM  *	file is written.
5339869SCasper.Dik@Sun.COM  *	If the server is not running, check for the log file;
5349869SCasper.Dik@Sun.COM  *	if there's a non-empty log file, we need to start the server
5359869SCasper.Dik@Sun.COM  *	as it will incorporate the log file into the contents file.
5369869SCasper.Dik@Sun.COM  *	And then check if the door is present.  If it doesn't, we don't
5379869SCasper.Dik@Sun.COM  *	need to call it.
5389869SCasper.Dik@Sun.COM  */
5399869SCasper.Dik@Sun.COM 
5409869SCasper.Dik@Sun.COM boolean_t
pkgsync_needed(const char * root,const char * sadmdir,boolean_t want_quit)5419869SCasper.Dik@Sun.COM pkgsync_needed(const char *root, const char *sadmdir, boolean_t want_quit)
5429869SCasper.Dik@Sun.COM {
5439869SCasper.Dik@Sun.COM 	struct stat pbuf;
5449869SCasper.Dik@Sun.COM 	char pkgfile[PATH_MAX];
5459869SCasper.Dik@Sun.COM 	boolean_t sync_needed, running;
5469869SCasper.Dik@Sun.COM 	int fd;
5479869SCasper.Dik@Sun.COM 	struct door_info di;
5489869SCasper.Dik@Sun.COM 
5499869SCasper.Dik@Sun.COM 	pkgfilename(pkgfile, root, sadmdir, PKGLOG);
5509869SCasper.Dik@Sun.COM 
5519869SCasper.Dik@Sun.COM 	sync_needed = stat(pkgfile, &pbuf) == 0 && pbuf.st_size > 0;
5529869SCasper.Dik@Sun.COM 
5539869SCasper.Dik@Sun.COM 	if (!sync_needed && !want_quit)
5549869SCasper.Dik@Sun.COM 		return (B_FALSE);
5559869SCasper.Dik@Sun.COM 
5569869SCasper.Dik@Sun.COM 	pkgfilename(pkgfile, root, sadmdir, PKGDOOR);
5579869SCasper.Dik@Sun.COM 
5589869SCasper.Dik@Sun.COM 	/* sync_needed == B_TRUE || want_quit == B_TRUE */
5599869SCasper.Dik@Sun.COM 	running = B_FALSE;
5609869SCasper.Dik@Sun.COM 
5619869SCasper.Dik@Sun.COM 	fd = open(pkgfile, O_RDWR);
5629869SCasper.Dik@Sun.COM 
5639869SCasper.Dik@Sun.COM 	if (fd >= 0) {
5649869SCasper.Dik@Sun.COM 		if (door_info(fd, &di) == 0) {
5659869SCasper.Dik@Sun.COM 			/* It's mounted, so the server is likely there */
5669869SCasper.Dik@Sun.COM 			running = B_TRUE;
5679869SCasper.Dik@Sun.COM 		}
5689869SCasper.Dik@Sun.COM 		(void) close(fd);
5699869SCasper.Dik@Sun.COM 	}
5709869SCasper.Dik@Sun.COM 	return (running || sync_needed);
5719869SCasper.Dik@Sun.COM }
5729869SCasper.Dik@Sun.COM 
5739869SCasper.Dik@Sun.COM int
pkgsync(const char * root,const char * sadmdir,boolean_t force_quit)5749869SCasper.Dik@Sun.COM pkgsync(const char *root, const char *sadmdir, boolean_t force_quit)
5759869SCasper.Dik@Sun.COM {
5769869SCasper.Dik@Sun.COM 	void *server;
5779869SCasper.Dik@Sun.COM 	pkgcmd_t cmd;
5789869SCasper.Dik@Sun.COM 
5799869SCasper.Dik@Sun.COM 	/* No need to write contents file; don't start if not running */
5809869SCasper.Dik@Sun.COM 	if (!pkgsync_needed(root, sadmdir, force_quit))
5819869SCasper.Dik@Sun.COM 		return (0);
5829869SCasper.Dik@Sun.COM 
5839869SCasper.Dik@Sun.COM 	server = pkgopenserver_i(root, sadmdir, B_FALSE, FLUSH_LOG);
5849869SCasper.Dik@Sun.COM 	/*
5859869SCasper.Dik@Sun.COM 	 * We're assuming that it started the server and exited immediately.
5869869SCasper.Dik@Sun.COM 	 * If that didn't work, there's nothing we can do.
5879869SCasper.Dik@Sun.COM 	 */
5889869SCasper.Dik@Sun.COM 	if (server == NULL)
5899869SCasper.Dik@Sun.COM 		return (0);
5909869SCasper.Dik@Sun.COM 
5919869SCasper.Dik@Sun.COM 	cmd.cmd = force_quit ? PKG_EXIT : PKG_DUMP;
5929869SCasper.Dik@Sun.COM 
5939869SCasper.Dik@Sun.COM 	(void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL);
5949869SCasper.Dik@Sun.COM 	(void) pkgcloseserver(server);
5959869SCasper.Dik@Sun.COM 	return (0);
5969869SCasper.Dik@Sun.COM }
5979869SCasper.Dik@Sun.COM 
5989869SCasper.Dik@Sun.COM int
pkgservercommitfile(VFP_T * a_vfp,PKGserver server)5999869SCasper.Dik@Sun.COM pkgservercommitfile(VFP_T *a_vfp, PKGserver server)
6009869SCasper.Dik@Sun.COM {
6019869SCasper.Dik@Sun.COM 	size_t len = vfpGetModifiedLen(a_vfp);
6029869SCasper.Dik@Sun.COM 	ssize_t rem = len;
6039869SCasper.Dik@Sun.COM 	size_t off;
6049869SCasper.Dik@Sun.COM 	pkgfilter_t *pcmd;
6059869SCasper.Dik@Sun.COM 	char *map = a_vfp->_vfpStart;
6069869SCasper.Dik@Sun.COM 
6079869SCasper.Dik@Sun.COM 	if (len < PKGADD_MAX)
6089869SCasper.Dik@Sun.COM 		pcmd = alloca(sizeof (*pcmd) + len);
6099869SCasper.Dik@Sun.COM 	else
6109869SCasper.Dik@Sun.COM 		pcmd = alloca(sizeof (*pcmd) + PKGADD_MAX);
6119869SCasper.Dik@Sun.COM 
6129869SCasper.Dik@Sun.COM 
6139869SCasper.Dik@Sun.COM 	off = 0;
6149869SCasper.Dik@Sun.COM 	pcmd->cmd = PKG_ADDLINES;
6159869SCasper.Dik@Sun.COM 	while (rem > 0) {
6169869SCasper.Dik@Sun.COM 		char *p = map + off;
6179869SCasper.Dik@Sun.COM 		len = rem;
6189869SCasper.Dik@Sun.COM 
6199869SCasper.Dik@Sun.COM 		if (len >= PKGADD_MAX) {
6209869SCasper.Dik@Sun.COM 			len = PKGADD_MAX - 1;
6219869SCasper.Dik@Sun.COM 			while (p[len] != '\n' && len > 0)
6229869SCasper.Dik@Sun.COM 				len--;
6239869SCasper.Dik@Sun.COM 			if (p[len] != '\n')
6249869SCasper.Dik@Sun.COM 				return (-1);
6259869SCasper.Dik@Sun.COM 			len++;
6269869SCasper.Dik@Sun.COM 		}
6279869SCasper.Dik@Sun.COM 		(void) memcpy(&pcmd->buf[0], p, len);
6289869SCasper.Dik@Sun.COM 		pcmd->len = len;
6299869SCasper.Dik@Sun.COM 
6309869SCasper.Dik@Sun.COM 		if (pkgcmd(server, pcmd, sizeof (*pcmd) + len - 1,
6319869SCasper.Dik@Sun.COM 		    NULL, NULL, NULL) != 0) {
6329869SCasper.Dik@Sun.COM 			return (-1);
6339869SCasper.Dik@Sun.COM 		}
6349869SCasper.Dik@Sun.COM 		rem -= len;
6359869SCasper.Dik@Sun.COM 		off += len;
6369869SCasper.Dik@Sun.COM 	}
6379869SCasper.Dik@Sun.COM 	pcmd->len = 0;
6389869SCasper.Dik@Sun.COM 	pcmd->cmd = PKG_PKGSYNC;
6399869SCasper.Dik@Sun.COM 	if (pkgcmd(server, pcmd, sizeof (*pcmd), NULL, NULL, NULL) != 0)
6409869SCasper.Dik@Sun.COM 		return (-1);
6419869SCasper.Dik@Sun.COM 
6429869SCasper.Dik@Sun.COM 	/* Mark it unmodified. */
6439869SCasper.Dik@Sun.COM 	vfpTruncate(a_vfp);
6449869SCasper.Dik@Sun.COM 	(void) vfpClearModified(a_vfp);
6459869SCasper.Dik@Sun.COM 
6469869SCasper.Dik@Sun.COM 	return (0);
6479869SCasper.Dik@Sun.COM }
6489869SCasper.Dik@Sun.COM 
6499869SCasper.Dik@Sun.COM int
pkgopenfilter(PKGserver server,const char * filt)6509869SCasper.Dik@Sun.COM pkgopenfilter(PKGserver server, const char *filt)
6519869SCasper.Dik@Sun.COM {
6529869SCasper.Dik@Sun.COM 	int fd;
6539869SCasper.Dik@Sun.COM 	pkgfilter_t *pfcmd;
6549869SCasper.Dik@Sun.COM 	int clen = filt == NULL ? 0 : strlen(filt);
6559869SCasper.Dik@Sun.COM 	int len = sizeof (*pfcmd) + clen;
6569869SCasper.Dik@Sun.COM 
6579869SCasper.Dik@Sun.COM 	pfcmd = alloca(len);
6589869SCasper.Dik@Sun.COM 
6599869SCasper.Dik@Sun.COM 	if (server->fp != NULL) {
6609869SCasper.Dik@Sun.COM 		(void) fclose(server->fp);
6619869SCasper.Dik@Sun.COM 		server->fp = NULL;
6629869SCasper.Dik@Sun.COM 	}
6639869SCasper.Dik@Sun.COM 
6649869SCasper.Dik@Sun.COM 	pfcmd->cmd = PKG_FILTER;
6659869SCasper.Dik@Sun.COM 	pfcmd->len = clen;
6669869SCasper.Dik@Sun.COM 	if (filt != NULL)
6679869SCasper.Dik@Sun.COM 		(void) strcpy(pfcmd->buf, filt);
6689869SCasper.Dik@Sun.COM 
6699869SCasper.Dik@Sun.COM 	fd = -1;
6709869SCasper.Dik@Sun.COM 
6719869SCasper.Dik@Sun.COM 	if (pkgcmd(server, pfcmd, len, NULL, NULL, &fd) != 0 || fd == -1) {
6729869SCasper.Dik@Sun.COM 		progerr(gettext(ERR_START_FILTER));
6739869SCasper.Dik@Sun.COM 		return (-1);
6749869SCasper.Dik@Sun.COM 	}
6759869SCasper.Dik@Sun.COM 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
6769869SCasper.Dik@Sun.COM 
6779869SCasper.Dik@Sun.COM 	server->fp = fdopen(fd, "r");
6789869SCasper.Dik@Sun.COM 	if (server->fp == NULL) {
6799869SCasper.Dik@Sun.COM 		(void) close(fd);
6809869SCasper.Dik@Sun.COM 		progerr(gettext(ERR_START_FILTER));
6819869SCasper.Dik@Sun.COM 		return (-1);
6829869SCasper.Dik@Sun.COM 	}
6839869SCasper.Dik@Sun.COM 	return (0);
6849869SCasper.Dik@Sun.COM }
6859869SCasper.Dik@Sun.COM 
6869869SCasper.Dik@Sun.COM void
pkgclosefilter(PKGserver server)6879869SCasper.Dik@Sun.COM pkgclosefilter(PKGserver server)
6889869SCasper.Dik@Sun.COM {
6899869SCasper.Dik@Sun.COM 	if (server->fp != NULL) {
6909869SCasper.Dik@Sun.COM 		(void) fclose(server->fp);
6919869SCasper.Dik@Sun.COM 		server->fp = NULL;
6929869SCasper.Dik@Sun.COM 	}
6939869SCasper.Dik@Sun.COM }
6949869SCasper.Dik@Sun.COM 
6959869SCasper.Dik@Sun.COM /*
6969869SCasper.Dik@Sun.COM  * Report the next entry from the contents file.
6979869SCasper.Dik@Sun.COM  */
6989869SCasper.Dik@Sun.COM char *
pkggetentry(PKGserver server,int * len,int * pathlen)6999869SCasper.Dik@Sun.COM pkggetentry(PKGserver server, int *len, int *pathlen)
7009869SCasper.Dik@Sun.COM {
7019869SCasper.Dik@Sun.COM 	int num[2];
7029869SCasper.Dik@Sun.COM 
7039869SCasper.Dik@Sun.COM 	if (server->fp == NULL)
7049869SCasper.Dik@Sun.COM 		return (NULL);
7059869SCasper.Dik@Sun.COM 
7069869SCasper.Dik@Sun.COM 	if (feof(server->fp) || ferror(server->fp))
7079869SCasper.Dik@Sun.COM 		return (NULL);
7089869SCasper.Dik@Sun.COM 
7099869SCasper.Dik@Sun.COM 	if (fread(num, sizeof (int), 2, server->fp) != 2)
7109869SCasper.Dik@Sun.COM 		return (NULL);
7119869SCasper.Dik@Sun.COM 
7129869SCasper.Dik@Sun.COM 	if (num[0] > server->buflen) {
7139869SCasper.Dik@Sun.COM 		free(server->curbuf);
7149869SCasper.Dik@Sun.COM 		server->buflen = num[0];
7159869SCasper.Dik@Sun.COM 		server->curbuf = malloc(server->buflen);
7169869SCasper.Dik@Sun.COM 		if (server->curbuf == NULL)
7179869SCasper.Dik@Sun.COM 			return (NULL);
7189869SCasper.Dik@Sun.COM 	}
7199869SCasper.Dik@Sun.COM 	if (fread(server->curbuf, 1, num[0], server->fp) != num[0])
7209869SCasper.Dik@Sun.COM 		return (NULL);
7219869SCasper.Dik@Sun.COM 
7229869SCasper.Dik@Sun.COM 	*len = num[0];
7239869SCasper.Dik@Sun.COM 	*pathlen = num[1];
7249869SCasper.Dik@Sun.COM 
7259869SCasper.Dik@Sun.COM 	return (server->curbuf);
7269869SCasper.Dik@Sun.COM }
7279869SCasper.Dik@Sun.COM 
7289869SCasper.Dik@Sun.COM char *
pkggetentry_named(PKGserver server,const char * path,int * len,int * pathlen)7299869SCasper.Dik@Sun.COM pkggetentry_named(PKGserver server, const char *path, int *len, int *pathlen)
7309869SCasper.Dik@Sun.COM {
7319869SCasper.Dik@Sun.COM 	int plen = strlen(path);
7329869SCasper.Dik@Sun.COM 	pkgfilter_t *pcmd = alloca(sizeof (*pcmd) + plen);
7339869SCasper.Dik@Sun.COM 	char *result;
7349869SCasper.Dik@Sun.COM 	unsigned int rlen;
7359869SCasper.Dik@Sun.COM 
7369869SCasper.Dik@Sun.COM 	pcmd->cmd = PKG_FINDFILE;
7379869SCasper.Dik@Sun.COM 	*pathlen = pcmd->len = plen;
7389869SCasper.Dik@Sun.COM 	(void) memcpy(pcmd->buf, path, pcmd->len + 1);
7399869SCasper.Dik@Sun.COM 
7409869SCasper.Dik@Sun.COM 	result = server->curbuf;
7419869SCasper.Dik@Sun.COM 	rlen = server->buflen;
7429869SCasper.Dik@Sun.COM 
7439869SCasper.Dik@Sun.COM 	if (pkgcmd(server, pcmd, sizeof (*pcmd) + pcmd->len,
7449869SCasper.Dik@Sun.COM 	    &result, &rlen, NULL) != 0) {
7459869SCasper.Dik@Sun.COM 		return (NULL);
7469869SCasper.Dik@Sun.COM 	}
7479869SCasper.Dik@Sun.COM 	if (rlen == 0)
7489869SCasper.Dik@Sun.COM 		return (NULL);
7499869SCasper.Dik@Sun.COM 
7509869SCasper.Dik@Sun.COM 	/* Result too big */
7519869SCasper.Dik@Sun.COM 	if (result != server->curbuf) {
7529869SCasper.Dik@Sun.COM 		free(server->curbuf);
7539869SCasper.Dik@Sun.COM 		server->buflen = rlen;
7549869SCasper.Dik@Sun.COM 		server->curbuf = malloc(server->buflen);
7559869SCasper.Dik@Sun.COM 		if (server->curbuf == NULL)
7569869SCasper.Dik@Sun.COM 			return (NULL);
7579869SCasper.Dik@Sun.COM 		(void) memcpy(server->curbuf, result, rlen);
7589869SCasper.Dik@Sun.COM 		(void) munmap(result, rlen);
7599869SCasper.Dik@Sun.COM 	}
7609869SCasper.Dik@Sun.COM 	*len = rlen;
7619869SCasper.Dik@Sun.COM 
7629869SCasper.Dik@Sun.COM 	return (server->curbuf);
7639869SCasper.Dik@Sun.COM }
764