10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51422Scarlsonj * Common Development and Distribution License (the "License").
61422Scarlsonj * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12706SPhaniram.Krishnamurthy@Sun.COM * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate */
240Sstevel@tonic-gate
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * This module contains functions used for reading and writing the index file.
280Sstevel@tonic-gate * setzoneent() opens the file. getzoneent() parses the file, doing the usual
290Sstevel@tonic-gate * skipping of comment lines, etc., and using gettok() to deal with the ":"
300Sstevel@tonic-gate * delimiters. endzoneent() closes the file. putzoneent() updates the file,
310Sstevel@tonic-gate * adding, deleting or modifying lines, locking and unlocking appropriately.
320Sstevel@tonic-gate */
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include <stdlib.h>
350Sstevel@tonic-gate #include <string.h>
360Sstevel@tonic-gate #include <errno.h>
370Sstevel@tonic-gate #include <libzonecfg.h>
380Sstevel@tonic-gate #include <unistd.h>
390Sstevel@tonic-gate #include <fcntl.h>
400Sstevel@tonic-gate #include <sys/stat.h>
410Sstevel@tonic-gate #include <assert.h>
42766Scarlsonj #include <uuid/uuid.h>
430Sstevel@tonic-gate #include "zonecfg_impl.h"
440Sstevel@tonic-gate
450Sstevel@tonic-gate
460Sstevel@tonic-gate #define _PATH_TMPFILE ZONE_CONFIG_ROOT "/zonecfg.XXXXXX"
470Sstevel@tonic-gate
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate * gettok() is a helper function for parsing the index file, used to split
500Sstevel@tonic-gate * the lines by their ":" delimiters. Note that an entry may contain a ":"
510Sstevel@tonic-gate * inside double quotes; this should only affect the zonepath, as zone names
520Sstevel@tonic-gate * do not allow such characters, and zone states do not have them either.
530Sstevel@tonic-gate * Same with double-quotes themselves: they are not allowed in zone names,
540Sstevel@tonic-gate * and do not occur in zone states, and in theory should never occur in a
550Sstevel@tonic-gate * zonepath since zonecfg does not support a method for escaping them.
56766Scarlsonj *
57766Scarlsonj * It never returns NULL.
580Sstevel@tonic-gate */
590Sstevel@tonic-gate
600Sstevel@tonic-gate static char *
gettok(char ** cpp)610Sstevel@tonic-gate gettok(char **cpp)
620Sstevel@tonic-gate {
630Sstevel@tonic-gate char *cp = *cpp, *retv;
640Sstevel@tonic-gate boolean_t quoted = B_FALSE;
650Sstevel@tonic-gate
660Sstevel@tonic-gate if (cp == NULL)
670Sstevel@tonic-gate return ("");
680Sstevel@tonic-gate if (*cp == '"') {
690Sstevel@tonic-gate quoted = B_TRUE;
700Sstevel@tonic-gate cp++;
710Sstevel@tonic-gate }
720Sstevel@tonic-gate retv = cp;
730Sstevel@tonic-gate if (quoted) {
740Sstevel@tonic-gate while (*cp != '\0' && *cp != '"')
750Sstevel@tonic-gate cp++;
760Sstevel@tonic-gate if (*cp == '"')
770Sstevel@tonic-gate *cp++ = '\0';
780Sstevel@tonic-gate }
790Sstevel@tonic-gate while (*cp != '\0' && *cp != ':')
800Sstevel@tonic-gate cp++;
810Sstevel@tonic-gate if (*cp == '\0') {
820Sstevel@tonic-gate *cpp = NULL;
830Sstevel@tonic-gate } else {
840Sstevel@tonic-gate *cp++ = '\0';
850Sstevel@tonic-gate *cpp = cp;
860Sstevel@tonic-gate }
870Sstevel@tonic-gate return (retv);
880Sstevel@tonic-gate }
890Sstevel@tonic-gate
900Sstevel@tonic-gate char *
getzoneent(FILE * cookie)910Sstevel@tonic-gate getzoneent(FILE *cookie)
920Sstevel@tonic-gate {
930Sstevel@tonic-gate struct zoneent *ze;
940Sstevel@tonic-gate char *name;
950Sstevel@tonic-gate
960Sstevel@tonic-gate if ((ze = getzoneent_private(cookie)) == NULL)
970Sstevel@tonic-gate return (NULL);
980Sstevel@tonic-gate name = strdup(ze->zone_name);
990Sstevel@tonic-gate free(ze);
1000Sstevel@tonic-gate return (name);
1010Sstevel@tonic-gate }
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate struct zoneent *
getzoneent_private(FILE * cookie)1040Sstevel@tonic-gate getzoneent_private(FILE *cookie)
1050Sstevel@tonic-gate {
1060Sstevel@tonic-gate char *cp, buf[MAX_INDEX_LEN], *p;
1070Sstevel@tonic-gate struct zoneent *ze;
1080Sstevel@tonic-gate
1090Sstevel@tonic-gate if (cookie == NULL)
1100Sstevel@tonic-gate return (NULL);
1110Sstevel@tonic-gate
1120Sstevel@tonic-gate if ((ze = malloc(sizeof (struct zoneent))) == NULL)
1130Sstevel@tonic-gate return (NULL);
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate for (;;) {
1160Sstevel@tonic-gate if (fgets(buf, sizeof (buf), cookie) == NULL) {
1170Sstevel@tonic-gate free(ze);
1180Sstevel@tonic-gate return (NULL);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate if ((cp = strpbrk(buf, "\r\n")) == NULL) {
1210Sstevel@tonic-gate /* this represents a line that's too long */
1220Sstevel@tonic-gate continue;
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate *cp = '\0';
1250Sstevel@tonic-gate cp = buf;
1260Sstevel@tonic-gate if (*cp == '#') {
1270Sstevel@tonic-gate /* skip comment lines */
1280Sstevel@tonic-gate continue;
1290Sstevel@tonic-gate }
1300Sstevel@tonic-gate p = gettok(&cp);
131766Scarlsonj if (*p == '\0' || strlen(p) >= ZONENAME_MAX) {
1320Sstevel@tonic-gate /*
1330Sstevel@tonic-gate * empty or very long zone names are not allowed
1340Sstevel@tonic-gate */
1350Sstevel@tonic-gate continue;
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate (void) strlcpy(ze->zone_name, p, ZONENAME_MAX);
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate p = gettok(&cp);
140766Scarlsonj if (*p == '\0') {
1410Sstevel@tonic-gate /* state field should not be empty */
1420Sstevel@tonic-gate continue;
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate errno = 0;
1450Sstevel@tonic-gate if (strcmp(p, ZONE_STATE_STR_CONFIGURED) == 0) {
1460Sstevel@tonic-gate ze->zone_state = ZONE_STATE_CONFIGURED;
1470Sstevel@tonic-gate } else if (strcmp(p, ZONE_STATE_STR_INCOMPLETE) == 0) {
1480Sstevel@tonic-gate ze->zone_state = ZONE_STATE_INCOMPLETE;
1490Sstevel@tonic-gate } else if (strcmp(p, ZONE_STATE_STR_INSTALLED) == 0) {
1500Sstevel@tonic-gate ze->zone_state = ZONE_STATE_INSTALLED;
151766Scarlsonj } else {
1520Sstevel@tonic-gate continue;
153766Scarlsonj }
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate p = gettok(&cp);
156766Scarlsonj if (strlen(p) >= MAXPATHLEN) {
1570Sstevel@tonic-gate /* very long paths are not allowed */
1580Sstevel@tonic-gate continue;
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate (void) strlcpy(ze->zone_path, p, MAXPATHLEN);
1610Sstevel@tonic-gate
162766Scarlsonj p = gettok(&cp);
163766Scarlsonj if (uuid_parse(p, ze->zone_uuid) == -1)
164766Scarlsonj uuid_clear(ze->zone_uuid);
165766Scarlsonj
1660Sstevel@tonic-gate break;
1670Sstevel@tonic-gate }
1680Sstevel@tonic-gate
1690Sstevel@tonic-gate return (ze);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate
172766Scarlsonj static boolean_t
get_index_path(char * path)173766Scarlsonj get_index_path(char *path)
174766Scarlsonj {
175766Scarlsonj return (snprintf(path, MAXPATHLEN, "%s%s", zonecfg_root,
176766Scarlsonj ZONE_INDEX_FILE) < MAXPATHLEN);
177766Scarlsonj }
178766Scarlsonj
1790Sstevel@tonic-gate FILE *
setzoneent(void)1800Sstevel@tonic-gate setzoneent(void)
1810Sstevel@tonic-gate {
182766Scarlsonj char path[MAXPATHLEN];
183766Scarlsonj
184766Scarlsonj if (!get_index_path(path)) {
185766Scarlsonj errno = EINVAL;
186766Scarlsonj return (NULL);
187766Scarlsonj }
188766Scarlsonj return (fopen(path, "r"));
1890Sstevel@tonic-gate }
1900Sstevel@tonic-gate
1910Sstevel@tonic-gate void
endzoneent(FILE * cookie)1920Sstevel@tonic-gate endzoneent(FILE *cookie)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate if (cookie != NULL)
1950Sstevel@tonic-gate (void) fclose(cookie);
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate static int
lock_index_file(void)199766Scarlsonj lock_index_file(void)
2000Sstevel@tonic-gate {
201766Scarlsonj int lock_fd;
2020Sstevel@tonic-gate struct flock lock;
203766Scarlsonj char path[MAXPATHLEN];
2040Sstevel@tonic-gate
205766Scarlsonj if (snprintf(path, sizeof (path), "%s%s", zonecfg_root,
206766Scarlsonj ZONE_INDEX_LOCK_DIR) >= sizeof (path))
207766Scarlsonj return (-1);
208766Scarlsonj if ((mkdir(path, S_IRWXU) == -1) && errno != EEXIST)
209766Scarlsonj return (-1);
210766Scarlsonj if (strlcat(path, ZONE_INDEX_LOCK_FILE, sizeof (path)) >=
211766Scarlsonj sizeof (path))
212766Scarlsonj return (-1);
213766Scarlsonj lock_fd = open(path, O_CREAT|O_RDWR, 0644);
214766Scarlsonj if (lock_fd == -1)
215766Scarlsonj return (-1);
2160Sstevel@tonic-gate
2170Sstevel@tonic-gate lock.l_type = F_WRLCK;
2180Sstevel@tonic-gate lock.l_whence = SEEK_SET;
2190Sstevel@tonic-gate lock.l_start = 0;
2200Sstevel@tonic-gate lock.l_len = 0;
2210Sstevel@tonic-gate
222766Scarlsonj if (fcntl(lock_fd, F_SETLKW, &lock) == -1) {
223766Scarlsonj (void) close(lock_fd);
224766Scarlsonj return (-1);
225766Scarlsonj }
2260Sstevel@tonic-gate
227766Scarlsonj return (lock_fd);
2280Sstevel@tonic-gate }
2290Sstevel@tonic-gate
2300Sstevel@tonic-gate static int
unlock_index_file(int lock_fd)2310Sstevel@tonic-gate unlock_index_file(int lock_fd)
2320Sstevel@tonic-gate {
2330Sstevel@tonic-gate struct flock lock;
2340Sstevel@tonic-gate
2350Sstevel@tonic-gate lock.l_type = F_UNLCK;
2360Sstevel@tonic-gate lock.l_whence = SEEK_SET;
2370Sstevel@tonic-gate lock.l_start = 0;
2380Sstevel@tonic-gate lock.l_len = 0;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate if (fcntl(lock_fd, F_SETLK, &lock) == -1)
2410Sstevel@tonic-gate return (Z_UNLOCKING_FILE);
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate if (close(lock_fd) == -1)
2440Sstevel@tonic-gate return (Z_UNLOCKING_FILE);
2450Sstevel@tonic-gate
2460Sstevel@tonic-gate return (Z_OK);
2470Sstevel@tonic-gate }
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate /*
2500Sstevel@tonic-gate * This function adds or removes a zone name et al. to the index file.
2510Sstevel@tonic-gate *
2520Sstevel@tonic-gate * If ze->zone_state is < 0, it means leave the
2530Sstevel@tonic-gate * existing value unchanged; this is only meaningful when operation ==
254565Sdp * PZE_MODIFY (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
2550Sstevel@tonic-gate *
256565Sdp * A zero-length ze->zone_path means leave the existing value
2570Sstevel@tonic-gate * unchanged; this is only meaningful when operation == PZE_MODIFY
258565Sdp * (i.e., it's bad on PZE_ADD and a no-op on PZE_REMOVE).
259565Sdp *
260565Sdp * A zero-length ze->zone_newname means leave the existing name
261565Sdp * unchanged; otherwise the zone is renamed to zone_newname. This is
262565Sdp * only meaningful when operation == PZE_MODIFY.
2630Sstevel@tonic-gate *
2640Sstevel@tonic-gate * Locking and unlocking is done via the functions above.
2650Sstevel@tonic-gate * The file itself is not modified in place; rather, a copy is made which
2660Sstevel@tonic-gate * is modified, then the copy is atomically renamed back to the main file.
2670Sstevel@tonic-gate */
2680Sstevel@tonic-gate int
putzoneent(struct zoneent * ze,zoneent_op_t operation)2690Sstevel@tonic-gate putzoneent(struct zoneent *ze, zoneent_op_t operation)
2700Sstevel@tonic-gate {
2710Sstevel@tonic-gate FILE *index_file, *tmp_file;
2721422Scarlsonj char *tmp_file_name, buf[MAX_INDEX_LEN];
2730Sstevel@tonic-gate int tmp_file_desc, lock_fd, err;
2741422Scarlsonj boolean_t exist, need_quotes;
2751422Scarlsonj char *cp;
276766Scarlsonj char path[MAXPATHLEN];
2771388Sgz161490 char uuidstr[UUID_PRINTABLE_STRING_LENGTH];
2781422Scarlsonj size_t tlen, namelen;
2791422Scarlsonj const char *zone_name, *zone_state, *zone_path, *zone_uuid;
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate assert(ze != NULL);
282*12706SPhaniram.Krishnamurthy@Sun.COM
283*12706SPhaniram.Krishnamurthy@Sun.COM /*
284*12706SPhaniram.Krishnamurthy@Sun.COM * Don't allow modification of Global Zone entry
285*12706SPhaniram.Krishnamurthy@Sun.COM * in index file
286*12706SPhaniram.Krishnamurthy@Sun.COM */
287*12706SPhaniram.Krishnamurthy@Sun.COM if ((operation == PZE_MODIFY) &&
288*12706SPhaniram.Krishnamurthy@Sun.COM (strcmp(ze->zone_name, GLOBAL_ZONENAME) == 0)) {
289*12706SPhaniram.Krishnamurthy@Sun.COM return (Z_OK);
290*12706SPhaniram.Krishnamurthy@Sun.COM }
291*12706SPhaniram.Krishnamurthy@Sun.COM
2920Sstevel@tonic-gate if (operation == PZE_ADD &&
2930Sstevel@tonic-gate (ze->zone_state < 0 || strlen(ze->zone_path) == 0))
2940Sstevel@tonic-gate return (Z_INVAL);
295565Sdp
296565Sdp if (operation != PZE_MODIFY && strlen(ze->zone_newname) != 0)
297565Sdp return (Z_INVAL);
298565Sdp
299766Scarlsonj if ((lock_fd = lock_index_file()) == -1)
300766Scarlsonj return (Z_LOCKING_FILE);
301766Scarlsonj
302766Scarlsonj /* using sizeof gives us room for the terminating NUL byte as well */
303766Scarlsonj tlen = sizeof (_PATH_TMPFILE) + strlen(zonecfg_root);
304766Scarlsonj tmp_file_name = malloc(tlen);
3050Sstevel@tonic-gate if (tmp_file_name == NULL) {
3060Sstevel@tonic-gate (void) unlock_index_file(lock_fd);
3070Sstevel@tonic-gate return (Z_NOMEM);
3080Sstevel@tonic-gate }
309766Scarlsonj (void) snprintf(tmp_file_name, tlen, "%s%s", zonecfg_root,
310766Scarlsonj _PATH_TMPFILE);
311766Scarlsonj
3120Sstevel@tonic-gate tmp_file_desc = mkstemp(tmp_file_name);
3130Sstevel@tonic-gate if (tmp_file_desc == -1) {
3140Sstevel@tonic-gate (void) unlink(tmp_file_name);
3150Sstevel@tonic-gate free(tmp_file_name);
3160Sstevel@tonic-gate (void) unlock_index_file(lock_fd);
3170Sstevel@tonic-gate return (Z_TEMP_FILE);
3180Sstevel@tonic-gate }
3192303Scarlsonj (void) fchmod(tmp_file_desc, ZONE_INDEX_MODE);
3202303Scarlsonj (void) fchown(tmp_file_desc, ZONE_INDEX_UID, ZONE_INDEX_GID);
3210Sstevel@tonic-gate if ((tmp_file = fdopen(tmp_file_desc, "w")) == NULL) {
3220Sstevel@tonic-gate (void) close(tmp_file_desc);
323766Scarlsonj err = Z_MISC_FS;
324766Scarlsonj goto error;
3250Sstevel@tonic-gate }
326766Scarlsonj if (!get_index_path(path)) {
327766Scarlsonj err = Z_MISC_FS;
328766Scarlsonj goto error;
329766Scarlsonj }
330766Scarlsonj if ((index_file = fopen(path, "r")) == NULL) {
331766Scarlsonj err = Z_MISC_FS;
332766Scarlsonj goto error;
3330Sstevel@tonic-gate }
3340Sstevel@tonic-gate
3351422Scarlsonj exist = B_FALSE;
3361422Scarlsonj zone_name = ze->zone_name;
3371422Scarlsonj namelen = strlen(zone_name);
3380Sstevel@tonic-gate for (;;) {
3390Sstevel@tonic-gate if (fgets(buf, sizeof (buf), index_file) == NULL) {
3401422Scarlsonj if (operation == PZE_ADD && !exist) {
3411422Scarlsonj zone_state = zone_state_str(ze->zone_state);
3421422Scarlsonj zone_path = ze->zone_path;
3431422Scarlsonj zone_uuid = "";
3441422Scarlsonj goto add_entry;
3451422Scarlsonj }
3461422Scarlsonj /*
3471422Scarlsonj * It's not considered an error to delete something
3481422Scarlsonj * that doesn't exist, but we can't modify a missing
3491422Scarlsonj * record.
3501422Scarlsonj */
3511422Scarlsonj if (operation == PZE_MODIFY && !exist) {
3521422Scarlsonj err = Z_UPDATING_INDEX;
3531422Scarlsonj goto error;
3541422Scarlsonj }
3550Sstevel@tonic-gate break;
3560Sstevel@tonic-gate }
3571422Scarlsonj
3581422Scarlsonj if (buf[0] == '#') {
3591422Scarlsonj /* skip and preserve comment lines */
3601422Scarlsonj (void) fputs(buf, tmp_file);
3611422Scarlsonj continue;
3621422Scarlsonj }
3631422Scarlsonj
3641422Scarlsonj if (strncmp(buf, zone_name, namelen) != 0 ||
3651422Scarlsonj buf[namelen] != ':') {
3661422Scarlsonj /* skip and preserve non-target lines */
3671422Scarlsonj (void) fputs(buf, tmp_file);
3681422Scarlsonj continue;
3691422Scarlsonj }
3700Sstevel@tonic-gate
3710Sstevel@tonic-gate if ((cp = strpbrk(buf, "\r\n")) == NULL) {
3721422Scarlsonj /* this represents a line that's too long; delete */
3730Sstevel@tonic-gate continue;
3740Sstevel@tonic-gate }
3750Sstevel@tonic-gate *cp = '\0';
3761422Scarlsonj
3771422Scarlsonj /*
3781422Scarlsonj * Skip over the zone name. Because we've already matched the
3791422Scarlsonj * target zone (above), we know for certain here that the zone
3801422Scarlsonj * name is present and correctly formed. No need to check.
3811422Scarlsonj */
3821422Scarlsonj cp = strchr(buf, ':') + 1;
3831422Scarlsonj
3841422Scarlsonj zone_state = gettok(&cp);
3851422Scarlsonj if (*zone_state == '\0') {
3861422Scarlsonj /* state field should not be empty */
3871422Scarlsonj err = Z_UPDATING_INDEX;
3881422Scarlsonj goto error;
3890Sstevel@tonic-gate }
3901422Scarlsonj zone_path = gettok(&cp);
3911422Scarlsonj zone_uuid = gettok(&cp);
3921422Scarlsonj
3931422Scarlsonj switch (operation) {
3941422Scarlsonj case PZE_ADD:
3951422Scarlsonj /* can't add same zone */
3961422Scarlsonj err = Z_UPDATING_INDEX;
3971422Scarlsonj goto error;
3981422Scarlsonj
3991422Scarlsonj case PZE_MODIFY:
4000Sstevel@tonic-gate /*
4011422Scarlsonj * If the caller specified a new state for the zone,
4021422Scarlsonj * then use that. Otherwise, use the current state.
4030Sstevel@tonic-gate */
4041422Scarlsonj if (ze->zone_state >= 0) {
4051422Scarlsonj zone_state = zone_state_str(ze->zone_state);
4061422Scarlsonj
4071422Scarlsonj /*
4081422Scarlsonj * If the caller is uninstalling this zone,
4091422Scarlsonj * then wipe out the uuid. The zone's contents
4101422Scarlsonj * are no longer known.
4111422Scarlsonj */
4121422Scarlsonj if (ze->zone_state < ZONE_STATE_INSTALLED)
4131422Scarlsonj zone_uuid = "";
4141422Scarlsonj }
4151422Scarlsonj
4161422Scarlsonj /* If a new name is supplied, use it. */
4171422Scarlsonj if (ze->zone_newname[0] != '\0')
4181422Scarlsonj zone_name = ze->zone_newname;
4191422Scarlsonj
4201422Scarlsonj if (ze->zone_path[0] != '\0')
4211422Scarlsonj zone_path = ze->zone_path;
4221422Scarlsonj break;
4231422Scarlsonj
4241422Scarlsonj case PZE_REMOVE:
4251422Scarlsonj default:
4260Sstevel@tonic-gate continue;
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate
4291422Scarlsonj add_entry:
4301422Scarlsonj /*
4311422Scarlsonj * If the entry in the file is in greater than configured
4321422Scarlsonj * state, then we must have a UUID. Make sure that we do.
4331422Scarlsonj * (Note that the file entry is only tokenized, not fully
4341422Scarlsonj * parsed, so we need to do a string comparison here.)
4351422Scarlsonj */
4361422Scarlsonj if (strcmp(zone_state, ZONE_STATE_STR_CONFIGURED) != 0 &&
4371422Scarlsonj *zone_uuid == '\0') {
4381422Scarlsonj if (uuid_is_null(ze->zone_uuid))
4391422Scarlsonj uuid_generate(ze->zone_uuid);
4401422Scarlsonj uuid_unparse(ze->zone_uuid, uuidstr);
4411422Scarlsonj zone_uuid = uuidstr;
4420Sstevel@tonic-gate }
4431422Scarlsonj /*
4441422Scarlsonj * We need to quote a path that contains a ":"; this should
4451422Scarlsonj * only affect the zonepath, as zone names do not allow such
4461422Scarlsonj * characters, and zone states do not have them either. Same
4471422Scarlsonj * with double-quotes themselves: they are not allowed in zone
4481422Scarlsonj * names, and do not occur in zone states, and in theory should
4491422Scarlsonj * never occur in a zonepath since zonecfg does not support a
4501422Scarlsonj * method for escaping them.
4511422Scarlsonj */
4521422Scarlsonj need_quotes = (strchr(zone_path, ':') != NULL);
4531422Scarlsonj (void) fprintf(tmp_file, "%s:%s:%s%s%s:%s\n", zone_name,
4541422Scarlsonj zone_state, need_quotes ? "\"" : "", zone_path,
4551422Scarlsonj need_quotes ? "\"" : "", zone_uuid);
4561422Scarlsonj exist = B_TRUE;
4570Sstevel@tonic-gate }
4580Sstevel@tonic-gate
4590Sstevel@tonic-gate (void) fclose(index_file);
460766Scarlsonj index_file = NULL;
4610Sstevel@tonic-gate if (fclose(tmp_file) != 0) {
462766Scarlsonj tmp_file = NULL;
463766Scarlsonj err = Z_MISC_FS;
464766Scarlsonj goto error;
4650Sstevel@tonic-gate }
466766Scarlsonj tmp_file = NULL;
467766Scarlsonj if (rename(tmp_file_name, path) == -1) {
468766Scarlsonj err = errno == EACCES ? Z_ACCES : Z_MISC_FS;
469766Scarlsonj goto error;
4700Sstevel@tonic-gate }
4710Sstevel@tonic-gate free(tmp_file_name);
4720Sstevel@tonic-gate if (unlock_index_file(lock_fd) != Z_OK)
4730Sstevel@tonic-gate return (Z_UNLOCKING_FILE);
4740Sstevel@tonic-gate return (Z_OK);
475766Scarlsonj
4760Sstevel@tonic-gate error:
477766Scarlsonj if (index_file != NULL)
478766Scarlsonj (void) fclose(index_file);
479766Scarlsonj if (tmp_file != NULL)
480766Scarlsonj (void) fclose(tmp_file);
4810Sstevel@tonic-gate (void) unlink(tmp_file_name);
4820Sstevel@tonic-gate free(tmp_file_name);
483766Scarlsonj (void) unlock_index_file(lock_fd);
484766Scarlsonj return (err);
4850Sstevel@tonic-gate }
486