Print this page
OS-4361 libzonecfg should be aware of branded zone native root
Reviewed by: Robert Mustacchi <rm@joyent.com>
| Split |
Close |
| Expand all |
| Collapse all |
--- old/usr/src/lib/libzonecfg/common/getzoneent.c
+++ new/usr/src/lib/libzonecfg/common/getzoneent.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
|
↓ open down ↓ |
12 lines elided |
↑ open up ↑ |
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
23 + * Copyright 2015 Joyent, Inc.
23 24 */
24 25
25 26
26 27 /*
27 28 * This module contains functions used for reading and writing the index file.
28 29 * setzoneent() opens the file. getzoneent() parses the file, doing the usual
29 30 * skipping of comment lines, etc., and using gettok() to deal with the ":"
30 31 * delimiters. endzoneent() closes the file. putzoneent() updates the file,
31 32 * adding, deleting or modifying lines, locking and unlocking appropriately.
32 33 */
33 34
34 35 #include <stdlib.h>
35 36 #include <string.h>
36 37 #include <errno.h>
37 38 #include <libzonecfg.h>
38 39 #include <unistd.h>
39 40 #include <fcntl.h>
40 41 #include <sys/stat.h>
41 42 #include <assert.h>
42 43 #include <uuid/uuid.h>
43 44 #include "zonecfg_impl.h"
44 45
45 46
46 47 #define _PATH_TMPFILE ZONE_CONFIG_ROOT "/zonecfg.XXXXXX"
47 48
48 49 /*
49 50 * gettok() is a helper function for parsing the index file, used to split
50 51 * the lines by their ":" delimiters. Note that an entry may contain a ":"
51 52 * inside double quotes; this should only affect the zonepath, as zone names
52 53 * do not allow such characters, and zone states do not have them either.
53 54 * Same with double-quotes themselves: they are not allowed in zone names,
54 55 * and do not occur in zone states, and in theory should never occur in a
55 56 * zonepath since zonecfg does not support a method for escaping them.
56 57 *
57 58 * It never returns NULL.
58 59 */
59 60
60 61 static char *
61 62 gettok(char **cpp)
62 63 {
63 64 char *cp = *cpp, *retv;
64 65 boolean_t quoted = B_FALSE;
65 66
66 67 if (cp == NULL)
67 68 return ("");
68 69 if (*cp == '"') {
69 70 quoted = B_TRUE;
70 71 cp++;
71 72 }
72 73 retv = cp;
73 74 if (quoted) {
74 75 while (*cp != '\0' && *cp != '"')
75 76 cp++;
76 77 if (*cp == '"')
77 78 *cp++ = '\0';
78 79 }
79 80 while (*cp != '\0' && *cp != ':')
80 81 cp++;
81 82 if (*cp == '\0') {
82 83 *cpp = NULL;
83 84 } else {
84 85 *cp++ = '\0';
85 86 *cpp = cp;
86 87 }
87 88 return (retv);
88 89 }
89 90
90 91 char *
91 92 getzoneent(FILE *cookie)
92 93 {
93 94 struct zoneent *ze;
94 95 char *name;
95 96
96 97 if ((ze = getzoneent_private(cookie)) == NULL)
97 98 return (NULL);
98 99 name = strdup(ze->zone_name);
99 100 free(ze);
100 101 return (name);
101 102 }
102 103
103 104 struct zoneent *
104 105 getzoneent_private(FILE *cookie)
105 106 {
106 107 char *cp, buf[MAX_INDEX_LEN], *p;
107 108 struct zoneent *ze;
108 109
109 110 if (cookie == NULL)
110 111 return (NULL);
111 112
112 113 if ((ze = malloc(sizeof (struct zoneent))) == NULL)
113 114 return (NULL);
114 115
115 116 for (;;) {
116 117 if (fgets(buf, sizeof (buf), cookie) == NULL) {
117 118 free(ze);
118 119 return (NULL);
119 120 }
120 121 if ((cp = strpbrk(buf, "\r\n")) == NULL) {
121 122 /* this represents a line that's too long */
122 123 continue;
123 124 }
124 125 *cp = '\0';
125 126 cp = buf;
126 127 if (*cp == '#') {
127 128 /* skip comment lines */
128 129 continue;
129 130 }
130 131 p = gettok(&cp);
131 132 if (*p == '\0' || strlen(p) >= ZONENAME_MAX) {
132 133 /*
133 134 * empty or very long zone names are not allowed
134 135 */
135 136 continue;
136 137 }
137 138 (void) strlcpy(ze->zone_name, p, ZONENAME_MAX);
138 139
139 140 p = gettok(&cp);
140 141 if (*p == '\0') {
141 142 /* state field should not be empty */
142 143 continue;
143 144 }
144 145 errno = 0;
145 146 if (strcmp(p, ZONE_STATE_STR_CONFIGURED) == 0) {
146 147 ze->zone_state = ZONE_STATE_CONFIGURED;
147 148 } else if (strcmp(p, ZONE_STATE_STR_INCOMPLETE) == 0) {
148 149 ze->zone_state = ZONE_STATE_INCOMPLETE;
149 150 } else if (strcmp(p, ZONE_STATE_STR_INSTALLED) == 0) {
150 151 ze->zone_state = ZONE_STATE_INSTALLED;
151 152 } else {
152 153 continue;
153 154 }
154 155
155 156 p = gettok(&cp);
156 157 if (strlen(p) >= MAXPATHLEN) {
157 158 /* very long paths are not allowed */
158 159 continue;
159 160 }
160 161 (void) strlcpy(ze->zone_path, p, MAXPATHLEN);
161 162
162 163 p = gettok(&cp);
|
↓ open down ↓ |
130 lines elided |
↑ open up ↑ |
163 164 if (uuid_parse(p, ze->zone_uuid) == -1)
164 165 uuid_clear(ze->zone_uuid);
165 166
166 167 break;
167 168 }
168 169
169 170 return (ze);
170 171 }
171 172
172 173 static boolean_t
173 -get_index_path(char *path)
174 +path_common(char *path, size_t path_size, const char *stem)
174 175 {
175 - return (snprintf(path, MAXPATHLEN, "%s%s", zonecfg_root,
176 - ZONE_INDEX_FILE) < MAXPATHLEN);
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);
177 188 }
178 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 +
179 202 FILE *
180 203 setzoneent(void)
181 204 {
182 205 char path[MAXPATHLEN];
183 206
184 - if (!get_index_path(path)) {
207 + if (!get_index_path(path, sizeof (path))) {
185 208 errno = EINVAL;
186 209 return (NULL);
187 210 }
188 211 return (fopen(path, "r"));
189 212 }
190 213
191 214 void
192 215 endzoneent(FILE *cookie)
193 216 {
194 217 if (cookie != NULL)
195 218 (void) fclose(cookie);
196 219 }
197 220
198 221 static int
199 222 lock_index_file(void)
200 223 {
201 224 int lock_fd;
202 225 struct flock lock;
203 226 char path[MAXPATHLEN];
204 227
205 - if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
206 - ZONE_INDEX_LOCK_DIR) >= sizeof (path))
228 + if (!path_common(path, sizeof (path), ZONE_INDEX_LOCK_DIR))
207 229 return (-1);
208 230 if ((mkdir(path, S_IRWXU) == -1) && errno != EEXIST)
209 231 return (-1);
210 232 if (strlcat(path, ZONE_INDEX_LOCK_FILE, sizeof (path)) >=
211 233 sizeof (path))
212 234 return (-1);
213 235 lock_fd = open(path, O_CREAT|O_RDWR, 0644);
214 236 if (lock_fd == -1)
215 237 return (-1);
216 238
217 239 lock.l_type = F_WRLCK;
218 240 lock.l_whence = SEEK_SET;
219 241 lock.l_start = 0;
220 242 lock.l_len = 0;
221 243
222 244 if (fcntl(lock_fd, F_SETLKW, &lock) == -1) {
223 245 (void) close(lock_fd);
224 246 return (-1);
225 247 }
226 248
227 249 return (lock_fd);
228 250 }
229 251
230 252 static int
231 253 unlock_index_file(int lock_fd)
232 254 {
233 255 struct flock lock;
234 256
235 257 lock.l_type = F_UNLCK;
236 258 lock.l_whence = SEEK_SET;
237 259 lock.l_start = 0;
238 260 lock.l_len = 0;
239 261
240 262 if (fcntl(lock_fd, F_SETLK, &lock) == -1)
241 263 return (Z_UNLOCKING_FILE);
242 264
243 265 if (close(lock_fd) == -1)
244 266 return (Z_UNLOCKING_FILE);
245 267
246 268 return (Z_OK);
247 269 }
248 270
249 271 /*
250 272 * This function adds or removes a zone name et al. to the index file.
251 273 *
252 274 * If ze->zone_state is < 0, it means leave the
253 275 * existing value unchanged; this is only meaningful when operation ==
254 276 * PZE_MODIFY (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
255 277 *
256 278 * A zero-length ze->zone_path means leave the existing value
257 279 * unchanged; this is only meaningful when operation == PZE_MODIFY
258 280 * (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
259 281 *
260 282 * A zero-length ze->zone_newname means leave the existing name
261 283 * unchanged; otherwise the zone is renamed to zone_newname. This is
|
↓ open down ↓ |
45 lines elided |
↑ open up ↑ |
262 284 * only meaningful when operation == PZE_MODIFY.
263 285 *
264 286 * Locking and unlocking is done via the functions above.
265 287 * The file itself is not modified in place; rather, a copy is made which
266 288 * is modified, then the copy is atomically renamed back to the main file.
267 289 */
268 290 int
269 291 putzoneent(struct zoneent *ze, zoneent_op_t operation)
270 292 {
271 293 FILE *index_file, *tmp_file;
272 - char *tmp_file_name, buf[MAX_INDEX_LEN];
294 + char buf[MAX_INDEX_LEN];
273 295 int tmp_file_desc, lock_fd, err;
274 296 boolean_t exist, need_quotes;
275 297 char *cp;
298 + char tmp_path[MAXPATHLEN];
276 299 char path[MAXPATHLEN];
277 300 char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
278 - size_t tlen, namelen;
301 + size_t namelen;
279 302 const char *zone_name, *zone_state, *zone_path, *zone_uuid;
280 303
281 304 assert(ze != NULL);
282 305
283 306 /*
284 307 * Don't allow modification of Global Zone entry
285 308 * in index file
286 309 */
287 310 if ((operation == PZE_MODIFY) &&
288 311 (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0)) {
289 312 return (Z_OK);
290 313 }
291 314
|
↓ open down ↓ |
3 lines elided |
↑ open up ↑ |
292 315 if (operation == PZE_ADD &&
293 316 (ze->zone_state < 0 || strlen(ze->zone_path) == 0))
294 317 return (Z_INVAL);
295 318
296 319 if (operation != PZE_MODIFY && strlen(ze->zone_newname) != 0)
297 320 return (Z_INVAL);
298 321
299 322 if ((lock_fd = lock_index_file()) == -1)
300 323 return (Z_LOCKING_FILE);
301 324
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) {
325 + if (!get_temp_path(tmp_path, sizeof (tmp_path))) {
306 326 (void) unlock_index_file(lock_fd);
307 327 return (Z_NOMEM);
308 328 }
309 - (void) snprintf(tmp_file_name, tlen, "%s%s", zonecfg_root,
310 - _PATH_TMPFILE);
311 329
312 - tmp_file_desc = mkstemp(tmp_file_name);
330 + tmp_file_desc = mkstemp(tmp_path);
313 331 if (tmp_file_desc == -1) {
314 - (void) unlink(tmp_file_name);
315 - free(tmp_file_name);
332 + (void) unlink(tmp_path);
316 333 (void) unlock_index_file(lock_fd);
317 334 return (Z_TEMP_FILE);
318 335 }
319 336 (void) fchmod(tmp_file_desc, ZONE_INDEX_MODE);
320 337 (void) fchown(tmp_file_desc, ZONE_INDEX_UID, ZONE_INDEX_GID);
321 338 if ((tmp_file = fdopen(tmp_file_desc, "w")) == NULL) {
322 339 (void) close(tmp_file_desc);
323 340 err = Z_MISC_FS;
324 341 goto error;
325 342 }
326 - if (!get_index_path(path)) {
343 + if (!get_index_path(path, sizeof (path))) {
327 344 err = Z_MISC_FS;
328 345 goto error;
329 346 }
330 347 if ((index_file = fopen(path, "r")) == NULL) {
331 348 err = Z_MISC_FS;
332 349 goto error;
333 350 }
334 351
335 352 exist = B_FALSE;
336 353 zone_name = ze->zone_name;
337 354 namelen = strlen(zone_name);
338 355 for (;;) {
339 356 if (fgets(buf, sizeof (buf), index_file) == NULL) {
340 357 if (operation == PZE_ADD && !exist) {
341 358 zone_state = zone_state_str(ze->zone_state);
342 359 zone_path = ze->zone_path;
343 360 zone_uuid = "";
344 361 goto add_entry;
345 362 }
346 363 /*
347 364 * It's not considered an error to delete something
348 365 * that doesn't exist, but we can't modify a missing
349 366 * record.
350 367 */
351 368 if (operation == PZE_MODIFY && !exist) {
352 369 err = Z_UPDATING_INDEX;
353 370 goto error;
354 371 }
355 372 break;
356 373 }
357 374
358 375 if (buf[0] == '#') {
359 376 /* skip and preserve comment lines */
360 377 (void) fputs(buf, tmp_file);
361 378 continue;
362 379 }
363 380
364 381 if (strncmp(buf, zone_name, namelen) != 0 ||
365 382 buf[namelen] != ':') {
366 383 /* skip and preserve non-target lines */
367 384 (void) fputs(buf, tmp_file);
368 385 continue;
369 386 }
370 387
371 388 if ((cp = strpbrk(buf, "\r\n")) == NULL) {
372 389 /* this represents a line that's too long; delete */
373 390 continue;
374 391 }
375 392 *cp = '\0';
376 393
377 394 /*
378 395 * Skip over the zone name. Because we've already matched the
379 396 * target zone (above), we know for certain here that the zone
380 397 * name is present and correctly formed. No need to check.
381 398 */
382 399 cp = strchr(buf, ':') + 1;
383 400
384 401 zone_state = gettok(&cp);
385 402 if (*zone_state == '\0') {
386 403 /* state field should not be empty */
387 404 err = Z_UPDATING_INDEX;
388 405 goto error;
389 406 }
390 407 zone_path = gettok(&cp);
391 408 zone_uuid = gettok(&cp);
392 409
393 410 switch (operation) {
394 411 case PZE_ADD:
395 412 /* can't add same zone */
396 413 err = Z_UPDATING_INDEX;
397 414 goto error;
398 415
399 416 case PZE_MODIFY:
400 417 /*
401 418 * If the caller specified a new state for the zone,
402 419 * then use that. Otherwise, use the current state.
403 420 */
404 421 if (ze->zone_state >= 0) {
405 422 zone_state = zone_state_str(ze->zone_state);
406 423
407 424 /*
408 425 * If the caller is uninstalling this zone,
409 426 * then wipe out the uuid. The zone's contents
410 427 * are no longer known.
411 428 */
412 429 if (ze->zone_state < ZONE_STATE_INSTALLED)
413 430 zone_uuid = "";
414 431 }
415 432
416 433 /* If a new name is supplied, use it. */
417 434 if (ze->zone_newname[0] != '\0')
418 435 zone_name = ze->zone_newname;
419 436
420 437 if (ze->zone_path[0] != '\0')
421 438 zone_path = ze->zone_path;
422 439 break;
423 440
424 441 case PZE_REMOVE:
425 442 default:
426 443 continue;
427 444 }
428 445
429 446 add_entry:
430 447 /*
431 448 * If the entry in the file is in greater than configured
432 449 * state, then we must have a UUID. Make sure that we do.
433 450 * (Note that the file entry is only tokenized, not fully
434 451 * parsed, so we need to do a string comparison here.)
435 452 */
436 453 if (strcmp(zone_state, ZONE_STATE_STR_CONFIGURED) != 0 &&
437 454 *zone_uuid == '\0') {
438 455 if (uuid_is_null(ze->zone_uuid))
439 456 uuid_generate(ze->zone_uuid);
440 457 uuid_unparse(ze->zone_uuid, uuidstr);
441 458 zone_uuid = uuidstr;
442 459 }
443 460 /*
444 461 * We need to quote a path that contains a ":"; this should
445 462 * only affect the zonepath, as zone names do not allow such
446 463 * characters, and zone states do not have them either. Same
447 464 * with double-quotes themselves: they are not allowed in zone
448 465 * names, and do not occur in zone states, and in theory should
449 466 * never occur in a zonepath since zonecfg does not support a
450 467 * method for escaping them.
451 468 */
452 469 need_quotes = (strchr(zone_path, ':') != NULL);
453 470 (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s\n", zone_name,
454 471 zone_state, need_quotes ? "\"" : "", zone_path,
455 472 need_quotes ? "\"" : "", zone_uuid);
456 473 exist = B_TRUE;
|
↓ open down ↓ |
120 lines elided |
↑ open up ↑ |
457 474 }
458 475
459 476 (void) fclose(index_file);
460 477 index_file = NULL;
461 478 if (fclose(tmp_file) != 0) {
462 479 tmp_file = NULL;
463 480 err = Z_MISC_FS;
464 481 goto error;
465 482 }
466 483 tmp_file = NULL;
467 - if (rename(tmp_file_name, path) == -1) {
484 + if (rename(tmp_path, path) == -1) {
468 485 err = errno == EACCES ? Z_ACCES : Z_MISC_FS;
469 486 goto error;
470 487 }
471 - free(tmp_file_name);
472 488 if (unlock_index_file(lock_fd) != Z_OK)
473 489 return (Z_UNLOCKING_FILE);
474 490 return (Z_OK);
475 491
476 492 error:
477 493 if (index_file != NULL)
478 494 (void) fclose(index_file);
479 495 if (tmp_file != NULL)
480 496 (void) fclose(tmp_file);
481 - (void) unlink(tmp_file_name);
482 - free(tmp_file_name);
497 + (void) unlink(tmp_path);
483 498 (void) unlock_index_file(lock_fd);
484 499 return (err);
485 500 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX