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
pkgdbmerg(PKGserver server,VFP_T * tmpvfp,struct cfextra ** extlist)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
do_like_ent(VFP_T * vfpo,struct cfextra * el_ent,struct cfent * cf_ent,int ctrl)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
do_new_ent(VFP_T * vfpo,struct cfextra * el_ent,int ctrl)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
files_installed(void)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
set_change(struct cfextra * el_ent)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
is_setuid(struct cfent * ent)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
is_setgid(struct cfent * ent)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
typechg(struct cfent * el_ent,struct cfent * cf_ent,struct mergstat * mstat)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
merg(struct cfextra * el_ent,struct cfent * cf_ent)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
output(VFP_T * vfpo,struct cfent * ent,struct pinfo * pinfo)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
chgclass(struct cfent * cf_ent,struct pinfo * pinfo)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