/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (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 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* commands to execute */ #define PKGINFO_CMD "/usr/bin/pkginfo" #define GLOBALZONE_ONLY_PACKAGE_FILE_PATH \ "/var/sadm/install/gz-only-packages" #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ #define TEXT_DOMAIN "SYS_TEST" #endif /* * forward declarations */ static void _pkginfoInit(struct pkginfo *a_info); static struct pkginfo *_pkginfoFactory(void); static char **thisZonePackages; static int numThisZonePackages; /* * ***************************************************************************** * global external (public) functions * ***************************************************************************** */ /* * Name: pkginfoFree * Description: free pkginfo structure returned from various functions * Arguments: r_info - pointer to pointer to pkginfo structure to free * Returns: void */ void pkginfoFree(struct pkginfo **r_info) { struct pkginfo *pinfo; /* entry assertions */ assert(r_info != (struct pkginfo **)NULL); /* localize reference to info structure to free */ pinfo = *r_info; /* reset callers handle to info structure */ *r_info = (struct pkginfo *)NULL; assert(pinfo != (struct pkginfo *)NULL); /* free up contents of the structure */ _pkginfoInit(pinfo); /* free up structure itself */ (void) free(pinfo); } /* * Name: pkginfoIsPkgInstalled * Description: determine if specified package is installed, return pkginfo * structure describing package if package is installed * Arguments: r_pinfo - pointer to pointer to pkginfo structure * If this pointer is NOT null: * -On success, this handle is filled in with a pointer * --to a newly allocated pkginfo structure describing * --the package discovered * -On failure, this handle is filled with NULL * If this pointer is NULL: * -no pkginfo structure is returned on success. * a_pkgInst - package instance (name) to lookup * Returns: boolean_t * B_TRUE - package installed, pkginfo returned * B_FALSE - package not installed, no pkginfo returned * NOTE: This function returns the first instance of package that * is installed - see pkginfo() function for details * NOTE: Any pkginfo structure returned is placed in new storage for the * calling function. The caller must use 'pkginfoFree' to dispose * of the storage once the pkginfo structure is no longer needed. */ boolean_t pkginfoIsPkgInstalled(struct pkginfo **r_pinfo, char *a_pkgInst) { int r; struct pkginfo *pinf; /* entry assertions */ assert(a_pkgInst != (char *)NULL); assert(*a_pkgInst != '\0'); /* reset returned pkginfo structure handle */ if (r_pinfo != (struct pkginfo **)NULL) { *r_pinfo = (struct pkginfo *)NULL; } /* allocate a new pinfo structure for use in the call to pkginfo */ pinf = _pkginfoFactory(); /* lookup the specified package */ /* NOTE: required 'pkgdir' set to spool directory or NULL */ r = pkginfo(pinf, a_pkgInst, NULL, NULL); echoDebug(DBG_PKGOPS_PKGINFO_RETURNED, a_pkgInst, r); if (r_pinfo != (struct pkginfo **)NULL) { *r_pinfo = pinf; } else { /* free pkginfo structure */ pkginfoFree(&pinf); } return (r == 0 ? B_TRUE : B_FALSE); } /* * Name: pkgOpenInGzOnlyFile * Description: Open the global zone only package list file * Arguments: a_rootPath - pointer to string representing the root path * where the global zone only package list file is * located - NULL is the same as "/" * Returns: FILE * * == NULL - failure - file not open * != NULL - success - file pointer returned * NOTE: This function will create the file if it does not exist. */ FILE * pkgOpenInGzOnlyFile(char *a_rootPath) { FILE *pkgingzonlyFP; char pkgingzonlyPath[PATH_MAX]; int len; /* normalize root path */ if (a_rootPath == (char *)NULL) { a_rootPath = ""; } /* generate path to glocal zone only list file */ len = snprintf(pkgingzonlyPath, sizeof (pkgingzonlyPath), "%s/%s", a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); if (len > sizeof (pkgingzonlyPath)) { progerr(ERR_CREATE_PATH_2, a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); return ((FILE *)NULL); } /* open global zone only list file */ pkgingzonlyFP = fopen(pkgingzonlyPath, "r+"); if ((pkgingzonlyFP == (FILE *)NULL) && (errno == ENOENT)) { pkgingzonlyFP = fopen(pkgingzonlyPath, "w+"); } if ((pkgingzonlyFP == (FILE *)NULL) && (errno != ENOENT)) { progerr(ERR_PKGOPS_OPEN_GZONLY, pkgingzonlyPath, strerror(errno)); return ((FILE *)NULL); } /* success - return FILE pointer open on global zone only list file */ return (pkgingzonlyFP); } /* * Name: pkgIsPkgInGzOnly * Description: determine if package is recorded as "in global zone only" * by opening the appropriate files and searching for the * specified package * Arguments: a_rootPath - pointer to string representing the root path * where the global zone only package list file is * located - NULL is the same as "/" * a_pkgInst - pointer to string representing the package instance * (name) of the package to lookup * Returns: boolean_t * B_TRUE - package is recorded as "in global zone only" * B_FALSE - package is NOT recorded as "in gz only" * NOTE: This function will create the file if it does not exist. */ boolean_t pkgIsPkgInGzOnly(char *a_rootPath, char *a_pkgInst) { FILE *fp; boolean_t in_gz_only; /* normalize root path */ if (a_rootPath == (char *)NULL) { a_rootPath = ""; } /* open the global zone only package list file */ fp = pkgOpenInGzOnlyFile(a_rootPath); if (fp == (FILE *)NULL) { echoDebug(ERR_PKGOPS_CANNOT_OPEN_GZONLY, a_rootPath ? a_rootPath : "/"); return (B_FALSE); } /* is the package recorded as "in global zone only" ? */ in_gz_only = pkgIsPkgInGzOnlyFP(fp, a_pkgInst); /* close the global zone only package list file */ (void) fclose(fp); /* return results */ return (in_gz_only); } /* * Name: pkgIsPkgInGzOnly * Description: determine if package is recorded as "in global zone only" * by searching the specified open FILE for the specified package * Arguments: a_fp - pointer to FILE handle open on file to search * a_pkgInst - pointer to string representing the package instance * (name) of the package to lookup * Returns: boolean_t * B_TRUE - package is recorded as "in global zone only" * B_FALSE - package is NOT recorded as "in gz only" */ boolean_t pkgIsPkgInGzOnlyFP(FILE *a_fp, char *a_pkgInst) { char line[PATH_MAX+1]; /* entry assertions */ assert(a_fp != (FILE *)NULL); assert(a_pkgInst != (char *)NULL); assert(*a_pkgInst != '\0'); /* rewind the file to the beginning */ rewind(a_fp); /* read the file line by line searching for the specified package */ while (fgets(line, sizeof (line), a_fp) != (char *)NULL) { int len; /* strip off trailing newlines */ len = strlen(line); while ((len > 0) && (line[len-1] == '\n')) { line[--len] = '\0'; } /* ignore blank and comment lines */ if ((line[0] == '#') || (line[0] == '\0')) { continue; } /* return true if this is the package we are looking for */ if (strcmp(a_pkgInst, line) == 0) { echoDebug(DBG_PKGOPS_PKG_IS_GZONLY, a_pkgInst); return (B_TRUE); } } /* end of file - package not found */ echoDebug(DBG_PKGOPS_PKG_NOT_GZONLY, a_pkgInst); return (B_FALSE); } /* * Name: pkgRemovePackageFromGzonlyList * Description: Remove specified package from the global zone only package list * file located at a specified root path * Arguments: a_rootPath - pointer to string representing the root path * where the global zone only package list file is * located - NULL is the same as "/" * a_pkgInst - pointer to string representing the package instance * (name) of the package to remove * Returns: boolean_t * B_TRUE - package is successfully removed * B_FALSE - failed to remove package from file * NOTE: This function will create the file if it does not exist. */ boolean_t pkgRemovePackageFromGzonlyList(char *a_rootPath, char *a_pkgInst) { FILE *destFP; FILE *srcFP; boolean_t pkgremoved = B_FALSE; char destPath[PATH_MAX]; char line[PATH_MAX+1]; char savePath[PATH_MAX]; char srcPath[PATH_MAX]; char timeb[BUFSIZ]; int len; struct tm *timep; time_t clock; /* entry assertions */ assert(a_pkgInst != (char *)NULL); assert(*a_pkgInst != '\0'); /* normalize root path */ if (a_rootPath == (char *)NULL) { a_rootPath = ""; } /* * calculate paths to various objects */ /* path to current "source" ingzonly file */ len = snprintf(srcPath, sizeof (srcPath), "%s/%s", a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); if (len > sizeof (srcPath)) { progerr(ERR_CREATE_PATH_2, a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); return (B_FALSE); } /* path to new "destination" ingzonly file */ len = snprintf(destPath, sizeof (destPath), "%s/%s.tmp", a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); if (len > sizeof (srcPath)) { progerr(ERR_CREATE_PATH_2, a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); return (B_FALSE); } /* path to temporary "saved" ingzonly file */ len = snprintf(savePath, sizeof (savePath), "%s/%s.save", a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); if (len > sizeof (srcPath)) { progerr(ERR_CREATE_PATH_2, a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); return (B_FALSE); } /* open source file, creating if necessary */ srcFP = fopen(srcPath, "r+"); if ((srcFP == (FILE *)NULL) && (errno == ENOENT)) { srcFP = fopen(srcPath, "w+"); } /* error if could not open/create file */ if (srcFP == (FILE *)NULL) { progerr(ERR_PKGOPS_OPEN_GZONLY, srcPath, strerror(errno)); return (B_FALSE); } /* open/create new destination file */ (void) remove(destPath); destFP = fopen(destPath, "w"); if (destFP == (FILE *)NULL) { progerr(ERR_PKGOPS_TMPOPEN, destPath, strerror(errno)); if (srcFP != (FILE *)NULL) { (void) fclose(srcFP); } return (B_FALSE); } /* add standard comment to beginning of file */ (void) time(&clock); timep = localtime(&clock); (void) strftime(timeb, sizeof (timeb), "%c\n", timep); /* put standard header at the beginning of the file */ (void) fprintf(destFP, MSG_GZONLY_FILE_HEADER, get_prog_name(), "remove", a_pkgInst, timeb); /* read source/write destination - removing specified package */ while (fgets(line, sizeof (line), srcFP) != (char *)NULL) { int len; /* strip off trailing newlines */ len = strlen(line); while ((len > 0) && (line[len-1] == '\n')) { line[--len] = '\0'; } /* ignore blank and comment lines */ if ((line[0] == '#') || (line[0] == '\0')) { continue; } /* add pkg if yet to add and pkg <= line */ if ((pkgremoved == B_FALSE) && (strcmp(a_pkgInst, line) == 0)) { pkgremoved = B_TRUE; } else { (void) fprintf(destFP, "%s\n", line); } } /* close both files */ (void) fclose(srcFP); (void) fclose(destFP); /* * if package not found there is no need to update the original file */ if (pkgremoved == B_FALSE) { (void) unlink(destPath); return (B_TRUE); } /* * Now we want to make a copy of the old gzonly file as a * fail-safe. */ if ((access(savePath, F_OK) == 0) && remove(savePath)) { progerr(ERR_REMOVE, savePath, strerror(errno)); (void) remove(destPath); return (B_FALSE); } if (link(srcPath, savePath) != 0) { progerr(ERR_LINK, savePath, srcPath, strerror(errno)); (void) remove(destPath); return (B_FALSE); } if (rename(destPath, srcPath) != 0) { progerr(ERR_RENAME, destPath, srcPath, strerror(errno)); if (rename(savePath, srcPath)) { progerr(ERR_RENAME, savePath, srcPath, strerror(errno)); } (void) remove(destPath); return (B_FALSE); } if (remove(savePath) != 0) { progerr(ERR_REMOVE, savePath, strerror(errno)); } /* successfully removed package */ echoDebug(DBG_PKGOPS_REMOVED_GZPKG, a_pkgInst); return (B_TRUE); } /* * Name: pkgAddPackageFromGzonlyList * Description: Add specified package to the global zone only package list * file located at a specified root path * Arguments: a_rootPath - pointer to string representing the root path * where the global zone only package list file is * located - NULL is the same as "/" * a_pkgInst - pointer to string representing the package instance * (name) of the package to add * Returns: boolean_t * B_TRUE - package is successfully added * B_FALSE - failed to add package to the file * NOTE: This function will create the file if it does not exist. */ boolean_t pkgAddPackageToGzonlyList(char *a_pkgInst, char *a_rootPath) { FILE *destFP; FILE *srcFP; boolean_t pkgadded = B_FALSE; char destPath[PATH_MAX]; char line[PATH_MAX+1]; char savePath[PATH_MAX]; char srcPath[PATH_MAX]; char timeb[BUFSIZ]; int len; struct tm *timep; time_t clock; /* entry assertions */ assert(a_pkgInst != (char *)NULL); assert(*a_pkgInst != '\0'); /* normalize root path */ if (a_rootPath == (char *)NULL) { a_rootPath = ""; } /* entry debugging info */ echoDebug(DBG_PKGOPS_ADDGZPKG, a_pkgInst, a_rootPath); /* * calculate paths to various objects */ /* path to current "source" ingzonly file */ len = snprintf(srcPath, sizeof (srcPath), "%s/%s", a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); if (len > sizeof (srcPath)) { progerr(ERR_CREATE_PATH_2, a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); return (B_FALSE); } /* path to new "destination" ingzonly file */ len = snprintf(destPath, sizeof (destPath), "%s/%s.tmp", a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); if (len > sizeof (srcPath)) { progerr(ERR_CREATE_PATH_2, a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); return (B_FALSE); } /* path to temporary "saved" ingzonly file */ len = snprintf(savePath, sizeof (savePath), "%s/%s.save", a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); if (len > sizeof (srcPath)) { progerr(ERR_CREATE_PATH_2, a_rootPath, GLOBALZONE_ONLY_PACKAGE_FILE_PATH); return (B_FALSE); } /* open source file, creating if necessary */ srcFP = fopen(srcPath, "r+"); if ((srcFP == (FILE *)NULL) && (errno == ENOENT)) { srcFP = fopen(srcPath, "w+"); } /* error if could not open/create file */ if (srcFP == (FILE *)NULL) { progerr(ERR_PKGOPS_OPEN_GZONLY, srcPath, strerror(errno)); return (B_FALSE); } /* open/create new destination file */ (void) remove(destPath); destFP = fopen(destPath, "w"); if (destFP == (FILE *)NULL) { progerr(ERR_PKGOPS_TMPOPEN, destPath, strerror(errno)); if (srcFP != (FILE *)NULL) { (void) fclose(srcFP); } return (B_FALSE); } /* add standard comment to beginning of file */ (void) time(&clock); timep = localtime(&clock); (void) strftime(timeb, sizeof (timeb), "%c\n", timep); /* put standard header at the beginning of the file */ (void) fprintf(destFP, MSG_GZONLY_FILE_HEADER, get_prog_name(), "add", a_pkgInst, timeb); /* read source/write destination; add package at appropriate location */ while (fgets(line, sizeof (line), srcFP) != (char *)NULL) { int len; /* strip off trailing newlines */ len = strlen(line); while ((len > 0) && (line[len-1] == '\n')) { line[--len] = '\0'; } /* ignore blank and comment lines */ if ((line[0] == '#') || (line[0] == '\0')) { continue; } /* add pkg if yet to add and pkg <= line */ if ((pkgadded == B_FALSE) && (strcmp(a_pkgInst, line) <= 0)) { if (strcmp(a_pkgInst, line) != 0) { (void) fprintf(destFP, "%s\n", a_pkgInst); } pkgadded = B_TRUE; } (void) fprintf(destFP, "%s\n", line); } /* if package not added yet, add to end of the file */ if (pkgadded == B_FALSE) { (void) fprintf(destFP, "%s\n", a_pkgInst); } /* close both files */ (void) fclose(srcFP); (void) fclose(destFP); /* * Now we want to make a copy of the old gzonly file as a * fail-safe. */ if ((access(savePath, F_OK) == 0) && remove(savePath)) { progerr(ERR_REMOVE, savePath, strerror(errno)); (void) remove(destPath); return (B_FALSE); } if (link(srcPath, savePath) != 0) { progerr(ERR_LINK, savePath, srcPath, strerror(errno)); (void) remove(destPath); return (B_FALSE); } if (rename(destPath, srcPath) != 0) { progerr(ERR_RENAME, destPath, srcPath, strerror(errno)); if (rename(savePath, srcPath)) { progerr(ERR_RENAME, savePath, srcPath, strerror(errno)); } (void) remove(destPath); return (B_FALSE); } if (remove(savePath) != 0) { progerr(ERR_REMOVE, savePath, strerror(errno)); } /* successfully added package */ echoDebug(DBG_PKGOPS_ADDED_GZPKG, a_pkgInst); return (B_TRUE); } /* * Name: pkginfoParamTruth * Description: Search pkginfo file for specified parameter/value pair * Arguments: a_fp - Pointer to FILE handle open on pkginfo file to search * a_param - Pointer to string representing the parameter name * to search for * a_value - Pointer to string representing the "success" value * being searched for * a_default - determine results if parameter NOT found * B_TRUE - parameter is TRUE if not found * B_FALSE - parameter is FALSE if not found * Returns: boolean_t * B_TRUE - the parameter was found and matched the specified value * OR the paramter was not found and a_default == B_TRUE * B_FALSE - the parameter was found and did NOT match the value * OR the paramter was not found and a_default == B_FALSE */ boolean_t pkginfoParamTruth(FILE *a_fp, char *a_param, char *a_value, boolean_t a_default) { char *param; boolean_t result; /* entry assertions */ assert(a_fp != (FILE *)NULL); assert(a_param != (char *)NULL); assert(*a_param != '\0'); assert(a_value != (char *)NULL); assert(*a_value != '\0'); /* rewind the file to the beginning */ rewind(a_fp); /* search pkginfo file for the specified parameter */ param = fpkgparam(a_fp, a_param); if (param == (char *)NULL) { /* parameter not found - return default */ result = a_default; } else if (*param == '\0') { /* parameter found but no value - return default */ result = a_default; } else if (strcasecmp(param, a_value) == 0) { /* paramter found - matches value */ result = B_TRUE; } else { /* parameter found - does not match value */ result = B_FALSE; } /* exit debugging info */ echoDebug(DBG_PKGOPS_PARAMTRUTH_RESULTS, a_param, a_value, a_default == B_TRUE ? "true" : "false", param ? param : "?", result == B_TRUE ? "true" : "false"); /* if parameter value found, free results */ if (param != (char *)NULL) { (void) free(param); } /* return results of search */ return (result); } /* * Name: pkgGetPackageList * Description: Determine list of packages based on list of packages that are * available, category of packages to select, and list of packages * to select. * Arguments: r_pkgList - pointer to pointer to string array where the list * of selected packages will be returned * a_argv - pointer to string array containing list of packages * to select * a_optind - index into string array of first package to select * a_categories - pointer to string representing the categories of * packages to select * a_categoryList - pointer to string array representing a list * of categories to select * a_pkgdev - package dev containing packages that can be selected * Returns: int * == 0 - packages found r_pkgList contains results package list retrieved * == -1 - no packages found (errno == ENOPKG) * != 0 - "quit" value entered by user * NOTE: If both a category and a list of packages to select are provided * the category is used over the list of packages provided * NOTE: If neither a category nor a list of packages to select are * provided, an error is returned */ int pkgGetPackageList(char ***r_pkgList, char **a_argv, int a_optind, char *a_categories, char **a_categoryList, struct pkgdev *a_pkgdev) { char *all_pkgs[4] = {"all", NULL}; /* entry assertions */ assert(a_pkgdev != (struct pkgdev *)NULL); assert(a_pkgdev->dirname != (char *)NULL); assert(*a_pkgdev->dirname != '\0'); assert(r_pkgList != (char ***)NULL); assert(a_argv != (char **)NULL); /* entry debugging info */ echoDebug(DBG_PKGOPS_GETPKGLIST_ENTRY); echoDebug(DBG_PKGOPS_GETPKGLIST_ARGS, a_pkgdev->dirname, a_categories ? a_categories : "?"); /* reset returned package list handle */ *r_pkgList = (char **)NULL; /* * generate list of packages to be removed: if removing by category, * then generate package list based on all packages by category, * else generate package list based on all packages specified. */ if (a_categories != NULL) { /* generate package list from all packages in given category */ *r_pkgList = gpkglist(a_pkgdev->dirname, &all_pkgs[0], a_categoryList); if (*r_pkgList == NULL) { echoDebug(DBG_PKGOPS_GPKGLIST_CATFAILED, a_categories); progerr(ERR_CAT_FND, a_categories); return (1); } echoDebug(DBG_PKGOPS_GPKGLIST_CATOK, a_categories); return (0); } /* generate package list from specified packages */ *r_pkgList = gpkglist(a_pkgdev->dirname, &a_argv[a_optind], NULL); /* if list generated return results */ if (*r_pkgList != NULL) { echoDebug(DBG_PKGOPS_GPKGLIST_OK); return (0); } /* handle error from gpkglist */ switch (errno) { case ENOPKG: /* no packages */ echoDebug(DBG_PKGOPS_GPKGLIST_ENOPKG); return (-1); case ESRCH: echoDebug(DBG_PKGOPS_GPKGLIST_ESRCH); return (1); case EINTR: echoDebug(DBG_PKGOPS_GPKGLIST_EINTR); return (3); default: echoDebug(DBG_PKGOPS_GPKGLIST_UNKNOWN, errno); progerr(ERR_GPKGLIST_ERROR); return (99); } } /* * Name: pkgMatchInherited * Description: given a pointer to a "source" and a "destination" for an object, * along with other attributes of the object, determine if the * object is already installed and is current. * Arguments: a_src - pointer to string representing the "source" file to * verify - this would be the current temporary location of * the file that would be installed * a_dst - pointer to string representing the "destination" file to * verify - this would be the ultimate destination for the * file if installed * a_rootDir - pointer to string representing the "root directory" * where the package is being installed * a_mode - final "mode" file should have when installed * a_modtime - final "modtime" file should have when installed * a_ftype - contents "type" of file (f/e/v/s/l) * a_cksum - final "checksum" file should have when installed * Returns: boolean_t * B_TRUE - the specified source file MATCHES the file * located at the specified destination * B_FALSE - the specified source files does NOT match * the file located at the specified destination */ boolean_t pkgMatchInherited(char *a_src, char *a_dst, char *a_rootDir, char a_mode, time_t a_modtime, char a_ftype, unsigned long a_cksum) { char cwd[PATH_MAX+1] = {'\0'}; char dstpath[PATH_MAX+1]; int cksumerr; int n; struct stat statbufDst; struct stat statbufSrc; unsigned long dstcksum; unsigned long srcksum; /* entry assertions */ assert(a_src != (char *)NULL); assert(*a_src != '\0'); assert(a_dst != (char *)NULL); assert(*a_dst != '\0'); /* normalize root directory */ if ((a_rootDir == (char *)NULL) || (*a_rootDir == '\0')) { a_rootDir = "/"; } /* entry debugging */ echoDebug(DBG_PKGOPS_MATCHINHERIT_ENTRY); echoDebug(DBG_PKGOPS_MATCHINHERIT_ARGS, a_src, a_dst, a_rootDir, a_mode, a_modtime, a_ftype, a_cksum); /* save current working directory - resolvepath can change it */ (void) getcwd(cwd, sizeof (cwd)); n = resolvepath(a_dst, dstpath, sizeof (dstpath)); if (n <= 0) { if (errno != ENOENT) { progerr(ERR_RESOLVEPATH, a_dst, strerror(errno)); } (void) chdir(cwd); return (B_FALSE); } dstpath[n++] = '\0'; /* make sure string is terminated */ /* return false if path is not in inherited file system space */ if (!z_path_is_inherited(dstpath, a_ftype, a_rootDir)) { return (B_FALSE); } /* * path is in inherited file system space: verify existence */ /* return false if source file cannot be stat()ed */ if (stat(a_src, &statbufSrc) != 0) { progerr(ERR_STAT, a_src, strerror(errno)); return (B_FALSE); } /* return false if destination file cannot be stat()ed */ if (stat(dstpath, &statbufDst) != 0) { progerr(ERR_STAT, dstpath, strerror(errno)); return (B_FALSE); } /* * if this is an editable or volatile file, then the only * thing to guarantee is that the file exists - the file * attributes do not need to match */ /* editable file only needs to exist */ if (a_ftype == 'e') { echoDebug(DBG_PKGOPS_EDITABLE_EXISTS, dstpath); return (B_TRUE); } /* volatile file only needs to exist */ if (a_ftype == 'v') { echoDebug(DBG_PKGOPS_VOLATILE_EXISTS, dstpath); return (B_TRUE); } /* * verify modtime if file is not modifiable after install */ /* return false if source and destination have different mod times */ if (statbufSrc.st_mtim.tv_sec != statbufDst.st_mtim.tv_sec) { echoDebug(DBG_PKGOPS_MOD_MISMATCH, a_src, statbufSrc.st_mtim.tv_sec, dstpath, statbufDst.st_mtim.tv_sec); return (B_FALSE); } /* return false if destination does not have required mod time */ if (statbufDst.st_mtim.tv_sec != a_modtime) { echoDebug(DBG_PKGOPS_MOD_MISMATCH, dstpath, statbufDst.st_mtim.tv_sec, "source", a_modtime); return (B_FALSE); } /* * verify checksums of both files */ /* generate checksum of installed file */ cksumerr = 0; dstcksum = compute_checksum(&cksumerr, dstpath); if (cksumerr != 0) { progerr(ERR_CANNOT_CKSUM_FILE, dstpath, strerror(errno)); return (B_FALSE); } /* return false if destination does not match recorded checksum */ if (dstcksum != a_cksum) { echoDebug(DBG_PKGOPS_CKSUM_MISMATCH, dstpath, dstcksum, "source", a_cksum); return (B_FALSE); } /* generate checksum of file to install */ cksumerr = 0; srcksum = compute_checksum(&cksumerr, a_src); if (cksumerr != 0) { progerr(ERR_CANNOT_CKSUM_FILE, a_src, strerror(errno)); return (B_FALSE); } /* return false if source to install does not match recorded checksum */ if (srcksum != dstcksum) { echoDebug(DBG_PKGOPS_CKSUM_MISMATCH, a_src, srcksum, dstpath, dstcksum); return (B_FALSE); } /* src/dest identical - return true */ echoDebug(DBG_PKGOPS_IS_INHERITED, dstpath, ""); return (B_TRUE); } /* * return string representing path to "global zone only file" */ char * pkgGetGzOnlyPath(void) { return (GLOBALZONE_ONLY_PACKAGE_FILE_PATH); } /* * Name: pkgAddThisZonePackage * Description: Add specified package to internal list of "this zone only" pkgs * Arguments: a_pkgInst - name of package to add to list * Returns: void */ void pkgAddThisZonePackage(char *a_pkgInst) { /* entry assertions */ assert(a_pkgInst != (char *)NULL); assert(*a_pkgInst != '\0'); /* do not duplicate entries */ if (pkgPackageIsThisZone(a_pkgInst) == B_TRUE) { return; } /* add package name to internal list */ if (thisZonePackages == (char **)NULL) { thisZonePackages = (char **)calloc(2, sizeof (char **)); } else { thisZonePackages = (char **)realloc(thisZonePackages, sizeof (char **)*(numThisZonePackages+2)); } /* handle out of memory error */ if (thisZonePackages == (char **)NULL) { progerr(ERR_MEMORY, errno); quit(99); } /* add this entry to the end of the list */ thisZonePackages[numThisZonePackages] = strdup(a_pkgInst); if (thisZonePackages[numThisZonePackages] == (char *)NULL) { progerr(ERR_MEMORY, errno); quit(99); } numThisZonePackages++; /* make sure end of the list is properly terminated */ thisZonePackages[numThisZonePackages] = (char *)NULL; /* exit debugging info */ echoDebug(DBG_PKGOPS_ADD_TZP, numThisZonePackages, thisZonePackages[numThisZonePackages-1]); } /* * Name: pkgPackageIsThisZone * Description: Determine if the specified package is marked to be installed * in this zone only * Arguments: a_pkgInst - pointer to string representing package name to check * Returns: boolean_t * B_TRUE - the package IS "this zone only" * B_FALSE - the paackage is NOT "this zone only" */ boolean_t pkgPackageIsThisZone(char *a_pkgInst) { int n; /* entry assertions */ assert(a_pkgInst != (char *)NULL); assert(*a_pkgInst != '\0'); /* if no inherited file systems, there can be no match */ if (numThisZonePackages == 0) { echoDebug(DBG_PKGOPS_NOT_THISZONE, a_pkgInst); return (B_FALSE); } /* * see if this package is in the "this zone only" list */ for (n = 0; n < numThisZonePackages; n++) { if (strcmp(a_pkgInst, thisZonePackages[n]) == 0) { echoDebug(DBG_PKGOPS_IS_THISZONE, a_pkgInst); return (B_TRUE); } } /* path is not in "this zone only" list */ echoDebug(DBG_PKGOPS_IS_NOT_THISZONE, a_pkgInst); return (B_FALSE); } /* * Name: pkgLocateHighestInst * Description: Locate the highest installed instance of a package * Arguments: r_path - [RO, *RW] - (char *) * Pointer to buffer where the full path to the top level * directory containing the latest instance of the * specified package is located is placed. * r_pathLen - [RO, *RO] - (int) * Integer representing the size of r_path in bytes. * r_pkgInst - [RO, *RW] - (char *) * Pointer to buffer where the package instance name of the * latest instance of the specified package is placed. * r_pkgInstLen - [RO, *RO] - (int) * Integer representing the size of r_pkgInst in bytes. * a_rootPath - [RO, *RO] - (char *) * Pointer to string representing the root path to look * for the latest instance of the specified package. * a_pkgInst - [RO, *RO] - (char *) * Pointer to string representing the name of the package * to locate the latest installed instance of. */ void pkgLocateHighestInst(char *r_path, int r_pathLen, char *r_pkgInst, int r_pkgInstLen, char *a_rootPath, char *a_pkgInst) { char pkgInstPath[PATH_MAX] = {'\0'}; char pkgWild[PKGSIZ+1] = {'\0'}; char pkgName[PKGSIZ+1] = {'\0'}; int npkgs; struct pkginfo *pinf = (struct pkginfo *)NULL; /* entry assertions */ assert(r_path != (char *)NULL); assert(r_pathLen > 0); assert(r_pkgInst != (char *)NULL); assert(r_pkgInstLen > 0); assert(a_pkgInst != (char *)NULL); assert(*a_pkgInst != '\0'); /* normalize root path */ if ((a_rootPath == (char *)NULL) || (strcmp(a_rootPath, "/") == 0)) { a_rootPath = ""; } /* construct path to package repository directory (eg. /var/sadm/pkg) */ (void) snprintf(pkgInstPath, sizeof (pkgInstPath), "%s%s", a_rootPath, PKGLOC); /* entry debugging info */ echoDebug(DBG_PKGOPS_LOCHIGH_ENTRY); echoDebug(DBG_PKGOPS_LOCHIGH_ARGS, pkgInstPath, a_pkgInst); /* reset returned path/package instance so both ares empty */ *r_path = '\0'; *r_pkgInst = '\0'; /* remove any architecture extension */ pkgstrGetToken_r((char *)NULL, a_pkgInst, 0, ".", pkgName, sizeof (pkgName)); /* make sure that the package name is valid and can be wild carded */ if (pkgnmchk(pkgName, NULL, 0) || strchr(pkgName, '.')) { progerr(ERR_PKGOPS_LOCHIGH_BAD_PKGNAME, pkgName); quit(99); } /* create wild card specification for this package instance */ (void) snprintf(pkgWild, sizeof (pkgWild), "%s.*", pkgName); echoDebug(DBG_PKGOPS_LOCHIGH_WILDCARD, pkgName, pkgWild); /* * inspect the system to determine if any instances of the * package being installed already exist on the system */ for (npkgs = 0; ; npkgs++) { char *savePkgdir; int r; /* allocate new pinfo structure for use in the pkginfo call */ pinf = _pkginfoFactory(); /* * lookup the specified package; the first call will cause the * pkgdir directory to be opened - it will be closed when the * end of directory is read and pkginfo() returns != 0. You must * cycle through all instances until pkginfo() returns != 0. * NOTE: pkginfo() requires the global variable 'pkgdir' be set * to the package installed directory (/var/sadm/pkg). */ savePkgdir = pkgdir; pkgdir = pkgInstPath; r = pkginfo(pinf, pkgWild, NULL, NULL); pkgdir = savePkgdir; echoDebug(DBG_PKGOPS_PKGINFO_RETURNED, pkgName, r); /* break out of loop of no package found */ if (r != 0) { pkginfoFree(&pinf); break; } echoDebug(DBG_PKGOPS_LOCHIGH_INSTANCE, npkgs, pinf->pkginst ? pinf->pkginst : "", pinf->name ? pinf->name : "", pinf->arch ? pinf->arch : "", pinf->version ? pinf->version : "", pinf->vendor ? pinf->vendor : "", pinf->basedir ? pinf->basedir : "", pinf->catg ? pinf->catg : "", pinf->status); /* save path/instance name for this instance found */ (void) strlcpy(r_pkgInst, pinf->pkginst, r_pkgInstLen); pkgstrPrintf_r(r_path, r_pathLen, "%s%s/%s", a_rootPath, PKGLOC, pinf->pkginst); pkginfoFree(&pinf); } echoDebug(DBG_PKGOPS_LOCHIGH_RETURN, npkgs, r_pkgInst, r_path); } /* * Name: pkgTestInstalled * Description: determine if package is installed at specified root path * Arguments: a_packageName - name of package to test * a_rootPath - root path of alternative root to test * Returns: B_TRUE - package is installed * B_FALSE - package is not installed */ boolean_t pkgTestInstalled(char *a_packageName, char *a_rootPath) { char cmd[MAXPATHLEN+1]; int rc; /* entry assertions */ assert(a_packageName != (char *)NULL); assert(*a_packageName != '\0'); assert(a_rootPath != (char *)NULL); assert(a_rootPath != '\0'); /* entry debugging info */ echoDebug(DBG_PKG_TEST_EXISTENCE, a_packageName, a_rootPath); /* * create pkginfo command to execute: * /usr/bin/pkginfo -q */ (void) snprintf(cmd, sizeof (cmd), "%s -q %s", PKGINFO_CMD, a_packageName); /* execute command */ rc = system(cmd); /* return success if pkginfo returns "0" */ if (rc == 0) { echoDebug(DBG_PKG_INSTALLED, a_packageName, a_rootPath); return (B_TRUE); } /* package not installed */ echoDebug(DBG_PKG_NOT_INSTALLED, a_packageName, a_rootPath); return (B_FALSE); } /* * ***************************************************************************** * static internal (private) functions * ***************************************************************************** */ static void _pkginfoInit(struct pkginfo *a_info) { /* entry assertions */ assert(a_info != (struct pkginfo *)NULL); /* free previously allocated space */ if (a_info->pkginst) { free(a_info->pkginst); if (a_info->arch) free(a_info->arch); if (a_info->version) free(a_info->version); if (a_info->basedir) free(a_info->basedir); if (a_info->name) free(a_info->name); if (a_info->vendor) free(a_info->vendor); if (a_info->catg) free(a_info->catg); } a_info->pkginst = NULL; a_info->arch = a_info->version = NULL; a_info->basedir = a_info->name = NULL; a_info->vendor = a_info->catg = NULL; a_info->status = PI_UNKNOWN; } static struct pkginfo * _pkginfoFactory(void) { struct pkginfo *pinf; pinf = (struct pkginfo *)calloc(1, sizeof (struct pkginfo)); if (pinf == (struct pkginfo *)NULL) { progerr(ERR_MEM); exit(1); } _pkginfoInit(pinf); return (pinf); }