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