Esempio n. 1
0
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) sprintf(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);
}
Esempio n. 2
0
void
setadminFile(char *file)
{
	FILE	*fp;
	int	i;
	char	param[MAX_PKG_PARAM_LENGTH];
	char	*value;
	char	path[PATH_MAX];
	int	mail = 0;

	if (file == NULL)
		file = "default";
	else if (strcmp(file, "none") == 0) {
		adm.basedir = "ask";
		return;
	}

	if (file[0] == '/')
		(void) strcpy(path, file);
	else {
		(void) snprintf(path, sizeof (path), "%s/admin/%s",
				get_PKGADM(), file);
		if (access(path, R_OK)) {
			(void) snprintf(path, sizeof (path), "%s/admin/%s",
				PKGADM, file);
		}
	}

	if ((fp = fopen(path, "r")) == NULL) {
		progerr(ERR_OPEN_ADMIN_FILE, file, strerror(errno));
		quit(99);
	}

	param[0] = '\0';
	while (value = fpkgparam(fp, param)) {
		if (strcmp(param, "mail") == 0) {
			mail = 1;
		}
		if (value[0] == '\0') {
			param[0] = '\0';
			continue; /* same as not being set at all */
		}
		for (i = 0; admlist[i].memloc; i++) {
			if (strcmp(param, admlist[i].tag) == 0) {
				*admlist[i].memloc = value;
				break;
			}
		}
		if (admlist[i].memloc == NULL) {
			logerr(WRN_UNKNOWN_ADM_PARAM, param);
			free(value);
		}
		param[0] = '\0';
	}

	(void) fclose(fp);

	if (!mail) {
		adm.mail = DEFMAIL; 	/* if we don't assign anything to it */
	}
}
Esempio n. 3
0
void
merginfo(struct cl_attr **pclass, int install_from_pspool)
{
	DIR		*pdirfp;
	FILE		*fp;
	FILE		*pkginfoFP;
	char		path[PATH_MAX];
	char		cmd[PATH_MAX];
	char		pkginfoPath[PATH_MAX];
	char		temp[PATH_MAX];
	int		i;
	int		nc;
	int		out;

	/* remove savelog from previous attempts */

	(void) unlink(savlog);

	/*
	 * create path to appropriate pkginfo file for the package that is
	 * already installed - is_spool_create() will be set (!= 0) if the
	 * -t option is presented to pkginstall - the -t option is used to
	 * disable save spool area creation; do not spool any partial package
	 * contents, that is, suppress the creation and population of the
	 * package save spool area (var/sadm/pkg/PKG/save/pspool/PKG). This
	 * option is set only when a non-global zone is being created.
	 */

	if (is_spool_create() == 0) {
		/*
		 * normal package install (not a non-global zone install);
		 * use the standard installed pkginfo file for this package:
		 * --> /var/sadm/pkg/PKGINST/pkginfo
		 * as the source pkginfo file to scan.
		 */
		i = snprintf(pkginfoPath, sizeof (pkginfoPath),
			"%s/var/sadm/pkg/%s/%s",
			((get_inst_root()) &&
			(strcmp(get_inst_root(), "/") != 0)) ?
			get_inst_root() : "", pkginst,
			PKGINFO);
		if (i > sizeof (pkginfoPath)) {
			progerr(ERR_CREATE_PATH_2,
				((get_inst_root()) &&
				(strcmp(get_inst_root(), "/") != 0)) ?
				get_inst_root() : "/",
				pkginst);
			quit(1);
		}
	} else {
		/*
		 * non-global zone installation - use the "saved" pspool
		 * pkginfo file in the global zone for this package:
		 * --> /var/sadm/install/PKG/save/pspool/PKG/pkginfo
		 * as the source pkginfo file to scan.
		 */
		i = snprintf(pkginfoPath, sizeof (pkginfoPath), "%s/%s",
			saveSpoolInstallDir, PKGINFO);
		if (i > sizeof (pkginfoPath)) {
			progerr(ERR_CREATE_PATH_2,
				saveSpoolInstallDir, PKGINFO);
			quit(1);
		}
	}

	i = snprintf(path, PATH_MAX, "%s/%s", pkgloc, PKGINFO);
	if (i > PATH_MAX) {
		progerr(ERR_CREATE_PATH_2, pkgloc, PKGINFO);
		quit(1);
	}

	/* entry debugging info */

	echoDebug(DBG_MERGINFO_ENTRY,
		instdir ? instdir : "??",
		((get_inst_root()) &&
		(strcmp(get_inst_root(), "/") != 0)) ?
		get_inst_root() : "??",
		saveSpoolInstallDir ? saveSpoolInstallDir : "??",
		pkgloc ? pkgloc : "??",	is_spool_create(),
		get_info_basedir() ? get_info_basedir() : "??",
		pkginfoPath, path);

	/*
	 * open the pkginfo file:
	 * if the source pkginfo file to check is the same as the merged one
	 * (e.g. /var/sadm/pkg/PKGINST/pkginfo) then do not open the source
	 * pkginfo file to "verify"
	 */

	if (strcmp(pkginfoPath, path) == 0) {
		pkginfoFP = (FILE *)NULL;
		echoDebug(DBG_MERGINFO_SAME, path);
	} else {
		echoDebug(DBG_MERGINFO_DIFFERENT, pkginfoPath, path);
		pkginfoFP = fopen(pkginfoPath, "r");

		if (pkginfoFP == (FILE *)NULL) {
			echoDebug(ERR_NO_PKG_INFOFILE, pkginst, pkginfoPath,
				strerror(errno));
		}
	}

	/*
	 * output packaging environment to create a pkginfo file in pkgloc[]
	 */

	if ((fp = fopen(path, "w")) == NULL) {
		progerr(ERR_CANNOT_OPEN_FOR_WRITING, path, strerror(errno));
		quit(99);
	}

	/*
	 * output CLASSES attribute
	 */

	out = 0;
	(void) fputs("CLASSES=", fp);
	if (pclass) {
		(void) fputs(pclass[0]->name, fp);
		out++;
		for (i = 1; pclass[i]; i++) {
			(void) putc(' ', fp);
			(void) fputs(pclass[i]->name, fp);
			out++;
		}
	}
	nc = cl_getn();
	for (i = 0; i < nc; i++) {
		int found = 0;

		if (pclass) {
			int	j;

			for (j = 0; pclass[j]; ++j) {
				if (cl_nam(i) != NULL &&
					strcmp(cl_nam(i),
					pclass[j]->name) == 0) {
					found++;
					break;
				}
			}
		}
		if (!found) {
			if (out > 0) {
				(void) putc(' ', fp);
			}
			(void) fputs(cl_nam(i), fp);
			out++;
		}
	}
	(void) putc('\n', fp);

	/*
	 * NOTE : BASEDIR below is relative to the machine that
	 * *runs* the package. If there's an install root, this
	 * is actually the CLIENT_BASEDIR wrt the machine
	 * doing the pkgadd'ing here. -- JST
	 */

	if (is_a_basedir()) {
		static char	*txs1 = "BASEDIR=";

		(void) fputs(txs1, fp);
		(void) fputs(get_info_basedir(), fp);
		(void) putc('\n', fp);
	} else {
		(void) fputs("BASEDIR=/", fp);
		(void) putc('\n', fp);
	}

	/*
	 * output all other environment attributes except those which
	 * are relevant only to install.
	 */

	for (i = 0; environ[i] != (char *)NULL; i++) {
		char	*ep = environ[i];
		int	attrPos = -1;
		int	incr = (ATTRTBL_SIZE >> 1)+1;	/* searches possible */
		int	pos = ATTRTBL_SIZE >> 1;	/* start in middle */
		NAMELIST_T	*pp = (NAMELIST_T *)NULL;

		/*
		 * find this attribute in the table - accept the attribute if it
		 * is outside of the bounds of the table; otherwise, do a binary
		 * search looking for this attribute.
		 */

		if (strncmp(ep, attrTbl[0]._nlName, attrTbl[0]._nlLen) < 0) {

			/* entry < first entry in attribute table */

			echoDebug(DBG_MERGINFO_LESS_THAN, ep,
				attrTbl[0]._nlName);

		} else if (strncmp(ep, attrTbl[ATTRTBL_SIZE-1]._nlName,
				attrTbl[ATTRTBL_SIZE-1]._nlLen) > 0) {

			/* entry > last entry in attribute table */

			echoDebug(DBG_MERGINFO_GREATER_THAN, ep,
				attrTbl[ATTRTBL_SIZE-1]._nlName);

		} else {
			/* first entry < entry < last entry in table: search */

			echoDebug(DBG_MERGINFO_SEARCHING, ep,
				attrTbl[0]._nlName,
				attrTbl[ATTRTBL_SIZE-1]._nlName);

			while (incr > 0) {	/* while possible to divide */
				int	r;

				pp = &attrTbl[pos];

				/* compare current attr with this table entry */
				r = strncmp(pp->_nlName, ep, pp->_nlLen);

				/* break out of loop if match */
				if (r == 0) {
					/* save location/break if match found */
					attrPos = pos;
					break;
				}

				/* no match search to next/prev half */
				incr = incr >> 1;
				pos += (r < 0) ? incr : -incr;
				continue;
			}
		}

		/* handle excluded attribute found */

		if ((attrPos >= 0) && (pp->_nlFlag == FLAG_EXCLUDE)) {
			/* attribute is excluded */
			echoDebug(DBG_MERGINFO_EXCLUDING, ep);
			continue;
		}

		/* handle fixed attribute found */

		if ((pkginfoFP != (FILE *)NULL) && (attrPos >= 0) &&
			(pp->_nlFlag == FLAG_IDENTICAL)) {
			/* attribute must not change */

			char	*src = ep+pp->_nlLen;
			char	*trg;
			char	theAttr[PATH_MAX+1];

			/* isolate attribute name only without '=' at end */

			(void) strncpy(theAttr, pp->_nlName, pp->_nlLen-1);
			theAttr[pp->_nlLen-1] = '\0';

			/* lookup attribute in installed package pkginfo file */

			rewind(pkginfoFP);
			trg = fpkgparam(pkginfoFP, theAttr);

			echoDebug(DBG_MERGINFO_ATTRCOMP, theAttr,
				trg ? trg : "");

			/* if target not found attribute is being added */

			if (trg == (char *)NULL) {
				progerr(ERR_PKGINFO_ATTR_ADDED, pkginst, ep);
				quit(1);
			}

			/* error if two values are not the same */

			if (strcmp(src, trg) != 0) {
				progerr(ERR_PKGINFO_ATTR_CHANGED, pkginst,
					theAttr, src, trg);
				quit(1);
			}
		}

		/* attribute not excluded/has not changed - process */

		if ((strncmp(ep, "PKGSAV=", 7) == 0)) {
			(void) fputs("PKGSAV=", fp);
			(void) fputs(infoloc, fp);
			(void) putc('/', fp);
			(void) fputs(pkginst, fp);
			(void) fputs("/save\n", fp);
			continue;
		}

		if ((strncmp(ep, "UPDATE=", 7) == 0) &&
				install_from_pspool != 0 &&
				!isPatchUpdate() &&
				!isUpdate()) {
			continue;
		}

		echoDebug(DBG_MERGINFO_FINAL, ep);

		(void) fputs(ep, fp);
		(void) putc('\n', fp);
	}

	(void) fclose(fp);
	(void) fclose(pkginfoFP);

	/*
	 * copy all packaging scripts to appropriate directory
	 */

	i = snprintf(path, PATH_MAX, "%s/install", instdir);
	if (i > PATH_MAX) {
		progerr(ERR_CREATE_PATH_2, instdir, "/install");
		quit(1);
	}

	if ((pdirfp = opendir(path)) != NULL) {
		struct dirent	*dp;

		while ((dp = readdir(pdirfp)) != NULL) {
			if (dp->d_name[0] == '.')
				continue;

			i = snprintf(path, PATH_MAX, "%s/install/%s",
					instdir, dp->d_name);
			if (i > PATH_MAX) {
				progerr(ERR_CREATE_PATH_3, instdir, "/install/",
					dp->d_name);
				quit(1);
			}

			i = snprintf(temp, PATH_MAX, "%s/%s", pkgbin,
					dp->d_name);
			if (i > PATH_MAX) {
				progerr(ERR_CREATE_PATH_2, pkgbin, dp->d_name);
				quit(1);
			}

			if (cppath(MODE_SRC|DIR_DISPLAY, path, temp, 0644)) {
			    progerr(ERR_CANNOT_COPY, dp->d_name, pkgbin);
				quit(99);
			}
		}
		(void) closedir(pdirfp);
	}

	/*
	 * copy all packaging scripts to the partial spool directory
	 */

	if (!is_spool_create()) {
		/* packages are being spooled to ../save/pspool/.. */
		i = snprintf(path, PATH_MAX, "%s/install", instdir);
		if (i > PATH_MAX) {
			progerr(ERR_CREATE_PATH_2, instdir, "/install");
			quit(1);
		}

		if (((pdirfp = opendir(path)) != NULL) &&
			!isPatchUpdate()) {
			struct dirent	*dp;


			while ((dp = readdir(pdirfp)) != NULL) {
				if (dp->d_name[0] == '.')
					continue;
				/*
				 * Don't copy i.none since if it exists it
				 * contains Class Archive Format procedure
				 * for installing archives. Only Directory
				 * Format packages can exist
				 * in a global spooled area.
				 */
				if (strcmp(dp->d_name, "i.none") == 0)
					continue;

				i = snprintf(path, PATH_MAX, "%s/install/%s",
						instdir, dp->d_name);

				if (i > PATH_MAX) {
					progerr(ERR_CREATE_PATH_3, instdir,
						"/install/", dp->d_name);
					quit(1);
				}

				i = snprintf(temp, PATH_MAX, "%s/install/%s",
						saveSpoolInstallDir,
						dp->d_name);

				if (i > PATH_MAX) {
					progerr(ERR_CREATE_PATH_3,
						saveSpoolInstallDir,
						"/install/", dp->d_name);
					quit(1);
				}

				if (cppath(MODE_SRC, path, temp, 0644)) {
					progerr(ERR_CANNOT_COPY, path, temp);
					(void) closedir(pdirfp);
					quit(99);
				}
			}
			(void) closedir(pdirfp);
		}

		/*
		 * Now copy the original pkginfo and pkgmap files from the
		 * installing package to the spooled directory.
		 */

		i = snprintf(path, sizeof (path), "%s/%s", instdir, PKGINFO);
		if (i > sizeof (path)) {
			progerr(ERR_CREATE_PATH_2, instdir, PKGINFO);
			quit(1);
		}

		i = snprintf(temp, sizeof (temp), "%s/%s",
				saveSpoolInstallDir, PKGINFO);
		if (i > sizeof (temp)) {
			progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir,
				PKGINFO);
			quit(1);
		}

		if (cppath(MODE_SRC, path, temp, 0644)) {
			progerr(ERR_CANNOT_COPY, path, temp);
			quit(99);
		}

		/*
		 * Only want to copy the FCS pkgmap if this is not a
		 * patch installation.
		 */

		if (!isPatchUpdate()) {
			i = snprintf(path, sizeof (path), "%s/pkgmap", instdir);
			if (i > sizeof (path)) {
				progerr(ERR_CREATE_PATH_2, instdir, "pkgmap");
				quit(1);
			}

			i = snprintf(temp, sizeof (temp), "%s/pkgmap",
				saveSpoolInstallDir);
			if (i > sizeof (path)) {
				progerr(ERR_CREATE_PATH_2, saveSpoolInstallDir,
					"pkgmap");
				quit(1);
			}

			if (cppath(MODE_SRC, path, temp, 0644)) {
				progerr(ERR_CANNOT_COPY, path, temp);
				quit(99);
			}
		}
	}

	/*
	 * If we are installing from a spool directory
	 * copy the save directory from it, it may have
	 * been patched. Duplicate it only if this
	 * installation isn't an update and is not to
	 * an alternate root.
	 */
	if (strstr(instdir, "pspool") != NULL) {
		struct stat status;

		i = snprintf(path, sizeof (path), "%s/save", instdir);
		if (i > sizeof (path)) {
			progerr(ERR_CREATE_PATH_2, instdir, "save");
			quit(1);
		}

		if ((stat(path, &status) == 0) &&
				(status.st_mode & S_IFDIR) &&
				!isPatchUpdate()) {
			i = snprintf(cmd, sizeof (cmd), "cp -pr %s/* %s",
					path, pkgsav);
			if (i > sizeof (cmd)) {
				progerr(ERR_SNPRINTF, "cp -pr %s/* %s");
				quit(1);
			}

			if (system(cmd)) {
				progerr(ERR_PKGBINCP, path, pkgsav);
				quit(99);
			}
		}
	}
}
Esempio n. 4
0
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) {
		if ((errno == ENOENT) && strcmp(pkgdir, get_PKGLOC()) == 0)
			return (svr4info(info, pkginst, ckvers));

		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) sprintf(temp, "%s/%s/!I-Lock!", pkgdir, pkginst);
		if (access(temp, 0) == 0)
			info->status = PI_PARTIAL;
		else {
			(void) sprintf(temp, "%s/%s/!R-Lock!", pkgdir, pkginst);
			if (access(temp, 0) == 0)
				info->status = PI_PARTIAL;
		}
	}
	info->pkginst = strdup(pkginst);
	return (0);
}
Esempio n. 5
0
/*
 * This function confirms the presence of pkgmap and pkginfo and verifies
 * that the mandatory parameters are available in the environment.
 */
