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 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include <libintl.h> 33 #include <errno.h> 34 #include <assert.h> 35 #include <sys/types.h> 36 #include <sys/mntent.h> 37 #include <sys/mnttab.h> 38 #include <sys/param.h> 39 #include <libzonecfg.h> 40 #include "zones_strings.h" 41 #include "instzones_lib.h" 42 43 #define MNTTAB "/etc/mnttab" 44 45 #define MNTTAB_HUNK 32 46 47 static struct mnttab *mountTable; 48 static size_t mountTableSize = 0; 49 static boolean_t createdFlag = B_FALSE; 50 51 /* 52 * Name : z_createMountTable 53 * Description : Populate the mountTable Array with mnttab entries 54 * Arguments : void 55 * Returns : int 56 * 0: The Mount Table was succesfully initialized 57 * -1: There was an error during initialisation 58 */ 59 int 60 z_createMountTable(void) 61 { 62 FILE *fp; 63 struct mnttab ent; 64 struct mnttab *entp; 65 66 if (createdFlag) { 67 return (0); 68 } 69 70 fp = fopen(MNTTAB, "r"); 71 if (fp == NULL) { 72 _z_program_error(ERR_OPEN_READ, MNTTAB, errno, 73 strerror(errno)); 74 return (-1); 75 } 76 77 /* Put the entries into the table */ 78 mountTable = NULL; 79 mountTableSize = 0; 80 createdFlag = B_TRUE; 81 while (getmntent(fp, &ent) == 0) { 82 if (mountTableSize % MNTTAB_HUNK == 0) { 83 mountTable = _z_realloc(mountTable, 84 (mountTableSize + MNTTAB_HUNK) * sizeof (ent)); 85 } 86 entp = &mountTable[mountTableSize++]; 87 88 /* 89 * Zero out any fields we're not using. 90 */ 91 (void) memset(entp, 0, sizeof (*entp)); 92 93 if (ent.mnt_special != NULL) 94 entp->mnt_special = _z_strdup(ent.mnt_special); 95 if (ent.mnt_mntopts != NULL) 96 entp->mnt_mntopts = _z_strdup(ent.mnt_mntopts); 97 entp->mnt_mountp = _z_strdup(ent.mnt_mountp); 98 entp->mnt_fstype = _z_strdup(ent.mnt_fstype); 99 } 100 101 (void) fclose(fp); 102 return (0); 103 } 104 105 /* 106 * Name : findPathRWStatus 107 * Description : Check whether the given path is an mnttab entry 108 * Arguments : char * - The Path to be verified 109 * Returns : int 110 * -1: The Path is NOT present in the table (mnttab) 111 * 0: The Path is present in the table and is mounted read-only 112 * 1: The Path is present in the table and is mounted read-write 113 */ 114 static int 115 findPathRWStatus(const char *a_path) 116 { 117 int i; 118 119 for (i = 0; i < mountTableSize; i++) { 120 if (strcmp(a_path, mountTable[i].mnt_mountp) == 0) { 121 if (hasmntopt(&mountTable[i], MNTOPT_RO) != NULL) { 122 return (0); 123 } else { 124 return (1); 125 } 126 } 127 } 128 129 return (-1); 130 } 131 132 133 /* 134 * Name : z_isPathWritable 135 * Description : Check if the given path is in a writable area 136 * Arguments : char * - The Path to be verified 137 * Returns : int 138 * 0: The Path is under a read-only mount 139 * 1: The Path is under a read-write mount 140 * NOTE : This funcion automatically initialises 141 * the mountPoint table if needed. 142 */ 143 int 144 z_isPathWritable(const char *a_str) 145 { 146 int i, result, slen; 147 char a_path[MAXPATHLEN]; 148 149 if (!createdFlag) { 150 if (z_createMountTable() != 0) { 151 return (1); 152 } 153 } 154 155 (void) strlcpy(a_path, a_str, sizeof (a_path)); 156 slen = strlen(a_path); 157 158 /* 159 * This for loop traverses Path backwards, incrementally removing the 160 * basename of Path and looking for the resultant directory in the 161 * mnttab. Once found, it returns the rw status of that file system. 162 */ 163 for (i = slen; i > 0; i--) { 164 if ((a_path[i] == '/') || (a_path[i] == '\0')) { 165 a_path[i] = '\0'; 166 result = findPathRWStatus(a_path); 167 if (result != -1) { 168 return (result); 169 } 170 } 171 } 172 173 return (1); 174 } 175 176 /* 177 * Name : z_destroyMountTable 178 * Description : Clear the entries in the mount table 179 * Arguments : void 180 * Returns : void 181 */ 182 void 183 z_destroyMountTable(void) 184 { 185 int i; 186 187 if (!createdFlag) { 188 return; 189 } 190 191 if (mountTable == NULL) { 192 return; 193 } 194 195 for (i = 0; i < mountTableSize; i++) { 196 free(mountTable[i].mnt_mountp); 197 free(mountTable[i].mnt_fstype); 198 free(mountTable[i].mnt_special); 199 free(mountTable[i].mnt_mntopts); 200 assert(mountTable[i].mnt_time == NULL); 201 } 202 203 free(mountTable); 204 mountTable = NULL; 205 mountTableSize = 0; 206 createdFlag = B_FALSE; 207 } 208 209 /* 210 * Name : z_resolve_lofs 211 * Description : Loop over potential loopback mounts and symlinks in a 212 * given path and resolve them all down to an absolute path. 213 * Arguments : char * - path to resolve. path is in writable storage. 214 * size_t - length of path storage. 215 * Returns : void 216 */ 217 void 218 z_resolve_lofs(char *path, size_t pathlen) 219 { 220 int len, arlen, i; 221 const char *altroot; 222 char tmppath[MAXPATHLEN]; 223 boolean_t outside_altroot; 224 225 if ((len = resolvepath(path, tmppath, sizeof (tmppath))) == -1) 226 return; 227 228 tmppath[len] = '\0'; 229 (void) strlcpy(path, tmppath, pathlen); 230 231 if (z_createMountTable() == -1) 232 return; 233 234 altroot = zonecfg_get_root(); 235 arlen = strlen(altroot); 236 outside_altroot = B_FALSE; 237 for (;;) { 238 struct mnttab *mnp; 239 240 /* Search in reverse order to find longest match */ 241 for (i = mountTableSize; i > 0; i--) { 242 mnp = &mountTable[i - 1]; 243 if (mnp->mnt_fstype == NULL || 244 mnp->mnt_mountp == NULL || 245 mnp->mnt_special == NULL) 246 continue; 247 len = strlen(mnp->mnt_mountp); 248 if (strncmp(mnp->mnt_mountp, path, len) == 0 && 249 (path[len] == '/' || path[len] == '\0')) 250 break; 251 } 252 if (i <= 0) 253 break; 254 255 /* If it's not a lofs then we're done */ 256 if (strcmp(mnp->mnt_fstype, MNTTYPE_LOFS) != 0) 257 break; 258 259 if (outside_altroot) { 260 char *cp; 261 int olen = sizeof (MNTOPT_RO) - 1; 262 263 /* 264 * If we run into a read-only mount outside of the 265 * alternate root environment, then the user doesn't 266 * want this path to be made read-write. 267 */ 268 if (mnp->mnt_mntopts != NULL && 269 (cp = strstr(mnp->mnt_mntopts, MNTOPT_RO)) != 270 NULL && 271 (cp == mnp->mnt_mntopts || cp[-1] == ',') && 272 (cp[olen] == '\0' || cp[olen] == ',')) { 273 break; 274 } 275 } else if (arlen > 0 && 276 (strncmp(mnp->mnt_special, altroot, arlen) != 0 || 277 (mnp->mnt_special[arlen] != '\0' && 278 mnp->mnt_special[arlen] != '/'))) { 279 outside_altroot = B_TRUE; 280 } 281 /* use temporary buffer because new path might be longer */ 282 (void) snprintf(tmppath, sizeof (tmppath), "%s%s", 283 mnp->mnt_special, path + len); 284 if ((len = resolvepath(tmppath, path, pathlen)) == -1) 285 break; 286 path[len] = '\0'; 287 } 288 } 289