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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 /* 25 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 26 * Use is subject to license terms. 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.1 */ 30 /*LINTLIBRARY*/ 31 32 /* 5-20-92 newroot support added */ 33 34 #include <stdio.h> 35 #include <limits.h> 36 #include <ctype.h> 37 #include <errno.h> 38 #include <string.h> 39 #include <sys/types.h> 40 #include <pkgstrct.h> 41 #include <pkginfo.h> 42 #include <pkglocs.h> 43 #include <stdlib.h> 44 #include <unistd.h> 45 #include "libadm.h" 46 47 #define VALSIZ 128 48 #define NEWLINE '\n' 49 #define ESCAPE '\\' 50 51 static char sepset[] = ":=\n"; 52 static char qset[] = "'\""; 53 static char *pkg_inst_root = NULL; 54 55 char *pkgdir = NULL; 56 char *pkgfile = NULL; 57 58 static char Adm_pkgold[PATH_MAX] = { 0 }; /* added for newroot */ 59 static char Adm_pkgloc[PATH_MAX] = { 0 }; /* added for newroot */ 60 static char Adm_pkgadm[PATH_MAX] = { 0 }; /* added for newroot */ 61 62 /* 63 * This looks in a directory that might be the top level directory of a 64 * package. It tests a temporary install directory first and then for a 65 * standard directory. This looks a little confusing, so here's what's 66 * happening. If this pkginfo is being openned in a script during a pkgadd 67 * which is updating an existing package, the original pkginfo file is in a 68 * directory that has been renamed from <pkginst> to .save.<pkginst>. If the 69 * pkgadd fails it will be renamed back to <pkginst>. We are always interested 70 * in the OLD pkginfo data because the new pkginfo data is already in our 71 * environment. For that reason, we try to open the backup first - that has 72 * the old data. This returns the first accessible path in "path" and a "1" 73 * if an appropriate pkginfo file was found. It returns a 0 if no type of 74 * pkginfo was located. 75 */ 76 int 77 pkginfofind(char *path, char *pkg_dir, char *pkginst) 78 { 79 int len = 0; 80 81 /* Construct the temporary pkginfo file name. */ 82 len = snprintf(path, PATH_MAX, "%s/.save.%s/pkginfo", pkg_dir, 83 pkginst); 84 if (len > PATH_MAX) 85 return (0); 86 if (access(path, 0)) { 87 /* 88 * This isn't a temporary directory, so we look for a 89 * regular one. 90 */ 91 len = snprintf(path, PATH_MAX, "%s/%s/pkginfo", pkg_dir, 92 pkginst); 93 if (len > PATH_MAX) 94 return (0); 95 if (access(path, 0)) 96 return (0); /* doesn't appear to be a package */ 97 } 98 99 return (1); 100 } 101 102 /* 103 * This opens the appropriate pkginfo file for a particular package. 104 */ 105 FILE * 106 pkginfopen(char *pkg_dir, char *pkginst) 107 { 108 FILE *fp = NULL; 109 char temp[PATH_MAX]; 110 111 if (pkginfofind(temp, pkg_dir, pkginst)) 112 fp = fopen(temp, "r"); 113 114 return (fp); 115 } 116 117 118 char * 119 fpkgparam(FILE *fp, char *param) 120 { 121 char ch, buffer[VALSIZ]; 122 char *mempt, *copy; 123 int c, n; 124 boolean_t check_end_quote = B_FALSE; 125 boolean_t begline, quoted, escape; 126 int idx = 0; 127 128 if (param == NULL) { 129 errno = ENOENT; 130 return (NULL); 131 } 132 133 mempt = NULL; 134 135 for (;;) { /* For each entry in the file fp */ 136 copy = buffer; 137 n = 0; 138 139 /* Get the next token. */ 140 while ((c = getc(fp)) != EOF) { 141 ch = (char)c; 142 if (strchr(sepset, ch)) 143 break; 144 if (++n < VALSIZ) 145 *copy++ = ch; 146 } 147 148 /* If it's the end of the file, exit the for() loop */ 149 if (c == EOF) { 150 errno = EINVAL; 151 return (NULL); /* No more entries left */ 152 153 /* If it's end of line, look for the next parameter. */ 154 } else if (c == NEWLINE) 155 continue; 156 157 /* At this point copy points to the end of a valid parameter. */ 158 *copy = '\0'; /* Terminate the string. */ 159 if (buffer[0] == '#') /* If it's a comment, drop thru. */ 160 copy = NULL; /* Comments don't get buffered. */ 161 else { 162 /* If parameter is NULL, we return whatever we got. */ 163 if (param[0] == '\0') { 164 (void) strcpy(param, buffer); 165 copy = buffer; 166 167 /* If this doesn't match the parameter, drop thru. */ 168 } else if (strcmp(param, buffer)) 169 copy = NULL; 170 171 /* Otherwise, this is our boy. */ 172 else 173 copy = buffer; 174 } 175 176 n = 0; 177 quoted = escape = B_FALSE; 178 begline = B_TRUE; /* Value's line begins */ 179 180 /* Now read the parameter value. */ 181 while ((c = getc(fp)) != EOF) { 182 ch = (char)c; 183 184 if (begline && ((ch == ' ') || (ch == '\t'))) 185 continue; /* Ignore leading white space */ 186 187 /* 188 * Take last end quote 'verbatim' if anything 189 * other than space, newline and escape. 190 * Example: 191 * PARAM1="zonename="test-zone"" 192 * Here in this example the letter 't' inside 193 * the value is followed by '"', this makes 194 * the previous end quote candidate '"', 195 * a part of value and the end quote 196 * disqualfies. Reset check_end_quote. 197 * PARAM2="value"<== newline here 198 * PARAM3="value"\ 199 * "continued"<== newline here. 200 * Check for end quote continues. 201 */ 202 if (ch != NEWLINE && ch != ' ' && ch != ESCAPE && 203 ch != '\t' && check_end_quote) 204 check_end_quote = B_FALSE; 205 206 if (ch == NEWLINE) { 207 if (!escape) { 208 /* 209 * The end quote candidate qualifies. 210 * Eat any trailing spaces. 211 */ 212 if (check_end_quote) { 213 copy -= n - idx; 214 n = idx; 215 check_end_quote = B_FALSE; 216 quoted = B_FALSE; 217 } 218 break; /* End of entry */ 219 } 220 /* 221 * The end quote if exists, doesn't qualify. 222 * Eat end quote and trailing spaces if any. 223 * Value spans to next line. 224 */ 225 if (check_end_quote) { 226 copy -= n - idx; 227 n = idx; 228 check_end_quote = B_FALSE; 229 } else if (copy) { 230 copy--; /* Eat previous esc */ 231 n--; 232 } 233 escape = B_FALSE; 234 begline = B_TRUE; /* New input line */ 235 continue; 236 } else { 237 if (!escape && strchr(qset, ch)) { 238 /* Handle quotes */ 239 if (begline) { 240 /* Starting quote */ 241 quoted = B_TRUE; 242 begline = B_FALSE; 243 continue; 244 } else if (quoted) { 245 /* 246 * This is the candidate 247 * for end quote. Check 248 * to see it qualifies. 249 */ 250 check_end_quote = B_TRUE; 251 idx = n; 252 } 253 } 254 if (ch == ESCAPE) 255 escape = B_TRUE; 256 else if (escape) 257 escape = B_FALSE; 258 if (copy) *copy++ = ch; 259 begline = B_FALSE; 260 } 261 262 if (copy && ((++n % VALSIZ) == 0)) { 263 if (mempt) { 264 mempt = realloc(mempt, 265 (n+VALSIZ)*sizeof (char)); 266 if (!mempt) 267 return (NULL); 268 } else { 269 mempt = calloc((size_t)(2*VALSIZ), 270 sizeof (char)); 271 if (!mempt) 272 return (NULL); 273 (void) strncpy(mempt, buffer, n); 274 } 275 copy = &mempt[n]; 276 } 277 } 278 279 /* 280 * Don't allow trailing white space. 281 * NOTE : White space in the middle is OK, since this may 282 * be a list. At some point it would be a good idea to let 283 * this function know how to validate such a list. -- JST 284 * 285 * Now while there's a parametric value and it ends in a 286 * space and the actual remaining string length is still 287 * greater than 0, back over the space. 288 */ 289 while (copy && isspace((unsigned char)*(copy - 1)) && n-- > 0) 290 copy--; 291 292 if (quoted) { 293 if (mempt) 294 (void) free(mempt); 295 errno = EFAULT; /* missing closing quote */ 296 return (NULL); 297 } 298 if (copy) { 299 *copy = '\0'; 300 break; 301 } 302 if (c == EOF) { 303 errno = EINVAL; /* parameter not found */ 304 return (NULL); 305 } 306 } 307 308 if (!mempt) 309 mempt = strdup(buffer); 310 else 311 mempt = realloc(mempt, (strlen(mempt)+1)*sizeof (char)); 312 return (mempt); 313 } 314 315 char * 316 pkgparam(char *pkg, char *param) 317 { 318 static char lastfname[PATH_MAX]; 319 static FILE *fp = NULL; 320 char *pt, *copy, *value, line[PATH_MAX]; 321 322 if (!pkgdir) 323 pkgdir = get_PKGLOC(); 324 325 if (!pkg) { 326 /* request to close file */ 327 if (fp) { 328 (void) fclose(fp); 329 fp = NULL; 330 } 331 return (NULL); 332 } 333 334 if (!param) { 335 errno = ENOENT; 336 return (NULL); 337 } 338 339 if (pkgfile) 340 (void) strcpy(line, pkgfile); /* filename was passed */ 341 else 342 (void) pkginfofind(line, pkgdir, pkg); 343 344 if (fp && strcmp(line, lastfname)) { 345 /* different filename implies need for different fp */ 346 (void) fclose(fp); 347 fp = NULL; 348 } 349 if (!fp) { 350 (void) strcpy(lastfname, line); 351 if ((fp = fopen(lastfname, "r")) == NULL) 352 return (NULL); 353 } 354 355 /* 356 * if parameter is a null string, then the user is requesting us 357 * to find the value of the next available parameter for this 358 * package and to copy the parameter name into the provided string; 359 * if it is not, then it is a request for a specified parameter, in 360 * which case we rewind the file to start search from beginning 361 */ 362 if (param[0]) { 363 /* new parameter request, so reset file position */ 364 if (fseek(fp, 0L, 0)) 365 return (NULL); 366 } 367 368 if (pt = fpkgparam(fp, param)) { 369 if (strcmp(param, "ARCH") == NULL || 370 strcmp(param, "CATEGORY") == NULL) { 371 /* remove all whitespace from value */ 372 value = copy = pt; 373 while (*value) { 374 if (!isspace((unsigned char)*value)) 375 *copy++ = *value; 376 value++; 377 } 378 *copy = '\0'; 379 } 380 return (pt); 381 } 382 return (NULL); 383 } 384 /* 385 * This routine sets adm_pkgloc and adm_pkgadm which are the 386 * replacement location for PKGLOC and PKGADM. 387 */ 388 389 static void canonize_name(char *); 390 391 void 392 set_PKGpaths(char *path) 393 { 394 if (path && *path) { 395 (void) sprintf(Adm_pkgloc, "%s%s", path, PKGLOC); 396 (void) sprintf(Adm_pkgold, "%s%s", path, PKGOLD); 397 (void) sprintf(Adm_pkgadm, "%s%s", path, PKGADM); 398 set_install_root(path); 399 } else { 400 (void) sprintf(Adm_pkgloc, "%s", PKGLOC); 401 (void) sprintf(Adm_pkgold, "%s", PKGOLD); 402 (void) sprintf(Adm_pkgadm, "%s", PKGADM); 403 } 404 canonize_name(Adm_pkgloc); 405 canonize_name(Adm_pkgold); 406 canonize_name(Adm_pkgadm); 407 pkgdir = Adm_pkgloc; 408 } 409 410 char * 411 get_PKGLOC(void) 412 { 413 if (Adm_pkgloc[0] == NULL) 414 return (PKGLOC); 415 else 416 return (Adm_pkgloc); 417 } 418 419 char * 420 get_PKGOLD(void) 421 { 422 if (Adm_pkgold[0] == NULL) 423 return (PKGOLD); 424 else 425 return (Adm_pkgold); 426 } 427 428 char * 429 get_PKGADM(void) 430 { 431 if (Adm_pkgadm[0] == NULL) 432 return (PKGADM); 433 else 434 return (Adm_pkgadm); 435 } 436 437 void 438 set_PKGADM(char *newpath) 439 { 440 (void) strcpy(Adm_pkgadm, newpath); 441 } 442 443 void 444 set_PKGLOC(char *newpath) 445 { 446 (void) strcpy(Adm_pkgloc, newpath); 447 } 448 449 #define isdot(x) ((x[0] == '.')&&(!x[1]||(x[1] == '/'))) 450 #define isdotdot(x) ((x[0] == '.')&&(x[1] == '.')&&(!x[2]||(x[2] == '/'))) 451 452 static void 453 canonize_name(char *file) 454 { 455 char *pt, *last; 456 int level; 457 458 /* Remove references such as "./" and "../" and "//" */ 459 460 for (pt = file; *pt; ) { 461 if (isdot(pt)) 462 (void) strcpy(pt, pt[1] ? pt+2 : pt+1); 463 else if (isdotdot(pt)) { 464 level = 0; 465 last = pt; 466 do { 467 level++; 468 last += 2; 469 if (*last) 470 last++; 471 } while (isdotdot(last)); 472 --pt; /* point to previous '/' */ 473 while (level--) { 474 if (pt <= file) 475 return; 476 while ((*--pt != '/') && (pt > file)) 477 ; 478 } 479 if (*pt == '/') 480 pt++; 481 (void) strcpy(pt, last); 482 } else { 483 while (*pt && (*pt != '/')) 484 pt++; 485 if (*pt == '/') { 486 while (pt[1] == '/') 487 (void) strcpy(pt, pt+1); 488 pt++; 489 } 490 } 491 } 492 if ((--pt > file) && (*pt == '/')) 493 *pt = '\0'; 494 } 495 496 void 497 set_install_root(char *path) 498 { 499 pkg_inst_root = strdup(path); 500 } 501 502 char * 503 get_install_root() 504 { 505 return (pkg_inst_root); 506 } 507