OpenSolaris_b135/cmd/svr4pkg/pkgmk/main.c

Compare this file to the similar file:
Show the results in this format:

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */


#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <errno.h>
#include <malloc.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <ctype.h>
#include <sys/mman.h>
#include <sys/sysmacros.h>
#include <strings.h>
#include <pkgstrct.h>
#include <pkgdev.h>
#include <pkginfo.h>
#include <pkglocs.h>
#include <locale.h>
#include <libintl.h>
#include <sys/statvfs.h>
#include <sys/utsname.h>
#include <instzones_api.h>
#include <pkglib.h>
#include <libadm.h>
#include <libinst.h>

extern char	**environ, *pkgdir;

/* mkpkgmap.c */
extern int	mkpkgmap(char *outfile, char *protofile, char **cmdparam);
/* splpkgmap.c */
extern int	splpkgmap(struct cfent **eptlist, unsigned int eptnum,
    char *order[], ulong_t bsize, ulong_t frsize, fsblkcnt_t *plimit,
    fsfilcnt_t *pilimit, fsblkcnt_t *pllimit);
/* scriptvfy.c */
extern int	checkscripts(char *inst_dir, int silent);

/* libpkg/gpkgmap.c */
extern void	setmapmode(int mode_no);

static boolean_t valid_zone_attr(struct cfent **eptlist);

#define	MALSIZ	16
#define	NROOT	8
#define	SPOOLDEV	"spool"

#define	MSG_PROTOTYPE	"## Building pkgmap from package prototype file.\n"
#define	MSG_PKGINFO	"## Processing pkginfo file.\n"
#define	MSG_VOLUMIZE	"## Attempting to volumize %d entries in pkgmap.\n"
#define	MSG_PACKAGE1	"## Packaging one part.\n"
#define	MSG_PACKAGEM	"## Packaging %d parts.\n"
#define	MSG_VALSCRIPTS	"## Validating control scripts.\n"

/* Other problems */
#define	ERR_MEMORY	"memory allocation failure, errno=%d"
#define	ERR_NROOT	"too many paths listed with -r option, limit is %d"
#define	ERR_PKGINST	"invalid package instance identifier <%s>"
#define	ERR_PKGABRV	"invalid package abbreviation <%s>"
#define	ERR_BADDEV	"unknown or invalid device specified <%s>"
#define	ERR_TEMP	"unable to obtain temporary file resources, errno=%d"
#define	ERR_DSTREAM	"invalid device specified (datastream) <%s>"
#define	ERR_SPLIT	"unable to volumize package"
#define	ERR_MKDIR	"unable to make directory <%s>"
#define	ERR_SYMLINK	"unable to create symbolic link for <%s>"
#define	ERR_OVERWRITE	"must use -o option to overwrite <%s>"
#define	ERR_UMOUNT	"unable to unmount device <%s>"
#define	ERR_NOPKGINFO	"required pkginfo file is not specified in prototype " \
			"file"
#define	ERR_RDPKGINFO	"unable to process pkginfo file <%s>"
#define	ERR_PROTOTYPE	"unable to locate prototype file"
#define	ERR_STATVFS	"unable to stat filesystem <%s>"
#define	ERR_WHATVFS	"unable to determine or access output filesystem for " \
			"device <%s>"
#define	ERR_DEVICE	"unable to find info for device <%s>"
#define	ERR_BUILD	"unable to build pkgmap from prototype file"
#define	ERR_ONEVOL	"other packages found - package must fit on a single " \
			"volume"
#define	ERR_NOPARAM	"parameter <%s> is not defined in <%s>"
#define	ERR_PKGMTCH	"PKG parameter <%s> does not match instance <%s>"
#define	ERR_NO_PKG_INFOFILE	"unable to open pkginfo file <%s>: %s"
#define	ERR_ALLZONES_AND_THISZONE	"The package <%s> has <%s> = true " \
					"and <%s> = true: the package may " \
					"set either parameter to true, but " \
					"may not set both parameters to " \
					"true. NOTE: if the package " \
					"contains a request script, it is " \
					"treated as though it has " \
					"<SUNW_PKG_THISZONE> = true"
