xref: /illumos-gate/usr/src/cmd/svr4pkg/libinst/fixpath.c (revision 726fad2a65f16c200a03969c29cb5c86c2d427db)
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 
28 /*
29  * This module contains all the code necessary to establish the key base
30  * directories to which the actual components of the package will be
31  * installed or removed. -- JST
32  */
33 
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <unistd.h>
38 #include <sys/stat.h>	/* mkdir() declaration */
39 #include <libintl.h>
40 #include <pkglib.h>
41 #include <install.h>
42 #include <libadm.h>
43 #include <libinst.h>
44 
45 static char *install_root = NULL;
46 static int install_root_exists = 0;	/* An install root was specified */
47 static int install_root_len;		/* strlen(install_root) */
48 static char *orig_basedir = NULL;	/* The unadjusted basedir */
49 static char *basedir = NULL;		/* basedir (cmb w/ inst rt if req) */
50 static int basedir_exists = 0;		/* There are relocatable paths */
51 static char *client_basedir = NULL;
52 static int client_basedir_exists = 0;	/* Installing from a host */
53 static char *env_cl_bdir = NULL;	/* CLIENT_BASEDIR from environment */
54 static int ir_accessed = 0;		/* install_root has been used */
55 static int relocatable;			/* set_basedir() assumed this */
56 static int partial_inst = 0; /* Installing pkg from partial spool directory */
57 static boolean_t depend_pkginfo_DB = B_FALSE; /* Only update depend/pkginfoDB */
58 static int partial_spool_create = 0; /* Create partial spool dir */
59 
60 static int	ask_basedir(char *path, int nointeract);
61 static char	*expand_path(char *path);
62 static int	set_client_basedir(void);
63 static char 	*fixpath_dup(char *path);
64 static int	orig_offset_rel;
65 
66 /*
67  * base_sepr and rel_fmt support construction of absolute paths from
68  * relative paths.
69  */
70 static int	base_sepr = 1;	/* separator length btwn basedir & path */
71 static char	*rel_fmt[] = { "%s%s", "%s/%s" };
72 
73 static int	eval_valid = 0;	/* everything set up to do an eval_path() */
74 
75 /* libpkg/gpkgmap.c */
76 extern int	getmapmode();
77 
78 #define	MSG_IR_REPL	"Replacing current install root with %s."
79 #define	ERR_IRSET	"Install_root has already been set to <%s> and used."
80 #define	ERR_IRNOTABS	"Install_root (-R option) requires an absolute " \
81 			"pathname: <%s>"
82 #define	ERR_ALLOCFAILED	"insufficient memory in %s"
83 #define	ERR_ADMIN_INVAL	"Invalid basedir entry in admin file."
84 #define	ERR_PATHNAME 	"Path name is invalid"
85 #define	ERR_RELINABS	"Relative path <%s> found in absolute package."
86 #define	ERR_CL_MIS	"Constructed CLIENT_BASEDIR <%s> and " \
87 			"environment CLIENT_BASEDIR <%s> do not match."
88 #define	ERR_ASKBD	"%s is already installed at %s. Cannot create a " \
89 			    "duplicate installation at %s."
90 #define	ERR_NO_CL_BD	"Cannot resolve CLIENT_BASEDIR conflicts."
91 #define	ERR_AMBDIRS	"Cannot evaluate path due to ambiguous " \
92 			"base directories."
93 #define	ERR_NODELETE	"unable to delete <%s>."
94 #define	ERR_MKBASE	"unable to make directory <%s>."
95 #define	MSG_REQBASEDIR	"Installation of this package requires a base " \
96 			"directory."
97 
98 #define	MSG_MUSTEXIST	"\\nThe selected base directory <%s> must exist " \
99 			"before installation is attempted."
100 #define	MSG_YORNPRMPT	"Do you want this directory created now"
101 
102 #define	MSG_ISAFILE	"\\nThe selected base directory <%s> must exist " \
103 			"before installation is attempted, but a file " \
104 			"already exists in it's place."
105 #define	MSG_YORNFILE	"Do you want the file deleted and the directory " \
106 			"created now"
107 
108 #define	MSG_PROMPT	"Enter path to package base directory"
109 
110 #define	MSG_HELP	"Installation of this package requires that a UNIX " \
111 			"directory be available for installation of " \
112 			"appropriate software.  This directory may be part " \
113 			"of any mounted filesystem, or may itself be a " \
114 			"mount point.  In general, it is unwise to select a " \
115 			"base directory which already contains other files " \
116 			"and/or directories."
117 
118 /*
119  * Set the install root (-R option).
120  */
121 
122 int
123 set_inst_root(char *path)
124 {
125 	static	char	tmp_path[PATH_MAX];
126 
127 	/*
128 	 * If we've already set the install_root but no one has used it
129 	 * yet, we'll complain and allow the change. If it's been used
130 	 * then we'll deny the switch & return failed.
131 	 */
132 	if (install_root_exists)
133 		/* If the two install_roots are different - problem */
134 		if (strcmp(install_root, path))
135 			/* We are trying to *change* the install_root */
136 			if (ir_accessed) {
137 				ptext(stderr, gettext(ERR_IRSET), path);
138 				return (0);
139 			} else { /* !ir_accessed */
140 				ptext(stderr, gettext(MSG_IR_REPL), path);
141 				install_root_exists = 0;	/* reset */
142 				install_root = NULL;
143 			}
144 
145 	if (path && *path) {
146 		if (*path != '/') {
147 			ptext(stderr, gettext(ERR_IRNOTABS), path);
148 			return (0);
149 		}
150 
151 		(void) strlcpy(tmp_path, path, sizeof (tmp_path));
152 
153 		canonize(tmp_path);
154 
155 		install_root = tmp_path;
156 
157 		install_root_exists = 1;
158 
159 		install_root_len = strlen(install_root);
160 
161 		/* If install_root is '/' then it's trivial. */
162 		if (install_root_len == 1)
163 			install_root_len = 0;
164 		else
165 			z_set_zone_root(install_root);
166 	} else
167 		install_root_exists = 0;
168 
169 	return (1);
170 }
171 
172 /*
173  * This routine returns a path with the correct install_root prepended.
174  * if the install_root has been set. NOTE : this allocates memory
175  * which will need to be freed at some point.
176  */
177 char *
178 fixpath(char *path)
179 {
180 	register char *npath_ptr, *ir_ptr;
181 	char *npath = NULL;
182 
183 	if (path && *path) {
184 		if (install_root_exists) {
185 			if ((npath =
186 			    calloc(1, strlen(path) + install_root_len +
187 			    1)) == NULL) {
188 				progerr(gettext(ERR_ALLOCFAILED), "fixpath()");
189 				quit(99);
190 			}
191 
192 			npath_ptr = npath;
193 			ir_ptr = get_inst_root();
194 
195 			while (*ir_ptr)	/* for every char in install_root */
196 				*npath_ptr++ = *ir_ptr++;	/* copy it */
197 
198 			/*
199 			 * If install_root == "/", a concatenation will
200 			 * result in a return value of "//...", same goes
201 			 * for an install_root ending in '/'. So we back
202 			 * over a trailing '/' if it's there.
203 			 */
204 			if (*(npath_ptr - 1) == '/')
205 				npath_ptr--;
206 
207 			if (strcmp(path, "/"))
208 				(void) strcpy(npath_ptr, path);
209 		} else
210 			/*
211 			 * If there's no install root & no client_basedir,
212 			 * then return the path
213 			 */
214 			npath = strdup(path);
215 	} else
216 		/*
217 		 * If there's no path specified, return the install root
218 		 * since no matter what happens, this is where the
219 		 * path will have to start.
220 		 */
221 		if (install_root_exists)
222 			npath = strdup(get_inst_root());
223 
224 	return (npath);
225 }
226 
227 /*
228  * This routine does what fixpath() does except it's for high-volume
229  * stuff restricted to the instvol() function. By using
230  * pathdup() and pathalloc() memory fragmentation is reduced. Also, the
231  * memory allocated by pathdup() and pathalloc() gets freed at the end
232  * of each volume installed.
233  */
234 char *
235 fixpath_dup(char *path)
236 {
237 	register char *npath_ptr, *ir_ptr;
238 	char *npath = NULL;
239 
240 	if (path && *path) {
241 		if (install_root_exists) {
242 			npath = pathalloc(strlen(path) + install_root_len + 1);
243 
244 			npath_ptr = npath;
245 			ir_ptr = get_inst_root();
246 
247 			while (*ir_ptr)	/* for every char in install_root */
248 				*npath_ptr++ = *ir_ptr++;	/* copy it */
249 
250 			/*
251 			 * If install_root == "/", a concatenation will
252 			 * result in a return value of "//...", same goes
253 			 * for an install_root ending in '/'. So we back
254 			 * over a trailing '/' if it's there.
255 			 */
256 			if (*(npath_ptr - 1) == '/')
257 				npath_ptr--;
258 
259 			if (strcmp(path, "/"))
260 				(void) strcpy(npath_ptr, path);
261 		} else
262 			/*
263 			 * If there's no install root & no client_basedir,
264 			 * then return the path
265 			 */
266 			npath = pathdup(path);
267 	} else
268 		/*
269 		 * If there's no path specified, return the install root
270 		 * since no matter what happens, this is where the
271 		 * path will have to start.
272 		 */
273 		if (install_root_exists)
274 			npath = pathdup(get_inst_root());
275 
276 	return (npath);
277 }
278 
279 /*
280  * This returns a pointer to a static name. This could be abused.
281  * -- JST (1993-07-21)
282  */
283 char *
284 get_inst_root(void)
285 {
286 	ir_accessed = 1;	/* we can't change it now */
287 	return (install_root);
288 }
289 
290 /*
291  * This routine takes path and removes install_root from the path
292  * if it has already been prepended. If install_root is not prepended to
293  * path or install_root is '/' or path == NULL then path is returned
294  * as is. If the resulting path is somehow relative, a corrupt
295  * package name error is raised and the program quits. NOTE : This
296  * function usually returns a pointer into the original path
297  * argument. It doesn't allocate new memory. This is possible,
298  * of course, because the path being returned is guaranteed to
299  * be a subset of the original argument unless basedir = '/' in
300  * which case a pointer to a static "/" is returned. See
301  * orig_path() below if you want to be handed a new copy of the
302  * return value.
303  */
304 char *
305 orig_path_ptr(char *path)
306 {
307 	char *retv = NULL;
308 
309 	if (path && *path) {	/* as long as we got an argument */
310 		if (!install_root_exists)	/* if no install_root */
311 			retv = path;		/*   path unchanged */
312 
313 		/*
314 		 * Otherwise, if install_root is really prepended to the path
315 		 * then remove it dealing appropriately with special cases.
316 		 */
317 		else if (strncmp(path, install_root, install_root_len) == 0) {
318 			retv = path + install_root_len;
319 			if (*retv == NULL)
320 				retv = "/";
321 
322 			/*
323 			 * The result will be relative if install_root = '/'.
324 			 * If the basedir path was built legally, then moving
325 			 * the pointer back one character will make it
326 			 * absolute. If that fails then the path we got was
327 			 * incorrectly constructed in the first place.
328 			 */
329 			else if (*retv != '/') {
330 				retv--;
331 				if (*retv != '/') {
332 					progerr(gettext(ERR_PATHNAME));
333 					quit(99);
334 				}
335 			}
336 		} else
337 			retv = path;	/* All else failing, return path. */
338 
339 		canonize(retv);
340 	}
341 
342 	return (retv);
343 }
344 
345 /*
346  * This function does the same as orig_path_ptr() except that it mallocs
347  * new space and provides a new copy of the original basedir path which
348  * needs to be free()'d one way or another later.
349  */
350 char *
351 orig_path(char *path)
352 {
353 	char *retv;
354 
355 	retv = orig_path_ptr(path);
356 
357 	return ((retv == NULL) ? retv : strdup(retv));
358 }
359 
360 /*
361  * This function lets us hold onto the environment's version of
362  * CLIENT_BASEDIR for later review by set_client_basedir().
363  */
364 void
365 set_env_cbdir()
366 {
367 	register char *cb_ptr;
368 
369 	cb_ptr = getenv("CLIENT_BASEDIR");
370 
371 	if (cb_ptr && *cb_ptr) {
372 		env_cl_bdir = strdup(cb_ptr);
373 		canonize(env_cl_bdir);
374 	}
375 }
376 
377 /* ask for the basedir */
378 static int
379 ask_basedir(char *path, int nointeract)
380 {
381 	int n;
382 
383 	if (nointeract) {
384 		progerr(gettext(MSG_REQBASEDIR));
385 		return (5);
386 	} else {
387 		path[0] = '\0';
388 		if (n = ckpath(path, P_ABSOLUTE|P_DIR|P_WRITE,
389 		    basedir, NULL, gettext(MSG_HELP),
390 		    gettext(MSG_PROMPT)))
391 			return (n);	/* FAIL */
392 		orig_basedir =
393 		    expand_path(path);
394 	}
395 	return (0);
396 }
397 
398 /*
399  * Set the basedir and client_basedir based on install root and config
400  * files. It returns 0 if all OK otherwise returns the error code base
401  * appropriate to the problem.
402  */
403 int
404 set_basedirs(int reloc, char *adm_basedir, char *pkginst, int nointeract)
405 {
406 	char	path[PATH_MAX];
407 	int	n;
408 
409 	relocatable = reloc;
410 
411 	/*
412 	 * If there are no relocatable files basedir is probably meaningless
413 	 * so we skip ahead to the simple tests. Otherwise we do the twisted
414 	 * stuff below. The BASEDIR is set based on the following heirarchy :
415 	 *	1. The entry in the admin file
416 	 *	2. The entry in the pkginfo file delivered on the medium
417 	 *	3. The entry in the already installed pkginfo file
418 	 *	4. ask
419 	 * If it's not a relocatable package, we go with whatever seems
420 	 * reasonable; if it's relocatable and we've exhausted our
421 	 * options, we ask.
422 	 */
423 	if (reloc) {
424 		int is_adm_basedir = (adm_basedir && *adm_basedir);
425 		int is_update = 0;
426 		int is_ask = 0;
427 
428 		if (is_adm_basedir) {
429 			if (strcmp(adm_basedir, "update") == 0) {
430 				is_update = 1;
431 				is_ask = 1;
432 			} else if (strcmp(adm_basedir, "ask") == 0)
433 				is_ask = 1;
434 		}
435 
436 		/*
437 		 * If there's a BASEDIR in the admin file & it's a valid
438 		 * absolute pathname, use it.
439 		 */
440 		if (is_adm_basedir && strchr("/$", *adm_basedir))
441 			orig_basedir = expand_path(adm_basedir);
442 
443 		/* If admin says 'ask regardless', ask and continue */
444 		else if (is_adm_basedir && is_ask) {
445 			if (n = ask_basedir(path, nointeract))
446 				return (n);
447 			if (is_update &&
448 			    strcmp(orig_basedir,
449 			    (basedir = getenv("BASEDIR"))) != 0) {
450 				progerr(gettext(ERR_ASKBD),
451 				    getenv("PKG"), basedir, orig_basedir);
452 				quit(4);
453 			}
454 		}
455 		/*
456 		 * If it isn't the only other valid option,
457 		 * namely 'default', quit FAIL.
458 		 */
459 		else if (is_adm_basedir &&
460 		    strcmp(adm_basedir, "default") != 0) {
461 			progerr(gettext(ERR_ADMIN_INVAL));
462 			return (1);
463 
464 		/*
465 		 * OK, the admin file has no preference, so we go to the
466 		 * other sources.
467 		 */
468 		} else {
469 			/*
470 			 * Check to see if BASEDIR is set in the environment
471 			 * (probably from the pkginfo file on the installation
472 			 * medium).
473 			 */
474 			basedir = getenv("BASEDIR");
475 			if (basedir && *basedir)
476 				orig_basedir = expand_path(basedir);
477 			else {
478 				/*
479 				 * Check to see if the package BASEDIR was
480 				 * already defined during a previous
481 				 * installation of this package instance. The
482 				 * function below looks for an installed
483 				 * pkginfo file and scans it.
484 				 */
485 				basedir = pkgparam(pkginst, "BASEDIR");
486 				if (basedir && *basedir)
487 					orig_basedir = expand_path(basedir);
488 				else if (n = ask_basedir(path, nointeract))
489 					return (n);
490 			}
491 		}
492 	} else {	/* not relocatable */
493 		/*
494 		 * Since all paths are absolute the only reason to have a
495 		 * basedir is if there's an install root meaning there's
496 		 * really a basedir relative to this host or this package is
497 		 * absolute only because it's sparse in which case we're
498 		 * interested in the prior basedir. So we next check for a
499 		 * prior basedir and then an install root.
500 		 */
501 		basedir = pkgparam(pkginst, "BASEDIR");
502 		if (basedir && *basedir)
503 			orig_basedir = expand_path(basedir);
504 
505 		else if (install_root_exists)
506 			/*
507 			 * If we have a basedir *only because*
508 			 * we have an install_root, we need to
509 			 * set orig_basedir to '/' to simplify
510 			 * later attempts to force
511 			 * client_basedir.
512 			 */
513 			orig_basedir = "/";
514 		else {
515 			eval_valid++;	/* we can run eval_path() now */
516 			return (0);	/* fixpath below unnecessary */
517 		}
518 	}
519 
520 	basedir_exists = 1;
521 
522 	basedir = fixpath(orig_basedir);
523 
524 	/*
525 	 * If basedir == "/" then there's no need for a "/" between
526 	 * it and the rest of the path.
527 	 */
528 	if (strcmp(basedir, "/") == 0)
529 		base_sepr = 0;
530 
531 	if (set_client_basedir() == 0) {
532 		progerr(gettext(ERR_NO_CL_BD));
533 		return (1);
534 	}
535 
536 	eval_valid++;	/* we've confirmed the validity of everything */
537 
538 	return (0);
539 }
540 
541 /*
542  * Make a directory from a path and all necessary directories above it as
543  * needed.
544  */
545 int
546 mkpath(char *p)
547 {
548 	char	*pt;
549 
550 	/* if entire path exists, return o.k. */
551 
552 	if (access(p, F_OK) == 0) {
553 		return (0);
554 	}
555 
556 	/* entire path not there - check components and create */
557 
558 	pt = (*p == '/') ? p+1 : p;
559 	do {
560 		if (pt = strchr(pt, '/')) {
561 			*pt = '\0';
562 		}
563 		if ((access(p, F_OK) != 0) && (mkdir(p, 0755) != 0)) {
564 			return (-1);
565 		}
566 		if (pt) {
567 			*pt++ = '/';
568 		}
569 	} while (pt);
570 
571 	return (0);
572 }
573 
574 /* This makes the required base directory if necessary */
575 void
576 mkbasedir(int flag, char *basedir)
577 {
578 	char	ans[MAX_INPUT];
579 	int	n;
580 
581 	/*
582 	 * If a base directory is called for but there's no such directory on
583 	 * the system, deal with that issue.
584 	 */
585 	if (is_a_basedir() && isdir(basedir)) {
586 		if (flag) {	/* Interaction is OK. */
587 			/*
588 			 * If there's a non-directory object in the way, ask.
589 			 */
590 			if (access(basedir, F_OK) == 0) {
591 				ptext(stderr, gettext(MSG_ISAFILE), basedir);
592 
593 				if (n = ckyorn(ans, NULL, NULL, NULL,
594 				    gettext(MSG_YORNFILE)))
595 					quit(n);
596 				if (strchr("yY", *ans) == NULL)
597 					quit(3);
598 
599 				/*
600 				 * It isn't a directory, so we'll just unlink
601 				 * it.
602 				 */
603 				if (unlink(basedir) == -1) {
604 					progerr(gettext(ERR_NODELETE),
605 					    basedir);
606 					quit(99);
607 				}
608 
609 			} else {
610 				ptext(stderr, gettext(MSG_MUSTEXIST), basedir);
611 
612 				if (n = ckyorn(ans, NULL, NULL, NULL,
613 				    gettext(MSG_YORNPRMPT)))
614 					quit(n);
615 				if (strchr("yY", *ans) == NULL)
616 					quit(3);
617 			}
618 		}
619 
620 		if (access(basedir, F_OK) == 0 || mkpath(basedir)) {
621 			progerr(gettext(ERR_MKBASE), basedir);
622 			quit(99);
623 		}
624 	}
625 }
626 
627 /*
628  * Create a client_basedir if it is appropriate. If all goes well, resulting
629  * in either a valid client_basedir or a valid lack thereof, it returns 1.
630  * If there is an irreconcileable conflict, it returns 0.
631  */
632 static int
633 set_client_basedir(void)
634 {
635 	if (install_root_exists) {
636 		if (basedir_exists)
637 			client_basedir = strdup(orig_basedir);
638 		else
639 			client_basedir = "/";
640 		client_basedir_exists = 1;
641 	}
642 
643 	/*
644 	 * In response to an agreement associated with bug report #1133956,
645 	 * CLIENT_BASEDIR will be defined in all cases where BASEDIR is
646 	 * defined until the on1094 release. For on1094 delete the else if
647 	 * and associated expressions below. -- JST (6/25/1993)
648 	 */
649 	else if (basedir_exists) {
650 		client_basedir = strdup(basedir);
651 		client_basedir_exists = 1;
652 	}
653 
654 	/*
655 	 * At this point we may or may not have a client_basedir defined. Now
656 	 * we need to check for one in the environment & make sure it syncs
657 	 * up with prior findings. If there's no other client_basedir defined,
658 	 * the environment defines it.
659 	 */
660 	if (env_cl_bdir && *env_cl_bdir) {
661 		if (client_basedir_exists) {
662 			/* If the two client basedirs mismatch, return fail */
663 			if (strcmp(client_basedir, env_cl_bdir)) {
664 				ptext(stderr, gettext(ERR_CL_MIS),
665 				    client_basedir, env_cl_bdir);
666 				return (0);
667 			}
668 		} else {
669 			client_basedir = env_cl_bdir;
670 			client_basedir_exists = 1;
671 		}
672 	}
673 
674 	return (1);
675 }
676 
677 static char *
678 expand_path(char *path)
679 {
680 	char	path_buf[PATH_MAX];
681 
682 	if (!path || !*path)
683 		return (path);
684 
685 	(void) strlcpy(path_buf, path, sizeof (path_buf));
686 	mappath(getmapmode(), path_buf);
687 	canonize(path_buf);
688 
689 	return (qstrdup(path_buf));
690 }
691 
692 char *
693 get_basedir(void)
694 {
695 	return (basedir);
696 }
697 
698 char *
699 get_client_basedir(void)
700 {
701 	return (client_basedir);
702 }
703 
704 /*
705  * This function returns the basedir that is appropriate for this package's
706  * pkginfo file.
707  */
708 char *
709 get_info_basedir(void)
710 {
711 	if (install_root_exists)
712 		return (client_basedir);
713 	else if (basedir_exists)
714 		return (basedir);
715 	else
716 		return (NULL);
717 }
718 
719 int
720 is_an_inst_root(void)
721 {
722 	return (install_root_exists);
723 }
724 
725 int
726 is_a_basedir(void)
727 {
728 	return (basedir_exists);
729 }
730 
731 int
732 is_relocatable(void)
733 {
734 	return (relocatable);
735 }
736 
737 int
738 is_a_cl_basedir(void)
739 {
740 	return (client_basedir_exists);
741 }
742 
743 /*
744  * Since calls to putparam() become valid long after much of the above
745  * code has run, this routine allows the insertion of these key
746  * environment variables without passing a bunch of pointers.
747  */
748 void
749 put_path_params(void)
750 {
751 	if (install_root_exists)
752 		putparam("PKG_INSTALL_ROOT", get_inst_root());
753 
754 	if (basedir_exists)
755 		putparam("BASEDIR", basedir);
756 
757 	if (client_basedir_exists)
758 		putparam("CLIENT_BASEDIR", client_basedir);
759 }
760 
761 /*
762  * This fills three pointers and a buffer which contains the longest
763  * possible path (with install_root and basedir prepended. The pointers
764  * are to the subpaths within the string. This was added so that the
765  * eptlist could be produced with all relevant paths defined without
766  * repeated calls and string scans. For example, given a path of
767  * haberdasher/crute we may return
768  *
769  *	server_ptr -----> /export/root/client1/opt/SUNWhab/haberdasher/crute
770  *                                            |            |
771  *	client_ptr ---------------------------             |
772  *	map_ptr -------------------------------------------
773  *
774  * We construct the new path based upon the established environment
775  * and the type of path that was passed. Here are the possibilities:
776  *
777  *   |					| relative path	| absolute path	|
778  *   |	--------------------------------|---------------|---------------|
779  *   |	is_an_inst_root			|	1	|	2	|
780  *   V	! an_inst_root && is_a_basedir	|	1	|	3	|
781  *	! an_inst_root && ! a_basedir	|	X	|	3	|
782  *
783  * METHOD
784  * 1. Prepend the basedir to the path (the basedir is guaranteed to exist
785  *	whenever there's an install_root).
786  *
787  * 2. Prepend the install_root (not the basedir) to the path
788  *
789  * 3. Return the path as unchanged.
790  *
791  * X. THIS CAN'T HAPPEN
792  */
793 int
794 eval_path(char **server_ptr, char **client_ptr, char **map_ptr, char *path)
795 {
796 	static int client_offset;
797 	static int offsets_valid, retcode;
798 	int path_size;
799 
800 	if (!offsets_valid) {
801 		/*
802 		 * This is the offset from the beginning of the evaluated
803 		 * path to the start of the relative path. Note that we
804 		 * are accounting for the '/' inserted between the
805 		 * basedir and the path with the '+ 1'. If there is a
806 		 * relative path, then there is always a basedir. The
807 		 * only way this will come up '0' is if this is an
808 		 * absolute package.
809 		 */
810 		orig_offset_rel = (is_a_basedir()) ? (strlen(basedir) +
811 		    base_sepr) : 0;
812 
813 		/*
814 		 * This is the position of the client-relative path
815 		 * in that it points to the '/' beginning the base
816 		 * directory or the absolute path. Once the basedir has
817 		 * been afixed, the path is absolute. For that reason,
818 		 * the client path is the same thing as the original path
819 		 * if it were absolute.
820 		 */
821 		client_offset = (is_an_inst_root()) ? install_root_len : 0;
822 
823 		offsets_valid = 1;
824 	}
825 
826 	/*
827 	 * If we've evaluated the base directory and come up trumps,
828 	 * then we can procede with this operation, otherwise, the
829 	 * available data is too ambiguous to resolve the issue.
830 	 */
831 	if (eval_valid) {
832 		if (RELATIVE(path)) {
833 			if (relocatable) {
834 				/*
835 				 * Figure out how long our buffer will
836 				 * have to be.
837 				 */
838 				path_size = orig_offset_rel + strlen(path);
839 
840 				(*server_ptr) = pathalloc(path_size);
841 
842 				*client_ptr = *server_ptr + client_offset;
843 
844 				if (map_ptr)
845 					*map_ptr = *server_ptr +
846 					    orig_offset_rel;
847 
848 				/* LINTED warning: variable format specifier */
849 				(void) snprintf(*server_ptr, path_size+1,
850 					rel_fmt[base_sepr], basedir, path);
851 			} else {
852 				ptext(stderr, gettext(ERR_RELINABS), path);
853 				retcode = 0;
854 			}
855 		} else {	/* NOT RELATIVE */
856 			*server_ptr = fixpath_dup(path);
857 
858 			if ((*client_ptr = *server_ptr + client_offset) == NULL)
859 				*client_ptr = "/";
860 
861 			if (map_ptr)
862 				*map_ptr = *client_ptr;
863 		}
864 
865 		retcode = 1;
866 	} else {
867 		ptext(stderr, gettext(ERR_AMBDIRS));
868 		retcode = 0;
869 	}
870 
871 	return (retcode);
872 }
873 
874 void
875 export_client_env(char *root_path)
876 {
877 	char	*inst_release_path;
878 	char	*key;
879 	char	*value;
880 	FILE	*inst_fp;
881 	size_t	len;
882 
883 	/*
884 	 * Put the variables found in a clients INST_RELEASE file into the
885 	 * package environment so procedure scripts can know what
886 	 * release/version/revision a client is running. Also this function
887 	 * doesn't return state since the INST_RELEASE file may not exist in
888 	 * some package installation environments
889 	 */
890 
891 	len = strlen(root_path) + strlen(INST_RELEASE) + 2;
892 
893 	inst_release_path = (char *)malloc(len);
894 
895 	key = (char *)malloc(PATH_MAX);
896 
897 	(void) snprintf(inst_release_path, len, "%s/%s", root_path,
898 				INST_RELEASE);
899 
900 	if ((inst_fp = fopen(inst_release_path, "r")) != NULL) {
901 		while (value = fpkgparam(inst_fp, key)) {
902 			if (strcmp(key, "OS") == 0) {
903 				putparam("PKG_CLIENT_OS", value);
904 			} else if (strcmp(key, "VERSION") == 0) {
905 				putparam("PKG_CLIENT_VERSION", value);
906 			} else if (strcmp(key, "REV") == 0) {
907 				putparam("PKG_CLIENT_REVISION", value);
908 			}
909 			*key = '\0';
910 		}
911 		(void) fclose(inst_fp);
912 	}
913 	free(inst_release_path);
914 	free(key);
915 }
916 
917 /*
918  * Increment variable indicating the installation is from a partially spooled
919  * package.
920  */
921 void
922 set_partial_inst(void)
923 {
924 	partial_inst++;
925 }
926 
927 /*
928  * Return variable indicating that the installation is from a partially spooled
929  * package.
930  * Returns:  !0 for true
931  *           0 for false
932  */
933 int
934 is_partial_inst(void)
935 {
936 	return (partial_inst);
937 }
938 
939 /*
940  * Increment variable indicating that only the depend and pkginfo DB's are to be
941  * updated
942  */
943 
944 void
945 set_depend_pkginfo_DB(boolean_t a_setting)
946 {
947 	depend_pkginfo_DB = a_setting;
948 }
949 
950 /*
951  * Return variable indicating that the installation only updates the depend
952  * and pkginfo DB's.
953  * Returns:  !0 for true
954  *           0 for false
955  */
956 
957 boolean_t
958 is_depend_pkginfo_DB(void)
959 {
960 	return (depend_pkginfo_DB);
961 }
962 
963 /*
964  * Increment variable indicating that packages should not be spooled in
965  * var/sadm/pkg/<pkgabbrev>/save/pspool/
966  */
967 void
968 disable_spool_create(void)
969 {
970 	partial_spool_create++;
971 }
972 
973 /*
974  * Return variable indicating whether or not the partial spool directory
975  * should be created.
976  * Returns:  1 for true
977  *           0 for false
978  */
979 int
980 is_spool_create(void)
981 {
982 	return (partial_spool_create);
983 }
984