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
z_createMountTable(void)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
findPathRWStatus(const char * a_path)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
z_isPathWritable(const char * a_str)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
z_destroyMountTable(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
z_resolve_lofs(char * path,size_t pathlen)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