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 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25
26 /*
27 * This module contains functions used for reading and writing the index file.
28 * setzoneent() opens the file. getzoneent() parses the file, doing the usual
29 * skipping of comment lines, etc., and using gettok() to deal with the ":"
30 * delimiters. endzoneent() closes the file. putzoneent() updates the file,
31 * adding, deleting or modifying lines, locking and unlocking appropriately.
32 */
33
34 #include <stdlib.h>
35 #include <string.h>
36 #include <errno.h>
37 #include <libzonecfg.h>
38 #include <unistd.h>
39 #include <fcntl.h>
40 #include <sys/stat.h>
41 #include <assert.h>
42 #include <uuid/uuid.h>
153 }
154
155 p = gettok(&cp);
156 if (strlen(p) >= MAXPATHLEN) {
157 /* very long paths are not allowed */
158 continue;
159 }
160 (void) strlcpy(ze->zone_path, p, MAXPATHLEN);
161
162 p = gettok(&cp);
163 if (uuid_parse(p, ze->zone_uuid) == -1)
164 uuid_clear(ze->zone_uuid);
165
166 break;
167 }
168
169 return (ze);
170 }
171
172 static boolean_t
173 get_index_path(char *path)
174 {
175 return (snprintf(path, MAXPATHLEN, "%s%s", zonecfg_root,
176 ZONE_INDEX_FILE) < MAXPATHLEN);
177 }
178
179 FILE *
180 setzoneent(void)
181 {
182 char path[MAXPATHLEN];
183
184 if (!get_index_path(path)) {
185 errno = EINVAL;
186 return (NULL);
187 }
188 return (fopen(path, "r"));
189 }
190
191 void
192 endzoneent(FILE *cookie)
193 {
194 if (cookie != NULL)
195 (void) fclose(cookie);
196 }
197
198 static int
199 lock_index_file(void)
200 {
201 int lock_fd;
202 struct flock lock;
203 char path[MAXPATHLEN];
204
205 if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
206 ZONE_INDEX_LOCK_DIR) >= sizeof (path))
207 return (-1);
208 if ((mkdir(path, S_IRWXU) == -1) && errno != EEXIST)
209 return (-1);
210 if (strlcat(path, ZONE_INDEX_LOCK_FILE, sizeof (path)) >=
211 sizeof (path))
212 return (-1);
213 lock_fd = open(path, O_CREAT|O_RDWR, 0644);
214 if (lock_fd == -1)
215 return (-1);
216
217 lock.l_type = F_WRLCK;
218 lock.l_whence = SEEK_SET;
219 lock.l_start = 0;
220 lock.l_len = 0;
221
222 if (fcntl(lock_fd, F_SETLKW, &lock) == -1) {
223 (void) close(lock_fd);
224 return (-1);
225 }
226
252 * If ze->zone_state is < 0, it means leave the
253 * existing value unchanged; this is only meaningful when operation ==
254 * PZE_MODIFY (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
255 *
256 * A zero-length ze->zone_path means leave the existing value
257 * unchanged; this is only meaningful when operation == PZE_MODIFY
258 * (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
259 *
260 * A zero-length ze->zone_newname means leave the existing name
261 * unchanged; otherwise the zone is renamed to zone_newname. This is
262 * only meaningful when operation == PZE_MODIFY.
263 *
264 * Locking and unlocking is done via the functions above.
265 * The file itself is not modified in place; rather, a copy is made which
266 * is modified, then the copy is atomically renamed back to the main file.
267 */
268 int
269 putzoneent(struct zoneent *ze, zoneent_op_t operation)
270 {
271 FILE *index_file, *tmp_file;
272 char *tmp_file_name, buf[MAX_INDEX_LEN];
273 int tmp_file_desc, lock_fd, err;
274 boolean_t exist, need_quotes;
275 char *cp;
276 char path[MAXPATHLEN];
277 char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
278 size_t tlen, namelen;
279 const char *zone_name, *zone_state, *zone_path, *zone_uuid;
280
281 assert(ze != NULL);
282
283 /*
284 * Don't allow modification of Global Zone entry
285 * in index file
286 */
287 if ((operation == PZE_MODIFY) &&
288 (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0)) {
289 return (Z_OK);
290 }
291
292 if (operation == PZE_ADD &&
293 (ze->zone_state < 0 || strlen(ze->zone_path) == 0))
294 return (Z_INVAL);
295
296 if (operation != PZE_MODIFY && strlen(ze->zone_newname) != 0)
297 return (Z_INVAL);
298
299 if ((lock_fd = lock_index_file()) == -1)
300 return (Z_LOCKING_FILE);
301
302 /* using sizeof gives us room for the terminating NUL byte as well */
303 tlen = sizeof (_PATH_TMPFILE) + strlen(zonecfg_root);
304 tmp_file_name = malloc(tlen);
305 if (tmp_file_name == NULL) {
306 (void) unlock_index_file(lock_fd);
307 return (Z_NOMEM);
308 }
309 (void) snprintf(tmp_file_name, tlen, "%s%s", zonecfg_root,
310 _PATH_TMPFILE);
311
312 tmp_file_desc = mkstemp(tmp_file_name);
313 if (tmp_file_desc == -1) {
314 (void) unlink(tmp_file_name);
315 free(tmp_file_name);
316 (void) unlock_index_file(lock_fd);
317 return (Z_TEMP_FILE);
318 }
319 (void) fchmod(tmp_file_desc, ZONE_INDEX_MODE);
320 (void) fchown(tmp_file_desc, ZONE_INDEX_UID, ZONE_INDEX_GID);
321 if ((tmp_file = fdopen(tmp_file_desc, "w")) == NULL) {
322 (void) close(tmp_file_desc);
323 err = Z_MISC_FS;
324 goto error;
325 }
326 if (!get_index_path(path)) {
327 err = Z_MISC_FS;
328 goto error;
329 }
330 if ((index_file = fopen(path, "r")) == NULL) {
331 err = Z_MISC_FS;
332 goto error;
333 }
334
335 exist = B_FALSE;
336 zone_name = ze->zone_name;
337 namelen = strlen(zone_name);
338 for (;;) {
339 if (fgets(buf, sizeof (buf), index_file) == NULL) {
340 if (operation == PZE_ADD && !exist) {
341 zone_state = zone_state_str(ze->zone_state);
342 zone_path = ze->zone_path;
343 zone_uuid = "";
344 goto add_entry;
345 }
346 /*
447 * with double-quotes themselves: they are not allowed in zone
448 * names, and do not occur in zone states, and in theory should
449 * never occur in a zonepath since zonecfg does not support a
450 * method for escaping them.
451 */
452 need_quotes = (strchr(zone_path, ':') != NULL);
453 (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s\n", zone_name,
454 zone_state, need_quotes ? "\"" : "", zone_path,
455 need_quotes ? "\"" : "", zone_uuid);
456 exist = B_TRUE;
457 }
458
459 (void) fclose(index_file);
460 index_file = NULL;
461 if (fclose(tmp_file) != 0) {
462 tmp_file = NULL;
463 err = Z_MISC_FS;
464 goto error;
465 }
466 tmp_file = NULL;
467 if (rename(tmp_file_name, path) == -1) {
468 err = errno == EACCES ? Z_ACCES : Z_MISC_FS;
469 goto error;
470 }
471 free(tmp_file_name);
472 if (unlock_index_file(lock_fd) != Z_OK)
473 return (Z_UNLOCKING_FILE);
474 return (Z_OK);
475
476 error:
477 if (index_file != NULL)
478 (void) fclose(index_file);
479 if (tmp_file != NULL)
480 (void) fclose(tmp_file);
481 (void) unlink(tmp_file_name);
482 free(tmp_file_name);
483 (void) unlock_index_file(lock_fd);
484 return (err);
485 }
|
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 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright 2015 Joyent, Inc.
24 */
25
26
27 /*
28 * This module contains functions used for reading and writing the index file.
29 * setzoneent() opens the file. getzoneent() parses the file, doing the usual
30 * skipping of comment lines, etc., and using gettok() to deal with the ":"
31 * delimiters. endzoneent() closes the file. putzoneent() updates the file,
32 * adding, deleting or modifying lines, locking and unlocking appropriately.
33 */
34
35 #include <stdlib.h>
36 #include <string.h>
37 #include <errno.h>
38 #include <libzonecfg.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <sys/stat.h>
42 #include <assert.h>
43 #include <uuid/uuid.h>
154 }
155
156 p = gettok(&cp);
157 if (strlen(p) >= MAXPATHLEN) {
158 /* very long paths are not allowed */
159 continue;
160 }
161 (void) strlcpy(ze->zone_path, p, MAXPATHLEN);
162
163 p = gettok(&cp);
164 if (uuid_parse(p, ze->zone_uuid) == -1)
165 uuid_clear(ze->zone_uuid);
166
167 break;
168 }
169
170 return (ze);
171 }
172
173 static boolean_t
174 path_common(char *path, size_t path_size, const char *stem)
175 {
176 const char *native_root = zone_get_nroot();
177
178 if (native_root == NULL || zonecfg_in_alt_root()) {
179 /*
180 * Do not prepend the native system root (e.g. "/native") if an
181 * alternative configuration root has been selected.
182 */
183 native_root = "";
184 }
185
186 return (snprintf(path, path_size, "%s%s%s", native_root, zonecfg_root,
187 stem) < path_size);
188 }
189
190 static boolean_t
191 get_index_path(char *path, size_t path_size)
192 {
193 return (path_common(path, path_size, ZONE_INDEX_FILE));
194 }
195
196 static boolean_t
197 get_temp_path(char *path, size_t path_size)
198 {
199 return (path_common(path, path_size, _PATH_TMPFILE));
200 }
201
202 FILE *
203 setzoneent(void)
204 {
205 char path[MAXPATHLEN];
206
207 if (!get_index_path(path, sizeof (path))) {
208 errno = EINVAL;
209 return (NULL);
210 }
211 return (fopen(path, "r"));
212 }
213
214 void
215 endzoneent(FILE *cookie)
216 {
217 if (cookie != NULL)
218 (void) fclose(cookie);
219 }
220
221 static int
222 lock_index_file(void)
223 {
224 int lock_fd;
225 struct flock lock;
226 char path[MAXPATHLEN];
227
228 if (!path_common(path, sizeof (path), ZONE_INDEX_LOCK_DIR))
229 return (-1);
230 if ((mkdir(path, S_IRWXU) == -1) && errno != EEXIST)
231 return (-1);
232 if (strlcat(path, ZONE_INDEX_LOCK_FILE, sizeof (path)) >=
233 sizeof (path))
234 return (-1);
235 lock_fd = open(path, O_CREAT|O_RDWR, 0644);
236 if (lock_fd == -1)
237 return (-1);
238
239 lock.l_type = F_WRLCK;
240 lock.l_whence = SEEK_SET;
241 lock.l_start = 0;
242 lock.l_len = 0;
243
244 if (fcntl(lock_fd, F_SETLKW, &lock) == -1) {
245 (void) close(lock_fd);
246 return (-1);
247 }
248
274 * If ze->zone_state is < 0, it means leave the
275 * existing value unchanged; this is only meaningful when operation ==
276 * PZE_MODIFY (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
277 *
278 * A zero-length ze->zone_path means leave the existing value
279 * unchanged; this is only meaningful when operation == PZE_MODIFY
280 * (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
281 *
282 * A zero-length ze->zone_newname means leave the existing name
283 * unchanged; otherwise the zone is renamed to zone_newname. This is
284 * only meaningful when operation == PZE_MODIFY.
285 *
286 * Locking and unlocking is done via the functions above.
287 * The file itself is not modified in place; rather, a copy is made which
288 * is modified, then the copy is atomically renamed back to the main file.
289 */
290 int
291 putzoneent(struct zoneent *ze, zoneent_op_t operation)
292 {
293 FILE *index_file, *tmp_file;
294 char buf[MAX_INDEX_LEN];
295 int tmp_file_desc, lock_fd, err;
296 boolean_t exist, need_quotes;
297 char *cp;
298 char tmp_path[MAXPATHLEN];
299 char path[MAXPATHLEN];
300 char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
301 size_t namelen;
302 const char *zone_name, *zone_state, *zone_path, *zone_uuid;
303
304 assert(ze != NULL);
305
306 /*
307 * Don't allow modification of Global Zone entry
308 * in index file
309 */
310 if ((operation == PZE_MODIFY) &&
311 (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0)) {
312 return (Z_OK);
313 }
314
315 if (operation == PZE_ADD &&
316 (ze->zone_state < 0 || strlen(ze->zone_path) == 0))
317 return (Z_INVAL);
318
319 if (operation != PZE_MODIFY && strlen(ze->zone_newname) != 0)
320 return (Z_INVAL);
321
322 if ((lock_fd = lock_index_file()) == -1)
323 return (Z_LOCKING_FILE);
324
325 if (!get_temp_path(tmp_path, sizeof (tmp_path))) {
326 (void) unlock_index_file(lock_fd);
327 return (Z_NOMEM);
328 }
329
330 tmp_file_desc = mkstemp(tmp_path);
331 if (tmp_file_desc == -1) {
332 (void) unlink(tmp_path);
333 (void) unlock_index_file(lock_fd);
334 return (Z_TEMP_FILE);
335 }
336 (void) fchmod(tmp_file_desc, ZONE_INDEX_MODE);
337 (void) fchown(tmp_file_desc, ZONE_INDEX_UID, ZONE_INDEX_GID);
338 if ((tmp_file = fdopen(tmp_file_desc, "w")) == NULL) {
339 (void) close(tmp_file_desc);
340 err = Z_MISC_FS;
341 goto error;
342 }
343 if (!get_index_path(path, sizeof (path))) {
344 err = Z_MISC_FS;
345 goto error;
346 }
347 if ((index_file = fopen(path, "r")) == NULL) {
348 err = Z_MISC_FS;
349 goto error;
350 }
351
352 exist = B_FALSE;
353 zone_name = ze->zone_name;
354 namelen = strlen(zone_name);
355 for (;;) {
356 if (fgets(buf, sizeof (buf), index_file) == NULL) {
357 if (operation == PZE_ADD && !exist) {
358 zone_state = zone_state_str(ze->zone_state);
359 zone_path = ze->zone_path;
360 zone_uuid = "";
361 goto add_entry;
362 }
363 /*
464 * with double-quotes themselves: they are not allowed in zone
465 * names, and do not occur in zone states, and in theory should
466 * never occur in a zonepath since zonecfg does not support a
467 * method for escaping them.
468 */
469 need_quotes = (strchr(zone_path, ':') != NULL);
470 (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s\n", zone_name,
471 zone_state, need_quotes ? "\"" : "", zone_path,
472 need_quotes ? "\"" : "", zone_uuid);
473 exist = B_TRUE;
474 }
475
476 (void) fclose(index_file);
477 index_file = NULL;
478 if (fclose(tmp_file) != 0) {
479 tmp_file = NULL;
480 err = Z_MISC_FS;
481 goto error;
482 }
483 tmp_file = NULL;
484 if (rename(tmp_path, path) == -1) {
485 err = errno == EACCES ? Z_ACCES : Z_MISC_FS;
486 goto error;
487 }
488 if (unlock_index_file(lock_fd) != Z_OK)
489 return (Z_UNLOCKING_FILE);
490 return (Z_OK);
491
492 error:
493 if (index_file != NULL)
494 (void) fclose(index_file);
495 if (tmp_file != NULL)
496 (void) fclose(tmp_file);
497 (void) unlink(tmp_path);
498 (void) unlock_index_file(lock_fd);
499 return (err);
500 }
|