xref: /titanic_50/usr/src/cmd/svr4pkg/pkginstall/instvol.c (revision d6114e2d100d9ec3b45f9968d45ac2e3a0827af0)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 
30 
31 #include <stdio.h>
32 #include <string.h>
33 #include <locale.h>
34 #include <libintl.h>
35 #include <dirent.h>
36 #include <pkgstrct.h>
37 #include <pkgdev.h>
38 #include <pkglocs.h>
39 #include <archives.h>
40 #include <errno.h>
41 #include <fcntl.h>
42 #include <sys/stat.h>
43 #include <sys/param.h>
44 #include <stdlib.h>
45 #include <unistd.h>
46 #include <assert.h>
47 #include <wait.h>
48 
49 /*
50  * libinstzones includes
51  */
52 
53 #include <instzones_api.h>
54 
55 /*
56  * consolidation pkg command library includes
57  */
58 
59 #include <pkglib.h>
60 #include <pkgweb.h>
61 
62 /*
63  * local pkg command library includes
64  */
65 
66 #include <install.h>
67 #include <libinst.h>
68 #include <libadm.h>
69 #include <dryrun.h>
70 #include <messages.h>
71 
72 /*
73  * pkginstall local includes
74  */
75 
76 #include "pkginstall.h"
77 
78 extern int		pkgverbose;
79 extern fsblkcnt_t	pkgmap_blks; 		/* main.c */
80 
81 extern struct pkgdev pkgdev;
82 
83 extern char	tmpdir[];
84 extern char	pkgbin[];
85 extern char	instdir[];
86 extern char	saveSpoolInstallDir[];
87 extern char	*pkginst;
88 
89 extern int	dbchg;
90 extern int	nosetuid;
91 extern int	nocnflct;
92 extern int	warnflag;
93 
94 #define	DMRG_DONE	-1
95 
96 #define	ck_efile(s, p)	\
97 		((p->cinfo.modtime >= 0) && \
98 		p->ainfo.local && \
99 		cverify(0, &p->ftype, s, &p->cinfo, 1))
100 
101 static int	eocflag;
102 
103 /*
104  * The variable below indicates that fix_attributes() will be inadequate
105  * because a replacement was permitted.
106  */
107 static int	repl_permitted = 0;
108 
109 static int	domerg(struct cfextra **extlist, int part, int nparts,
110 			int myclass, char **srcp, char **dstp,
111 			char **r_updated, char **r_skipped,
112 			char **r_anyPathLocal);
113 static void	endofclass(struct cfextra **extlist, int myclass,
114 			int ckflag, PKGserver server, VFP_T **a_cfTmpVfp);
115 static int	fix_attributes(struct cfextra **, int);
116 static int	dir_is_populated(char *dirpath);
117 static boolean_t absolutepath(char *path);
118 static boolean_t parametricpath(char *path, char **relocpath);
119 
120 /* Used to keep track of the entries in extlist that are regular files. */
121 struct reg_files {
122 	struct reg_files *next;
123 	int val;
124 };
125 static struct reg_files *regfiles_head = NULL;
126 
127 /*
128  * This is the function that actually installs one volume (usually that's
129  * all there is). Upon entry, the extlist is entirely correct:
130  *
131  *	1. It contains only those files which are to be installed
132  *	   from all volumes.
133  *	2. The mode bits in the ainfo structure for each file are set
134  *	   correctly in accordance with administrative defaults.
135  *	3. mstat.setuid/setgid reflect what the status *was* before
136  *	   pkgdbmerg() processed compliance.
137  */
138 void
139 instvol(struct cfextra **extlist, char *srcinst, int part,
140 	int nparts, PKGserver pkgserver, VFP_T **a_cfTmpVfp,
141 	char **r_updated, char **r_skipped,
142 	char *a_zoneName)
143 {
144 	FILE		*listfp;
145 	char		*updated = (char *)NULL;
146 	char		*skipped = (char *)NULL;
147 	char		*anyPathLocal = (char *)NULL;
148 	char		*relocpath = (char *)NULL;
149 	char		*dstp;
150 	char		*listfile;
151 	char		*srcp;
152 	char		*pspool_loc;
153 	char		scrpt_dst[PATH_MAX];
154 	int		count;
155 	int		entryidx;	/* array of current package objects */
156 	int		n;
157 	int		nc = 0;
158 	int		pass;		/* pass count through the for loop. */
159 	int		tcount;
160 	struct cfent	*ept;
161 	struct cfextra	*ext;
162 	struct mergstat	*mstat;
163 	struct reg_files *rfp = NULL;
164 
165 	/*
166 	 * r_updated and r_skipped are optional parameters that can be passed in
167 	 * by the caller if the caller wants to know if any objects are either
168 	 * updated or skipped. Do not initialize either r_updated or r_skipped;
169 	 * the call to instvol could be cumulative and any previous update or
170 	 * skipped indication must not be disturbed - these flags are only set,
171 	 * they must never be reset. These flags are "char *" pointers so that
172 	 * the object that was skipped or updated can be displayed in debugging
173 	 * output.
174 	 */
175 
176 	if (part == 1) {
177 		pkgvolume(&pkgdev, srcinst, part, nparts);
178 	}
179 
180 	tcount = 0;
181 	nc = cl_getn();
182 
183 	/*
184 	 * For each class in this volume, install those files.
185 	 *
186 	 * NOTE : This loop index may be decremented by code below forcing a
187 	 * second trip through for the same class. This happens only when a
188 	 * class is split between an archive and the tree. Examples would be
189 	 * old WOS packages and the occasional class containing dynamic
190 	 * libraries which require special treatment.
191 	 */
192 
193 	if (is_depend_pkginfo_DB() == B_FALSE) {
194 	    int		classidx;	/* the current class */
195 
196 	    for (classidx = 0; classidx < nc; classidx++) {
197 		int pass_relative = 0;
198 		int rel_init = 0;
199 
200 		eocflag = count = pass = 0;
201 		listfp = (FILE *)0;
202 		listfile = NULL;
203 
204 		/* Now what do we pass to the class action script */
205 
206 		if (cl_pthrel(classidx) == REL_2_CAS) {
207 			pass_relative = 1;
208 		}
209 
210 		for (;;) {
211 			if (!tcount++) {
212 				/* first file to install */
213 				if (a_zoneName == (char *)NULL) {
214 					echo(MSG_INS_N_N, part, nparts);
215 				} else {
216 					echo(MSG_INS_N_N_LZ, part, nparts,
217 						a_zoneName);
218 				}
219 			}
220 
221 			/*
222 			 * If there's an install class action script and no
223 			 * list file has been created yet, create that file
224 			 * and provide the pointer in listfp.
225 			 */
226 			if (cl_iscript(classidx) && !listfp) {
227 				/* create list file */
228 				putparam("TMPDIR", tmpdir);
229 				listfile = tempnam(tmpdir, "list");
230 				if ((listfp = fopen(listfile, "w")) == NULL) {
231 					progerr(ERR_WTMPFILE, listfile);
232 					quit(99);
233 				}
234 			}
235 
236 			/*
237 			 * The following function goes through the package
238 			 * object list returning the array index of the next
239 			 * regular file. If it encounters a directory,
240 			 * symlink, named pipe or device, it just creates it.
241 			 */
242 
243 			entryidx = domerg(extlist, (pass++ ? 0 : part), nparts,
244 				classidx, &srcp, &dstp, &updated, &skipped,
245 				&anyPathLocal);
246 
247 			/* Evaluate the return code */
248 			if (entryidx == DMRG_DONE) {
249 				/*
250 				 * Set ept to the first entry in extlist
251 				 * which is guaranteed to exist so
252 				 * later checks against ept->ftype are
253 				 * not compared to NULL.
254 				 */
255 				ext = extlist[0];
256 				ept = &(ext->cf_ent);
257 				break; /* no more entries to process */
258 			}
259 
260 			ext = extlist[entryidx];
261 			ept = &(ext->cf_ent);
262 			mstat = &(ext->mstat);
263 
264 			/*
265 			 * If not installing from a partially spooled package
266 			 * (the "save/pspool" area), and the file contents can
267 			 * be changed (type is 'e' or 'v'), and the class is not
268 			 * "none": copy the file from the package (in pristine
269 			 * state with no actions performed) into the appropriate
270 			 * location in the packages destination "save/pspool"
271 			 * area.
272 			 */
273 
274 			if ((!is_partial_inst()) &&
275 				((ept->ftype == 'e') || (ept->ftype == 'v')) &&
276 				(strcmp(ept->pkg_class, "none") != 0)) {
277 
278 				if (absolutepath(ext->map_path) == B_TRUE &&
279 					parametricpath(ext->cf_ent.ainfo.local,
280 						&relocpath) == B_FALSE) {
281 					pspool_loc = ROOT;
282 				} else {
283 					pspool_loc = RELOC;
284 				}
285 
286 				n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s",
287 					saveSpoolInstallDir, pspool_loc,
288 					relocpath ? relocpath : ext->map_path);
289 
290 				if (n >= PATH_MAX) {
291 					progerr(ERR_CREATE_PATH_2,
292 						saveSpoolInstallDir,
293 						ext->map_path);
294 					quit(99);
295 				}
296 
297 				/* copy, preserve source file mode */
298 
299 				if (cppath(MODE_SRC, srcp, scrpt_dst, 0644)) {
300 					warnflag++;
301 				}
302 			}
303 
304 			/*
305 			 * If this isn't writeable anyway, it's not going
306 			 * into the list file. Only count it if it's going
307 			 * into the list file.
308 			 */
309 			if (is_fs_writeable(ext->cf_ent.path,
310 				&(ext->fsys_value)))
311 				count++;
312 
313 			pkgvolume(&pkgdev, srcinst, part, nparts);
314 
315 			/*
316 			 * If source verification is OK for this class, make
317 			 * sure the source we're passing to the class action
318 			 * script is useable.
319 			 */
320 			if (cl_svfy(classidx) != NOVERIFY) {
321 				if (cl_iscript(classidx) ||
322 					((ept->ftype == 'e') ||
323 					(ept->ftype == 'n'))) {
324 					if (ck_efile(srcp, ept)) {
325 						progerr(ERR_CORRUPT,
326 							srcp);
327 						logerr(getErrbufAddr());
328 						warnflag++;
329 						continue;
330 					}
331 				}
332 			}
333 
334 			/*
335 			 * If there's a class action script for this class,
336 			 * just collect names in a temporary file
337 			 * that will be used as the stdin when the
338 			 * class action script is invoked.
339 			 */
340 
341 			if ((cl_iscript(classidx)) &&
342 					((is_fs_writeable(ept->path,
343 						&(ext->fsys_value))))) {
344 				if (pass_relative) {
345 					if (!rel_init) {
346 						(void) fputs(instdir, listfp);
347 						(void) putc('\n', listfp);
348 						rel_init++;
349 					}
350 					(void) fputs(ext->map_path, listfp);
351 					(void) putc('\n', listfp);
352 				} else {
353 					(void) fputs(srcp ?
354 						srcp : "/dev/null", listfp);
355 					(void) putc(' ', listfp);
356 					(void) fputs(dstp, listfp);
357 					(void) putc('\n', listfp);
358 				}
359 				/*
360 				 * Note which entries in extlist are regular
361 				 * files to be installed via the class action
362 				 * script.
363 				 */
364 				if (regfiles_head == NULL) {
365 					assert(rfp == NULL);
366 					regfiles_head =
367 					    malloc(sizeof (struct reg_files));
368 					if (regfiles_head == NULL) {
369 						progerr(ERR_MEMORY, errno);
370 						quit(99);
371 					}
372 					regfiles_head->next = NULL;
373 					regfiles_head->val = entryidx;
374 					rfp = regfiles_head;
375 				} else {
376 					assert(rfp != NULL);
377 					rfp->next =
378 					    malloc(sizeof (struct reg_files));
379 					if (rfp->next == NULL) {
380 						progerr(ERR_MEMORY, errno);
381 						quit(99);
382 					}
383 					rfp = rfp->next;
384 					rfp->next = NULL;
385 					rfp->val = entryidx;
386 				}
387 
388 				/*
389 				 * A warning message about unwritable targets
390 				 * in a class may be appropriate here.
391 				 */
392 				continue;
393 			}
394 
395 			/*
396 			 * If not installing from a partially spooled package
397 			 * (the "save/pspool" area), and the file contents can
398 			 * be changed (type is 'e' or 'v') and the class
399 			 * identifier is not "none": copy the file from the
400 			 * package (in pristine state with no actions performed)
401 			 * into the appropriate location in the packages
402 			 * destination "save/pspool" area.
403 			 */
404 
405 			if ((!is_partial_inst()) &&
406 			    ((ept->ftype == 'e') || (ept->ftype == 'v') &&
407 			    (strcmp(ept->pkg_class, "none") != 0))) {
408 
409 				if (absolutepath(ext->map_path) == B_TRUE &&
410 					parametricpath(ext->cf_ent.ainfo.local,
411 						&relocpath) == B_FALSE) {
412 					pspool_loc = ROOT;
413 				} else {
414 					pspool_loc = RELOC;
415 				}
416 
417 				n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s",
418 					saveSpoolInstallDir, pspool_loc,
419 					relocpath ? relocpath : ext->map_path);
420 
421 				if (n >= PATH_MAX) {
422 					progerr(ERR_CREATE_PATH_2,
423 						saveSpoolInstallDir,
424 						ext->map_path);
425 					quit(99);
426 				}
427 
428 				/* copy, preserve source file mode */
429 
430 				if (cppath(MODE_SRC, srcp, scrpt_dst, 0644)) {
431 					warnflag++;
432 				}
433 			}
434 
435 			/*
436 			 * There are several tests here to determine
437 			 * how we're going to deal with objects
438 			 * intended for remote read-only filesystems.
439 			 * We don't use is_served() because this may be
440 			 * a server. We're actually interested in if
441 			 * it's *really* remote and *really* not
442 			 * writeable.
443 			 */
444 
445 			n = is_remote_fs(ept->path, &(ext->fsys_value));
446 			if ((n != 0) &&
447 				!is_fs_writeable(ept->path,
448 				&(ext->fsys_value))) {
449 
450 				/*
451 				 * Don't change the file, we can't write
452 				 * to it anyway.
453 				 */
454 
455 				mstat->attrchg = 0;
456 				mstat->contchg = 0;
457 
458 				/*
459 				 * If it's currently mounted, we can
460 				 * at least test it for existence.
461 				 */
462 
463 				if (is_mounted(ept->path, &(ext->fsys_value))) {
464 					if (!isfile(NULL, dstp)) {
465 						echo(MSG_IS_PRESENT, dstp);
466 					} else {
467 						echo(WRN_INSTVOL_NONE, dstp);
468 					}
469 				} else {
470 					char *server_host;
471 
472 					server_host = get_server_host(
473 						ext->fsys_value);
474 
475 					/* If not, we're just stuck. */
476 					echo(WRN_INSTVOL_NOVERIFY,
477 						dstp, server_host);
478 				}
479 
480 				continue;
481 			}
482 
483 			/* echo output destination name */
484 
485 			echo("%s", dstp);
486 
487 			/*
488 			 * if no source then no need to copy/verify
489 			 */
490 
491 			if (srcp == (char *)NULL) {
492 				continue;
493 			}
494 
495 			/*
496 			 * If doing a partial installation (creating a
497 			 * non-global zone), extra steps need to be taken:
498 			 *
499 			 * 1) if the file is not type 'e' and not type 'v' and
500 			 * the class is "none": then the file must already
501 			 * exist (as a result of the initial non-global zone
502 			 * installation which caused all non-e/v files to be
503 			 * copied from the global zone to the non-global
504 			 * zone). If this is the case, verify that the file
505 			 * exists and has the correct attributes.
506 			 *
507 			 * 2) if the file is not type 'e' and not type 'v'
508 			 * and the class is NOT "none", *OR* if the file is
509 			 * type 'e' or type 'v': then check to see if the
510 			 * file is located in an area inherited from the
511 			 * global zone. If so, then there is no ability to
512 			 * change the file since inherited file systems are
513 			 * "read only" - just verify that the file exists and
514 			 * verify attributes only if not 'e' or 'v'.
515 			 */
516 
517 			if (is_partial_inst() != 0) {
518 
519 				/*
520 				 * determine if the destination package is in an
521 				 * area inherited from the global zone
522 				 */
523 
524 				n = pkgMatchInherited(srcp, dstp,
525 					get_inst_root(), ept->ainfo.mode,
526 					ept->cinfo.modtime, ept->ftype,
527 					ept->cinfo.cksum);
528 
529 				echoDebug(DBG_INSTVOL_PARTIAL_INST,
530 					srcp ? srcp : "", dstp ? dstp: "",
531 					((get_inst_root()) &&
532 					(strcmp(get_inst_root(), "/") != 0)) ?
533 					get_inst_root() : "",
534 					ept->ainfo.mode, ept->cinfo.modtime,
535 					ept->ftype, ept->cinfo.cksum, n);
536 
537 				/*
538 				 * if not type 'e|v' and class 'none', then the
539 				 * file must already exist.
540 				 */
541 
542 				if ((ept->ftype != 'e') &&
543 					(ept->ftype != 'v') &&
544 					(strcmp(cl_nam(ept->pkg_class_idx),
545 								"none") == 0)) {
546 
547 					/*
548 					 * if the file is in a space inherited
549 					 * from the global zone, and if the
550 					 * contents or attributes are incorrect,
551 					 * then generate a warning that the
552 					 * global zone file contents and/or file
553 					 * attributes have been modified and
554 					 * that the modifications are extended
555 					 * to the non-global zone (inherited
556 					 * from the global zone).
557 					 */
558 
559 					if (n == 0) {
560 						/* is file changed? */
561 						n = finalck(ept, 1, 1, B_TRUE);
562 
563 						/* no - ok - continue */
564 						if (n == 0) {
565 							continue;
566 						}
567 
568 						/* output warning message */
569 						logerr(NOTE_INSTVOL_FINALCKFAIL,
570 							pkginst, ext->map_path,
571 							a_zoneName, ept->path);
572 						continue;
573 					} else if (!finalck(ept, 1, 1,
574 								B_FALSE)) {
575 						/*
576 						 * non-e/v file of class "none"
577 						 * not inherited from the global
578 						 * zone: verify file already
579 						 * exists:everything checks here
580 						 */
581 						mstat->attrchg = 0;
582 						mstat->contchg = 0;
583 					}
584 					continue;
585 				}
586 
587 				/*
588 				 * non-e/v file with class action script, or
589 				 * e/v file: if the file is in an area inherited
590 				 * from the global zone, then no need (or the
591 				 * ability) to update just accept the file as is
592 				 */
593 
594 				if (n == B_TRUE) {
595 					/*
596 					 * the object is in an area inherited
597 					 * from the global zone and the objects
598 					 * attributes are verified
599 					 */
600 
601 					mstat->attrchg = 0;
602 					mstat->contchg = 0;
603 
604 					/* NOTE: package object skipped */
605 
606 					if (skipped == (char *)NULL) {
607 						skipped = dstp;
608 					echoDebug(DBG_INSTVOL_OBJ_SKIPPED,
609 								skipped);
610 					}
611 					continue;
612 				}
613 			}
614 
615 			/*
616 			 * Copy from source media to target path and fix file
617 			 * mode and permission now in case installation halted.
618 			 */
619 
620 			if (z_path_is_inherited(dstp, ept->ftype,
621 			    get_inst_root()) == B_FALSE) {
622 
623 				/*
624 				 * If the filesystem is read-only don't attempt
625 				 * to copy a file. Just check that the content
626 				 * and attributes of the file are correct.
627 				 *
628 				 * Normally this doesn't happen, because files,
629 				 * which don't change, are not returned by
630 				 * domerg(). However when installing a patch in
631 				 * a sparse zone, which was already installed
632 				 * in global zone with -G option, NGZ's
633 				 * contents db still contains the old record
634 				 * for this file and therefore domerg()
635 				 * considers these files to be different even
636 				 * though they are the same.
637 				 */
638 				n = 0;
639 				if (is_fs_writeable(ept->path,
640 				    &(ext->fsys_value)))
641 					n = cppath(MODE_SET|DIR_DISPLAY, srcp,
642 					    dstp, ept->ainfo.mode);
643 
644 				if (n != 0) {
645 					warnflag++;
646 				} else if (!finalck(ept, 1, 1, B_FALSE)) {
647 					/*
648 					 * everything checks here
649 					 */
650 					mstat->attrchg = 0;
651 					mstat->contchg = 0;
652 				}
653 			}
654 
655 			/* NOTE: a package object was updated */
656 
657 			if (updated == (char *)NULL) {
658 				echoDebug(DBG_INSTVOL_OBJ_UPDATED, dstp);
659 				updated = dstp;
660 			}
661 		}
662 
663 		/*
664 		 * We have now completed processing of all pathnames
665 		 * associated with this volume and class.
666 		 */
667 		if (cl_iscript(classidx)) {
668 			/*
669 			 * Execute appropriate class action script
670 			 * with list of source/destination pathnames
671 			 * as the input to the script.
672 			 */
673 
674 			if (chdir(pkgbin)) {
675 				progerr(ERR_CHGDIR, pkgbin);
676 				quit(99);
677 			}
678 
679 			if (listfp) {
680 				(void) fclose(listfp);
681 			}
682 
683 			/*
684 			 * if the object associated with the class action script
685 			 * is in an area inherited from the global zone, then
686 			 * there is no need to run the class action script -
687 			 * assume that anything the script would do has already
688 			 * been done in the area shared from the global zone.
689 			 */
690 
691 			/* nothing updated, nothing skipped */
692 
693 			echoDebug(DBG_INSTVOL_CAS_INFO, is_partial_inst(),
694 				updated ? updated : "",
695 				skipped ? skipped : "",
696 				anyPathLocal ? anyPathLocal : "");
697 
698 			if ((is_partial_inst() != 0) &&
699 					(updated == (char *)NULL) &&
700 					(anyPathLocal == (char *)NULL)) {
701 
702 				/*
703 				 * installing in non-global zone, and no object
704 				 * has been updated (installed/verified in non-
705 				 * inherited area), and no path delivered by the
706 				 * package is in an area not inherited from the
707 				 * global zone (all paths delivered are in
708 				 * areas inherited from the global zone): do not
709 				 * run the class action script because the only
710 				 * affected areas are inherited (read only).
711 				 */
712 
713 				echoDebug(DBG_INSTVOL_NOT_RUNNING_CAS,
714 					a_zoneName ? a_zoneName : "?",
715 					eocflag ? "ENDOFCLASS" :
716 							cl_iscript(classidx),
717 					cl_nam(classidx),
718 					cl_iscript(classidx));
719 
720 				if ((r_skipped != (char **)NULL) &&
721 					(*r_skipped == (char *)NULL) &&
722 					(skipped == (char *)NULL)) {
723 					skipped = "postinstall";
724 					echoDebug(DBG_INSTVOL_OBJ_SKIPPED,
725 								skipped);
726 				}
727 			} else {
728 				/* run the class action script */
729 
730 				echoDebug(DBG_INSTVOL_RUNNING_CAS,
731 					a_zoneName ? a_zoneName : "?",
732 					eocflag ? "ENDOFCLASS" :
733 							cl_iscript(classidx),
734 					cl_nam(classidx),
735 					cl_iscript(classidx));
736 
737 				/* Use ULIMIT if supplied. */
738 				set_ulimit(cl_iscript(classidx), ERR_CASFAIL);
739 
740 				if (eocflag) {
741 					/*
742 					 * end of class detected.
743 					 * Since there are no more volumes which
744 					 * contain pathnames associated with
745 					 * this class, execute class action
746 					 * script with the ENDOFCLASS argument;
747 					 * we do this even if none of the path
748 					 * names associated with this class and
749 					 * volume needed installation to
750 					 * guarantee the class action script is
751 					 * executed at least once during package
752 					 * installation.
753 					 */
754 					if (pkgverbose) {
755 						n = pkgexecl((listfp ?
756 							listfile : CAS_STDIN),
757 							CAS_STDOUT,
758 							CAS_USER, CAS_GRP,
759 							SHELL, "-x",
760 							cl_iscript(classidx),
761 							"ENDOFCLASS", NULL);
762 					} else {
763 						n = pkgexecl(
764 							(listfp ?
765 							listfile : CAS_STDIN),
766 							CAS_STDOUT, CAS_USER,
767 							CAS_GRP, SHELL,
768 							cl_iscript(classidx),
769 							"ENDOFCLASS", NULL);
770 					}
771 					ckreturn(n, ERR_CASFAIL);
772 				} else if (count) {
773 					/* execute class action script */
774 					if (pkgverbose) {
775 						n = pkgexecl(listfile,
776 							CAS_STDOUT, CAS_USER,
777 							CAS_GRP, SHELL, "-x",
778 							cl_iscript(classidx),
779 							NULL);
780 					} else {
781 						n = pkgexecl(listfile,
782 							CAS_STDOUT, CAS_USER,
783 							CAS_GRP, SHELL,
784 							cl_iscript(classidx),
785 							NULL);
786 					}
787 					ckreturn(n, ERR_CASFAIL);
788 				}
789 
790 				/*
791 				 * Ensure the mod times on disk match those
792 				 * in the pkgmap. In this case, call cverify
793 				 * with checksumming disabled, since the only
794 				 * action that needs to be done is to verify
795 				 * that the attributes are correct.
796 				 */
797 
798 				if ((rfp = regfiles_head) != NULL) {
799 					while (rfp != NULL) {
800 					    ept = &(extlist[rfp->val]->cf_ent);
801 					    cverify(1, &ept->ftype, ept->path,
802 						&ept->cinfo, 0);
803 					    rfp = rfp->next;
804 					}
805 					regfiles_free();
806 				}
807 
808 				clr_ulimit();
809 
810 				if ((r_updated != (char **)NULL) &&
811 					(*r_updated == (char *)NULL) &&
812 					(updated == (char *)NULL)) {
813 					updated = "postinstall";
814 					echoDebug(DBG_INSTVOL_OBJ_UPDATED,
815 								updated);
816 				}
817 			}
818 			if (listfile) {
819 				(void) remove(listfile);
820 			}
821 		}
822 
823 		if (eocflag && (!is_partial_inst() || (is_partial_inst() &&
824 			strcmp(cl_nam(classidx), "none") != 0))) {
825 			if (cl_dvfy(classidx) == QKVERIFY && !repl_permitted) {
826 				/*
827 				 * The quick verify just fixes everything.
828 				 * If it returns 0, all is well. If it
829 				 * returns 1, then the class installation
830 				 * was incomplete and we retry on the
831 				 * stuff that failed in the conventional
832 				 * way (without a CAS). this is primarily
833 				 * to accomodate old archives such as are
834 				 * found in pre-2.5 WOS; but, it is also
835 				 * used when a critical dynamic library
836 				 * is not archived with its class.
837 				 */
838 				if (!fix_attributes(extlist, classidx)) {
839 					/*
840 					 * Reset the CAS pointer. If the
841 					 * function returns 0 then there
842 					 * was no script there in the first
843 					 * place and we'll just have to
844 					 * call this a miss.
845 					 */
846 					if (cl_deliscript(classidx))
847 						/*
848 						 * Decrement classidx for
849 						 * next pass.
850 						 */
851 						classidx--;
852 				}
853 			} else {
854 				/*
855 				 * Finalize merge. This checks to make sure
856 				 * file attributes are correct and any links
857 				 * specified are created.
858 				 */
859 				(void) endofclass(extlist, classidx,
860 					(cl_iscript(classidx) ? 0 : 1),
861 					pkgserver, a_cfTmpVfp);
862 			}
863 		}
864 	    }
865 	}
866 
867 	/*
868 	 * Instead of creating links back to the GZ files the logic is
869 	 * to let zdo recreate the files from the GZ then invoke pkgadd to
870 	 * install the editable files and skip over any 'f'type files.
871 	 * The commented out block is to create the links which should be
872 	 * removed once the current code is tested to be correct.
873 	 */
874 
875 	/*
876 	 * Go through extlist creating links for 'f'type files
877 	 * if we're in a global zone. Note that this code lies
878 	 * here instead of in the main loop to support CAF packages.
879 	 * In a CAF package the files are installed by the i.none script
880 	 * and don't exist until all files are done being processed, thus
881 	 * the additional loop through extlist.
882 	 */
883 
884 	/*
885 	 * output appropriate completion message
886 	 */
887 
888 	if (is_depend_pkginfo_DB() == B_TRUE) {
889 		/* updating database only (hollow package) */
890 		if (a_zoneName == (char *)NULL) {
891 			echo(MSG_DBUPD_N_N, part, nparts);
892 		} else {
893 			echo(MSG_DBUPD_N_N_LZ, part, nparts, a_zoneName);
894 		}
895 	} else if (tcount == 0) {
896 		/* updating package (non-hollow package) */
897 		if (a_zoneName == (char *)NULL) {
898 			echo(MSG_INST_N_N, part, nparts);
899 		} else {
900 			echo(MSG_INST_N_N_LZ, part, nparts, a_zoneName);
901 		}
902 	}
903 
904 	/*
905 	 * if any package objects were updated (not inherited from the
906 	 * global zone or otherwise already in existence), set the updated
907 	 * flag as appropriate
908 	 */
909 
910 	if (updated != (char *)NULL) {
911 		echoDebug(DBG_INSTVOL_OBJ_UPDATED, updated);
912 		if (r_updated != (char **)NULL) {
913 			*r_updated = updated;
914 		}
915 	}
916 
917 	/*
918 	 * if any package objects were skipped (verified inherited from the
919 	 * global zone), set the skipped flag as appropriate
920 	 */
921 
922 	if (skipped != (char *)NULL) {
923 		echoDebug(DBG_INSTVOL_OBJ_SKIPPED, skipped);
924 		if (r_skipped != (char **)NULL) {
925 			*r_skipped = skipped;
926 		}
927 	}
928 }
929 
930 /*
931  * Name:	domerg
932  * Description: For the specified class, review each entry and return the array
933  *		index number of the next regular file to process. Hard links are
934  *		skipped (they are created in endofclass() and directories,
935  *		symlinks, pipes and devices are created here, as well as any
936  *		file that already exists and has the correct attributes.
937  * Arguments:	struct cfextra **extlist - [RO, *RW]
938  *			- Pointer to list of cfextra structures representing
939  *			  the pkgmap of the package to be installed
940  *		int part - [RO, *RO]
941  *			- the part of the package currently being processed;
942  *			  packages begin with part "1" and proceed for the
943  *			  number (nparts) that comprise the package (volume).
944  *		int nparts - [RO, *RO]
945  *			- the number of parts the package is divided into
946  *		int myclass - [RO, *RO]
947  *			- index into class array of the current class
948  *		char **srcp - [RW, *RW]
949  *			- pointer to pointer to string representing the source
950  *			  path for the next package to process - if this
951  *			  function returns != DMRG_DONE then this pointer is
952  *			  set to a pointer to a string representing the source
953  *			  path for the next object from the package to process
954  *		char **dstp - [RW, *RW]
955  *			- pointer to pointer to string representing the target
956  *			  path for the next package to process - if this
957  *			  function returns != DMRG_DONE then this pointer is
958  *			  set to a pointer to a string representing the target
959  *			  path for the next object from the package to process
960  *		char **r_updated - [RO, *RW]
961  *			- pointer to pointer to string - set if the last path
962  *			  returned exists or does not need updating and the
963  *			  object is NOT located in an area inherited from the
964  *			  global zone. This is used to determine if the last
965  *			  path object returned DOES exist in an area that is
966  *			  inherited from the global zone. If no paths are
967  *			  inherited from the global zone, this is always set
968  *			  when a path to be installed exists and has the
969  *			  correct contents.
970  *		char **r_skipped - [RO, *RW]
971  *			- pointer to pointer to string - set if the last path
972  *			  returned exists or does not need updating and the
973  *			  object IS located in an area inherited from the
974  *			  global zone. This is used to determine if the last
975  *			  path object returned does NOT exist in an area that
976  *			  is inherited from the global zone. If no paths are
977  *			  inherited from the global zone, this is never set.
978  *		char **r_anyPathLocal - [RO, *RW]
979  *			- pointer to pointer to string - set if any object
980  *			  belonging to the package is NOT located in an area
981  *			  inherited from the global zone. This is used to
982  *			  determine if the package references ANY objects that
983  *			  are NOT located in an area inherited from the global
984  *			  zone - regardless of whether or not they need to be
985  *			  updated (installed/copied). If no paths are inherited
986  *			  from the global zone, this is always set when a path
987  *			  to be installed already exists and has the correct
988  *			  contents.
989  * Returns:	int
990  *			!= DMRG_DONE - index into extlist of the next path to
991  *				be processed - that needs to be installed/copied
992  *			== DMRG_DONE - all entries processed
993  */
994 
995 static int
996 domerg(struct cfextra **extlist, int part, int nparts,
997 	int myclass, char **srcp, char **dstp,
998 	char **r_updated, char **r_skipped,
999 	char **r_anyPathLocal)
1000 {
1001 	boolean_t	stateFlag = B_FALSE;
1002 	int		i;
1003 	int		msg_ugid;
1004 	static int	maxvol = 0;
1005 	static int	svindx = 0;
1006 	static int	svpart = 0;
1007 	struct cfent	*ept = (struct cfent *)NULL;
1008 	struct mergstat *mstat = (struct mergstat *)NULL;
1009 
1010 	/* reset returned path pointers */
1011 
1012 	*dstp = (char *)NULL;
1013 	*srcp = (char *)NULL;
1014 
1015 	/* set to start or continue based on which part being processed */
1016 
1017 	if (part != 0) {
1018 		maxvol = 0;
1019 		svindx = 0;
1020 		svpart = part;
1021 	} else {
1022 		i = svindx;
1023 		part = svpart;
1024 	}
1025 
1026 	/*
1027 	 * This goes through the pkgmap entries one by one testing them
1028 	 * for inclusion in the package database as well as for validity
1029 	 * against existing files.
1030 	 */
1031 	for (i = svindx; extlist[i]; i++) {
1032 		ept = &(extlist[i]->cf_ent);
1033 		mstat = &(extlist[i]->mstat);
1034 
1035 		/*
1036 		 * as paths are processed, if the "anyPathLocal" flag has not
1037 		 * been set, if the object is not of type 'i' (package script),
1038 		 * check to see if the object is in an area inherited from the
1039 		 * global zone - if not, set "anyPathLocal" to the path found,
1040 		 * indicating that at least one path is in an area that is not
1041 		 * inherited from the global zone.
1042 		 */
1043 
1044 		if ((r_anyPathLocal != (char **)NULL) &&
1045 			(*r_anyPathLocal == (char *)NULL) &&
1046 			(ept->ftype != 'i') &&
1047 			(z_path_is_inherited(ept->path, ept->ftype,
1048 						get_inst_root()) == B_FALSE)) {
1049 			echoDebug(DBG_INSTVOL_OBJ_LOCAL, ept->path);
1050 			*r_anyPathLocal = ept->path;
1051 		}
1052 
1053 		/* if this isn't the class of current interest, skip it */
1054 
1055 		if (myclass != ept->pkg_class_idx) {
1056 			continue;
1057 		}
1058 
1059 		/* if the class is invalid, announce it & exit */
1060 		if (ept->pkg_class_idx == -1) {
1061 			progerr(ERR_CLIDX, ept->pkg_class_idx,
1062 			    (ept->path && *ept->path) ? ept->path : "unknown");
1063 			logerr(gettext("pathname=%s"),
1064 			    (ept->path && *ept->path) ? ept->path : "unknown");
1065 			logerr(gettext("class=<%s>"),
1066 			    (ept->pkg_class && *ept->pkg_class) ?
1067 			    ept->pkg_class : "Unknown");
1068 			logerr(gettext("CLASSES=<%s>"),
1069 			    getenv("CLASSES") ? getenv("CLASSES") : "Not Set");
1070 			quit(99);
1071 		}
1072 
1073 		/*
1074 		 * Next check to see if we are going to try to delete a
1075 		 * populated directory in some distressing way.
1076 		 */
1077 		if (mstat->dir2nondir)
1078 			if (dir_is_populated(ept->path)) {
1079 				logerr(WRN_INSTVOL_NOTDIR, ept->path);
1080 				warnflag++;
1081 				mstat->denied = 1;	/* install denied! */
1082 				continue;
1083 			} else {	/* Replace is OK. */
1084 				/*
1085 				 * Remove this directory, so it won't
1086 				 * interfere with creation of the new object.
1087 				 */
1088 				if (rmdir(ept->path)) {
1089 					/*
1090 					 * If it didn't work, there's nothing
1091 					 * we can do. To continue would
1092 					 * likely corrupt the filesystem
1093 					 * which is unacceptable.
1094 					 */
1095 					progerr(ERR_RMDIR, ept->path);
1096 					quit(99);
1097 				}
1098 
1099 				repl_permitted = 1;	/* flag it */
1100 			}
1101 
1102 		/* adjust the max volume number appropriately */
1103 
1104 		if (ept->volno > maxvol) {
1105 			maxvol = ept->volno;
1106 		}
1107 
1108 		/* if this part goes into another volume, skip it */
1109 
1110 		if (part != ept->volno) {
1111 			continue;
1112 		}
1113 
1114 		/*
1115 		 * If it's a conflicting file and it's not supposed to be
1116 		 * installed, note it and skip.
1117 		 */
1118 		if (nocnflct && mstat->shared && ept->ftype != 'e') {
1119 			if (mstat->contchg || mstat->attrchg) {
1120 				echo(MSG_SHIGN, ept->path);
1121 			}
1122 			continue;
1123 		}
1124 
1125 		/*
1126 		 * If we want to set uid or gid but user says no, note it.
1127 		 * Remember that the actual mode bits in the structure have
1128 		 * already been adjusted and the mstat flag is telling us
1129 		 * about the original mode.
1130 		 */
1131 		if (nosetuid && (mstat->setuid || mstat->setgid)) {
1132 			msg_ugid = 1;	/* don't repeat attribute message. */
1133 			if (is_fs_writeable(ept->path,
1134 				&(extlist[i]->fsys_value))) {
1135 				if (!(mstat->contchg) && mstat->attrchg) {
1136 					echo(MSG_UGMOD, ept->path);
1137 				} else {
1138 					echo(MSG_UGID, ept->path);
1139 				}
1140 			}
1141 		} else {
1142 			msg_ugid = 0;
1143 		}
1144 
1145 		switch (ept->ftype) {
1146 			case 'l':	/* hard link */
1147 				/* links treated as object "update/skip" */
1148 				stateFlag = B_TRUE;
1149 				continue; /* defer to final proc */
1150 
1151 			case 's': /* for symlink, verify without fix first */
1152 				/* links treated as object "update/skip" */
1153 				stateFlag = B_TRUE;
1154 
1155 				/* Do this only for default verify */
1156 				if (cl_dvfy(myclass) == DEFAULT) {
1157 					if (averify(0, &ept->ftype,
1158 						ept->path, &ept->ainfo))
1159 						echo(MSG_SLINK, ept->path);
1160 				}
1161 
1162 				/*FALLTHRU*/
1163 
1164 			case 'd':	/* directory */
1165 			case 'x':	/* exclusive directory */
1166 			case 'c':	/* character special device */
1167 			case 'b':	/* block special device */
1168 			case 'p':	/* named pipe */
1169 				/* these NOT treated as object "update/skip" */
1170 				stateFlag = B_FALSE;
1171 
1172 				/*
1173 				 * If we can't get to it for legitimate reasons,
1174 				 * don't try to verify it.
1175 				 */
1176 				if ((z_path_is_inherited(ept->path, ept->ftype,
1177 				    get_inst_root())) ||
1178 				    is_remote_fs(ept->path,
1179 				    &(extlist[i]->fsys_value)) &&
1180 				    !is_fs_writeable(ept->path,
1181 				    &(extlist[i]->fsys_value))) {
1182 					mstat->attrchg = 0;
1183 					mstat->contchg = 0;
1184 					break;
1185 				}
1186 
1187 				if (averify(1, &ept->ftype, ept->path,
1188 							&ept->ainfo) == 0) {
1189 					mstat->contchg = mstat->attrchg = 0;
1190 				} else {
1191 					progerr(ERR_CREATE_PKGOBJ, ept->path);
1192 					logerr(getErrbufAddr());
1193 					warnflag++;
1194 				}
1195 
1196 				break;
1197 
1198 			case 'i':	/* information file */
1199 				/* not treated as object "update/skip" */
1200 				stateFlag = B_FALSE;
1201 				break;
1202 
1203 			default:
1204 				/* all files treated as object "update/skip" */
1205 				stateFlag = B_TRUE;
1206 				break;
1207 		}
1208 
1209 		/*
1210 		 * Both contchg and shared flags have to be taken into
1211 		 * account. contchg is set if the file is already present
1212 		 * in the package database, if it does not exist or if it
1213 		 * exists and is modified.
1214 		 * The shared flag is set when 'e' or 'v' file is not
1215 		 * present in the package database, exists and is not
1216 		 * modified. It also has to be checked here.
1217 		 * Shared flag is also set when file is present in package
1218 		 * database and owned by more than one package, but for
1219 		 * this case contchg has already been set.
1220 		 */
1221 		if (mstat->contchg || (mstat->shared &&
1222 		    ((ept->ftype == 'e') || (ept->ftype == 'v')))) {
1223 			*dstp = ept->path;
1224 			if ((ept->ftype == 'f') || (ept->ftype == 'e') ||
1225 				(ept->ftype == 'v')) {
1226 				*srcp = ept->ainfo.local;
1227 				if (is_partial_inst() != 0) {
1228 					if (*srcp[0] == '~') {
1229 						/* Done only for C style */
1230 						char *tmp_ptr;
1231 						tmp_ptr = extlist[i]->map_path;
1232 						if (ept->ftype != 'f') {
1233 							/*
1234 							 * translate source
1235 							 * pathname
1236 							 */
1237 							*srcp =
1238 							    srcpath(instdir,
1239 							    tmp_ptr,
1240 							    part,
1241 							    nparts);
1242 						} else {
1243 						/*
1244 						 * instdir has the absolute path
1245 						 * to saveSpoolInstallDir for
1246 						 * the package. This is only
1247 						 * useful for 'e','v' types.
1248 						 *
1249 						 * For 'f', we generate the
1250 						 * absolute src path with the
1251 						 * help of install root and the
1252 						 * basedir.
1253 						 */
1254 							*srcp = trans_srcp_pi(
1255 							    ept->ainfo.local);
1256 						}
1257 					} else {
1258 						*srcp = extlist[i]->map_path;
1259 					}
1260 				} else {
1261 					if (*srcp[0] == '~') {
1262 						/* translate source pathname */
1263 						*srcp = srcpath(instdir,
1264 						    &(ept->ainfo.local[1]),
1265 						    part, nparts);
1266 					}
1267 				}
1268 
1269 				echoDebug(DBG_DOMERG_NO_SUCH_FILE,
1270 					ept->ftype, cl_nam(ept->pkg_class_idx),
1271 					ept->path);
1272 			} else {
1273 				/*
1274 				 * At this point, we're returning a non-file
1275 				 * that couldn't be created in the standard
1276 				 * way. If it refers to a filesystem that is
1277 				 * not writeable by us, don't waste the
1278 				 * calling process's time.
1279 				 */
1280 				if (!is_fs_writeable(ept->path,
1281 					&(extlist[i]->fsys_value))) {
1282 					echoDebug(DBG_DOMERG_NOT_WRITABLE,
1283 						ept->ftype,
1284 						cl_nam(ept->pkg_class_idx),
1285 						ept->path);
1286 					continue;
1287 				}
1288 
1289 				*srcp = NULL;
1290 				echoDebug(DBG_DOMERG_NOT_THERE,
1291 					ept->ftype, cl_nam(ept->pkg_class_idx),
1292 					ept->path);
1293 			}
1294 
1295 			svindx = i+1;
1296 			backup(*dstp, 1);
1297 			return (i);
1298 		}
1299 
1300 		if (mstat->attrchg) {
1301 			backup(ept->path, 0);
1302 			if (!msg_ugid)
1303 				echo(MSG_ATTRIB, ept->path);
1304 
1305 			/* fix the attributes now for robustness sake */
1306 			if (averify(1, &ept->ftype,
1307 				ept->path,
1308 				&ept->ainfo) == 0) {
1309 				mstat->attrchg = 0;
1310 			}
1311 		}
1312 
1313 		/*
1314 		 * package object exists, or does not need updating: if the path
1315 		 * is in an area inherited from the global zone, then treat
1316 		 * the object as if it were "skipped" - if the path is not in an
1317 		 * area inherited from the global zone, then treat the object as
1318 		 * if it were "updated"
1319 		 */
1320 
1321 		/* LINTED warning: statement has no consequent: if */
1322 		if ((stateFlag == B_FALSE) || (ept == (struct cfent *)NULL)) {
1323 			/*
1324 			 * the object in question is a directory or special
1325 			 * file - the fact that this type of object already
1326 			 * exists or does not need updating must not trigger
1327 			 * the object updated/object skipped indication -
1328 			 * that would cause class action scripts to be run
1329 			 * when installing a new non-global zone - that action
1330 			 * must only be done when a file object that is in
1331 			 * an area inherited from the global zone is present.
1332 			 */
1333 		} else if (z_path_is_inherited(ept->path, ept->ftype,
1334 						get_inst_root()) == B_TRUE) {
1335 			if (r_skipped != (char **)NULL) {
1336 				if (*r_skipped == (char *)NULL) {
1337 					echoDebug(DBG_INSTVOL_OBJ_SKIPPED,
1338 								ept->path);
1339 					*r_skipped = ept->path;
1340 				}
1341 			}
1342 		} else {
1343 			if (r_updated != (char **)NULL) {
1344 				if (*r_updated == (char *)NULL) {
1345 					echoDebug(DBG_INSTVOL_OBJ_UPDATED,
1346 								ept->path);
1347 				}
1348 				*r_updated = ept->path;
1349 			}
1350 		}
1351 	}
1352 
1353 	if (maxvol == part) {
1354 		eocflag++;	/* endofclass */
1355 	}
1356 
1357 	return (DMRG_DONE);	/* no remaining entries on this volume */
1358 }
1359 
1360 /*
1361  * Determine if the provided directory is populated. Return 0 if so and 1 if
1362  * not. This also returns 0 if the dirpath is not a directory or if it does
1363  * not exist.
1364  */
1365 static int
1366 dir_is_populated(char *dirpath) {
1367 	DIR	*dirfp;
1368 	struct	dirent *drp;
1369 	int	retcode = 0;
1370 
1371 	if ((dirfp = opendir(dirpath)) != NULL) {
1372 		while ((drp = readdir(dirfp)) != NULL) {
1373 			if (strcmp(drp->d_name, ".") == 0) {
1374 				continue;
1375 			}
1376 			if (strcmp(drp->d_name, "..") == 0) {
1377 				continue;
1378 			}
1379 			/*
1380 			 * If we get here, there's a real file in the
1381 			 * directory
1382 			 */
1383 			retcode = 1;
1384 			break;
1385 		}
1386 		(void) closedir(dirfp);
1387 	}
1388 
1389 	return (retcode);
1390 }
1391 
1392 /*
1393  * This is the function that cleans up the installation of this class.
1394  * This is where hard links get put in since the stuff they're linking
1395  * probably exists by now.
1396  */
1397 static void
1398 endofclass(struct cfextra **extlist, int myclass, int ckflag,
1399 	PKGserver pkgserver, VFP_T **a_cfTmpVfp)
1400 {
1401 	char		*temppath;
1402 	char 		*pspool_loc;
1403 	char 		*relocpath = (char *)NULL;
1404 	char 		scrpt_dst[PATH_MAX];
1405 	int		flag;
1406 	int		idx;
1407 	int		n;
1408 	struct cfent	*ept;	/* entry from the internal list */
1409 	struct cfextra	entry;	/* entry from the package database */
1410 	struct mergstat	*mstat;	/* merge status */
1411 	struct pinfo	*pinfo;
1412 
1413 	/* open the package database (contents) file */
1414 
1415 	if (!ocfile(&pkgserver, a_cfTmpVfp, pkgmap_blks)) {
1416 		quit(99);
1417 	}
1418 
1419 	echo(MSG_VERIFYING_CLASS, cl_nam(myclass));
1420 
1421 	for (idx = 0; /* void */; idx++) {
1422 		/* find next package object in this class */
1423 		while (extlist[idx]) {
1424 			if ((extlist[idx]->cf_ent.ftype != 'i') &&
1425 				extlist[idx]->cf_ent.pkg_class_idx == myclass) {
1426 				break;
1427 			}
1428 			idx++;
1429 		}
1430 
1431 		if (extlist[idx] == NULL)
1432 			break;
1433 
1434 
1435 		ept = &(extlist[idx]->cf_ent);
1436 		mstat = &(extlist[idx]->mstat);
1437 
1438 		temppath = extlist[idx]->client_path;
1439 
1440 		/*
1441 		 * At this point  the only difference between the entry
1442 		 * in the contents file and the entry in extlist[] is
1443 		 * that the status indicator contains CONFIRM_CONT.
1444 		 * This function should return one or something is wrong.
1445 		 */
1446 
1447 		n = srchcfile(&(entry.cf_ent), temppath, pkgserver);
1448 
1449 		if (n < 0) {
1450 			char	*errstr = getErrstr();
1451 			progerr(ERR_CFBAD);
1452 			logerr(gettext("pathname=%s"),
1453 				entry.cf_ent.path && *entry.cf_ent.path ?
1454 				entry.cf_ent.path : "Unknown");
1455 			logerr(gettext("problem=%s"),
1456 				(errstr && *errstr) ? errstr : "Unknown");
1457 			quit(99);
1458 		} else if (n != 1) {
1459 			/*
1460 			 * Check if path should be in the package
1461 			 * database.
1462 			 */
1463 			if ((mstat->shared && nocnflct)) {
1464 				continue;
1465 			}
1466 			progerr(ERR_CFMISSING, ept->path);
1467 			quit(99);
1468 		}
1469 
1470 		/*
1471 		 * If merge was not appropriate for this object, now is the
1472 		 * time to choose one or the other.
1473 		 */
1474 		if (mstat->denied) {
1475 			/*
1476 			 * If installation was denied AFTER the package
1477 			 * database was updated, skip this. We've already
1478 			 * announced the discrepancy and the verifications
1479 			 * that follow will make faulty decisions based on
1480 			 * the ftype, which may not be correct.
1481 			 */
1482 			progerr(ERR_COULD_NOT_INSTALL, ept->path);
1483 			warnflag++;
1484 		} else {
1485 			if (mstat->replace)
1486 				/*
1487 				 * This replaces the old entry with the new
1488 				 * one. This should never happen in the new
1489 				 * DB since the entries are already identical.
1490 				 */
1491 				repl_cfent(ept, &(entry.cf_ent));
1492 
1493 			/*
1494 			 * Validate this entry and change the status flag in
1495 			 * the package database.
1496 			 */
1497 			if (ept->ftype == RM_RDY) {
1498 				(void) eptstat(&(entry.cf_ent), pkginst,
1499 					STAT_NEXT);
1500 			} else {
1501 				/* check the hard link now. */
1502 				if (ept->ftype == 'l') {
1503 					if (averify(0, &ept->ftype,
1504 						ept->path, &ept->ainfo)) {
1505 						echo(MSG_HRDLINK,
1506 							ept->path);
1507 						mstat->attrchg++;
1508 					}
1509 				}
1510 
1511 				/*
1512 				 * Don't install or verify objects for
1513 				 * remote, read-only filesystems.  We need
1514 				 * only flag them as shared from some server.
1515 				 * Otherwise, ok to do final check.
1516 				 */
1517 				if (is_remote_fs(ept->path,
1518 					&(extlist[idx]->fsys_value)) &&
1519 					!is_fs_writeable(ept->path,
1520 					&(extlist[idx]->fsys_value))) {
1521 					flag = -1;
1522 				} else {
1523 					boolean_t inheritedFlag;
1524 					inheritedFlag =
1525 					    z_path_is_inherited(ept->path,
1526 						ept->ftype, get_inst_root());
1527 					flag = finalck(ept, mstat->attrchg,
1528 						(ckflag ? mstat->contchg :
1529 						(-1)), inheritedFlag);
1530 				}
1531 
1532 				pinfo = entry.cf_ent.pinfo;
1533 
1534 				/* Find this package in the list. */
1535 				while (pinfo) {
1536 					if (strcmp(pkginst, pinfo->pkg) == 0) {
1537 						break;
1538 					}
1539 					pinfo = pinfo->next;
1540 				}
1541 
1542 				/*
1543 				 * If this package owns this file, then store
1544 				 * it in the database with the appropriate
1545 				 * status. Need to check pinfo in case it
1546 				 * points to NULL which could happen if
1547 				 * pinfo->next = NULL above.
1548 				 */
1549 				if (pinfo) {
1550 					if (flag < 0 || is_served(ept->path,
1551 						&(extlist[idx]->fsys_value))) {
1552 						/*
1553 						 * This is provided to
1554 						 * clients by a server.
1555 						 */
1556 						pinfo->status = SERVED_FILE;
1557 					} else {
1558 						/*
1559 						 * It's either there or it's
1560 						 * not.
1561 						 */
1562 						pinfo->status = (flag ?
1563 							NOT_FND : ENTRY_OK);
1564 					}
1565 				}
1566 			}
1567 		}
1568 
1569 		/*
1570 		 * If not installing from a partially spooled package, the
1571 		 * "save/pspool" area, and the file contents can be
1572 		 * changed (type is 'e' or 'v'), and the class IS "none":
1573 		 * copy the installed volatile file into the appropriate
1574 		 * location in the packages destination "save/pspool" area.
1575 		 */
1576 
1577 		if ((!is_partial_inst()) &&
1578 			((ept->ftype == 'e') || (ept->ftype == 'v')) &&
1579 			(strcmp(ept->pkg_class, "none") == 0)) {
1580 
1581 			if (absolutepath(extlist[idx]->map_path) == B_TRUE &&
1582 				parametricpath(extlist[idx]->cf_ent.ainfo.local,
1583 					&relocpath) == B_FALSE) {
1584 				pspool_loc = ROOT;
1585 			} else {
1586 				pspool_loc = RELOC;
1587 			}
1588 
1589 			n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s",
1590 				saveSpoolInstallDir, pspool_loc,
1591 				relocpath ? relocpath : extlist[idx]->map_path);
1592 
1593 			if (n >= PATH_MAX) {
1594 				progerr(ERR_CREATE_PATH_2,
1595 					saveSpoolInstallDir,
1596 					extlist[idx]->map_path);
1597 				quit(99);
1598 			}
1599 
1600 			/* copy, preserve source file mode */
1601 
1602 			if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) {
1603 				warnflag++;
1604 			}
1605 		}
1606 
1607 		/*
1608 		 * Now insert this potentially changed package database
1609 		 * entry.
1610 		 */
1611 		if (entry.cf_ent.npkgs) {
1612 			if (putcvfpfile(&(entry.cf_ent), *a_cfTmpVfp)) {
1613 				quit(99);
1614 			}
1615 		}
1616 	}
1617 
1618 	n = swapcfile(pkgserver, a_cfTmpVfp, pkginst, dbchg);
1619 	if (n == RESULT_WRN) {
1620 		warnflag++;
1621 	} else if (n == RESULT_ERR) {
1622 		quit(99);
1623 	}
1624 }
1625 
1626 /*
1627  * This function goes through and fixes all the attributes. This is called
1628  * out by using DST_QKVERIFY=this_class in the pkginfo file. The primary
1629  * use for this is to fix up files installed by a class action script
1630  * which is time-critical and reliable enough to assume likely success.
1631  * The first such format was for WOS compressed-cpio'd file sets.
1632  * The second format is the Class Archive Format.
1633  */
1634 static int
1635 fix_attributes(struct cfextra **extlist, int idx)
1636 {
1637 	struct	cfextra *ext;
1638 	int	i, retval = 1;
1639 	int 	nc = cl_getn();
1640 	int	n;
1641 	struct cfent *ept;
1642 	struct mergstat *mstat;
1643 	char scrpt_dst[PATH_MAX];
1644 	char *pspool_loc;
1645 	char *relocpath = (char *)NULL;
1646 
1647 	for (i = 0; extlist[i]; i++) {
1648 		ext = extlist[i];
1649 		ept = &(extlist[i]->cf_ent);
1650 		mstat = &(extlist[i]->mstat);
1651 
1652 		/*
1653 		 * We don't care about 'i'nfo files because, they
1654 		 * aren't laid down, 'e'ditable files can change
1655 		 * anyway, so who cares and 's'ymlinks were already
1656 		 * fixed in domerg(); however, certain old WOS
1657 		 * package symlinks depend on a bug in the old
1658 		 * pkgadd which has recently been expunged. For
1659 		 * those packages in 2.2, we repeat the verification
1660 		 * of symlinks.
1661 		 *
1662 		 * By 2.6 or so, ftype == 's' should be added to this.
1663 		 */
1664 		if (ept->ftype == 'i' || ept->ftype == 'e' ||
1665 			(mstat->shared && nocnflct))
1666 			continue;
1667 
1668 		if (mstat->denied) {
1669 			progerr(ERR_COULD_NOT_INSTALL, ept->path);
1670 			warnflag++;
1671 			continue;
1672 		}
1673 
1674 		if (ept->pkg_class_idx < 0 || ept->pkg_class_idx > nc) {
1675 			progerr(ERR_CLIDX, ept->pkg_class_idx,
1676 			    (ept->path && *ept->path) ? ept->path : "unknown");
1677 			continue;
1678 		}
1679 
1680 		/* If this is the right class, do the fast verify. */
1681 		if (ept->pkg_class_idx == idx) {
1682 			if (fverify(1, &ept->ftype, ept->path,
1683 				&ept->ainfo, &ept->cinfo) == 0) {
1684 				mstat->attrchg = 0;
1685 				mstat->contchg =  0;
1686 			} else	/* We'll try full verify later */
1687 				retval = 0;
1688 		}
1689 		/*
1690 		 * Need to copy the installed volitale file back to the
1691 		 * partial spooled area if we are installing to a local zone
1692 		 * or similar installation method.
1693 		 */
1694 
1695 		if ((!is_partial_inst()) &&
1696 			((ept->ftype == 'e') || (ept->ftype == 'v')) &&
1697 			(strcmp(ept->pkg_class, "none") == 0)) {
1698 
1699 			if (absolutepath(ext->map_path) == B_TRUE &&
1700 				parametricpath(ext->cf_ent.ainfo.local,
1701 					&relocpath) == B_FALSE) {
1702 				pspool_loc = ROOT;
1703 			} else {
1704 				pspool_loc = RELOC;
1705 			}
1706 
1707 			n = snprintf(scrpt_dst, PATH_MAX, "%s/%s/%s",
1708 				saveSpoolInstallDir, pspool_loc,
1709 				relocpath ? relocpath : ext->map_path);
1710 
1711 			if (n >= PATH_MAX) {
1712 				progerr(ERR_CREATE_PATH_2,
1713 					saveSpoolInstallDir,
1714 					ext->map_path);
1715 				quit(99);
1716 			}
1717 
1718 			/* copy, preserve source file mode */
1719 
1720 			if (cppath(MODE_SRC, ept->path, scrpt_dst, 0644)) {
1721 				warnflag++;
1722 			}
1723 		}
1724 	}
1725 
1726 	return (retval);
1727 }
1728 
1729 /*
1730  * Check to see if first charcter in path is a '/'.
1731  *
1732  * Return:
1733  * 			B_TRUE - if path is prepended with '/'
1734  * 			B_FALSE - if not
1735  */
1736 static boolean_t
1737 absolutepath(char *path)
1738 {
1739 	assert(path != NULL);
1740 	assert(path[0] != '\0');
1741 
1742 	return (path[0] == '/' ? B_TRUE : B_FALSE);
1743 }
1744 
1745 /*
1746  * Check to see if path contains a '$' which makes it
1747  * a parametric path and therefore relocatable.
1748  *
1749  * Parameters:
1750  *             path - The path to determine if it is absolute
1751  *             relocpath - The value of the unconditioned path
1752  *                         i.e. $OPTDIR/usr/ls
1753  * Return:
1754  * 			B_TRUE - if path is a parametric path
1755  * 			B_FALSE - if not
1756  */
1757 static boolean_t
1758 parametricpath(char *path, char **relocpath)
1759 {
1760 	assert(path != NULL);
1761 	assert(path[0] != '\0');
1762 
1763 	/*
1764 	 * If this is a valid parametric path then a '$' MUST occur at the
1765 	 * first or second character.
1766 	 */
1767 
1768 	if (path[0] == '$' || path[1] == '$') {
1769 		/*
1770 		 * If a parametric path exists then when copying the
1771 		 * path to the pspool directoy from the installing
1772 		 * pkgs reloc directory we want to use the uncononditional
1773 		 * varaiable path.
1774 		 */
1775 		*relocpath = (path + 1);
1776 		return (B_TRUE);
1777 	}
1778 	return (B_FALSE);
1779 }
1780 
1781 void
1782 regfiles_free()
1783 {
1784 	if (regfiles_head != NULL) {
1785 		struct reg_files *rfp = regfiles_head->next;
1786 
1787 		while (rfp != NULL) {
1788 			free(regfiles_head);
1789 			regfiles_head = rfp;
1790 			rfp = regfiles_head->next;
1791 		}
1792 		free(regfiles_head);
1793 		regfiles_head = NULL;
1794 	}
1795 }
1796