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 **
next_n(int * n,char ** nwpkg)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
pkglist_cont(char * keyword)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 **
gpkglist(char * dir,char ** pkg,char ** catg)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
is_not_valid_category(char ** category,char * progname)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
is_not_valid_length(char ** category)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
is_same_CATEGORY(char ** category,char * persistent_category)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 **
get_categories(char * catg_arg)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