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