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 (c) 1995-1998 by Sun Microsystems, Inc. 27 * All rights reserved. 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 /* Construct the temporary pkginfo file name. */ 81 (void) sprintf(path, "%s/.save.%s/pkginfo", pkg_dir, pkginst); 82 if (access(path, 0)) { 83 /* 84 * This isn't a temporary directory, so we look for a 85 * regular one. 86 */ 87 (void) sprintf(path, "%s/%s/pkginfo", pkg_dir, pkginst); 88 if (access(path, 0)) 89 return (0); /* doesn't appear to be a package */ 90 } 91 92 return (1); 93 } 94 95 /* 96 * This opens the appropriate pkginfo file for a particular package. 97 */ 98 FILE * 99 pkginfopen(char *pkg_dir, char *pkginst) 100 { 101 FILE *fp = NULL; 102 char temp[PATH_MAX]; 103 104 if (pkginfofind(temp, pkg_dir, pkginst)) 105 fp = fopen(temp, "r"); 106 107 return (fp); 108 } 109 110 111 char * 112 fpkgparam(FILE *fp, char *param) 113 { 114 char ch, buffer[VALSIZ]; 115 char *mempt, *copy; 116 int c, n, escape, begline, quoted; 117 118 if (param == NULL) { 119 errno = ENOENT; 120 return (NULL); 121 } 122 123 mempt = NULL; 124 125 for (;;) { /* for each entry in the file fp */ 126 copy = buffer; 127 n = 0; 128 129 /* Get the next token. */ 130 while ((c = getc(fp)) != EOF) { 131 ch = (char) c; 132 if (strchr(sepset, ch)) 133 break; 134 if (++n < VALSIZ) 135 *copy++ = ch; 136 } 137 138 /* If it's the end of the file, exit the for() loop */ 139 if (c == EOF) { 140 errno = EINVAL; 141 return (NULL); /* no more entries left */ 142 143 /* If it's end of line, look for the next parameter. */ 144 } else if (c == NEWLINE) 145 continue; 146 147 /* At this point copy points to the end of a valid parameter. */ 148 *copy = '\0'; /* Terminate the string. */ 149 if (buffer[0] == '#') /* If it's a comment, drop thru. */ 150 copy = NULL; /* Comments don't get buffered. */ 151 else { 152 /* If parameter is NULL, we return whatever we got. */ 153 if (param[0] == '\0') { 154 (void) strcpy(param, buffer); 155 copy = buffer; 156 157 /* If this doesn't match the parameter, drop thru. */ 158 } else if (strcmp(param, buffer)) 159 copy = NULL; 160 161 /* Otherwise, this is our boy. */ 162 else 163 copy = buffer; 164 } 165 166 n = quoted = escape = 0; 167 begline = 1; 168 169 /* Now read the parameter value. */ 170 while ((c = getc(fp)) != EOF) { 171 ch = (char) c; 172 if (begline && ((ch == ' ') || (ch == '\t'))) 173 continue; /* ignore leading white space */ 174 175 if (ch == NEWLINE) { 176 if (!escape) 177 break; /* end of entry */ 178 if (copy) { 179 if (escape) { 180 copy--; /* eat previous esc */ 181 n--; 182 } 183 *copy++ = NEWLINE; 184 } 185 escape = 0; 186 begline = 1; /* new input line */ 187 } else { 188 if (!escape && strchr(qset, ch)) { 189 /* handle quotes */ 190 if (begline) { 191 quoted++; 192 begline = 0; 193 continue; 194 } else if (quoted) { 195 quoted = 0; 196 continue; 197 } 198 } 199 if (ch == ESCAPE) 200 escape++; 201 else if (escape) 202 escape = 0; 203 if (copy) *copy++ = ch; 204 begline = 0; 205 } 206 207 if (copy && ((++n % VALSIZ) == 0)) { 208 if (mempt) { 209 mempt = realloc(mempt, 210 (n+VALSIZ)*sizeof (char)); 211 if (!mempt) 212 return (NULL); 213 } else { 214 mempt = calloc((size_t)(2*VALSIZ), 215 sizeof (char)); 216 if (!mempt) 217 return (NULL); 218 (void) strncpy(mempt, buffer, n); 219 } 220 copy = &mempt[n]; 221 } 222 } 223 224 /* 225 * Don't allow trailing white space. 226 * NOTE : White space in the middle is OK, since this may 227 * be a list. At some point it would be a good idea to let 228 * this function know how to validate such a list. -- JST 229 * 230 * Now while there's a parametric value and it ends in a 231 * space and the actual remaining string length is still 232 * greater than 0, back over the space. 233 */ 234 while (copy && isspace((unsigned char)*(copy - 1)) && n-- > 0) 235 copy--; 236 237 if (quoted) { 238 if (mempt) 239 (void) free(mempt); 240 errno = EFAULT; /* missing closing quote */ 241 return (NULL); 242 } 243 if (copy) { 244 *copy = '\0'; 245 break; 246 } 247 if (c == EOF) { 248 errno = EINVAL; /* parameter not found */ 249 return (NULL); 250 } 251 } 252 253 if (!mempt) 254 mempt = strdup(buffer); 255 else 256 mempt = realloc(mempt, (strlen(mempt)+1)*sizeof (char)); 257 return (mempt); 258 } 259 260 char * 261 pkgparam(char *pkg, char *param) 262 { 263 static char lastfname[PATH_MAX]; 264 static FILE *fp = NULL; 265 char *pt, *copy, *value, line[PATH_MAX]; 266 267 if (!pkgdir) 268 pkgdir = get_PKGLOC(); 269 270 if (!pkg) { 271 /* request to close file */ 272 if (fp) { 273 (void) fclose(fp); 274 fp = NULL; 275 } 276 return (NULL); 277 } 278 279 if (!param) { 280 errno = ENOENT; 281 return (NULL); 282 } 283 284 if (pkgfile) 285 (void) strcpy(line, pkgfile); /* filename was passed */ 286 else 287 (void) pkginfofind(line, pkgdir, pkg); 288 289 if (fp && strcmp(line, lastfname)) { 290 /* different filename implies need for different fp */ 291 (void) fclose(fp); 292 fp = NULL; 293 } 294 if (!fp) { 295 (void) strcpy(lastfname, line); 296 if ((fp = fopen(lastfname, "r")) == NULL) 297 return (NULL); 298 } 299 300 /* 301 * if parameter is a null string, then the user is requesting us 302 * to find the value of the next available parameter for this 303 * package and to copy the parameter name into the provided string; 304 * if it is not, then it is a request for a specified parameter, in 305 * which case we rewind the file to start search from beginning 306 */ 307 if (param[0]) { 308 /* new parameter request, so reset file position */ 309 if (fseek(fp, 0L, 0)) 310 return (NULL); 311 } 312 313 if (pt = fpkgparam(fp, param)) { 314 if (strcmp(param, "ARCH") == NULL || 315 strcmp(param, "CATEGORY") == NULL) { 316 /* remove all whitespace from value */ 317 value = copy = pt; 318 while (*value) { 319 if (!isspace((unsigned char)*value)) 320 *copy++ = *value; 321 value++; 322 } 323 *copy = '\0'; 324 } 325 return (pt); 326 } 327 return (NULL); 328 } 329 /* 330 * This routine sets adm_pkgloc and adm_pkgadm which are the 331 * replacement location for PKGLOC and PKGADM. 332 */ 333 334 static void canonize_name(char *); 335 336 void 337 set_PKGpaths(char *path) 338 { 339 if (path && *path) { 340 (void) sprintf(Adm_pkgloc, "%s%s", path, PKGLOC); 341 (void) sprintf(Adm_pkgold, "%s%s", path, PKGOLD); 342 (void) sprintf(Adm_pkgadm, "%s%s", path, PKGADM); 343 set_install_root(path); 344 } else { 345 (void) sprintf(Adm_pkgloc, "%s", PKGLOC); 346 (void) sprintf(Adm_pkgold, "%s", PKGOLD); 347 (void) sprintf(Adm_pkgadm, "%s", PKGADM); 348 } 349 canonize_name(Adm_pkgloc); 350 canonize_name(Adm_pkgold); 351 canonize_name(Adm_pkgadm); 352 pkgdir = Adm_pkgloc; 353 } 354 355 char * 356 get_PKGLOC(void) 357 { 358 if (Adm_pkgloc[0] == NULL) 359 return (PKGLOC); 360 else 361 return (Adm_pkgloc); 362 } 363 364 char * 365 get_PKGOLD(void) 366 { 367 if (Adm_pkgold[0] == NULL) 368 return (PKGOLD); 369 else 370 return (Adm_pkgold); 371 } 372 373 char * 374 get_PKGADM(void) 375 { 376 if (Adm_pkgadm[0] == NULL) 377 return (PKGADM); 378 else 379 return (Adm_pkgadm); 380 } 381 382 void 383 set_PKGADM(char *newpath) 384 { 385 (void) strcpy(Adm_pkgadm, newpath); 386 } 387 388 void 389 set_PKGLOC(char *newpath) 390 { 391 (void) strcpy(Adm_pkgloc, newpath); 392 } 393 394 #define isdot(x) ((x[0] == '.')&&(!x[1]||(x[1] == '/'))) 395 #define isdotdot(x) ((x[0] == '.')&&(x[1] == '.')&&(!x[2]||(x[2] == '/'))) 396 397 static void 398 canonize_name(char *file) 399 { 400 char *pt, *last; 401 int level; 402 403 /* Remove references such as "./" and "../" and "//" */ 404 405 for (pt = file; *pt; ) { 406 if (isdot(pt)) 407 (void) strcpy(pt, pt[1] ? pt+2 : pt+1); 408 else if (isdotdot(pt)) { 409 level = 0; 410 last = pt; 411 do { 412 level++; 413 last += 2; 414 if (*last) 415 last++; 416 } while (isdotdot(last)); 417 --pt; /* point to previous '/' */ 418 while (level--) { 419 if (pt <= file) 420 return; 421 while ((*--pt != '/') && (pt > file)) 422 ; 423 } 424 if (*pt == '/') 425 pt++; 426 (void) strcpy(pt, last); 427 } else { 428 while (*pt && (*pt != '/')) 429 pt++; 430 if (*pt == '/') { 431 while (pt[1] == '/') 432 (void) strcpy(pt, pt+1); 433 pt++; 434 } 435 } 436 } 437 if ((--pt > file) && (*pt == '/')) 438 *pt = '\0'; 439 } 440 441 void 442 set_install_root(char *path) 443 { 444 pkg_inst_root = strdup(path); 445 } 446 447 char * 448 get_install_root() 449 { 450 return (pkg_inst_root); 451 } 452