#define	ERR_NO_ALLZONES_AND_HOLLOW	"The package <%s> has <%s> = false " \
					"and <%s> = true: a hollow package " \
					"must also be set to install in all " \
					"zones"
#define	ERR_PKGINFO_INVALID_OPTION_COMB	"Invalid combinations of zone " \
					"parameters in pkginfo file"

#define	ERR_USAGE	"usage: %s [options] [VAR=value [VAR=value]] " \
			"[pkginst]\n" \
			"   where options may include:\n" \
			"\t-o\n" \
			"\t-a arch\n" \
			"\t-v version\n" \
			"\t-p pstamp\n" \
			"\t-l limit\n" \
			"\t-r rootpath\n" \
			"\t-b basedir\n" \
			"\t-d device\n" \
			"\t-f protofile\n"
#define	WRN_MISSINGDIR	"WARNING: missing directory entry for <%s>"
#define	WRN_SETPARAM	"WARNING: parameter <%s> set to \"%s\""
#define	WRN_CLASSES	"WARNING: unreferenced class <%s> in prototype file"

#define	LINK    1

struct pkgdev pkgdev; 	/* holds info about the installation device */
int	started;
char	pkgloc[PATH_MAX];
char	*basedir;
char	*root;
char	*rootlist[NROOT];
char	*t_pkgmap;
char	*t_pkginfo;

static struct cfent *svept;
static char	*protofile,
		*device;
static fsblkcnt_t limit = 0;
static fsblkcnt_t llimit = 0;
static fsfilcnt_t ilimit = 0;
static int	overwrite,
		nflag,
		sflag;
static void	ckmissing(char *path, char type);
static void	outvol(struct cfent **eptlist, unsigned int eptnum, int part,
			int nparts);
static void	trap(int n);
static void	usage(void);

static int	slinkf(char *from, char *to);

int
main(int argc, char *argv[])
{
	struct utsname utsbuf;
	struct statvfs64 svfsb;
	struct cfent	**eptlist;
	FILE	*fp;
	VFP_T	*vfp;
	int	c, n, found;
	int	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;
	ulong_t	bsize = 0;
	ulong_t	frsize = 0;
	struct cl_attr	**allclass = NULL;
	struct cl_attr	**order;
	unsigned int eptnum, i;

	/* 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 = strtoull(optarg, NULL, 10);
			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();
			/*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);
		}
	}

	/*
	 * 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 = (fsblkcnt_t)(((fsblkcnt_t)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);
	/* LINTED: no return */
}

static void
trap(int n)
{
	(void) signal(SIGINT, SIG_IGN);
	(void) signal(SIGHUP, SIG_IGN);

	if (n == SIGINT)
		quit(3);
	else {
		(void) fprintf(stderr, gettext("%s terminated (signal %d).\n"),
				get_prog_name(), n);
		quit(99);
	}
}

