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