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