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