xref: /titanic_51/usr/src/lib/libpkg/common/pkgserv.c (revision 62224350e5355e6834f7deb9d8a7d062a50cb7c2)
1*62224350SCasper H.S. Dik /*
2*62224350SCasper H.S. Dik  * CDDL HEADER START
3*62224350SCasper H.S. Dik  *
4*62224350SCasper H.S. Dik  * The contents of this file are subject to the terms of the
5*62224350SCasper H.S. Dik  * Common Development and Distribution License (the "License").
6*62224350SCasper H.S. Dik  * You may not use this file except in compliance with the License.
7*62224350SCasper H.S. Dik  *
8*62224350SCasper H.S. Dik  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*62224350SCasper H.S. Dik  * or http://www.opensolaris.org/os/licensing.
10*62224350SCasper H.S. Dik  * See the License for the specific language governing permissions
11*62224350SCasper H.S. Dik  * and limitations under the License.
12*62224350SCasper H.S. Dik  *
13*62224350SCasper H.S. Dik  * When distributing Covered Code, include this CDDL HEADER in each
14*62224350SCasper H.S. Dik  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*62224350SCasper H.S. Dik  * If applicable, add the following below this CDDL HEADER, with the
16*62224350SCasper H.S. Dik  * fields enclosed by brackets "[]" replaced with your own identifying
17*62224350SCasper H.S. Dik  * information: Portions Copyright [yyyy] [name of copyright owner]
18*62224350SCasper H.S. Dik  *
19*62224350SCasper H.S. Dik  * CDDL HEADER END
20*62224350SCasper H.S. Dik  */
21*62224350SCasper H.S. Dik 
22*62224350SCasper H.S. Dik /*
23*62224350SCasper H.S. Dik  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*62224350SCasper H.S. Dik  * Use is subject to license terms.
25*62224350SCasper H.S. Dik  */
26*62224350SCasper H.S. Dik 
27*62224350SCasper H.S. Dik #include <pkglib.h>
28*62224350SCasper H.S. Dik 
29*62224350SCasper H.S. Dik #include <alloca.h>
30*62224350SCasper H.S. Dik #include <assert.h>
31*62224350SCasper H.S. Dik #include <door.h>
32*62224350SCasper H.S. Dik #include <errno.h>
33*62224350SCasper H.S. Dik #include <fcntl.h>
34*62224350SCasper H.S. Dik #include <pthread.h>
35*62224350SCasper H.S. Dik #include <spawn.h>
36*62224350SCasper H.S. Dik #include <stdio.h>
37*62224350SCasper H.S. Dik #include <stdlib.h>
38*62224350SCasper H.S. Dik #include <strings.h>
39*62224350SCasper H.S. Dik #include <sys/mman.h>
40*62224350SCasper H.S. Dik #include <sys/param.h>
41*62224350SCasper H.S. Dik #include <sys/stat.h>
42*62224350SCasper H.S. Dik #include <sys/wait.h>
43*62224350SCasper H.S. Dik #include <unistd.h>
44*62224350SCasper H.S. Dik #include <libintl.h>
45*62224350SCasper H.S. Dik 
46*62224350SCasper H.S. Dik #define	PKGADD_MAX	(512 * 1024)
47*62224350SCasper H.S. Dik 
48*62224350SCasper H.S. Dik #define	SADM_DIR	"/var/sadm/install"
49*62224350SCasper H.S. Dik 
50*62224350SCasper H.S. Dik #define	PKGSERV_PATH	"/usr/sadm/install/bin/pkgserv"
51*62224350SCasper H.S. Dik 
52*62224350SCasper H.S. Dik #define	ERR_PATH_TOO_BIG	"alternate root path is too long"
53*62224350SCasper H.S. Dik #define	ERR_OPEN_DOOR		"cannot open pkgserv door"
54*62224350SCasper H.S. Dik #define	ERR_START_SERVER	"cannot start pkgserv daemon: %s"
55*62224350SCasper H.S. Dik #define	ERR_START_FILTER	"cannot enumerate database entries"
56*62224350SCasper H.S. Dik 
57*62224350SCasper H.S. Dik struct pkg_server {
58*62224350SCasper H.S. Dik 	FILE		*fp;
59*62224350SCasper H.S. Dik 	char		*curbuf;
60*62224350SCasper H.S. Dik 	int		buflen;
61*62224350SCasper H.S. Dik 	int		door;
62*62224350SCasper H.S. Dik 	boolean_t	onetime;
63*62224350SCasper H.S. Dik };
64*62224350SCasper H.S. Dik 
65*62224350SCasper H.S. Dik static PKGserver current_server;
66*62224350SCasper H.S. Dik 
67*62224350SCasper H.S. Dik static start_mode_t defmode = INVALID;
68*62224350SCasper H.S. Dik static boolean_t registered = B_FALSE;
69*62224350SCasper H.S. Dik static pid_t master_pid = -1;
70*62224350SCasper H.S. Dik 
71*62224350SCasper H.S. Dik static void
72*62224350SCasper H.S. Dik pkgfilename(char path[PATH_MAX], const char *root, const char *sadmdir,
73*62224350SCasper H.S. Dik     const char *file)
74*62224350SCasper H.S. Dik {
75*62224350SCasper H.S. Dik 	if (snprintf(path, PATH_MAX, "%s%s/%s", root == NULL ? "" : root,
76*62224350SCasper H.S. Dik 	    sadmdir == NULL ? SADM_DIR : sadmdir, file) >= PATH_MAX) {
77*62224350SCasper H.S. Dik 		progerr(gettext(ERR_PATH_TOO_BIG));
78*62224350SCasper H.S. Dik 		exit(99);
79*62224350SCasper H.S. Dik 	}
80*62224350SCasper H.S. Dik }
81*62224350SCasper H.S. Dik 
82*62224350SCasper H.S. Dik static void
83*62224350SCasper H.S. Dik pkgexit_close(void)
84*62224350SCasper H.S. Dik {
85*62224350SCasper H.S. Dik 	if (current_server != NULL)
86*62224350SCasper H.S. Dik 		pkgcloseserver(current_server);
87*62224350SCasper H.S. Dik }
88*62224350SCasper H.S. Dik 
89*62224350SCasper H.S. Dik static PKGserver
90*62224350SCasper H.S. Dik pkgopenserver_i(const char *root, const char *sadmdir, boolean_t readonly,
91*62224350SCasper H.S. Dik 	start_mode_t mode)
92*62224350SCasper H.S. Dik {
93*62224350SCasper H.S. Dik 	PKGserver server;
94*62224350SCasper H.S. Dik 	struct door_info di;
95*62224350SCasper H.S. Dik 	pid_t pid;
96*62224350SCasper H.S. Dik 	int stat;
97*62224350SCasper H.S. Dik 	int first = B_TRUE;
98*62224350SCasper H.S. Dik 	char *cmd[16];
99*62224350SCasper H.S. Dik 	int args;
100*62224350SCasper H.S. Dik 	char pkgdoor[PATH_MAX];
101*62224350SCasper H.S. Dik 	extern char **environ;
102*62224350SCasper H.S. Dik 	char *prog;
103*62224350SCasper H.S. Dik 	char pidbuf[12];
104*62224350SCasper H.S. Dik 
105*62224350SCasper H.S. Dik 	if (current_server != NULL)
106*62224350SCasper H.S. Dik 		return (current_server);
107*62224350SCasper H.S. Dik 
108*62224350SCasper H.S. Dik 	if (!registered) {
109*62224350SCasper H.S. Dik 		registered = B_TRUE;
110*62224350SCasper H.S. Dik 		(void) atexit(pkgexit_close);
111*62224350SCasper H.S. Dik 	}
112*62224350SCasper H.S. Dik 	if (readonly) {
113*62224350SCasper H.S. Dik 		int fd;
114*62224350SCasper H.S. Dik 
115*62224350SCasper H.S. Dik 		(void) strcpy(pkgdoor, "/tmp/pkgdoor.XXXXXX");
116*62224350SCasper H.S. Dik 		if ((fd = mkstemp(pkgdoor)) < 0) {
117*62224350SCasper H.S. Dik 			progerr(gettext(ERR_OPEN_DOOR));
118*62224350SCasper H.S. Dik 			return (NULL);
119*62224350SCasper H.S. Dik 		}
120*62224350SCasper H.S. Dik 		(void) close(fd);
121*62224350SCasper H.S. Dik 	} else {
122*62224350SCasper H.S. Dik 		pkgfilename(pkgdoor, root, sadmdir, PKGDOOR);
123*62224350SCasper H.S. Dik 	}
124*62224350SCasper H.S. Dik 
125*62224350SCasper H.S. Dik 	server = malloc(sizeof (*server));
126*62224350SCasper H.S. Dik 
127*62224350SCasper H.S. Dik 	if (server == NULL)
128*62224350SCasper H.S. Dik 		goto return_null;
129*62224350SCasper H.S. Dik 
130*62224350SCasper H.S. Dik 	server->fp = NULL;
131*62224350SCasper H.S. Dik 	server->onetime = readonly;
132*62224350SCasper H.S. Dik 
133*62224350SCasper H.S. Dik openserver:
134*62224350SCasper H.S. Dik 	server->door = open(pkgdoor, O_RDWR);
135*62224350SCasper H.S. Dik 
136*62224350SCasper H.S. Dik 	if (server->door >= 0) {
137*62224350SCasper H.S. Dik 		if (door_info(server->door, &di) == 0 && di.di_target >= 0) {
138*62224350SCasper H.S. Dik 			pkgcmd_t n;
139*62224350SCasper H.S. Dik 			n.cmd = PKG_NOP;
140*62224350SCasper H.S. Dik 			server->buflen = 1024;
141*62224350SCasper H.S. Dik 			server->curbuf = malloc(1024);
142*62224350SCasper H.S. Dik 			if (server->curbuf == NULL ||
143*62224350SCasper H.S. Dik 			    pkgcmd(server, &n, sizeof (n), NULL, NULL, NULL)) {
144*62224350SCasper H.S. Dik 				pkgcloseserver(server);
145*62224350SCasper H.S. Dik 				return (NULL);
146*62224350SCasper H.S. Dik 			}
147*62224350SCasper H.S. Dik 			return (current_server = server);
148*62224350SCasper H.S. Dik 		}
149*62224350SCasper H.S. Dik 
150*62224350SCasper H.S. Dik 		(void) close(server->door);
151*62224350SCasper H.S. Dik 	}
152*62224350SCasper H.S. Dik 
153*62224350SCasper H.S. Dik 	if (!first || mode == NEVER)
154*62224350SCasper H.S. Dik 		goto return_null;
155*62224350SCasper H.S. Dik 
156*62224350SCasper H.S. Dik 	first = B_FALSE;
157*62224350SCasper H.S. Dik 
158*62224350SCasper H.S. Dik 	args = 0;
159*62224350SCasper H.S. Dik 	cmd[args++] = strrchr(PKGSERV_PATH, '/') + 1;
160*62224350SCasper H.S. Dik 	if (root != NULL && strcmp(root, "/") != 0) {
161*62224350SCasper H.S. Dik 		cmd[args++] = "-R";
162*62224350SCasper H.S. Dik 		cmd[args++] = (char *)root;
163*62224350SCasper H.S. Dik 	}
164*62224350SCasper H.S. Dik 	if (sadmdir != NULL && strcmp(sadmdir, SADM_DIR) != 0) {
165*62224350SCasper H.S. Dik 		cmd[args++] = "-d";
166*62224350SCasper H.S. Dik 		cmd[args++] = (char *)sadmdir;
167*62224350SCasper H.S. Dik 	}
168*62224350SCasper H.S. Dik 	if (readonly) {
169*62224350SCasper H.S. Dik 		cmd[args++] = "-r";
170*62224350SCasper H.S. Dik 		cmd[args++] = pkgdoor;
171*62224350SCasper H.S. Dik 	}
172*62224350SCasper H.S. Dik 	prog = get_prog_name();
173*62224350SCasper H.S. Dik 	if (prog != NULL) {
174*62224350SCasper H.S. Dik 		cmd[args++] = "-N";
175*62224350SCasper H.S. Dik 		cmd[args++] = prog;
176*62224350SCasper H.S. Dik 	}
177*62224350SCasper H.S. Dik 
178*62224350SCasper H.S. Dik 	switch (mode) {
179*62224350SCasper H.S. Dik 	case FLUSH_LOG:
180*62224350SCasper H.S. Dik 		cmd[args++] = "-e";
181*62224350SCasper H.S. Dik 		break;
182*62224350SCasper H.S. Dik 	case RUN_ONCE:
183*62224350SCasper H.S. Dik 		cmd[args++] = "-o";
184*62224350SCasper H.S. Dik 		break;
185*62224350SCasper H.S. Dik 	case PERMANENT:
186*62224350SCasper H.S. Dik 		cmd[args++] = "-p";
187*62224350SCasper H.S. Dik 		break;
188*62224350SCasper H.S. Dik 	default:
189*62224350SCasper H.S. Dik 		break;
190*62224350SCasper H.S. Dik 	}
191*62224350SCasper H.S. Dik 
192*62224350SCasper H.S. Dik 	if (master_pid != -1) {
193*62224350SCasper H.S. Dik 		cmd[args++] = "-P";
194*62224350SCasper H.S. Dik 		(void) snprintf(pidbuf, sizeof (pidbuf), "%d", master_pid);
195*62224350SCasper H.S. Dik 		cmd[args++] = pidbuf;
196*62224350SCasper H.S. Dik 	}
197*62224350SCasper H.S. Dik 	cmd[args++] = NULL;
198*62224350SCasper H.S. Dik 	assert(args <= sizeof (cmd)/sizeof (char *));
199*62224350SCasper H.S. Dik 
200*62224350SCasper H.S. Dik 	if (posix_spawn(&pid, PKGSERV_PATH, NULL, NULL, cmd, environ) == 0) {
201*62224350SCasper H.S. Dik 		server->onetime |= mode == RUN_ONCE;
202*62224350SCasper H.S. Dik 		while (wait4(pid, &stat, 0, NULL) != -1) {
203*62224350SCasper H.S. Dik 			if (WIFEXITED(stat)) {
204*62224350SCasper H.S. Dik 				int s = WEXITSTATUS(stat);
205*62224350SCasper H.S. Dik 				if (s == 0 || s == 1)
206*62224350SCasper H.S. Dik 					if (mode == FLUSH_LOG)
207*62224350SCasper H.S. Dik 						goto return_null;
208*62224350SCasper H.S. Dik 					else
209*62224350SCasper H.S. Dik 						goto openserver;
210*62224350SCasper H.S. Dik 				if (s == 2)
211*62224350SCasper H.S. Dik 					goto return_null;
212*62224350SCasper H.S. Dik 				break;
213*62224350SCasper H.S. Dik 			} else if (WIFSIGNALED(stat)) {
214*62224350SCasper H.S. Dik 				break;
215*62224350SCasper H.S. Dik 			}
216*62224350SCasper H.S. Dik 		}
217*62224350SCasper H.S. Dik 	}
218*62224350SCasper H.S. Dik 
219*62224350SCasper H.S. Dik 	progerr(gettext(ERR_START_SERVER), strerror(errno));
220*62224350SCasper H.S. Dik 
221*62224350SCasper H.S. Dik return_null:
222*62224350SCasper H.S. Dik 	if (readonly)
223*62224350SCasper H.S. Dik 		(void) unlink(pkgdoor);
224*62224350SCasper H.S. Dik 	free(server);
225*62224350SCasper H.S. Dik 	return (NULL);
226*62224350SCasper H.S. Dik }
227*62224350SCasper H.S. Dik 
228*62224350SCasper H.S. Dik PKGserver
229*62224350SCasper H.S. Dik pkgopenserver(const char *root, const char *sadmdir, boolean_t ro)
230*62224350SCasper H.S. Dik {
231*62224350SCasper H.S. Dik 	return (pkgopenserver_i(root, sadmdir, ro, pkgservergetmode()));
232*62224350SCasper H.S. Dik }
233*62224350SCasper H.S. Dik 
234*62224350SCasper H.S. Dik start_mode_t
235*62224350SCasper H.S. Dik pkgparsemode(const char *mode)
236*62224350SCasper H.S. Dik {
237*62224350SCasper H.S. Dik 	if (strcasecmp(mode, MODE_PERMANENT) == 0) {
238*62224350SCasper H.S. Dik 		return (PERMANENT);
239*62224350SCasper H.S. Dik 	} else if (strncasecmp(mode, MODE_TIMEOUT,
240*62224350SCasper H.S. Dik 	    sizeof (MODE_TIMEOUT) - 1) == 0) {
241*62224350SCasper H.S. Dik 		const char *pidstr = mode + sizeof (MODE_TIMEOUT) - 1;
242*62224350SCasper H.S. Dik 		if (pidstr[0] != '\0') {
243*62224350SCasper H.S. Dik 			master_pid = atoi(pidstr);
244*62224350SCasper H.S. Dik 			if (master_pid <= 1 || kill(master_pid, 0) != 0)
245*62224350SCasper H.S. Dik 				master_pid = -1;
246*62224350SCasper H.S. Dik 		}
247*62224350SCasper H.S. Dik 
248*62224350SCasper H.S. Dik 		return (TIMEOUT);
249*62224350SCasper H.S. Dik 	} else if (strcasecmp(mode, MODE_RUN_ONCE) == 0) {
250*62224350SCasper H.S. Dik 		return (RUN_ONCE);
251*62224350SCasper H.S. Dik 	} else {
252*62224350SCasper H.S. Dik 		progerr(gettext("invalid pkgserver mode: %s"), mode);
253*62224350SCasper H.S. Dik 		exit(99);
254*62224350SCasper H.S. Dik 		/*NOTREACHED*/
255*62224350SCasper H.S. Dik 	}
256*62224350SCasper H.S. Dik }
257*62224350SCasper H.S. Dik 
258*62224350SCasper H.S. Dik char *
259*62224350SCasper H.S. Dik pkgmodeargument(start_mode_t mode)
260*62224350SCasper H.S. Dik {
261*62224350SCasper H.S. Dik 	static char timebuf[sizeof (PKGSERV_MODE) + sizeof (MODE_TIMEOUT) + 10];
262*62224350SCasper H.S. Dik 
263*62224350SCasper H.S. Dik 	switch (mode) {
264*62224350SCasper H.S. Dik 	case PERMANENT:
265*62224350SCasper H.S. Dik 		return (PKGSERV_MODE MODE_PERMANENT);
266*62224350SCasper H.S. Dik 	case TIMEOUT:
267*62224350SCasper H.S. Dik 		(void) snprintf(timebuf, sizeof (timebuf),
268*62224350SCasper H.S. Dik 		    PKGSERV_MODE MODE_TIMEOUT "%d",
269*62224350SCasper H.S. Dik 		    (master_pid > 1 && kill(master_pid, 0) == 0) ? master_pid :
270*62224350SCasper H.S. Dik 		    getpid());
271*62224350SCasper H.S. Dik 		return (timebuf);
272*62224350SCasper H.S. Dik 	case RUN_ONCE:
273*62224350SCasper H.S. Dik 		return (PKGSERV_MODE MODE_RUN_ONCE);
274*62224350SCasper H.S. Dik 	}
275*62224350SCasper H.S. Dik 	progerr(gettext("Bad pkgserv mode: %d"), (int)mode);
276*62224350SCasper H.S. Dik 	exit(99);
277*62224350SCasper H.S. Dik }
278*62224350SCasper H.S. Dik 
279*62224350SCasper H.S. Dik void
280*62224350SCasper H.S. Dik pkgserversetmode(start_mode_t mode)
281*62224350SCasper H.S. Dik {
282*62224350SCasper H.S. Dik 	if (mode == DEFAULTMODE || mode == INVALID) {
283*62224350SCasper H.S. Dik 		char *var = getenv(SUNW_PKG_SERVERMODE);
284*62224350SCasper H.S. Dik 
285*62224350SCasper H.S. Dik 		if (var != NULL)
286*62224350SCasper H.S. Dik 			defmode = pkgparsemode(var);
287*62224350SCasper H.S. Dik 		else
288*62224350SCasper H.S. Dik 			defmode = DEFAULTMODE;
289*62224350SCasper H.S. Dik 	} else {
290*62224350SCasper H.S. Dik 		defmode = mode;
291*62224350SCasper H.S. Dik 	}
292*62224350SCasper H.S. Dik }
293*62224350SCasper H.S. Dik 
294*62224350SCasper H.S. Dik start_mode_t
295*62224350SCasper H.S. Dik pkgservergetmode(void)
296*62224350SCasper H.S. Dik {
297*62224350SCasper H.S. Dik 	if (defmode == INVALID)
298*62224350SCasper H.S. Dik 		pkgserversetmode(DEFAULTMODE);
299*62224350SCasper H.S. Dik 	return (defmode);
300*62224350SCasper H.S. Dik }
301*62224350SCasper H.S. Dik 
302*62224350SCasper H.S. Dik void
303*62224350SCasper H.S. Dik pkgcloseserver(PKGserver server)
304*62224350SCasper H.S. Dik {
305*62224350SCasper H.S. Dik 
306*62224350SCasper H.S. Dik 	if (server->fp != NULL)
307*62224350SCasper H.S. Dik 		(void) fclose(server->fp);
308*62224350SCasper H.S. Dik 	free(server->curbuf);
309*62224350SCasper H.S. Dik 	if (server->onetime) {
310*62224350SCasper H.S. Dik 		pkgcmd_t cmd;
311*62224350SCasper H.S. Dik 		cmd.cmd = PKG_EXIT;
312*62224350SCasper H.S. Dik 		(void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL);
313*62224350SCasper H.S. Dik 	}
314*62224350SCasper H.S. Dik 	(void) close(server->door);
315*62224350SCasper H.S. Dik 	if (server == current_server)
316*62224350SCasper H.S. Dik 		current_server = NULL;
317*62224350SCasper H.S. Dik 	free(server);
318*62224350SCasper H.S. Dik }
319*62224350SCasper H.S. Dik 
320*62224350SCasper H.S. Dik int
321*62224350SCasper H.S. Dik pkgcmd(PKGserver srv, void *cmd, size_t len, char **result, size_t *rlen,
322*62224350SCasper H.S. Dik     int *fd)
323*62224350SCasper H.S. Dik {
324*62224350SCasper H.S. Dik 	door_arg_t da;
325*62224350SCasper H.S. Dik 
326*62224350SCasper H.S. Dik 	da.data_ptr = cmd;
327*62224350SCasper H.S. Dik 	da.data_size = len;
328*62224350SCasper H.S. Dik 	da.desc_ptr = NULL;
329*62224350SCasper H.S. Dik 	da.desc_num = 0;
330*62224350SCasper H.S. Dik 	da.rbuf = result == NULL ? NULL : *result;
331*62224350SCasper H.S. Dik 	da.rsize = rlen == NULL ? 0 : *rlen;
332*62224350SCasper H.S. Dik 
333*62224350SCasper H.S. Dik 	if (door_call(srv->door, &da) != 0) {
334*62224350SCasper H.S. Dik 		if (((pkgcmd_t *)cmd)->cmd == PKG_EXIT && errno == EINTR)
335*62224350SCasper H.S. Dik 			return (0);
336*62224350SCasper H.S. Dik 		return (-1);
337*62224350SCasper H.S. Dik 	}
338*62224350SCasper H.S. Dik 
339*62224350SCasper H.S. Dik 	if (da.desc_ptr != NULL) {
340*62224350SCasper H.S. Dik 		int i = 0;
341*62224350SCasper H.S. Dik 		if (fd != NULL)
342*62224350SCasper H.S. Dik 			*fd = da.desc_ptr[i++].d_data.d_desc.d_descriptor;
343*62224350SCasper H.S. Dik 		for (; i < da.desc_num; i++)
344*62224350SCasper H.S. Dik 			(void) close(da.desc_ptr[i].d_data.d_desc.d_descriptor);
345*62224350SCasper H.S. Dik 	}
346*62224350SCasper H.S. Dik 	/* Error return */
347*62224350SCasper H.S. Dik 	if (da.data_size == sizeof (int)) {
348*62224350SCasper H.S. Dik 		int x = *(int *)da.data_ptr;
349*62224350SCasper H.S. Dik 		if (x != 0) {
350*62224350SCasper H.S. Dik 			if (result == NULL || da.rbuf != *result)
351*62224350SCasper H.S. Dik 				(void) munmap(da.rbuf, da.rsize);
352*62224350SCasper H.S. Dik 			return (x);
353*62224350SCasper H.S. Dik 		}
354*62224350SCasper H.S. Dik 	}
355*62224350SCasper H.S. Dik 
356*62224350SCasper H.S. Dik 	/* Other result */
357*62224350SCasper H.S. Dik 	if (result != NULL) {
358*62224350SCasper H.S. Dik 		/* Make sure that the result is at the start of the buffer. */
359*62224350SCasper H.S. Dik 		if (da.data_ptr != NULL && da.rbuf != da.data_ptr)
360*62224350SCasper H.S. Dik 			(void) memmove(da.rbuf, da.data_ptr, da.data_size);
361*62224350SCasper H.S. Dik 		*result = da.rbuf;
362*62224350SCasper H.S. Dik 		*rlen = da.data_size;
363*62224350SCasper H.S. Dik 	} else if (da.rbuf != NULL) {
364*62224350SCasper H.S. Dik 		(void) munmap(da.rbuf, da.rsize);
365*62224350SCasper H.S. Dik 	}
366*62224350SCasper H.S. Dik 	return (0);
367*62224350SCasper H.S. Dik }
368*62224350SCasper H.S. Dik 
369*62224350SCasper H.S. Dik /*
370*62224350SCasper H.S. Dik  * Pkgsync:
371*62224350SCasper H.S. Dik  *	If the server is running, make sure that the contents
372*62224350SCasper H.S. Dik  *	file is written.
373*62224350SCasper H.S. Dik  *	If the server is not running, check for the log file;
374*62224350SCasper H.S. Dik  *	if there's a non-empty log file, we need to start the server
375*62224350SCasper H.S. Dik  *	as it will incorporate the log file into the contents file.
376*62224350SCasper H.S. Dik  *	And then check if the door is present.  If it doesn't, we don't
377*62224350SCasper H.S. Dik  *	need to call it.
378*62224350SCasper H.S. Dik  */
379*62224350SCasper H.S. Dik 
380*62224350SCasper H.S. Dik boolean_t
381*62224350SCasper H.S. Dik pkgsync_needed(const char *root, const char *sadmdir, boolean_t want_quit)
382*62224350SCasper H.S. Dik {
383*62224350SCasper H.S. Dik 	struct stat pbuf;
384*62224350SCasper H.S. Dik 	char pkgfile[PATH_MAX];
385*62224350SCasper H.S. Dik 	boolean_t sync_needed, running;
386*62224350SCasper H.S. Dik 	int fd;
387*62224350SCasper H.S. Dik 	struct door_info di;
388*62224350SCasper H.S. Dik 
389*62224350SCasper H.S. Dik 	pkgfilename(pkgfile, root, sadmdir, PKGLOG);
390*62224350SCasper H.S. Dik 
391*62224350SCasper H.S. Dik 	sync_needed = stat(pkgfile, &pbuf) == 0 && pbuf.st_size > 0;
392*62224350SCasper H.S. Dik 
393*62224350SCasper H.S. Dik 	if (!sync_needed && !want_quit)
394*62224350SCasper H.S. Dik 		return (B_FALSE);
395*62224350SCasper H.S. Dik 
396*62224350SCasper H.S. Dik 	pkgfilename(pkgfile, root, sadmdir, PKGDOOR);
397*62224350SCasper H.S. Dik 
398*62224350SCasper H.S. Dik 	/* sync_needed == B_TRUE || want_quit == B_TRUE */
399*62224350SCasper H.S. Dik 	running = B_FALSE;
400*62224350SCasper H.S. Dik 
401*62224350SCasper H.S. Dik 	fd = open(pkgfile, O_RDWR);
402*62224350SCasper H.S. Dik 
403*62224350SCasper H.S. Dik 	if (fd >= 0) {
404*62224350SCasper H.S. Dik 		if (door_info(fd, &di) == 0) {
405*62224350SCasper H.S. Dik 			/* It's mounted, so the server is likely there */
406*62224350SCasper H.S. Dik 			running = B_TRUE;
407*62224350SCasper H.S. Dik 		}
408*62224350SCasper H.S. Dik 		(void) close(fd);
409*62224350SCasper H.S. Dik 	}
410*62224350SCasper H.S. Dik 	return (running || sync_needed);
411*62224350SCasper H.S. Dik }
412*62224350SCasper H.S. Dik 
413*62224350SCasper H.S. Dik int
414*62224350SCasper H.S. Dik pkgsync(const char *root, const char *sadmdir, boolean_t force_quit)
415*62224350SCasper H.S. Dik {
416*62224350SCasper H.S. Dik 	void *server;
417*62224350SCasper H.S. Dik 	pkgcmd_t cmd;
418*62224350SCasper H.S. Dik 
419*62224350SCasper H.S. Dik 	/* No need to write contents file; don't start if not running */
420*62224350SCasper H.S. Dik 	if (!pkgsync_needed(root, sadmdir, force_quit))
421*62224350SCasper H.S. Dik 		return (0);
422*62224350SCasper H.S. Dik 
423*62224350SCasper H.S. Dik 	server = pkgopenserver_i(root, sadmdir, B_FALSE, FLUSH_LOG);
424*62224350SCasper H.S. Dik 	/*
425*62224350SCasper H.S. Dik 	 * We're assuming that it started the server and exited immediately.
426*62224350SCasper H.S. Dik 	 * If that didn't work, there's nothing we can do.
427*62224350SCasper H.S. Dik 	 */
428*62224350SCasper H.S. Dik 	if (server == NULL)
429*62224350SCasper H.S. Dik 		return (0);
430*62224350SCasper H.S. Dik 
431*62224350SCasper H.S. Dik 	cmd.cmd = force_quit ? PKG_EXIT : PKG_DUMP;
432*62224350SCasper H.S. Dik 
433*62224350SCasper H.S. Dik 	(void) pkgcmd(server, &cmd, sizeof (cmd), NULL, NULL, NULL);
434*62224350SCasper H.S. Dik 	(void) pkgcloseserver(server);
435*62224350SCasper H.S. Dik 	return (0);
436*62224350SCasper H.S. Dik }
437*62224350SCasper H.S. Dik 
438*62224350SCasper H.S. Dik int
439*62224350SCasper H.S. Dik pkgservercommitfile(VFP_T *a_vfp, PKGserver server)
440*62224350SCasper H.S. Dik {
441*62224350SCasper H.S. Dik 	size_t len = vfpGetModifiedLen(a_vfp);
442*62224350SCasper H.S. Dik 	ssize_t rem = len;
443*62224350SCasper H.S. Dik 	size_t off;
444*62224350SCasper H.S. Dik 	pkgfilter_t *pcmd;
445*62224350SCasper H.S. Dik 	char *map = a_vfp->_vfpStart;
446*62224350SCasper H.S. Dik 
447*62224350SCasper H.S. Dik 	if (len < PKGADD_MAX)
448*62224350SCasper H.S. Dik 		pcmd = alloca(sizeof (*pcmd) + len);
449*62224350SCasper H.S. Dik 	else
450*62224350SCasper H.S. Dik 		pcmd = alloca(sizeof (*pcmd) + PKGADD_MAX);
451*62224350SCasper H.S. Dik 
452*62224350SCasper H.S. Dik 
453*62224350SCasper H.S. Dik 	off = 0;
454*62224350SCasper H.S. Dik 	pcmd->cmd = PKG_ADDLINES;
455*62224350SCasper H.S. Dik 	while (rem > 0) {
456*62224350SCasper H.S. Dik 		char *p = map + off;
457*62224350SCasper H.S. Dik 		len = rem;
458*62224350SCasper H.S. Dik 
459*62224350SCasper H.S. Dik 		if (len >= PKGADD_MAX) {
460*62224350SCasper H.S. Dik 			len = PKGADD_MAX - 1;
461*62224350SCasper H.S. Dik 			while (p[len] != '\n' && len > 0)
462*62224350SCasper H.S. Dik 				len--;
463*62224350SCasper H.S. Dik 			if (p[len] != '\n')
464*62224350SCasper H.S. Dik 				return (-1);
465*62224350SCasper H.S. Dik 			len++;
466*62224350SCasper H.S. Dik 		}
467*62224350SCasper H.S. Dik 		(void) memcpy(&pcmd->buf[0], p, len);
468*62224350SCasper H.S. Dik 		pcmd->len = len;
469*62224350SCasper H.S. Dik 
470*62224350SCasper H.S. Dik 		if (pkgcmd(server, pcmd, sizeof (*pcmd) + len - 1,
471*62224350SCasper H.S. Dik 		    NULL, NULL, NULL) != 0) {
472*62224350SCasper H.S. Dik 			return (-1);
473*62224350SCasper H.S. Dik 		}
474*62224350SCasper H.S. Dik 		rem -= len;
475*62224350SCasper H.S. Dik 		off += len;
476*62224350SCasper H.S. Dik 	}
477*62224350SCasper H.S. Dik 	pcmd->len = 0;
478*62224350SCasper H.S. Dik 	pcmd->cmd = PKG_PKGSYNC;
479*62224350SCasper H.S. Dik 	if (pkgcmd(server, pcmd, sizeof (*pcmd), NULL, NULL, NULL) != 0)
480*62224350SCasper H.S. Dik 		return (-1);
481*62224350SCasper H.S. Dik 
482*62224350SCasper H.S. Dik 	/* Mark it unmodified. */
483*62224350SCasper H.S. Dik 	vfpTruncate(a_vfp);
484*62224350SCasper H.S. Dik 	(void) vfpClearModified(a_vfp);
485*62224350SCasper H.S. Dik 
486*62224350SCasper H.S. Dik 	return (0);
487*62224350SCasper H.S. Dik }
488*62224350SCasper H.S. Dik 
489*62224350SCasper H.S. Dik int
490*62224350SCasper H.S. Dik pkgopenfilter(PKGserver server, const char *filt)
491*62224350SCasper H.S. Dik {
492*62224350SCasper H.S. Dik 	int fd;
493*62224350SCasper H.S. Dik 	pkgfilter_t *pfcmd;
494*62224350SCasper H.S. Dik 	int clen = filt == NULL ? 0 : strlen(filt);
495*62224350SCasper H.S. Dik 	int len = sizeof (*pfcmd) + clen;
496*62224350SCasper H.S. Dik 
497*62224350SCasper H.S. Dik 	pfcmd = alloca(len);
498*62224350SCasper H.S. Dik 
499*62224350SCasper H.S. Dik 	if (server->fp != NULL) {
500*62224350SCasper H.S. Dik 		(void) fclose(server->fp);
501*62224350SCasper H.S. Dik 		server->fp = NULL;
502*62224350SCasper H.S. Dik 	}
503*62224350SCasper H.S. Dik 
504*62224350SCasper H.S. Dik 	pfcmd->cmd = PKG_FILTER;
505*62224350SCasper H.S. Dik 	pfcmd->len = clen;
506*62224350SCasper H.S. Dik 	if (filt != NULL)
507*62224350SCasper H.S. Dik 		(void) strcpy(pfcmd->buf, filt);
508*62224350SCasper H.S. Dik 
509*62224350SCasper H.S. Dik 	fd = -1;
510*62224350SCasper H.S. Dik 
511*62224350SCasper H.S. Dik 	if (pkgcmd(server, pfcmd, len, NULL, NULL, &fd) != 0 || fd == -1) {
512*62224350SCasper H.S. Dik 		progerr(gettext(ERR_START_FILTER));
513*62224350SCasper H.S. Dik 		return (-1);
514*62224350SCasper H.S. Dik 	}
515*62224350SCasper H.S. Dik 	(void) fcntl(fd, F_SETFD, FD_CLOEXEC);
516*62224350SCasper H.S. Dik 
517*62224350SCasper H.S. Dik 	server->fp = fdopen(fd, "r");
518*62224350SCasper H.S. Dik 	if (server->fp == NULL) {
519*62224350SCasper H.S. Dik 		(void) close(fd);
520*62224350SCasper H.S. Dik 		progerr(gettext(ERR_START_FILTER));
521*62224350SCasper H.S. Dik 		return (-1);
522*62224350SCasper H.S. Dik 	}
523*62224350SCasper H.S. Dik 	return (0);
524*62224350SCasper H.S. Dik }
525*62224350SCasper H.S. Dik 
526*62224350SCasper H.S. Dik void
527*62224350SCasper H.S. Dik pkgclosefilter(PKGserver server)
528*62224350SCasper H.S. Dik {
529*62224350SCasper H.S. Dik 	if (server->fp != NULL) {
530*62224350SCasper H.S. Dik 		(void) fclose(server->fp);
531*62224350SCasper H.S. Dik 		server->fp = NULL;
532*62224350SCasper H.S. Dik 	}
533*62224350SCasper H.S. Dik }
534*62224350SCasper H.S. Dik 
535*62224350SCasper H.S. Dik /*
536*62224350SCasper H.S. Dik  * Report the next entry from the contents file.
537*62224350SCasper H.S. Dik  */
538*62224350SCasper H.S. Dik char *
539*62224350SCasper H.S. Dik pkggetentry(PKGserver server, int *len, int *pathlen)
540*62224350SCasper H.S. Dik {
541*62224350SCasper H.S. Dik 	int num[2];
542*62224350SCasper H.S. Dik 
543*62224350SCasper H.S. Dik 	if (server->fp == NULL)
544*62224350SCasper H.S. Dik 		return (NULL);
545*62224350SCasper H.S. Dik 
546*62224350SCasper H.S. Dik 	if (feof(server->fp) || ferror(server->fp))
547*62224350SCasper H.S. Dik 		return (NULL);
548*62224350SCasper H.S. Dik 
549*62224350SCasper H.S. Dik 	if (fread(num, sizeof (int), 2, server->fp) != 2)
550*62224350SCasper H.S. Dik 		return (NULL);
551*62224350SCasper H.S. Dik 
552*62224350SCasper H.S. Dik 	if (num[0] > server->buflen) {
553*62224350SCasper H.S. Dik 		free(server->curbuf);
554*62224350SCasper H.S. Dik 		server->buflen = num[0];
555*62224350SCasper H.S. Dik 		server->curbuf = malloc(server->buflen);
556*62224350SCasper H.S. Dik 		if (server->curbuf == NULL)
557*62224350SCasper H.S. Dik 			return (NULL);
558*62224350SCasper H.S. Dik 	}
559*62224350SCasper H.S. Dik 	if (fread(server->curbuf, 1, num[0], server->fp) != num[0])
560*62224350SCasper H.S. Dik 		return (NULL);
561*62224350SCasper H.S. Dik 
562*62224350SCasper H.S. Dik 	*len = num[0];
563*62224350SCasper H.S. Dik 	*pathlen = num[1];
564*62224350SCasper H.S. Dik 
565*62224350SCasper H.S. Dik 	return (server->curbuf);
566*62224350SCasper H.S. Dik }
567*62224350SCasper H.S. Dik 
568*62224350SCasper H.S. Dik char *
569*62224350SCasper H.S. Dik pkggetentry_named(PKGserver server, const char *path, int *len, int *pathlen)
570*62224350SCasper H.S. Dik {
571*62224350SCasper H.S. Dik 	int plen = strlen(path);
572*62224350SCasper H.S. Dik 	pkgfilter_t *pcmd = alloca(sizeof (*pcmd) + plen);
573*62224350SCasper H.S. Dik 	char *result;
574*62224350SCasper H.S. Dik 	unsigned int rlen;
575*62224350SCasper H.S. Dik 
576*62224350SCasper H.S. Dik 	pcmd->cmd = PKG_FINDFILE;
577*62224350SCasper H.S. Dik 	*pathlen = pcmd->len = plen;
578*62224350SCasper H.S. Dik 	(void) memcpy(pcmd->buf, path, pcmd->len + 1);
579*62224350SCasper H.S. Dik 
580*62224350SCasper H.S. Dik 	result = server->curbuf;
581*62224350SCasper H.S. Dik 	rlen = server->buflen;
582*62224350SCasper H.S. Dik 
583*62224350SCasper H.S. Dik 	if (pkgcmd(server, pcmd, sizeof (*pcmd) + pcmd->len,
584*62224350SCasper H.S. Dik 	    &result, &rlen, NULL) != 0) {
585*62224350SCasper H.S. Dik 		return (NULL);
586*62224350SCasper H.S. Dik 	}
587*62224350SCasper H.S. Dik 	if (rlen == 0)
588*62224350SCasper H.S. Dik 		return (NULL);
589*62224350SCasper H.S. Dik 
590*62224350SCasper H.S. Dik 	/* Result too big */
591*62224350SCasper H.S. Dik 	if (result != server->curbuf) {
592*62224350SCasper H.S. Dik 		free(server->curbuf);
593*62224350SCasper H.S. Dik 		server->buflen = rlen;
594*62224350SCasper H.S. Dik 		server->curbuf = malloc(server->buflen);
595*62224350SCasper H.S. Dik 		if (server->curbuf == NULL)
596*62224350SCasper H.S. Dik 			return (NULL);
597*62224350SCasper H.S. Dik 		(void) memcpy(server->curbuf, result, rlen);
598*62224350SCasper H.S. Dik 		(void) munmap(result, rlen);
599*62224350SCasper H.S. Dik 	}
600*62224350SCasper H.S. Dik 	*len = rlen;
601*62224350SCasper H.S. Dik 
602*62224350SCasper H.S. Dik 	return (server->curbuf);
603*62224350SCasper H.S. Dik }
604