/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" #include #include #include #include #include #include #include #include #include #include #include #include /* * magic strings in system */ #define BEGMDDBSTR "* Begin MDD database info (do not edit)\n" #define ENDMDDBSTR "* End MDD database info (do not edit)\n" #define NEW_BEGMDDBSTR "# Begin MDD database info (do not edit)\n" #define NEW_ENDMDDBSTR "# End MDD database info (do not edit)\n" #define MDDBBOOTLIST "mddb_bootlist" #define SYS_COMMENTCHAR '*' #define CONF_COMMENTCHAR '#' typedef struct { char *prop_name; int prop_val; } md_prop_t; typedef enum { MDDB_SYS_FILE, MDDB_MDCONF_FILE } ftype_t; static md_prop_t upgrade_props[] = { { PROP_KEEP_REPL_STATE, 0 }, { PROP_DEVID_DESTROY, 0}, { NULL, 0} }; /* * The following functions manage upgrade properties */ void set_upgrade_prop(char *prop_name, int val) { md_prop_t *upp; upp = &upgrade_props[0]; for (; upp->prop_name != NULL; upp++) { if (strcmp(upp->prop_name, prop_name) == 0) { upp->prop_val = val; return; } } } int is_upgrade_prop(char *prop_name) { md_prop_t *upp; upp = &upgrade_props[0]; for (; upp->prop_name != NULL; upp++) { if (strcmp(upp->prop_name, prop_name) == 0) { return (upp->prop_val == 1); } } return (0); } int create_in_file_prop(char *prop_name, char *fname) { FILE *fp; md_prop_t *upp; int rval = RET_ERROR; if ((fp = fopen(fname, "a")) == NULL) { return (errno); } upp = &upgrade_props[0]; for (; upp->prop_name != NULL; upp++) { if (strcmp(upp->prop_name, prop_name) == 0) { (void) fprintf(fp, "%s = 1;\n", upp->prop_name); rval = RET_SUCCESS; break; } } (void) fclose(fp); return (rval); } static int is_devid_added(char *str) { int cnt = 0; char *cp; /* there are exactly 3 colons in the string for devid */ for (cnt = 0; cnt < 4; cnt++) { if ((cp = strchr(str, ':')) == NULL) break; str = ++cp; } return (cnt == 3); } /* * FUNCTION: parse_bootlist * Parse the bootlist and add the extra field to mddb_boolist entry to * conform to devid changes. * * Old format: :: * New format: ::: * Devid of id0 implies no device id. * * INPUT: *line - contains the mddb_bootlist * *tfp - File pointer to the md.conf.tmp file. * * RETURN: * 0 - Success * > 0 - Failure. Errno returned */ static int parse_bootlist(char *line, FILE *tfp) { char output[1024]; char *cp; int retval = RET_SUCCESS; (void) memset(output, 0, sizeof (output)); if (line[0] == SYS_COMMENTCHAR) { output[0] = CONF_COMMENTCHAR; } /* move the line start of mddbbootlist */ cp = strstr(line, MDDBBOOTLIST); if (cp != NULL) line = cp; /* grab the "mddb_boolist" word */ cp = strtok(line, "= "); (void) strcat(output, cp); (void) strcat(output, "=\042"); /* add back the EQUAL and QUOTE chars */ /* * The line passed in is for example, * mddb_bootlist1="sd:7:16:id1,sd@SIBM_DDRS34560SUN4.2G2N9688_____/h"; * At this point mddb_bootlist and "=" have been parsed out. * The remaining string consists of driver name, colon separator and * the device id(if it exists) within quotes. * The deviceid string can contain upper and lower letters, digits * and +-.=_~. Quotes, spaces and \n and \t are not * allowed. They are converted to either _ or their ascii value. * So using space,\n,;and quotes as a separator is safe. */ while ((cp = strtok(NULL, " \n\042;")) != NULL) { (void) strcat(output, cp); if (!is_devid_added(cp)) { /* append :id0 for devid */ (void) strcat(strcat(output, ":"), devid_str_encode(NULL, NULL)); /* no devid => SDS->SLVM migration. Set the flag */ set_upgrade_prop(PROP_DEVID_DESTROY, 1); } (void) strcat(output, " "); /* leave space between entries */ } /* remove the extra space at the end */ output[strlen(output) - 1] = 0; (void) strcat(output, "\042;\n"); if (fprintf(tfp, "%s", output) < 0) { retval = errno; } return (retval); } /* * FUNCTION: snarf_n_modify_bootlist * This function stuffs the mddb_bootlist from either etc/system * or kernel/drv/md.conf of the target system into a temporary file tname. * The boolist in the temporary file is in device ID format. * * INPUT: *fp - file pointer that contains the mddb_bootlist. * *tname - file into which the modified bootlist will be written to. * * buf - buffer handed by upper level routine for reading in contents. * * bufsiz - size of the buffer. * mddb_file - flag * * RETURN: * 0 - Success * > 0 - Failure. Errno returned. */ static int snarf_n_modify_bootlist( FILE *fp, /* File pointer to snarf from */ char *tname, /* name of the temporary file */ char *buf, /* Buffer to read into */ int bufsz, /* buffer size */ ftype_t mddb_file /* flag to indicate if its /etc/system or md.conf */ ) { FILE *tfp; int rval = RET_SUCCESS; char *fname = SYSTEM_FILE; char *mddb_start = BEGMDDBSTR; char *mddb_end = ENDMDDBSTR; convflag_t cstatus = MD_STR_NOTFOUND; if (mddb_file == MDDB_MDCONF_FILE) { fname = MD_CONF; mddb_start = NEW_BEGMDDBSTR; mddb_end = NEW_ENDMDDBSTR; } if ((tfp = fopen(tname, "a")) == NULL) return (errno); debug_printf("Convert from %s\n", fname); rewind(fp); while (fgets(buf, bufsz, fp) != NULL) { if (strcmp(buf, mddb_start) == 0) { cstatus = MD_STR_START; if (fprintf(tfp, "%s", NEW_BEGMDDBSTR) < 0) { rval = errno; break; } continue; } if (cstatus == MD_STR_START) { if (strcmp(buf, mddb_end) == 0) { cstatus = MD_STR_DONE; if (fprintf(tfp, "%s", NEW_ENDMDDBSTR) < 0) { rval = errno; break; } if (mddb_file == MDDB_MDCONF_FILE) continue; else break; } rval = parse_bootlist(buf, tfp); if (rval == RET_SUCCESS) continue; else break; } if (mddb_file == MDDB_MDCONF_FILE) { if (fprintf(tfp, "%s\n", buf) < 0) { rval = errno; break; } } } /* while (fgets */ if (cstatus == MD_STR_NOTFOUND || cstatus == MD_STR_START) rval = RET_ERROR; (void) fclose(tfp); return (rval); } /* * FUNCTION: convert_bootlist * Get the bootlist from $ROOT/etc/system and add modified bootlist to * md.conf. * The function converts the mddb_boolist format from that in /etc/system * to md.conf. Also new fields are added to handle the devid id format. * A copy of md.conf is created and the new entries are added to it. * The name of the new file is returned to the calling program. * * Input: system file name * md.conf file name * pointer to temp file name. * RETURN: * *tname - name of the file that has md.conf + new mddb_boolist entries * 0 - success * -1 - mddb_bootlist not found * > 0 - errno * */ int convert_bootlist( char *sname, /* system file name */ char *mdconf, /* md.conf file name */ char **tname /* temp file name */ ) { FILE *fp; char cmd_buf[MDDB_BOOTLIST_MAX_LEN]; int retval = RET_SUCCESS; /* check names */ assert(sname != NULL); assert(tname != NULL); /* get temp name */ *tname = tmpnam(NULL); if ((fp = fopen(sname, "r")) == NULL) { retval = errno; goto out; } if (valid_bootlist(fp, MDDB_BOOTLIST_MAX_LEN) == RET_SUCCESS) { if ((retval = copyfile(mdconf, *tname)) == RET_ERROR) { debug_printf("convert_bootlist: copy %s %s failed\n", mdconf, *tname); goto out; } retval = snarf_n_modify_bootlist(fp, *tname, cmd_buf, MDDB_BOOTLIST_MAX_LEN, MDDB_SYS_FILE); } else { (void) fclose(fp); /* close system file */ if ((fp = fopen(mdconf, "r")) == NULL) { retval = errno; goto out; } if (valid_bootlist(fp, MDDB_BOOTLIST_MAX_LEN) == RET_ERROR) { retval = RET_ERROR; goto out; } retval = snarf_n_modify_bootlist(fp, *tname, cmd_buf, MDDB_BOOTLIST_MAX_LEN, MDDB_MDCONF_FILE); } out: debug_printf("convert_bootlist: retval %d\n", retval); if (fp != NULL) (void) fclose(fp); if ((retval != RET_SUCCESS) && (*tname != NULL)) { (void) unlink(*tname); free(*tname); } return (retval); }