/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ /* All Rights Reserved */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /*LINTLIBRARY*/ /* 5-20-92 added newroot functions */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "libadm.h" static void initpkg(struct pkginfo *); static int rdconfig(struct pkginfo *, char *, char *); static int ckinfo(char *, char *, char *); static int ckinst(char *, char *, char *, char *, char *); static int verscmp(char *, char *); static int archcmp(char *, char *); static int compver(char *, char *); /* * Globals: * pkgdir - specifies the directory where information about packages * resides, i.e. the pkginfo file is located in a subdirectory * * Caveats: * The structure provided via "info" will contain malloc'd information; * this will be free'd upon the next call to pkginfo with this * same structure. Application calls must make sure this structure * is null on the first call, or else we'll free static memory areas * If the "pkg" argument is a wildcard specification, the next found * instance available which matches the request will be returned * If the "pkg" argument is a NULL pointer, the structure pointed to * via "info" will have its elements deallocated and all files * associated with this routine will be closed * * Return codes: * A non-zero exit code indicates error with "errno" appropriately set: * EINVAL - invalid argument * ESRCH - there are no more instances of this package around * EACCESS - unable to access files which should have been there */ /*VARARGS*/ int pkginfo(struct pkginfo *info, char *pkginst, ...) { char *ckarch, *ckvers; int check; va_list ap; va_start(ap, pkginst); if (info == NULL) { errno = EINVAL; return (-1); } if (pkginst == NULL) { info->pkginst = NULL; (void) fpkginfo(info, NULL); (void) fpkginst(NULL); return (0); } ckarch = va_arg(ap, char *); ckvers = va_arg(ap, char *); va_end(ap); check = 0; if (pkgnmchk(pkginst, "all", 1)) { /* wild card specification */ pkginst = fpkginst(pkginst, ckarch, ckvers); if (pkginst == NULL) return (-1); } else { /* request to check indicated instance */ if (ckarch || ckvers) check++; } info->pkginst = NULL; if (fpkginfo(info, pkginst)) return (-1); if (check) { /* * verify that the provided instance matches * any arch & vers specs that were provided */ if (ckinst(pkginst, info->arch, info->version, ckarch, ckvers)) { errno = ESRCH; return (-1); } } return (0); } /*ARGSUSED*/ int fpkginfo(struct pkginfo *info, char *pkginst) { if (info == NULL) { errno = EINVAL; return (-1); } initpkg(info); if (pkginst == NULL) return (0); else if (pkgnmchk(pkginst, "all", 1)) { errno = EINVAL; /* not an instance identifier */ return (-1); } if (pkgdir == NULL) pkgdir = get_PKGLOC(); if (rdconfig(info, pkginst, NULL)) { initpkg(info); return (-1); } return (0); } static void initpkg(struct pkginfo *info) { /* free previously allocated space */ if (info->pkginst) { free(info->pkginst); if (info->arch) free(info->arch); if (info->version) free(info->version); if (info->basedir) free(info->basedir); if (info->name) free(info->name); if (info->vendor) free(info->vendor); if (info->catg) free(info->catg); } info->pkginst = NULL; info->arch = info->version = NULL; info->basedir = info->name = NULL; info->vendor = info->catg = NULL; info->status = PI_UNKNOWN; } static int rdconfig(struct pkginfo *info, char *pkginst, char *ckvers) { FILE *fp; char temp[256]; char *value, *pt, *copy, **memloc; int count; if ((fp = pkginfopen(pkgdir, pkginst)) == NULL) { errno = EACCES; return (-1); } *temp = '\0'; count = 0; while (value = fpkgparam(fp, temp)) { if (strcmp(temp, "ARCH") == 0 || strcmp(temp, "CATEGORY") == 0) { /* remove all whitespace from value */ pt = copy = value; while (*pt) { if (!isspace((unsigned char)*pt)) *copy++ = *pt; pt++; } *copy = '\0'; } count++; memloc = NULL; if (strcmp(temp, "NAME") == 0) memloc = &info->name; else if (strcmp(temp, "VERSION") == 0) memloc = &info->version; else if (strcmp(temp, "ARCH") == 0) memloc = &info->arch; else if (strcmp(temp, "VENDOR") == 0) memloc = &info->vendor; else if (strcmp(temp, "BASEDIR") == 0) memloc = &info->basedir; else if (strcmp(temp, "CATEGORY") == 0) memloc = &info->catg; temp[0] = '\0'; if (memloc == NULL) continue; /* not a parameter we're looking for */ *memloc = strdup(value); if (!*memloc) { (void) fclose(fp); errno = ENOMEM; return (-1); /* malloc from strdup failed */ } } (void) fclose(fp); if (!count) { errno = ESRCH; return (-1); } info->status = (strcmp(pkgdir, get_PKGLOC()) ? PI_SPOOLED : PI_INSTALLED); if (info->status == PI_INSTALLED) { (void) snprintf(temp, sizeof (temp), "%s/%s/!I-Lock!", pkgdir, pkginst); if (access(temp, 0) == 0) info->status = PI_PARTIAL; else { (void) snprintf(temp, sizeof (temp), "%s/%s/!R-Lock!", pkgdir, pkginst); if (access(temp, 0) == 0) info->status = PI_PARTIAL; } } info->pkginst = strdup(pkginst); return (0); } static int ckinst(char *pkginst, char *pkgarch, char *pkgvers, char *ckarch, char *ckvers) { if (ckarch && archcmp(ckarch, pkgarch)) return (-1); if (ckvers) { /* Check for exact version match */ if (verscmp(ckvers, pkgvers)) { /* Check for compatable version */ if (compver(pkginst, ckvers)) return (-1); } } return (0); } /*VARARGS*/ char * fpkginst(char *pkg, ...) { static char pkginst[PKGSIZ+1]; static DIR *pdirfp; struct dirent64 *dp; char *ckarch, *ckvers; va_list ap; va_start(ap, pkg); if (pkg == NULL) { /* request to close or rewind the file */ if (pdirfp) { (void) closedir(pdirfp); pdirfp = NULL; } return (NULL); } ckarch = va_arg(ap, char *); ckvers = va_arg(ap, char *); va_end(ap); if (!pkgdir) pkgdir = get_PKGLOC(); if (!pdirfp && ((pdirfp = opendir(pkgdir)) == NULL)) { errno = EACCES; return (NULL); } while ((dp = readdir64(pdirfp)) != NULL) { if (dp->d_name[0] == '.') continue; if (pkgnmchk(dp->d_name, pkg, 0)) continue; /* ignore invalid SVR4 package names */ if (ckinfo(dp->d_name, ckarch, ckvers)) continue; /* * Leave directory open in case user requests another * instance. */ (void) strcpy(pkginst, dp->d_name); return (pkginst); } errno = ESRCH; /* close any file we might have open */ (void) closedir(pdirfp); pdirfp = NULL; return (NULL); } static int verscmp(char *request, char *actual) { /* eat leading white space */ while (isspace((unsigned char)*actual)) actual++; while (isspace((unsigned char)*request)) request++; while (*request || *actual) { /* * Once the pointers don't match, return an error condition. */ if (*request++ != *actual++) return (-1); /* eat white space if any in both the strings */ if (isspace((unsigned char)*request)) { if (*actual && !isspace((unsigned char)*actual)) return (-1); while (isspace((unsigned char)*request)) request++; while (isspace((unsigned char)*actual)) actual++; } } return (0); } static int compver(char *pkginst, char *version) { FILE *fp; char temp[256]; (void) snprintf(temp, sizeof (temp), "%s/%s/install/compver", get_PKGLOC(), pkginst); if ((fp = fopen(temp, "r")) == NULL) return (-1); while (fgets(temp, 256, fp)) { if (*temp == '#') continue; if (verscmp(temp, version) == 0) { (void) fclose(fp); return (0); } } (void) fclose(fp); return (-1); } static int archcmp(char *arch, char *archlist) { char *pt; if (arch == NULL) return (0); /* arch and archlist must not contain whitespace! */ while (*archlist) { for (pt = arch; *pt && (*pt == *archlist); ) pt++, archlist++; if (!*pt && (!*archlist || (*archlist == ','))) return (0); while (*archlist) { if (*archlist++ == ',') break; } } return (-1); } static int ckinfo(char *inst, char *arch, char *vers) { FILE *fp; char temp[128]; char file[PATH_MAX]; char *pt, *copy, *value, *myarch, *myvers; int errflg; (void) snprintf(file, sizeof (file), "%s/%s/pkginfo", pkgdir, inst); if ((fp = fopen(file, "r")) == NULL) return (1); if ((arch == NULL) && (vers == NULL)) { (void) fclose(fp); return (0); } temp[0] = '\0'; myarch = myvers = NULL; while (value = fpkgparam(fp, temp)) { if (strcmp(temp, "ARCH") == 0) { /* remove all whitespace from value */ pt = copy = value; while (*pt) { if (!isspace((unsigned char)*pt)) *copy++ = *pt; pt++; } *copy = '\0'; myarch = value; if (myvers) break; } else if (strcmp(temp, "VERSION") == 0) { myvers = value; if (myarch) break; } else free(value); temp[0] = '\0'; } (void) fclose(fp); errflg = 0; if (ckinst(inst, myarch, myvers, arch, vers)) errflg++; if (myarch) free(myarch); if (myvers) free(myvers); return (errflg); }