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