int
pkgenv(char *pkginst, char *p_pkginfo, char *p_pkgmap)
{
	FILE	*fp;
	char 	*value,
		path[PATH_MAX],
		param[MAX_PKG_PARAM_LENGTH];
	int	errflg;

	errflg = 0;
	if (access(p_pkgmap, 0)) {
		progerr(gettext(ERR_PKGMAP), p_pkgmap);
		return (1);
	}
	if ((fp = fopen(p_pkginfo, "r")) == NULL) {
		progerr(gettext(ERR_PKGINFO), p_pkginfo);
		return (1);
	}
	param[0] = '\0';
	while (value = fpkgparam(fp, param)) {
		if (strcmp("PATH", param))
			putparam(param, value);
		free(value);
		param[0] = '\0';
	}
	(void) fclose(fp);
	/*
	 * verify that required parameters are now present in
	 * the environment
	 */
	if ((pkgabrv = getenv("PKG")) == NULL) {
		progerr(gettext(ERR_NOPARAM), "PKG", path);
		errflg++;
	}
	if (pkgnmchk(pkgabrv, NULL, 0) || strchr(pkgabrv, '.')) {
		progerr(gettext(ERR_PKGBAD), pkgabrv);
		errflg++;
	}
	(void) snprintf(pkgwild, sizeof (pkgwild), "%s.*", pkgabrv);
	if ((pkgname = getenv("NAME")) == NULL) {
		progerr(gettext(ERR_NOPARAM), "NAME", path);
		errflg++;
	}
	if ((pkgarch = getenv("ARCH")) == NULL) {
		progerr(gettext(ERR_NOPARAM), "ARCH", path);
		errflg++;
	}
	if ((pkgvers = getenv("VERSION")) == NULL) {
		progerr(gettext(ERR_NOPARAM), "VERSION", path);
		errflg++;
	}
	if (getenv("CATEGORY") == NULL) {
		progerr(gettext(ERR_NOPARAM), "CATEGORY", path);
		errflg++;
	}
	/*
	 * verify consistency between PKG parameter and pkginst that
	 * was determined from the directory structure
	 */
	(void) snprintf(param, sizeof (param), "%s.*", pkgabrv);
	if (pkgnmchk(pkginst, param, 0)) {
		progerr(gettext(ERR_PKGMTCH), pkgabrv, pkginst);
		errflg++;
	}
	return (errflg);
}
Esempio n. 6
0
int
main(int argc, char *argv[])
{
	FILE		*fp;
	char		*abi_comp_ptr;
	char		*abi_sym_ptr;
	char		*p;
	char		*prog_full_name = NULL;
	char		*pt;
	char		*value;
	char		*vfstab_file = NULL;
	char		*zoneName = (char *)NULL;
	char		cmdbin[PATH_MAX];
	char		param[MAX_PKG_PARAM_LENGTH];
	char		path[PATH_MAX];
	char		script[PATH_MAX];
	int		c;
	int		err;
	int		fd;
	int		i;
	int		map_client = 1;
	int		n;
	int		nodelete = 0; 	/* do not delete file or run scripts */
	int		pkgrmremote = 0;	/* dont remove remote objects */
	struct sigaction	nact;
	struct sigaction	oact;
	PKGserver	pkgserver = NULL;
	VFP_T		*tmpfp;

	/* reset contents of all default paths */

	(void) memset(cmdbin, '\0', sizeof (cmdbin));

	/* initialize locale environment */

	(void) setlocale(LC_ALL, "");
	(void) textdomain(TEXT_DOMAIN);

	/* initialize program name */

	prog_full_name = argv[0];
	(void) set_prog_name(argv[0]);

	/* tell spmi zones interface how to access package output functions */

	z_set_output_functions(echo, echoDebug, progerr);

	/* exit if not root */

	if (getuid()) {
		progerr(ERR_NOT_ROOT, get_prog_name());
		exit(1);
		/* NOTREACHED */
	}

	/* Read PKG_INSTALL_ROOT from the environment, if it's there. */

	if (!set_inst_root(getenv("PKG_INSTALL_ROOT"))) {
		progerr(ERR_ROOT_SET);
		exit(1);
	}

	pkgserversetmode(DEFAULTMODE);

	/* parse command line options */

	while ((c = getopt(argc, argv, "?Aa:b:FMN:nO:oR:V:vy")) != EOF) {
		switch (c) {
		/*
		 * Same as pkgrm: Allow admin to remove package objects from
		 * a shared area from a reference client.
		 */
		case 'A':
			pkgrmremote++;
			break;

		/*
		 * Same as pkgrm: Use the installation
		 * administration file, admin, in place of the
		 * default admin file. pkgrm first looks in the
		 * current working directory for the administration
		 * file.  If the specified administration file is not
		 * in the current working directory, pkgrm looks in
		 * the /var/sadm/install/admin directory for the
		 * administration file.
		 */
		case 'a':
			admnfile = flex_device(optarg, 0);
			break;

		/*
		 * Same as pkgrm: location where package executables
		 * can be found - default is /usr/sadm/install/bin.
		 */
		case 'b':
			if (!path_valid(optarg)) {
				progerr(ERR_PATH, optarg);
				exit(1);
			}
			if (isdir(optarg) != 0) {
				char *p = strerror(errno);
				progerr(ERR_CANNOT_USE_DIR, optarg, p);
				exit(1);
			}
			(void) strlcpy(cmdbin, optarg, sizeof (cmdbin));
			break;

		/*
		 * Same as pkgrm: suppresses the removal of any
		 * files and any class action scripts, and suppresses
		 * the running of any class action scripts.  The
		 * package files remain but the package looks like it
		 * is not installed. This is mainly for use by the
		 * upgrade process.
		 */
		case 'F':
			nodelete++;
			break;

		/*
		 * Same as pkgrm: Instruct pkgrm not to use the
		 * $root_path/etc/vfstab file for determining the
		 * client's mount points. This option assumes the
		 * mount points are correct on the server and it
		 * behaves consistently with Solaris 2.5 and earlier
		 * releases.
		 */
		case 'M':
			map_client = 0;
			break;

		/*
		 * Different from pkgrm: specify program name to use
		 * for messages.
		 */
		case 'N':
			(void) set_prog_name(optarg);
			break;

		/*
		 * Same as pkgrm: package removal occurs in
		 * non-interactive mode.  Suppress output of the list of
		 * removed files. The default mode is interactive.
		 */
		case 'n':
			nointeract++;
			(void) echoSetFlag(B_FALSE);
			break;

		/*
		 * Almost same as pkgrm: the -O option allows the behavior
		 * of the package tools to be modified. Recognized options:
		 * -> debug
		 * ---> enable debugging output
		 * -> preremovecheck
		 * ---> perform a "pre removal" check of the specified
		 * ---> package - suppress all regular output and cause a
		 * ---> series of one or more "name=value" pair format lines
		 * ---> to be output that describes the "removability" of
		 * ---> the specified package
		 * -> enable-hollow-package-support
		 * --> Enable hollow package support. When specified, for any
		 * --> package that has SUNW_PKG_HOLLOW=true:
		 * --> Do not calculate and verify package size against target
		 * --> Do not run any package procedure or class action scripts
		 * --> Do not create or remove any target directories
		 * --> Do not perform any script locking
		 * --> Do not install or uninstall any components of any package
		 * --> Do not output any status or database update messages
		 */
		case 'O':
			for (p = strtok(optarg, ","); p != (char *)NULL;
			    p = strtok(NULL, ",")) {

				/* process debug option */

				if (strcmp(p, "debug") == 0) {
					/* set debug flag/enable debug output */
					debugFlag = B_TRUE;
					(void) echoDebugSetFlag(debugFlag);

					/* debug info on arguments to pkgadd */
					for (n = 0; n < argc && argv[n]; n++) {
						echoDebug(DBG_ARG, n, argv[n]);
					}

					continue;
				}

				/* process enable-hollow-package-support opt */

				if (strcmp(p,
				    "enable-hollow-package-support") == 0) {
					set_depend_pkginfo_DB(B_TRUE);
					continue;
				}

				/* process preremovecheck option */

				if (strcmp(p, "preremovecheck") == 0) {
					preremoveCheck = B_TRUE;
					nointeract++;	/* -n */
					nodelete++;	/* -F */
					quitSetSilentExit(B_TRUE);
					continue;
				}

				/* process addzonename option */

				if (strcmp(p, "addzonename") == 0) {
					zoneName = z_get_zonename();
					quitSetZoneName(zoneName);
					continue;
				}

				/* process parent-zone-name option */

				if (strncmp(p, PARENTZONENAME,
				    PARENTZONENAME_LEN) == 0) {
					parentZoneName = p+PARENTZONENAME_LEN;
					continue;
				}

				/* process parent-zone-type option */

				if (strncmp(p, PARENTZONETYPE,
				    PARENTZONETYPE_LEN) == 0) {
					parentZoneType = p+PARENTZONETYPE_LEN;
					continue;
				}

				if (strncmp(p, PKGSERV_MODE,
				    PKGSERV_MODE_LEN) == 0) {
					pkgserversetmode(pkgparsemode(p +
					    PKGSERV_MODE_LEN));
					continue;
				}
				/* option not recognized - issue warning */

				progerr(ERR_INVALID_O_OPTION, p);
				continue;
			}
			break;

		/*
		 * Different from pkgrm: This is an old non-ABI package
		 */

		case 'o':
			script_in = PROC_XSTDIN;
			break;

		/*
		 * Same as pkgrm: defines the full path name of a
		 * directory to use as the root_path.  All files,
		 * including package system information files, are
		 * relocated to a directory tree starting in the
		 * specified root_path.
		 */
		case 'R':
			if (!set_inst_root(optarg)) {
				progerr(ERR_ROOT_CMD);
				exit(1);
			}
			break;

		/*
		 * Same as pkgrm: allow admin to establish the client
		 * filesystem using a vfstab-like file of stable format.
		 */
		case 'V':
			vfstab_file = flex_device(optarg, 2);
			map_client = 1;
			break;

		/*
		 * Same as pkgrm: trace all of the scripts that
		 * get executed by pkgrm, located in the
		 * pkginst/install directory. This option is used for
		 * debugging the procedural and non-procedural
		 * scripts.
		 */
		case 'v':
			pkgverbose++;
			break;

		/*
		 * Different from pkgrm: process this package using
		 * old non-ABI symlinks
		 */
		case 'y':
			set_nonABI_symlinks();
			break;

		default:
			usage();
			/*NOTREACHED*/
			/*
			 * Although usage() calls a noreturn function,
			 * needed to add return (1);  so that main() would
			 * pass compilation checks. The statement below
			 * should never be executed.
			 */
			return (1);
		}
	}

	/*
	 * ********************************************************************
	 * validate command line options
	 * ********************************************************************
	 */

	(void) echoDebugSetFlag(debugFlag);
	(void) log_set_verbose(debugFlag);

	if (z_running_in_global_zone()) {
		echoDebug(DBG_ENTRY_IN_GZ, prog_full_name);
	} else {
		echoDebug(DBG_ENTRY_IN_LZ, prog_full_name, getzoneid(),
		    z_get_zonename());
	}

	/* establish cmdbin path */

	if (cmdbin[0] == '\0') {
		(void) strlcpy(cmdbin, PKGBIN, sizeof (cmdbin));
	}

	/* Read the mount table */

	if (get_mntinfo(map_client, vfstab_file)) {
		quit(99);
	}

	/*
	 * This function defines the standard /var/... directories used later
	 * to construct the paths to the various databases.
	 */

	set_PKGpaths(get_inst_root());

	/*
	 * If this is being removed from a client whose /var filesystem is
	 * mounted in some odd way, remap the administrative paths to the
	 * real filesystem. This could be avoided by simply mounting up the
	 * client now; but we aren't yet to the point in the process where
	 * modification of the filesystem is permitted.
	 */
	if (is_an_inst_root()) {
		int fsys_value;

		fsys_value = fsys(get_PKGLOC());
		if (use_srvr_map_n(fsys_value))
			set_PKGLOC(server_map(get_PKGLOC(), fsys_value));

		fsys_value = fsys(get_PKGADM());
		if (use_srvr_map_n(fsys_value))
			set_PKGADM(server_map(get_PKGADM(), fsys_value));
	} else {
		pkgrmremote = 0;	/* Makes no sense on local host. */
	}

	/*
	 * hook SIGINT and SIGHUP interrupts into quit.c's trap handler
	 */

	/* hold SIGINT/SIGHUP interrupts */

	(void) sighold(SIGHUP);
	(void) sighold(SIGINT);

	/* connect quit.c:trap() to SIGINT */

	nact.sa_handler = quitGetTrapHandler();
	nact.sa_flags = SA_RESTART;
	(void) sigemptyset(&nact.sa_mask);

	(void) sigaction(SIGINT, &nact, &oact);

	/* connect quit.c:trap() to SIGHUP */

	nact.sa_handler = quitGetTrapHandler();
	nact.sa_flags = SA_RESTART;
	(void) sigemptyset(&nact.sa_mask);

	(void) sigaction(SIGHUP, &nact, &oact);

	/* release hold on signals */

	(void) sigrelse(SIGHUP);
	(void) sigrelse(SIGINT);

	pkginst = argv[optind++];
	if (optind != argc) {
		usage();
	}

	/* validate package software database (contents) file */

	if (vcfile() == 0) {
		quit(99);
	}

	/*
	 * Acquire the package lock - currently at "remove initialization"
	 */

	if (!lockinst(get_prog_name(), pkginst, "remove-initial")) {
		quit(99);
	}

	/* establish temporary directory to use */

	tmpdir = getenv("TMPDIR");
	if (tmpdir == NULL) {
		tmpdir = P_tmpdir;
	}

	echoDebug(DBG_PKGREMOVE_TMPDIR, tmpdir);

	/*
	 * Initialize installation admin parameters by reading
	 * the adminfile.
	 */

	echoDebug(DBG_PKGREMOVE_ADMINFILE, admnfile ? admnfile : "");
	setadminFile(admnfile);

	/*
	 * about to perform first operation that could be modified by the
	 * preremove check option - if preremove check is selected (that is,
	 * only gathering dependencies), then output a debug message to
	 * indicate that the check is beginning. Also turn echo() output
	 * off and set various other flags.
	 */

	if (preremoveCheck == B_TRUE) {
		(void) echoSetFlag(B_FALSE);
		echoDebug(DBG_PKGREMOVE_PRERMCHK, pkginst ? pkginst : "",
		    zoneName ? zoneName : "global");
		rcksetPreremoveCheck(B_TRUE);
		rcksetZoneName(zoneName);
	}

	(void) snprintf(pkgloc, sizeof (pkgloc), "%s/%s", get_PKGLOC(),
	    pkginst);
	(void) snprintf(pkgbin, sizeof (pkgbin), "%s/install", pkgloc);
	(void) snprintf(rlockfile, sizeof (rlockfile), "%s/!R-Lock!", pkgloc);

	if (chdir(pkgbin)) {
		progerr(ERR_CHDIR, pkgbin);
		quit(99);
	}

	echo(MSG_PREREMOVE_REMINST, pkginst);

	/*
	 * if a lock file is present, then a previous attempt to remove this
	 * package may have been unsuccessful.
	 */

	if (access(rlockfile, F_OK) == 0) {
		echo(ERR_UNSUCC);
		echoDebug(DBG_PKGINSTALL_HAS_LOCKFILE, pkginst, rlockfile,
		    zoneName ? zoneName : "global");
	}

	/*
	 * Process all parameters from the pkginfo file
	 * and place them in the execution environment
	 */

	/* Add DB retreival of the pkginfo parameters here */
	(void) snprintf(path, sizeof (path), "%s/pkginfo", pkgloc);
	if ((fp = fopen(path, "r")) == NULL) {
		progerr(ERR_PKGINFO, path);
		quit(99);
	}

	/* Mount up the client if necessary. */
	if (map_client && !mount_client()) {
		logerr(MSG_MANMOUNT);
	}

	/* Get mount point of client */
	client_mntdir = getenv("CLIENT_MNTDIR");

	getuserlocale();

	/*
	 * current environment has been read; clear environment out
	 * so putparam() can be used to populate the new environment
	 * to be passed to any executables/scripts.
	 */

	environ = NULL;

	if (nonABI_symlinks()) {
		putparam("PKG_NONABI_SYMLINKS", "TRUE");
	}

	/*
	 * read the pkginfo file and fix any PKGSAV path - the correct
	 * install_root will be prepended to the existing path.
	 */

	param[0] = '\0';
	while (value = fpkgparam(fp, param)) {
		int validx = 0;
		char *newvalue;

		/* strip out any setting of PATH */

		if (strcmp(param, "PATH") == 0) {
			free(value);
			param[0] = '\0';
			continue;
		}

		/* if not PKGSAV then write out unchanged */

		if (strcmp(param, "PKGSAV") != 0) {
			putparam(param, value);
			free(value);
			param[0] = '\0';
			continue;
		}

		/*
		 * PKGSAV parameter found - interpret the directory:
		 * If in host:path format or marked with the leading "//",
		 * then there is no client-relative translation - take it
		 * literally later rather than use fixpath().
		 */

		if (strstr(value, ":/")) {
			/* no modification needed */
			validx = 0;
		} else if (strstr(value, "//") == value) {
			validx = 1;
		} else if (is_an_inst_root()) {
			/* This PKGSAV needs to be made client-relative. */
			newvalue = fixpath(value);
			free(value);
			value = newvalue;
		}
		putparam(param, value+validx);
		free(value);
		param[0] = '\0';
	}

	(void) fclose(fp);

	/* write parent condition information to environment */

	putConditionInfo(parentZoneName, parentZoneType);

	putuserlocale();

	/*
	 * Now do all the various setups based on ABI compliance
	 */

	/* Read the environment provided by the pkginfo file */
	abi_comp_ptr = getenv("NONABI_SCRIPTS");

	/* if not ABI compliant set global flag */
	abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS");
	if (abi_sym_ptr && strncasecmp(abi_sym_ptr, "TRUE", 4) == 0) {
		set_nonABI_symlinks();
	}

	/*
	 * If pkginfo says it's not compliant then set non_abi_scripts.
	 */
	if (abi_comp_ptr && strncmp(abi_comp_ptr, "TRUE", 4) == 0) {
		script_in = PROC_XSTDIN;
	}

	/*
	 * Since this is a removal, we can tell whether it's absolute or
	 * not from the resident pkginfo file read above.
	 */
	if ((err = set_basedirs((getenv("BASEDIR") != NULL), adm.basedir,
	    pkginst, nointeract)) != 0) {
		quit(err);
	}

	/*
	 * See if were are removing a package that only wants to update
	 * the database or only remove files associated with CAS's. We
	 * only check the PKG_HOLLOW_VARIABLE variable if told to do so by
	 * the caller.
	 */

	if (is_depend_pkginfo_DB()) {
		pt = getenv(PKG_HOLLOW_VARIABLE);

		if ((pt != NULL) && (strncasecmp(pt, "true", 4) == 0)) {
			echoDebug(DBG_PKGREMOVE_HOLLOW_ENABLED);

			/*
			 * this is a hollow package and hollow package support
			 * is enabled -- override admin settings to suppress
			 * checks that do not make sense since no scripts will
			 * be executed and no files will be removed.
			 */

			setadminSetting("conflict", "nocheck");
			setadminSetting("setuid", "nocheck");
			setadminSetting("action", "nocheck");
			setadminSetting("partial", "nocheck");
			setadminSetting("space", "nocheck");
			setadminSetting("authentication", "nocheck");
		} else {
			echoDebug(DBG_PKGREMOVE_HOLLOW_DISABLED);
			set_depend_pkginfo_DB(B_FALSE);
		}
	}

	put_path_params();

	/* If client mount point, add it to pkgremove environment */

	if (client_mntdir != NULL) {
		putparam("CLIENT_MNTDIR", client_mntdir);
	}

	/* Establish the class list and the class attributes. */

	if ((value = getenv("CLASSES")) != NULL) {
		cl_sets(qstrdup(value));
	} else {
		progerr(ERR_CLASSES, path);
		quit(99);
	}

	/* establish path and tmpdir */

	if (cmdbin[0] == '\0') {
		(void) strlcpy(cmdbin, PKGBIN, sizeof (cmdbin));
	}

	(void) snprintf(path, sizeof (path), "%s:%s", DEFPATH, cmdbin);
	putparam("PATH", path);

	putparam("TMPDIR", tmpdir);

	/*
	 * Check ulimit requirement (provided in pkginfo). The purpose of
	 * this limit is to terminate pathological file growth resulting from
	 * file edits in scripts. It does not apply to files in the pkgmap
	 * and it does not apply to any database files manipulated by the
	 * installation service.
	 */
	if (value = getenv("ULIMIT")) {
		if (assign_ulimit(value) == -1) {
			progerr(ERR_BADULIMIT, value);
			warnflag++;
		}
		putparam("PKG_ULIMIT", "TRUE");
	}

	/*
	 * If only gathering dependencies, check and output status of all
	 * remaining dependencies and exit.
	 */

	if (preremoveCheck == B_TRUE) {
		/*
		 * make sure current runlevel is appropriate
		 */

		(void) fprintf(stdout, "rckrunlevel=%d\n", rckrunlevel());

		/*
		 * determine if any packaging scripts provided with
		 * this package will execute as a priviledged user
		 */

		(void) fprintf(stdout, "rckpriv=%d\n", rckpriv());

		/*
		 * verify package dependencies
		 */

		(void) fprintf(stdout, "rckdepend=%d\n", rckdepend());

		/*
		 * ****** preremove check done - exit ******
		 */

		echoDebug(DBG_PKGREMOVE_PRERMCHK_OK);
		quit(0);
		/*NOTREACHED*/
	}

	/*
	 * Not gathering dependencies only, proceed to check dependencies
	 * and continue with the package removal operation.
	 */

	/*
	 * make sure current runlevel is appropriate
	 */

	n = rckrunlevel();

	if (n != 0) {
		quit(n);
		/* NOTREACHED */
	}

	/*
	 * determine if any packaging scripts provided with
	 * this package will execute as a priviledged user
	 */

	n = rckpriv();

	if (n != 0) {
		quit(n);
		/* NOTREACHED */
	}

	/*
	 * verify package dependencies
	 */
	n = rckdepend();

	if (n != 0) {
		quit(n);
		/* NOTREACHED */
	}

	/*
	 * *********************************************************************
	 * the actual removal of the package begins here
	 * *********************************************************************
	 */

	/*
	 * create lockfile to indicate start of removal
	 */
	started++;
	if ((fd = open(rlockfile, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) {
		progerr(ERR_LOCKFILE, rlockfile);
		quit(99);
	} else {
		(void) close(fd);
	}

	if (zoneName == (char *)NULL) {
		echo(MSG_PKGREMOVE_PROCPKG_GZ);
		echoDebug(DBG_PKGREMOVE_PROCPKG_GZ, pkginst, rlockfile);
	} else {
		echo(MSG_PKGREMOVE_PROCPKG_LZ, zoneName);
		echoDebug(DBG_PKGREMOVE_PROCPKG_LZ, pkginst, rlockfile,
		    zoneName);
	}
	if (delmap(0, pkginst, &pkgserver, &tmpfp) != 0) {
		progerr(ERR_DB_QUERY, pkginst);
		quit(99);
	}

	/*
	 * Run a preremove script if one is provided by the package.
	 * Don't execute preremove script if only updating the DB.
	 * Don't execute preremove script if files are not being deleted.
	 */

	/* update the lock - at the preremove script */
	lockupd("preremove");

	/* execute preremove script if one is provided */
	(void) snprintf(script, sizeof (script), "%s/preremove", pkgbin);
	if (access(script, F_OK) != 0) {
		/* no script present */
		echoDebug(DBG_PKGREMOVE_POC_NONE, pkginst,
		    zoneName ? zoneName : "global");
	} else if (nodelete) {
		/* not deleting files: skip preremove script */
		echoDebug(DBG_PKGREMOVE_POC_NODEL, pkginst, script,
		    zoneName ? zoneName : "global");
	} else if (is_depend_pkginfo_DB()) {
		/* updating db only: skip preremove script */
		echoDebug(DBG_PKGREMOVE_POC_DBUPD, pkginst, script,
		    zoneName ? zoneName : "global");
	} else {
		/* script present and ok to run: run the script */
		set_ulimit("preremove", ERR_PREREMOVE);
		if (zoneName == (char *)NULL) {
			echo(MSG_PKGREMOVE_EXEPOC_GZ);
			echoDebug(DBG_PKGREMOVE_EXEPOC_GZ, pkginst, script);
		} else {
			echo(MSG_PKGREMOVE_EXEPOC_LZ, zoneName);
			echoDebug(DBG_PKGREMOVE_EXEPOC_LZ, pkginst, script,
			    zoneName);
		}
		putparam("PKG_PROC_SCRIPT", "preremove");
		if (pkgverbose) {
			ckreturn(pkgexecl(script_in, PROC_STDOUT,
			    PROC_USER, PROC_GRP, SHELL, "-x",
			    script, NULL), ERR_PREREMOVE);
		} else {
			ckreturn(pkgexecl(script_in, PROC_STDOUT,
			    PROC_USER, PROC_GRP, SHELL, script,
			    NULL), ERR_PREREMOVE);
		}
		clr_ulimit();
	}

	/* update the lock - doing removal */

	lockupd("remove");

	/*
	 * Remove all components belonging to this package.
	 * Don't remove components if only updating the DB.
	 * Don't remove components if files are not being deleted.
	 */

	if (nodelete) {
		echoDebug(DBG_PKGREMOVE_REM_NODEL, pkginst,
		    zoneName ? zoneName : "global");
	} else if (is_depend_pkginfo_DB()) {
		echoDebug(DBG_PKGREMOVE_REM_DBUPD, pkginst,
		    zoneName ? zoneName : "global");
	} else {
		echoDebug(DBG_PKGREMOVE_REM, pkginst,
		    zoneName ? zoneName : "global");
		/*
		 * remove package one class at a time
		 */

		/* reverse order of classes */
		for (i = cl_getn() - 1; i >= 0; i--) {
			rmclass(cl_nam(i), pkgrmremote, zoneName);
		}

		rmclass(NULL, pkgrmremote, zoneName);
	}

	z_destroyMountTable();

	/*
	 * Execute postremove script, if any
	 * Don't execute postremove script if only updating the DB.
	 * Don't execute postremove script if files are not being deleted.
	 */

	/* update the lock - at the postremove script */
	lockupd("postremove");

	/* execute postremove script if one is provided */
	(void) snprintf(script, sizeof (script), "%s/postremove", pkgbin);
	if (access(script, F_OK) != 0) {
		/* no script present */
		echoDebug(DBG_PKGREMOVE_PIC_NONE, pkginst,
		    zoneName ? zoneName : "global");
	} else if (nodelete) {
		/* not deleting files: skip postremove script */
		echoDebug(DBG_PKGREMOVE_PIC_NODEL, pkginst, script,
		    zoneName ? zoneName : "global");
	} else if (is_depend_pkginfo_DB()) {
		/* updating db only: skip postremove script */
		echoDebug(DBG_PKGREMOVE_PIC_DBUPD, pkginst, script,
		    zoneName ? zoneName : "global");
	} else {
		/* script present and ok to run: run the script */
		set_ulimit("postremove", ERR_POSTREMOVE);
		if (zoneName == (char *)NULL) {
			echo(MSG_PKGREMOVE_EXEPIC_GZ);
			echoDebug(DBG_PKGREMOVE_EXEPIC_GZ, pkginst, script);
		} else {
			echo(MSG_PKGREMOVE_EXEPIC_LZ, zoneName);
			echoDebug(DBG_PKGREMOVE_EXEPIC_LZ, pkginst, script,
			    zoneName);
		}
		putparam("PKG_PROC_SCRIPT", "postremove");
		putparam("TMPDIR", tmpdir);
		if (pkgverbose) {
			ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER,
			    PROC_GRP, SHELL, "-x", script, NULL),
			    ERR_POSTREMOVE);
		} else {
			ckreturn(pkgexecl(script_in, PROC_STDOUT, PROC_USER,
			    PROC_GRP, SHELL, script, NULL),
			    ERR_POSTREMOVE);
		}
		clr_ulimit();
	}

	if (zoneName == (char *)NULL) {
		echo(MSG_PKGREMOVE_UPDINF_GZ);
	} else {
		echo(MSG_PKGREMOVE_UPDINF_LZ, zoneName);
	}

	if (delmap(1, pkginst, &pkgserver, &tmpfp) != 0) {
		progerr(ERR_DB_QUERY, pkginst);
		quit(99);
	}

	if (!warnflag && !failflag) {
		(void) chdir("/");
		if (rrmdir(pkgloc))
			warnflag++;
	}

	if ((z_running_in_global_zone() == B_TRUE) &&
	    (pkgIsPkgInGzOnly(get_inst_root(), pkginst) == B_TRUE)) {
		boolean_t	b;

		b = pkgRemovePackageFromGzonlyList(get_inst_root(), pkginst);
		if (b == B_FALSE) {
			progerr(ERR_PKGREMOVE_GZONLY_REMOVE, pkginst);
			ckreturn(1, NULL);
		}
	}

	/* release the generic package lock */

	(void) unlockinst();

	pkgcloseserver(pkgserver);

	quit(0);
	/* LINTED: no return */
}
Esempio n. 7
0
int
checkmap(int maptyp, int uninst, char *mapfile, char *envfile,
		char *pkginst, char *path, int pathtype)
{
	FILE		*fp;
	char		*cl = NULL;
	char		*value;
	char		param[MAX_PKG_PARAM_LENGTH];
	int		count;
	int		errflg;
	int		n;
	int		selected;
	struct pinfo	*pinfo;
	VFP_T		*vfp = (VFP_T *)NULL;
	PKGserver	server;

	if (envfile != NULL) {
		if ((fp = fopen(envfile, "r")) == NULL) {
			progerr(gettext(ERR_ENVFILE), envfile);
			return (-1);
		}
		param[0] = '\0';
		while (value = fpkgparam(fp, param)) {
			if (strcmp("PATH", param) != 0) {
				/*
				 * If checking an uninstalled package, we
				 * only want two parameters. If we took all
				 * of them, including path definitions, we
				 * wouldn't be looking in the right places in
				 * the reloc and root directories.
				 */
				if (uninst) {
					if ((strncmp("PKG_SRC_NOVERIFY", param,
					    16) == 0) && value) {
						logerr(gettext(MSG_ARCHIVE));
						putparam(param, value);
					}
					if ((strncmp("CLASSES", param,
					    7) == 0) && value)
						putparam(param, value);
				} else
					putparam(param, value);
			}

			free(value);

			param[0] = '\0';
		}
		(void) fclose(fp);
		basedir = getenv("BASEDIR");
	}

	/*
	 * If we are using a contents file for the map, this locks the
	 * contents file in order to freeze the database and assure it
	 * remains synchronized with the file system against which it is
	 * being compared. There is no practical way to lock another pkgmap
	 * on some unknown medium so we don't bother.
	 */
	if (maptyp) {	/* If this is the contents file */
		if (!socfile(&server, B_FALSE) ||
		    pkgopenfilter(server, pkgcnt == 1 ? pkginst : NULL) != 0) {
			progerr(gettext(ERR_PKGMAP), "contents");
			return (-1);
		}
	} else {
		if (vfpOpen(&vfp, mapfile, "r", VFP_NONE) != 0) {
			progerr(gettext(ERR_PKGMAP), mapfile);
			return (-1);
		}
	}

	if ((cl = getenv("CLASSES")) != NULL)
		cl_sets(qstrdup(cl));

	errflg = count = 0;

	do {
		if ((n = NXTENTRY(&entry, vfp, server)) == 0) {
			break;
		}
		/*
		 * Search for partial paths in the ext DB.
		 */
		if (pathtype) {
			/* LINTED warning: statement has no consequent: if */
			if (is_partial_path_in_DB(entry.path, path)) {
				/* Check this entry */
				;
			} else if (entry.ftype == 's' || entry.ftype == 'l') {
				if (is_partial_path_in_DB(
				/* LINTED warning: statement has no consequen */
					entry.ainfo.local, path)) {
					/* Check this entry */
					;
				} else {
					continue;
				}
			} else {
				/* Skip to next DB entry */
				continue;
			}
		}

		if (n < 0) {
			char	*errstr = getErrstr();
			logerr(gettext("ERROR: garbled entry"));
			logerr(gettext("pathname: %s"),
			    (entry.path && *entry.path) ? entry.path :
			    "Unknown");
			logerr(gettext("problem: %s"),
			    (errstr && *errstr) ? errstr : "Unknown");
			exit(99);
		}
		if (n == 0)
			break; /* done with file */

		/*
		 * The class list may not be complete for good reason, so
		 * there's no complaining if this returns an index of -1.
		 */
		if (cl != NULL)
			entry.pkg_class_idx = cl_idx(entry.pkg_class);

		if (maptyp && pkginst != NULL) {
			/*
			 * check to see if the entry we just read
			 * is associated with one of the packages
			 * we have listed on the command line
			 */
			selected = 0;
			pinfo = entry.pinfo;
			while (pinfo) {
				if (selpkg(pinfo->pkg)) {
					selected++;
					break;
				}
				pinfo = pinfo->next;
			}
			if (!selected)
				continue; /* not selected */
		}

		/*
		 * Check to see if the pathname associated with the entry
		 * we just read is associated with the list of paths we
		 * supplied on the command line
		 */
		if (!selpath(entry.path, pathtype))
			continue; /* not selected */

		/*
		 * Determine if this is a package object wanting
		 * verification. Metafiles are always checked, otherwise, we
		 * rely on the class to discriminate.
		 */
		if (entry.ftype != 'i')
			/* If there's no class list... */
			if (cl != NULL)
				/*
				 * ... or this entry isn't in that class list
				 * or it's in a private format, then don't
				 * check it.
				 */
				if (entry.pkg_class_idx == -1 ||
				    cl_svfy(entry.pkg_class_idx) == NOVERIFY)
					continue;

		count++;
		if (ckentry((envfile ? 1 : 0), maptyp, &entry, vfp, server))
			errflg++;
	} while (n != 0);

	if (maptyp)
		relslock();
	else
		(void) vfpClose(&vfp);

	if (environ) {
		/* free up environment resources */
		for (n = 0; environ[n]; n++)
			free(environ[n]);
		free(environ);
		environ = NULL;
	}

	if (maptyp) {
		/*
		 * make sure each listed package was associated with
		 * an entry from the prototype or pkgmap
		 */
		(void) selpkg(NULL);
	}
	if (!qflag && !lflag && !Lflag) {
		/*
		 * make sure each listed pathname was associated with an entry
		 * from the prototype or pkgmap
		 */
		(void) selpath(NULL, pathtype);
	}
	return (errflg);
}
Esempio n. 8
0
/*
 * valid_zone_attr:	Validates the zone attributes specified in
 *			pkginfo file for this package. The package
 *			can not be created with certain combinations
 *			of the attributes.
 */
