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