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) sprintf(temp, "%s %s\n(%s) %s", info.pkginst, 150 info.name, info.arch, info.version); 151 if (setitem(menup, temp)) { 152 errno = EFAULT; 153 return (NULL); 154 } 155 } while (pkginfo(&info, "all", NULL, NULL) == 0); 156 /* clear memory usage by pkginfo */ 157 (void) pkginfo(&info, NULL, NULL, NULL); 158 pkgdir = savedir; /* restore pkgdir to orig value */ 159 160 nwpkg = (char **)calloc(MALLOCSIZ, sizeof (char **)); 161 n = ckitem(menup, nwpkg, MALLOCSIZ, "all", NULL, 162 pkg_gt(HELP), pkg_gt(PROMPT)); 163 if (n) { 164 free(nwpkg); 165 errno = ((n == 3) ? EINTR : EFAULT); 166 pkgdir = savedir; 167 return (NULL); 168 } 169 if (strcmp(nwpkg[0], "all") == 0) { 170 chp = menup->choice; 171 for (n = 0; chp; /* void */) { 172 nwpkg[n] = strdup(chp->token); 173 nwpkg = next_n(&n, nwpkg); 174 chp = chp->next; 175 nwpkg[n] = NULL; 176 } 177 } else { 178 for (n = 0; nwpkg[n]; n++) 179 nwpkg[n] = strdup(nwpkg[n]); 180 } 181 (void) setitem(menup, NULL); /* free resources */ 182 free(menup); 183 pkgdir = savedir; 184 return (nwpkg); 185 } 186 187 /* clear memory usage by pkginfo */ 188 (void) pkginfo(&info, NULL, NULL, NULL); 189 190 nwpkg = (char **)calloc(MALLOCSIZ, sizeof (char **)); 191 192 /* 193 * pkg array contains the instance identifiers to 194 * be selected, or possibly wildcard definitions 195 */ 196 i = n = 0; 197 do { 198 if (cont_in_list) { /* This is a live continuation. */ 199 nwpkg[n] = strdup(cont_keyword); 200 nwpkg = next_n(&n, nwpkg); 201 nwpkg[n] = NULL; 202 cont_in_list = 0; /* handled */ 203 204 if (pkg[0] == NULL) { /* It's just a continuation. */ 205 break; 206 } 207 } else if (pkgnmchk(pkg[i], "all", 1)) { 208 /* wildcard specification */ 209 (void) fpkginst(NULL); 210 inst = fpkginst(pkg[i], NULL, NULL); 211 if (inst == NULL) { 212 progerr(pkg_gt(ERR_NOPKG), pkg[i]); 213 free(nwpkg); 214 nwpkg = NULL; 215 errno = ESRCH; 216 break; 217 } 218 do { 219 if (catg != NULL) { 220 pkginfo(&info, inst, NULL, NULL); 221 if (!is_same_CATEGORY(catg, 222 info.catg)) 223 continue; 224 } 225 nwpkg[n] = strdup(inst); 226 nwpkg = next_n(&n, nwpkg); 227 nwpkg[n] = NULL; 228 } while (inst = fpkginst(pkg[i], NULL, NULL)); 229 } else { 230 if (fpkginfo(&info, pkg[i])) { 231 progerr(pkg_gt(ERR_NOPKG), pkg[i]); 232 free(nwpkg); 233 nwpkg = NULL; 234 errno = ESRCH; 235 break; 236 } 237 nwpkg[n] = strdup(pkg[i]); 238 nwpkg = next_n(&n, nwpkg); 239 nwpkg[n] = NULL; 240 } 241 } while (pkg[++i]); 242 243 (void) fpkginst(NULL); 244 (void) fpkginfo(&info, NULL); 245 pkgdir = savedir; /* restore pkgdir to orig value */ 246 247 if (catg != NULL) { 248 if (nwpkg[0] == NULL) { 249 250 /* 251 * No pkgs in the spooled directory matched the 252 * category specified by the user. 253 */ 254 255 free(nwpkg); 256 return (NULL); 257 } 258 } 259 return (nwpkg); 260 } 261 262 /* 263 * Check category passed in on the command line to see if it is valid. 264 * 265 * returns 0 if the category is valid 266 * returns 1 if the category is invalid 267 */ 268 269 int 270 is_not_valid_category(char **category, char *progname) 271 { 272 if (strcasecmp(progname, "pkgrm") == 0) { 273 if (is_same_CATEGORY(category, "system")) 274 return (1); 275 } 276 277 return (0); 278 } 279 280 /* 281 * Check category length 282 * 283 * returns 0 if the category length is valid 284 * returns 1 if a category has length > 16 chars as defined by the SVr4 ABI 285 */ 286 287 int 288 is_not_valid_length(char **category) 289 { 290 int i; 291 292 for (i = 0; category[i] != NULL; i++) { 293 if (strlen(category[i]) > MAX_CAT_LEN) 294 return (1); 295 } 296 297 return (0); 298 } 299 300 /* 301 * Check category passed in on the command line against the CATEGORY in the 302 * spooled or installed packages pkginfo file. 303 * 304 * returns 0 if categories match 305 * returns 1 if categories don't match 306 */ 307 308 int 309 is_same_CATEGORY(char **category, char *persistent_category) 310 { 311 int i, j, n = 0; 312 char *pers_catg, **pers_catgs; 313 314 pers_catg = strdup(persistent_category); 315 316 pers_catgs = (char **)calloc(MAX_CAT_LEN, sizeof (char **)); 317 318 pers_catgs[n++] = strtok(pers_catg, " \t\n, "); 319 while (pers_catgs[n] = strtok(NULL, " \t\n, ")) 320 n++; 321 322 for (i = 0; category[i] != NULL; i++) { 323 for (j = 0; j < n; j++) { 324 if (strcasecmp(category[i], pers_catgs[j]) == 0) { 325 return (1); 326 } 327 } 328 } 329 330 return (0); 331 } 332 333 /* 334 * Given a string of categories, construct a null-terminated array of 335 * categories. 336 * 337 * returns the array of categories or NULL 338 */ 339 340 char ** 341 get_categories(char *catg_arg) 342 { 343 int n = 0; 344 char *tmp_catg; 345 char **catgs; 346 347 tmp_catg = strdup(catg_arg); 348 349 catgs = (char **)calloc(MAX_CAT_LEN, sizeof (char **)); 350 351 catgs[n++] = strtok(tmp_catg, " \t\n, "); 352 while (catgs[n] = strtok(NULL, " \t\n, ")) 353 n++; 354 355 if (*catgs == NULL) 356 return (NULL); 357 else 358 return (catgs); 359 } 360