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