コード例 #1
0
ファイル: pkgadm_contents.c プロジェクト: belenix/belenixold
/*
 * convert_contents_to_sql
 *
 * Converts the entire contents file into a set of SQL transactions which
 * populate the database.  The reason that a single transaction is not used
 * is that some systems run out of memory in this case.
 *
 * Return: 0 on success, nonzero on failure
 */
int
convert_contents_to_sql(struct dstr *pd, const char *pcroot)
{
	VFP_T		*vfp;
	char		path[PATH_MAX];
	int		n;
	int		total = 0;
	struct cfent	entry;

	if (pcroot == NULL) {
		pcroot = "/";
	}

	if (pcroot[strlen(pcroot) - 1] == '/') {
		if (snprintf(path, sizeof (path),
			"%svar/sadm/install/contents", pcroot)
						>= sizeof (path)) {
			return (1);
		}
	} else {
		if (snprintf(path, sizeof (path),
			"%s/var/sadm/install/contents", pcroot)
						>= sizeof (path)) {
			return (1);
		}
	}

	if (vfpOpen(&vfp, path, "r", VFP_NEEDNOW) != 0) {
		log_msg(LOG_MSG_ERR, MSG_FILE_ACCESS, path, strerror(errno));
		return (1);
	}

	while ((n = srchcfile(&entry, "*", vfp, (VFP_T *)NULL)) > 0) {
		if (append_contents_sql(pd, &entry)) {
			(void) vfpClose(&vfp);
			return (1);
		}

		total++;
	}

	(void) vfpClose(&vfp);

	if (n < 0) {
		log_msg(LOG_MSG_ERR, MSG_CONTENTS_FORMAT);
		return (1);
	}

	return (0);
}
コード例 #2
0
ファイル: pkginfo.c プロジェクト: Sunshine-OS/pkg-gate
static void
getinfo(struct cfstat *dp)
{
	int		n;
	char		pkgmap[MAXPATHLEN];
	VFP_T		*vfp;

	(void) snprintf(pkgmap, sizeof (pkgmap),
			"%s/%s/pkgmap", pkgdir, dp->pkginst);

	if (vfpOpen(&vfp, pkgmap, "r", VFP_NEEDNOW) != 0) {
		progerr(gettext("unable open \"%s\" for reading"), pkgmap);
		exit(1);
	}

	dp->spooled = 1; /* pkgmap counts! */

	while ((n = gpkgmapvfp(&entry, vfp)) > 0) {
		dp->spooled++;
		pkgusage(dp, &entry);
	}

	if (n < 0) {
		char	*errstr = getErrstr();
		progerr(gettext("bad entry read in pkgmap file"));
		logerr(gettext("pathname: %s"),
		    (entry.path && *entry.path) ? entry.path : "Unknown");
		logerr(gettext("problem: %s"),
		    (errstr && *errstr) ? errstr : "Unknown");
		exit(1);
	}

	(void) vfpClose(&vfp);
}
コード例 #3
0
ファイル: pkginfo.c プロジェクト: Sunshine-OS/pkg-gate
static void
rdcontents(void)
{
	VFP_T		*vfp;
	struct cfstat	*dp;
	struct pinfo	*pinfo;
	int		n;

	if (vfpOpen(&vfp, contents, "r", VFP_NEEDNOW) != 0) {
		progerr(gettext("unable to open \"%s\" for reading"), contents);
		exit(1);
	}

	/* check the contents file to look for referenced packages */
	while ((n = srchcfile(&entry, "*", vfp, (VFP_T *)NULL)) > 0) {
		for (pinfo = entry.pinfo; pinfo; pinfo = pinfo->next) {
			/* see if entry is used by indicated packaged */
			if (pkgcnt && (selectp(pinfo->pkg) < 0))
				continue;

			dp = fpkg(pinfo->pkg);
			pkgusage(dp, &entry);

			if (entry.npkgs > 1)
				dp->shared++;

			/*
			 * Only objects specifically tagged with '!' event
			 * character are considered "partial", everything
			 * else is considered "installed" (even server
			 * objects).
			 */
			switch (pinfo->status) {
			case '!' :
				dp->partial++;
				break;
			default :
				dp->installed++;
				break;
			}
		}
	}
	if (n < 0) {
		char	*errstr = getErrstr();
		progerr(gettext("bad entry read in contents file"));
		logerr(gettext("pathname: %s"),
		    (entry.path && *entry.path) ? entry.path : "Unknown");
		logerr(gettext("problem: %s"),
		    (errstr && *errstr) ? errstr : "Unknown");
		exit(1);
	}

	(void) vfpClose(&vfp);
}
コード例 #4
0
ファイル: vfpops.c プロジェクト: apprisi/illumos-gate
int
vfpCheckpointOpen(VFP_T **a_cpVfp, VFP_T **r_vfp, char *a_path,
	char *a_mode, VFPFLAGS_T a_flags)
{
	FILE		*fp;	/* backing store */
	VFP_T		*cpVfp;	/* local -> to a_cpVfp checkpointed VFP */
	VFP_T		*vfp;	/* new VFP open on checkpointed backing store */
	struct stat	statbuf; /* stat(2) info on backing store */

	/*
	 * if no source VFP, or source VFP empty,
	 * or no backing store, just open file
	 */

	if ((a_cpVfp == (VFP_T **)NULL) || (*a_cpVfp == (VFP_T *)NULL) ||
		((*a_cpVfp)->_vfpStart == (char *)NULL)) {
		(void) vfpClose(a_cpVfp);
		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
	}

	/* localize access to checkpointed VFP_T (*a_cpVfp) */

	cpVfp = *a_cpVfp;

	/* if no path specified, grab it from the checkpointed VFP */

	if ((a_path == (char *)NULL) || (*a_path == '\0')) {
		a_path = cpVfp->_vfpPath;
	}

	/* return error if no path specified and no path in checkpointed VFP */

	if ((a_path == (char *)NULL) && (*a_path == '\0')) {
		errno = EINVAL;
		return (-1);
	}

	/* if no backing store path, then just open file */

	if (stat(a_path, &statbuf) != 0) {
		(void) vfpClose(a_cpVfp);
		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
	}

	/*
	 * if backing store tokens do not match checkpointed VFP,
	 * the backing store has been updated since the VFP was checkpointed;
	 * release the in-memory data, and open and read the backing store
	 */

	if ((statbuf.st_size != cpVfp->_vfpCkSize) ||
		(statbuf.st_mtime != cpVfp->_vfpCkMtime) ||
		(statbuf.st_blocks != cpVfp->_vfpCkStBlocks) ||
		(statbuf.st_ino != cpVfp->_vfpCkIno) ||
		(statbuf.st_dev != cpVfp->_vfpCkDev)) {
		(void) vfpClose(a_cpVfp);
		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
	}

	/*
	 * backing store has not been updated since the VFP was checkpointed;
	 * use the in-memory data without re-reading the backing store; open the
	 * backing store file (if no file already open on the checkpointed VFP)
	 * so there is an open file associated with the in-memory data
	 */

	fp = cpVfp->_vfpFile;
	if (fp == (FILE *)NULL) {
		fp = fopen(a_path, a_mode);
		if (fp == (FILE *)NULL) {
			int	lerrno;

			lerrno = errno;
			(void) vfpClose(a_cpVfp);
			errno = lerrno;
			return (-1);
		}
	}

	/* allocate new VFP object to return as open VFP */

	vfp = (VFP_T *)malloc(sizeof (VFP_T));
	if (vfp == (VFP_T *)NULL) {
		(void) vfpClose(a_cpVfp);
		return (vfpOpen(r_vfp, a_path, a_mode, a_flags));
	}

	/* copy cached checkpointed VFP to new VFP to return */

	(void) memcpy(vfp, cpVfp, sizeof (VFP_T));

	/*
	 * initialize VFP to return contents
	 */

	/* FILE -> file opened on the VFPs backing store */

	vfp->_vfpFile = fp;

	/* release any existing path associated with the VFP */

	if (vfp->_vfpPath != (char *)NULL) {
		(void) free(vfp->_vfpPath);
	}

	/* path associated with the backing store for this VFP */

	vfp->_vfpPath = strdup(a_path);

	/*
	 * data pointers associated with in memory copy of backing store
	 * (such as _vfpHighWater, _vfpEnd, _vfpStart, etc.)
	 * do not need to be modified because we are using the same backing
	 * store as was checkpointed in cpVfp that is pointed to by vfp.
	 */

	/* _vfpCurr -> next byte to read */
	vfp->_vfpCurr = (char *)vfp->_vfpStart;

	/* free checkpointed VFP as it is now open on "vfp" */

	(void) free(cpVfp);

	/* reset callers -> checkpointed VFP */

	(*a_cpVfp) = (VFP_T *)NULL;

	/* set return VFP pointer */

	(*r_vfp) = vfp;

	/* success! */

	return (0);
}
コード例 #5
0
ファイル: ocfile.c プロジェクト: AlfredArouna/illumos-gate
int
swapcfile(PKGserver server, VFP_T **a_cfTmpVfp, char *pkginst, int dbchg)
{
	char	*pe;
	char	*pl;
	char	*ps;
	char	line[256];
	char	timeb[BUFSIZ];
	int	retval = RESULT_OK;
	struct tm	*timep;
	time_t	clock;

	/* normalize pkginst so its never null */

	if (pkginst == (char *)NULL) {
		dbchg = 0;
		pkginst = "<unknown>";
	}

	/*
	 * If no changes were made to the database, checkpoint the temporary
	 * contents file - if this fails, then just close the file which causes
	 * the contents file to be reopened and reread if it is needed again
	 */

	if ((dbchg == 0) && (vfpGetModified(*a_cfTmpVfp) == 0)) {
		(void) pkgWunlock();	/* Free the database lock. */
		return (retval);
	}

	/*
	 * changes made to the current temporary contents file -
	 * remove any trailing comment lines in the temp contents file, then
	 * append updated modification info records to temp contents file
	 */

	pe = vfpGetCurrCharPtr(*a_cfTmpVfp);	/* last char in contents file */
	ps = vfpGetFirstCharPtr(*a_cfTmpVfp);	/* 1st char in contents file */
	pl = pe;	/* last match is last char in contents file */

	/* skip past all trailing newlines and null bytes */

	while ((pe > ps) && ((*pe == '\n') || (*pe == '\0'))) {
		pe--;
	}

	/* remove trailing comments as long as there are lines in the file */

	while (pe > ps) {
		if (*pe != '\n') {
			/* curr char is not newline: backup one byte */
			pl = pe--;
		} else if (*pl != '#') {
			/* curr char is newline next char not comment break */
			break;
		} else {
			/* curr char is newline next char is comment - remove */
			*pl = '\0';
			vfpSetLastCharPtr(*a_cfTmpVfp, pl);
			pe--;
		}
	}

	/* create two update comment lines */

	(void) time(&clock);
	timep = localtime(&clock);

	(void) strftime(timeb, sizeof (timeb), "%c\n", timep);
	(void) snprintf(line, sizeof (line),
	    gettext("# Last modified by %s for %s package\n# %s"),
	    get_prog_name(), pkginst, timeb);
	vfpPuts(*a_cfTmpVfp, line);

	/* commit temporary contents file bytes to storage */

	if (pkgservercommitfile(*a_cfTmpVfp, server) != 0) {
		int	lerrno = errno;

		logerr(gettext(ERR_COMMIT));
		vfpClose(a_cfTmpVfp);
		pkgcloseserver(server);
		(void) pkgWunlock();	/* Free the database lock. */
		return (RESULT_ERR);
	}

	return (relslock() == 0 ? RESULT_ERR : retval);
}
コード例 #6
0
ファイル: ocfile.c プロジェクト: AlfredArouna/illumos-gate
/*
 * This function installs the database lock, opens the contents file for
 * reading and creates and opens the temporary contents file for read/write.
 * It returns 1 if successful, 0 otherwise.
 */
