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 /* 27 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 /*LINTLIBRARY*/ 32 33 /* 5-20-92 added newroot functions */ 34 35 #include <stdio.h> 36 #include <limits.h> 37 #include <stdarg.h> 38 #include <unistd.h> 39 #include <stdlib.h> 40 #include <ctype.h> 41 #include <string.h> 42 #include <sys/types.h> 43 #include <sys/stat.h> 44 #include <dirent.h> 45 #include <pkginfo.h> 46 #include <pkgstrct.h> 47 #include <pkglocs.h> 48 #include <errno.h> 49 #include "libadm.h" 50 51 static void initpkg(struct pkginfo *); 52 static int rdconfig(struct pkginfo *, char *, char *); 53 static int ckinfo(char *, char *, char *); 54 static int ckinst(char *, char *, char *, char *, char *); 55 static int verscmp(char *, char *); 56 static int archcmp(char *, char *); 57 static int compver(char *, char *); 58 59 /* 60 * Globals: 61 * pkgdir - specifies the directory where information about packages 62 * resides, i.e. the pkginfo file is located in a subdirectory 63 * 64 * Caveats: 65 * The structure provided via "info" will contain malloc'd information; 66 * this will be free'd upon the next call to pkginfo with this 67 * same structure. Application calls must make sure this structure 68 * is null on the first call, or else we'll free static memory areas 69 * If the "pkg" argument is a wildcard specification, the next found 70 * instance available which matches the request will be returned 71 * If the "pkg" argument is a NULL pointer, the structure pointed to 72 * via "info" will have its elements deallocated and all files 73 * associated with this routine will be closed 74 * 75 * Return codes: 76 * A non-zero exit code indicates error with "errno" appropriately set: 77 * EINVAL - invalid argument 78 * ESRCH - there are no more instances of this package around 79 * EACCESS - unable to access files which should have been there 80 */ 81 82 /*VARARGS*/ 83 int 84 pkginfo(struct pkginfo *info, char *pkginst, ...) 85 { 86 char *ckarch, *ckvers; 87 int check; 88 va_list ap; 89 90 va_start(ap, pkginst); 91 if (info == NULL) { 92 errno = EINVAL; 93 return (-1); 94 } 95 if (pkginst == NULL) { 96 info->pkginst = NULL; 97 (void) fpkginfo(info, NULL); 98 (void) fpkginst(NULL); 99 return (0); 100 } 101 ckarch = va_arg(ap, char *); 102 ckvers = va_arg(ap, char *); 103 va_end(ap); 104 105 check = 0; 106 if (pkgnmchk(pkginst, "all", 1)) { 107 /* wild card specification */ 108 pkginst = fpkginst(pkginst, ckarch, ckvers); 109 if (pkginst == NULL) 110 return (-1); 111 } else { 112 /* request to check indicated instance */ 113 if (ckarch || ckvers) 114 check++; 115 } 116 117 info->pkginst = NULL; 118 if (fpkginfo(info, pkginst)) 119 return (-1); 120 121 if (check) { 122 /* 123 * verify that the provided instance matches 124 * any arch & vers specs that were provided 125 */ 126 if (ckinst(pkginst, info->arch, info->version, ckarch, 127 ckvers)) { 128 errno = ESRCH; 129 return (-1); 130 } 131 } 132 return (0); 133 } 134 /*ARGSUSED*/ 135 136 int 137 fpkginfo(struct pkginfo *info, char *pkginst) 138 { 139 140 if (info == NULL) { 141 errno = EINVAL; 142 return (-1); 143 } 144 145 initpkg(info); 146 147 if (pkginst == NULL) 148 return (0); 149 else if (pkgnmchk(pkginst, "all", 1)) { 150 errno = EINVAL; /* not an instance identifier */ 151 return (-1); 152 } 153 if (pkgdir == NULL) 154 pkgdir = get_PKGLOC(); 155 156 if (rdconfig(info, pkginst, NULL)) { 157 initpkg(info); 158 return (-1); 159 } 160 return (0); 161 } 162 163 static void 164 initpkg(struct pkginfo *info) 165 { 166 /* free previously allocated space */ 167 if (info->pkginst) { 168 free(info->pkginst); 169 if (info->arch) 170 free(info->arch); 171 if (info->version) 172 free(info->version); 173 if (info->basedir) 174 free(info->basedir); 175 if (info->name) 176 free(info->name); 177 if (info->vendor) 178 free(info->vendor); 179 if (info->catg) 180 free(info->catg); 181 } 182 183 info->pkginst = NULL; 184 info->arch = info->version = NULL; 185 info->basedir = info->name = NULL; 186 info->vendor = info->catg = NULL; 187 info->status = PI_UNKNOWN; 188 } 189 190 static int 191 rdconfig(struct pkginfo *info, char *pkginst, char *ckvers) 192 { 193 FILE *fp; 194 char temp[256]; 195 char *value, *pt, *copy, **memloc; 196 int count; 197 198 if ((fp = pkginfopen(pkgdir, pkginst)) == NULL) { 199 errno = EACCES; 200 return (-1); 201 } 202 203 *temp = '\0'; 204 count = 0; 205 while (value = fpkgparam(fp, temp)) { 206 if (strcmp(temp, "ARCH") == 0 || 207 strcmp(temp, "CATEGORY") == 0) { 208 /* remove all whitespace from value */ 209 pt = copy = value; 210 while (*pt) { 211 if (!isspace((unsigned char)*pt)) 212 *copy++ = *pt; 213 pt++; 214 } 215 *copy = '\0'; 216 } 217 count++; 218 memloc = NULL; 219 if (strcmp(temp, "NAME") == 0) 220 memloc = &info->name; 221 else if (strcmp(temp, "VERSION") == 0) 222 memloc = &info->version; 223 else if (strcmp(temp, "ARCH") == 0) 224 memloc = &info->arch; 225 else if (strcmp(temp, "VENDOR") == 0) 226 memloc = &info->vendor; 227 else if (strcmp(temp, "BASEDIR") == 0) 228 memloc = &info->basedir; 229 else if (strcmp(temp, "CATEGORY") == 0) 230 memloc = &info->catg; 231 232 temp[0] = '\0'; 233 if (memloc == NULL) 234 continue; /* not a parameter we're looking for */ 235 236 *memloc = strdup(value); 237 if (!*memloc) { 238 (void) fclose(fp); 239 errno = ENOMEM; 240 return (-1); /* malloc from strdup failed */ 241 } 242 } 243 (void) fclose(fp); 244 245 if (!count) { 246 errno = ESRCH; 247 return (-1); 248 } 249 250 info->status = (strcmp(pkgdir, get_PKGLOC()) ? PI_SPOOLED : 251 PI_INSTALLED); 252 253 if (info->status == PI_INSTALLED) { 254 (void) snprintf(temp, sizeof (temp), 255 "%s/%s/!I-Lock!", pkgdir, pkginst); 256 if (access(temp, 0) == 0) 257 info->status = PI_PARTIAL; 258 else { 259 (void) snprintf(temp, sizeof (temp), 260 "%s/%s/!R-Lock!", pkgdir, pkginst); 261 if (access(temp, 0) == 0) 262 info->status = PI_PARTIAL; 263 } 264 } 265 info->pkginst = strdup(pkginst); 266 return (0); 267 } 268 269 static int 270 ckinst(char *pkginst, char *pkgarch, char *pkgvers, char *ckarch, char *ckvers) 271 { 272 if (ckarch && archcmp(ckarch, pkgarch)) 273 return (-1); 274 if (ckvers) { 275 /* Check for exact version match */ 276 if (verscmp(ckvers, pkgvers)) { 277 /* Check for compatable version */ 278 if (compver(pkginst, ckvers)) 279 return (-1); 280 } 281 } 282 return (0); 283 } 284 285 /*VARARGS*/ 286 char * 287 fpkginst(char *pkg, ...) 288 { 289 static char pkginst[PKGSIZ+1]; 290 static DIR *pdirfp; 291 struct dirent64 *dp; 292 char *ckarch, *ckvers; 293 va_list ap; 294 295 va_start(ap, pkg); 296 297 if (pkg == NULL) { 298 /* request to close or rewind the file */ 299 if (pdirfp) { 300 (void) closedir(pdirfp); 301 pdirfp = NULL; 302 } 303 return (NULL); 304 } 305 306 ckarch = va_arg(ap, char *); 307 ckvers = va_arg(ap, char *); 308 va_end(ap); 309 310 if (!pkgdir) 311 pkgdir = get_PKGLOC(); 312 313 if (!pdirfp && ((pdirfp = opendir(pkgdir)) == NULL)) { 314 errno = EACCES; 315 return (NULL); 316 } 317 318 while ((dp = readdir64(pdirfp)) != NULL) { 319 if (dp->d_name[0] == '.') 320 continue; 321 322 if (pkgnmchk(dp->d_name, pkg, 0)) 323 continue; /* ignore invalid SVR4 package names */ 324 325 if (ckinfo(dp->d_name, ckarch, ckvers)) 326 continue; 327 328 /* 329 * Leave directory open in case user requests another 330 * instance. 331 */ 332 (void) strcpy(pkginst, dp->d_name); 333 return (pkginst); 334 } 335 336 errno = ESRCH; 337 /* close any file we might have open */ 338 (void) closedir(pdirfp); 339 pdirfp = NULL; 340 return (NULL); 341 } 342 343 static int 344 verscmp(char *request, char *actual) 345 { 346 /* eat leading white space */ 347 while (isspace((unsigned char)*actual)) 348 actual++; 349 while (isspace((unsigned char)*request)) 350 request++; 351 352 while (*request || *actual) { 353 /* 354 * Once the pointers don't match, return an error condition. 355 */ 356 357 if (*request++ != *actual++) 358 return (-1); 359 360 /* eat white space if any in both the strings */ 361 if (isspace((unsigned char)*request)) { 362 if (*actual && !isspace((unsigned char)*actual)) 363 return (-1); 364 while (isspace((unsigned char)*request)) 365 request++; 366 while (isspace((unsigned char)*actual)) 367 actual++; 368 } 369 } 370 371 return (0); 372 373 } 374 375 static int 376 compver(char *pkginst, char *version) 377 { 378 FILE *fp; 379 char temp[256]; 380 381 (void) snprintf(temp, sizeof (temp), 382 "%s/%s/install/compver", get_PKGLOC(), pkginst); 383 if ((fp = fopen(temp, "r")) == NULL) 384 return (-1); 385 386 while (fgets(temp, 256, fp)) { 387 if (*temp == '#') 388 continue; 389 if (verscmp(temp, version) == 0) { 390 (void) fclose(fp); 391 return (0); 392 } 393 } 394 (void) fclose(fp); 395 return (-1); 396 } 397 398 static int 399 archcmp(char *arch, char *archlist) 400 { 401 char *pt; 402 403 if (arch == NULL) 404 return (0); 405 406 /* arch and archlist must not contain whitespace! */ 407 408 while (*archlist) { 409 for (pt = arch; *pt && (*pt == *archlist); ) 410 pt++, archlist++; 411 if (!*pt && (!*archlist || (*archlist == ','))) 412 return (0); 413 while (*archlist) { 414 if (*archlist++ == ',') 415 break; 416 } 417 } 418 return (-1); 419 } 420 421 static int 422 ckinfo(char *inst, char *arch, char *vers) 423 { 424 FILE *fp; 425 char temp[128]; 426 char file[PATH_MAX]; 427 char *pt, *copy, *value, *myarch, *myvers; 428 int errflg; 429 430 (void) snprintf(file, sizeof (file), "%s/%s/pkginfo", pkgdir, inst); 431 if ((fp = fopen(file, "r")) == NULL) 432 return (1); 433 434 if ((arch == NULL) && (vers == NULL)) { 435 (void) fclose(fp); 436 return (0); 437 } 438 temp[0] = '\0'; 439 myarch = myvers = NULL; 440 while (value = fpkgparam(fp, temp)) { 441 if (strcmp(temp, "ARCH") == 0) { 442 /* remove all whitespace from value */ 443 pt = copy = value; 444 while (*pt) { 445 if (!isspace((unsigned char)*pt)) 446 *copy++ = *pt; 447 pt++; 448 } 449 *copy = '\0'; 450 myarch = value; 451 if (myvers) 452 break; 453 } else if (strcmp(temp, "VERSION") == 0) { 454 myvers = value; 455 if (myarch) 456 break; 457 } else 458 free(value); 459 temp[0] = '\0'; 460 } 461 (void) fclose(fp); 462 errflg = 0; 463 464 if (ckinst(inst, myarch, myvers, arch, vers)) 465 errflg++; 466 467 if (myarch) 468 free(myarch); 469 if (myvers) 470 free(myvers); 471 472 return (errflg); 473 } 474