static void
outvol(struct cfent **eptlist, unsigned int eptnum, int part, int nparts)
{
	FILE	*fp;
	char	*svpt, *path, temp[PATH_MAX];
	unsigned int	i;


	if (nparts > 1)
		(void) fprintf(stderr, gettext(" -- part %2d:\n"), part);
	if (part == 1) {
		/* re-write pkgmap, but exclude local pathnames */
		(void) snprintf(temp, sizeof (temp), "%s/pkgmap", pkgloc);
		if ((fp = fopen(temp, "w")) == NULL) {
			progerr(gettext(ERR_TEMP), errno);
			quit(99);
		}
		(void) fprintf(fp, ": %d %ld\n", nparts, limit);
		for (i = 0; eptlist[i]; i++) {
			svpt = eptlist[i]->ainfo.local;
			if (!strchr("sl", eptlist[i]->ftype))
				eptlist[i]->ainfo.local = NULL;
			if (ppkgmap(eptlist[i], fp)) {
				progerr(gettext(ERR_TEMP), errno);
				quit(99);
			}
			eptlist[i]->ainfo.local = svpt;
		}
		(void) fclose(fp);
		(void) fprintf(stderr, "%s\n", temp);
	}

	(void) snprintf(temp, sizeof (temp), "%s/pkginfo", pkgloc);
	if (copyf(svept->ainfo.local, temp, svept->cinfo.modtime))
		quit(1);
	(void) fprintf(stderr, "%s\n", temp);

	for (i = 0; i < eptnum; i++) {
		if (eptlist[i]->volno != part)
			continue;
		if (strchr("dxslcbp", eptlist[i]->ftype))
			continue;
		if (eptlist[i]->ftype == 'i') {
			if (eptlist[i] == svept)
				continue; /* don't copy pkginfo file */
			(void) snprintf(temp, sizeof (temp),
				"%s/install/%s", pkgloc,
				eptlist[i]->path);
			path = temp;
		} else
			path = srcpath(pkgloc, eptlist[i]->path, part, nparts);
		if (sflag) {
			if (slinkf(eptlist[i]->ainfo.local, path))
				quit(1);
		} else if (copyf(eptlist[i]->ainfo.local, path,
				eptlist[i]->cinfo.modtime)) {
			quit(1);
		}

		/*
		 * If the package file attributes can be sync'd up with
		 * the pkgmap, we fix the attributes here.
		 */
		if (*(eptlist[i]->ainfo.owner) != '$' &&
		    *(eptlist[i]->ainfo.group) != '$') {
			/* Clear dangerous bits. */
			eptlist[i]->ainfo.mode=
			    (eptlist[i]->ainfo.mode & S_IAMB);
			/*
			 * Make sure it can be read by the world and written
			 * by the owner.
			 */
			eptlist[i]->ainfo.mode |= 0644;
			if (!strchr("in", eptlist[i]->ftype)) {
				/* Set the safe attributes. */
				averify(1, &(eptlist[i]->ftype),
				    path, &(eptlist[i]->ainfo));
			}
		}

		(void) fprintf(stderr, "%s\n", path);
	}
}

static void
ckmissing(char *path, char type)
{
	static char	**dir;
	static int	ndir;
	char	*pt;
	int	i, found;

	if (dir == NULL) {
		dir = (char **)calloc(MALSIZ, sizeof (char *));
		if (dir == NULL) {
			progerr(gettext(ERR_MEMORY), errno);
			quit(99);
		}
	}

	if (strchr("dx", type)) {
		dir[ndir] = path;
		if ((++ndir % MALSIZ) == 0) {
			dir = (char **)realloc((void *)dir,
				(ndir+MALSIZ)*sizeof (char *));
			if (dir == NULL) {
				progerr(gettext(ERR_MEMORY), errno);
				quit(99);
			}
		}
		dir[ndir] = (char *)NULL;
	}

	pt = path;
	if (*pt == '/')
		pt++;
	while (pt = strchr(pt, '/')) {
		*pt = '\0';
		found = 0;
		for (i = 0; i < ndir; i++) {
			if (strcmp(path, dir[i]) == 0) {
				found++;
				break;
			}
		}
		if (!found) {
			logerr(gettext(WRN_MISSINGDIR), path);
			ckmissing(qstrdup(path), 'd');
		}
		*pt++ = '/';
	}
}

static int
slinkf(char *from, char *to)
{
	char	*pt;

	pt = to;
	while (pt = strchr(pt+1, '/')) {
		*pt = '\0';
		if (isdir(to) && mkdir(to, 0755)) {
			progerr(gettext(ERR_MKDIR), to);
			*pt = '/';
			return (-1);
		}
		*pt = '/';
	}
	if (symlink(from, to)) {
		progerr(gettext(ERR_SYMLINK), to);
		return (-1);
	}
	return (0);
}

static void
usage(void)
{
	(void) fprintf(stderr, gettext(ERR_USAGE), get_prog_name());
	exit(1);
	/*NOTREACHED*/
}

/*
 * 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);
}