1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 
30 
31 
32 #include <stdio.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <ctype.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <locale.h>
39 #include <libintl.h>
40 #include <pkglocs.h>
41 #include <pkglib.h>
42 #include "libinst.h"
43 
44 int	cl_NClasses = -1;
45 static int	cl_handle = -1;	/* list array handle */
46 
47 struct cl_attr	**cl_Classes = NULL;
48 
49 static int new_order;
50 static struct cl_attr	*new_cl_attr(char *cl_name);
51 
52 static unsigned	s_verify(char *class_name), d_verify(char *class_name);
53 static unsigned	s_pathtype(char *class_name);
54 
55 #define	MALSIZ	64
56 #define	ERR_MEMORY	"memory allocation failure"
57 
58 static struct cl_attr *
new_cl_attr(char * cl_name)59 new_cl_attr(char *cl_name)
60 {
61 	struct cl_attr *class, **class_ptr;
62 
63 	if (cl_handle == -1) {
64 		cl_handle = ar_create(MALSIZ, sizeof (struct cl_attr),
65 		    "package class");
66 		if (cl_handle == -1) {
67 			progerr(gettext(ERR_MEMORY));
68 			return (NULL);
69 		}
70 	}
71 
72 	class_ptr = (struct cl_attr **)ar_next_avail(cl_handle);
73 
74 	if (class_ptr == NULL || *class_ptr == NULL) {
75 		progerr(gettext(ERR_MEMORY));
76 		return (NULL);
77 	}
78 
79 	class = *class_ptr;
80 
81 	strcpy(class->name, cl_name);
82 	class->inst_script = NULL;
83 	class->rem_script = NULL;
84 	class->src_verify = s_verify(cl_name);
85 	class->dst_verify = d_verify(cl_name);
86 	class->relpath_2_CAS = s_pathtype(cl_name);
87 
88 	return (class);
89 }
90 
91 /* Insert a single class into the list. */
92 void
addlist(struct cl_attr *** listp,char * item)93 addlist(struct cl_attr ***listp, char *item)
94 {
95 	int	i;
96 
97 	/* If the list is already there, scan for this item */
98 	if (*listp) {
99 		for (i = 0; (*listp)[i]; i++)
100 			if (strcmp(item, (*listp)[i]->name) == 0)
101 				return;
102 	} else {
103 		i = 0;
104 	}
105 
106 	/* Insert the new entry */
107 	if (new_cl_attr(item) == NULL)
108 		quit(99);
109 
110 	/* Point the passed pointer to the head of the list. */
111 	(*listp) = (struct cl_attr **)ar_get_head(cl_handle);
112 }
113 
114 /*
115  * Create a list of all classes involved in this installation as well as
116  * their attributes.
117  */
118 int
setlist(struct cl_attr *** plist,char * slist)119 setlist(struct cl_attr ***plist, char *slist)
120 {
121 	struct cl_attr	**list, *struct_ptr;
122 	char	*pt;
123 	int	n;
124 	int	i;
125 	int	sn = -1;
126 
127 	/* Initialize the environment scanners. */
128 	(void) s_verify(NULL);
129 	(void) d_verify(NULL);
130 	(void) s_pathtype(NULL);
131 
132 	n = 0;
133 
134 	/*
135 	 * This looks like a serious memory leak, however pkgmk depends on
136 	 * this creating a second list and forgetting any prior ones. The
137 	 * pkgmk utility does a reasonable job of keeping track of a prior
138 	 * list constructed from the prototype file using addlist() above.
139 	 * Perhaps this should be reviewed later, but I do not believe this
140 	 * to be a problem from what I've seen. - JST
141 	 */
142 	cl_handle = -1;		/* forget other lists */
143 
144 	/* Isolate the first token. */
145 	pt = strtok(slist, " \t\n");
146 	while (pt) {
147 		if (sn == -1 && strcmp(pt, "none") == 0)
148 			sn = n;
149 
150 		/* Add new class to list. */
151 		if ((struct_ptr = new_cl_attr(pt)) == NULL)
152 			quit(99);
153 
154 		/* Next token. */
155 		n++;
156 		pt = strtok(NULL, " \t\n");
157 		if (pt && sn != -1)
158 			if (strcmp(pt, "none") == 0)
159 				pt = strtok(NULL, " \t\n");
160 	}
161 	/*
162 	 * According to the ABI, if there is a class "none", it will be
163 	 * the first class to be installed.  This insures that iff there
164 	 * is a class "none", it will be the first to be installed.
165 	 * If there is no class "none", nothing happens!
166 	 */
167 	new_order = 0;
168 
169 	/* Get the head of the array. */
170 	list = (struct cl_attr **)ar_get_head(cl_handle);
171 
172 	if (sn > 0) {
173 		struct_ptr = list[sn];
174 		for (i = sn; i > 0; i--)
175 			list[i] = list[i - 1];
176 		list[0] = struct_ptr;
177 		new_order++;	/* the order is different now */
178 	}
179 
180 	/* Point the passed pointer to the head of the list. */
181 	*plist = list;
182 
183 	return (n);
184 }
185 
186 /* Process the class list from the caller. */
187 void
cl_sets(char * slist)188 cl_sets(char *slist)
189 {
190 	char *list_ptr;
191 
192 	/* If there is a list, process it; else skip it */
193 	if (slist && *slist) {
194 		list_ptr = qstrdup(slist);
195 
196 		if (list_ptr && *list_ptr) {
197 			cl_NClasses = setlist(&cl_Classes, list_ptr);
198 			if (new_order)		/* if list order changed ... */
199 				/* ... tell the environment. */
200 				cl_putl("CLASSES", cl_Classes);
201 		}
202 	}
203 }
204 
205 int
cl_getn(void)206 cl_getn(void)
207 {
208 	return (cl_NClasses);
209 }
210 
211 /*
212  * Since the order may have changed, this puts the CLASSES list back into
213  * the environment in the precise order to be used.
214  */
215 void
cl_putl(char * parm_name,struct cl_attr ** list)216 cl_putl(char *parm_name, struct cl_attr **list)
217 {
218 	int i;
219 	size_t j;
220 	char *pt = NULL;
221 
222 	if (list && *list) {
223 		j = 1; /* room for ending null */
224 		for (i = 0; list[i]; i++)
225 			j += strlen(list[i]->name) + 1;
226 		pt = calloc(j, sizeof (char));
227 		(void) strcpy(pt, list[0]->name);
228 		for (i = 1; list[i]; i++) {
229 			(void) strcat(pt, " ");
230 			(void) strcat(pt, list[i]->name);
231 		}
232 		if (parm_name && *parm_name)
233 			putparam(parm_name, pt);
234 		free(pt);
235 	}
236 }
237 
238 
239 int
cl_idx(char * cl_nam)240 cl_idx(char *cl_nam)
241 {
242 	int	n;
243 
244 	for (n = 0; n < cl_NClasses; n++)
245 		if (strcmp(cl_Classes[n]->name, cl_nam) == 0)
246 			return (n);
247 	return (-1);
248 }
249 
250 /* Return source verification level for this class */
251 unsigned
cl_svfy(int idx)252 cl_svfy(int idx)
253 {
254 	if (cl_Classes && idx >= 0 && idx < cl_NClasses)
255 		return (cl_Classes[idx]->src_verify);
256 	return (0);
257 }
258 
259 /* Return destination verify level for this class */
260 unsigned
cl_dvfy(int idx)261 cl_dvfy(int idx)
262 {
263 	if (cl_Classes && idx >= 0 && idx < cl_NClasses)
264 		return (cl_Classes[idx]->dst_verify);
265 	return (0);
266 }
267 
268 /* Return path argument type for this class. */
269 unsigned
cl_pthrel(int idx)270 cl_pthrel(int idx)
271 {
272 	if (cl_Classes && idx >= 0 && idx < cl_NClasses)
273 		return (cl_Classes[idx]->relpath_2_CAS);
274 	return (0);
275 }
276 
277 /* Return the class name associated with this class index */
278 char *
cl_nam(int idx)279 cl_nam(int idx)
280 {
281 	if (cl_Classes && idx >= 0 && idx < cl_NClasses)
282 		return (cl_Classes[idx]->name);
283 	return (NULL);
284 }
285 
286 void
cl_setl(struct cl_attr ** cl_lst)287 cl_setl(struct cl_attr **cl_lst)
288 {
289 	int	i;
290 	int	sn = -1;
291 	struct cl_attr	*pt;
292 
293 	if (cl_lst) {
294 		for (cl_NClasses = 0; cl_lst[cl_NClasses]; cl_NClasses++)
295 			if (strcmp(cl_lst[cl_NClasses]->name, "none") == 0)
296 				if (sn == -1)
297 					sn = cl_NClasses;
298 		if (sn > 0) {
299 			pt = cl_lst[sn];
300 			for (i = sn; i > 0; i--)
301 				cl_lst[i] = cl_lst[i - 1];
302 			cl_lst[0] = pt;
303 		}
304 		i = 1;
305 		while (i < cl_NClasses) {
306 			if (strcmp(cl_lst[i]->name, "none") == 0)
307 				for (sn = i; sn < (cl_NClasses - 1); sn++)
308 					cl_lst[sn] = cl_lst[sn + 1];
309 			i++;
310 		}
311 		cl_Classes = cl_lst;
312 	} else {
313 		cl_Classes = NULL;
314 		cl_NClasses = -1;
315 	}
316 }
317 
318 /*
319  * Scan the given environment variable for an occurrance of the given
320  * class name. Return 0 if not found or 1 if found.
321  */
322 static unsigned
is_in_env(char * class_name,char * paramname,char ** paramvalue,int * noentry)323 is_in_env(char *class_name, char *paramname, char **paramvalue, int *noentry)
324 {
325 	unsigned retval = 0;
326 	char *test_class;
327 
328 	if (class_name && *class_name) {
329 		/*
330 		 * If a prior getenv() has not failed and there is no
331 		 * environment string then get environment info on
332 		 * this parameter.
333 		 */
334 		if (!(*noentry) && *paramvalue == NULL) {
335 			*paramvalue = getenv(paramname);
336 			if (*paramvalue == NULL)
337 				(*noentry)++;
338 		}
339 
340 		/* If there's something there, evaluate it. */
341 		if (!(*noentry)) {
342 			int n;
343 
344 			n = strlen(class_name);	/* end of class name */
345 			test_class = *paramvalue;	/* environ ptr */
346 
347 			while (test_class = strstr(test_class, class_name)) {
348 				/*
349 				 * At this point we have a pointer to a
350 				 * substring within param that matches
351 				 * class_name for its length, but class_name
352 				 * may be a substring of the test_class, so
353 				 * we check that next.
354 				 */
355 				if (isspace(*(test_class + n)) ||
356 				    *(test_class + n) == '\0') {
357 					retval = 1;
358 					break;
359 				}
360 				if (*(++test_class) == '\0')
361 					break;
362 			}
363 		}
364 	}
365 	return (retval);
366 }
367 
368 /* Assign source path verification level to this class */
369 static unsigned
s_verify(char * class_name)370 s_verify(char *class_name)
371 {
372 	static int noentry;
373 	static char *noverify;
374 
375 	if (class_name == NULL) {	/* initialize */
376 		noentry = 0;
377 		noverify = NULL;
378 	} else {
379 		if (is_in_env(class_name, "PKG_SRC_NOVERIFY", &noverify,
380 		    &noentry))
381 			return (NOVERIFY);
382 		else
383 			return (DEFAULT);
384 	}
385 	return (0);
386 }
387 
388 /*
389  * Set destination verify to default. This is usually called by pkgdbmerg()
390  * in order to correct verification conflicts.
391  */
392 void
cl_def_dverify(int idx)393 cl_def_dverify(int idx)
394 {
395 	if (cl_Classes && idx >= 0 && idx < cl_NClasses)
396 		cl_Classes[idx]->dst_verify = DEFAULT;
397 }
398 
399 /* Assign destination path verification level to this path. */
400 static unsigned
d_verify(char * class_name)401 d_verify(char *class_name)
402 {
403 	static int noentry;
404 	static char *qkverify;
405 
406 	if (class_name == NULL) {	/* initialize */
407 		noentry = 0;
408 		qkverify = NULL;
409 	} else {
410 		if (is_in_env(class_name, "PKG_DST_QKVERIFY", &qkverify,
411 		    &noentry))
412 			return (QKVERIFY);
413 		else
414 			return (DEFAULT);
415 	}
416 	return (0);
417 }
418 
419 /* Assign CAS path type to this class */
420 static unsigned
s_pathtype(char * class_name)421 s_pathtype(char *class_name)
422 {
423 	static int noentry;
424 	static char *type_list;
425 
426 	if (class_name == NULL) {	/* initialize */
427 		noentry = 0;
428 		type_list = NULL;
429 	} else {
430 		if (is_in_env(class_name, "PKG_CAS_PASSRELATIVE", &type_list,
431 		    &noentry))
432 			return (REL_2_CAS);
433 		else
434 			return (DEFAULT);
435 	}
436 	return (0);
437 }
438