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
set_upgrade_prop(char * prop_name,int val)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
is_upgrade_prop(char * prop_name)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
create_in_file_prop(char * prop_name,char * fname)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
is_devid_added(char * str)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
parse_bootlist(char * line,FILE * tfp)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
snarf_n_modify_bootlist(FILE * fp,char * tname,char * buf,int bufsz,ftype_t mddb_file)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
convert_bootlist(char * sname,char * mdconf,char ** tname)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