xref: /titanic_52/usr/src/cmd/svr4pkg/libinst/pkgdbmerg.c (revision aad74983c015b9377370a62fd6867b6074434d3e)
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 <signal.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <assert.h>
38 #include <pkgstrct.h>
39 #include <sys/stat.h>
40 #include <locale.h>
41 #include <libintl.h>
42 #include <pkginfo.h>
43 #include <instzones_api.h>
44 #include <pkglib.h>
45 #include <libinst.h>
46 #include <messages.h>
47 
48 /* merg() return codes */
49 #define	MRG_SAME	0
50 #define	MRG_DIFFERENT	1
51 #define	MRG_REPLACE	2
52 
53 /* typechg() return codes */
54 #define	TYPE_OK		0
55 #define	TYPE_WARNING	1
56 #define	TYPE_IGNORED	2
57 #define	TYPE_REPLACE	3
58 #define	TYPE_FATAL	4
59 
60 /* message pool */
61 #define	ERR_OUTPUT	"unable to update package database"
62 #define	ERR_PINFO	"missing pinfo structure for <%s>"
63 #define	INFO_PROCESS	"   %2ld%% of information processed; continuing ..."
64 
65 #define	WRN_NOTFILE	"WARNING: %s <no longer a regular file>"
66 #define	WRN_NOTSYMLN	"WARNING: %s <no longer a symbolic link>"
67 #define	WRN_NOTLINK	"WARNING: %s <no longer a linked file>"
68 #define	WRN_NOTDIR	"WARNING: %s <no longer a directory>"
69 #define	WRN_NOTCHAR	"WARNING: %s <no longer a character special device>"
70 #define	WRN_NOTBLOCK	"WARNING: %s <no longer a block special device>"
71 #define	WRN_NOTPIPE	"WARNING: %s <no longer a named pipe>"
72 #define	WRN_TOEXCL	"WARNING: cannot convert %s to an exclusive directory."
73 #define	WRN_ODDVERIFY	"WARNING: quick verify disabled for class %s."
74 
75 #define	MSG_TYPIGN	"Object type change ignored."
76 #define	MSG_TYPE_ERR	"Package attempts fatal object type change."
77 
78 extern char	*pkginst;
79 extern int	nosetuid, nocnflct, otherstoo;
80 
81 /* pkgobjmap.c */
82 extern int	cp_cfent(struct cfent *cf_ent, struct cfextra *el_ent);
83 
84 /* setlist.c */
85 extern void	cl_def_dverify(int idx);
86 
87 char dbst = '\0';	/* usually set by installf() or removef() */
88 
89 int files_installed(void);	/* return number of files installed. */
90 
91 static int	errflg = 0;
92 static int	eptnum;
93 static VFP_T	*fpvfp = {(VFP_T *)NULL};
94 static long	sizetot;
95 static int	seconds;
96 static int	installed;	/* # of files, already properly installed. */
97 static struct	pinfo	*pkgpinfo = (struct pinfo *)0;
98 
99 static int	is_setuid(struct cfent *ent);
100 static int	is_setgid(struct cfent *ent);
101 static int	merg(struct cfextra *el_ent, struct cfent *cf_ent);
102 static int	do_like_ent(VFP_T *vfpo, struct cfextra *el_ent,
103 		    struct cfent *cf_ent, int ctrl);
104 static int	do_new_ent(VFP_T *vfpo, struct cfextra *el_ent, int ctrl);
105 static int	typechg(struct cfent *el_ent, struct cfent *cf_ent,
106 		    struct mergstat *mstat);
107 
108 static void	set_change(struct cfextra *el_ent);
109 static void	chgclass(struct cfent *cf_ent, struct pinfo *pinfo);
110 static void	output(VFP_T *vfpo, struct cfent *ent, struct pinfo *pinfo);
111 
112 /* ARGSUNUSED */
113 void
114 notice(int n)
115 {
116 #ifdef lint
117 	int i = n;
118 	n = i;
119 #endif	/* lint */
120 	(void) signal(SIGALRM, SIG_IGN);
121 	if (sizetot != 0) {
122 		echo(gettext(INFO_PROCESS),
123 			vfpGetBytesRemaining(fpvfp) * 100L / sizetot);
124 	}
125 	(void) signal(SIGALRM, notice);
126 	(void) alarm(seconds);
127 }
128 
129 /* ARGSUSED */
130 
131 /*
132  * This scans the extlist (pkgmap) and the package database to the end,
133  * copying out the merged contents to the file at tmpfp. It updates the mergstat
134  * structures and deals with administrative defaults regarding setuid and
135  * conflict.
136  *
137  * Since both the extlist and the package database entries are in numerical
138  * order, they both scan unidirectionally. If the entry in the extlist is
139  * found in the package database (by pathname) then do_like_ent() is called.
140  * If the extlist entry is not found in the package database then
141  * do_new_ent() is called. srchcfile() is responsible for copying out
142  * non-matching package database entries. At package database EOF, the
143  * eocontents flag is set and the rest of the extlist are assumed to be new
144  * entries. At the end of the extlist, the eoextlist flag is set and the
145  * remaining package database ends up copied out by srchcfile().
146  */
147 
148 int
149 pkgdbmerg(VFP_T *mapvfp, VFP_T *tmpvfp, struct cfextra **extlist, int notify)
150 {
151 	static	struct	cfent	cf_ent;	/* scratch area */
152 	struct	cfextra	*el_ent;	/* extlist entry under review */
153 	int	eocontents = 0;
154 	int	eoextlist = 0;
155 	int	n;
156 	int	changed;
157 	int	assume_ok = 0;
158 
159 	cf_ent.pinfo = (NULL);
160 	errflg = 0;
161 	eptnum = 0;
162 	installed = changed = 0;
163 
164 	fpvfp = mapvfp;	/* for notice function ...arg! */
165 
166 	if (notify) {
167 		seconds = notify;
168 		(void) signal(SIGALRM, notice);
169 		(void) alarm(seconds);
170 	}
171 
172 	(void) sighold(SIGALRM);
173 
174 	sizetot = (((ptrdiff_t)(mapvfp->_vfpEnd)) -
175 				((ptrdiff_t)(mapvfp->_vfpStart)));
176 	vfpRewind(mapvfp);
177 	vfpRewind(tmpvfp);
178 
179 	(void) sigrelse(SIGALRM);
180 
181 	do {
182 		(void) sighold(SIGALRM);
183 
184 		/*
185 		 * If there's an entry in the extlist at this position,
186 		 * process that entry.
187 		 */
188 		if (!eoextlist && (el_ent = extlist[eptnum])) {
189 
190 			/* Metafiles don't get merged. */
191 			if ((el_ent->cf_ent.ftype == 'i') ||
192 				(el_ent->cf_ent.ftype == 'n')) {
193 				continue;
194 			}
195 
196 			/*
197 			 * Copy cfextra structure for duplicated paths.
198 			 * This is not just an optimization, it is
199 			 * necessary for correct operation of algorithm.
200 			 */
201 			if ((eptnum > 0) && (strncmp(el_ent->cf_ent.path,
202 			    extlist[eptnum-1]->cf_ent.path, PATH_MAX) == 0)) {
203 				memcpy(extlist[eptnum], extlist[eptnum-1],
204 				    sizeof (struct cfextra));
205 				continue;
206 			}
207 
208 			/*
209 			 * Normally dbst comes to us from installf() or
210 			 * removef() in order to specify their special
211 			 * database status codes. They cannot implement a
212 			 * quick verify (it just doesn't make sense). For
213 			 * that reason, we can test to see if we already have
214 			 * a special database status. If we don't (it's from
215 			 * pkgadd) then we can test to see if this is calling
216 			 * for a quick verify wherein we assume the install
217 			 * will work and fix it if it doesn't. In that case
218 			 * we set our own dbst to be ENTRY_OK.
219 			 */
220 			if (dbst == '\0') {
221 				if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) ==
222 				    QKVERIFY) {
223 					assume_ok = 1;
224 				}
225 			} else {
226 				/*
227 				 * If we DO end up with an installf/quick
228 				 * verify combination, we fix that by simply
229 				 * denying the quick verify for this class.
230 				 * This forces everything to come out alright
231 				 * by forcing the standard assumptions as
232 				 * regards package database for the rest of
233 				 * the load.
234 				 */
235 				if (cl_dvfy(el_ent->cf_ent.pkg_class_idx) ==
236 				    QKVERIFY) {
237 					logerr(gettext(WRN_ODDVERIFY),
238 					    cl_nam(
239 					    el_ent->cf_ent.pkg_class_idx));
240 					/*
241 					 * Set destination verification to
242 					 * default.
243 					 */
244 					cl_def_dverify(
245 					    el_ent->cf_ent.pkg_class_idx);
246 				}
247 			}
248 
249 			/*
250 			 * Comply with administrative requirements regarding
251 			 * setuid/setgid processes.
252 			 */
253 			if (is_setuid(&(el_ent->cf_ent))) {
254 				el_ent->mstat.setuid = 1;
255 			}
256 			if (is_setgid(&(el_ent->cf_ent))) {
257 				el_ent->mstat.setgid = 1;
258 			}
259 
260 			/*
261 			 * If setuid/setgid processes are not allowed, reset
262 			 * those bits.
263 			 */
264 			if (nosetuid && (el_ent->mstat.setgid ||
265 			    el_ent->mstat.setuid)) {
266 				el_ent->cf_ent.ainfo.mode &=
267 				    ~(S_ISUID | S_ISGID);
268 			}
269 		} else {
270 			eoextlist = 1;	/* end of extlist[] */
271 		}
272 
273 		/*
274 		 * If we're not at the end of the package database, get the
275 		 * next entry for comparison.
276 		 */
277 		if (!eocontents) {
278 
279 			/* Search package database for this entry. */
280 			n = srchcfile(&cf_ent, el_ent ?
281 				el_ent->cf_ent.path : NULL,
282 				mapvfp, tmpvfp);
283 
284 			/*
285 			 * If there was an error, note it and return an error
286 			 * flag.
287 			 */
288 			if (n < 0) {
289 				char	*errstr = getErrstr();
290 				logerr(gettext(
291 				    "bad entry read from contents file"));
292 				logerr(gettext("- pathname: %s"),
293 				    (cf_ent.path && *cf_ent.path) ?
294 				    cf_ent.path : "Unknown");
295 				logerr(gettext("- problem: %s"),
296 				    (errstr && *errstr) ? errstr : "Unknown");
297 				return (-1);
298 			/*
299 			 * If there was a match, then merge them into a
300 			 * single entry.
301 			 */
302 			} else if (n == 1) {
303 				/*
304 				 * If this package is overwriting a setuid or
305 				 * setgid process, set the status bits so we
306 				 * can inform the administrator.
307 				 */
308 				if (is_setuid(&cf_ent)) {
309 					el_ent->mstat.osetuid = 1;
310 				}
311 
312 				if (is_setgid(&cf_ent)) {
313 					el_ent->mstat.osetgid = 1;
314 				}
315 				/*
316 				 * Detect if a symlink has changed to directory
317 				 * If so mark all the files/dir supposed to be
318 				 * iniside this dir, so that they are not miss
319 				 * understood by do_new_ent later as already
320 				 * installed.
321 				 */
322 				if ((!eoextlist) && (cf_ent.ftype == 's') &&
323 				    (el_ent->cf_ent.ftype == 'd')) {
324 					int i;
325 					int plen = strlen(el_ent->cf_ent.path);
326 					for (i = eptnum + 1; extlist[i]; i++) {
327 						if (strncmp(el_ent->cf_ent.path,
328 						    extlist[i]->cf_ent.path,
329 						    plen) != 0)
330 							break;
331 						extlist[i]->mstat.parentsyml2dir
332 						    = 1;
333 					}
334 				}
335 
336 				if (do_like_ent(tmpvfp, el_ent, &cf_ent,
337 				    assume_ok)) {
338 					changed++;
339 				}
340 
341 			/*
342 			 * If the alphabetical position in the package
343 			 * database is unfilled, then this will be a new
344 			 * entry. If n == 0, then we're also at the end of
345 			 * the contents file.
346 			 */
347 			} else {
348 				if (n == 0) {
349 					eocontents++;
350 				}
351 
352 				/*
353 				 * If there is an extlist entry in the
354 				 * hopper, insert it at the end of the
355 				 * package database.
356 				 */
357 				if (!eoextlist) {
358 					if (do_new_ent(tmpvfp, el_ent,
359 					    assume_ok)) {
360 						changed++;
361 					}
362 				}
363 			}
364 		/*
365 		 * We have passed the last entry in the package database,
366 		 * tagging these extlist entries onto the end.
367 		 */
368 		} else if (!eoextlist) {
369 			if (do_new_ent(tmpvfp, el_ent, assume_ok)) {
370 				changed++;
371 			}
372 		}
373 		/* Else, we'll drop out of the loop. */
374 
375 		(void) sigrelse(SIGALRM);
376 	} while (eptnum++, (!eocontents || !eoextlist));
377 
378 	if (notify) {
379 		(void) alarm(0);
380 		(void) signal(SIGALRM, SIG_IGN);
381 	}
382 
383 	return (errflg ? -1 : changed);
384 }
385 
386 /*
387  * Merge a new entry with an installed package object of the same name and
388  * insert that object into the package database. Obey administrative defaults
389  * as regards conflicting files.
390  */
391 
392 static int
393 do_like_ent(VFP_T *vfpo, struct cfextra *el_ent, struct cfent *cf_ent, int ctrl)
394 {
395 	int	stflag, ignore, changed, mrg_result;
396 
397 	ignore = changed = 0;
398 
399 	/*
400 	 * Construct the record defining the current package. If there are
401 	 * other packages involved, this will be appended to the existing
402 	 * list. If this is an update of the same package, it will get merged
403 	 * with the existing record. If this is a preloaded record (like from
404 	 * a dryrun file), it will keep it's current pinfo pointer and will
405 	 * pass it on to the record from the contents file - because on the
406 	 * final continuation, the contents file will be wrong.
407 	 */
408 	if (el_ent->mstat.preloaded) {
409 		struct pinfo *pkginfo;
410 
411 		/* Contents file is not to be trusted for this list. */
412 		pkginfo = cf_ent->pinfo;
413 
414 		/* Free the potentially bogus list. */
415 		while (pkginfo) {
416 			struct pinfo *next;
417 			next = pkginfo->next;
418 			free(pkginfo);
419 			pkginfo = next;
420 		}
421 
422 		cf_ent->pinfo = el_ent->cf_ent.pinfo;
423 	}
424 
425 	pkgpinfo = eptstat(cf_ent, pkginst, DUP_ENTRY);
426 
427 	stflag = pkgpinfo->status;
428 
429 	if (otherstoo)
430 		el_ent->mstat.shared = 1;
431 
432 	/* If it's marked for erasure, make it official */
433 	if (el_ent->cf_ent.ftype == RM_RDY) {
434 		if (!errflg) {
435 			pkgpinfo = eptstat(cf_ent, pkginst, RM_RDY);
436 
437 			/*
438 			 * Get copy of status character in case the object is
439 			 * "shared" by a server, in which case we need to
440 			 * maintain the shared status after the entry is
441 			 * written to the package database with RM_RDY
442 			 * status. This is needed to support the `removef'
443 			 * command.
444 			 */
445 			stflag = pkgpinfo->status;
446 			pkgpinfo->status = RM_RDY;
447 
448 			if (putcvfpfile(cf_ent, vfpo)) {
449 				progerr(gettext(ERR_OUTPUT));
450 				quit(99);
451 			}
452 
453 			/*
454 			 * If object is provided by a server, allocate an
455 			 * info block and set the status to indicate this.
456 			 * This is needed to support the `removef' command.
457 			 */
458 			if (stflag == SERVED_FILE) {
459 				el_ent->cf_ent.pinfo =
460 				    (struct pinfo *)calloc(1,
461 				    sizeof (struct pinfo));
462 				el_ent->cf_ent.pinfo->next = NULL;
463 				el_ent->cf_ent.pinfo->status = SERVED_FILE;
464 			}
465 		}
466 		return (1);
467 	}
468 
469 	/*
470 	 * If there is no package associated with it, there's something
471 	 * very wrong.
472 	 */
473 	if (!pkgpinfo) {
474 		progerr(gettext(ERR_PINFO), cf_ent->path);
475 		quit(99);
476 	}
477 
478 	/*
479 	 * Do not allow installation if nocnflct is set and other packages
480 	 * reference this pathname. The cp_cfent() function below writes the
481 	 * information from the installed file over the new entry, so the
482 	 * package database will be unchanged.
483 	 *
484 	 * By the way, ftype "e" is often shared and that's OK, so ftype
485 	 * "e" doesn't count here.
486 	 */
487 	if ((nocnflct && el_ent->mstat.shared && el_ent->cf_ent.ftype != 'e')) {
488 		/*
489 		 * First set the attrchg and contchg entries for proper
490 		 * messaging in the install phase.
491 		 */
492 		set_change(el_ent);
493 
494 		/*
495 		 * Now overwrite the new entry with the entry for the
496 		 * currently installed object.
497 		 */
498 		if (cp_cfent(cf_ent, el_ent) == 0)
499 			quit(99);
500 
501 		ignore++;
502 	} else {
503 		mrg_result = merg(el_ent, cf_ent);
504 
505 		switch (mrg_result) {
506 		    case MRG_SAME:
507 			break;
508 
509 		    case MRG_DIFFERENT:
510 			changed++;
511 			break;
512 
513 		    case MRG_REPLACE:
514 			/*
515 			 * We'll pick one or the other later. For now, cf_ent
516 			 * will have the fault value and el_ent will retain
517 			 * the other value. This is the only state that allows
518 			 * the database and the pkgmap to differ.
519 			 */
520 
521 			el_ent->mstat.contchg = 1;	/* subject to change */
522 			ignore++;
523 			break;
524 
525 		    default:
526 			break;
527 		}
528 	}
529 
530 	/* el_ent structure now contains updated entry */
531 	if (!el_ent->mstat.contchg && !ignore) {
532 		/*
533 		 * We know the DB entry matches the pkgmap, so now we need to
534 		 * see if the actual object matches the pkgmap.
535 		 */
536 		set_change(el_ent);
537 	}
538 
539 	if (!errflg) {
540 		if (ctrl == 1) {	/* quick verify assumes OK */
541 			/*
542 			 * The pkgpinfo entry is already correctly
543 			 * constructed. Look into dropping this soon.
544 			 */
545 			pkgpinfo = eptstat(&(el_ent->cf_ent), pkginst,
546 			    ENTRY_OK);
547 
548 			if (stflag != DUP_ENTRY) {
549 				changed++;
550 			}
551 
552 			/*
553 			 * We could trust the prior pkginfo entry, but things
554 			 * could have changed and  we need to update the
555 			 * fs_tab[] anyway. We check for a server object
556 			 * here.
557 			 */
558 			if (is_served(el_ent->server_path,
559 			    &(el_ent->fsys_value)))
560 				pkgpinfo->status = SERVED_FILE;
561 		} else {
562 			if (!ignore && el_ent->mstat.contchg) {
563 				pkgpinfo =
564 				    eptstat(&(el_ent->cf_ent), pkginst,
565 				    (dbst ? dbst : CONFIRM_CONT));
566 			} else if (!ignore && el_ent->mstat.attrchg) {
567 				pkgpinfo =
568 				    eptstat(&(el_ent->cf_ent), pkginst,
569 				    (dbst ? dbst : CONFIRM_ATTR));
570 			} else if (!ignore && el_ent->mstat.shared) {
571 				pkgpinfo =
572 				    eptstat(&(el_ent->cf_ent), pkginst,
573 				    dbst);
574 				changed++;
575 			} else if (stflag != DUP_ENTRY) {
576 				pkgpinfo = eptstat(&(el_ent->cf_ent),
577 				    pkginst, '\0');
578 				if (stflag != ENTRY_OK) {
579 					changed++;
580 				}
581 			}
582 		}
583 
584 		if (mrg_result == MRG_REPLACE) {
585 			/*
586 			 * Put the original package database entry back into
587 			 * the package database for now.
588 			 */
589 			output(vfpo, cf_ent, pkgpinfo);
590 		} else {
591 			/* Put the merged entry into the package database. */
592 			output(vfpo, &(el_ent->cf_ent), pkgpinfo);
593 		}
594 	}
595 
596 	if (pkgpinfo->aclass[0] != '\0') {
597 		(void) strcpy(el_ent->cf_ent.pkg_class, pkgpinfo->aclass);
598 	}
599 
600 	/*
601 	 * If a sym link entry exists in the contents file and
602 	 * and the destination of the link does not exist on the the system
603 	 * then the contents file needs to be updated appropriately so a
604 	 * subsequent invocation of "installf -f" will create the destination.
605 	 */
606 	if (el_ent->mstat.contchg && pkgpinfo->status == INST_RDY) {
607 		changed++;
608 	}
609 
610 	if (!(el_ent->mstat.preloaded))
611 		el_ent->cf_ent.pinfo = NULL;
612 
613 	/*
614 	 * If no change during the merg and we don't have a case where types
615 	 * were different in odd ways, count this as installed.
616 	 */
617 	if (!el_ent->mstat.attrchg && !el_ent->mstat.contchg &&
618 	    !el_ent->mstat.replace)
619 		installed++;
620 	return (changed);
621 }
622 
623 /* Insert an entirely new entry into the package database. */
624 static int
625 do_new_ent(VFP_T *vfpo, struct cfextra *el_ent, int ctrl)
626 {
627 	struct pinfo	*pinfo;
628 	char		*tp;
629 	int		changed = 0;
630 
631 	if (el_ent->cf_ent.ftype == RM_RDY) {
632 		return (0);
633 	}
634 
635 	tp = el_ent->server_path;
636 	/*
637 	 * Check the file/dir existence only if any of the parent directory
638 	 * of the file/dir has not changed from symbolic link to directory.
639 	 * At this time we are only doing a dry run, the symlink is not yet
640 	 * replaced, so if this is done directly then access will result in
641 	 * incorrect information in case a file with the same attr and cont
642 	 * exists in the link target.
643 	 */
644 	if ((!el_ent->mstat.parentsyml2dir) && (access(tp, F_OK) == 0)) {
645 		/*
646 		 * Path exists, and although its not referenced by any
647 		 * package we make it look like it is so it appears as a
648 		 * conflicting file in case the user doesn't want it
649 		 * installed. We set the rogue flag to distinguish this from
650 		 * package object conflicts if the administrator is queried
651 		 * about this later. Note that noconflict means NO conflict
652 		 * at the file level. Even rogue files count.
653 		 */
654 		el_ent->mstat.shared = 1;
655 		el_ent->mstat.rogue = 1;
656 		set_change(el_ent);
657 	} else {
658 		/* since path doesn't exist, we're changing everything */
659 		el_ent->mstat.rogue = 0;
660 		el_ent->mstat.contchg = 1;
661 		el_ent->mstat.attrchg = 1;
662 	}
663 
664 	if (el_ent->cf_ent.ainfo.mode == WILDCARD) {
665 		if (el_ent->cf_ent.ftype == 'd') {
666 			el_ent->cf_ent.ainfo.mode = DEFAULT_MODE;
667 		} else {
668 			el_ent->cf_ent.ainfo.mode = DEFAULT_MODE_FILE;
669 		}
670 		logerr(WRN_SET_DEF_MODE, el_ent->cf_ent.path,
671 		    (int)el_ent->cf_ent.ainfo.mode);
672 	}
673 
674 	if (strcmp(el_ent->cf_ent.ainfo.owner, DB_UNDEFINED_ENTRY) == 0)
675 		(void) strcpy(el_ent->cf_ent.ainfo.owner,
676 				DEFAULT_OWNER);
677 	if (strcmp(el_ent->cf_ent.ainfo.group, DB_UNDEFINED_ENTRY) == 0)
678 		(void) strcpy(el_ent->cf_ent.ainfo.group,
679 				DEFAULT_GROUP);
680 
681 	/*
682 	 * Do not allow installation if nocnflct is set and this pathname is
683 	 * already in place. Since this entry is new (not associated with a
684 	 * package), we don't issue anything to the database we're building.
685 	 */
686 	if (nocnflct && el_ent->mstat.shared) {
687 		return (0);
688 	}
689 
690 	if (!errflg) {
691 		if (el_ent->mstat.preloaded) {
692 			/* Add this package to the already established list. */
693 			pinfo = eptstat(&(el_ent->cf_ent), pkginst, DUP_ENTRY);
694 		} else {
695 			el_ent->cf_ent.npkgs = 1;
696 			pinfo = (struct pinfo *)calloc(1,
697 			    sizeof (struct pinfo));
698 			if (!pinfo) {
699 				progerr(gettext(ERR_MEMORY), errno);
700 				quit(99);
701 			}
702 			el_ent->cf_ent.pinfo = pinfo;
703 			(void) strcpy(pinfo->pkg, pkginst);
704 		}
705 
706 		if (ctrl == 1) {	/* quick verify assumes OK */
707 			pinfo->status = dbst ? dbst : ENTRY_OK;
708 			/*
709 			 * The entry won't be verified, but the entry in the
710 			 * database isn't necessarily ENTRY_OK. If this is
711 			 * coming from a server, we need to note that
712 			 * instead.
713 			 */
714 			if (is_served(el_ent->server_path,
715 			    &(el_ent->fsys_value)))
716 				pinfo->status = SERVED_FILE;
717 		} else {
718 			pinfo->status = dbst ? dbst : CONFIRM_CONT;
719 		}
720 
721 		output(vfpo, &(el_ent->cf_ent), pinfo);
722 		changed++;
723 
724 		free(pinfo);
725 		el_ent->cf_ent.pinfo = NULL;
726 		}
727 	if (!el_ent->mstat.attrchg && !el_ent->mstat.contchg) {
728 		installed++;
729 	}
730 
731 	return (changed);
732 }
733 
734 int
735 files_installed(void)
736 {
737 	return (installed);
738 }
739 
740 /*
741  * This function determines if there is a difference between the file on
742  * the disk and the file to be laid down. It set's mstat flags attrchg
743  * and contchg accordingly.
744  */
745 static void
746 set_change(struct cfextra *el_ent)
747 {
748 	int	n;
749 	char 	*tp;
750 
751 	tp = el_ent->server_path;
752 	if ((el_ent->cf_ent.ftype == 'f') || (el_ent->cf_ent.ftype == 'e') ||
753 		(el_ent->cf_ent.ftype == 'v')) {
754 		if (cverify(0, &(el_ent->cf_ent.ftype), tp,
755 		    &(el_ent->cf_ent.cinfo), 1)) {
756 			el_ent->mstat.contchg = 1;
757 		} else if (!el_ent->mstat.contchg && !el_ent->mstat.attrchg) {
758 			if (averify(0, &(el_ent->cf_ent.ftype), tp,
759 			    &(el_ent->cf_ent.ainfo)))
760 				el_ent->mstat.attrchg = 1;
761 		}
762 	} else if (!el_ent->mstat.attrchg &&
763 		((el_ent->cf_ent.ftype == 'd') ||
764 		(el_ent->cf_ent.ftype == 'x') ||
765 		(el_ent->cf_ent.ftype == 'c') ||
766 		(el_ent->cf_ent.ftype == 'b') ||
767 		(el_ent->cf_ent.ftype == 'p'))) {
768 		n = averify(0, &(el_ent->cf_ent.ftype), tp,
769 		    &(el_ent->cf_ent.ainfo));
770 		if (n == VE_ATTR)
771 			el_ent->mstat.attrchg = 1;
772 		else if (n && (n != VE_EXIST)) {
773 			el_ent->mstat.contchg = 1;
774 		}
775 	} else if (!el_ent->mstat.attrchg &&
776 		((el_ent->cf_ent.ftype == 's') ||
777 		(el_ent->cf_ent.ftype == 'l'))) {
778 		n = averify(0, &(el_ent->cf_ent.ftype), tp,
779 		    &(el_ent->cf_ent.ainfo));
780 		if (n == VE_ATTR)
781 			el_ent->mstat.attrchg = 1;
782 		else if (n && (n == VE_EXIST)) {
783 			el_ent->mstat.contchg = 1;
784 		}
785 	}
786 }
787 
788 static int
789 is_setuid(struct cfent *ent)
790 {
791 	return (((ent->ftype == 'f') || (ent->ftype == 'v') ||
792 		(ent->ftype == 'e')) &&
793 		(ent->ainfo.mode != BADMODE) &&
794 		(ent->ainfo.mode != WILDCARD) &&
795 		(ent->ainfo.mode & S_ISUID));
796 }
797 
798 static int
799 is_setgid(struct cfent *ent)
800 {
801 	return (((ent->ftype == 'f') || (ent->ftype == 'v') ||
802 		(ent->ftype == 'e')) && (ent->ainfo.mode != BADMODE) &&
803 		(ent->ainfo.mode != WILDCARD) &&
804 		(ent->ainfo.mode & S_ISGID) &&
805 		(ent->ainfo.mode & (S_IEXEC|S_IXUSR|S_IXOTH)));
806 }
807 
808 char *types[] = {
809 	"fev",	/* type 1, regular files */
810 	"s", 	/* type 2, symbolic links */
811 	"l", 	/* type 3, linked files */
812 	"dx", 	/* type 4, directories */
813 	"c", 	/* type 5, character special devices */
814 	"b", 	/* type 6, block special devices */
815 	"p", 	/* type 7, named pipes */
816 	NULL
817 };
818 
819 /*
820  * This determines if the ftype of the file on the disk and the file to be
821  * laid down are close enough. If they aren't, this either returns an error
822  * or displays a warning. This returns :
823  *	TYPE_OK		they're identical or close enough
824  *	TYPE_WARNING	they're pretty close (probably no problem)
825  *	TYPE_IGNORED	the type change was not allowed
826  *	TYPE_REPLACE	to be reviewed later - in endofclass() maybe
827  *	TYPE_FATAL	something awful happened
828  */
829 static int
830 typechg(struct cfent *el_ent, struct cfent *cf_ent, struct mergstat *mstat)
831 {
832 	int	i, etype, itype, retcode;
833 
834 	/* If they are identical, return OK */
835 	if (cf_ent->ftype == el_ent->ftype)
836 		return (TYPE_OK);
837 
838 	/*
839 	 * If package database entry is ambiguous, set it to the new entity's
840 	 * ftype
841 	 */
842 	if (cf_ent->ftype == BADFTYPE) {
843 		cf_ent->ftype = el_ent->ftype;
844 		return (TYPE_OK); /* do nothing; not really different */
845 	}
846 
847 	/* If the new entity is ambiguous, wait for the verify */
848 	if (el_ent->ftype == BADFTYPE)
849 		return (TYPE_OK);
850 
851 	/*
852 	 * If we're trying to convert an existing regular directory to an
853 	 * exclusive directory, this is very dangerous. We will continue, but
854 	 * we will deny the conversion.
855 	 */
856 	if (el_ent->ftype == 'x' && cf_ent->ftype == 'd') {
857 		logerr(gettext(WRN_TOEXCL), el_ent->path);
858 		return (TYPE_IGNORED);
859 	}
860 
861 	etype = itype = 0;
862 
863 	/* Set etype to that of the new entity */
864 	for (i = 0; types[i]; ++i) {
865 		if (strchr(types[i], el_ent->ftype)) {
866 			etype = i+1;
867 			break;
868 		}
869 	}
870 
871 	/* Set itype to that in the package database. */
872 	for (i = 0; types[i]; ++i) {
873 		if (strchr(types[i], cf_ent->ftype)) {
874 			itype = i+1;
875 			break;
876 		}
877 	}
878 
879 	if (itype == etype) {
880 		/* same basic object type */
881 		return (TYPE_OK);
882 	}
883 
884 	retcode = TYPE_WARNING;
885 
886 	/*
887 	 * If a simple object (like a file) is overwriting a directory, mark
888 	 * it for full inspection during installation.
889 	 */
890 	if (etype != 4 && itype == 4) {
891 		mstat->dir2nondir = 1;
892 		retcode = TYPE_REPLACE;
893 	}
894 
895 	/* allow change, but warn user of possible problems */
896 	switch (itype) {
897 	    case 1:
898 		logerr(gettext(WRN_NOTFILE), el_ent->path);
899 		break;
900 
901 	    case 2:
902 		logerr(gettext(WRN_NOTSYMLN), el_ent->path);
903 		break;
904 
905 	    case 3:
906 		logerr(gettext(WRN_NOTLINK), el_ent->path);
907 		break;
908 
909 	    case 4:
910 		logerr(gettext(WRN_NOTDIR), el_ent->path);
911 		break;
912 
913 	    case 5:
914 		logerr(gettext(WRN_NOTCHAR), el_ent->path);
915 		break;
916 
917 	    case 6:
918 		logerr(gettext(WRN_NOTBLOCK), el_ent->path);
919 		break;
920 
921 	    case 7:
922 		logerr(gettext(WRN_NOTPIPE), el_ent->path);
923 		break;
924 
925 	    default:
926 		break;
927 	}
928 	return (retcode);
929 }
930 
931 /*
932  * This function takes el_ent (the entry from the pkgmap) and cf_ent (the
933  * entry from the package database) and merge them into el_ent. The rules
934  * are still being figured out, but the comments should make the approach
935  * pretty clear.
936  *
937  * RETURN CODES:
938  *	MRG_DIFFERENT	The two entries are different and el_ent now contains
939  *			the intended new entry to be installed.
940  *	MRG_SAME	The two entries were identical and the old database
941  *			entry will be replaced unchanged.
942  *	MRG_REPLACE	One or the other entry will be used but the decision
943  *			has to be made at install time.
944  */
945 static int
946 merg(struct cfextra *el_ent, struct cfent *cf_ent)
947 {
948 	int	n, changed = 0;
949 
950 	/*
951 	 * We need to change the original entry to make it look like the new
952 	 * entry (the eptstat() routine has already added appropriate package
953 	 * information, but not about 'aclass' which may represent a change
954 	 * in class from the previous installation.
955 	 *
956 	 * NOTE: elent->cf_ent.pinfo (the list of associated packages) is NULL
957 	 * upon entry to this function.
958 	 */
959 
960 	el_ent->cf_ent.pinfo = cf_ent->pinfo;
961 
962 	if (dbst == INST_RDY && el_ent->cf_ent.ftype == '?') {
963 		el_ent->cf_ent.ftype = cf_ent->ftype;
964 	}
965 
966 	/*
967 	 * Evaluate the ftype change. Usually the ftype won't change. If it
968 	 * does it may be easy (s -> f), not allowed (d -> x), so complex we
969 	 * can't figure it 'til later (d -> s) or fatal (a hook for later).
970 	 */
971 	if (cf_ent->ftype != el_ent->cf_ent.ftype) {
972 		n = typechg(&(el_ent->cf_ent), cf_ent, &(el_ent->mstat));
973 
974 		switch (n) {
975 		    case TYPE_OK:
976 			break;
977 
978 		    /* This is an allowable change. */
979 		    case TYPE_WARNING:
980 			el_ent->mstat.contchg = 1;
981 			break;
982 
983 		    /* Not allowed, but leaving it as is is OK. */
984 		    case TYPE_IGNORED:
985 			logerr(gettext(MSG_TYPIGN));
986 			if (cp_cfent(cf_ent, el_ent) == 0)
987 				quit(99);
988 			return (MRG_SAME);
989 
990 		    /* Future analysis will reveal if this is OK. */
991 		    case TYPE_REPLACE:
992 			el_ent->mstat.replace = 1;
993 			return (MRG_REPLACE);
994 
995 		    /* Kill it before it does any damage. */
996 		    case TYPE_FATAL:
997 			logerr(gettext(MSG_TYPE_ERR));
998 			quit(99);
999 
1000 		    default:
1001 			break;
1002 		}
1003 
1004 		changed++;
1005 	}
1006 
1007 	/* Evaluate and merge the class. */
1008 	if (strcmp(cf_ent->pkg_class, el_ent->cf_ent.pkg_class)) {
1009 		/*
1010 		 * we always allow a class change as long as we have
1011 		 * consistent ftypes, which at this point we must
1012 		 */
1013 		changed++;
1014 		if (strcmp(cf_ent->pkg_class, "?")) {
1015 			(void) strcpy(pkgpinfo->aclass,
1016 			    el_ent->cf_ent.pkg_class);
1017 			(void) strcpy(el_ent->cf_ent.pkg_class,
1018 			    cf_ent->pkg_class);
1019 			chgclass(&(el_ent->cf_ent), pkgpinfo);
1020 		}
1021 	}
1022 
1023 	/*
1024 	 * Evaluate and merge based upon the ftype of the intended package
1025 	 * database entry.
1026 	 */
1027 	if (((el_ent->cf_ent.ftype == 's') || (el_ent->cf_ent.ftype == 'l'))) {
1028 
1029 		/* If both have link sources, then they need to be merged. */
1030 		if (cf_ent->ainfo.local && el_ent->cf_ent.ainfo.local) {
1031 			/*
1032 			 * If both sources are identical, the merge is
1033 			 * already done.
1034 			 */
1035 			if (strcmp(cf_ent->ainfo.local,
1036 			    el_ent->cf_ent.ainfo.local) != NULL) {
1037 				changed++;
1038 
1039 				/*
1040 				 * Otherwise, if the pkgmap entry is
1041 				 * ambiguous, it will inherit the database
1042 				 * entry.
1043 				 */
1044 				if (strcmp(el_ent->cf_ent.ainfo.local,
1045 				    "?") == NULL) {
1046 					(void) strlcpy(
1047 						el_ent->cf_ent.ainfo.local,
1048 						cf_ent->ainfo.local,
1049 						PATH_MAX);
1050 				} else {
1051 					el_ent->mstat.contchg = 1;
1052 				}
1053 			}
1054 		}
1055 		return (changed ? MRG_DIFFERENT : MRG_SAME);
1056 
1057 	} else if (el_ent->cf_ent.ftype == 'e') {
1058 
1059 		/*
1060 		 * The contents of edittable files are assumed to be changing
1061 		 * since some class action script will be doing the work and
1062 		 * we have no way of evaluating what it will actually do.
1063 		 */
1064 		el_ent->mstat.contchg = 1;
1065 		changed++;
1066 	} else if (((el_ent->cf_ent.ftype == 'f') ||
1067 					(el_ent->cf_ent.ftype == 'v'))) {
1068 		/*
1069 		 * For regular files, Look at content information; a BADCONT
1070 		 * in any el_ent field indicates the contents are unknown --
1071 		 * since cf_ent is guaranteed to have a valid entry here (bad
1072 		 * assumption?) this function will recognize this as a
1073 		 * change. The ambiguous el_ent values will be evaluated and
1074 		 * set later.
1075 		 */
1076 
1077 		/*
1078 		 * for type f/v files, if the file is in an area that is
1079 		 * inherited from the global zone, that area is read only
1080 		 * and the object cannot be changed - ignore any settings
1081 		 * in the current package database that may be present for
1082 		 * any existing object because they are irrelevant - since
1083 		 * the object is in a read-only area shared from the global
1084 		 * zone, accept that file's actual attributes as being correct.
1085 		 */
1086 
1087 		if (z_path_is_inherited(el_ent->cf_ent.path,
1088 			el_ent->cf_ent.ftype, get_inst_root()) == B_TRUE) {
1089 			echoDebug(DBG_PKGDBMRG_INHERITED, el_ent->cf_ent.path);
1090 		} else if (cf_ent->cinfo.size != el_ent->cf_ent.cinfo.size) {
1091 			changed++;
1092 			el_ent->mstat.contchg = 1;
1093 		} else if (cf_ent->cinfo.modtime !=
1094 		    el_ent->cf_ent.cinfo.modtime) {
1095 			changed++;
1096 			el_ent->mstat.contchg = 1;
1097 		} else if (cf_ent->cinfo.cksum != el_ent->cf_ent.cinfo.cksum) {
1098 			changed++;
1099 			el_ent->mstat.contchg = 1;
1100 		}
1101 	} else if (((el_ent->cf_ent.ftype == 'c') ||
1102 					(el_ent->cf_ent.ftype == 'b'))) {
1103 		/*
1104 		 * For devices, if major or minor numbers are identical the
1105 		 * merge is trivial. If the el_ent value is ambiguous (BAD),
1106 		 * the cf_ent value is inherited. Otherwise, the el_ent value
1107 		 * is preserved.
1108 		 */
1109 		if (cf_ent->ainfo.major != el_ent->cf_ent.ainfo.major) {
1110 			changed++;
1111 			if (el_ent->cf_ent.ainfo.major == BADMAJOR) {
1112 				el_ent->cf_ent.ainfo.major =
1113 				    cf_ent->ainfo.major;
1114 			} else {
1115 				el_ent->mstat.contchg = 1;
1116 			}
1117 		}
1118 		if (cf_ent->ainfo.minor != el_ent->cf_ent.ainfo.minor) {
1119 			changed++;
1120 			if (el_ent->cf_ent.ainfo.minor == BADMINOR)
1121 				el_ent->cf_ent.ainfo.minor =
1122 				    cf_ent->ainfo.minor;
1123 			else
1124 				el_ent->mstat.contchg = 1;
1125 		}
1126 	}
1127 
1128 	/*
1129 	 * For mode, owner and group follow the same rules as above - if
1130 	 * ambiguous, inherit, otherwise keep the new one.
1131 	 */
1132 	if (cf_ent->ainfo.mode != el_ent->cf_ent.ainfo.mode) {
1133 		changed++;  /* attribute info is changing */
1134 		if (el_ent->cf_ent.ainfo.mode == BADMODE) {
1135 			el_ent->cf_ent.ainfo.mode = cf_ent->ainfo.mode;
1136 		} else if (el_ent->cf_ent.ainfo.mode == WILDCARD) {
1137 			/*
1138 			 * If pkgmap has a '?' set for mode, use the mode from
1139 			 * the pkg DB (contents file).
1140 			 */
1141 			el_ent->cf_ent.ainfo.mode = cf_ent->ainfo.mode;
1142 			el_ent->mstat.attrchg = 0;
1143 		} else {
1144 			el_ent->mstat.attrchg = 1;
1145 		}
1146 	}
1147 	if (strcmp(cf_ent->ainfo.owner, el_ent->cf_ent.ainfo.owner) != 0) {
1148 		changed++;  /* attribute info is changing */
1149 		if (strcmp(el_ent->cf_ent.ainfo.owner, BADOWNER) == 0)
1150 			(void) strcpy(el_ent->cf_ent.ainfo.owner,
1151 			    cf_ent->ainfo.owner);
1152 		else
1153 			el_ent->mstat.attrchg = 1;
1154 	}
1155 	if (strcmp(cf_ent->ainfo.group, el_ent->cf_ent.ainfo.group) != 0) {
1156 		changed++;  /* attribute info is changing */
1157 		if (strcmp(el_ent->cf_ent.ainfo.group, BADGROUP) == 0)
1158 			(void) strcpy(el_ent->cf_ent.ainfo.group,
1159 			    cf_ent->ainfo.group);
1160 		else
1161 			el_ent->mstat.attrchg = 1;
1162 	}
1163 	return (changed ? MRG_DIFFERENT : MRG_SAME);
1164 }
1165 
1166 /*
1167  * This puts the current entry into the package database in the appropriate
1168  * intermediate format for this stage of the installation. This also assures
1169  * the correct format for the various package object ftypes, stripping the
1170  * link name before storing a regular file and stuff like that.
1171  */
1172 
1173 static void
1174 output(VFP_T *vfpo, struct cfent *ent, struct pinfo *pinfo)
1175 {
1176 	short	svvolno;
1177 	char	*svpt;
1178 
1179 	/* output without volume information */
1180 	svvolno = ent->volno;
1181 	ent->volno = 0;
1182 
1183 	pinfo->editflag = 0;
1184 	if (((ent->ftype == 's') || (ent->ftype == 'l'))) {
1185 		if (putcvfpfile(ent, vfpo)) {
1186 			progerr(gettext(ERR_OUTPUT));
1187 			quit(99);
1188 		}
1189 	} else {
1190 
1191 		/* output without local pathname */
1192 		svpt = ent->ainfo.local;
1193 		ent->ainfo.local = NULL;
1194 		if (putcvfpfile(ent, vfpo)) {
1195 			progerr(gettext(ERR_OUTPUT));
1196 			quit(99);
1197 		}
1198 
1199 		ent->ainfo.local = svpt;
1200 		/*
1201 		 * If this entry represents a file which is being edited, we
1202 		 * need to store in memory the fact that it is an edittable
1203 		 * file so that when we audit it after installation we do not
1204 		 * worry about its contents; we do this by resetting the ftype
1205 		 * to 'e' in the memory array which is later used to control
1206 		 * the audit
1207 		 */
1208 		if (pinfo->editflag)
1209 			ent->ftype = 'e';
1210 	}
1211 	/* restore volume information */
1212 	ent->volno = svvolno;
1213 }
1214 
1215 static void
1216 chgclass(struct cfent *cf_ent, struct pinfo *pinfo)
1217 {
1218 	struct pinfo *pp;
1219 	char	*oldclass, newclass[CLSSIZ+1];
1220 	int	newcnt, oldcnt;
1221 
1222 	/*
1223 	 * we use this routine to minimize the use of the aclass element by
1224 	 * optimizing the use of the cf_ent->pkg_class element
1225 	 */
1226 
1227 	(void) strlcpy(newclass, pinfo->aclass, sizeof (newclass));
1228 	newcnt = 1;
1229 
1230 	oldclass = cf_ent->pkg_class;
1231 	oldcnt = 0;
1232 
1233 	/*
1234 	 * count the number of times the newclass will be used and see if it
1235 	 * exceeds the number of times the oldclass is referenced
1236 	 */
1237 	pp = cf_ent->pinfo;
1238 	while (pp) {
1239 		if (pp->aclass[0] != '\0') {
1240 			if (strcmp(pp->aclass, newclass) == 0)
1241 				newcnt++;
1242 			else if (strcmp(pp->aclass, oldclass) == 0)
1243 				oldcnt++;
1244 		}
1245 		pp = pp->next;
1246 	}
1247 	if (newcnt > oldcnt) {
1248 		pp = cf_ent->pinfo;
1249 		while (pp) {
1250 			if (pp->aclass[0] == '\0') {
1251 				(void) strcpy(pp->aclass, oldclass);
1252 			} else if (strcmp(pp->aclass, newclass) == 0) {
1253 				pp->aclass[0] = '\0';
1254 			}
1255 			pp = pp->next;
1256 		}
1257 		(void) strcpy(cf_ent->pkg_class, newclass);
1258 	}
1259 }
1260