19781SMoriah.Waterland@Sun.COM /*
29781SMoriah.Waterland@Sun.COM  * CDDL HEADER START
39781SMoriah.Waterland@Sun.COM  *
49781SMoriah.Waterland@Sun.COM  * The contents of this file are subject to the terms of the
59781SMoriah.Waterland@Sun.COM  * Common Development and Distribution License (the "License").
69781SMoriah.Waterland@Sun.COM  * You may not use this file except in compliance with the License.
79781SMoriah.Waterland@Sun.COM  *
89781SMoriah.Waterland@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
99781SMoriah.Waterland@Sun.COM  * or http://www.opensolaris.org/os/licensing.
109781SMoriah.Waterland@Sun.COM  * See the License for the specific language governing permissions
119781SMoriah.Waterland@Sun.COM  * and limitations under the License.
129781SMoriah.Waterland@Sun.COM  *
139781SMoriah.Waterland@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
149781SMoriah.Waterland@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
159781SMoriah.Waterland@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
169781SMoriah.Waterland@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
179781SMoriah.Waterland@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
189781SMoriah.Waterland@Sun.COM  *
199781SMoriah.Waterland@Sun.COM  * CDDL HEADER END
209781SMoriah.Waterland@Sun.COM  */
219781SMoriah.Waterland@Sun.COM 
229781SMoriah.Waterland@Sun.COM /*
239781SMoriah.Waterland@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
249781SMoriah.Waterland@Sun.COM  * Use is subject to license terms.
259781SMoriah.Waterland@Sun.COM  */
269781SMoriah.Waterland@Sun.COM 
279781SMoriah.Waterland@Sun.COM /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
289781SMoriah.Waterland@Sun.COM /* All Rights Reserved */
299781SMoriah.Waterland@Sun.COM 
309781SMoriah.Waterland@Sun.COM 
319781SMoriah.Waterland@Sun.COM #include <stdio.h>
329781SMoriah.Waterland@Sun.COM #include <string.h>
339781SMoriah.Waterland@Sun.COM #include <locale.h>
349781SMoriah.Waterland@Sun.COM #include <libintl.h>
359781SMoriah.Waterland@Sun.COM #include <dirent.h>
369781SMoriah.Waterland@Sun.COM #include <pkgstrct.h>
379781SMoriah.Waterland@Sun.COM #include <pkgdev.h>
389781SMoriah.Waterland@Sun.COM #include <pkglocs.h>
399781SMoriah.Waterland@Sun.COM #include <archives.h>
409781SMoriah.Waterland@Sun.COM #include <errno.h>
419781SMoriah.Waterland@Sun.COM #include <fcntl.h>
429781SMoriah.Waterland@Sun.COM #include <sys/stat.h>
439781SMoriah.Waterland@Sun.COM #include <sys/param.h>
449781SMoriah.Waterland@Sun.COM #include <stdlib.h>
459781SMoriah.Waterland@Sun.COM #include <unistd.h>
469781SMoriah.Waterland@Sun.COM #include <assert.h>
479781SMoriah.Waterland@Sun.COM #include <wait.h>
489781SMoriah.Waterland@Sun.COM 
499781SMoriah.Waterland@Sun.COM /*
509781SMoriah.Waterland@Sun.COM  * libinstzones includes
519781SMoriah.Waterland@Sun.COM  */
529781SMoriah.Waterland@Sun.COM 
539781SMoriah.Waterland@Sun.COM #include <instzones_api.h>
549781SMoriah.Waterland@Sun.COM 
559781SMoriah.Waterland@Sun.COM /*
569781SMoriah.Waterland@Sun.COM  * consolidation pkg command library includes
579781SMoriah.Waterland@Sun.COM  */
589781SMoriah.Waterland@Sun.COM 
599781SMoriah.Waterland@Sun.COM #include <pkglib.h>
609781SMoriah.Waterland@Sun.COM #include <pkgweb.h>
619781SMoriah.Waterland@Sun.COM 
629781SMoriah.Waterland@Sun.COM /*
639781SMoriah.Waterland@Sun.COM  * local pkg command library includes
649781SMoriah.Waterland@Sun.COM  */
659781SMoriah.Waterland@Sun.COM 
669781SMoriah.Waterland@Sun.COM #include <install.h>
679781SMoriah.Waterland@Sun.COM #include <libinst.h>
689781SMoriah.Waterland@Sun.COM #include <libadm.h>
699781SMoriah.Waterland@Sun.COM #include <dryrun.h>
709781SMoriah.Waterland@Sun.COM #include <messages.h>
719781SMoriah.Waterland@Sun.COM 
729781SMoriah.Waterland@Sun.COM /*
739781SMoriah.Waterland@Sun.COM  * pkginstall local includes
749781SMoriah.Waterland@Sun.COM  */
759781SMoriah.Waterland@Sun.COM 
769781SMoriah.Waterland@Sun.COM #include "pkginstall.h"
779781SMoriah.Waterland@Sun.COM 
789781SMoriah.Waterland@Sun.COM extern int		pkgverbose;
799781SMoriah.Waterland@Sun.COM extern fsblkcnt_t	pkgmap_blks; 		/* main.c */
809781SMoriah.Waterland@Sun.COM 
819781SMoriah.Waterland@Sun.COM extern struct pkgdev pkgdev;
829781SMoriah.Waterland@Sun.COM 
839781SMoriah.Waterland@Sun.COM extern char	tmpdir[];
849781SMoriah.Waterland@Sun.COM extern char	pkgbin[];
859781SMoriah.Waterland@Sun.COM extern char	instdir[];
869781SMoriah.Waterland@Sun.COM extern char	saveSpoolInstallDir[];
879781SMoriah.Waterland@Sun.COM extern char	*pkginst;
889781SMoriah.Waterland@Sun.COM 
899781SMoriah.Waterland@Sun.COM extern int	dbchg;
909781SMoriah.Waterland@Sun.COM extern int	nosetuid;
919781SMoriah.Waterland@Sun.COM extern int	nocnflct;
929781SMoriah.Waterland@Sun.COM extern int	warnflag;
939781SMoriah.Waterland@Sun.COM 
949781SMoriah.Waterland@Sun.COM #define	DMRG_DONE	-1
959781SMoriah.Waterland@Sun.COM 
969781SMoriah.Waterland@Sun.COM #define	ck_efile(s, p)	\
979781SMoriah.Waterland@Sun.COM 		((p->cinfo.modtime >= 0) && \
989781SMoriah.Waterland@Sun.COM 		p->ainfo.local && \
999781SMoriah.Waterland@Sun.COM 		cverify(0, &p->ftype, s, &p->cinfo, 1))
1009781SMoriah.Waterland@Sun.COM 
1019781SMoriah.Waterland@Sun.COM static int	eocflag;
1029781SMoriah.Waterland@Sun.COM 
1039781SMoriah.Waterland@Sun.COM /*
1049781SMoriah.Waterland@Sun.COM  * The variable below indicates that fix_attributes() will be inadequate
1059781SMoriah.Waterland@Sun.COM  * because a replacement was permitted.
1069781SMoriah.Waterland@Sun.COM  */
1079781SMoriah.Waterland@Sun.COM static int	repl_permitted = 0;
1089781SMoriah.Waterland@Sun.COM 
1099781SMoriah.Waterland@Sun.COM static int	domerg(struct cfextra **extlist, int part, int nparts,
1109781SMoriah.Waterland@Sun.COM 			int myclass, char **srcp, char **dstp,
1119781SMoriah.Waterland@Sun.COM 			char **r_updated, char **r_skipped,
1129781SMoriah.Waterland@Sun.COM 			char **r_anyPathLocal);
1139781SMoriah.Waterland@Sun.COM static void	endofclass(struct cfextra **extlist, int myclass,
1149869SCasper.Dik@Sun.COM 			int ckflag, PKGserver server, VFP_T **a_cfTmpVfp);
1159781SMoriah.Waterland@Sun.COM static int	fix_attributes(struct cfextra **, int);
1169781SMoriah.Waterland@Sun.COM static int	dir_is_populated(char *dirpath);
1179781SMoriah.Waterland@Sun.COM static boolean_t absolutepath(char *path);
1189781SMoriah.Waterland@Sun.COM static boolean_t parametricpath(char *path, char **relocpath);
1199781SMoriah.Waterland@Sun.COM 
1209781SMoriah.Waterland@Sun.COM /* Used to keep track of the entries in extlist that are regular files. */
1219781SMoriah.Waterland@Sun.COM struct reg_files {
1229781SMoriah.Waterland@Sun.COM 	struct reg_files *next;
1239781SMoriah.Waterland@Sun.COM 	int val;
1249781SMoriah.Waterland@Sun.COM };
1259781SMoriah.Waterland@Sun.COM static struct reg_files *regfiles_head = NULL;
1269781SMoriah.Waterland@Sun.COM 
1279781SMoriah.Waterland@Sun.COM /*
1289781SMoriah.Waterland@Sun.COM  * This is the function that actually installs one volume (usually that's
1299781SMoriah.Waterland@Sun.COM  * all there is). Upon entry, the extlist is entirely correct:
1309781SMoriah.Waterland@Sun.COM  *
1319781SMoriah.Waterland@Sun.COM  *	1. It contains only those files which are to be installed
1329781SMoriah.Waterland@Sun.COM  *	   from all volumes.
1339781SMoriah.Waterland@Sun.COM  *	2. The mode bits in the ainfo structure for each file are set
1349781SMoriah.Waterland@Sun.COM  *	   correctly in accordance with administrative defaults.
1359781SMoriah.Waterland@Sun.COM  *	3. mstat.setuid/setgid reflect what the status *was* before
1369781SMoriah.Waterland@Sun.COM  *	   pkgdbmerg() processed compliance.
1379781SMoriah.Waterland@Sun.COM  */
1389781SMoriah.Waterland@Sun.COM void
1399781SMoriah.Waterland@Sun.COM instvol(struct cfextra **extlist, char *srcinst, int part,
1409869SCasper.Dik@Sun.COM 	int nparts, PKGserver pkgserver, VFP_T **a_cfTmpVfp,
1419781SMoriah.Waterland@Sun.COM 	char **r_updated, char **r_skipped,
1429781SMoriah.Waterland@Sun.COM 	char *a_zoneName)
1439781SMoriah.Waterland@Sun.COM {
1449781SMoriah.Waterland@Sun.COM 	FILE		*listfp;
1459781SMoriah.Waterland@Sun.COM 	char		*updated = (char *)NULL;
1469781SMoriah.Waterland@Sun.COM 	char		*skipped = (char *)NULL;
1479781SMoriah.Waterland@Sun.COM 	char		*anyPathLocal = (char *)NULL;
1489781SMoriah.Waterland@Sun.COM 	char		*relocpath = (char *)NULL;
1499781SMoriah.Waterland@Sun.COM 	char		*dstp;
1509781SMoriah.Waterland@Sun.COM 	char		*listfile;
1519781SMoriah.Waterland@Sun.COM 	char		*srcp;
1529781SMoriah.Waterland@Sun.COM 	char		*pspool_loc;
1539781SMoriah.Waterland@Sun.COM 	char		scrpt_dst[PATH_MAX];
1549781SMoriah.Waterland@Sun.COM 	int		count;
1559781SMoriah.Waterland@Sun.COM 	int		entryidx;	/* array of current package objects */
1569781SMoriah.Waterland@Sun.COM 	int		n;
1579781SMoriah.Waterland@Sun.COM 	int		nc = 0;
1589781SMoriah.Waterland@Sun.COM 	int		pass;		/* pass count through the for loop. */
1599781SMoriah.Waterland@Sun.COM 	int		tcount;
1609781SMoriah.Waterland@Sun.COM 	struct cfent	*ept;
1619781SMoriah.Waterland@Sun.COM 	struct cfextra	*ext;
1629781SMoriah.Waterland@Sun.COM 	struct mergstat	*mstat;
1639781SMoriah.Waterland@Sun.COM 	struct reg_files *rfp = NULL;
1649781SMoriah.Waterland@Sun.COM 
1659781SMoriah.Waterland@Sun.COM 	/*
1669781SMoriah.Waterland@Sun.COM 	 * r_updated and r_skipped are optional parameters that can be passed in
1679781SMoriah.Waterland@Sun.COM 	 * by the caller if the caller wants to know if any objects are either
1689781SMoriah.Waterland@Sun.COM 	 * updated or skipped. Do not initialize either r_updated or r_skipped;
1699781SMoriah.Waterland@Sun.COM 	 * the call to instvol could be cumulative and any previous update or
1709781SMoriah.Waterland@Sun.COM 	 * skipped indication must not be disturbed - these flags are only set,
1719781SMoriah.Waterland@Sun.COM 	 * they must never be reset. These flags are "char *" pointers so that
1729781SMoriah.Waterland@Sun.COM 	 * the object that was skipped or updated can be displayed in debugging
1739781SMoriah.Waterland@Sun.COM 	 * output.
1749781SMoriah.Waterland@Sun.COM 	 */
1759781SMoriah.Waterland@Sun.COM 
1769781SMoriah.Waterland@Sun.COM 	if (part == 1) {
1779781SMoriah.Waterland@Sun.COM 		pkgvolume(&pkgdev, srcinst, part, nparts);
1789781SMoriah.Waterland@Sun.COM 	}
1799781SMoriah.Waterland@Sun.COM 
1809781SMoriah.Waterland@Sun.COM 	tcount = 0;
1819781SMoriah.Waterland@Sun.COM 	nc = cl_getn();
1829781SMoriah.Waterland@Sun.COM 
1839781SMoriah.Waterland@Sun.COM 	/*
1849781SMoriah.Waterland@Sun.COM 	 * For each class in this volume, install those files.
1859781SMoriah.Waterland@Sun.COM 	 *
1869781SMoriah.Waterland@Sun.COM 	 * NOTE : This loop index may be decremented by code below forcing a
1879781SMoriah.Waterland@Sun.COM 	 * second trip through for the same class. This happens only when a
1889781SMoriah.Waterland@Sun.COM 	 * class is split between an archive and the tree. Examples would be
1899781SMoriah.Waterland@Sun.COM 	 * old WOS packages and the occasional class containing dynamic
1909781SMoriah.Waterland@Sun.COM 	 * libraries which require special treatment.
1919781SMoriah.Waterland@Sun.COM 	 */
1929781SMoriah.Waterland@Sun.COM 
1939781SMoriah.Waterland@Sun.COM 	if (is_depend_pkginfo_DB() == B_FALSE) {
1949781SMoriah.Waterland@Sun.COM 	    int		classidx;	/* the current class */
1959781SMoriah.Waterland@Sun.COM 
1969781SMoriah.Waterland@Sun.COM 	    for (classidx = 0; classidx < nc; classidx++) {
1979781SMoriah.Waterland@Sun.COM 		int pass_relative = 0;
1989781SMoriah.Waterland@Sun.COM 		int rel_init = 0;
1999781SMoriah.Waterland@Sun.COM 
2009781SMoriah.Waterland@Sun.COM 		eocflag = count = pass = 0;
2019781SMoriah.Waterland@Sun.COM 		listfp = (FILE *)0;
2029781SMoriah.Waterland@Sun.COM 		listfile = NULL;
2039781SMoriah.Waterland@Sun.COM 
2049781SMoriah.Waterland@Sun.COM 		/* Now what do we pass to the class action script */
2059781SMoriah.Waterland@Sun.COM 
2069781SMoriah.Waterland@Sun.COM 		if (cl_pthrel(classidx) == REL_2_CAS) {
2079781SMoriah.Waterland@Sun.COM 			pass_relative = 1;
2089781SMoriah.Waterland@Sun.COM 		}
2099781SMoriah.Waterland@Sun.COM 
2109781SMoriah.Waterland@Sun.COM 		for (;;) {
2119781SMoriah.Waterland@Sun.COM 			if (!tcount++) {
2129781SMoriah.Waterland@Sun.COM 				/* first file to install */
2139781SMoriah.Waterland@Sun.COM 				if (a_zoneName == (char *)NULL) {
2149781SMoriah.Waterland@Sun.COM 					echo(MSG_INS_N_N, part, nparts);
2159781SMoriah.Waterland@Sun.COM 				} else {
2169781SMoriah.Waterland@Sun.COM 					echo(MSG_INS_N_N_LZ, part, nparts,
2179781SMoriah.Waterland@Sun.COM 						a_zoneName);
2189781SMoriah.Waterland@Sun.COM 				}
2199781SMoriah.Waterland@Sun.COM 			}
2209781SMoriah.Waterland@Sun.COM 
2219781SMoriah.Waterland@Sun.COM 			/*
2229781SMoriah.Waterland@Sun.COM 			 * If there's an install class action script and no
2239781SMoriah.Waterland@Sun.COM 			 * list file has been created yet, create that file
2249781SMoriah.Waterland@Sun.COM 			 * and provide the pointer in listfp.
2259781SMoriah.Waterland@Sun.COM 			 */
2269781SMoriah.Waterland@Sun.COM 			if (cl_iscript(classidx) && !listfp) {
2279781SMoriah.Waterland@Sun.COM 				/* create list file */
2289781SMoriah.Waterland@Sun.COM 				putparam("TMPDIR", tmpdir);
2299781SMoriah.Waterland@Sun.COM 				listfile = tempnam(tmpdir, "list");
2309781SMoriah.Waterland@Sun.COM 				if ((listfp = fopen(listfile, "w")) == NULL) {
2319781SMoriah.Waterland@Sun.COM 					progerr(ERR_WTMPFILE, listfile);
2329781SMoriah.Waterland@Sun.COM 					quit(99);
2339781SMoriah.Waterland@Sun.COM 				}
2349781SMoriah.Waterland@Sun.COM 			}
2359781SMoriah.Waterland@Sun.COM 
2369781SMoriah.Waterland@Sun.COM 			/*
2379781SMoriah.Waterland@Sun.COM 			 * The following function goes through the package
2389781SMoriah.Waterland@Sun.COM 			 * object list returning the array index of the next
2399781SMoriah.Waterland@Sun.COM 			 * regular file. If it encounters a directory,
2409781SMoriah.Waterland@Sun.COM 			 * symlink, named pipe or device, it just creates it.
2419781SMoriah.Waterland@Sun.COM 			 */
2429781SMoriah.Waterland@Sun.COM 
2439781SMoriah.Waterland@Sun.COM 			entryidx = domerg(extlist, (pass++ ? 0 : part), nparts,
2449781SMoriah.Waterland@Sun.COM 				classidx, &srcp, &dstp, &updated, &skipped,
2459781SMoriah.Waterland@Sun.COM 				&anyPathLocal);
2469781SMoriah.Waterland@Sun.COM 
2479781SMoriah.Waterland@Sun.COM 			/* Evaluate the return code */
2489781SMoriah.Waterland@Sun.COM 			if (entryidx == DMRG_DONE) {
2499781SMoriah.Waterland@Sun.COM 				/*
2509781SMoriah.Waterland@Sun.COM 				 * Set ept to the first entry in extlist
2519781SMoriah.Waterland@Sun.COM 				 * which is guaranteed to exist so
2529781SMoriah.Waterland@Sun.COM 				 * later checks against ept->ftype are
2539781SMoriah.Waterland@Sun.COM 				 * not compared to NULL.
2549781SMoriah.Waterland@Sun.COM 				 */
2559781SMoriah.Waterland@Sun.COM 				ext = extlist[0];
2569781SMoriah.Waterland@Sun.COM 				ept = &(ext->cf_ent);
2579781SMoriah.Waterland@Sun.COM 				break; /* no more entries to process */
2589781SMoriah.Waterland@Sun.COM 			}
2599781SMoriah.Waterland@Sun.COM 
2609781SMoriah.Waterland@Sun.COM 			ext = extlist[entryidx];
2619781SMoriah.Waterland@Sun.COM 			ept = &(ext->cf_ent);
2629781SMoriah.Waterland@Sun.COM 			mstat = &(ext->mstat);
2639781SMoriah.Waterland@Sun.COM 
2649781SMoriah.Waterland@Sun.COM 			/*
2659781SMoriah.Waterland@Sun.COM 			 * If not installing from a partially spooled package
2669781SMoriah.Waterland@Sun.COM 			 * (the "save/pspool" area), and the file contents can
2679781SMoriah.Waterland@Sun.COM 			 * be changed (type is 'e' or 'v'), and the class is not
2689781SMoriah.Waterland@Sun.COM 			 * "none": copy the file from the package (in pristine
2699781SMoriah.Waterland@Sun.COM 			 * state with no actions performed) into the appropriate
2709781SMoriah.Waterland@Sun.COM 			 * location in the packages destination "save/pspool"
2719781SMoriah.Waterland@Sun.COM 			 * area.
2729781SMoriah.Waterland@Sun.COM 			 */
2739781SMoriah.Waterland@Sun.COM 
2749781SMoriah.Waterland@Sun.COM 			if ((!is_partial_inst()) &&
2759781SMoriah.Waterland@Sun.COM 				((ept->ftype == 'e') || (ept->ftype == 'v')) &&
2769781SMoriah.Waterland@Sun.COM 				(strcmp(ept->pkg_class, "none") != 0)) {
2779781SMoriah.Waterland@Sun.COM 
2789781SMoriah.Waterland@Sun.COM 				if (absolutepath(ext->map_path) == B_TRUE &&
2799781SMoriah.Waterland@Sun.COM 					parametricpath(ext->cf_ent.ainfo.local,
2809781SMoriah.Waterland@Sun.COM 						&relocpath) == B_FALSE) {
2819781SMoriah.Waterland@Sun.COM 					pspool_loc = ROOT;
2829781SMoriah.Waterland@Sun.COM 				} else {
2839781SMoriah.Waterland@Sun.COM 					pspool_loc = RELOC;
2849781SMoriah.Waterland@Sun.COM 				}
2859781SMoriah.Waterland@Sun.COM 
2869781SMoriah.Waterland@Sun.COM 				n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s",
2879781SMoriah.Waterland@Sun.COM 					saveSpoolInstallDir, pspool_loc,
2889781SMoriah.Waterland@Sun.COM 					relocpath ? relocpath : ext->map_path);
2899781SMoriah.Waterland@Sun.COM 
2909781SMoriah.Waterland@Sun.COM 				if (n >= PATH_MAX) {
2919781SMoriah.Waterland@Sun.COM 					progerr(ERR_CREATE_PATH_2,
2929781SMoriah.Waterland@Sun.COM 						saveSpoolInstallDir,
2939781SMoriah.Waterland@Sun.COM 						ext->map_path);
2949781SMoriah.Waterland@Sun.COM 					quit(99);
2959781SMoriah.Waterland@Sun.COM 				}
2969781SMoriah.Waterland@Sun.COM 
2979781SMoriah.Waterland@Sun.COM 				/* copy, preserve source file mode */
2989781SMoriah.Waterland@Sun.COM 
2999781SMoriah.Waterland@Sun.COM 				if (cppath(MODE_SRC, srcp, scrpt_dst, 0644)) {
3009781SMoriah.Waterland@Sun.COM 					warnflag++;
3019781SMoriah.Waterland@Sun.COM 				}
3029781SMoriah.Waterland@Sun.COM 			}
3039781SMoriah.Waterland@Sun.COM 
3049781SMoriah.Waterland@Sun.COM 			/*
3059781SMoriah.Waterland@Sun.COM 			 * If this isn't writeable anyway, it's not going
3069781SMoriah.Waterland@Sun.COM 			 * into the list file. Only count it if it's going
3079781SMoriah.Waterland@Sun.COM 			 * into the list file.
3089781SMoriah.Waterland@Sun.COM 			 */
3099781SMoriah.Waterland@Sun.COM 			if (is_fs_writeable(ext->cf_ent.path,
3109781SMoriah.Waterland@Sun.COM 				&(ext->fsys_value)))
3119781SMoriah.Waterland@Sun.COM 				count++;
3129781SMoriah.Waterland@Sun.COM 
3139781SMoriah.Waterland@Sun.COM 			pkgvolume(&pkgdev, srcinst, part, nparts);
3149781SMoriah.Waterland@Sun.COM 
3159781SMoriah.Waterland@Sun.COM 			/*
3169781SMoriah.Waterland@Sun.COM 			 * If source verification is OK for this class, make
3179781SMoriah.Waterland@Sun.COM 			 * sure the source we're passing to the class action
3189781SMoriah.Waterland@Sun.COM 			 * script is useable.
3199781SMoriah.Waterland@Sun.COM 			 */
3209781SMoriah.Waterland@Sun.COM 			if (cl_svfy(classidx) != NOVERIFY) {
3219781SMoriah.Waterland@Sun.COM 				if (cl_iscript(classidx) ||
3229781SMoriah.Waterland@Sun.COM 					((ept->ftype == 'e') ||
3239781SMoriah.Waterland@Sun.COM 					(ept->ftype == 'n'))) {
3249781SMoriah.Waterland@Sun.COM 					if (ck_efile(srcp, ept)) {
3259781SMoriah.Waterland@Sun.COM 						progerr(ERR_CORRUPT,
3269781SMoriah.Waterland@Sun.COM 							srcp);
3279781SMoriah.Waterland@Sun.COM 						logerr(getErrbufAddr());
3289781SMoriah.Waterland@Sun.COM 						warnflag++;
3299781SMoriah.Waterland@Sun.COM 						continue;
3309781SMoriah.Waterland@Sun.COM 					}
3319781SMoriah.Waterland@Sun.COM 				}
3329781SMoriah.Waterland@Sun.COM 			}
3339781SMoriah.Waterland@Sun.COM 
3349781SMoriah.Waterland@Sun.COM 			/*
3359781SMoriah.Waterland@Sun.COM 			 * If there's a class action script for this class,
3369781SMoriah.Waterland@Sun.COM 			 * just collect names in a temporary file
3379781SMoriah.Waterland@Sun.COM 			 * that will be used as the stdin when the
3389781SMoriah.Waterland@Sun.COM 			 * class action script is invoked.
3399781SMoriah.Waterland@Sun.COM 			 */
3409781SMoriah.Waterland@Sun.COM 
3419781SMoriah.Waterland@Sun.COM 			if ((cl_iscript(classidx)) &&
3429781SMoriah.Waterland@Sun.COM 					((is_fs_writeable(ept->path,
3439781SMoriah.Waterland@Sun.COM 						&(ext->fsys_value))))) {
3449781SMoriah.Waterland@Sun.COM 				if (pass_relative) {
3459781SMoriah.Waterland@Sun.COM 					if (!rel_init) {
3469781SMoriah.Waterland@Sun.COM 						(void) fputs(instdir, listfp);
3479781SMoriah.Waterland@Sun.COM 						(void) putc('\n', listfp);
3489781SMoriah.Waterland@Sun.COM 						rel_init++;
3499781SMoriah.Waterland@Sun.COM 					}
3509781SMoriah.Waterland@Sun.COM 					(void) fputs(ext->map_path, listfp);
3519781SMoriah.Waterland@Sun.COM 					(void) putc('\n', listfp);
3529781SMoriah.Waterland@Sun.COM 				} else {
3539781SMoriah.Waterland@Sun.COM 					(void) fputs(srcp ?
3549781SMoriah.Waterland@Sun.COM 						srcp : "/dev/null", listfp);
3559781SMoriah.Waterland@Sun.COM 					(void) putc(' ', listfp);
3569781SMoriah.Waterland@Sun.COM 					(void) fputs(dstp, listfp);
3579781SMoriah.Waterland@Sun.COM 					(void) putc('\n', listfp);
3589781SMoriah.Waterland@Sun.COM 				}
3599781SMoriah.Waterland@Sun.COM 				/*
3609781SMoriah.Waterland@Sun.COM 				 * Note which entries in extlist are regular
3619781SMoriah.Waterland@Sun.COM 				 * files to be installed via the class action
3629781SMoriah.Waterland@Sun.COM 				 * script.
3639781SMoriah.Waterland@Sun.COM 				 */
3649781SMoriah.Waterland@Sun.COM 				if (regfiles_head == NULL) {
3659781SMoriah.Waterland@Sun.COM 					assert(rfp == NULL);
3669781SMoriah.Waterland@Sun.COM 					regfiles_head =
3679781SMoriah.Waterland@Sun.COM 					    malloc(sizeof (struct reg_files));
3689781SMoriah.Waterland@Sun.COM 					if (regfiles_head == NULL) {
3699781SMoriah.Waterland@Sun.COM 						progerr(ERR_MEMORY, errno);
3709781SMoriah.Waterland@Sun.COM 						quit(99);
3719781SMoriah.Waterland@Sun.COM 					}
3729781SMoriah.Waterland@Sun.COM 					regfiles_head->next = NULL;
3739781SMoriah.Waterland@Sun.COM 					regfiles_head->val = entryidx;
3749781SMoriah.Waterland@Sun.COM 					rfp = regfiles_head;
3759781SMoriah.Waterland@Sun.COM 				} else {
3769781SMoriah.Waterland@Sun.COM 					assert(rfp != NULL);
3779781SMoriah.Waterland@Sun.COM 					rfp->next =
3789781SMoriah.Waterland@Sun.COM 					    malloc(sizeof (struct reg_files));
3799781SMoriah.Waterland@Sun.COM 					if (rfp->next == NULL) {
3809781SMoriah.Waterland@Sun.COM 						progerr(ERR_MEMORY, errno);
3819781SMoriah.Waterland@Sun.COM 						quit(99);
3829781SMoriah.Waterland@Sun.COM 					}
3839781SMoriah.Waterland@Sun.COM 					rfp = rfp->next;
3849781SMoriah.Waterland@Sun.COM 					rfp->next = NULL;
3859781SMoriah.Waterland@Sun.COM 					rfp->val = entryidx;
3869781SMoriah.Waterland@Sun.COM 				}
3879781SMoriah.Waterland@Sun.COM 
3889781SMoriah.Waterland@Sun.COM 				/*
3899781SMoriah.Waterland@Sun.COM 				 * A warning message about unwritable targets
3909781SMoriah.Waterland@Sun.COM 				 * in a class may be appropriate here.
3919781SMoriah.Waterland@Sun.COM 				 */
3929781SMoriah.Waterland@Sun.COM 				continue;
3939781SMoriah.Waterland@Sun.COM 			}
3949781SMoriah.Waterland@Sun.COM 
3959781SMoriah.Waterland@Sun.COM 			/*
3969781SMoriah.Waterland@Sun.COM 			 * If not installing from a partially spooled package
3979781SMoriah.Waterland@Sun.COM 			 * (the "save/pspool" area), and the file contents can
3989781SMoriah.Waterland@Sun.COM 			 * be changed (type is 'e' or 'v') and the class
3999781SMoriah.Waterland@Sun.COM 			 * identifier is not "none": copy the file from the
4009781SMoriah.Waterland@Sun.COM 			 * package (in pristine state with no actions performed)
4019781SMoriah.Waterland@Sun.COM 			 * into the appropriate location in the packages
4029781SMoriah.Waterland@Sun.COM 			 * destination "save/pspool" area.
4039781SMoriah.Waterland@Sun.COM 			 */
4049781SMoriah.Waterland@Sun.COM 
4059781SMoriah.Waterland@Sun.COM 			if ((!is_partial_inst()) &&
4069781SMoriah.Waterland@Sun.COM 			    ((ept->ftype == 'e') || (ept->ftype == 'v') &&
4079781SMoriah.Waterland@Sun.COM 			    (strcmp(ept->pkg_class, "none") != 0))) {
4089781SMoriah.Waterland@Sun.COM 
4099781SMoriah.Waterland@Sun.COM 				if (absolutepath(ext->map_path) == B_TRUE &&
4109781SMoriah.Waterland@Sun.COM 					parametricpath(ext->cf_ent.ainfo.local,
4119781SMoriah.Waterland@Sun.COM 						&relocpath) == B_FALSE) {
4129781SMoriah.Waterland@Sun.COM 					pspool_loc = ROOT;
4139781SMoriah.Waterland@Sun.COM 				} else {
4149781SMoriah.Waterland@Sun.COM 					pspool_loc = RELOC;
4159781SMoriah.Waterland@Sun.COM 				}
4169781SMoriah.Waterland@Sun.COM 
4179781SMoriah.Waterland@Sun.COM 				n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s",
4189781SMoriah.Waterland@Sun.COM 					saveSpoolInstallDir, pspool_loc,
4199781SMoriah.Waterland@Sun.COM 					relocpath ? relocpath : ext->map_path);
4209781SMoriah.Waterland@Sun.COM 
4219781SMoriah.Waterland@Sun.COM 				if (n >= PATH_MAX) {
4229781SMoriah.Waterland@Sun.COM 					progerr(ERR_CREATE_PATH_2,
4239781SMoriah.Waterland@Sun.COM 						saveSpoolInstallDir,
4249781SMoriah.Waterland@Sun.COM 						ext->map_path);
4259781SMoriah.Waterland@Sun.COM 					quit(99);
4269781SMoriah.Waterland@Sun.COM 				}
4279781SMoriah.Waterland@Sun.COM 
4289781SMoriah.Waterland@Sun.COM 				/* copy, preserve source file mode */
4299781SMoriah.Waterland@Sun.COM 
4309781SMoriah.Waterland@Sun.COM 				if (cppath(MODE_SRC, srcp, scrpt_dst, 0644)) {
4319781SMoriah.Waterland@Sun.COM 					warnflag++;
4329781SMoriah.Waterland@Sun.COM 				}
4339781SMoriah.Waterland@Sun.COM 			}
4349781SMoriah.Waterland@Sun.COM 
4359781SMoriah.Waterland@Sun.COM 			/*
4369781SMoriah.Waterland@Sun.COM 			 * There are several tests here to determine
4379781SMoriah.Waterland@Sun.COM 			 * how we're going to deal with objects
4389781SMoriah.Waterland@Sun.COM 			 * intended for remote read-only filesystems.
4399781SMoriah.Waterland@Sun.COM 			 * We don't use is_served() because this may be
4409781SMoriah.Waterland@Sun.COM 			 * a server. We're actually interested in if
4419781SMoriah.Waterland@Sun.COM 			 * it's *really* remote and *really* not
4429781SMoriah.Waterland@Sun.COM 			 * writeable.
4439781SMoriah.Waterland@Sun.COM 			 */
4449781SMoriah.Waterland@Sun.COM 
4459781SMoriah.Waterland@Sun.COM 			n = is_remote_fs(ept->path, &(ext->fsys_value));
4469781SMoriah.Waterland@Sun.COM 			if ((n != 0) &&
4479781SMoriah.Waterland@Sun.COM 				!is_fs_writeable(ept->path,
4489781SMoriah.Waterland@Sun.COM 				&(ext->fsys_value))) {
4499781SMoriah.Waterland@Sun.COM 
4509781SMoriah.Waterland@Sun.COM 				/*
4519781SMoriah.Waterland@Sun.COM 				 * Don't change the file, we can't write
4529781SMoriah.Waterland@Sun.COM 				 * to it anyway.
4539781SMoriah.Waterland@Sun.COM 				 */
4549781SMoriah.Waterland@Sun.COM 
4559781SMoriah.Waterland@Sun.COM 				mstat->attrchg = 0;
4569781SMoriah.Waterland@Sun.COM 				mstat->contchg = 0;
4579781SMoriah.Waterland@Sun.COM 
4589781SMoriah.Waterland@Sun.COM 				/*
4599781SMoriah.Waterland@Sun.COM 				 * If it's currently mounted, we can
4609781SMoriah.Waterland@Sun.COM 				 * at least test it for existence.
4619781SMoriah.Waterland@Sun.COM 				 */
4629781SMoriah.Waterland@Sun.COM 
4639781SMoriah.Waterland@Sun.COM 				if (is_mounted(ept->path, &(ext->fsys_value))) {
4649781SMoriah.Waterland@Sun.COM 					if (!isfile(NULL, dstp)) {
4659781SMoriah.Waterland@Sun.COM 						echo(MSG_IS_PRESENT, dstp);
4669781SMoriah.Waterland@Sun.COM 					} else {
4679781SMoriah.Waterland@Sun.COM 						echo(WRN_INSTVOL_NONE, dstp);
4689781SMoriah.Waterland@Sun.COM 					}
4699781SMoriah.Waterland@Sun.COM 				} else {
4709781SMoriah.Waterland@Sun.COM 					char *server_host;
4719781SMoriah.Waterland@Sun.COM 
4729781SMoriah.Waterland@Sun.COM 					server_host = get_server_host(
4739781SMoriah.Waterland@Sun.COM 						ext->fsys_value);
4749781SMoriah.Waterland@Sun.COM 
4759781SMoriah.Waterland@Sun.COM 					/* If not, we're just stuck. */
4769781SMoriah.Waterland@Sun.COM 					echo(WRN_INSTVOL_NOVERIFY,
4779781SMoriah.Waterland@Sun.COM 						dstp, server_host);
4789781SMoriah.Waterland@Sun.COM 				}
4799781SMoriah.Waterland@Sun.COM 
4809781SMoriah.Waterland@Sun.COM 				continue;
4819781SMoriah.Waterland@Sun.COM 			}
4829781SMoriah.Waterland@Sun.COM 
4839781SMoriah.Waterland@Sun.COM 			/* echo output destination name */
4849781SMoriah.Waterland@Sun.COM 
4859781SMoriah.Waterland@Sun.COM 			echo("%s", dstp);
4869781SMoriah.Waterland@Sun.COM 
4879781SMoriah.Waterland@Sun.COM 			/*
4889781SMoriah.Waterland@Sun.COM 			 * if no source then no need to copy/verify
4899781SMoriah.Waterland@Sun.COM 			 */
4909781SMoriah.Waterland@Sun.COM 
4919781SMoriah.Waterland@Sun.COM 			if (srcp == (char *)NULL) {
4929781SMoriah.Waterland@Sun.COM 				continue;
4939781SMoriah.Waterland@Sun.COM 			}
4949781SMoriah.Waterland@Sun.COM 
4959781SMoriah.Waterland@Sun.COM 			/*
4969781SMoriah.Waterland@Sun.COM 			 * If doing a partial installation (creating a
4979781SMoriah.Waterland@Sun.COM 			 * non-global zone), extra steps need to be taken:
4989781SMoriah.Waterland@Sun.COM 			 *
4999781SMoriah.Waterland@Sun.COM 			 * 1) if the file is not type 'e' and not type 'v' and
5009781SMoriah.Waterland@Sun.COM 			 * the class is "none": then the file must already
5019781SMoriah.Waterland@Sun.COM 			 * exist (as a result of the initial non-global zone
5029781SMoriah.Waterland@Sun.COM 			 * installation which caused all non-e/v files to be
5039781SMoriah.Waterland@Sun.COM 			 * copied from the global zone to the non-global
5049781SMoriah.Waterland@Sun.COM 			 * zone). If this is the case, verify that the file
5059781SMoriah.Waterland@Sun.COM 			 * exists and has the correct attributes.
5069781SMoriah.Waterland@Sun.COM 			 *
5079781SMoriah.Waterland@Sun.COM 			 * 2) if the file is not type 'e' and not type 'v'
5089781SMoriah.Waterland@Sun.COM 			 * and the class is NOT "none", *OR* if the file is
5099781SMoriah.Waterland@Sun.COM 			 * type 'e' or type 'v': then check to see if the
5109781SMoriah.Waterland@Sun.COM 			 * file is located in an area inherited from the
5119781SMoriah.Waterland@Sun.COM 			 * global zone. If so, then there is no ability to
5129781SMoriah.Waterland@Sun.COM 			 * change the file since inherited file systems are
5139781SMoriah.Waterland@Sun.COM 			 * "read only" - just verify that the file exists and
5149781SMoriah.Waterland@Sun.COM 			 * verify attributes only if not 'e' or 'v'.
5159781SMoriah.Waterland@Sun.COM 			 */
5169781SMoriah.Waterland@Sun.COM 
5179781SMoriah.Waterland@Sun.COM 			if (is_partial_inst() != 0) {
5189781SMoriah.Waterland@Sun.COM 
5199781SMoriah.Waterland@Sun.COM 				/*
5209781SMoriah.Waterland@Sun.COM 				 * determine if the destination package is in an
5219781SMoriah.Waterland@Sun.COM 				 * area inherited from the global zone
5229781SMoriah.Waterland@Sun.COM 				 */
5239781SMoriah.Waterland@Sun.COM 
5249781SMoriah.Waterland@Sun.COM 				n = pkgMatchInherited(srcp, dstp,
5259781SMoriah.Waterland@Sun.COM 					get_inst_root(), ept->ainfo.mode,
5269781SMoriah.Waterland@Sun.COM 					ept->cinfo.modtime, ept->ftype,
5279781SMoriah.Waterland@Sun.COM 					ept->cinfo.cksum);
5289781SMoriah.Waterland@Sun.COM 
5299781SMoriah.Waterland@Sun.COM 				echoDebug(DBG_INSTVOL_PARTIAL_INST,
5309781SMoriah.Waterland@Sun.COM 					srcp ? srcp : "", dstp ? dstp: "",
5319781SMoriah.Waterland@Sun.COM 					((get_inst_root()) &&
5329781SMoriah.Waterland@Sun.COM 					(strcmp(get_inst_root(), "/") != 0)) ?
5339781SMoriah.Waterland@Sun.COM 					get_inst_root() : "",
5349781SMoriah.Waterland@Sun.COM 					ept->ainfo.mode, ept->cinfo.modtime,
5359781SMoriah.Waterland@Sun.COM 					ept->ftype, ept->cinfo.cksum, n);
5369781SMoriah.Waterland@Sun.COM 
5379781SMoriah.Waterland@Sun.COM 				/*
5389781SMoriah.Waterland@Sun.COM 				 * if not type 'e|v' and class 'none', then the
5399781SMoriah.Waterland@Sun.COM 				 * file must already exist.
5409781SMoriah.Waterland@Sun.COM 				 */
5419781SMoriah.Waterland@Sun.COM 
5429781SMoriah.Waterland@Sun.COM 				if ((ept->ftype != 'e') &&
5439781SMoriah.Waterland@Sun.COM 					(ept->ftype != 'v') &&
5449781SMoriah.Waterland@Sun.COM 					(strcmp(cl_nam(ept->pkg_class_idx),
5459781SMoriah.Waterland@Sun.COM 								"none") == 0)) {
5469781SMoriah.Waterland@Sun.COM 
5479781SMoriah.Waterland@Sun.COM 					/*
5489781SMoriah.Waterland@Sun.COM 					 * if the file is in a space inherited
5499781SMoriah.Waterland@Sun.COM 					 * from the global zone, and if the
5509781SMoriah.Waterland@Sun.COM 					 * contents or attributes are incorrect,
5519781SMoriah.Waterland@Sun.COM 					 * then generate a warning that the
5529781SMoriah.Waterland@Sun.COM 					 * global zone file contents and/or file
5539781SMoriah.Waterland@Sun.COM 					 * attributes have been modified and
5549781SMoriah.Waterland@Sun.COM 					 * that the modifications are extended
5559781SMoriah.Waterland@Sun.COM 					 * to the non-global zone (inherited
5569781SMoriah.Waterland@Sun.COM 					 * from the global zone).
5579781SMoriah.Waterland@Sun.COM 					 */
5589781SMoriah.Waterland@Sun.COM 
5599781SMoriah.Waterland@Sun.COM 					if (n == 0) {
5609781SMoriah.Waterland@Sun.COM 						/* is file changed? */
5619781SMoriah.Waterland@Sun.COM 						n = finalck(ept, 1, 1, B_TRUE);
5629781SMoriah.Waterland@Sun.COM 
5639781SMoriah.Waterland@Sun.COM 						/* no - ok - continue */
5649781SMoriah.Waterland@Sun.COM 						if (n == 0) {
5659781SMoriah.Waterland@Sun.COM 							continue;
5669781SMoriah.Waterland@Sun.COM 						}
5679781SMoriah.Waterland@Sun.COM 
5689781SMoriah.Waterland@Sun.COM 						/* output warning message */
5699781SMoriah.Waterland@Sun.COM 						logerr(NOTE_INSTVOL_FINALCKFAIL,
5709781SMoriah.Waterland@Sun.COM 							pkginst, ext->map_path,
5719781SMoriah.Waterland@Sun.COM 							a_zoneName, ept->path);
5729781SMoriah.Waterland@Sun.COM 						continue;
5739781SMoriah.Waterland@Sun.COM 					} else if (!finalck(ept, 1, 1,
5749781SMoriah.Waterland@Sun.COM 								B_FALSE)) {
5759781SMoriah.Waterland@Sun.COM 						/*
5769781SMoriah.Waterland@Sun.COM 						 * non-e/v file of class "none"
5779781SMoriah.Waterland@Sun.COM 						 * not inherited from the global
5789781SMoriah.Waterland@Sun.COM 						 * zone: verify file already
5799781SMoriah.Waterland@Sun.COM 						 * exists:everything checks here
5809781SMoriah.Waterland@Sun.COM 						 */
5819781SMoriah.Waterland@Sun.COM 						mstat->attrchg = 0;
5829781SMoriah.Waterland@Sun.COM 						mstat->contchg = 0;
5839781SMoriah.Waterland@Sun.COM 					}
5849781SMoriah.Waterland@Sun.COM 					continue;
5859781SMoriah.Waterland@Sun.COM 				}
5869781SMoriah.Waterland@Sun.COM 
5879781SMoriah.Waterland@Sun.COM 				/*
5889781SMoriah.Waterland@Sun.COM 				 * non-e/v file with class action script, or
5899781SMoriah.Waterland@Sun.COM 				 * e/v file: if the file is in an area inherited
5909781SMoriah.Waterland@Sun.COM 				 * from the global zone, then no need (or the
5919781SMoriah.Waterland@Sun.COM 				 * ability) to update just accept the file as is
5929781SMoriah.Waterland@Sun.COM 				 */
5939781SMoriah.Waterland@Sun.COM 
5949781SMoriah.Waterland@Sun.COM 				if (n == B_TRUE) {
5959781SMoriah.Waterland@Sun.COM 					/*
5969781SMoriah.Waterland@Sun.COM 					 * the object is in an area inherited
5979781SMoriah.Waterland@Sun.COM 					 * from the global zone and the objects
5989781SMoriah.Waterland@Sun.COM 					 * attributes are verified
5999781SMoriah.Waterland@Sun.COM 					 */
6009781SMoriah.Waterland@Sun.COM 
6019781SMoriah.Waterland@Sun.COM 					mstat->attrchg = 0;
6029781SMoriah.Waterland@Sun.COM 					mstat->contchg = 0;
6039781SMoriah.Waterland@Sun.COM 
6049781SMoriah.Waterland@Sun.COM 					/* NOTE: package object skipped */
6059781SMoriah.Waterland@Sun.COM 
6069781SMoriah.Waterland@Sun.COM 					if (skipped == (char *)NULL) {
6079781SMoriah.Waterland@Sun.COM 						skipped = dstp;
6089781SMoriah.Waterland@Sun.COM 					echoDebug(DBG_INSTVOL_OBJ_SKIPPED,
6099781SMoriah.Waterland@Sun.COM 								skipped);
6109781SMoriah.Waterland@Sun.COM 					}
6119781SMoriah.Waterland@Sun.COM 					continue;
6129781SMoriah.Waterland@Sun.COM 				}
6139781SMoriah.Waterland@Sun.COM 			}
6149781SMoriah.Waterland@Sun.COM 
6159781SMoriah.Waterland@Sun.COM 			/*
6169781SMoriah.Waterland@Sun.COM 			 * Copy from source media to target path and fix file
6179781SMoriah.Waterland@Sun.COM 			 * mode and permission now in case installation halted.
6189781SMoriah.Waterland@Sun.COM 			 */
6199781SMoriah.Waterland@Sun.COM 
6209781SMoriah.Waterland@Sun.COM 			if (z_path_is_inherited(dstp, ept->ftype,
6219781SMoriah.Waterland@Sun.COM 			    get_inst_root()) == B_FALSE) {
6229781SMoriah.Waterland@Sun.COM 
6239781SMoriah.Waterland@Sun.COM 				/*
6249781SMoriah.Waterland@Sun.COM 				 * If the filesystem is read-only don't attempt
6259781SMoriah.Waterland@Sun.COM 				 * to copy a file. Just check that the content
6269781SMoriah.Waterland@Sun.COM 				 * and attributes of the file are correct.
6279781SMoriah.Waterland@Sun.COM 				 *
6289781SMoriah.Waterland@Sun.COM 				 * Normally this doesn't happen, because files,
6299781SMoriah.Waterland@Sun.COM 				 * which don't change, are not returned by
6309781SMoriah.Waterland@Sun.COM 				 * domerg(). However when installing a patch in
6319781SMoriah.Waterland@Sun.COM 				 * a sparse zone, which was already installed
6329781SMoriah.Waterland@Sun.COM 				 * in global zone with -G option, NGZ's
6339781SMoriah.Waterland@Sun.COM 				 * contents db still contains the old record
6349781SMoriah.Waterland@Sun.COM 				 * for this file and therefore domerg()
6359781SMoriah.Waterland@Sun.COM 				 * considers these files to be different even
6369781SMoriah.Waterland@Sun.COM 				 * though they are the same.
6379781SMoriah.Waterland@Sun.COM 				 */
6389781SMoriah.Waterland@Sun.COM 				n = 0;
6399781SMoriah.Waterland@Sun.COM 				if (is_fs_writeable(ept->path,
6409781SMoriah.Waterland@Sun.COM 				    &(ext->fsys_value)))
6419781SMoriah.Waterland@Sun.COM 					n = cppath(MODE_SET|DIR_DISPLAY, srcp,
6429781SMoriah.Waterland@Sun.COM 					    dstp, ept->ainfo.mode);
6439781SMoriah.Waterland@Sun.COM 
6449781SMoriah.Waterland@Sun.COM 				if (n != 0) {
6459781SMoriah.Waterland@Sun.COM 					warnflag++;
6469781SMoriah.Waterland@Sun.COM 				} else if (!finalck(ept, 1, 1, B_FALSE)) {
6479781SMoriah.Waterland@Sun.COM 					/*
6489781SMoriah.Waterland@Sun.COM 					 * everything checks here
6499781SMoriah.Waterland@Sun.COM 					 */
6509781SMoriah.Waterland@Sun.COM 					mstat->attrchg = 0;
6519781SMoriah.Waterland@Sun.COM 					mstat->contchg = 0;
6529781SMoriah.Waterland@Sun.COM 				}
6539781SMoriah.Waterland@Sun.COM 			}
6549781SMoriah.Waterland@Sun.COM 
6559781SMoriah.Waterland@Sun.COM 			/* NOTE: a package object was updated */
6569781SMoriah.Waterland@Sun.COM 
6579781SMoriah.Waterland@Sun.COM 			if (updated == (char *)NULL) {
6589781SMoriah.Waterland@Sun.COM 				echoDebug(DBG_INSTVOL_OBJ_UPDATED, dstp);
6599781SMoriah.Waterland@Sun.COM 				updated = dstp;
6609781SMoriah.Waterland@Sun.COM 			}
6619781SMoriah.Waterland@Sun.COM 		}
6629781SMoriah.Waterland@Sun.COM 
6639781SMoriah.Waterland@Sun.COM 		/*
6649781SMoriah.Waterland@Sun.COM 		 * We have now completed processing of all pathnames
6659781SMoriah.Waterland@Sun.COM 		 * associated with this volume and class.
6669781SMoriah.Waterland@Sun.COM 		 */
6679781SMoriah.Waterland@Sun.COM 		if (cl_iscript(classidx)) {
6689781SMoriah.Waterland@Sun.COM 			/*
6699781SMoriah.Waterland@Sun.COM 			 * Execute appropriate class action script
6709781SMoriah.Waterland@Sun.COM 			 * with list of source/destination pathnames
6719781SMoriah.Waterland@Sun.COM 			 * as the input to the script.
6729781SMoriah.Waterland@Sun.COM 			 */
6739781SMoriah.Waterland@Sun.COM 
6749781SMoriah.Waterland@Sun.COM 			if (chdir(pkgbin)) {
6759781SMoriah.Waterland@Sun.COM 				progerr(ERR_CHGDIR, pkgbin);
6769781SMoriah.Waterland@Sun.COM 				quit(99);
6779781SMoriah.Waterland@Sun.COM 			}
6789781SMoriah.Waterland@Sun.COM 
6799781SMoriah.Waterland@Sun.COM 			if (listfp) {
6809781SMoriah.Waterland@Sun.COM 				(void) fclose(listfp);
6819781SMoriah.Waterland@Sun.COM 			}
6829781SMoriah.Waterland@Sun.COM 
6839781SMoriah.Waterland@Sun.COM 			/*
6849781SMoriah.Waterland@Sun.COM 			 * if the object associated with the class action script
6859781SMoriah.Waterland@Sun.COM 			 * is in an area inherited from the global zone, then
6869781SMoriah.Waterland@Sun.COM 			 * there is no need to run the class action script -
6879781SMoriah.Waterland@Sun.COM 			 * assume that anything the script would do has already
6889781SMoriah.Waterland@Sun.COM 			 * been done in the area shared from the global zone.
6899781SMoriah.Waterland@Sun.COM 			 */
6909781SMoriah.Waterland@Sun.COM 
6919781SMoriah.Waterland@Sun.COM 			/* nothing updated, nothing skipped */
6929781SMoriah.Waterland@Sun.COM 
6939781SMoriah.Waterland@Sun.COM 			echoDebug(DBG_INSTVOL_CAS_INFO, is_partial_inst(),
6949781SMoriah.Waterland@Sun.COM 				updated ? updated : "",
6959781SMoriah.Waterland@Sun.COM 				skipped ? skipped : "",
6969781SMoriah.Waterland@Sun.COM 				anyPathLocal ? anyPathLocal : "");
6979781SMoriah.Waterland@Sun.COM 
6989781SMoriah.Waterland@Sun.COM 			if ((is_partial_inst() != 0) &&
6999781SMoriah.Waterland@Sun.COM 					(updated == (char *)NULL) &&
7009781SMoriah.Waterland@Sun.COM 					(anyPathLocal == (char *)NULL)) {
7019781SMoriah.Waterland@Sun.COM 
7029781SMoriah.Waterland@Sun.COM 				/*
7039781SMoriah.Waterland@Sun.COM 				 * installing in non-global zone, and no object
7049781SMoriah.Waterland@Sun.COM 				 * has been updated (installed/verified in non-
7059781SMoriah.Waterland@Sun.COM 				 * inherited area), and no path delivered by the
7069781SMoriah.Waterland@Sun.COM 				 * package is in an area not inherited from the
7079781SMoriah.Waterland@Sun.COM 				 * global zone (all paths delivered are in
7089781SMoriah.Waterland@Sun.COM 				 * areas inherited from the global zone): do not
7099781SMoriah.Waterland@Sun.COM 				 * run the class action script because the only
7109781SMoriah.Waterland@Sun.COM 				 * affected areas are inherited (read only).
7119781SMoriah.Waterland@Sun.COM 				 */
7129781SMoriah.Waterland@Sun.COM 
7139781SMoriah.Waterland@Sun.COM 				echoDebug(DBG_INSTVOL_NOT_RUNNING_CAS,
7149781SMoriah.Waterland@Sun.COM 					a_zoneName ? a_zoneName : "?",
7159781SMoriah.Waterland@Sun.COM 					eocflag ? "ENDOFCLASS" :
7169781SMoriah.Waterland@Sun.COM 							cl_iscript(classidx),
7179781SMoriah.Waterland@Sun.COM 					cl_nam(classidx),
7189781SMoriah.Waterland@Sun.COM 					cl_iscript(classidx));
7199781SMoriah.Waterland@Sun.COM 
7209781SMoriah.Waterland@Sun.COM 				if ((r_skipped != (char **)NULL) &&
7219781SMoriah.Waterland@Sun.COM 					(*r_skipped == (char *)NULL) &&
7229781SMoriah.Waterland@Sun.COM 					(skipped == (char *)NULL)) {
7239781SMoriah.Waterland@Sun.COM 					skipped = "postinstall";
7249781SMoriah.Waterland@Sun.COM 					echoDebug(DBG_INSTVOL_OBJ_SKIPPED,
7259781SMoriah.Waterland@Sun.COM 								skipped);
7269781SMoriah.Waterland@Sun.COM 				}
7279781SMoriah.Waterland@Sun.COM 			} else {
7289781SMoriah.Waterland@Sun.COM 				/* run the class action script */
7299781SMoriah.Waterland@Sun.COM 
7309781SMoriah.Waterland@Sun.COM 				echoDebug(DBG_INSTVOL_RUNNING_CAS,
7319781SMoriah.Waterland@Sun.COM 					a_zoneName ? a_zoneName : "?",
7329781SMoriah.Waterland@Sun.COM 					eocflag ? "ENDOFCLASS" :
7339781SMoriah.Waterland@Sun.COM 							cl_iscript(classidx),
7349781SMoriah.Waterland@Sun.COM 					cl_nam(classidx),
7359781SMoriah.Waterland@Sun.COM 					cl_iscript(classidx));
7369781SMoriah.Waterland@Sun.COM 
7379781SMoriah.Waterland@Sun.COM 				/* Use ULIMIT if supplied. */
7389781SMoriah.Waterland@Sun.COM 				set_ulimit(cl_iscript(classidx), ERR_CASFAIL);
7399781SMoriah.Waterland@Sun.COM 
7409781SMoriah.Waterland@Sun.COM 				if (eocflag) {
7419781SMoriah.Waterland@Sun.COM 					/*
7429781SMoriah.Waterland@Sun.COM 					 * end of class detected.
7439781SMoriah.Waterland@Sun.COM 					 * Since there are no more volumes which
7449781SMoriah.Waterland@Sun.COM 					 * contain pathnames associated with
7459781SMoriah.Waterland@Sun.COM 					 * this class, execute class action
7469781SMoriah.Waterland@Sun.COM 					 * script with the ENDOFCLASS argument;
7479781SMoriah.Waterland@Sun.COM 					 * we do this even if none of the path
7489781SMoriah.Waterland@Sun.COM 					 * names associated with this class and
7499781SMoriah.Waterland@Sun.COM 					 * volume needed installation to
7509781SMoriah.Waterland@Sun.COM 					 * guarantee the class action script is
7519781SMoriah.Waterland@Sun.COM 					 * executed at least once during package
7529781SMoriah.Waterland@Sun.COM 					 * installation.
7539781SMoriah.Waterland@Sun.COM 					 */
7549781SMoriah.Waterland@Sun.COM 					if (pkgverbose) {
7559781SMoriah.Waterland@Sun.COM 						n = pkgexecl((listfp ?
7569781SMoriah.Waterland@Sun.COM 							listfile : CAS_STDIN),
7579781SMoriah.Waterland@Sun.COM 							CAS_STDOUT,
7589781SMoriah.Waterland@Sun.COM 							CAS_USER, CAS_GRP,
7599781SMoriah.Waterland@Sun.COM 							SHELL, "-x",
7609781SMoriah.Waterland@Sun.COM 							cl_iscript(classidx),
7619781SMoriah.Waterland@Sun.COM 							"ENDOFCLASS", NULL);
7629781SMoriah.Waterland@Sun.COM 					} else {
7639781SMoriah.Waterland@Sun.COM 						n = pkgexecl(
7649781SMoriah.Waterland@Sun.COM 							(listfp ?
7659781SMoriah.Waterland@Sun.COM 							listfile : CAS_STDIN),
7669781SMoriah.Waterland@Sun.COM 							CAS_STDOUT, CAS_USER,
7679781SMoriah.Waterland@Sun.COM 							CAS_GRP, SHELL,
7689781SMoriah.Waterland@Sun.COM 							cl_iscript(classidx),
7699781SMoriah.Waterland@Sun.COM 							"ENDOFCLASS", NULL);
7709781SMoriah.Waterland@Sun.COM 					}
7719781SMoriah.Waterland@Sun.COM 					ckreturn(n, ERR_CASFAIL);
7729781SMoriah.Waterland@Sun.COM 				} else if (count) {
7739781SMoriah.Waterland@Sun.COM 					/* execute class action script */
7749781SMoriah.Waterland@Sun.COM 					if (pkgverbose) {
7759781SMoriah.Waterland@Sun.COM 						n = pkgexecl(listfile,
7769781SMoriah.Waterland@Sun.COM 							CAS_STDOUT, CAS_USER,
7779781SMoriah.Waterland@Sun.COM 							CAS_GRP, SHELL, "-x",
7789781SMoriah.Waterland@Sun.COM 							cl_iscript(classidx),
7799781SMoriah.Waterland@Sun.COM 							NULL);
7809781SMoriah.Waterland@Sun.COM 					} else {
7819781SMoriah.Waterland@Sun.COM 						n = pkgexecl(listfile,
7829781SMoriah.Waterland@Sun.COM 							CAS_STDOUT, CAS_USER,
7839781SMoriah.Waterland@Sun.COM 							CAS_GRP, SHELL,
7849781SMoriah.Waterland@Sun.COM 							cl_iscript(classidx),
7859781SMoriah.Waterland@Sun.COM 							NULL);
7869781SMoriah.Waterland@Sun.COM 					}
7879781SMoriah.Waterland@Sun.COM 					ckreturn(n, ERR_CASFAIL);
7889781SMoriah.Waterland@Sun.COM 				}
7899781SMoriah.Waterland@Sun.COM 
7909781SMoriah.Waterland@Sun.COM 				/*
7919781SMoriah.Waterland@Sun.COM 				 * Ensure the mod times on disk match those
7929781SMoriah.Waterland@Sun.COM 				 * in the pkgmap. In this case, call cverify
7939781SMoriah.Waterland@Sun.COM 				 * with checksumming disabled, since the only
7949781SMoriah.Waterland@Sun.COM 				 * action that needs to be done is to verify
7959781SMoriah.Waterland@Sun.COM 				 * that the attributes are correct.
7969781SMoriah.Waterland@Sun.COM 				 */
7979781SMoriah.Waterland@Sun.COM 
7989781SMoriah.Waterland@Sun.COM 				if ((rfp = regfiles_head) != NULL) {
7999781SMoriah.Waterland@Sun.COM 					while (rfp != NULL) {
8009781SMoriah.Waterland@Sun.COM 					    ept = &(extlist[rfp->val]->cf_ent);
8019781SMoriah.Waterland@Sun.COM 					    cverify(1, &ept->ftype, ept->path,
8029781SMoriah.Waterland@Sun.COM 						&ept->cinfo, 0);
8039781SMoriah.Waterland@Sun.COM 					    rfp = rfp->next;
8049781SMoriah.Waterland@Sun.COM 					}
8059781SMoriah.Waterland@Sun.COM 					regfiles_free();
8069781SMoriah.Waterland@Sun.COM 				}
8079781SMoriah.Waterland@Sun.COM 
8089781SMoriah.Waterland@Sun.COM 				clr_ulimit();
8099781SMoriah.Waterland@Sun.COM 
8109781SMoriah.Waterland@Sun.COM 				if ((r_updated != (char **)NULL) &&
8119781SMoriah.Waterland@Sun.COM 					(*r_updated == (char *)NULL) &&
8129781SMoriah.Waterland@Sun.COM 					(updated == (char *)NULL)) {
8139781SMoriah.Waterland@Sun.COM 					updated = "postinstall";
8149781SMoriah.Waterland@Sun.COM 					echoDebug(DBG_INSTVOL_OBJ_UPDATED,
8159781SMoriah.Waterland@Sun.COM 								updated);
8169781SMoriah.Waterland@Sun.COM 				}
8179781SMoriah.Waterland@Sun.COM 			}
8189781SMoriah.Waterland@Sun.COM 			if (listfile) {
8199781SMoriah.Waterland@Sun.COM 				(void) remove(listfile);
8209781SMoriah.Waterland@Sun.COM 			}
8219781SMoriah.Waterland@Sun.COM 		}
8229781SMoriah.Waterland@Sun.COM 
8239781SMoriah.Waterland@Sun.COM 		if (eocflag && (!is_partial_inst() || (is_partial_inst() &&
8249781SMoriah.Waterland@Sun.COM 			strcmp(cl_nam(classidx), "none") != 0))) {
8259781SMoriah.Waterland@Sun.COM 			if (cl_dvfy(classidx) == QKVERIFY && !repl_permitted) {
8269781SMoriah.Waterland@Sun.COM 				/*
8279781SMoriah.Waterland@Sun.COM 				 * The quick verify just fixes everything.
8289781SMoriah.Waterland@Sun.COM 				 * If it returns 0, all is well. If it
8299781SMoriah.Waterland@Sun.COM 				 * returns 1, then the class installation
8309781SMoriah.Waterland@Sun.COM 				 * was incomplete and we retry on the
8319781SMoriah.Waterland@Sun.COM 				 * stuff that failed in the conventional
8329781SMoriah.Waterland@Sun.COM 				 * way (without a CAS). this is primarily
8339781SMoriah.Waterland@Sun.COM 				 * to accomodate old archives such as are
8349781SMoriah.Waterland@Sun.COM 				 * found in pre-2.5 WOS; but, it is also
8359781SMoriah.Waterland@Sun.COM 				 * used when a critical dynamic library
8369781SMoriah.Waterland@Sun.COM 				 * is not archived with its class.
8379781SMoriah.Waterland@Sun.COM 				 */
8389781SMoriah.Waterland@Sun.COM 				if (!fix_attributes(extlist, classidx)) {
8399781SMoriah.Waterland@Sun.COM 					/*
8409781SMoriah.Waterland@Sun.COM 					 * Reset the CAS pointer. If the
8419781SMoriah.Waterland@Sun.COM 					 * function returns 0 then there
8429781SMoriah.Waterland@Sun.COM 					 * was no script there in the first
8439781SMoriah.Waterland@Sun.COM 					 * place and we'll just have to
8449781SMoriah.Waterland@Sun.COM 					 * call this a miss.
8459781SMoriah.Waterland@Sun.COM 					 */
8469781SMoriah.Waterland@Sun.COM 					if (cl_deliscript(classidx))
8479781SMoriah.Waterland@Sun.COM 						/*
8489781SMoriah.Waterland@Sun.COM 						 * Decrement classidx for
8499781SMoriah.Waterland@Sun.COM 						 * next pass.
8509781SMoriah.Waterland@Sun.COM 						 */
8519781SMoriah.Waterland@Sun.COM 						classidx--;
8529781SMoriah.Waterland@Sun.COM 				}
8539781SMoriah.Waterland@Sun.COM 			} else {
8549781SMoriah.Waterland@Sun.COM 				/*
8559781SMoriah.Waterland@Sun.COM 				 * Finalize merge. This checks to make sure
8569781SMoriah.Waterland@Sun.COM 				 * file attributes are correct and any links
8579781SMoriah.Waterland@Sun.COM 				 * specified are created.
8589781SMoriah.Waterland@Sun.COM 				 */
8599781SMoriah.Waterland@Sun.COM 				(void) endofclass(extlist, classidx,
8609781SMoriah.Waterland@Sun.COM 					(cl_iscript(classidx) ? 0 : 1),
8619869SCasper.Dik@Sun.COM 					pkgserver, a_cfTmpVfp);
8629781SMoriah.Waterland@Sun.COM 			}
8639781SMoriah.Waterland@Sun.COM 		}
8649781SMoriah.Waterland@Sun.COM 	    }
8659781SMoriah.Waterland@Sun.COM 	}
8669781SMoriah.Waterland@Sun.COM 
8679781SMoriah.Waterland@Sun.COM 	/*
8689781SMoriah.Waterland@Sun.COM 	 * Instead of creating links back to the GZ files the logic is
8699781SMoriah.Waterland@Sun.COM 	 * to let zdo recreate the files from the GZ then invoke pkgadd to
8709781SMoriah.Waterland@Sun.COM 	 * install the editable files and skip over any 'f'type files.
8719781SMoriah.Waterland@Sun.COM 	 * The commented out block is to create the links which should be
8729781SMoriah.Waterland@Sun.COM 	 * removed once the current code is tested to be correct.
8739781SMoriah.Waterland@Sun.COM 	 */
8749781SMoriah.Waterland@Sun.COM 
8759781SMoriah.Waterland@Sun.COM 	/*
8769781SMoriah.Waterland@Sun.COM 	 * Go through extlist creating links for 'f'type files
8779781SMoriah.Waterland@Sun.COM 	 * if we're in a global zone. Note that this code lies
8789781SMoriah.Waterland@Sun.COM 	 * here instead of in the main loop to support CAF packages.
8799781SMoriah.Waterland@Sun.COM 	 * In a CAF package the files are installed by the i.none script
8809781SMoriah.Waterland@Sun.COM 	 * and don't exist until all files are done being processed, thus
8819781SMoriah.Waterland@Sun.COM 	 * the additional loop through extlist.
8829781SMoriah.Waterland@Sun.COM 	 */
8839781SMoriah.Waterland@Sun.COM 
8849781SMoriah.Waterland@Sun.COM 	/*
8859781SMoriah.Waterland@Sun.COM 	 * output appropriate completion message
8869781SMoriah.Waterland@Sun.COM 	 */
8879781SMoriah.Waterland@Sun.COM 
8889781SMoriah.Waterland@Sun.COM 	if (is_depend_pkginfo_DB() == B_TRUE) {
8899781SMoriah.Waterland@Sun.COM 		/* updating database only (hollow package) */
8909781SMoriah.Waterland@Sun.COM 		if (a_zoneName == (char *)NULL) {
8919781SMoriah.Waterland@Sun.COM 			echo(MSG_DBUPD_N_N, part, nparts);
8929781SMoriah.Waterland@Sun.COM 		} else {
8939781SMoriah.Waterland@Sun.COM 			echo(MSG_DBUPD_N_N_LZ, part, nparts, a_zoneName);
8949781SMoriah.Waterland@Sun.COM 		}
8959781SMoriah.Waterland@Sun.COM 	} else if (tcount == 0) {
8969781SMoriah.Waterland@Sun.COM 		/* updating package (non-hollow package) */
8979781SMoriah.Waterland@Sun.COM 		if (a_zoneName == (char *)NULL) {
8989781SMoriah.Waterland@Sun.COM 			echo(MSG_INST_N_N, part, nparts);
8999781SMoriah.Waterland@Sun.COM 		} else {
9009781SMoriah.Waterland@Sun.COM 			echo(MSG_INST_N_N_LZ, part, nparts, a_zoneName);
9019781SMoriah.Waterland@Sun.COM 		}
9029781SMoriah.Waterland@Sun.COM 	}
9039781SMoriah.Waterland@Sun.COM 
9049781SMoriah.Waterland@Sun.COM 	/*
9059781SMoriah.Waterland@Sun.COM 	 * if any package objects were updated (not inherited from the
9069781SMoriah.Waterland@Sun.COM 	 * global zone or otherwise already in existence), set the updated
9079781SMoriah.Waterland@Sun.COM 	 * flag as appropriate
9089781SMoriah.Waterland@Sun.COM 	 */
9099781SMoriah.Waterland@Sun.COM 
9109781SMoriah.Waterland@Sun.COM 	if (updated != (char *)NULL) {
9119781SMoriah.Waterland@Sun.COM 		echoDebug(DBG_INSTVOL_OBJ_UPDATED, updated);
9129781SMoriah.Waterland@Sun.COM 		if (r_updated != (char **)NULL) {
9139781SMoriah.Waterland@Sun.COM 			*r_updated = updated;
9149781SMoriah.Waterland@Sun.COM 		}
9159781SMoriah.Waterland@Sun.COM 	}
9169781SMoriah.Waterland@Sun.COM 
9179781SMoriah.Waterland@Sun.COM 	/*
9189781SMoriah.Waterland@Sun.COM 	 * if any package objects were skipped (verified inherited from the
9199781SMoriah.Waterland@Sun.COM 	 * global zone), set the skipped flag as appropriate
9209781SMoriah.Waterland@Sun.COM 	 */
9219781SMoriah.Waterland@Sun.COM 
9229781SMoriah.Waterland@Sun.COM 	if (skipped != (char *)NULL) {
9239781SMoriah.Waterland@Sun.COM 		echoDebug(DBG_INSTVOL_OBJ_SKIPPED, skipped);
9249781SMoriah.Waterland@Sun.COM 		if (r_skipped != (char **)NULL) {
9259781SMoriah.Waterland@Sun.COM 			*r_skipped = skipped;
9269781SMoriah.Waterland@Sun.COM 		}
9279781SMoriah.Waterland@Sun.COM 	}
9289781SMoriah.Waterland@Sun.COM }
9299781SMoriah.Waterland@Sun.COM 
9309781SMoriah.Waterland@Sun.COM /*
9319781SMoriah.Waterland@Sun.COM  * Name:	domerg
9329781SMoriah.Waterland@Sun.COM  * Description: For the specified class, review each entry and return the array
9339781SMoriah.Waterland@Sun.COM  *		index number of the next regular file to process. Hard links are
9349781SMoriah.Waterland@Sun.COM  *		skipped (they are created in endofclass() and directories,
9359781SMoriah.Waterland@Sun.COM  *		symlinks, pipes and devices are created here, as well as any
9369781SMoriah.Waterland@Sun.COM  *		file that already exists and has the correct attributes.
9379781SMoriah.Waterland@Sun.COM  * Arguments:	struct cfextra **extlist - [RO, *RW]
9389781SMoriah.Waterland@Sun.COM  *			- Pointer to list of cfextra structures representing
9399781SMoriah.Waterland@Sun.COM  *			  the pkgmap of the package to be installed
9409781SMoriah.Waterland@Sun.COM  *		int part - [RO, *RO]
9419781SMoriah.Waterland@Sun.COM  *			- the part of the package currently being processed;
9429781SMoriah.Waterland@Sun.COM  *			  packages begin with part "1" and proceed for the
9439781SMoriah.Waterland@Sun.COM  *			  number (nparts) that comprise the package (volume).
9449781SMoriah.Waterland@Sun.COM  *		int nparts - [RO, *RO]
9459781SMoriah.Waterland@Sun.COM  *			- the number of parts the package is divided into
9469781SMoriah.Waterland@Sun.COM  *		int myclass - [RO, *RO]
9479781SMoriah.Waterland@Sun.COM  *			- index into class array of the current class
9489781SMoriah.Waterland@Sun.COM  *		char **srcp - [RW, *RW]
9499781SMoriah.Waterland@Sun.COM  *			- pointer to pointer to string representing the source
9509781SMoriah.Waterland@Sun.COM  *			  path for the next package to process - if this
9519781SMoriah.Waterland@Sun.COM  *			  function returns != DMRG_DONE then this pointer is
9529781SMoriah.Waterland@Sun.COM  *			  set to a pointer to a string representing the source
9539781SMoriah.Waterland@Sun.COM  *			  path for the next object from the package to process
9549781SMoriah.Waterland@Sun.COM  *		char **dstp - [RW, *RW]
9559781SMoriah.Waterland@Sun.COM  *			- pointer to pointer to string representing the target
9569781SMoriah.Waterland@Sun.COM  *			  path for the next package to process - if this
9579781SMoriah.Waterland@Sun.COM  *			  function returns != DMRG_DONE then this pointer is
9589781SMoriah.Waterland@Sun.COM  *			  set to a pointer to a string representing the target
9599781SMoriah.Waterland@Sun.COM  *			  path for the next object from the package to process
9609781SMoriah.Waterland@Sun.COM  *		char **r_updated - [RO, *RW]
9619781SMoriah.Waterland@Sun.COM  *			- pointer to pointer to string - set if the last path
9629781SMoriah.Waterland@Sun.COM  *			  returned exists or does not need updating and the
9639781SMoriah.Waterland@Sun.COM  *			  object is NOT located in an area inherited from the
9649781SMoriah.Waterland@Sun.COM  *			  global zone. This is used to determine if the last
9659781SMoriah.Waterland@Sun.COM  *			  path object returned DOES exist in an area that is
9669781SMoriah.Waterland@Sun.COM  *			  inherited from the global zone. If no paths are
9679781SMoriah.Waterland@Sun.COM  *			  inherited from the global zone, this is always set
9689781SMoriah.Waterland@Sun.COM  *			  when a path to be installed exists and has the
9699781SMoriah.Waterland@Sun.COM  *			  correct contents.
9709781SMoriah.Waterland@Sun.COM  *		char **r_skipped - [RO, *RW]
9719781SMoriah.Waterland@Sun.COM  *			- pointer to pointer to string - set if the last path
9729781SMoriah.Waterland@Sun.COM  *			  returned exists or does not need updating and the
9739781SMoriah.Waterland@Sun.COM  *			  object IS located in an area inherited from the
9749781SMoriah.Waterland@Sun.COM  *			  global zone. This is used to determine if the last
9759781SMoriah.Waterland@Sun.COM  *			  path object returned does NOT exist in an area that
9769781SMoriah.Waterland@Sun.COM  *			  is inherited from the global zone. If no paths are
9779781SMoriah.Waterland@Sun.COM  *			  inherited from the global zone, this is never set.
9789781SMoriah.Waterland@Sun.COM  *		char **r_anyPathLocal - [RO, *RW]
9799781SMoriah.Waterland@Sun.COM  *			- pointer to pointer to string - set if any object
9809781SMoriah.Waterland@Sun.COM  *			  belonging to the package is NOT located in an area
9819781SMoriah.Waterland@Sun.COM  *			  inherited from the global zone. This is used to
9829781SMoriah.Waterland@Sun.COM  *			  determine if the package references ANY objects that
9839781SMoriah.Waterland@Sun.COM  *			  are NOT located in an area inherited from the global
9849781SMoriah.Waterland@Sun.COM  *			  zone - regardless of whether or not they need to be
9859781SMoriah.Waterland@Sun.COM  *			  updated (installed/copied). If no paths are inherited
9869781SMoriah.Waterland@Sun.COM  *			  from the global zone, this is always set when a path
9879781SMoriah.Waterland@Sun.COM  *			  to be installed already exists and has the correct
9889781SMoriah.Waterland@Sun.COM  *			  contents.
9899781SMoriah.Waterland@Sun.COM  * Returns:	int
9909781SMoriah.Waterland@Sun.COM  *			!= DMRG_DONE - index into extlist of the next path to
9919781SMoriah.Waterland@Sun.COM  *				be processed - that needs to be installed/copied
9929781SMoriah.Waterland@Sun.COM  *			== DMRG_DONE - all entries processed
9939781SMoriah.Waterland@Sun.COM  */
9949781SMoriah.Waterland@Sun.COM 
9959781SMoriah.Waterland@Sun.COM static int
9969781SMoriah.Waterland@Sun.COM domerg(struct cfextra **extlist, int part, int nparts,
9979781SMoriah.Waterland@Sun.COM 	int myclass, char **srcp, char **dstp,
9989781SMoriah.Waterland@Sun.COM 	char **r_updated, char **r_skipped,
9999781SMoriah.Waterland@Sun.COM 	char **r_anyPathLocal)
10009781SMoriah.Waterland@Sun.COM {
10019781SMoriah.Waterland@Sun.COM 	boolean_t	stateFlag = B_FALSE;
10029781SMoriah.Waterland@Sun.COM 	int		i;
10039781SMoriah.Waterland@Sun.COM 	int		msg_ugid;
10049781SMoriah.Waterland@Sun.COM 	static int	maxvol = 0;
10059781SMoriah.Waterland@Sun.COM 	static int	svindx = 0;
10069781SMoriah.Waterland@Sun.COM 	static int	svpart = 0;
10079781SMoriah.Waterland@Sun.COM 	struct cfent	*ept = (struct cfent *)NULL;
10089781SMoriah.Waterland@Sun.COM 	struct mergstat *mstat = (struct mergstat *)NULL;
10099781SMoriah.Waterland@Sun.COM 
10109781SMoriah.Waterland@Sun.COM 	/* reset returned path pointers */
10119781SMoriah.Waterland@Sun.COM 
10129781SMoriah.Waterland@Sun.COM 	*dstp = (char *)NULL;
10139781SMoriah.Waterland@Sun.COM 	*srcp = (char *)NULL;
10149781SMoriah.Waterland@Sun.COM 
10159781SMoriah.Waterland@Sun.COM 	/* set to start or continue based on which part being processed */
10169781SMoriah.Waterland@Sun.COM 
10179781SMoriah.Waterland@Sun.COM 	if (part != 0) {
10189781SMoriah.Waterland@Sun.COM 		maxvol = 0;
10199781SMoriah.Waterland@Sun.COM 		svindx = 0;
10209781SMoriah.Waterland@Sun.COM 		svpart = part;
10219781SMoriah.Waterland@Sun.COM 	} else {
10229781SMoriah.Waterland@Sun.COM 		i = svindx;
10239781SMoriah.Waterland@Sun.COM 		part = svpart;
10249781SMoriah.Waterland@Sun.COM 	}
10259781SMoriah.Waterland@Sun.COM 
10269781SMoriah.Waterland@Sun.COM 	/*
10279781SMoriah.Waterland@Sun.COM 	 * This goes through the pkgmap entries one by one testing them
10289781SMoriah.Waterland@Sun.COM 	 * for inclusion in the package database as well as for validity
10299781SMoriah.Waterland@Sun.COM 	 * against existing files.
10309781SMoriah.Waterland@Sun.COM 	 */
10319781SMoriah.Waterland@Sun.COM 	for (i = svindx; extlist[i]; i++) {
10329781SMoriah.Waterland@Sun.COM 		ept = &(extlist[i]->cf_ent);
10339781SMoriah.Waterland@Sun.COM 		mstat = &(extlist[i]->mstat);
10349781SMoriah.Waterland@Sun.COM 
10359781SMoriah.Waterland@Sun.COM 		/*
10369781SMoriah.Waterland@Sun.COM 		 * as paths are processed, if the "anyPathLocal" flag has not
10379781SMoriah.Waterland@Sun.COM 		 * been set, if the object is not of type 'i' (package script),
10389781SMoriah.Waterland@Sun.COM 		 * check to see if the object is in an area inherited from the
10399781SMoriah.Waterland@Sun.COM 		 * global zone - if not, set "anyPathLocal" to the path found,
10409781SMoriah.Waterland@Sun.COM 		 * indicating that at least one path is in an area that is not
10419781SMoriah.Waterland@Sun.COM 		 * inherited from the global zone.
10429781SMoriah.Waterland@Sun.COM 		 */
10439781SMoriah.Waterland@Sun.COM 
10449781SMoriah.Waterland@Sun.COM 		if ((r_anyPathLocal != (char **)NULL) &&
10459781SMoriah.Waterland@Sun.COM 			(*r_anyPathLocal == (char *)NULL) &&
10469781SMoriah.Waterland@Sun.COM 			(ept->ftype != 'i') &&
10479781SMoriah.Waterland@Sun.COM 			(z_path_is_inherited(ept->path, ept->ftype,
10489781SMoriah.Waterland@Sun.COM 						get_inst_root()) == B_FALSE)) {
10499781SMoriah.Waterland@Sun.COM 			echoDebug(DBG_INSTVOL_OBJ_LOCAL, ept->path);
10509781SMoriah.Waterland@Sun.COM 			*r_anyPathLocal = ept->path;
10519781SMoriah.Waterland@Sun.COM 		}
10529781SMoriah.Waterland@Sun.COM 
10539781SMoriah.Waterland@Sun.COM 		/* if this isn't the class of current interest, skip it */
10549781SMoriah.Waterland@Sun.COM 
10559781SMoriah.Waterland@Sun.COM 		if (myclass != ept->pkg_class_idx) {
10569781SMoriah.Waterland@Sun.COM 			continue;
10579781SMoriah.Waterland@Sun.COM 		}
10589781SMoriah.Waterland@Sun.COM 
10599781SMoriah.Waterland@Sun.COM 		/* if the class is invalid, announce it & exit */
10609781SMoriah.Waterland@Sun.COM 		if (ept->pkg_class_idx == -1) {
10619781SMoriah.Waterland@Sun.COM 			progerr(ERR_CLIDX, ept->pkg_class_idx,
10629781SMoriah.Waterland@Sun.COM 			    (ept->path && *ept->path) ? ept->path : "unknown");
10639869SCasper.Dik@Sun.COM 			logerr(gettext("pathname=%s"),
10649781SMoriah.Waterland@Sun.COM 			    (ept->path && *ept->path) ? ept->path : "unknown");
10659869SCasper.Dik@Sun.COM 			logerr(gettext("class=<%s>"),
10669781SMoriah.Waterland@Sun.COM 			    (ept->pkg_class && *ept->pkg_class) ?
10679781SMoriah.Waterland@Sun.COM 			    ept->pkg_class : "Unknown");
10689869SCasper.Dik@Sun.COM 			logerr(gettext("CLASSES=<%s>"),
10699781SMoriah.Waterland@Sun.COM 			    getenv("CLASSES") ? getenv("CLASSES") : "Not Set");
10709781SMoriah.Waterland@Sun.COM 			quit(99);
10719781SMoriah.Waterland@Sun.COM 		}
10729781SMoriah.Waterland@Sun.COM 
10739781SMoriah.Waterland@Sun.COM 		/*
10749781SMoriah.Waterland@Sun.COM 		 * Next check to see if we are going to try to delete a
10759781SMoriah.Waterland@Sun.COM 		 * populated directory in some distressing way.
10769781SMoriah.Waterland@Sun.COM 		 */
10779781SMoriah.Waterland@Sun.COM 		if (mstat->dir2nondir)
10789781SMoriah.Waterland@Sun.COM 			if (dir_is_populated(ept->path)) {
10799781SMoriah.Waterland@Sun.COM 				logerr(WRN_INSTVOL_NOTDIR, ept->path);
10809781SMoriah.Waterland@Sun.COM 				warnflag++;
10819781SMoriah.Waterland@Sun.COM 				mstat->denied = 1;	/* install denied! */
10829781SMoriah.Waterland@Sun.COM 				continue;
10839781SMoriah.Waterland@Sun.COM 			} else {	/* Replace is OK. */
10849781SMoriah.Waterland@Sun.COM 				/*
10859781SMoriah.Waterland@Sun.COM 				 * Remove this directory, so it won't
10869781SMoriah.Waterland@Sun.COM 				 * interfere with creation of the new object.
10879781SMoriah.Waterland@Sun.COM 				 */
10889781SMoriah.Waterland@Sun.COM 				if (rmdir(ept->path)) {
10899781SMoriah.Waterland@Sun.COM 					/*
10909781SMoriah.Waterland@Sun.COM 					 * If it didn't work, there's nothing
10919781SMoriah.Waterland@Sun.COM 					 * we can do. To continue would
10929781SMoriah.Waterland@Sun.COM 					 * likely corrupt the filesystem
10939781SMoriah.Waterland@Sun.COM 					 * which is unacceptable.
10949781SMoriah.Waterland@Sun.COM 					 */
10959781SMoriah.Waterland@Sun.COM 					progerr(ERR_RMDIR, ept->path);
10969781SMoriah.Waterland@Sun.COM 					quit(99);
10979781SMoriah.Waterland@Sun.COM 				}
10989781SMoriah.Waterland@Sun.COM 
10999781SMoriah.Waterland@Sun.COM 				repl_permitted = 1;	/* flag it */
11009781SMoriah.Waterland@Sun.COM 			}
11019781SMoriah.Waterland@Sun.COM 
11029781SMoriah.Waterland@Sun.COM 		/* adjust the max volume number appropriately */
11039781SMoriah.Waterland@Sun.COM 
11049781SMoriah.Waterland@Sun.COM 		if (ept->volno > maxvol) {
11059781SMoriah.Waterland@Sun.COM 			maxvol = ept->volno;
11069781SMoriah.Waterland@Sun.COM 		}
11079781SMoriah.Waterland@Sun.COM 
11089781SMoriah.Waterland@Sun.COM 		/* if this part goes into another volume, skip it */
11099781SMoriah.Waterland@Sun.COM 
11109781SMoriah.Waterland@Sun.COM 		if (part != ept->volno) {
11119781SMoriah.Waterland@Sun.COM 			continue;
11129781SMoriah.Waterland@Sun.COM 		}
11139781SMoriah.Waterland@Sun.COM 
11149781SMoriah.Waterland@Sun.COM 		/*
11159781SMoriah.Waterland@Sun.COM 		 * If it's a conflicting file and it's not supposed to be
11169781SMoriah.Waterland@Sun.COM 		 * installed, note it and skip.
11179781SMoriah.Waterland@Sun.COM 		 */
11189781SMoriah.Waterland@Sun.COM 		if (nocnflct && mstat->shared && ept->ftype != 'e') {
11199781SMoriah.Waterland@Sun.COM 			if (mstat->contchg || mstat->attrchg) {
11209781SMoriah.Waterland@Sun.COM 				echo(MSG_SHIGN, ept->path);
11219781SMoriah.Waterland@Sun.COM 			}
11229781SMoriah.Waterland@Sun.COM 			continue;
11239781SMoriah.Waterland@Sun.COM 		}
11249781SMoriah.Waterland@Sun.COM 
11259781SMoriah.Waterland@Sun.COM 		/*
11269781SMoriah.Waterland@Sun.COM 		 * If we want to set uid or gid but user says no, note it.
11279781SMoriah.Waterland@Sun.COM 		 * Remember that the actual mode bits in the structure have
11289781SMoriah.Waterland@Sun.COM 		 * already been adjusted and the mstat flag is telling us
11299781SMoriah.Waterland@Sun.COM 		 * about the original mode.
11309781SMoriah.Waterland@Sun.COM 		 */
11319781SMoriah.Waterland@Sun.COM 		if (nosetuid && (mstat->setuid || mstat->setgid)) {
11329781SMoriah.Waterland@Sun.COM 			msg_ugid = 1;	/* don't repeat attribute message. */
11339781SMoriah.Waterland@Sun.COM 			if (is_fs_writeable(ept->path,
11349781SMoriah.Waterland@Sun.COM 				&(extlist[i]->fsys_value))) {
11359781SMoriah.Waterland@Sun.COM 				if (!(mstat->contchg) && mstat->attrchg) {
11369781SMoriah.Waterland@Sun.COM 					echo(MSG_UGMOD, ept->path);
11379781SMoriah.Waterland@Sun.COM 				} else {
11389781SMoriah.Waterland@Sun.COM 					echo(MSG_UGID, ept->path);
11399781SMoriah.Waterland@Sun.COM 				}
11409781SMoriah.Waterland@Sun.COM 			}
11419781SMoriah.Waterland@Sun.COM 		} else {
11429781SMoriah.Waterland@Sun.COM 			msg_ugid = 0;
11439781SMoriah.Waterland@Sun.COM 		}
11449781SMoriah.Waterland@Sun.COM 
11459781SMoriah.Waterland@Sun.COM 		switch (ept->ftype) {
11469781SMoriah.Waterland@Sun.COM 			case 'l':	/* hard link */
11479781SMoriah.Waterland@Sun.COM 				/* links treated as object "update/skip" */
11489781SMoriah.Waterland@Sun.COM 				stateFlag = B_TRUE;
11499781SMoriah.Waterland@Sun.COM 				continue; /* defer to final proc */
11509781SMoriah.Waterland@Sun.COM 
11519781SMoriah.Waterland@Sun.COM 			case 's': /* for symlink, verify without fix first */
11529781SMoriah.Waterland@Sun.COM 				/* links treated as object "update/skip" */
11539781SMoriah.Waterland@Sun.COM 				stateFlag = B_TRUE;
11549781SMoriah.Waterland@Sun.COM 
11559781SMoriah.Waterland@Sun.COM 				/* Do this only for default verify */
11569781SMoriah.Waterland@Sun.COM 				if (cl_dvfy(myclass) == DEFAULT) {
11579781SMoriah.Waterland@Sun.COM 					if (averify(0, &ept->ftype,
11589781SMoriah.Waterland@Sun.COM 						ept->path, &ept->ainfo))
11599781SMoriah.Waterland@Sun.COM 						echo(MSG_SLINK, ept->path);
11609781SMoriah.Waterland@Sun.COM 				}
11619781SMoriah.Waterland@Sun.COM 
11629781SMoriah.Waterland@Sun.COM 				/*FALLTHRU*/
11639781SMoriah.Waterland@Sun.COM 
11649781SMoriah.Waterland@Sun.COM 			case 'd':	/* directory */
11659781SMoriah.Waterland@Sun.COM 			case 'x':	/* exclusive directory */
11669781SMoriah.Waterland@Sun.COM 			case 'c':	/* character special device */
11679781SMoriah.Waterland@Sun.COM 			case 'b':	/* block special device */
11689781SMoriah.Waterland@Sun.COM 			case 'p':	/* named pipe */
11699781SMoriah.Waterland@Sun.COM 				/* these NOT treated as object "update/skip" */
11709781SMoriah.Waterland@Sun.COM 				stateFlag = B_FALSE;
11719781SMoriah.Waterland@Sun.COM 
11729781SMoriah.Waterland@Sun.COM 				/*
11739781SMoriah.Waterland@Sun.COM 				 * If we can't get to it for legitimate reasons,
11749781SMoriah.Waterland@Sun.COM 				 * don't try to verify it.
11759781SMoriah.Waterland@Sun.COM 				 */
11769781SMoriah.Waterland@Sun.COM 				if ((z_path_is_inherited(ept->path, ept->ftype,
11779781SMoriah.Waterland@Sun.COM 				    get_inst_root())) ||
11789781SMoriah.Waterland@Sun.COM 				    is_remote_fs(ept->path,
11799781SMoriah.Waterland@Sun.COM 				    &(extlist[i]->fsys_value)) &&
11809781SMoriah.Waterland@Sun.COM 				    !is_fs_writeable(ept->path,
11819781SMoriah.Waterland@Sun.COM 				    &(extlist[i]->fsys_value))) {
11829781SMoriah.Waterland@Sun.COM 					mstat->attrchg = 0;
11839781SMoriah.Waterland@Sun.COM 					mstat->contchg = 0;
11849781SMoriah.Waterland@Sun.COM 					break;
11859781SMoriah.Waterland@Sun.COM 				}
11869781SMoriah.Waterland@Sun.COM 
11879781SMoriah.Waterland@Sun.COM 				if (averify(1, &ept->ftype, ept->path,
11889781SMoriah.Waterland@Sun.COM 							&ept->ainfo) == 0) {
11899781SMoriah.Waterland@Sun.COM 					mstat->contchg = mstat->attrchg = 0;
11909781SMoriah.Waterland@Sun.COM 				} else {
11919781SMoriah.Waterland@Sun.COM 					progerr(ERR_CREATE_PKGOBJ, ept->path);
11929781SMoriah.Waterland@Sun.COM 					logerr(getErrbufAddr());
11939781SMoriah.Waterland@Sun.COM 					warnflag++;
11949781SMoriah.Waterland@Sun.COM 				}
11959781SMoriah.Waterland@Sun.COM 
11969781SMoriah.Waterland@Sun.COM 				break;
11979781SMoriah.Waterland@Sun.COM 
11989781SMoriah.Waterland@Sun.COM 			case 'i':	/* information file */
11999781SMoriah.Waterland@Sun.COM 				/* not treated as object "update/skip" */
12009781SMoriah.Waterland@Sun.COM 				stateFlag = B_FALSE;
12019781SMoriah.Waterland@Sun.COM 				break;
12029781SMoriah.Waterland@Sun.COM 
12039781SMoriah.Waterland@Sun.COM 			default:
12049781SMoriah.Waterland@Sun.COM 				/* all files treated as object "update/skip" */
12059781SMoriah.Waterland@Sun.COM 				stateFlag = B_TRUE;
12069781SMoriah.Waterland@Sun.COM 				break;
12079781SMoriah.Waterland@Sun.COM 		}
12089781SMoriah.Waterland@Sun.COM 
12099781SMoriah.Waterland@Sun.COM 		/*
12109781SMoriah.Waterland@Sun.COM 		 * Both contchg and shared flags have to be taken into
12119781SMoriah.Waterland@Sun.COM 		 * account. contchg is set if the file is already present
12129781SMoriah.Waterland@Sun.COM 		 * in the package database, if it does not exist or if it
12139781SMoriah.Waterland@Sun.COM 		 * exists and is modified.
12149781SMoriah.Waterland@Sun.COM 		 * The shared flag is set when 'e' or 'v' file is not
12159781SMoriah.Waterland@Sun.COM 		 * present in the package database, exists and is not
12169781SMoriah.Waterland@Sun.COM 		 * modified. It also has to be checked here.
12179781SMoriah.Waterland@Sun.COM 		 * Shared flag is also set when file is present in package
12189781SMoriah.Waterland@Sun.COM 		 * database and owned by more than one package, but for
12199781SMoriah.Waterland@Sun.COM 		 * this case contchg has already been set.
12209781SMoriah.Waterland@Sun.COM 		 */
12219781SMoriah.Waterland@Sun.COM 		if (mstat->contchg || (mstat->shared &&
12229781SMoriah.Waterland@Sun.COM 		    ((ept->ftype == 'e') || (ept->ftype == 'v')))) {
12239781SMoriah.Waterland@Sun.COM 			*dstp = ept->path;
12249781SMoriah.Waterland@Sun.COM 			if ((ept->ftype == 'f') || (ept->ftype == 'e') ||
12259781SMoriah.Waterland@Sun.COM 				(ept->ftype == 'v')) {
12269781SMoriah.Waterland@Sun.COM 				*srcp = ept->ainfo.local;
12279781SMoriah.Waterland@Sun.COM 				if (is_partial_inst() != 0) {
12289781SMoriah.Waterland@Sun.COM 					if (*srcp[0] == '~') {
1229*10619SPhaniram.Krishnamurthy@Sun.COM 						/* Done only for C style */
1230*10619SPhaniram.Krishnamurthy@Sun.COM 						char *tmp_ptr;
1231*10619SPhaniram.Krishnamurthy@Sun.COM 						tmp_ptr = extlist[i]->map_path;
1232*10619SPhaniram.Krishnamurthy@Sun.COM 						if (ept->ftype != 'f') {
1233*10619SPhaniram.Krishnamurthy@Sun.COM 							/*
1234*10619SPhaniram.Krishnamurthy@Sun.COM 							 * translate source
1235*10619SPhaniram.Krishnamurthy@Sun.COM 							 * pathname
1236*10619SPhaniram.Krishnamurthy@Sun.COM 							 */
1237*10619SPhaniram.Krishnamurthy@Sun.COM 							*srcp =
1238*10619SPhaniram.Krishnamurthy@Sun.COM 							    srcpath(instdir,
1239*10619SPhaniram.Krishnamurthy@Sun.COM 							    tmp_ptr,
1240*10619SPhaniram.Krishnamurthy@Sun.COM 							    part,
1241*10619SPhaniram.Krishnamurthy@Sun.COM 							    nparts);
1242*10619SPhaniram.Krishnamurthy@Sun.COM 						} else {
1243*10619SPhaniram.Krishnamurthy@Sun.COM 						/*
1244*10619SPhaniram.Krishnamurthy@Sun.COM 						 * instdir has the absolute path
1245*10619SPhaniram.Krishnamurthy@Sun.COM 						 * to saveSpoolInstallDir for
1246*10619SPhaniram.Krishnamurthy@Sun.COM 						 * the package. This is only
1247*10619SPhaniram.Krishnamurthy@Sun.COM 						 * useful for 'e','v' types.
1248*10619SPhaniram.Krishnamurthy@Sun.COM 						 *
1249*10619SPhaniram.Krishnamurthy@Sun.COM 						 * For 'f', we generate the
1250*10619SPhaniram.Krishnamurthy@Sun.COM 						 * absolute src path with the
1251*10619SPhaniram.Krishnamurthy@Sun.COM 						 * help of install root and the
1252*10619SPhaniram.Krishnamurthy@Sun.COM 						 * basedir.
1253*10619SPhaniram.Krishnamurthy@Sun.COM 						 */
1254*10619SPhaniram.Krishnamurthy@Sun.COM 							*srcp = trans_srcp_pi(
1255*10619SPhaniram.Krishnamurthy@Sun.COM 							    ept->ainfo.local);
1256*10619SPhaniram.Krishnamurthy@Sun.COM 						}
12579781SMoriah.Waterland@Sun.COM 					} else {
12589781SMoriah.Waterland@Sun.COM 						*srcp = extlist[i]->map_path;
12599781SMoriah.Waterland@Sun.COM 					}
12609781SMoriah.Waterland@Sun.COM 				} else {
12619781SMoriah.Waterland@Sun.COM 					if (*srcp[0] == '~') {
12629781SMoriah.Waterland@Sun.COM 						/* translate source pathname */
12639781SMoriah.Waterland@Sun.COM 						*srcp = srcpath(instdir,
12649781SMoriah.Waterland@Sun.COM 						    &(ept->ainfo.local[1]),
12659781SMoriah.Waterland@Sun.COM 						    part, nparts);
12669781SMoriah.Waterland@Sun.COM 					}
12679781SMoriah.Waterland@Sun.COM 				}
12689781SMoriah.Waterland@Sun.COM 
12699781SMoriah.Waterland@Sun.COM 				echoDebug(DBG_DOMERG_NO_SUCH_FILE,
12709781SMoriah.Waterland@Sun.COM 					ept->ftype, cl_nam(ept->pkg_class_idx),
12719781SMoriah.Waterland@Sun.COM 					ept->path);
12729781SMoriah.Waterland@Sun.COM 			} else {
12739781SMoriah.Waterland@Sun.COM 				/*
12749781SMoriah.Waterland@Sun.COM 				 * At this point, we're returning a non-file
12759781SMoriah.Waterland@Sun.COM 				 * that couldn't be created in the standard
12769781SMoriah.Waterland@Sun.COM 				 * way. If it refers to a filesystem that is
12779781SMoriah.Waterland@Sun.COM 				 * not writeable by us, don't waste the
12789781SMoriah.Waterland@Sun.COM 				 * calling process's time.
12799781SMoriah.Waterland@Sun.COM 				 */
12809781SMoriah.Waterland@Sun.COM 				if (!is_fs_writeable(ept->path,
12819781SMoriah.Waterland@Sun.COM 					&(extlist[i]->fsys_value))) {
12829781SMoriah.Waterland@Sun.COM 					echoDebug(DBG_DOMERG_NOT_WRITABLE,
12839781SMoriah.Waterland@Sun.COM 						ept->ftype,
12849781SMoriah.Waterland@Sun.COM 						cl_nam(ept->pkg_class_idx),
12859781SMoriah.Waterland@Sun.COM 						ept->path);
12869781SMoriah.Waterland@Sun.COM 					continue;
12879781SMoriah.Waterland@Sun.COM 				}
12889781SMoriah.Waterland@Sun.COM 
12899781SMoriah.Waterland@Sun.COM 				*srcp = NULL;
12909781SMoriah.Waterland@Sun.COM 				echoDebug(DBG_DOMERG_NOT_THERE,
12919781SMoriah.Waterland@Sun.COM 					ept->ftype, cl_nam(ept->pkg_class_idx),
12929781SMoriah.Waterland@Sun.COM 					ept->path);
12939781SMoriah.Waterland@Sun.COM 			}
12949781SMoriah.Waterland@Sun.COM 
12959781SMoriah.Waterland@Sun.COM 			svindx = i+1;
12969781SMoriah.Waterland@Sun.COM 			backup(*dstp, 1);
12979781SMoriah.Waterland@Sun.COM 			return (i);
12989781SMoriah.Waterland@Sun.COM 		}
12999781SMoriah.Waterland@Sun.COM 
13009781SMoriah.Waterland@Sun.COM 		if (mstat->attrchg) {
13019781SMoriah.Waterland@Sun.COM 			backup(ept->path, 0);
13029781SMoriah.Waterland@Sun.COM 			if (!msg_ugid)
13039781SMoriah.Waterland@Sun.COM 				echo(MSG_ATTRIB, ept->path);
13049781SMoriah.Waterland@Sun.COM 
13059781SMoriah.Waterland@Sun.COM 			/* fix the attributes now for robustness sake */
13069781SMoriah.Waterland@Sun.COM 			if (averify(1, &ept->ftype,
13079781SMoriah.Waterland@Sun.COM 				ept->path,
13089781SMoriah.Waterland@Sun.COM 				&ept->ainfo) == 0) {
13099781SMoriah.Waterland@Sun.COM 				mstat->attrchg = 0;
13109781SMoriah.Waterland@Sun.COM 			}
13119781SMoriah.Waterland@Sun.COM 		}
13129781SMoriah.Waterland@Sun.COM 
13139781SMoriah.Waterland@Sun.COM 		/*
13149781SMoriah.Waterland@Sun.COM 		 * package object exists, or does not need updating: if the path
13159781SMoriah.Waterland@Sun.COM 		 * is in an area inherited from the global zone, then treat
13169781SMoriah.Waterland@Sun.COM 		 * the object as if it were "skipped" - if the path is not in an
13179781SMoriah.Waterland@Sun.COM 		 * area inherited from the global zone, then treat the object as
13189781SMoriah.Waterland@Sun.COM 		 * if it were "updated"
13199781SMoriah.Waterland@Sun.COM 		 */
13209781SMoriah.Waterland@Sun.COM 
13219781SMoriah.Waterland@Sun.COM 		/* LINTED warning: statement has no consequent: if */
13229781SMoriah.Waterland@Sun.COM 		if ((stateFlag == B_FALSE) || (ept == (struct cfent *)NULL)) {
13239781SMoriah.Waterland@Sun.COM 			/*
13249781SMoriah.Waterland@Sun.COM 			 * the object in question is a directory or special
13259781SMoriah.Waterland@Sun.COM 			 * file - the fact that this type of object already
13269781SMoriah.Waterland@Sun.COM 			 * exists or does not need updating must not trigger
13279781SMoriah.Waterland@Sun.COM 			 * the object updated/object skipped indication -
13289781SMoriah.Waterland@Sun.COM 			 * that would cause class action scripts to be run
13299781SMoriah.Waterland@Sun.COM 			 * when installing a new non-global zone - that action
13309781SMoriah.Waterland@Sun.COM 			 * must only be done when a file object that is in
13319781SMoriah.Waterland@Sun.COM 			 * an area inherited from the global zone is present.
13329781SMoriah.Waterland@Sun.COM 			 */
13339781SMoriah.Waterland@Sun.COM 		} else if (z_path_is_inherited(ept->path, ept->ftype,
13349781SMoriah.Waterland@Sun.COM 						get_inst_root()) == B_TRUE) {
13359781SMoriah.Waterland@Sun.COM 			if (r_skipped != (char **)NULL) {
13369781SMoriah.Waterland@Sun.COM 				if (*r_skipped == (char *)NULL) {
13379781SMoriah.Waterland@Sun.COM 					echoDebug(DBG_INSTVOL_OBJ_SKIPPED,
13389781SMoriah.Waterland@Sun.COM 								ept->path);
13399781SMoriah.Waterland@Sun.COM 					*r_skipped = ept->path;
13409781SMoriah.Waterland@Sun.COM 				}
13419781SMoriah.Waterland@Sun.COM 			}
13429781SMoriah.Waterland@Sun.COM 		} else {
13439781SMoriah.Waterland@Sun.COM 			if (r_updated != (char **)NULL) {
13449781SMoriah.Waterland@Sun.COM 				if (*r_updated == (char *)NULL) {
13459781SMoriah.Waterland@Sun.COM 					echoDebug(DBG_INSTVOL_OBJ_UPDATED,
13469781SMoriah.Waterland@Sun.COM 								ept->path);
13479781SMoriah.Waterland@Sun.COM 				}
13489781SMoriah.Waterland@Sun.COM 				*r_updated = ept->path;
13499781SMoriah.Waterland@Sun.COM 			}
13509781SMoriah.Waterland@Sun.COM 		}
13519781SMoriah.Waterland@Sun.COM 	}
13529781SMoriah.Waterland@Sun.COM 
13539781SMoriah.Waterland@Sun.COM 	if (maxvol == part) {
13549781SMoriah.Waterland@Sun.COM 		eocflag++;	/* endofclass */
13559781SMoriah.Waterland@Sun.COM 	}
13569781SMoriah.Waterland@Sun.COM 
13579781SMoriah.Waterland@Sun.COM 	return (DMRG_DONE);	/* no remaining entries on this volume */
13589781SMoriah.Waterland@Sun.COM }
13599781SMoriah.Waterland@Sun.COM 
13609781SMoriah.Waterland@Sun.COM /*
13619781SMoriah.Waterland@Sun.COM  * Determine if the provided directory is populated. Return 0 if so and 1 if
13629781SMoriah.Waterland@Sun.COM  * not. This also returns 0 if the dirpath is not a directory or if it does
13639781SMoriah.Waterland@Sun.COM  * not exist.
13649781SMoriah.Waterland@Sun.COM  */
13659781SMoriah.Waterland@Sun.COM static int
13669781SMoriah.Waterland@Sun.COM dir_is_populated(char *dirpath) {
13679781SMoriah.Waterland@Sun.COM 	DIR	*dirfp;
13689781SMoriah.Waterland@Sun.COM 	struct	dirent *drp;
13699781SMoriah.Waterland@Sun.COM 	int	retcode = 0;
13709781SMoriah.Waterland@Sun.COM 
13719781SMoriah.Waterland@Sun.COM 	if ((dirfp = opendir(dirpath)) != NULL) {
13729781SMoriah.Waterland@Sun.COM 		while ((drp = readdir(dirfp)) != NULL) {
13739781SMoriah.Waterland@Sun.COM 			if (strcmp(drp->d_name, ".") == 0) {
13749781SMoriah.Waterland@Sun.COM 				continue;
13759781SMoriah.Waterland@Sun.COM 			}
13769781SMoriah.Waterland@Sun.COM 			if (strcmp(drp->d_name, "..") == 0) {
13779781SMoriah.Waterland@Sun.COM 				continue;
13789781SMoriah.Waterland@Sun.COM 			}
13799781SMoriah.Waterland@Sun.COM 			/*
13809781SMoriah.Waterland@Sun.COM 			 * If we get here, there's a real file in the
13819781SMoriah.Waterland@Sun.COM 			 * directory
13829781SMoriah.Waterland@Sun.COM 			 */
13839781SMoriah.Waterland@Sun.COM 			retcode = 1;
13849781SMoriah.Waterland@Sun.COM 			break;
13859781SMoriah.Waterland@Sun.COM 		}
13869781SMoriah.Waterland@Sun.COM 		(void) closedir(dirfp);
13879781SMoriah.Waterland@Sun.COM 	}
13889781SMoriah.Waterland@Sun.COM 
13899781SMoriah.Waterland@Sun.COM 	return (retcode);
13909781SMoriah.Waterland@Sun.COM }
13919781SMoriah.Waterland@Sun.COM 
13929781SMoriah.Waterland@Sun.COM /*
13939781SMoriah.Waterland@Sun.COM  * This is the function that cleans up the installation of this class.
13949781SMoriah.Waterland@Sun.COM  * This is where hard links get put in since the stuff they're linking
13959781SMoriah.Waterland@Sun.COM  * probably exists by now.
13969781SMoriah.Waterland@Sun.COM  */
13979781SMoriah.Waterland@Sun.COM static void
13989781SMoriah.Waterland@Sun.COM endofclass(struct cfextra **extlist, int myclass, int ckflag,
13999869SCasper.Dik@Sun.COM 	PKGserver pkgserver, VFP_T **a_cfTmpVfp)
14009781SMoriah.Waterland@Sun.COM {
14019781SMoriah.Waterland@Sun.COM 	char		*temppath;
14029781SMoriah.Waterland@Sun.COM 	char 		*pspool_loc;
14039781SMoriah.Waterland@Sun.COM 	char 		*relocpath = (char *)NULL;
14049781SMoriah.Waterland@Sun.COM 	char 		scrpt_dst[PATH_MAX];
14059781SMoriah.Waterland@Sun.COM 	int		flag;
14069781SMoriah.Waterland@Sun.COM 	int		idx;
14079781SMoriah.Waterland@Sun.COM 	int		n;
14089781SMoriah.Waterland@Sun.COM 	struct cfent	*ept;	/* entry from the internal list */
14099781SMoriah.Waterland@Sun.COM 	struct cfextra	entry;	/* entry from the package database */
14109781SMoriah.Waterland@Sun.COM 	struct mergstat	*mstat;	/* merge status */
14119781SMoriah.Waterland@Sun.COM 	struct pinfo	*pinfo;
14129781SMoriah.Waterland@Sun.COM 
14139781SMoriah.Waterland@Sun.COM 	/* open the package database (contents) file */
14149781SMoriah.Waterland@Sun.COM 
14159869SCasper.Dik@Sun.COM 	if (!ocfile(&pkgserver, a_cfTmpVfp, pkgmap_blks)) {
14169781SMoriah.Waterland@Sun.COM 		quit(99);
14179781SMoriah.Waterland@Sun.COM 	}
14189781SMoriah.Waterland@Sun.COM 
14199781SMoriah.Waterland@Sun.COM 	echo(MSG_VERIFYING_CLASS, cl_nam(myclass));
14209781SMoriah.Waterland@Sun.COM 
14219781SMoriah.Waterland@Sun.COM 	for (idx = 0; /* void */; idx++) {
14229781SMoriah.Waterland@Sun.COM 		/* find next package object in this class */
14239781SMoriah.Waterland@Sun.COM 		while (extlist[idx]) {
14249781SMoriah.Waterland@Sun.COM 			if ((extlist[idx]->cf_ent.ftype != 'i') &&
14259781SMoriah.Waterland@Sun.COM 				extlist[idx]->cf_ent.pkg_class_idx == myclass) {
14269781SMoriah.Waterland@Sun.COM 				break;
14279781SMoriah.Waterland@Sun.COM 			}
14289781SMoriah.Waterland@Sun.COM 			idx++;
14299781SMoriah.Waterland@Sun.COM 		}
14309781SMoriah.Waterland@Sun.COM 
14319869SCasper.Dik@Sun.COM 		if (extlist[idx] == NULL)
14329781SMoriah.Waterland@Sun.COM 			break;
14339869SCasper.Dik@Sun.COM 
14349781SMoriah.Waterland@Sun.COM 
14359781SMoriah.Waterland@Sun.COM 		ept = &(extlist[idx]->cf_ent);
14369781SMoriah.Waterland@Sun.COM 		mstat = &(extlist[idx]->mstat);
14379781SMoriah.Waterland@Sun.COM 
14389869SCasper.Dik@Sun.COM 		temppath = extlist[idx]->client_path;
14399781SMoriah.Waterland@Sun.COM 
14409781SMoriah.Waterland@Sun.COM 		/*
14419781SMoriah.Waterland@Sun.COM 		 * At this point  the only difference between the entry
14429781SMoriah.Waterland@Sun.COM 		 * in the contents file and the entry in extlist[] is
14439781SMoriah.Waterland@Sun.COM 		 * that the status indicator contains CONFIRM_CONT.
14449869SCasper.Dik@Sun.COM 		 * This function should return one or something is wrong.
14459781SMoriah.Waterland@Sun.COM 		 */
14469781SMoriah.Waterland@Sun.COM 
14479869SCasper.Dik@Sun.COM 		n = srchcfile(&(entry.cf_ent), temppath, pkgserver);
14489781SMoriah.Waterland@Sun.COM 
14499869SCasper.Dik@Sun.COM 		if (n < 0) {
14509781SMoriah.Waterland@Sun.COM 			char	*errstr = getErrstr();
14519781SMoriah.Waterland@Sun.COM 			progerr(ERR_CFBAD);
14529869SCasper.Dik@Sun.COM 			logerr(gettext("pathname=%s"),
14539781SMoriah.Waterland@Sun.COM 				entry.cf_ent.path && *entry.cf_ent.path ?
14549781SMoriah.Waterland@Sun.COM 				entry.cf_ent.path : "Unknown");
14559869SCasper.Dik@Sun.COM 			logerr(gettext("problem=%s"),
14569781SMoriah.Waterland@Sun.COM 				(errstr && *errstr) ? errstr : "Unknown");
14579781SMoriah.Waterland@Sun.COM 			quit(99);
14589781SMoriah.Waterland@Sun.COM 		} else if (n != 1) {
14599781SMoriah.Waterland@Sun.COM 			/*
14609781SMoriah.Waterland@Sun.COM 			 * Check if path should be in the package
14619781SMoriah.Waterland@Sun.COM 			 * database.
14629781SMoriah.Waterland@Sun.COM 			 */
14639781SMoriah.Waterland@Sun.COM 			if ((mstat->shared && nocnflct)) {
14649781SMoriah.Waterland@Sun.COM 				continue;
14659781SMoriah.Waterland@Sun.COM 			}
14669781SMoriah.Waterland@Sun.COM 			progerr(ERR_CFMISSING, ept->path);
14679781SMoriah.Waterland@Sun.COM 			quit(99);
14689781SMoriah.Waterland@Sun.COM 		}
14699781SMoriah.Waterland@Sun.COM 
14709781SMoriah.Waterland@Sun.COM 		/*
14719781SMoriah.Waterland@Sun.COM 		 * If merge was not appropriate for this object, now is the
14729781SMoriah.Waterland@Sun.COM 		 * time to choose one or the other.
14739781SMoriah.Waterland@Sun.COM 		 */
14749781SMoriah.Waterland@Sun.COM 		if (mstat->denied) {
14759781SMoriah.Waterland@Sun.COM 			/*
14769781SMoriah.Waterland@Sun.COM 			 * If installation was denied AFTER the package
14779781SMoriah.Waterland@Sun.COM 			 * database was updated, skip this. We've already
14789781SMoriah.Waterland@Sun.COM 			 * announced the discrepancy and the verifications
14799781SMoriah.Waterland@Sun.COM 			 * that follow will make faulty decisions based on
14809781SMoriah.Waterland@Sun.COM 			 * the ftype, which may not be correct.
14819781SMoriah.Waterland@Sun.COM 			 */
14829781SMoriah.Waterland@Sun.COM 			progerr(ERR_COULD_NOT_INSTALL, ept->path);
14839781SMoriah.Waterland@Sun.COM 			warnflag++;
14849781SMoriah.Waterland@Sun.COM 		} else {
14859781SMoriah.Waterland@Sun.COM 			if (mstat->replace)
14869781SMoriah.Waterland@Sun.COM 				/*
14879781SMoriah.Waterland@Sun.COM 				 * This replaces the old entry with the new
14889781SMoriah.Waterland@Sun.COM 				 * one. This should never happen in the new
14899781SMoriah.Waterland@Sun.COM 				 * DB since the entries are already identical.
14909781SMoriah.Waterland@Sun.COM 				 */
14919781SMoriah.Waterland@Sun.COM 				repl_cfent(ept, &(entry.cf_ent));
14929781SMoriah.Waterland@Sun.COM 
14939781SMoriah.Waterland@Sun.COM 			/*
14949781SMoriah.Waterland@Sun.COM 			 * Validate this entry and change the status flag in
14959781SMoriah.Waterland@Sun.COM 			 * the package database.
14969781SMoriah.Waterland@Sun.COM 			 */
14979781SMoriah.Waterland@Sun.COM 			if (ept->ftype == RM_RDY) {
14989781SMoriah.Waterland@Sun.COM 				(void) eptstat(&(entry.cf_ent), pkginst,
14999781SMoriah.Waterland@Sun.COM 					STAT_NEXT);
15009781SMoriah.Waterland@Sun.COM 			} else {
15019781SMoriah.Waterland@Sun.COM 				/* check the hard link now. */
15029781SMoriah.Waterland@Sun.COM 				if (ept->ftype == 'l') {
15039781SMoriah.Waterland@Sun.COM 					if (averify(0, &ept->ftype,
15049781SMoriah.Waterland@Sun.COM 						ept->path, &ept->ainfo)) {
15059781SMoriah.Waterland@Sun.COM 						echo(MSG_HRDLINK,
15069781SMoriah.Waterland@Sun.COM 							ept->path);
15079781SMoriah.Waterland@Sun.COM 						mstat->attrchg++;
15089781SMoriah.Waterland@Sun.COM 					}
15099781SMoriah.Waterland@Sun.COM 				}
15109781SMoriah.Waterland@Sun.COM 
15119781SMoriah.Waterland@Sun.COM 				/*
15129781SMoriah.Waterland@Sun.COM 				 * Don't install or verify objects for
15139781SMoriah.Waterland@Sun.COM 				 * remote, read-only filesystems.  We need
15149781SMoriah.Waterland@Sun.COM 				 * only flag them as shared from some server.
15159781SMoriah.Waterland@Sun.COM 				 * Otherwise, ok to do final check.
15169781SMoriah.Waterland@Sun.COM 				 */
15179781SMoriah.Waterland@Sun.COM 				if (is_remote_fs(ept->path,
15189781SMoriah.Waterland@Sun.COM 					&(extlist[idx]->fsys_value)) &&
15199781SMoriah.Waterland@Sun.COM 					!is_fs_writeable(ept->path,
15209781SMoriah.Waterland@Sun.COM 					&(extlist[idx]->fsys_value))) {
15219781SMoriah.Waterland@Sun.COM 					flag = -1;
15229781SMoriah.Waterland@Sun.COM 				} else {
15239781SMoriah.Waterland@Sun.COM 					boolean_t inheritedFlag;
15249781SMoriah.Waterland@Sun.COM 					inheritedFlag =
15259781SMoriah.Waterland@Sun.COM 					    z_path_is_inherited(ept->path,
15269781SMoriah.Waterland@Sun.COM 						ept->ftype, get_inst_root());
15279781SMoriah.Waterland@Sun.COM 					flag = finalck(ept, mstat->attrchg,
15289781SMoriah.Waterland@Sun.COM 						(ckflag ? mstat->contchg :
15299781SMoriah.Waterland@Sun.COM 						(-1)), inheritedFlag);
15309781SMoriah.Waterland@Sun.COM 				}
15319781SMoriah.Waterland@Sun.COM 
15329781SMoriah.Waterland@Sun.COM 				pinfo = entry.cf_ent.pinfo;
15339781SMoriah.Waterland@Sun.COM 
15349781SMoriah.Waterland@Sun.COM 				/* Find this package in the list. */
15359781SMoriah.Waterland@Sun.COM 				while (pinfo) {
15369781SMoriah.Waterland@Sun.COM 					if (strcmp(pkginst, pinfo->pkg) == 0) {
15379781SMoriah.Waterland@Sun.COM 						break;
15389781SMoriah.Waterland@Sun.COM 					}
15399781SMoriah.Waterland@Sun.COM 					pinfo = pinfo->next;
15409781SMoriah.Waterland@Sun.COM 				}
15419781SMoriah.Waterland@Sun.COM 
15429781SMoriah.Waterland@Sun.COM 				/*
15439781SMoriah.Waterland@Sun.COM 				 * If this package owns this file, then store
15449781SMoriah.Waterland@Sun.COM 				 * it in the database with the appropriate
15459781SMoriah.Waterland@Sun.COM 				 * status. Need to check pinfo in case it
15469781SMoriah.Waterland@Sun.COM 				 * points to NULL which could happen if
15479781SMoriah.Waterland@Sun.COM 				 * pinfo->next = NULL above.
15489781SMoriah.Waterland@Sun.COM 				 */
15499781SMoriah.Waterland@Sun.COM 				if (pinfo) {
15509781SMoriah.Waterland@Sun.COM 					if (flag < 0 || is_served(ept->path,
15519781SMoriah.Waterland@Sun.COM 						&(extlist[idx]->fsys_value))) {
15529781SMoriah.Waterland@Sun.COM 						/*
15539781SMoriah.Waterland@Sun.COM 						 * This is provided to
15549781SMoriah.Waterland@Sun.COM 						 * clients by a server.
15559781SMoriah.Waterland@Sun.COM 						 */
15569781SMoriah.Waterland@Sun.COM 						pinfo->status = SERVED_FILE;
15579781SMoriah.Waterland@Sun.COM 					} else {
15589781SMoriah.Waterland@Sun.COM 						/*
15599781SMoriah.Waterland@Sun.COM 						 * It's either there or it's
15609781SMoriah.Waterland@Sun.COM 						 * not.
15619781SMoriah.Waterland@Sun.COM 						 */
15629781SMoriah.Waterland@Sun.COM 						pinfo->status = (flag ?
15639781SMoriah.Waterland@Sun.COM 							NOT_FND : ENTRY_OK);
15649781SMoriah.Waterland@Sun.COM 					}
15659781SMoriah.Waterland@Sun.COM 				}
15669781SMoriah.Waterland@Sun.COM 			}
15679781SMoriah.Waterland@Sun.COM 		}
15689781SMoriah.Waterland@Sun.COM 
15699781SMoriah.Waterland@Sun.COM 		/*
15709781SMoriah.Waterland@Sun.COM 		 * If not installing from a partially spooled package, the
15719781SMoriah.Waterland@Sun.COM 		 * "save/pspool" area, and the file contents can be
15729781SMoriah.Waterland@Sun.COM 		 * changed (type is 'e' or 'v'), and the class IS "none":
15739781SMoriah.Waterland@Sun.COM 		 * copy the installed volatile file into the appropriate
15749781SMoriah.Waterland@Sun.COM 		 * location in the packages destination "save/pspool" area.
15759781SMoriah.Waterland@Sun.COM 		 */
15769781SMoriah.Waterland@Sun.COM 
15779781SMoriah.Waterland@Sun.COM 		if ((!is_partial_inst()) &&
15789781SMoriah.Waterland@Sun.COM 			((ept->ftype == 'e') || (ept->ftype == 'v')) &&
15799781SMoriah.Waterland@Sun.COM 			(strcmp(ept->pkg_class, "none") == 0)) {
15809781SMoriah.Waterland@Sun.COM 
15819781SMoriah.Waterland@Sun.COM 			if (absolutepath(extlist[idx]->map_path) == B_TRUE &&
15829781SMoriah.Waterland@Sun.COM 				parametricpath(extlist[idx]->cf_ent.ainfo.local,
15839781SMoriah.Waterland@Sun.COM 					&relocpath) == B_FALSE) {
15849781SMoriah.Waterland@Sun.COM 				pspool_loc = ROOT;
15859781SMoriah.Waterland@Sun.COM 			} else {
15869781SMoriah.Waterland@Sun.COM 				pspool_loc = RELOC;
15879781SMoriah.Waterland@Sun.COM 			}
15889781SMoriah.Waterland@Sun.COM 
15899781SMoriah.Waterland@Sun.COM 			n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s",
15909781SMoriah.Waterland@Sun.COM 				saveSpoolInstallDir, pspool_loc,
15919781SMoriah.Waterland@Sun.COM 				relocpath ? relocpath : extlist[idx]->map_path);
15929781SMoriah.Waterland@Sun.COM 
15939781SMoriah.Waterland@Sun.COM 			if (n >= PATH_MAX) {
15949781SMoriah.Waterland@Sun.COM 				progerr(ERR_CREATE_PATH_2,
15959781SMoriah.Waterland@Sun.COM 					saveSpoolInstallDir,
15969781SMoriah.Waterland@Sun.COM 					extlist[idx]->map_path);
15979781SMoriah.Waterland@Sun.COM 				quit(99);
15989781SMoriah.Waterland@Sun.COM 			}
15999781SMoriah.Waterland@Sun.COM 
16009781SMoriah.Waterland@Sun.COM 			/* copy, preserve source file mode */
16019781SMoriah.Waterland@Sun.COM 
16029781SMoriah.Waterland@Sun.COM 			if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) {
16039781SMoriah.Waterland@Sun.COM 				warnflag++;
16049781SMoriah.Waterland@Sun.COM 			}
16059781SMoriah.Waterland@Sun.COM 		}
16069781SMoriah.Waterland@Sun.COM 
16079781SMoriah.Waterland@Sun.COM 		/*
16089781SMoriah.Waterland@Sun.COM 		 * Now insert this potentially changed package database
16099781SMoriah.Waterland@Sun.COM 		 * entry.
16109781SMoriah.Waterland@Sun.COM 		 */
16119781SMoriah.Waterland@Sun.COM 		if (entry.cf_ent.npkgs) {
16129781SMoriah.Waterland@Sun.COM 			if (putcvfpfile(&(entry.cf_ent), *a_cfTmpVfp)) {
16139781SMoriah.Waterland@Sun.COM 				quit(99);
16149781SMoriah.Waterland@Sun.COM 			}
16159781SMoriah.Waterland@Sun.COM 		}
16169781SMoriah.Waterland@Sun.COM 	}
16179781SMoriah.Waterland@Sun.COM 
16189869SCasper.Dik@Sun.COM 	n = swapcfile(pkgserver, a_cfTmpVfp, pkginst, dbchg);
16199781SMoriah.Waterland@Sun.COM 	if (n == RESULT_WRN) {
16209781SMoriah.Waterland@Sun.COM 		warnflag++;
16219781SMoriah.Waterland@Sun.COM 	} else if (n == RESULT_ERR) {
16229781SMoriah.Waterland@Sun.COM 		quit(99);
16239781SMoriah.Waterland@Sun.COM 	}
16249781SMoriah.Waterland@Sun.COM }
16259781SMoriah.Waterland@Sun.COM 
16269781SMoriah.Waterland@Sun.COM /*
16279781SMoriah.Waterland@Sun.COM  * This function goes through and fixes all the attributes. This is called
16289781SMoriah.Waterland@Sun.COM  * out by using DST_QKVERIFY=this_class in the pkginfo file. The primary
16299781SMoriah.Waterland@Sun.COM  * use for this is to fix up files installed by a class action script
16309781SMoriah.Waterland@Sun.COM  * which is time-critical and reliable enough to assume likely success.
16319781SMoriah.Waterland@Sun.COM  * The first such format was for WOS compressed-cpio'd file sets.
16329781SMoriah.Waterland@Sun.COM  * The second format is the Class Archive Format.
16339781SMoriah.Waterland@Sun.COM  */
16349781SMoriah.Waterland@Sun.COM static int
16359781SMoriah.Waterland@Sun.COM fix_attributes(struct cfextra **extlist, int idx)
16369781SMoriah.Waterland@Sun.COM {
16379781SMoriah.Waterland@Sun.COM 	struct	cfextra *ext;
16389781SMoriah.Waterland@Sun.COM 	int	i, retval = 1;
16399781SMoriah.Waterland@Sun.COM 	int 	nc = cl_getn();
16409781SMoriah.Waterland@Sun.COM 	int	n;
16419781SMoriah.Waterland@Sun.COM 	struct cfent *ept;
16429781SMoriah.Waterland@Sun.COM 	struct mergstat *mstat;
16439781SMoriah.Waterland@Sun.COM 	char scrpt_dst[PATH_MAX];
16449781SMoriah.Waterland@Sun.COM 	char *pspool_loc;
16459781SMoriah.Waterland@Sun.COM 	char *relocpath = (char *)NULL;
16469781SMoriah.Waterland@Sun.COM 
16479781SMoriah.Waterland@Sun.COM 	for (i = 0; extlist[i]; i++) {
16489781SMoriah.Waterland@Sun.COM 		ext = extlist[i];
16499781SMoriah.Waterland@Sun.COM 		ept = &(extlist[i]->cf_ent);
16509781SMoriah.Waterland@Sun.COM 		mstat = &(extlist[i]->mstat);
16519781SMoriah.Waterland@Sun.COM 
16529781SMoriah.Waterland@Sun.COM 		/*
16539781SMoriah.Waterland@Sun.COM 		 * We don't care about 'i'nfo files because, they
16549781SMoriah.Waterland@Sun.COM 		 * aren't laid down, 'e'ditable files can change
16559781SMoriah.Waterland@Sun.COM 		 * anyway, so who cares and 's'ymlinks were already
16569781SMoriah.Waterland@Sun.COM 		 * fixed in domerg(); however, certain old WOS
16579781SMoriah.Waterland@Sun.COM 		 * package symlinks depend on a bug in the old
16589781SMoriah.Waterland@Sun.COM 		 * pkgadd which has recently been expunged. For
16599781SMoriah.Waterland@Sun.COM 		 * those packages in 2.2, we repeat the verification
16609781SMoriah.Waterland@Sun.COM 		 * of symlinks.
16619781SMoriah.Waterland@Sun.COM 		 *
16629781SMoriah.Waterland@Sun.COM 		 * By 2.6 or so, ftype == 's' should be added to this.
16639781SMoriah.Waterland@Sun.COM 		 */
16649781SMoriah.Waterland@Sun.COM 		if (ept->ftype == 'i' || ept->ftype == 'e' ||
16659781SMoriah.Waterland@Sun.COM 			(mstat->shared && nocnflct))
16669781SMoriah.Waterland@Sun.COM 			continue;
16679781SMoriah.Waterland@Sun.COM 
16689781SMoriah.Waterland@Sun.COM 		if (mstat->denied) {
16699781SMoriah.Waterland@Sun.COM 			progerr(ERR_COULD_NOT_INSTALL, ept->path);
16709781SMoriah.Waterland@Sun.COM 			warnflag++;
16719781SMoriah.Waterland@Sun.COM 			continue;
16729781SMoriah.Waterland@Sun.COM 		}
16739781SMoriah.Waterland@Sun.COM 
16749781SMoriah.Waterland@Sun.COM 		if (ept->pkg_class_idx < 0 || ept->pkg_class_idx > nc) {
16759781SMoriah.Waterland@Sun.COM 			progerr(ERR_CLIDX, ept->pkg_class_idx,
16769781SMoriah.Waterland@Sun.COM 			    (ept->path && *ept->path) ? ept->path : "unknown");
16779781SMoriah.Waterland@Sun.COM 			continue;
16789781SMoriah.Waterland@Sun.COM 		}
16799781SMoriah.Waterland@Sun.COM 
16809781SMoriah.Waterland@Sun.COM 		/* If this is the right class, do the fast verify. */
16819781SMoriah.Waterland@Sun.COM 		if (ept->pkg_class_idx == idx) {
16829781SMoriah.Waterland@Sun.COM 			if (fverify(1, &ept->ftype, ept->path,
16839781SMoriah.Waterland@Sun.COM 				&ept->ainfo, &ept->cinfo) == 0) {
16849781SMoriah.Waterland@Sun.COM 				mstat->attrchg = 0;
16859781SMoriah.Waterland@Sun.COM 				mstat->contchg =  0;
16869781SMoriah.Waterland@Sun.COM 			} else	/* We'll try full verify later */
16879781SMoriah.Waterland@Sun.COM 				retval = 0;
16889781SMoriah.Waterland@Sun.COM 		}
16899781SMoriah.Waterland@Sun.COM 		/*
16909781SMoriah.Waterland@Sun.COM 		 * Need to copy the installed volitale file back to the
16919781SMoriah.Waterland@Sun.COM 		 * partial spooled area if we are installing to a local zone
16929781SMoriah.Waterland@Sun.COM 		 * or similar installation method.
16939781SMoriah.Waterland@Sun.COM 		 */
16949781SMoriah.Waterland@Sun.COM 
16959781SMoriah.Waterland@Sun.COM 		if ((!is_partial_inst()) &&
16969781SMoriah.Waterland@Sun.COM 			((ept->ftype == 'e') || (ept->ftype == 'v')) &&
16979781SMoriah.Waterland@Sun.COM 			(strcmp(ept->pkg_class, "none") == 0)) {
16989781SMoriah.Waterland@Sun.COM 
16999781SMoriah.Waterland@Sun.COM 			if (absolutepath(ext->map_path) == B_TRUE &&
17009781SMoriah.Waterland@Sun.COM 				parametricpath(ext->cf_ent.ainfo.local,
17019781SMoriah.Waterland@Sun.COM 					&relocpath) == B_FALSE) {
17029781SMoriah.Waterland@Sun.COM 				pspool_loc = ROOT;
17039781SMoriah.Waterland@Sun.COM 			} else {
17049781SMoriah.Waterland@Sun.COM 				pspool_loc = RELOC;
17059781SMoriah.Waterland@Sun.COM 			}
17069781SMoriah.Waterland@Sun.COM 
17079781SMoriah.Waterland@Sun.COM 			n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s",
17089781SMoriah.Waterland@Sun.COM 				saveSpoolInstallDir, pspool_loc,
17099781SMoriah.Waterland@Sun.COM 				relocpath ? relocpath : ext->map_path);
17109781SMoriah.Waterland@Sun.COM 
17119781SMoriah.Waterland@Sun.COM 			if (n >= PATH_MAX) {
17129781SMoriah.Waterland@Sun.COM 				progerr(ERR_CREATE_PATH_2,
17139781SMoriah.Waterland@Sun.COM 					saveSpoolInstallDir,
17149781SMoriah.Waterland@Sun.COM 					ext->map_path);
17159781SMoriah.Waterland@Sun.COM 				quit(99);
17169781SMoriah.Waterland@Sun.COM 			}
17179781SMoriah.Waterland@Sun.COM 
17189781SMoriah.Waterland@Sun.COM 			/* copy, preserve source file mode */
17199781SMoriah.Waterland@Sun.COM 
17209781SMoriah.Waterland@Sun.COM 			if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) {
17219781SMoriah.Waterland@Sun.COM 				warnflag++;
17229781SMoriah.Waterland@Sun.COM 			}
17239781SMoriah.Waterland@Sun.COM 		}
17249781SMoriah.Waterland@Sun.COM 	}
17259781SMoriah.Waterland@Sun.COM 
17269781SMoriah.Waterland@Sun.COM 	return (retval);
17279781SMoriah.Waterland@Sun.COM }
17289781SMoriah.Waterland@Sun.COM 
17299781SMoriah.Waterland@Sun.COM /*
17309781SMoriah.Waterland@Sun.COM  * Check to see if first charcter in path is a '/'.
17319781SMoriah.Waterland@Sun.COM  *
17329781SMoriah.Waterland@Sun.COM  * Return:
17339781SMoriah.Waterland@Sun.COM  * 			B_TRUE - if path is prepended with '/'
17349781SMoriah.Waterland@Sun.COM  * 			B_FALSE - if not
17359781SMoriah.Waterland@Sun.COM  */
17369781SMoriah.Waterland@Sun.COM static boolean_t
17379781SMoriah.Waterland@Sun.COM absolutepath(char *path)
17389781SMoriah.Waterland@Sun.COM {
17399781SMoriah.Waterland@Sun.COM 	assert(path != NULL);
17409781SMoriah.Waterland@Sun.COM 	assert(path[0] != '\0');
17419781SMoriah.Waterland@Sun.COM 
17429781SMoriah.Waterland@Sun.COM 	return (path[0] == '/' ? B_TRUE : B_FALSE);
17439781SMoriah.Waterland@Sun.COM }
17449781SMoriah.Waterland@Sun.COM 
17459781SMoriah.Waterland@Sun.COM /*
17469781SMoriah.Waterland@Sun.COM  * Check to see if path contains a '$' which makes it
17479781SMoriah.Waterland@Sun.COM  * a parametric path and therefore relocatable.
17489781SMoriah.Waterland@Sun.COM  *
17499781SMoriah.Waterland@Sun.COM  * Parameters:
17509781SMoriah.Waterland@Sun.COM  *             path - The path to determine if it is absolute
17519781SMoriah.Waterland@Sun.COM  *             relocpath - The value of the unconditioned path
17529781SMoriah.Waterland@Sun.COM  *                         i.e. $OPTDIR/usr/ls
17539781SMoriah.Waterland@Sun.COM  * Return:
17549781SMoriah.Waterland@Sun.COM  * 			B_TRUE - if path is a parametric path
17559781SMoriah.Waterland@Sun.COM  * 			B_FALSE - if not
17569781SMoriah.Waterland@Sun.COM  */
17579781SMoriah.Waterland@Sun.COM static boolean_t
17589781SMoriah.Waterland@Sun.COM parametricpath(char *path, char **relocpath)
17599781SMoriah.Waterland@Sun.COM {
17609781SMoriah.Waterland@Sun.COM 	assert(path != NULL);
17619781SMoriah.Waterland@Sun.COM 	assert(path[0] != '\0');
17629781SMoriah.Waterland@Sun.COM 
17639781SMoriah.Waterland@Sun.COM 	/*
17649781SMoriah.Waterland@Sun.COM 	 * If this is a valid parametric path then a '$' MUST occur at the
17659781SMoriah.Waterland@Sun.COM 	 * first or second character.
17669781SMoriah.Waterland@Sun.COM 	 */
17679781SMoriah.Waterland@Sun.COM 
17689781SMoriah.Waterland@Sun.COM 	if (path[0] == '$' || path[1] == '$') {
17699781SMoriah.Waterland@Sun.COM 		/*
17709781SMoriah.Waterland@Sun.COM 		 * If a parametric path exists then when copying the
17719781SMoriah.Waterland@Sun.COM 		 * path to the pspool directoy from the installing
17729781SMoriah.Waterland@Sun.COM 		 * pkgs reloc directory we want to use the uncononditional
17739781SMoriah.Waterland@Sun.COM 		 * varaiable path.
17749781SMoriah.Waterland@Sun.COM 		 */
17759781SMoriah.Waterland@Sun.COM 		*relocpath = (path + 1);
17769781SMoriah.Waterland@Sun.COM 		return (B_TRUE);
17779781SMoriah.Waterland@Sun.COM 	}
17789781SMoriah.Waterland@Sun.COM 	return (B_FALSE);
17799781SMoriah.Waterland@Sun.COM }
17809781SMoriah.Waterland@Sun.COM 
17819781SMoriah.Waterland@Sun.COM void
17829781SMoriah.Waterland@Sun.COM regfiles_free()
17839781SMoriah.Waterland@Sun.COM {
17849781SMoriah.Waterland@Sun.COM 	if (regfiles_head != NULL) {
17859781SMoriah.Waterland@Sun.COM 		struct reg_files *rfp = regfiles_head->next;
17869781SMoriah.Waterland@Sun.COM 
17879781SMoriah.Waterland@Sun.COM 		while (rfp != NULL) {
17889781SMoriah.Waterland@Sun.COM 			free(regfiles_head);
17899781SMoriah.Waterland@Sun.COM 			regfiles_head = rfp;
17909781SMoriah.Waterland@Sun.COM 			rfp = regfiles_head->next;
17919781SMoriah.Waterland@Sun.COM 		}
17929781SMoriah.Waterland@Sun.COM 		free(regfiles_head);
17939781SMoriah.Waterland@Sun.COM 		regfiles_head = NULL;
17949781SMoriah.Waterland@Sun.COM 	}
17959781SMoriah.Waterland@Sun.COM }
1796