#include <stdio.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
#include <pkgdev.h>
#include <pkginfo.h>
#include <pkglocs.h>
#include <locale.h>
#include <libintl.h>
#include <instzones_api.h>
#include <pkglib.h>
#include <install.h>
#include <libinst.h>
#include <libadm.h>
#include <messages.h>
#define PKGINFO_CMD "/usr/bin/pkginfo"
#define GLOBALZONE_ONLY_PACKAGE_FILE_PATH \
"/var/sadm/install/gz-only-packages"
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
static void _pkginfoInit(struct pkginfo *a_info);
static struct pkginfo *_pkginfoFactory(void);
static char **thisZonePackages;
static int numThisZonePackages;
void
pkginfoFree(struct pkginfo **r_info)
{
struct pkginfo *pinfo;
assert(r_info != (struct pkginfo **)NULL);
pinfo = *r_info;
*r_info = (struct pkginfo *)NULL;
assert(pinfo != (struct pkginfo *)NULL);
_pkginfoInit(pinfo);
(void) free(pinfo);
}
boolean_t
pkginfoIsPkgInstalled(struct pkginfo **r_pinfo, char *a_pkgInst)
{
int r;
struct pkginfo *pinf;
assert(a_pkgInst != (char *)NULL);
assert(*a_pkgInst != '\0');
if (r_pinfo != (struct pkginfo **)NULL) {
*r_pinfo = (struct pkginfo *)NULL;
}
pinf = _pkginfoFactory();
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 {
pkginfoFree(&pinf);
}
return (r == 0 ? B_TRUE : B_FALSE);
}
FILE *
pkgOpenInGzOnlyFile(char *a_rootPath)
{
FILE *pkgingzonlyFP;
char pkgingzonlyPath[PATH_MAX];
int len;
if (a_rootPath == (char *)NULL) {
a_rootPath = "";
}
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);
}
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);
}
return (pkgingzonlyFP);
}
boolean_t
pkgIsPkgInGzOnly(char *a_rootPath, char *a_pkgInst)
{
FILE *fp;
boolean_t in_gz_only;
if (a_rootPath == (char *)NULL) {
a_rootPath = "";
}
fp = pkgOpenInGzOnlyFile(a_rootPath);
if (fp == (FILE *)NULL) {
echoDebug(ERR_PKGOPS_CANNOT_OPEN_GZONLY,
a_rootPath ? a_rootPath : "/");
return (B_FALSE);
}
in_gz_only = pkgIsPkgInGzOnlyFP(fp, a_pkgInst);
(void) fclose(fp);
return (in_gz_only);
}
boolean_t
pkgIsPkgInGzOnlyFP(FILE *a_fp, char *a_pkgInst)
{
char line[PATH_MAX+1];
assert(a_fp != (FILE *)NULL);
assert(a_pkgInst != (char *)NULL);
assert(*a_pkgInst != '\0');
rewind(a_fp);
while (fgets(line, sizeof (line), a_fp) != (char *)NULL) {
int len;
len = strlen(line);
while ((len > 0) && (line[len-1] == '\n')) {
line[--len] = '\0';
}
if ((line[0] == '#') || (line[0] == '\0')) {
continue;
}
if (strcmp(a_pkgInst, line) == 0) {
echoDebug(DBG_PKGOPS_PKG_IS_GZONLY, a_pkgInst);
return (B_TRUE);
}
}
echoDebug(DBG_PKGOPS_PKG_NOT_GZONLY, a_pkgInst);
return (B_FALSE);
}
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;
assert(a_pkgInst != (char *)NULL);
assert(*a_pkgInst != '\0');
if (a_rootPath == (char *)NULL) {
a_rootPath = "";
}
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);
}
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);
}
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);
}
srcFP = fopen(srcPath, "r+");
if ((srcFP == (FILE *)NULL) && (errno == ENOENT)) {
srcFP = fopen(srcPath, "w+");
}
if (srcFP == (FILE *)NULL) {
progerr(ERR_PKGOPS_OPEN_GZONLY, srcPath, strerror(errno));
return (B_FALSE);
}
(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);
}
(void) time(&clock);
timep = localtime(&clock);
(void) strftime(timeb, sizeof (timeb), "%c\n", timep);
(void) fprintf(destFP, MSG_GZONLY_FILE_HEADER,
get_prog_name(), "remove", a_pkgInst, timeb);
while (fgets(line, sizeof (line), srcFP) != (char *)NULL) {
int len;
len = strlen(line);
while ((len > 0) && (line[len-1] == '\n')) {
line[--len] = '\0';
}
if ((line[0] == '#') || (line[0] == '\0')) {
continue;
}
if ((pkgremoved == B_FALSE) && (strcmp(a_pkgInst, line) == 0)) {
pkgremoved = B_TRUE;
} else {
(void) fprintf(destFP, "%s\n", line);
}
}
(void) fclose(srcFP);
(void) fclose(destFP);
if (pkgremoved == B_FALSE) {
(void) unlink(destPath);
return (B_TRUE);
}
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));
}
echoDebug(DBG_PKGOPS_REMOVED_GZPKG, a_pkgInst);
return (B_TRUE);
}
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;
assert(a_pkgInst != (char *)NULL);
assert(*a_pkgInst != '\0');
if (a_rootPath == (char *)NULL) {
a_rootPath = "";
}
echoDebug(DBG_PKGOPS_ADDGZPKG, a_pkgInst, a_rootPath);
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);
}
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);
}
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);
}
srcFP = fopen(srcPath, "r+");
if ((srcFP == (FILE *)NULL) && (errno == ENOENT)) {
srcFP = fopen(srcPath, "w+");
}
if (srcFP == (FILE *)NULL) {
progerr(ERR_PKGOPS_OPEN_GZONLY, srcPath, strerror(errno));
return (B_FALSE);
}
(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);
}
(void) time(&clock);
timep = localtime(&clock);
(void) strftime(timeb, sizeof (timeb), "%c\n", timep);
(void) fprintf(destFP, MSG_GZONLY_FILE_HEADER,
get_prog_name(), "add", a_pkgInst, timeb);
while (fgets(line, sizeof (line), srcFP) != (char *)NULL) {
int len;
len = strlen(line);
while ((len > 0) && (line[len-1] == '\n')) {
line[--len] = '\0';
}
if ((line[0] == '#') || (line[0] == '\0')) {
continue;
}
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 (pkgadded == B_FALSE) {
(void) fprintf(destFP, "%s\n", a_pkgInst);
}
(void) fclose(srcFP);
(void) fclose(destFP);
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));
}
echoDebug(DBG_PKGOPS_ADDED_GZPKG, a_pkgInst);
return (B_TRUE);
}
boolean_t
pkginfoParamTruth(FILE *a_fp, char *a_param, char *a_value, boolean_t a_default)
{
char *param;
boolean_t result;
assert(a_fp != (FILE *)NULL);
assert(a_param != (char *)NULL);
assert(*a_param != '\0');
assert(a_value != (char *)NULL);
assert(*a_value != '\0');
rewind(a_fp);
param = fpkgparam(a_fp, a_param);
if (param == (char *)NULL) {
result = a_default;
} else if (*param == '\0') {
result = a_default;
} else if (strcasecmp(param, a_value) == 0) {
result = B_TRUE;
} else {
result = B_FALSE;
}
echoDebug(DBG_PKGOPS_PARAMTRUTH_RESULTS,
a_param, a_value, a_default == B_TRUE ? "true" : "false",
param ? param : "?", result == B_TRUE ? "true" : "false");
if (param != (char *)NULL) {
(void) free(param);
}
return (result);
}
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};
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);
echoDebug(DBG_PKGOPS_GETPKGLIST_ENTRY);
echoDebug(DBG_PKGOPS_GETPKGLIST_ARGS, a_pkgdev->dirname,
a_categories ? a_categories : "?");
*r_pkgList = (char **)NULL;
if (a_categories != NULL) {
*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);
}
*r_pkgList = gpkglist(a_pkgdev->dirname, &a_argv[a_optind], NULL);
if (*r_pkgList != NULL) {
echoDebug(DBG_PKGOPS_GPKGLIST_OK);
return (0);
}
switch (errno) {
case ENOPKG:
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);
}
}
char *
pkgGetGzOnlyPath(void)
{
return (GLOBALZONE_ONLY_PACKAGE_FILE_PATH);
}
void
pkgAddThisZonePackage(char *a_pkgInst)
{
assert(a_pkgInst != (char *)NULL);
assert(*a_pkgInst != '\0');
if (pkgPackageIsThisZone(a_pkgInst) == B_TRUE) {
return;
}
if (thisZonePackages == (char **)NULL) {
thisZonePackages =
(char **)calloc(2, sizeof (char **));
} else {
thisZonePackages =
(char **)realloc(thisZonePackages,
sizeof (char **)*(numThisZonePackages+2));
}
if (thisZonePackages == (char **)NULL) {
progerr(ERR_MEMORY, errno);
quit(99);
}
thisZonePackages[numThisZonePackages] = strdup(a_pkgInst);
if (thisZonePackages[numThisZonePackages] == (char *)NULL) {
progerr(ERR_MEMORY, errno);
quit(99);
}
numThisZonePackages++;
thisZonePackages[numThisZonePackages] = (char *)NULL;
echoDebug(DBG_PKGOPS_ADD_TZP, numThisZonePackages,
thisZonePackages[numThisZonePackages-1]);
}
boolean_t
pkgPackageIsThisZone(char *a_pkgInst)
{
int n;
assert(a_pkgInst != (char *)NULL);
assert(*a_pkgInst != '\0');
for (n = 0; n < numThisZonePackages; n++) {
if (strcmp(a_pkgInst, thisZonePackages[n]) == 0) {
echoDebug(DBG_PKGOPS_IS_THISZONE, a_pkgInst);
return (B_TRUE);
}
}
echoDebug(DBG_PKGOPS_IS_NOT_THISZONE, a_pkgInst);
return (B_FALSE);
}
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;
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');
if ((a_rootPath == (char *)NULL) || (strcmp(a_rootPath, "/") == 0)) {
a_rootPath = "";
}
(void) snprintf(pkgInstPath, sizeof (pkgInstPath), "%s%s", a_rootPath,
PKGLOC);
echoDebug(DBG_PKGOPS_LOCHIGH_ENTRY);
echoDebug(DBG_PKGOPS_LOCHIGH_ARGS, pkgInstPath, a_pkgInst);
*r_path = '\0';
*r_pkgInst = '\0';
pkgstrGetToken_r((char *)NULL, a_pkgInst, 0, ".",
pkgName, sizeof (pkgName));
if (pkgnmchk(pkgName, NULL, 0) || strchr(pkgName, '.')) {
progerr(ERR_PKGOPS_LOCHIGH_BAD_PKGNAME, pkgName);
quit(99);
}
(void) snprintf(pkgWild, sizeof (pkgWild), "%s.*", pkgName);
echoDebug(DBG_PKGOPS_LOCHIGH_WILDCARD, pkgName, pkgWild);
for (npkgs = 0; ; npkgs++) {
char *savePkgdir;
int r;
pinf = _pkginfoFactory();
savePkgdir = pkgdir;
pkgdir = pkgInstPath;
r = pkginfo(pinf, pkgWild, NULL, NULL);
pkgdir = savePkgdir;
echoDebug(DBG_PKGOPS_PKGINFO_RETURNED, pkgName, r);
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);
(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);
}
boolean_t
pkgTestInstalled(char *a_packageName, char *a_rootPath)
{
char cmd[MAXPATHLEN+1];
int rc;
assert(a_packageName != NULL);
assert(*a_packageName != '\0');
assert(a_rootPath != NULL);
assert(*a_rootPath != '\0');
echoDebug(DBG_PKG_TEST_EXISTENCE, a_packageName, a_rootPath);
(void) snprintf(cmd, sizeof (cmd),
"%s -q %s", PKGINFO_CMD, a_packageName);
rc = system(cmd);
if (rc == 0) {
echoDebug(DBG_PKG_INSTALLED, a_packageName, a_rootPath);
return (B_TRUE);
}
echoDebug(DBG_PKG_NOT_INSTALLED, a_packageName, a_rootPath);
return (B_FALSE);
}
static void
_pkginfoInit(struct pkginfo *a_info)
{
assert(a_info != (struct pkginfo *)NULL);
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);
}