xref: /illumos-gate/usr/src/lib/libpkg/common/gpkglist.c (revision 2bbdd445a21f9d61f4a0ca0faf05d5ceb2bd91f3)
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 2009 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 <ctype.h>
34 #include <string.h>
35 #include <signal.h>
36 #include <errno.h>
37 #include <stdlib.h>
38 #include <valtools.h>
39 #include "pkginfo.h"
40 #include "pkglib.h"
41 #include "pkglibmsgs.h"
42 #include "pkgstrct.h"
43 #include "pkglocale.h"
44 
45 extern char	*pkgdir; 		/* WHERE? */
46 
47 /* libadm.a */
48 extern CKMENU	*allocmenu(char *label, int attr);
49 extern int	ckitem(CKMENU *menup, char *item[], short max, char *defstr,
50 				char *error, char *help, char *prompt);
51 extern int	pkgnmchk(register char *pkg, register char *spec,
52 				int presvr4flg);
53 extern int	fpkginfo(struct pkginfo *info, char *pkginst);
54 extern char	*fpkginst(char *pkg, ...);
55 extern int	setinvis(CKMENU *menup, char *choice);
56 extern int	setitem(CKMENU *menup, char *choice);
57 
58 #define	CMDSIZ			512
59 #define	LSIZE			256
60 #define	MAXSIZE			128
61 #define	MALLOCSIZ		128
62 #define	MAX_CAT_ARGS	64
63 #define	MAX_CAT_LEN		16
64 
65 static int	cont_in_list = 0;	/* live continuation */
66 static char	cont_keyword[PKGSIZ+1];	/* the continuation keyword */
67 
68 /*
69  * Allocate memory for the next package name. This function attempts the
70  * allocation and if that succeeds, returns a pointer to the new memory
71  * location and increments "n". Otherwise, it returens NULL and n is
72  * unchanged.
73  */
74 static char **
75 next_n(int *n, char **nwpkg)
76 {
77 	int loc_n = *n;
78 
79 	if ((++loc_n % MALLOCSIZ) == 0) {
80 		nwpkg = (char **)realloc(nwpkg,
81 			(loc_n+MALLOCSIZ) * sizeof (char **));
82 		if (nwpkg == NULL) {
83 			progerr(pkg_gt(ERR_MEMORY), errno);
84 			errno = ENOMEM;
85 			return (NULL);
86 		}
87 	}
88 
89 	*n = loc_n;
90 	return (nwpkg);
91 }
92 
93 /*
94  * This informs gpkglist() to put a keyword at the head of the pkglist. This
95  * was originally intended for live continue, but it may have other
96  * applications as well.
97  */
98 void
99 pkglist_cont(char *keyword)
100 {
101 	cont_in_list = 1;
102 	(void) strncpy(cont_keyword, keyword, PKGSIZ);
103 }
104 
105 /*
106  * This function constructs the list of packages that the user wants managed.
107  * It may be a list on the command line, it may be some or all of the
108  * packages in a directory or it may be a continuation from a previous
109  * dryrun. It may also be a list of pkgs gathered from the CATEGORY parameter
110  * in a spooled or installed pkginfo file.
111  */
112 char **
113 gpkglist(char *dir, char **pkg, char **catg)
114 {
115 	struct _choice_ *chp;
116 	struct pkginfo info;
117 	char	*inst;
118 	CKMENU	*menup;
119 	char	temp[LSIZE];
120 	char	*savedir, **nwpkg;
121 	int	i, n;
122 
123 	savedir = pkgdir;
124 	pkgdir = dir;
125 
126 	info.pkginst = NULL; /* initialize for memory handling */
127 	if (pkginfo(&info, "all", NULL, NULL)) {
128 		errno = ENOPKG; /* contains no valid packages */
129 		pkgdir = savedir;
130 		return (NULL);
131 	}
132 
133 	/*
134 	 * If no explicit list was provided and this is not a continuation
135 	 * (implying a certain level of direction on the caller's part)
136 	 * present a menu of available packages for installation.
137 	 */
138 	if (pkg[0] == NULL && !cont_in_list) {
139 		menup = allocmenu(pkg_gt(HEADER), CKALPHA);
140 		if (setinvis(menup, "all")) {
141 			errno = EFAULT;
142 			return (NULL);
143 		}
144 		do {
145 			/* bug id 1087404 */
146 			if (!info.pkginst || !info.name || !info.arch ||
147 			    !info.version)
148 				continue;
149 			(void) snprintf(temp, sizeof (temp),
150 			    "%s %s\n(%s) %s", info.pkginst,
151 			    info.name, info.arch, info.version);
152 			if (setitem(menup, temp)) {
153 				errno = EFAULT;
154 				return (NULL);
155 			}
156 		} while (pkginfo(&info, "all", NULL, NULL) == 0);
157 		/* clear memory usage by pkginfo */
158 		(void) pkginfo(&info, NULL, NULL, NULL);
159 		pkgdir = savedir; 	/* restore pkgdir to orig value */
160 
161 		nwpkg = (char **)calloc(MALLOCSIZ, sizeof (char **));
162 		n = ckitem(menup, nwpkg, MALLOCSIZ, "all", NULL,
163 		    pkg_gt(HELP), pkg_gt(PROMPT));
164 		if (n) {
165 			free(nwpkg);
166 			errno = ((n == 3) ? EINTR : EFAULT);
167 			pkgdir = savedir;
168 			return (NULL);
169 		}
170 		if (strcmp(nwpkg[0], "all") == 0) {
171 			chp = menup->choice;
172 			for (n = 0; chp; /* void */) {
173 				nwpkg[n] = strdup(chp->token);
174 				nwpkg = next_n(&n, nwpkg);
175 				chp = chp->next;
176 				nwpkg[n] = NULL;
177 			}
178 		} else {
179 			for (n = 0; nwpkg[n]; n++)
180 				nwpkg[n] = strdup(nwpkg[n]);
181 		}
182 		(void) setitem(menup, NULL); /* free resources */
183 		free(menup);
184 		pkgdir = savedir;
185 		return (nwpkg);
186 	}
187 
188 	/* clear memory usage by pkginfo */
189 	(void) pkginfo(&info, NULL, NULL, NULL);
190 
191 	nwpkg = (char **)calloc(MALLOCSIZ, sizeof (char **));
192 
193 	/*
194 	 * pkg array contains the instance identifiers to
195 	 * be selected, or possibly wildcard definitions
196 	 */
197 	i = n = 0;
198 	do {
199 		if (cont_in_list) {	/* This is a live continuation. */
200 			nwpkg[n] = strdup(cont_keyword);
201 			nwpkg = next_n(&n, nwpkg);
202 			nwpkg[n] = NULL;
203 			cont_in_list = 0;	/* handled */
204 
205 			if (pkg[0] == NULL) {	/* It's just a continuation. */
206 				break;
207 			}
208 		} else if (pkgnmchk(pkg[i], "all", 1)) {
209 			/* wildcard specification */
210 			(void) fpkginst(NULL);
211 			inst = fpkginst(pkg[i], NULL, NULL);
212 			if (inst == NULL) {
213 				progerr(pkg_gt(ERR_NOPKG), pkg[i]);
214 				free(nwpkg);
215 				nwpkg = NULL;
216 				errno = ESRCH;
217 				break;
218 			}
219 			do {
220 				if (catg != NULL) {
221 					pkginfo(&info, inst, NULL, NULL);
222 					if (!is_same_CATEGORY(catg,
223 							info.catg))
224 						continue;
225 				}
226 				nwpkg[n] = strdup(inst);
227 				nwpkg = next_n(&n, nwpkg);
228 				nwpkg[n] = NULL;
229 			} while (inst = fpkginst(pkg[i], NULL, NULL));
230 		} else {
231 			if (fpkginfo(&info, pkg[i])) {
232 				progerr(pkg_gt(ERR_NOPKG), pkg[i]);
233 				free(nwpkg);
234 				nwpkg = NULL;
235 				errno = ESRCH;
236 				break;
237 			}
238 			nwpkg[n] = strdup(pkg[i]);
239 			nwpkg = next_n(&n, nwpkg);
240 			nwpkg[n] = NULL;
241 		}
242 	} while (pkg[++i]);
243 
244 	(void) fpkginst(NULL);
245 	(void) fpkginfo(&info, NULL);
246 	pkgdir = savedir; 	/* restore pkgdir to orig value */
247 
248 	if (catg != NULL) {
249 		if (nwpkg[0] == NULL) {
250 
251 			/*
252 			 * No pkgs in the spooled directory matched the
253 			 * category specified by the user.
254 			 */
255 
256 			free(nwpkg);
257 			return (NULL);
258 		}
259 	}
260 	return (nwpkg);
261 }
262 
263 /*
264  * Check category passed in on the command line to see if it is valid.
265  *
266  * returns 0 if the category is valid
267  * returns 1 if the category is invalid
268  */
269 
270 int
271 is_not_valid_category(char **category, char *progname)
272 {
273 	if (strcasecmp(progname, "pkgrm") == 0) {
274 		if (is_same_CATEGORY(category, "system"))
275 			return (1);
276 	}
277 
278 	return (0);
279 }
280 
281 /*
282  * Check category length
283  *
284  * returns 0 if the category length is valid
285  * returns 1 if a category has length > 16 chars as defined by the SVr4 ABI
286  */
287 
288 int
289 is_not_valid_length(char **category)
290 {
291 	int i;
292 
293 	for (i = 0; category[i] != NULL; i++) {
294 		if (strlen(category[i]) > MAX_CAT_LEN)
295 			return (1);
296 	}
297 
298 	return (0);
299 }
300 
301 /*
302  * Check category passed in on the command line against the CATEGORY in the
303  * spooled or installed packages pkginfo file.
304  *
305  * returns 0 if categories match
306  * returns 1 if categories don't match
307  */
308 
309 int
310 is_same_CATEGORY(char **category, char *persistent_category)
311 {
312 	int i, j, n = 0;
313 	char *pers_catg, **pers_catgs;
314 
315 	pers_catg = strdup(persistent_category);
316 
317 	pers_catgs = (char **)calloc(MAX_CAT_LEN, sizeof (char **));
318 
319 	pers_catgs[n++] = strtok(pers_catg, " \t\n, ");
320 	while (pers_catgs[n] = strtok(NULL, " \t\n, "))
321 		n++;
322 
323 	for (i = 0; category[i] != NULL; i++) {
324 		for (j = 0; j < n; j++) {
325 			if (strcasecmp(category[i], pers_catgs[j]) == 0) {
326 				return (1);
327 			}
328 		}
329 	}
330 
331 	return (0);
332 }
333 
334 /*
335  * Given a string of categories, construct a null-terminated array of
336  * categories.
337  *
338  * returns the array of categories or NULL
339  */
340 
341 char **
342 get_categories(char *catg_arg)
343 {
344 	int n = 0;
345 	char *tmp_catg;
346 	char **catgs;
347 
348 	tmp_catg = strdup(catg_arg);
349 
350 	catgs = (char **)calloc(MAX_CAT_LEN, sizeof (char **));
351 
352 	catgs[n++] = strtok(tmp_catg, " \t\n, ");
353 	while (catgs[n] = strtok(NULL, " \t\n, "))
354 		n++;
355 
356 	if (*catgs == NULL)
357 		return (NULL);
358 	else
359 		return (catgs);
360 }
361