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