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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 /* 29 * Just in case we're not in a build environment, make sure that 30 * TEXT_DOMAIN gets set to something. 31 */ 32 #if !defined(TEXT_DOMAIN) 33 #define TEXT_DOMAIN "SYS_TEST" 34 #endif 35 36 /* 37 * patch /kernel/drv/md.conf file 38 */ 39 #include <sys/types.h> 40 #include <sys/stat.h> 41 #include <meta.h> 42 #include <sys/lvm/md_mddb.h> 43 44 /* 45 * magic strings in system 46 */ 47 #define BEGROOTSTR "* Begin MDD root info (do not edit)\n" 48 #define ENDROOTSTR "* End MDD root info (do not edit)\n" 49 #define BEGMDDBSTR "# Begin MDD database info (do not edit)\n" 50 #define ENDMDDBSTR "# End MDD database info (do not edit)\n" 51 52 /* 53 * copy system file, yank root and database lines 54 */ 55 int 56 meta_systemfile_copy( 57 char *sname, /* system file name */ 58 int doroot, /* remove mdd root stuff */ 59 int domddb, /* remove mdd database stuff */ 60 int doit, /* really copy file */ 61 int verbose, /* show what we're doing */ 62 char **tname, /* returned temp file name */ 63 FILE **tfp, /* returned open FILE */ 64 md_error_t *ep /* returned error */ 65 ) 66 { 67 FILE *fp; 68 struct stat sbuf; 69 char buf[MDDB_BOOTLIST_MAX_LEN]; 70 int delroot = 0; 71 int delmddb = 0; 72 73 /* check names */ 74 assert(sname != NULL); 75 assert(tname != NULL); 76 assert(tfp != NULL); 77 78 /* get temp name */ 79 *tfp = NULL; 80 *tname = Malloc(strlen(sname) + strlen(".tmp") + 1); 81 (void) strcpy(*tname, sname); 82 (void) strcat(*tname, ".tmp"); 83 84 /* copy system file, yank stuff */ 85 if (((fp = fopen(sname, "r")) == NULL) || 86 (fstat(fileno(fp), &sbuf) != 0)) { 87 if (errno != ENOENT) { 88 (void) mdsyserror(ep, errno, sname); 89 goto out; 90 } 91 } 92 if (doit) { 93 if ((*tfp = fopen(*tname, "w")) == NULL) { 94 /* 95 * If we are on the miniroot we need to create 96 * files in /var/tmp. Opening a writable file 97 * in the miniroot result is EROFS error. 98 */ 99 if (errno != EROFS) { 100 (void) mdsyserror(ep, errno, *tname); 101 goto out; 102 } 103 Free(*tname); 104 *tname = tempnam("/var/tmp", "svm_"); 105 if (*tname == NULL) { 106 (void) mdsyserror(ep, errno, NULL); 107 goto out; 108 } 109 if ((*tfp = fopen(*tname, "w")) == NULL) { 110 (void) mdsyserror(ep, errno, *tname); 111 goto out; 112 } 113 } 114 if (fp != NULL) { 115 if ((fchmod(fileno(*tfp), (sbuf.st_mode & 0777)) 116 != 0) || 117 (fchown(fileno(*tfp), sbuf.st_uid, sbuf.st_gid) 118 != 0)) { 119 (void) mdsyserror(ep, errno, *tname); 120 goto out; 121 } 122 } 123 } 124 if (verbose) { 125 (void) printf(dgettext(TEXT_DOMAIN, 126 "Delete the following lines from %s:\n\n"), sname); 127 } 128 while ((fp != NULL) && (fgets(buf, sizeof (buf), fp) != NULL)) { 129 if ((doroot) && (strcmp(buf, BEGROOTSTR) == 0)) { 130 delroot = 1; 131 if (verbose) 132 (void) printf("%s", buf); 133 continue; 134 } 135 if (delroot) { 136 if (strcmp(buf, ENDROOTSTR) == 0) 137 delroot = 0; 138 if (verbose) 139 (void) printf("%s", buf); 140 continue; 141 } 142 if ((domddb) && (strcmp(buf, BEGMDDBSTR) == 0)) { 143 delmddb = 1; 144 if (verbose) 145 (void) printf("%s", buf); 146 continue; 147 } 148 if (delmddb) { 149 if (strcmp(buf, ENDMDDBSTR) == 0) 150 delmddb = 0; 151 if (verbose) 152 (void) printf("%s", buf); 153 continue; 154 } 155 if (doit) { 156 if (fputs(buf, *tfp) == EOF) { 157 (void) mdsyserror(ep, errno, *tname); 158 goto out; 159 } 160 } 161 } 162 if (fp != NULL) { 163 if ((! feof(fp)) || 164 (fclose(fp) != 0)) { 165 (void) mdsyserror(ep, errno, sname); 166 goto out; 167 } 168 fp = NULL; 169 } 170 if (verbose) 171 (void) printf("\n"); 172 173 /* make sure we didn't stop mid-delete */ 174 if ((delroot) || (delmddb)) { 175 (void) mderror(ep, MDE_SYSTEM_FILE, sname); 176 goto out; 177 } 178 179 /* flush stuff */ 180 if (doit) { 181 if ((fflush(*tfp) != 0) || 182 (fsync(fileno(*tfp)) != 0)) { 183 (void) mdsyserror(ep, errno, *tname); 184 goto out; 185 } 186 } 187 188 /* return success */ 189 return (0); 190 191 /* cleanup, return error */ 192 out: 193 if (fp != NULL) 194 (void) fclose(fp); 195 if (*tname != NULL) { 196 (void) unlink(*tname); 197 Free(*tname); 198 } 199 if (*tfp != NULL) 200 (void) fclose(*tfp); 201 return (-1); 202 } 203 204 /* 205 * append root on MD lines to system 206 */ 207 int 208 meta_systemfile_append_mdroot( 209 mdname_t *rootnp, /* root device name */ 210 char *sname, /* system file name */ 211 char *tname, /* temp file name */ 212 FILE *tfp, /* temp FILE */ 213 int ismeta, /* is a metadevice */ 214 int doit, /* really patch file */ 215 int verbose, /* show what we're doing */ 216 md_error_t *ep 217 ) 218 { 219 char *longblkname; 220 221 /* check names */ 222 assert(sname != NULL); 223 assert(tname != NULL); 224 assert(!doit || tfp != NULL); 225 226 /* get root /devices name */ 227 if ((longblkname = metagetdevicesname(rootnp, ep)) == NULL) 228 return (-1); 229 230 /* add header */ 231 if (verbose) { 232 (void) printf(dgettext(TEXT_DOMAIN, 233 "Add the following lines to %s:\n\n"), sname); 234 (void) printf("%s", BEGROOTSTR); 235 } 236 if (doit) { 237 if (fprintf(tfp, "%s", BEGROOTSTR) == EOF) { 238 return (mdsyserror(ep, errno, tname)); 239 } 240 } 241 242 /* add rootdev */ 243 if (ismeta) { 244 if (verbose) 245 (void) printf("rootdev:%s\n", longblkname); 246 if (doit) { 247 if (fprintf(tfp, "rootdev:%s\n", longblkname) == EOF) { 248 return (mdsyserror(ep, errno, tname)); 249 } 250 } 251 } 252 253 /* add trailer */ 254 if (verbose) { 255 (void) printf("%s\n", ENDROOTSTR); 256 } 257 if (doit) { 258 if (fprintf(tfp, "%s", ENDROOTSTR) == EOF) { 259 return (mdsyserror(ep, errno, tname)); 260 } 261 } 262 263 /* flush stuff */ 264 if (doit) { 265 if ((fflush(tfp) != 0) || 266 (fsync(fileno(tfp)) != 0)) { 267 return (mdsyserror(ep, errno, tname)); 268 } 269 } 270 271 /* return success */ 272 return (0); 273 } 274 275 /* 276 * parse mddb.cf line 277 * 278 * Caller of this routine needs to free the device id string that 279 * is passed back during a successful return. 280 */ 281 static int 282 confline( 283 char *line, /* line in file */ 284 char **driver, /* returned driver name */ 285 minor_t *mnump, /* returned minor number */ 286 daddr_t *block, /* returned block offset */ 287 char **devid_char_pp /* returned device id string */ 288 ) 289 { 290 char *p = line; 291 int chksum = 0; 292 int i; 293 uint_t devid_size; 294 295 if (*p == '#') { 296 return (-1); 297 } 298 *driver = p; 299 while ((*p != ' ') && (*p != '\t')) 300 chksum += *p++; 301 if (*driver == p) { 302 return (-1); 303 } 304 *p++ = '\0'; 305 *mnump = strtoul(p, &p, 10); 306 chksum += *mnump; 307 *block = strtol(p, &p, 10); 308 chksum += *block; 309 310 /* parse out devid */ 311 while ((*p == ' ') || (*p == '\t')) { 312 p++; 313 } 314 i = strcspn(p, " \t"); 315 *devid_char_pp = Malloc(i+1); 316 (void) strncpy(*devid_char_pp, p, i); 317 (*devid_char_pp)[i] = '\0'; 318 devid_size = i; 319 p += devid_size; 320 for (i = 0; i < devid_size; i++) { 321 chksum += (*devid_char_pp)[i]; 322 } 323 324 chksum += strtol(p, &p, 10); 325 if (chksum != 42) { 326 Free (*devid_char_pp); 327 devid_char_pp = NULL; 328 return (-1); 329 } 330 return (0); 331 } 332 333 /* 334 * append MDDB lines to system 335 */ 336 int 337 meta_systemfile_append_mddb( 338 char *cname, /* mddb.cf file name */ 339 char *sname, /* system file name */ 340 char *tname, /* temp file name */ 341 FILE *tfp, /* temp FILE */ 342 int doit, /* really patch file */ 343 int verbose, /* show what we're doing */ 344 int check, /* if set check that mddb.cf is not */ 345 /* empty before updating md.conf */ 346 md_error_t *ep /* returned error */ 347 ) 348 { 349 FILE *cfp = NULL; 350 char buf[1024]; 351 char *p; 352 int i; 353 char *driver; 354 minor_t mnum; 355 daddr_t block; 356 char line[MDDB_BOOTLIST_MAX_LEN]; 357 char entry[MDDB_BOOTLIST_MAX_LEN]; 358 char *devid_char_p = NULL; 359 struct stat statbuf; 360 361 /* check names */ 362 assert(cname != NULL); 363 assert(sname != NULL); 364 assert(tname != NULL); 365 assert(!doit || tfp != NULL); 366 367 /* open database conf file */ 368 if ((cfp = fopen(cname, "r")) == NULL) { 369 (void) mdsyserror(ep, errno, cname); 370 goto out; 371 } 372 /* Check that it is an ordinary file */ 373 if (stat(cname, &statbuf) != 0) { 374 (void) mdsyserror(ep, errno, cname); 375 goto out; 376 } 377 if ((statbuf.st_mode & S_IFMT) != S_IFREG) { 378 (void) mderror(ep, MDE_MDDB_FILE, cname); 379 goto out; 380 } 381 382 /* add header */ 383 if (verbose) { 384 (void) printf(dgettext(TEXT_DOMAIN, 385 "Add the following lines to %s:\n\n"), sname); 386 (void) printf("%s", BEGMDDBSTR); 387 } 388 if (doit) { 389 if (fprintf(tfp, "%s", BEGMDDBSTR) == EOF) { 390 (void) mdsyserror(ep, errno, tname); 391 goto out; 392 } 393 } 394 395 /* append database lines */ 396 while (((p = fgets(buf, sizeof (buf), cfp)) != NULL) && 397 (confline(buf, &driver, &mnum, &block, &devid_char_p) != 0)) 398 ; 399 /* 400 * It is possible to be in a state where the md_devid_destroy flag 401 * has been set and the mdmonitor service not be enabled on reboot 402 * such that metadevadm doesn't get run and the entries in mddb.cf 403 * recreated. The following checks for this condition and will not 404 * allow an empty mddb.cf to overwrite md.conf and lose the users 405 * configuration 406 */ 407 if (check && p == NULL) { 408 (void) mderror(ep, MDE_MDDB_FILE, cname); 409 goto out; 410 } 411 412 for (i = 1; ((p != NULL) && (i <= MDDB_MAX_PATCH)); ++i) { 413 (void) snprintf(line, sizeof (line), 414 "mddb_bootlist%d=\"%s:%lu:%ld:%s", 415 i, driver, mnum, block, devid_char_p); 416 if (devid_char_p != NULL) { 417 free(devid_char_p); 418 devid_char_p = NULL; 419 } 420 421 while ((p = fgets(buf, sizeof (buf), cfp)) != NULL) { 422 if (confline(buf, &driver, &mnum, &block, 423 &devid_char_p) != 0) { 424 continue; 425 } 426 (void) snprintf(entry, sizeof (entry), " %s:%lu:%ld:%s", 427 driver, mnum, block, devid_char_p); 428 429 if ((strlen(line) + strlen(entry) + 4) > sizeof (line)) 430 break; 431 (void) strcat(line, entry); 432 if (devid_char_p != NULL) { 433 free(devid_char_p); 434 devid_char_p = NULL; 435 } 436 } 437 if (verbose) 438 /* CSTYLED */ 439 (void) printf("%s\";\n", line); 440 if (doit) { 441 /* CSTYLED */ 442 if (fprintf(tfp, "%s\";\n", line) <= 0) { 443 (void) mdsyserror(ep, errno, tname); 444 goto out; 445 } 446 } 447 } 448 449 if (devid_char_p != NULL) { 450 free(devid_char_p); 451 devid_char_p = NULL; 452 } 453 454 /* add trailer */ 455 if (verbose) 456 (void) printf("%s\n", ENDMDDBSTR); 457 if (doit) { 458 if (fprintf(tfp, "%s", ENDMDDBSTR) == EOF) { 459 (void) mdsyserror(ep, errno, tname); 460 goto out; 461 } 462 } 463 464 /* close database conf file */ 465 if (fclose(cfp) != 0) { 466 cfp = NULL; 467 (void) mdsyserror(ep, errno, cname); 468 goto out; 469 } 470 cfp = NULL; 471 472 /* flush stuff */ 473 if (doit) { 474 if ((fflush(tfp) != 0) || 475 (fsync(fileno(tfp)) != 0)) { 476 (void) mdsyserror(ep, errno, tname); 477 goto out; 478 } 479 } 480 481 /* return success */ 482 return (0); 483 484 /* cleanup, return error */ 485 out: 486 if (cfp != NULL) 487 (void) fclose(cfp); 488 return (-1); 489 } 490