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
44int	cl_NClasses = -1;
45static int	cl_handle = -1;	/* list array handle */
46
47struct cl_attr	**cl_Classes = NULL;
48
49static int new_order;
50static struct cl_attr	*new_cl_attr(char *cl_name);
51
52static unsigned	s_verify(char *class_name), d_verify(char *class_name);
53static unsigned	s_pathtype(char *class_name);
54
55#define	MALSIZ	64
56#define	ERR_MEMORY	"memory allocation failure"
57
58static struct cl_attr *
59new_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. */
92void
93addlist(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 */
118int
119setlist(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. */
187void
188cl_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
205int
206cl_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 */
215void
216cl_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
239int
240cl_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 */
251unsigned
252cl_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 */
260unsigned
261cl_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. */
269unsigned
270cl_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 */
278char *
279cl_nam(int idx)
280{
281	if (cl_Classes && idx >= 0 && idx < cl_NClasses)
282		return (cl_Classes[idx]->name);
283	return (NULL);
284}
285
286void
287cl_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 */
322static unsigned
323is_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 */
369static unsigned
370s_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 */
392void
393cl_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. */
400static unsigned
401d_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 */
420static unsigned
421s_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