int
ocfile(PKGserver *server, VFP_T **r_tmpvfp, fsblkcnt_t map_blks)
{
	struct	stat64	statb, statl;
	struct	statvfs64	svfsb;
	fsblkcnt_t free_blocks;
	fsblkcnt_t need_blocks;
	fsblkcnt_t log_blocks;
	VFP_T		*tmpvfp = (VFP_T *)NULL;
	char		contents[PATH_MAX];
	char		logfile[PATH_MAX];
	int		n;
	off_t		cdiff_alloc;
	PKGserver	newserver;

	/* establish package administration contents directory location */

	if (pkgadm_dir == NULL) {
		if (set_cfdir(NULL) != 0) {
			progerr(gettext(ERR_CFDIR));
			return (0);
		}
	}

	/* Lock the file for exclusive access */

	if (!pkgWlock(1)) {
		progerr(gettext(ERR_NOLOCK));
		return (0);
	}

	if (*server != NULL) {
		vfpTruncate(*r_tmpvfp);
		(void) vfpClearModified(*r_tmpvfp);

		return (1);
	}

	newserver = pkgopenserver(NULL, pkgadm_dir, B_FALSE);

	/* The error has been reported. */
	if (newserver == NULL)
		return (0);

	/* reset return VFP/FILE pointers */

	(*r_tmpvfp) = (VFP_T *)NULL;

	/* determine path to the primary contents file */
	(void) snprintf(contents, sizeof (contents), "%s/contents", pkgadm_dir);

	/*
	 * Check and see if there is enough space for the packaging commands
	 * to back up the contents file, if there is not, then do not allow
	 * execution to continue by failing the ocfile() call.
	 */

	/* Get the contents file size */

	if (stat64(contents, &statb) == -1) {
		int	lerrno = errno;

		progerr(gettext(ERR_NOCFILE), contents);
		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
		pkgcloseserver(newserver);
		return (0);
	}

	/* Get the filesystem space */

	if (statvfs64(contents, &svfsb) == -1) {
		int	lerrno = errno;

		progerr(gettext(ERR_NOSTATV), contents);
		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
		pkgcloseserver(newserver);
		return (0);
	}

	free_blocks = (((fsblkcnt_t)svfsb.f_frsize > 0) ?
	    howmany(svfsb.f_frsize, DEV_BSIZE) :
	    howmany(svfsb.f_bsize, DEV_BSIZE)) * svfsb.f_bfree;

	/* determine blocks used by the logfile */
	(void) snprintf(logfile, sizeof (logfile), "%s/" PKGLOG, pkgadm_dir);

	if (stat64(logfile, &statl) == -1)
		log_blocks = 0;
	else
		log_blocks = nblk(statl.st_size, svfsb.f_bsize, svfsb.f_frsize);

	/*
	 * Calculate the number of blocks we need to be able to operate on
	 * the contents file and the log file.
	 * When adding a package (map_blks > 0), we add the size of the
	 * pkgmap file times 1.5 as the pkgmap is a bit smaller then the
	 * lines added to the contents file.  That data is written both to
	 * the new contents file and the log file (2 * 1.5 * map_blks).
	 * The new contents file is limited by the size of the current
	 * contents file and the increased log file.
	 * If we're removing a package, then the log might grow to the size
	 * of the full contents file but then the new contents file would
	 * be zero and so we only need to add the size of the contents file.
	 */
	need_blocks = map_blks * 3 +
	    /* Current log file */
	    log_blocks +
	    /* Current contents file */
	    nblk(statb.st_size, svfsb.f_bsize, svfsb.f_frsize);

	if ((need_blocks + 10) > free_blocks) {
		progerr(gettext(ERR_CFBACK), contents);
		progerr(gettext(ERR_CFBACK1), need_blocks, free_blocks,
		    DEV_BSIZE);
		pkgcloseserver(newserver);
		return (0);
	}

	/*
	 * open the temporary contents file without a path name - this causes
	 * the "vfp" to be opened on in-memory storage only, the size of which
	 * is set following a successful return - this causes the temporary
	 * contents file to be maintained in memory only - if no changes are
	 * made as the primary contents file is processed, the in memory data
	 * is discarded and not written to the disk.
	 */

	if (vfpOpen(&tmpvfp, (char *)NULL, "w", VFP_NONE) != 0) {
		int	lerrno = errno;

		progerr(gettext(ERR_NOTMPOPEN));
		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
		pkgcloseserver(newserver);
		return (0);
	}

	/*
	 * set size of allocation for temporary contents file - this sets the
	 * size of the in-memory buffer associated with the open vfp.
	 * We only store the new and changed entries.
	 * We allocate memory depending on the size of the pkgmap; it's not
	 * completely right but <some value + * 1.5 * map_blks * DEV_BSIZE>
	 * seems fine (an install adds the size if the name of the package.)
	 */

	cdiff_alloc = map_blks * DEV_BSIZE;
	cdiff_alloc += cdiff_alloc/2;
	if (cdiff_alloc < 1000000)
		cdiff_alloc += 1000000;

	if (vfpSetSize(tmpvfp, cdiff_alloc) != 0) {
		int	lerrno = errno;

		progerr(gettext(ERR_NOTMPOPEN));
		logerr(gettext(ERR_ERRNO), lerrno, strerror(lerrno));
		(void) vfpClose(&tmpvfp);
		pkgcloseserver(newserver);
		return (0);
	}

	/* set return ->s to open server/vfps */

	(*r_tmpvfp) = tmpvfp;
	*server = newserver;

	return (1);	/* All OK */
}
コード例 #7
0
ファイル: checkmap.c プロジェクト: AlfredArouna/illumos-gate
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);
}
コード例 #8
0
ファイル: main.c プロジェクト: belenix/belenixold
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*/
}