static boolean_t
valid_zone_attr(struct cfent **eptlist)
{
	FILE		*pkginfoFP;
	boolean_t	all_zones;	/* pkg is "all zones" only */
	boolean_t	is_hollow;	/* pkg is "hollow" */
	boolean_t	this_zone;	/* pkg is "this zone" only */
	char 		pkginfoPath[PATH_MAX];	/* pkginfo file path */
	char		*pkgInst;
	int i;

	/* Path to pkginfo file within the package to be installed */

	this_zone = B_FALSE;
	for (i = 0; eptlist[i]; i++) {
		if (eptlist[i]->ftype != 'i')
			continue;
		if (strcmp(eptlist[i]->path, "pkginfo") == 0)
			(void) strcpy(pkginfoPath, eptlist[i]->ainfo.local);

		/*
		 * Check to see if this package has a request script. If this
		 * package does have a request script, then mark the package
		 * for installation in this zone only. Any package with a
		 * request script cannot be installed outside of the zone the
		 * pkgadd command is being run in, nor can such a package be
		 * installed as part of a new zone install. A new zone install
		 * must be non-interactive, which is required by all packages
		 * integrated into the Solaris WOS.
		 * If request file is set in prototype, then this_zone is TRUE.
		 */
		if (strcmp(eptlist[i]->path, "request") == 0)
			this_zone = B_TRUE;
	}

	/* Gather information from the pkginfo file */

	pkginfoFP = fopen(pkginfoPath, "r");

	if (pkginfoFP == NULL) {
		progerr(ERR_NO_PKG_INFOFILE, pkginfoPath, strerror(errno));
		return (B_FALSE);
	}

	if ((pkgInst = fpkgparam(pkginfoFP, "PKG")) == NULL) {
		progerr(gettext(ERR_NOPARAM), "PKG", pkginfoPath);
		return (B_FALSE);
	}


	/* Determine "HOLLOW" setting for this package */
	is_hollow = pkginfoParamTruth(pkginfoFP, PKG_HOLLOW_VARIABLE,
			"true", B_FALSE);

	/* Determine "ALLZONES" setting for this package */
	all_zones = pkginfoParamTruth(pkginfoFP, PKG_ALLZONES_VARIABLE,
			"true", B_FALSE);

	/* Determine "THISZONE" setting for this package, if no request file */
	if (!this_zone)
		this_zone = pkginfoParamTruth(pkginfoFP, PKG_THISZONE_VARIABLE,
			"true", B_FALSE);

	/* Close pkginfo file */
	(void) fclose(pkginfoFP);

	/*
	 * Validate zone attributes based on information gathered,
	 * and validate the three SUNW_PKG_ options:
	 *
	 * -----------------------------|---------------|
	 * <ALLZONES><HOLLOW><THISZONE> |  If Allowed   |
	 * ----1------------------------|---------------|
	 *		F F F		|	OK	|
	 *		F F T		|	OK	|
	 *		F T *		|	NO	|
	 * ----2------------------------|---------------|
	 *		T F F		|	OK	|
	 *		T T F		|	OK	|
	 *		T * T		|	NO	|
	 * -----------------------------|---------------|
	 */

	/* pkg "all zones" && "this zone" (#2) */

	if (all_zones && this_zone) {
		progerr(ERR_ALLZONES_AND_THISZONE, pkgInst,
		    PKG_ALLZONES_VARIABLE, PKG_THISZONE_VARIABLE);
		return (B_FALSE);
	}

	/* pkg "!all zones" && "hollow" (#1) */

	if ((!all_zones) && is_hollow) {
		progerr(ERR_NO_ALLZONES_AND_HOLLOW, pkgInst,
		    PKG_ALLZONES_VARIABLE, PKG_HOLLOW_VARIABLE);
		return (B_FALSE);
	}

	return (B_TRUE);
}
Esempio n. 9
0
int
main(int argc, char *argv[])
{
	struct utsname utsbuf;
	struct statvfs64 svfsb;
	struct cfent	**eptlist;
	FILE	*fp;
	VFP_T	*vfp;
	int	i, c, n, eptnum, found,
		part, nparts, npkgs, objects;
	char	buf[MAX_PKG_PARAM_LENGTH];
	char	temp[MAX_PKG_PARAM_LENGTH];
	char	param[MAX_PKG_PARAM_LENGTH];
	char	*pt, *value, *pkginst, *tmpdir, *abi_sym_ptr,
		**cmdparam;
	char	*pkgname;
	char	*pkgvers;
	char	*pkgarch;
	char	*pkgcat;
	void	(*func)();
	time_t	clock;
	fsblkcnt_t	bsize = 0;
	fsblkcnt_t	frsize = 0;
	struct cl_attr	**allclass = NULL;
	struct cl_attr	**order;

	/* initialize locale environment */

	(void) setlocale(LC_ALL, "");

#if !defined(TEXT_DOMAIN)	/* Should be defined by cc -D */
#define	TEXT_DOMAIN "SYS_TEST"
#endif
	(void) textdomain(TEXT_DOMAIN);

	/* initialize program name */

	(void) set_prog_name(argv[0]);

	/* tell spmi zones interface how to access package output functions */

	z_set_output_functions(echo, echoDebug, progerr);

	func = sigset(SIGINT, trap);
	if (func != SIG_DFL)
		func = sigset(SIGINT, func);
	func = sigset(SIGHUP, trap);
	setmapmode(MAPBUILD);	/* variable binding */
	if (func != SIG_DFL)
		func = sigset(SIGHUP, func);

	environ = NULL;
	while ((c = getopt(argc, argv, "osnp:l:r:b:d:f:a:v:?")) != EOF) {
		switch (c) {
		    case 'n':
			nflag++;
			break;

		    case 's':
			sflag++;
			break;

		    case 'o':
			overwrite++;
			break;

		    case 'p':
			putparam("PSTAMP", optarg);
			break;

		    case 'l':
			llimit = atol(optarg);
			break;

		    case 'r':
			pt = strtok(optarg, " \t\n, ");
			n = 0;
			do {
				rootlist[n++] = flex_device(pt, 0);
				if (n >= NROOT) {
					progerr(gettext(ERR_NROOT), NROOT);
					quit(1);
				}
			} while (pt = strtok(NULL, " \t\n, "));
			rootlist[n] = NULL;
			break;

		    case 'b':
			basedir = optarg;
			break;

		    case 'f':
			protofile = optarg;
			break;

		    case 'd':
			device = flex_device(optarg, 1);
			break;

		    case 'a':
			putparam("ARCH", optarg);
			break;

		    case 'v':
			putparam("VERSION", optarg);
			break;

		    default:
			usage();
		}
	}

	/*
	 * Store command line variable assignments for later
	 * incorporation into the environment.
	 */
	cmdparam = &argv[optind];

	/* Skip past equates. */
	while (argv[optind] && strchr(argv[optind], '='))
		optind++;

	/* Confirm that the instance name is valid */
	if ((pkginst = argv[optind]) != NULL) {
		if (pkgnmchk(pkginst, "all", 0)) {
			progerr(gettext(ERR_PKGINST), pkginst);
			quit(1);
		}
		argv[optind++] = NULL;
	}
	if (optind != argc)
		usage();

	tmpdir = getenv("TMPDIR");
	if (tmpdir == NULL)
		tmpdir = P_tmpdir;

	/* bug id 4244631, not ABI compliant */
	abi_sym_ptr = getenv("PKG_NONABI_SYMLINKS");
	if (abi_sym_ptr && (strncasecmp(abi_sym_ptr, "TRUE", 4) == 0)) {
		set_nonABI_symlinks();
	}

	if (device == NULL) {
		device = devattr(SPOOLDEV, "pathname");
		if (device == NULL) {
			progerr(gettext(ERR_DEVICE), SPOOLDEV);
			exit(99);
		}
	}

	if (protofile == NULL) {
		if (access("prototype", 0) == 0)
			protofile = "prototype";
		else if (access("Prototype", 0) == 0)
			protofile = "Prototype";
		else {
			progerr(gettext(ERR_PROTOTYPE));
			quit(1);
		}
	}

	if (devtype(device, &pkgdev)) {
		progerr(gettext(ERR_BADDEV), device);
		quit(1);
	}
	if (pkgdev.norewind) {
		/* initialize datastream */
		progerr(gettext(ERR_DSTREAM), device);
		quit(1);
	}
	if (pkgdev.mount) {
		if (n = pkgmount(&pkgdev, NULL, 0, 0, 1))
			quit(n);
	}

	/*
	 * convert prototype file to a pkgmap, while locating
	 * package objects in the current environment
	 */
	t_pkgmap = tempnam(tmpdir, "tmpmap");
	if (t_pkgmap == NULL) {
		progerr(gettext(ERR_TEMP), errno);
		exit(99);
	}

	(void) fprintf(stderr, gettext(MSG_PROTOTYPE));
	if (n = mkpkgmap(t_pkgmap, protofile, cmdparam)) {
		progerr(gettext(ERR_BUILD));
		quit(1);
	}

	setmapmode(MAPNONE);	/* All appropriate variables are now bound */

	if (vfpOpen(&vfp, t_pkgmap, "r", VFP_NEEDNOW) != 0) {
		progerr(gettext(ERR_TEMP), errno);
		quit(99);
	}

	eptlist = procmap(vfp, 0, NULL);

	if (eptlist == NULL) {
		quit(1);
	}

	(void) vfpClose(&vfp);

	/* Validate the zone attributes in pkginfo, before creation */
	if (!valid_zone_attr(eptlist)) {
		progerr(ERR_PKGINFO_INVALID_OPTION_COMB);
		quit(1);
	}

	(void) fprintf(stderr, gettext(MSG_PKGINFO));
	pt = NULL;
	for (i = 0; eptlist[i]; i++) {
		ckmissing(eptlist[i]->path, eptlist[i]->ftype);
		if (eptlist[i]->ftype != 'i')
			continue;
		if (strcmp(eptlist[i]->path, "pkginfo") == 0)
			svept = eptlist[i];
	}
	if (svept == NULL) {
		progerr(gettext(ERR_NOPKGINFO));
		quit(99);
	}
	eptnum = i;

	/*
	 * process all parameters from the pkginfo file
	 * and place them in the execution environment
	 */

	if ((fp = fopen(svept->ainfo.local, "r")) == NULL) {
		progerr(gettext(ERR_RDPKGINFO), svept->ainfo.local);
		quit(99);
	}
	param[0] = '\0';
	while (value = fpkgparam(fp, param)) {
		if (getenv(param) == NULL)
			putparam(param, value);
		free((void *)value);
		param[0] = '\0';
	}
	(void) fclose(fp);

	/* add command line variables */
	while (*cmdparam && (value = strchr(*cmdparam, '=')) != NULL) {
		*value = NULL;	/* terminate the parameter */
		value++;	/* value is now the value (not '=') */
		putparam(*cmdparam++, value);  /* store it in environ */
	}

	/* make sure parameters are valid */
	(void) time(&clock);
	if (pt = getenv("PKG")) {
		if (pkgnmchk(pt, NULL, 0) || strchr(pt, '.')) {
			progerr(gettext(ERR_PKGABRV), pt);
			quit(1);
		}
		if (pkginst == NULL)
			pkginst = pt;
	} else {
		progerr(gettext(ERR_NOPARAM), "PKG", svept->path);
		quit(1);
	}
	/*
	 * verify consistency between PKG parameter and pkginst
	 */
	(void) snprintf(param, sizeof (param), "%s.*", pt);
	if (pkgnmchk(pkginst, param, 0)) {
		progerr(gettext(ERR_PKGMTCH), pt, pkginst);
		quit(1);
	}

	/*
	 * *********************************************************************
	 * this feature is removed starting with Solaris 10 - there is no built
	 * in list of packages that should be run "the old way"
	 * *********************************************************************
	 */

#ifdef	ALLOW_EXCEPTION_PKG_LIST
	/* Until 2.9, set it from the execption list */
	if (exception_pkg(pkginst, LINK))
		set_nonABI_symlinks();
#endif

	if ((pkgname = getenv("NAME")) == NULL) {
		progerr(gettext(ERR_NOPARAM), "NAME", svept->path);
		quit(1);
	}
	if (ckparam("NAME", pkgname))
		quit(1);
	if ((pkgvers = getenv("VERSION")) == NULL) {
		/* XXX - I18n */
		/* LINTED do not use cftime(); use strftime instead */
		(void) cftime(buf, "\045m/\045d/\045Y", &clock);
		(void) snprintf(temp, sizeof (temp),
			gettext("Dev Release %s"), buf);
		putparam("VERSION", temp);
		pkgvers = getenv("VERSION");
		logerr(gettext(WRN_SETPARAM), "VERSION", temp);
	}
	if (ckparam("VERSION", pkgvers))
		quit(1);
	if ((pkgarch = getenv("ARCH")) == NULL) {
		(void) uname(&utsbuf);
		putparam("ARCH", utsbuf.machine);
		pkgarch = getenv("ARCH");
		logerr(gettext(WRN_SETPARAM), "ARCH", utsbuf.machine);
	}
	if (ckparam("ARCH", pkgarch))
		quit(1);
	if (getenv("PSTAMP") == NULL) {
		/* use octal value of '%' to fight sccs expansion */
		/* XXX - I18n */
		/* LINTED do not use cftime(); use strftime instead */
		(void) cftime(buf, "\045Y\045m\045d\045H\045M\045S", &clock);
		(void) uname(&utsbuf);
		(void) snprintf(temp, sizeof (temp), "%s%s",
			utsbuf.nodename, buf);
		putparam("PSTAMP", temp);
		logerr(gettext(WRN_SETPARAM), "PSTAMP", temp);
	}
	if ((pkgcat = getenv("CATEGORY")) == NULL) {
		progerr(gettext(ERR_NOPARAM), "CATEGORY", svept->path);
		quit(1);
	}
	if (ckparam("CATEGORY", pkgcat))
		quit(1);

	/*
	 * warn user of classes listed in package which do
	 * not appear in CLASSES variable in pkginfo file
	 */
	objects = 0;
	for (i = 0; eptlist[i]; i++) {
		if (eptlist[i]->ftype != 'i') {
			objects++;
			addlist(&allclass, eptlist[i]->pkg_class);
		}
	}

	if ((pt = getenv("CLASSES")) == NULL) {
		if (allclass && *allclass) {
			cl_setl(allclass);
			cl_putl("CLASSES", allclass);
			logerr(gettext(WRN_SETPARAM), "CLASSES",
			    getenv("CLASSES"));
		}
	} else {
		cl_sets(qstrdup(pt));
		if (allclass && *allclass) {
			for (i = 0; allclass[i]; i++) {
				found = 0;
				if (cl_idx(allclass[i]->name) != -1) {
					found++;
					break;
				}
				if (!found) {
					logerr(gettext(WRN_CLASSES),
					    (char *)allclass[i]);
				}
			}
		}
	}

	(void) fprintf(stderr, gettext(MSG_VOLUMIZE), objects);
	order = (struct cl_attr **)0;
	if (pt = getenv("ORDER")) {
		pt = qstrdup(pt);
		(void) setlist(&order, pt);
		cl_putl("ORDER", order);
	}

	/* stat the intended output filesystem to get blocking information */
	if (pkgdev.dirname == NULL) {
		progerr(gettext(ERR_WHATVFS), device);
		quit(99);
	}
	if (statvfs64(pkgdev.dirname, &svfsb)) {
		progerr(gettext(ERR_STATVFS), pkgdev.dirname);
		quit(99);
	}

	if (bsize == 0) {
		bsize = svfsb.f_bsize;
	}
	if (frsize == 0) {
		frsize = svfsb.f_frsize;
	}
	if (limit == 0)
		/*
		 * bavail is in terms of fragment size blocks - change
		 * to 512 byte blocks
		 */
		limit = (((long)frsize > 0) ?
			howmany(frsize, DEV_BSIZE) :
			howmany(bsize, DEV_BSIZE)) * svfsb.f_bavail;
	if (ilimit == 0) {
		ilimit = (svfsb.f_favail > 0) ?
		    svfsb.f_favail : svfsb.f_ffree;
	}

	nparts = splpkgmap(eptlist, eptnum, (char **)order, bsize, frsize,
	    &limit, &ilimit, &llimit);

	if (nparts <= 0) {
		progerr(gettext(ERR_SPLIT));
		quit(1);
	}

	if (nflag) {
		for (i = 0; eptlist[i]; i++)
			(void) ppkgmap(eptlist[i], stdout);
		exit(0);
		/*NOTREACHED*/
	}

	(void) snprintf(pkgloc, sizeof (pkgloc), "%s/%s",
			pkgdev.dirname, pkginst);
	if (!isdir(pkgloc) && !overwrite) {
		progerr(gettext(ERR_OVERWRITE), pkgloc);
		quit(1);
	}

	/* output all environment install parameters */
	t_pkginfo = tempnam(tmpdir, "pkginfo");
	if ((fp = fopen(t_pkginfo, "w")) == NULL) {
		progerr(gettext(ERR_TEMP), errno);
		exit(99);
	}
	for (i = 0; environ[i]; i++) {
		if (isupper(*environ[i])) {
			(void) fputs(environ[i], fp);
			(void) fputc('\n', fp);
		}
	}
	(void) fclose(fp);

	started++;
	(void) rrmdir(pkgloc);
	if (mkdir(pkgloc, 0755)) {
		progerr(gettext(ERR_MKDIR), pkgloc);
		quit(1);
	}

	/* determine how many packages already reside on the medium */
	pkgdir = pkgdev.dirname;
	npkgs = 0;
	while (pt = fpkginst("all", NULL, NULL))
		npkgs++;
	(void) fpkginst(NULL); /* free resource usage */

	if (nparts > 1) {
		if (pkgdev.mount && npkgs) {
			progerr(gettext(ERR_ONEVOL));
			quit(1);
		}
	}

	/*
	 *  update pkgmap entry for pkginfo file, since it may
	 *  have changed due to command line or failure to
	 *  specify all neccessary parameters
	 */
	for (i = 0; eptlist[i]; i++) {
		if (eptlist[i]->ftype != 'i')
			continue;
		if (strcmp(eptlist[i]->path, "pkginfo") == 0) {
			svept = eptlist[i];
			svept->ftype = '?';
			svept->ainfo.local = t_pkginfo;
			(void) cverify(0, &svept->ftype, t_pkginfo,
				&svept->cinfo, 1);
			svept->ftype = 'i';
			break;
		}
	}

	if (nparts > 1)
		(void) fprintf(stderr, gettext(MSG_PACKAGEM), nparts);
	else
		(void) fprintf(stderr, gettext(MSG_PACKAGE1));

	for (part = 1; part <= nparts; part++) {
		if ((part > 1) && pkgdev.mount) {
			if (pkgumount(&pkgdev)) {
				progerr(gettext(ERR_UMOUNT), pkgdev.mount);
				quit(99);
			}
			if (n = pkgmount(&pkgdev, NULL, part, nparts, 1))
				quit(n);
			(void) rrmdir(pkgloc);
			if (mkdir(pkgloc, 0555)) {
				progerr(gettext(ERR_MKDIR), pkgloc);
				quit(99);
			}
		}
		outvol(eptlist, eptnum, part, nparts);

		/* Validate (as much as possible) the control scripts. */
		if (part == 1) {
			char inst_path[PATH_MAX];

			(void) fprintf(stderr, gettext(MSG_VALSCRIPTS));
			(void) snprintf(inst_path, sizeof (inst_path),
					"%s/install", pkgloc);
			checkscripts(inst_path, 0);
		}
	}

	quit(0);
	/*NOTREACHED*/
}