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