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.
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.
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]
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
30 #include <sys/types.h>
31 #include <sys/param.h>
45 #define ERR_NOPKGMAP "Cannot open pkgmap file."
47 #define ENTRY_MAX (PATH_MAX + 38)
48 #define IGNORE_START ":#!"
49 #define IGNORE_TYPE "i"
51 static int has_rel_path(char *entry
);
52 static int is_relative(char *entry
);
55 * This routine attempts to determine with certainty whether or not
56 * the package is relocatable or not. It first attempts to determine if
57 * there is a reloc directory by scanning pkginstdir. If that fails to
58 * provide a definite result (pkg is coming from a stream device and
59 * the directories aren't in place) it inspects the pkgmap in pkginstdir
60 * in order to determine if the package has relocatable elements. If
61 * there is a single relative pathname or $BASEDIR/... construct,
62 * this returns 1. If no relative pathnames are found it returns 0
63 * meaning absolute package and all the things that implies.
65 * This does not determine the validity of the pkgmap file. If the pkgmap
66 * is corrupted, this returns 0.
69 isreloc(char *pkginstdir
)
76 /* First look in the directory */
77 if ((dirfp
= opendir(pkginstdir
)) != NULL
) {
78 while ((drp
= readdir(dirfp
)) != NULL
) {
79 if (drp
->d_name
[0] == '.')
81 if (strlen(drp
->d_name
) < (size_t)5)
83 if (strncmp(drp
->d_name
, "reloc", 5) == 0) {
88 (void) closedir(dirfp
);
92 * If retcode == 0, meaning we didn't find a reloc directory then we
93 * probably don't have a complete directory structure available to
94 * us. We'll have to determine what type of package it is by scanning
98 char path_buffer
[ENTRY_MAX
];
100 (void) snprintf(path_buffer
, sizeof (path_buffer
),
101 "%s/pkgmap", pkginstdir
);
103 canonize(path_buffer
);
105 if ((pkg_fp
= fopen(path_buffer
, "r")) != NULL
) {
106 while (fgets(path_buffer
, sizeof (path_buffer
), pkg_fp
))
107 if (has_rel_path(path_buffer
)) {
111 (void) fclose(pkg_fp
);
113 progerr(gettext(ERR_NOPKGMAP
));
122 * Test the string for the presence of a relative path. If found, return
123 * 1 otherwise return 0. If we get past the IGNORE_TYPE test, we're working
124 * with a line of the form :
126 * dpart type classname pathname ...
128 * It's pathname we're going to test here.
130 * Yes, yes, I know about sscanf(); but, I don't need to reserve 4K of
131 * space and parse the whole string, I just need to get to two tokens.
135 has_rel_path(char *entry
)
137 register int entry_pos
= 1;
139 /* If the line is a comment or special directive, return 0 */
140 if (*entry
== NULL
|| strchr(IGNORE_START
, *entry
))
143 /* Skip past this data entry if it is volume number. */
144 if (isdigit(*entry
)) {
145 while (*entry
&& !isspace(*entry
)) {
150 /* Skip past this white space */
151 while (*entry
&& isspace(*entry
)) {
156 * Now we're either pointing at the type or we're pointing at
157 * the termination of a degenerate entry. If the line is degenerate
158 * or the type indicates this line should be ignored, we return
159 * as though not relative.
161 if (*entry
== NULL
|| strchr(IGNORE_TYPE
, *entry
))
164 /* The pathname is in the third position */
166 /* Skip past this data entry */
167 while (*entry
&& !isspace(*entry
)) {
171 /* Skip past this white space and call this the next entry */
172 while (*entry
&& isspace(*entry
)) {
175 } while (++entry_pos
< 3 && *entry
!= NULL
);
178 * Now we're pointing at the first character of the pathname.
179 * If the file is corrupted, we're pointing at NULL. is_relative()
180 * will return FALSE for NULL which will yield the correct return
183 return (is_relative(entry
));
187 * If the path doesn't begin with a variable, the first character in the
188 * path is tested for '/' to determine if it is absolute or not. If the
189 * path begins with a '$', that variable is resolved if possible. If it
190 * isn't defined yet, we exit with error code 1.
193 is_relative(char *entry
)
195 register char *eopath
= entry
; /* end of full pathname pointer */
196 register char **lasts
= &entry
;
198 /* If there is a path, test it */
199 if (entry
&& *entry
) {
200 if (*entry
== '$') { /* it's an environment parameter */
201 entry
++; /* skip the '$' */
203 while (*eopath
&& !isspace(*eopath
))
206 *eopath
= '\0'; /* terminate the pathname */
208 /* isolate the variable */
209 entry
= strtok_r(entry
, "/", lasts
);
212 * Some packages call out $BASEDIR for relative
213 * paths in the pkgmap even though that is
214 * redundant. This special case is actually
215 * an indication that this is a relative
218 if (strcmp(entry
, "BASEDIR") == 0)
221 * Since entry is pointing to a now-expendable PATH_MAX
222 * size buffer, we can expand the path variable into it
225 entry
= getenv(entry
);
229 * Return type of path. If pathname was unresolvable
230 * variable, assume relative. This looks like a strange
231 * assumption since the resolved path may end up
232 * absolute and pkgadd may prompt the user for a basedir
233 * incorrectly because of this assumption. Unfortunately,
234 * the request script MUST have a final BASEDIR in the
235 * environment before it executes.
238 return (RELATIVE(entry
));
241 } else /* no path, so we skip it */