xref: /titanic_41/usr/src/lib/lvm/libsvm/common/update_mdconf.c (revision c10c16dec587a0662068f6e2991c29ed3a9db943)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <devid.h>
33 #include <errno.h>
34 #include <string.h>
35 #include <assert.h>
36 #include <sys/types.h>
37 #include <sys/stat.h>
38 #include <meta.h>
39 #include <libsvm.h>
40 #include <svm.h>
41 
42 /*
43  * magic strings in system
44  */
45 #define	BEGMDDBSTR	"* Begin MDD database info (do not edit)\n"
46 #define	ENDMDDBSTR	"* End MDD database info (do not edit)\n"
47 #define	NEW_BEGMDDBSTR	"# Begin MDD database info (do not edit)\n"
48 #define	NEW_ENDMDDBSTR	"# End MDD database info (do not edit)\n"
49 
50 #define	MDDBBOOTLIST	"mddb_bootlist"
51 
52 #define	SYS_COMMENTCHAR	'*'
53 #define	CONF_COMMENTCHAR '#'
54 
55 typedef struct {
56 	char *prop_name;
57 	int  prop_val;
58 } md_prop_t;
59 
60 typedef enum {
61 	MDDB_SYS_FILE,
62 	MDDB_MDCONF_FILE
63 } ftype_t;
64 
65 static md_prop_t upgrade_props[] = {
66 		{ PROP_KEEP_REPL_STATE, 0 },
67 		{ PROP_DEVID_DESTROY, 0},
68 		{ NULL, 0}
69 };
70 
71 /*
72  * The following functions manage upgrade properties
73  */
74 
75 void
76 set_upgrade_prop(char *prop_name, int val)
77 {
78 	md_prop_t *upp;
79 
80 	upp = &upgrade_props[0];
81 
82 	for (; upp->prop_name != NULL; upp++) {
83 		if (strcmp(upp->prop_name, prop_name) == 0) {
84 			upp->prop_val = val;
85 			return;
86 		}
87 	}
88 }
89 
90 int
91 is_upgrade_prop(char *prop_name)
92 {
93 	md_prop_t *upp;
94 
95 	upp = &upgrade_props[0];
96 
97 	for (; upp->prop_name != NULL; upp++) {
98 		if (strcmp(upp->prop_name, prop_name) == 0) {
99 			return (upp->prop_val == 1);
100 		}
101 	}
102 	return (0);
103 }
104 
105 int
106 create_in_file_prop(char *prop_name, char *fname)
107 {
108 	FILE *fp;
109 	md_prop_t *upp;
110 	int rval = RET_ERROR;
111 
112 	if ((fp = fopen(fname, "a")) == NULL) {
113 		return (errno);
114 	}
115 
116 	upp = &upgrade_props[0];
117 
118 	for (; upp->prop_name != NULL; upp++) {
119 		if (strcmp(upp->prop_name, prop_name) == 0) {
120 			(void) fprintf(fp, "%s = 1;\n", upp->prop_name);
121 			rval = RET_SUCCESS;
122 			break;
123 		}
124 	}
125 	(void) fclose(fp);
126 	return (rval);
127 }
128 
129 static int
130 is_devid_added(char *str)
131 {
132 	int cnt = 0;
133 	char *cp;
134 
135 	/* there are exactly 3 colons in the string for devid */
136 	for (cnt = 0; cnt < 4; cnt++) {
137 		if ((cp = strchr(str, ':')) == NULL)
138 			break;
139 		str = ++cp;
140 	}
141 	return (cnt == 3);
142 }
143 
144 /*
145  * FUNCTION: parse_bootlist
146  *	Parse the bootlist and add the extra field to mddb_boolist entry to
147  *	conform to devid changes.
148  *
149  * Old format: <drivername>:<minor_number>:<offset>
150  * New format: <drivername>:<minor_number>:<offset>:<devid>
151  * Devid of id0 implies no device id.
152  *
153  * INPUT: *line - contains the mddb_bootlist
154  *	  *tfp - File pointer to the md.conf.tmp file.
155  *
156  * RETURN:
157  *	  0	- Success
158  *	  > 0	- Failure. Errno returned
159  */
160 
161 static int
162 parse_bootlist(char *line, FILE *tfp)
163 {
164 	char output[1024];
165 	char *cp;
166 	int retval = RET_SUCCESS;
167 
168 	(void) memset(output, 0, sizeof (output));
169 
170 	if (line[0] == SYS_COMMENTCHAR) {
171 		output[0] = CONF_COMMENTCHAR;
172 	}
173 	/* move the line start of mddbbootlist */
174 	cp = strstr(line, MDDBBOOTLIST);
175 	if (cp != NULL)
176 		line = cp;
177 
178 	/* grab the "mddb_boolist" word */
179 	cp = strtok(line, "= ");
180 	(void) strcat(output, cp);
181 	(void) strcat(output, "=\042"); /* add back the EQUAL and QUOTE chars */
182 
183 	/*
184 	 * The line passed in is for example,
185 	 * mddb_bootlist1="sd:7:16:id1,sd@SIBM_DDRS34560SUN4.2G2N9688_____/h";
186 	 * At this point mddb_bootlist and "=" have been parsed out.
187 	 * The remaining string consists of driver name, colon separator and
188 	 * the device id(if it exists) within quotes.
189 	 * The deviceid string can contain upper and lower letters, digits
190 	 * and +-.=_~. Quotes, spaces and \n and \t are not
191 	 * allowed. They are converted to either _ or their ascii value.
192 	 * So using space,\n,;and quotes as a separator is safe.
193 	 */
194 
195 	while ((cp = strtok(NULL, " \n\042;")) != NULL) {
196 		(void) strcat(output, cp);
197 		if (!is_devid_added(cp)) {
198 			/* append :id0 for devid */
199 			(void) strcat(strcat(output, ":"),
200 						devid_str_encode(NULL, NULL));
201 
202 			/* no devid => SDS->SLVM migration. Set the flag */
203 			set_upgrade_prop(PROP_DEVID_DESTROY, 1);
204 		}
205 		(void) strcat(output, " "); /* leave space between entries */
206 	}
207 
208 	/* remove the extra space at the end */
209 	output[strlen(output) - 1] = 0;
210 	(void) strcat(output, "\042;\n");
211 	if (fprintf(tfp, "%s", output) < 0) {
212 		retval = errno;
213 	}
214 	return (retval);
215 }
216 
217 /*
218  * FUNCTION: snarf_n_modify_bootlist
219  *  This function stuffs the mddb_bootlist from either etc/system
220  * or kernel/drv/md.conf of the target system into a temporary file tname.
221  * The boolist in the temporary file is in device ID format.
222  *
223  * INPUT: *fp - file pointer that contains the mddb_bootlist.
224  *	  *tname - file into which the modified bootlist will be written to.
225  *	  * buf - buffer handed by upper level routine for reading in contents.
226  *	  * bufsiz - size of the buffer.
227  *	  mddb_file - flag
228  *
229  * RETURN:
230  *	0	- Success
231  *	> 0	- Failure. Errno returned.
232  */
233 
234 static int
235 snarf_n_modify_bootlist(
236 	FILE *fp,	/* File pointer to snarf from */
237 	char *tname,	/* name of the temporary file */
238 	char *buf,	/* Buffer to read into */
239 	int bufsz,	/* buffer size */
240 	ftype_t mddb_file /* flag to indicate if its /etc/system or md.conf */
241 )
242 {
243 	FILE *tfp;
244 	int rval = RET_SUCCESS;
245 	char *fname = SYSTEM_FILE;
246 	char *mddb_start = BEGMDDBSTR;
247 	char *mddb_end = ENDMDDBSTR;
248 	convflag_t cstatus = MD_STR_NOTFOUND;
249 
250 	if (mddb_file == MDDB_MDCONF_FILE) {
251 		fname = MD_CONF;
252 		mddb_start = NEW_BEGMDDBSTR;
253 		mddb_end = NEW_ENDMDDBSTR;
254 	}
255 
256 	if ((tfp = fopen(tname, "a")) == NULL)
257 		return (errno);
258 	debug_printf("Convert from %s\n", fname);
259 
260 	rewind(fp);
261 	while (fgets(buf, bufsz, fp) != NULL) {
262 		if (strcmp(buf, mddb_start) == 0) {
263 			cstatus = MD_STR_START;
264 			if (fprintf(tfp, "%s", NEW_BEGMDDBSTR) < 0) {
265 				rval = errno;
266 				break;
267 			}
268 			continue;
269 		}
270 		if (cstatus == MD_STR_START) {
271 			if (strcmp(buf, mddb_end) == 0) {
272 				cstatus = MD_STR_DONE;
273 				if (fprintf(tfp, "%s", NEW_ENDMDDBSTR) < 0) {
274 					rval = errno;
275 					break;
276 				}
277 
278 				if (mddb_file == MDDB_MDCONF_FILE)
279 					continue;
280 				else
281 					break;
282 			}
283 
284 			rval = parse_bootlist(buf, tfp);
285 			if (rval == RET_SUCCESS)
286 				continue;
287 			else
288 				break;
289 		}
290 		if (mddb_file == MDDB_MDCONF_FILE) {
291 			if (fprintf(tfp, "%s\n", buf) < 0) {
292 				rval = errno;
293 				break;
294 			}
295 		}
296 
297 	} /* while (fgets */
298 
299 	if (cstatus == MD_STR_NOTFOUND || cstatus == MD_STR_START)
300 		rval = RET_ERROR;
301 	(void) fclose(tfp);
302 	return (rval);
303 }
304 
305 
306 /*
307  * FUNCTION: convert_bootlist
308  * Get the bootlist from $ROOT/etc/system and add modified bootlist to
309  * md.conf.
310  * The function converts the mddb_boolist format from that in /etc/system
311  * to md.conf. Also new fields are added to handle the devid id format.
312  * A copy of md.conf is created and the new entries are added to it.
313  * The name of the new file is returned to the calling program.
314  *
315  * Input: system file name
316  *	  md.conf file name
317  *	  pointer to  temp file name.
318  * RETURN:
319  *	 *tname - name of the file that has md.conf + new mddb_boolist entries
320  *	 0	- success
321  *	 -1	- mddb_bootlist not found
322  *	 > 0	- errno
323  *
324  */
325 
326 int
327 convert_bootlist(
328 	char 	*sname, /* system file name */
329 	char	*mdconf, /* md.conf file name */
330 	char 	**tname /* temp file name */
331 )
332 {
333 	FILE	*fp;
334 	char	cmd_buf[MDDB_BOOTLIST_MAX_LEN];
335 	int	retval = RET_SUCCESS;
336 
337 	/* check names */
338 	assert(sname != NULL);
339 	assert(tname != NULL);
340 
341 	/* get temp name */
342 	*tname = tmpnam(NULL);
343 
344 	if ((fp = fopen(sname, "r")) == NULL) {
345 		retval = errno;
346 		goto out;
347 	}
348 	if (valid_bootlist(fp, MDDB_BOOTLIST_MAX_LEN) == RET_SUCCESS) {
349 		if ((retval = copyfile(mdconf, *tname)) == RET_ERROR) {
350 			debug_printf("convert_bootlist: copy %s %s failed\n",
351 				mdconf, *tname);
352 			goto out;
353 		}
354 		retval = snarf_n_modify_bootlist(fp, *tname, cmd_buf,
355 				MDDB_BOOTLIST_MAX_LEN, MDDB_SYS_FILE);
356 	} else {
357 		(void) fclose(fp); /* close system file */
358 		if ((fp = fopen(mdconf, "r")) == NULL) {
359 			retval = errno;
360 			goto out;
361 		}
362 		if (valid_bootlist(fp, MDDB_BOOTLIST_MAX_LEN) == RET_ERROR) {
363 			retval = RET_ERROR;
364 			goto out;
365 		}
366 		retval = snarf_n_modify_bootlist(fp, *tname, cmd_buf,
367 			MDDB_BOOTLIST_MAX_LEN, MDDB_MDCONF_FILE);
368 	}
369 out:
370 	debug_printf("convert_bootlist: retval %d\n", retval);
371 	if (fp != NULL)
372 		(void) fclose(fp);
373 
374 	if ((retval != RET_SUCCESS) && (*tname != NULL)) {
375 		(void) unlink(*tname);
376 		free(*tname);
377 	}
378 	return (retval);
379 }
380