xref: /onnv-gate/usr/src/cmd/svr4pkg/libinst/isreloc.c (revision 9781:ccf49524d5dc)
1*9781SMoriah.Waterland@Sun.COM /*
2*9781SMoriah.Waterland@Sun.COM  * CDDL HEADER START
3*9781SMoriah.Waterland@Sun.COM  *
4*9781SMoriah.Waterland@Sun.COM  * The contents of this file are subject to the terms of the
5*9781SMoriah.Waterland@Sun.COM  * Common Development and Distribution License (the "License").
6*9781SMoriah.Waterland@Sun.COM  * You may not use this file except in compliance with the License.
7*9781SMoriah.Waterland@Sun.COM  *
8*9781SMoriah.Waterland@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*9781SMoriah.Waterland@Sun.COM  * or http://www.opensolaris.org/os/licensing.
10*9781SMoriah.Waterland@Sun.COM  * See the License for the specific language governing permissions
11*9781SMoriah.Waterland@Sun.COM  * and limitations under the License.
12*9781SMoriah.Waterland@Sun.COM  *
13*9781SMoriah.Waterland@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
14*9781SMoriah.Waterland@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*9781SMoriah.Waterland@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
16*9781SMoriah.Waterland@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
17*9781SMoriah.Waterland@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
18*9781SMoriah.Waterland@Sun.COM  *
19*9781SMoriah.Waterland@Sun.COM  * CDDL HEADER END
20*9781SMoriah.Waterland@Sun.COM  */
21*9781SMoriah.Waterland@Sun.COM 
22*9781SMoriah.Waterland@Sun.COM /*
23*9781SMoriah.Waterland@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24*9781SMoriah.Waterland@Sun.COM  * Use is subject to license terms.
25*9781SMoriah.Waterland@Sun.COM  */
26*9781SMoriah.Waterland@Sun.COM 
27*9781SMoriah.Waterland@Sun.COM 
28*9781SMoriah.Waterland@Sun.COM 
29*9781SMoriah.Waterland@Sun.COM #include <stdio.h>
30*9781SMoriah.Waterland@Sun.COM #include <sys/types.h>
31*9781SMoriah.Waterland@Sun.COM #include <sys/param.h>
32*9781SMoriah.Waterland@Sun.COM #include <dirent.h>
33*9781SMoriah.Waterland@Sun.COM #include <limits.h>
34*9781SMoriah.Waterland@Sun.COM #include <errno.h>
35*9781SMoriah.Waterland@Sun.COM #include <ctype.h>
36*9781SMoriah.Waterland@Sun.COM #include <fcntl.h>
37*9781SMoriah.Waterland@Sun.COM #include <stdlib.h>
38*9781SMoriah.Waterland@Sun.COM #include <string.h>
39*9781SMoriah.Waterland@Sun.COM #include <unistd.h>
40*9781SMoriah.Waterland@Sun.COM #include <pkglib.h>
41*9781SMoriah.Waterland@Sun.COM #include <libintl.h>
42*9781SMoriah.Waterland@Sun.COM #include <libinst.h>
43*9781SMoriah.Waterland@Sun.COM #include <install.h>
44*9781SMoriah.Waterland@Sun.COM 
45*9781SMoriah.Waterland@Sun.COM #define	ERR_NOPKGMAP	"Cannot open pkgmap file."
46*9781SMoriah.Waterland@Sun.COM 
47*9781SMoriah.Waterland@Sun.COM #define	ENTRY_MAX (PATH_MAX + 38)
48*9781SMoriah.Waterland@Sun.COM #define	IGNORE_START	":#!"
49*9781SMoriah.Waterland@Sun.COM #define	IGNORE_TYPE	"i"
50*9781SMoriah.Waterland@Sun.COM 
51*9781SMoriah.Waterland@Sun.COM static int	has_rel_path(char *entry);
52*9781SMoriah.Waterland@Sun.COM static int	is_relative(char *entry);
53*9781SMoriah.Waterland@Sun.COM 
54*9781SMoriah.Waterland@Sun.COM /*
55*9781SMoriah.Waterland@Sun.COM  * This routine attempts to determine with certainty whether or not
56*9781SMoriah.Waterland@Sun.COM  * the package is relocatable or not. It first attempts to determine if
57*9781SMoriah.Waterland@Sun.COM  * there is a reloc directory by scanning pkginstdir. If that fails to
58*9781SMoriah.Waterland@Sun.COM  * provide a definite result (pkg is coming from a stream device and
59*9781SMoriah.Waterland@Sun.COM  * the directories aren't in place) it inspects the pkgmap in pkginstdir
60*9781SMoriah.Waterland@Sun.COM  * in order to determine if the package has relocatable elements. If
61*9781SMoriah.Waterland@Sun.COM  * there is a single relative pathname or $BASEDIR/... construct,
62*9781SMoriah.Waterland@Sun.COM  * this returns 1. If no relative pathnames are found it returns 0
63*9781SMoriah.Waterland@Sun.COM  * meaning absolute package and all the things that implies.
64*9781SMoriah.Waterland@Sun.COM  *
65*9781SMoriah.Waterland@Sun.COM  * This does not determine the validity of the pkgmap file. If the pkgmap
66*9781SMoriah.Waterland@Sun.COM  * is corrupted, this returns 0.
67*9781SMoriah.Waterland@Sun.COM  */
68*9781SMoriah.Waterland@Sun.COM int
isreloc(char * pkginstdir)69*9781SMoriah.Waterland@Sun.COM isreloc(char *pkginstdir)
70*9781SMoriah.Waterland@Sun.COM {
71*9781SMoriah.Waterland@Sun.COM 	FILE	*pkg_fp;
72*9781SMoriah.Waterland@Sun.COM 	struct	dirent *drp;
73*9781SMoriah.Waterland@Sun.COM 	DIR	*dirfp;
74*9781SMoriah.Waterland@Sun.COM 	int	retcode = 0;
75*9781SMoriah.Waterland@Sun.COM 
76*9781SMoriah.Waterland@Sun.COM 	/* First look in the directory */
77*9781SMoriah.Waterland@Sun.COM 	if ((dirfp = opendir(pkginstdir)) != NULL) {
78*9781SMoriah.Waterland@Sun.COM 		while ((drp = readdir(dirfp)) != NULL) {
79*9781SMoriah.Waterland@Sun.COM 			if (drp->d_name[0] == '.')
80*9781SMoriah.Waterland@Sun.COM 				continue;
81*9781SMoriah.Waterland@Sun.COM 			if (strlen(drp->d_name) < (size_t)5)
82*9781SMoriah.Waterland@Sun.COM 				continue;
83*9781SMoriah.Waterland@Sun.COM 			if (strncmp(drp->d_name, "reloc", 5) == 0) {
84*9781SMoriah.Waterland@Sun.COM 				retcode = 1;
85*9781SMoriah.Waterland@Sun.COM 				break;
86*9781SMoriah.Waterland@Sun.COM 			}
87*9781SMoriah.Waterland@Sun.COM 		}
88*9781SMoriah.Waterland@Sun.COM 		(void) closedir(dirfp);
89*9781SMoriah.Waterland@Sun.COM 	}
90*9781SMoriah.Waterland@Sun.COM 
91*9781SMoriah.Waterland@Sun.COM 	/*
92*9781SMoriah.Waterland@Sun.COM 	 * If retcode == 0, meaning we didn't find a reloc directory then we
93*9781SMoriah.Waterland@Sun.COM 	 * probably don't have a complete directory structure available to
94*9781SMoriah.Waterland@Sun.COM 	 * us. We'll have to determine what type of package it is by scanning
95*9781SMoriah.Waterland@Sun.COM 	 * the pkgmap file.
96*9781SMoriah.Waterland@Sun.COM 	 */
97*9781SMoriah.Waterland@Sun.COM 	if (retcode == 0) {
98*9781SMoriah.Waterland@Sun.COM 		char	path_buffer[ENTRY_MAX];
99*9781SMoriah.Waterland@Sun.COM 
100*9781SMoriah.Waterland@Sun.COM 		(void) snprintf(path_buffer, sizeof (path_buffer),
101*9781SMoriah.Waterland@Sun.COM 						"%s/pkgmap", pkginstdir);
102*9781SMoriah.Waterland@Sun.COM 
103*9781SMoriah.Waterland@Sun.COM 		canonize(path_buffer);
104*9781SMoriah.Waterland@Sun.COM 
105*9781SMoriah.Waterland@Sun.COM 		if ((pkg_fp = fopen(path_buffer, "r")) != NULL) {
106*9781SMoriah.Waterland@Sun.COM 			while (fgets(path_buffer, sizeof (path_buffer), pkg_fp))
107*9781SMoriah.Waterland@Sun.COM 				if (has_rel_path(path_buffer)) {
108*9781SMoriah.Waterland@Sun.COM 					retcode = 1;
109*9781SMoriah.Waterland@Sun.COM 					break;
110*9781SMoriah.Waterland@Sun.COM 				}
111*9781SMoriah.Waterland@Sun.COM 			(void) fclose(pkg_fp);
112*9781SMoriah.Waterland@Sun.COM 		} else {
113*9781SMoriah.Waterland@Sun.COM 			progerr(gettext(ERR_NOPKGMAP));
114*9781SMoriah.Waterland@Sun.COM 			quit(99);
115*9781SMoriah.Waterland@Sun.COM 		}
116*9781SMoriah.Waterland@Sun.COM 	}
117*9781SMoriah.Waterland@Sun.COM 
118*9781SMoriah.Waterland@Sun.COM 	return (retcode);
119*9781SMoriah.Waterland@Sun.COM }
120*9781SMoriah.Waterland@Sun.COM 
121*9781SMoriah.Waterland@Sun.COM /*
122*9781SMoriah.Waterland@Sun.COM  * Test the string for the presence of a relative path. If found, return
123*9781SMoriah.Waterland@Sun.COM  * 1 otherwise return 0. If we get past the IGNORE_TYPE test, we're working
124*9781SMoriah.Waterland@Sun.COM  * with a line of the form :
125*9781SMoriah.Waterland@Sun.COM  *
126*9781SMoriah.Waterland@Sun.COM  *	dpart type classname pathname ...
127*9781SMoriah.Waterland@Sun.COM  *
128*9781SMoriah.Waterland@Sun.COM  * It's pathname we're going to test here.
129*9781SMoriah.Waterland@Sun.COM  *
130*9781SMoriah.Waterland@Sun.COM  * Yes, yes, I know about sscanf(); but, I don't need to reserve 4K of
131*9781SMoriah.Waterland@Sun.COM  * space and parse the whole string, I just need to get to two tokens.
132*9781SMoriah.Waterland@Sun.COM  * We're in a hurry.
133*9781SMoriah.Waterland@Sun.COM  */
134*9781SMoriah.Waterland@Sun.COM static int
has_rel_path(char * entry)135*9781SMoriah.Waterland@Sun.COM has_rel_path(char *entry)
136*9781SMoriah.Waterland@Sun.COM {
137*9781SMoriah.Waterland@Sun.COM 	register int entry_pos = 1;
138*9781SMoriah.Waterland@Sun.COM 
139*9781SMoriah.Waterland@Sun.COM 	/* If the line is a comment or special directive, return 0 */
140*9781SMoriah.Waterland@Sun.COM 	if (*entry == NULL || strchr(IGNORE_START, *entry))
141*9781SMoriah.Waterland@Sun.COM 		return (0);
142*9781SMoriah.Waterland@Sun.COM 
143*9781SMoriah.Waterland@Sun.COM 	/* Skip past this data entry if it is volume number. */
144*9781SMoriah.Waterland@Sun.COM 	if (isdigit(*entry)) {
145*9781SMoriah.Waterland@Sun.COM 		while (*entry && !isspace(*entry)) {
146*9781SMoriah.Waterland@Sun.COM 			entry++;
147*9781SMoriah.Waterland@Sun.COM 		}
148*9781SMoriah.Waterland@Sun.COM 	}
149*9781SMoriah.Waterland@Sun.COM 
150*9781SMoriah.Waterland@Sun.COM 	/* Skip past this white space */
151*9781SMoriah.Waterland@Sun.COM 	while (*entry && isspace(*entry)) {
152*9781SMoriah.Waterland@Sun.COM 		entry++;
153*9781SMoriah.Waterland@Sun.COM 	}
154*9781SMoriah.Waterland@Sun.COM 
155*9781SMoriah.Waterland@Sun.COM 	/*
156*9781SMoriah.Waterland@Sun.COM 	 * Now we're either pointing at the type or we're pointing at
157*9781SMoriah.Waterland@Sun.COM 	 * the termination of a degenerate entry. If the line is degenerate
158*9781SMoriah.Waterland@Sun.COM 	 * or the type indicates this line should be ignored, we return
159*9781SMoriah.Waterland@Sun.COM 	 * as though not relative.
160*9781SMoriah.Waterland@Sun.COM 	 */
161*9781SMoriah.Waterland@Sun.COM 	if (*entry == NULL || strchr(IGNORE_TYPE, *entry))
162*9781SMoriah.Waterland@Sun.COM 		return (0);
163*9781SMoriah.Waterland@Sun.COM 
164*9781SMoriah.Waterland@Sun.COM 	/* The pathname is in the third position */
165*9781SMoriah.Waterland@Sun.COM 	do {
166*9781SMoriah.Waterland@Sun.COM 		/* Skip past this data entry */
167*9781SMoriah.Waterland@Sun.COM 		while (*entry && !isspace(*entry)) {
168*9781SMoriah.Waterland@Sun.COM 			entry++;
169*9781SMoriah.Waterland@Sun.COM 		}
170*9781SMoriah.Waterland@Sun.COM 
171*9781SMoriah.Waterland@Sun.COM 		/* Skip past this white space and call this the next entry */
172*9781SMoriah.Waterland@Sun.COM 		while (*entry && isspace(*entry)) {
173*9781SMoriah.Waterland@Sun.COM 			entry++;
174*9781SMoriah.Waterland@Sun.COM 		}
175*9781SMoriah.Waterland@Sun.COM 	} while (++entry_pos < 3 && *entry != NULL);
176*9781SMoriah.Waterland@Sun.COM 
177*9781SMoriah.Waterland@Sun.COM 	/*
178*9781SMoriah.Waterland@Sun.COM 	 * Now we're pointing at the first character of the pathname.
179*9781SMoriah.Waterland@Sun.COM 	 * If the file is corrupted, we're pointing at NULL. is_relative()
180*9781SMoriah.Waterland@Sun.COM 	 * will return FALSE for NULL which will yield the correct return
181*9781SMoriah.Waterland@Sun.COM 	 * value.
182*9781SMoriah.Waterland@Sun.COM 	 */
183*9781SMoriah.Waterland@Sun.COM 	return (is_relative(entry));
184*9781SMoriah.Waterland@Sun.COM }
185*9781SMoriah.Waterland@Sun.COM 
186*9781SMoriah.Waterland@Sun.COM /*
187*9781SMoriah.Waterland@Sun.COM  * If the path doesn't begin with a variable, the first character in the
188*9781SMoriah.Waterland@Sun.COM  * path is tested for '/' to determine if it is absolute or not. If the
189*9781SMoriah.Waterland@Sun.COM  * path begins with a '$', that variable is resolved if possible. If it
190*9781SMoriah.Waterland@Sun.COM  * isn't defined yet, we exit with error code 1.
191*9781SMoriah.Waterland@Sun.COM  */
192*9781SMoriah.Waterland@Sun.COM static int
is_relative(char * entry)193*9781SMoriah.Waterland@Sun.COM is_relative(char *entry)
194*9781SMoriah.Waterland@Sun.COM {
195*9781SMoriah.Waterland@Sun.COM 	register char *eopath = entry;	/* end of full pathname pointer */
196*9781SMoriah.Waterland@Sun.COM 	register char **lasts = &entry;
197*9781SMoriah.Waterland@Sun.COM 
198*9781SMoriah.Waterland@Sun.COM 	/* If there is a path, test it */
199*9781SMoriah.Waterland@Sun.COM 	if (entry && *entry) {
200*9781SMoriah.Waterland@Sun.COM 		if (*entry == '$') {	/* it's an environment parameter */
201*9781SMoriah.Waterland@Sun.COM 			entry++;	/* skip the '$' */
202*9781SMoriah.Waterland@Sun.COM 
203*9781SMoriah.Waterland@Sun.COM 			while (*eopath && !isspace(*eopath))
204*9781SMoriah.Waterland@Sun.COM 				eopath++;
205*9781SMoriah.Waterland@Sun.COM 
206*9781SMoriah.Waterland@Sun.COM 			*eopath = '\0';	/* terminate the pathname */
207*9781SMoriah.Waterland@Sun.COM 
208*9781SMoriah.Waterland@Sun.COM 			/* isolate the variable */
209*9781SMoriah.Waterland@Sun.COM 			entry = strtok_r(entry, "/", lasts);
210*9781SMoriah.Waterland@Sun.COM 
211*9781SMoriah.Waterland@Sun.COM 			/*
212*9781SMoriah.Waterland@Sun.COM 			 * Some packages call out $BASEDIR for relative
213*9781SMoriah.Waterland@Sun.COM 			 * paths in the pkgmap even though that is
214*9781SMoriah.Waterland@Sun.COM 			 * redundant. This special case is actually
215*9781SMoriah.Waterland@Sun.COM 			 * an indication that this is a relative
216*9781SMoriah.Waterland@Sun.COM 			 * path.
217*9781SMoriah.Waterland@Sun.COM 			 */
218*9781SMoriah.Waterland@Sun.COM 			if (strcmp(entry, "BASEDIR") == 0)
219*9781SMoriah.Waterland@Sun.COM 				return (1);
220*9781SMoriah.Waterland@Sun.COM 			/*
221*9781SMoriah.Waterland@Sun.COM 			 * Since entry is pointing to a now-expendable PATH_MAX
222*9781SMoriah.Waterland@Sun.COM 			 * size buffer, we can expand the path variable into it
223*9781SMoriah.Waterland@Sun.COM 			 * here.
224*9781SMoriah.Waterland@Sun.COM 			 */
225*9781SMoriah.Waterland@Sun.COM 			entry = getenv(entry);
226*9781SMoriah.Waterland@Sun.COM 		}
227*9781SMoriah.Waterland@Sun.COM 
228*9781SMoriah.Waterland@Sun.COM 		/*
229*9781SMoriah.Waterland@Sun.COM 		 * Return type of path. If pathname was unresolvable
230*9781SMoriah.Waterland@Sun.COM 		 * variable, assume relative. This looks like a strange
231*9781SMoriah.Waterland@Sun.COM 		 * assumption since the resolved path may end up
232*9781SMoriah.Waterland@Sun.COM 		 * absolute and pkgadd may prompt the user for a basedir
233*9781SMoriah.Waterland@Sun.COM 		 * incorrectly because of this assumption. Unfortunately,
234*9781SMoriah.Waterland@Sun.COM 		 * the request script MUST have a final BASEDIR in the
235*9781SMoriah.Waterland@Sun.COM 		 * environment before it executes.
236*9781SMoriah.Waterland@Sun.COM 		 */
237*9781SMoriah.Waterland@Sun.COM 		if (entry && *entry)
238*9781SMoriah.Waterland@Sun.COM 			return (RELATIVE(entry));
239*9781SMoriah.Waterland@Sun.COM 		else
240*9781SMoriah.Waterland@Sun.COM 			return (1);
241*9781SMoriah.Waterland@Sun.COM 	} else		/* no path, so we skip it */
242*9781SMoriah.Waterland@Sun.COM 		return (0);
243*9781SMoriah.Waterland@Sun.COM }
244