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