xref: /titanic_50/usr/src/lib/libzonecfg/common/getzoneent.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * This module contains functions used for reading and writing the index file.
31*7c478bd9Sstevel@tonic-gate  * setzoneent() opens the file.  getzoneent() parses the file, doing the usual
32*7c478bd9Sstevel@tonic-gate  * skipping of comment lines, etc., and using gettok() to deal with the ":"
33*7c478bd9Sstevel@tonic-gate  * delimiters.  endzoneent() closes the file.  putzoneent() updates the file,
34*7c478bd9Sstevel@tonic-gate  * adding, deleting or modifying lines, locking and unlocking appropriately.
35*7c478bd9Sstevel@tonic-gate  */
36*7c478bd9Sstevel@tonic-gate 
37*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
38*7c478bd9Sstevel@tonic-gate #include <ctype.h>
39*7c478bd9Sstevel@tonic-gate #include <string.h>
40*7c478bd9Sstevel@tonic-gate #include <errno.h>
41*7c478bd9Sstevel@tonic-gate #include <libzonecfg.h>
42*7c478bd9Sstevel@tonic-gate #include <unistd.h>
43*7c478bd9Sstevel@tonic-gate #include <fcntl.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
45*7c478bd9Sstevel@tonic-gate #include <assert.h>
46*7c478bd9Sstevel@tonic-gate #include "zonecfg_impl.h"
47*7c478bd9Sstevel@tonic-gate 
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate #define	_PATH_TMPFILE	ZONE_CONFIG_ROOT "/zonecfg.XXXXXX"
50*7c478bd9Sstevel@tonic-gate 
51*7c478bd9Sstevel@tonic-gate /*
52*7c478bd9Sstevel@tonic-gate  * gettok() is a helper function for parsing the index file, used to split
53*7c478bd9Sstevel@tonic-gate  * the lines by their ":" delimiters.  Note that an entry may contain a ":"
54*7c478bd9Sstevel@tonic-gate  * inside double quotes; this should only affect the zonepath, as zone names
55*7c478bd9Sstevel@tonic-gate  * do not allow such characters, and zone states do not have them either.
56*7c478bd9Sstevel@tonic-gate  * Same with double-quotes themselves: they are not allowed in zone names,
57*7c478bd9Sstevel@tonic-gate  * and do not occur in zone states, and in theory should never occur in a
58*7c478bd9Sstevel@tonic-gate  * zonepath since zonecfg does not support a method for escaping them.
59*7c478bd9Sstevel@tonic-gate  */
60*7c478bd9Sstevel@tonic-gate 
61*7c478bd9Sstevel@tonic-gate static char *
62*7c478bd9Sstevel@tonic-gate gettok(char **cpp)
63*7c478bd9Sstevel@tonic-gate {
64*7c478bd9Sstevel@tonic-gate 	char *cp = *cpp, *retv;
65*7c478bd9Sstevel@tonic-gate 	boolean_t quoted = B_FALSE;
66*7c478bd9Sstevel@tonic-gate 
67*7c478bd9Sstevel@tonic-gate 	if (cp == NULL)
68*7c478bd9Sstevel@tonic-gate 		return ("");
69*7c478bd9Sstevel@tonic-gate 	if (*cp == '"') {
70*7c478bd9Sstevel@tonic-gate 		quoted = B_TRUE;
71*7c478bd9Sstevel@tonic-gate 		cp++;
72*7c478bd9Sstevel@tonic-gate 	}
73*7c478bd9Sstevel@tonic-gate 	retv = cp;
74*7c478bd9Sstevel@tonic-gate 	if (quoted) {
75*7c478bd9Sstevel@tonic-gate 		while (*cp != '\0' && *cp != '"')
76*7c478bd9Sstevel@tonic-gate 			cp++;
77*7c478bd9Sstevel@tonic-gate 		if (*cp == '"')
78*7c478bd9Sstevel@tonic-gate 			*cp++ = '\0';
79*7c478bd9Sstevel@tonic-gate 	}
80*7c478bd9Sstevel@tonic-gate 	while (*cp != '\0' && *cp != ':')
81*7c478bd9Sstevel@tonic-gate 		cp++;
82*7c478bd9Sstevel@tonic-gate 	if (*cp == '\0') {
83*7c478bd9Sstevel@tonic-gate 		*cpp = NULL;
84*7c478bd9Sstevel@tonic-gate 	} else {
85*7c478bd9Sstevel@tonic-gate 		*cp++ = '\0';
86*7c478bd9Sstevel@tonic-gate 		*cpp = cp;
87*7c478bd9Sstevel@tonic-gate 	}
88*7c478bd9Sstevel@tonic-gate 	return (retv);
89*7c478bd9Sstevel@tonic-gate }
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate char *
92*7c478bd9Sstevel@tonic-gate getzoneent(FILE *cookie)
93*7c478bd9Sstevel@tonic-gate {
94*7c478bd9Sstevel@tonic-gate 	struct zoneent *ze;
95*7c478bd9Sstevel@tonic-gate 	char *name;
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	if ((ze = getzoneent_private(cookie)) == NULL)
98*7c478bd9Sstevel@tonic-gate 		return (NULL);
99*7c478bd9Sstevel@tonic-gate 	name = strdup(ze->zone_name);
100*7c478bd9Sstevel@tonic-gate 	free(ze);
101*7c478bd9Sstevel@tonic-gate 	return (name);
102*7c478bd9Sstevel@tonic-gate }
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate struct zoneent *
105*7c478bd9Sstevel@tonic-gate getzoneent_private(FILE *cookie)
106*7c478bd9Sstevel@tonic-gate {
107*7c478bd9Sstevel@tonic-gate 	char *cp, buf[MAX_INDEX_LEN], *p;
108*7c478bd9Sstevel@tonic-gate 	struct zoneent *ze;
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	if (cookie == NULL)
111*7c478bd9Sstevel@tonic-gate 		return (NULL);
112*7c478bd9Sstevel@tonic-gate 
113*7c478bd9Sstevel@tonic-gate 	if ((ze = malloc(sizeof (struct zoneent))) == NULL)
114*7c478bd9Sstevel@tonic-gate 		return (NULL);
115*7c478bd9Sstevel@tonic-gate 
116*7c478bd9Sstevel@tonic-gate 	for (;;) {
117*7c478bd9Sstevel@tonic-gate 		if (fgets(buf, sizeof (buf), cookie) == NULL) {
118*7c478bd9Sstevel@tonic-gate 			free(ze);
119*7c478bd9Sstevel@tonic-gate 			return (NULL);
120*7c478bd9Sstevel@tonic-gate 		}
121*7c478bd9Sstevel@tonic-gate 		if ((cp = strpbrk(buf, "\r\n")) == NULL) {
122*7c478bd9Sstevel@tonic-gate 			/* this represents a line that's too long */
123*7c478bd9Sstevel@tonic-gate 			continue;
124*7c478bd9Sstevel@tonic-gate 		}
125*7c478bd9Sstevel@tonic-gate 		*cp = '\0';
126*7c478bd9Sstevel@tonic-gate 		cp = buf;
127*7c478bd9Sstevel@tonic-gate 		if (*cp == '#') {
128*7c478bd9Sstevel@tonic-gate 			/* skip comment lines */
129*7c478bd9Sstevel@tonic-gate 			continue;
130*7c478bd9Sstevel@tonic-gate 		}
131*7c478bd9Sstevel@tonic-gate 		p = gettok(&cp);
132*7c478bd9Sstevel@tonic-gate 		if (p == NULL || *p == '\0' || strlen(p) > ZONENAME_MAX) {
133*7c478bd9Sstevel@tonic-gate 			/*
134*7c478bd9Sstevel@tonic-gate 			 * empty or very long zone names are not allowed
135*7c478bd9Sstevel@tonic-gate 			 */
136*7c478bd9Sstevel@tonic-gate 			continue;
137*7c478bd9Sstevel@tonic-gate 		}
138*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(ze->zone_name, p, ZONENAME_MAX);
139*7c478bd9Sstevel@tonic-gate 
140*7c478bd9Sstevel@tonic-gate 		p = gettok(&cp);
141*7c478bd9Sstevel@tonic-gate 		if (p == NULL || *p == '\0') {
142*7c478bd9Sstevel@tonic-gate 			/* state field should not be empty */
143*7c478bd9Sstevel@tonic-gate 			continue;
144*7c478bd9Sstevel@tonic-gate 		}
145*7c478bd9Sstevel@tonic-gate 		errno = 0;
146*7c478bd9Sstevel@tonic-gate 		if (strcmp(p, ZONE_STATE_STR_CONFIGURED) == 0) {
147*7c478bd9Sstevel@tonic-gate 			ze->zone_state = ZONE_STATE_CONFIGURED;
148*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(p, ZONE_STATE_STR_INCOMPLETE) == 0) {
149*7c478bd9Sstevel@tonic-gate 			ze->zone_state = ZONE_STATE_INCOMPLETE;
150*7c478bd9Sstevel@tonic-gate 		} else if (strcmp(p, ZONE_STATE_STR_INSTALLED) == 0) {
151*7c478bd9Sstevel@tonic-gate 			ze->zone_state = ZONE_STATE_INSTALLED;
152*7c478bd9Sstevel@tonic-gate 		} else
153*7c478bd9Sstevel@tonic-gate 			continue;
154*7c478bd9Sstevel@tonic-gate 
155*7c478bd9Sstevel@tonic-gate 		p = gettok(&cp);
156*7c478bd9Sstevel@tonic-gate 		if (strlen(p) > MAXPATHLEN) {
157*7c478bd9Sstevel@tonic-gate 			/* very long paths are not allowed */
158*7c478bd9Sstevel@tonic-gate 			continue;
159*7c478bd9Sstevel@tonic-gate 		}
160*7c478bd9Sstevel@tonic-gate 		if (p == NULL) {
161*7c478bd9Sstevel@tonic-gate 			/* empty paths accepted for backwards compatibility */
162*7c478bd9Sstevel@tonic-gate 			p = "";
163*7c478bd9Sstevel@tonic-gate 		}
164*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(ze->zone_path, p, MAXPATHLEN);
165*7c478bd9Sstevel@tonic-gate 
166*7c478bd9Sstevel@tonic-gate 		break;
167*7c478bd9Sstevel@tonic-gate 	}
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	return (ze);
170*7c478bd9Sstevel@tonic-gate }
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate FILE *
173*7c478bd9Sstevel@tonic-gate setzoneent(void)
174*7c478bd9Sstevel@tonic-gate {
175*7c478bd9Sstevel@tonic-gate 	return (fopen(ZONE_INDEX_FILE, "r"));
176*7c478bd9Sstevel@tonic-gate }
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate void
179*7c478bd9Sstevel@tonic-gate endzoneent(FILE *cookie)
180*7c478bd9Sstevel@tonic-gate {
181*7c478bd9Sstevel@tonic-gate 	if (cookie != NULL)
182*7c478bd9Sstevel@tonic-gate 		(void) fclose(cookie);
183*7c478bd9Sstevel@tonic-gate }
184*7c478bd9Sstevel@tonic-gate 
185*7c478bd9Sstevel@tonic-gate static int
186*7c478bd9Sstevel@tonic-gate lock_index_file(int *lock_fd)
187*7c478bd9Sstevel@tonic-gate {
188*7c478bd9Sstevel@tonic-gate 	struct flock lock;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	if ((mkdir(ZONE_SNAPSHOT_ROOT, S_IRWXU) == -1) && errno != EEXIST)
191*7c478bd9Sstevel@tonic-gate 		return (Z_LOCKING_FILE);
192*7c478bd9Sstevel@tonic-gate 	*lock_fd = open(ZONE_INDEX_LOCK_FILE, O_CREAT|O_RDWR, 0644);
193*7c478bd9Sstevel@tonic-gate 	if (*lock_fd < 0)
194*7c478bd9Sstevel@tonic-gate 		return (Z_LOCKING_FILE);
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	lock.l_type = F_WRLCK;
197*7c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
198*7c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
199*7c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	if (fcntl(*lock_fd, F_SETLKW, &lock) == -1)
202*7c478bd9Sstevel@tonic-gate 		return (Z_LOCKING_FILE);
203*7c478bd9Sstevel@tonic-gate 
204*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
205*7c478bd9Sstevel@tonic-gate }
206*7c478bd9Sstevel@tonic-gate 
207*7c478bd9Sstevel@tonic-gate static int
208*7c478bd9Sstevel@tonic-gate unlock_index_file(int lock_fd)
209*7c478bd9Sstevel@tonic-gate {
210*7c478bd9Sstevel@tonic-gate 	struct flock lock;
211*7c478bd9Sstevel@tonic-gate 
212*7c478bd9Sstevel@tonic-gate 	lock.l_type = F_UNLCK;
213*7c478bd9Sstevel@tonic-gate 	lock.l_whence = SEEK_SET;
214*7c478bd9Sstevel@tonic-gate 	lock.l_start = 0;
215*7c478bd9Sstevel@tonic-gate 	lock.l_len = 0;
216*7c478bd9Sstevel@tonic-gate 
217*7c478bd9Sstevel@tonic-gate 	if (fcntl(lock_fd, F_SETLK, &lock) == -1)
218*7c478bd9Sstevel@tonic-gate 		return (Z_UNLOCKING_FILE);
219*7c478bd9Sstevel@tonic-gate 
220*7c478bd9Sstevel@tonic-gate 	if (close(lock_fd) == -1)
221*7c478bd9Sstevel@tonic-gate 		return (Z_UNLOCKING_FILE);
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
224*7c478bd9Sstevel@tonic-gate }
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate /*
227*7c478bd9Sstevel@tonic-gate  * This function adds or removes a zone name et al. to the index file.
228*7c478bd9Sstevel@tonic-gate  *
229*7c478bd9Sstevel@tonic-gate  * If ze->zone_state is < 0, it means leave the
230*7c478bd9Sstevel@tonic-gate  * existing value unchanged; this is only meaningful when operation ==
231*7c478bd9Sstevel@tonic-gate  * PZE_MODIFY (i.e., it's bad on PZE_ADD and a no-op on PZE_DELETE).
232*7c478bd9Sstevel@tonic-gate  *
233*7c478bd9Sstevel@tonic-gate  * Likewise, a zero-length ze->zone_path means leave the existing value
234*7c478bd9Sstevel@tonic-gate  * unchanged; this is only meaningful when operation == PZE_MODIFY
235*7c478bd9Sstevel@tonic-gate  * (i.e., it's bad on PZE_ADD and a no-op on PZE_DELETE).
236*7c478bd9Sstevel@tonic-gate  *
237*7c478bd9Sstevel@tonic-gate  * Locking and unlocking is done via the functions above.
238*7c478bd9Sstevel@tonic-gate  * The file itself is not modified in place; rather, a copy is made which
239*7c478bd9Sstevel@tonic-gate  * is modified, then the copy is atomically renamed back to the main file.
240*7c478bd9Sstevel@tonic-gate  */
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate int
243*7c478bd9Sstevel@tonic-gate putzoneent(struct zoneent *ze, zoneent_op_t operation)
244*7c478bd9Sstevel@tonic-gate {
245*7c478bd9Sstevel@tonic-gate 	FILE *index_file, *tmp_file;
246*7c478bd9Sstevel@tonic-gate 	char *tmp_file_name, buf[MAX_INDEX_LEN], orig_buf[MAX_INDEX_LEN];
247*7c478bd9Sstevel@tonic-gate 	char zone[ZONENAME_MAX + 1];		/* name plus newline */
248*7c478bd9Sstevel@tonic-gate 	char line[MAX_INDEX_LEN];
249*7c478bd9Sstevel@tonic-gate 	int tmp_file_desc, lock_fd, err;
250*7c478bd9Sstevel@tonic-gate 	boolean_t exists = B_FALSE, need_quotes;
251*7c478bd9Sstevel@tonic-gate 	char *cp, *p;
252*7c478bd9Sstevel@tonic-gate 
253*7c478bd9Sstevel@tonic-gate 	assert(ze != NULL);
254*7c478bd9Sstevel@tonic-gate 	if (operation == PZE_ADD &&
255*7c478bd9Sstevel@tonic-gate 	    (ze->zone_state < 0 || strlen(ze->zone_path) == 0))
256*7c478bd9Sstevel@tonic-gate 		return (Z_INVAL);
257*7c478bd9Sstevel@tonic-gate 	if ((err = lock_index_file(&lock_fd)) != Z_OK)
258*7c478bd9Sstevel@tonic-gate 		return (err);
259*7c478bd9Sstevel@tonic-gate 	tmp_file_name = strdup(_PATH_TMPFILE);
260*7c478bd9Sstevel@tonic-gate 	if (tmp_file_name == NULL) {
261*7c478bd9Sstevel@tonic-gate 		(void) unlock_index_file(lock_fd);
262*7c478bd9Sstevel@tonic-gate 		return (Z_NOMEM);
263*7c478bd9Sstevel@tonic-gate 	}
264*7c478bd9Sstevel@tonic-gate 	tmp_file_desc = mkstemp(tmp_file_name);
265*7c478bd9Sstevel@tonic-gate 	if (tmp_file_desc == -1) {
266*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_file_name);
267*7c478bd9Sstevel@tonic-gate 		free(tmp_file_name);
268*7c478bd9Sstevel@tonic-gate 		(void) unlock_index_file(lock_fd);
269*7c478bd9Sstevel@tonic-gate 		return (Z_TEMP_FILE);
270*7c478bd9Sstevel@tonic-gate 	}
271*7c478bd9Sstevel@tonic-gate 	if ((tmp_file = fdopen(tmp_file_desc, "w")) == NULL) {
272*7c478bd9Sstevel@tonic-gate 		(void) close(tmp_file_desc);
273*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_file_name);
274*7c478bd9Sstevel@tonic-gate 		free(tmp_file_name);
275*7c478bd9Sstevel@tonic-gate 		(void) unlock_index_file(lock_fd);
276*7c478bd9Sstevel@tonic-gate 		return (Z_MISC_FS);
277*7c478bd9Sstevel@tonic-gate 	}
278*7c478bd9Sstevel@tonic-gate 	if ((index_file = fopen(ZONE_INDEX_FILE, "r")) == NULL) {
279*7c478bd9Sstevel@tonic-gate 		(void) fclose(tmp_file);
280*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_file_name);
281*7c478bd9Sstevel@tonic-gate 		free(tmp_file_name);
282*7c478bd9Sstevel@tonic-gate 		(void) unlock_index_file(lock_fd);
283*7c478bd9Sstevel@tonic-gate 		return (Z_MISC_FS);
284*7c478bd9Sstevel@tonic-gate 	}
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	/*
287*7c478bd9Sstevel@tonic-gate 	 * We need to quote a path which contains a ":"; this should only
288*7c478bd9Sstevel@tonic-gate 	 * affect the zonepath, as zone names do not allow such characters,
289*7c478bd9Sstevel@tonic-gate 	 * and zone states do not have them either.  Same with double-quotes
290*7c478bd9Sstevel@tonic-gate 	 * themselves: they are not allowed in zone names, and do not occur
291*7c478bd9Sstevel@tonic-gate 	 * in zone states, and in theory should never occur in a zonepath
292*7c478bd9Sstevel@tonic-gate 	 * since zonecfg does not support a method for escaping them.
293*7c478bd9Sstevel@tonic-gate 	 */
294*7c478bd9Sstevel@tonic-gate 	need_quotes = (strchr(ze->zone_path, ':') != NULL);
295*7c478bd9Sstevel@tonic-gate 
296*7c478bd9Sstevel@tonic-gate 	(void) snprintf(line, sizeof (line), "%s:%s:%s%s%s\n", ze->zone_name,
297*7c478bd9Sstevel@tonic-gate 	    zone_state_str(ze->zone_state), need_quotes ? "\"" : "",
298*7c478bd9Sstevel@tonic-gate 	    ze->zone_path, need_quotes ? "\"" : "");
299*7c478bd9Sstevel@tonic-gate 	for (;;) {
300*7c478bd9Sstevel@tonic-gate 		if (fgets(buf, sizeof (buf), index_file) == NULL) {
301*7c478bd9Sstevel@tonic-gate 			if (operation == PZE_ADD && !exists)
302*7c478bd9Sstevel@tonic-gate 				(void) fputs(line, tmp_file);
303*7c478bd9Sstevel@tonic-gate 			break;
304*7c478bd9Sstevel@tonic-gate 		}
305*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(orig_buf, buf, sizeof (orig_buf));
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 		if ((cp = strpbrk(buf, "\r\n")) == NULL) {
308*7c478bd9Sstevel@tonic-gate 			/* this represents a line that's too long */
309*7c478bd9Sstevel@tonic-gate 			continue;
310*7c478bd9Sstevel@tonic-gate 		}
311*7c478bd9Sstevel@tonic-gate 		*cp = '\0';
312*7c478bd9Sstevel@tonic-gate 		cp = buf;
313*7c478bd9Sstevel@tonic-gate 		if (*cp == '#') {
314*7c478bd9Sstevel@tonic-gate 			/* skip comment lines */
315*7c478bd9Sstevel@tonic-gate 			(void) fputs(orig_buf, tmp_file);
316*7c478bd9Sstevel@tonic-gate 			continue;
317*7c478bd9Sstevel@tonic-gate 		}
318*7c478bd9Sstevel@tonic-gate 		p = gettok(&cp);
319*7c478bd9Sstevel@tonic-gate 		if (p == NULL || *p == '\0' || strlen(p) > ZONENAME_MAX) {
320*7c478bd9Sstevel@tonic-gate 			/*
321*7c478bd9Sstevel@tonic-gate 			 * empty or very long zone names are not allowed
322*7c478bd9Sstevel@tonic-gate 			 */
323*7c478bd9Sstevel@tonic-gate 			continue;
324*7c478bd9Sstevel@tonic-gate 		}
325*7c478bd9Sstevel@tonic-gate 		(void) strlcpy(zone, p, ZONENAME_MAX);
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate 		if (strcmp(zone, ze->zone_name) == 0) {
328*7c478bd9Sstevel@tonic-gate 			exists = B_TRUE;		/* already there */
329*7c478bd9Sstevel@tonic-gate 			if (operation == PZE_ADD) {
330*7c478bd9Sstevel@tonic-gate 				/* can't add same zone */
331*7c478bd9Sstevel@tonic-gate 				goto error;
332*7c478bd9Sstevel@tonic-gate 			} else if (operation == PZE_MODIFY) {
333*7c478bd9Sstevel@tonic-gate 				char tmp_state[ZONE_STATE_MAXSTRLEN + 1];
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 				if (ze->zone_state >= 0 &&
336*7c478bd9Sstevel@tonic-gate 				    strlen(ze->zone_path) > 0) {
337*7c478bd9Sstevel@tonic-gate 					/* use specified values */
338*7c478bd9Sstevel@tonic-gate 					(void) fputs(line, tmp_file);
339*7c478bd9Sstevel@tonic-gate 					continue;
340*7c478bd9Sstevel@tonic-gate 				}
341*7c478bd9Sstevel@tonic-gate 				/* use existing value for state */
342*7c478bd9Sstevel@tonic-gate 				p = gettok(&cp);
343*7c478bd9Sstevel@tonic-gate 				if (p == NULL || *p == '\0') {
344*7c478bd9Sstevel@tonic-gate 					/* state field should not be empty */
345*7c478bd9Sstevel@tonic-gate 					goto error;
346*7c478bd9Sstevel@tonic-gate 				}
347*7c478bd9Sstevel@tonic-gate 				(void) strlcpy(tmp_state,
348*7c478bd9Sstevel@tonic-gate 				    (ze->zone_state < 0) ? p :
349*7c478bd9Sstevel@tonic-gate 				    zone_state_str(ze->zone_state),
350*7c478bd9Sstevel@tonic-gate 				    sizeof (tmp_state));
351*7c478bd9Sstevel@tonic-gate 
352*7c478bd9Sstevel@tonic-gate 				p = gettok(&cp);
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 				(void) fprintf(tmp_file, "%s:%s:%s%s%s\n",
355*7c478bd9Sstevel@tonic-gate 				    ze->zone_name, tmp_state,
356*7c478bd9Sstevel@tonic-gate 				    need_quotes ? "\"" : "",
357*7c478bd9Sstevel@tonic-gate 				    (strlen(ze->zone_path) == 0) ? p :
358*7c478bd9Sstevel@tonic-gate 				    ze->zone_path, need_quotes ? "\"" : "");
359*7c478bd9Sstevel@tonic-gate 			}
360*7c478bd9Sstevel@tonic-gate 		} else {
361*7c478bd9Sstevel@tonic-gate 			(void) fputs(orig_buf, tmp_file);
362*7c478bd9Sstevel@tonic-gate 		}
363*7c478bd9Sstevel@tonic-gate 	}
364*7c478bd9Sstevel@tonic-gate 
365*7c478bd9Sstevel@tonic-gate 	(void) fclose(index_file);
366*7c478bd9Sstevel@tonic-gate 	if (fclose(tmp_file) != 0) {
367*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_file_name);
368*7c478bd9Sstevel@tonic-gate 		free(tmp_file_name);
369*7c478bd9Sstevel@tonic-gate 		(void) unlock_index_file(lock_fd);
370*7c478bd9Sstevel@tonic-gate 		return (Z_MISC_FS);
371*7c478bd9Sstevel@tonic-gate 	}
372*7c478bd9Sstevel@tonic-gate 	(void) chmod(tmp_file_name, 0644);
373*7c478bd9Sstevel@tonic-gate 	if (rename(tmp_file_name, ZONE_INDEX_FILE) == -1) {
374*7c478bd9Sstevel@tonic-gate 		(void) unlink(tmp_file_name);
375*7c478bd9Sstevel@tonic-gate 		free(tmp_file_name);
376*7c478bd9Sstevel@tonic-gate 		(void) unlock_index_file(lock_fd);
377*7c478bd9Sstevel@tonic-gate 		if (errno == EACCES)
378*7c478bd9Sstevel@tonic-gate 			return (Z_ACCES);
379*7c478bd9Sstevel@tonic-gate 		return (Z_MISC_FS);
380*7c478bd9Sstevel@tonic-gate 	}
381*7c478bd9Sstevel@tonic-gate 	free(tmp_file_name);
382*7c478bd9Sstevel@tonic-gate 	if (unlock_index_file(lock_fd) != Z_OK)
383*7c478bd9Sstevel@tonic-gate 		return (Z_UNLOCKING_FILE);
384*7c478bd9Sstevel@tonic-gate 	return (Z_OK);
385*7c478bd9Sstevel@tonic-gate error:
386*7c478bd9Sstevel@tonic-gate 	(void) fclose(index_file);
387*7c478bd9Sstevel@tonic-gate 	(void) fclose(tmp_file);
388*7c478bd9Sstevel@tonic-gate 	(void) unlink(tmp_file_name);
389*7c478bd9Sstevel@tonic-gate 	free(tmp_file_name);
390*7c478bd9Sstevel@tonic-gate 	if (unlock_index_file(lock_fd) != Z_OK)
391*7c478bd9Sstevel@tonic-gate 		return (Z_UNLOCKING_FILE);
392*7c478bd9Sstevel@tonic-gate 	return (Z_UPDATING_INDEX);
393*7c478bd9Sstevel@tonic-gate }
394