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