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 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <stdarg.h> 30 #include <sys/types.h> 31 #include <sys/stat.h> 32 #include <fcntl.h> 33 #include <errno.h> 34 #include <unistd.h> 35 #include <stropts.h> 36 #include <strings.h> 37 #include <sys/param.h> 38 #include <libdevinfo.h> 39 #include <locale.h> 40 #include <libintl.h> 41 #include <devid.h> 42 #include <sys/modctl.h> /* for MAXMODCONFNAME */ 43 #include <sys/scsi/adapters/scsi_vhci.h> 44 45 /* 46 * SAVE_DIR is the directory in which system files are saved. 47 * SAVE_DIR must be under the root filesystem, as this program is 48 * typically run before any other filesystems are mounted. 49 */ 50 #define SAVE_DIR "/etc/mpxio" 51 #define VHCI_CTL_NODE "/devices/scsi_vhci:devctl" 52 53 /* nvlist property names, these are ALL string types */ 54 #define NVL_DEVID "nvl-devid" 55 #define NVL_PATH "nvl-path" 56 #define NVL_PHYSPATH "nvl-physpath" 57 #define NVL_MPXPATH "nvl-mpxiopath" 58 #define NVL_MPXEN "nvl-mpxioenabled" 59 60 #define MPX_LIST 0x01 61 #define MPX_MAP 0x02 62 #define MPX_CAPABLE_CTRL 0x04 63 #define MPX_INIT 0x08 64 #define MPX_PHYSICAL 0x10 65 #define MPX_BOOTPATH 0x20 66 #define MPX_UPDATEVFSTAB 0x40 67 #define MPX_USAGE 0x80 68 #define MSG_INFO 0x01 69 #define MSG_ERROR 0x02 70 #define MSG_PANIC 0x04 71 72 #define BOOT 0x01 73 #define NONBOOT 0x00 74 75 static di_node_t devinfo_root = DI_NODE_NIL; 76 static char *ondiskname = "/etc/mpxio/devid_path.cache"; 77 78 /* 79 * We use devid-keyed nvlists to keep track of the guid, traditional and 80 * MPxIO-enabled /dev/rdsk paths. Each of these nvlists is eventually 81 * added to our global nvlist and our on-disk nvlist. 82 */ 83 static nvlist_t *mapnvl; 84 static int mpxenabled = 0; 85 static int limctrl = -1; 86 static int guid = 0; 87 static char *drvlimit; 88 static int globarg = 0; 89 static int debugflag = 0; 90 static char *devicep; 91 static int readonlyroot = 0; 92 static int cap_N_option = 0; 93 94 static void print_mpx_capable(di_node_t curnode); 95 static int popcheck_devnvl(di_node_t thisnode, nvlist_t *devnvl, 96 char *strdevid); 97 static int mpxio_nvl_boilerplate(di_node_t curnode); 98 static int validate_devnvl(); 99 static void report_map(char *argdev, int physpath); 100 static void list_devs(int listguids, int ctrl); 101 static void logmsg(int level, const char *msg, ...); 102 static char *find_link(di_node_t cnode); 103 static void usage(); 104 static void parse_args(int argc, char *argv[]); 105 static void get_devid(di_node_t node, ddi_devid_t *thisdevid); 106 static int print_bootpath(); 107 static void vhci_to_phci(char *devpath, char *physpath); 108 static int update_vfstab(); 109 110 int 111 main(int argc, char **argv) 112 { 113 struct stat cachestat; 114 int mapfd = 0; 115 int rv = 0; 116 char *ondiskbuf; 117 size_t newsz = 0; 118 119 parse_args(argc, argv); 120 errno = 0; 121 devinfo_root = di_init("/", DINFOCPYALL|DINFOFORCE); 122 logmsg(MSG_INFO, "errno = %d after " 123 "di_init(/,DINFOCPYALL|DINFOFORCE)\n", errno); 124 if (devinfo_root == NULL) { 125 logmsg(MSG_ERROR, 126 gettext("Unable to take device tree snapshot " 127 "(%s: %d)\n"), strerror(errno), errno); 128 return (-1); 129 } 130 logmsg(MSG_INFO, "opened root di_node\n"); 131 132 if (globarg == MPX_CAPABLE_CTRL) { 133 /* we just want to find MPxIO-capable controllers and exit */ 134 if (drvlimit != NULL) { 135 print_mpx_capable(di_drv_first_node(drvlimit, 136 devinfo_root)); 137 } else { 138 print_mpx_capable(di_drv_first_node("fp", 139 devinfo_root)); 140 print_mpx_capable(di_drv_first_node("mpt", 141 devinfo_root)); 142 } 143 di_fini(devinfo_root); 144 return (0); 145 } 146 147 mapfd = open(ondiskname, O_RDWR|O_CREAT|O_SYNC, S_IRUSR | S_IWUSR); 148 if (mapfd < 0) { 149 /* we could be in single-user, so try for RO */ 150 if ((mapfd = open(ondiskname, O_RDONLY)) < 0) { 151 logmsg(MSG_ERROR, 152 gettext("Unable to open or create %s:%s\n"), 153 ondiskname, strerror(errno)); 154 return (errno); 155 } 156 readonlyroot = 1; 157 } 158 159 if (stat(ondiskname, &cachestat) != 0) { 160 logmsg(MSG_ERROR, 161 gettext("Unable to stat() %s: %s\n"), 162 ondiskname, strerror(errno)); 163 return (errno); 164 } 165 ondiskbuf = calloc(1, cachestat.st_size); 166 if (ondiskbuf == NULL) { 167 logmsg(MSG_ERROR, 168 gettext("Unable to allocate memory for the devid " 169 "cache file: %s\n"), strerror(errno)); 170 return (errno); 171 } 172 rv = read(mapfd, ondiskbuf, cachestat.st_size); 173 if (rv != cachestat.st_size) { 174 logmsg(MSG_ERROR, 175 gettext("Unable to read all of devid cache file (got %d " 176 "from expected %d bytes): %s\n"), 177 rv, cachestat.st_size, strerror(errno)); 178 return (errno); 179 } 180 errno = 0; 181 rv = nvlist_unpack(ondiskbuf, cachestat.st_size, &mapnvl, 0); 182 if (rv) { 183 logmsg(MSG_INFO, 184 "Unable to unpack devid cache file %s: %s (%d)\n", 185 ondiskname, strerror(rv), rv); 186 if (nvlist_alloc(&mapnvl, NV_UNIQUE_NAME, 0) != 0) { 187 logmsg(MSG_ERROR, 188 gettext("Unable to allocate root property" 189 "list\n")); 190 return (errno); 191 } 192 } 193 free(ondiskbuf); 194 195 if (validate_devnvl() < 0) { 196 logmsg(MSG_ERROR, 197 gettext("unable to validate kernel with on-disk devid " 198 "cache file\n")); 199 return (errno); 200 } 201 202 /* 203 * If we're in single-user mode or maintenance mode, we won't 204 * necessarily have a writable root device (ZFSroot; ufs root is 205 * different in that we _do_ have a writable root device. 206 * This causes problems for the devlink calls (see 207 * $SRC/lib/libdevinfo/devinfo_devlink.c) and we do not try to 208 * write out the devnvl if root is readonly. 209 */ 210 if (!readonlyroot) { 211 rv = nvlist_size(mapnvl, &newsz, NV_ENCODE_NATIVE); 212 if (rv) { 213 logmsg(MSG_ERROR, 214 gettext("Unable to determine size of packed " 215 "on-disk devid cache file %s: %s (%d).\n"), 216 ondiskname, strerror(rv), rv); 217 logmsg(MSG_ERROR, gettext("Terminating\n")); 218 nvlist_free(mapnvl); 219 (void) close(mapfd); 220 return (rv); 221 } 222 223 if ((ondiskbuf = calloc(1, newsz)) == NULL) { 224 logmsg(MSG_ERROR, 225 "Unable to allocate space for writing out new " 226 "on-disk devid cache file: %s\n", strerror(errno)); 227 (void) close(mapfd); 228 nvlist_free(mapnvl); 229 return (errno); 230 } 231 232 rv = nvlist_pack(mapnvl, &ondiskbuf, &newsz, 233 NV_ENCODE_NATIVE, 0); 234 if (rv) { 235 logmsg(MSG_ERROR, 236 gettext("Unable to pack on-disk devid cache " 237 "file: %s (%d)\n"), strerror(rv), rv); 238 (void) close(mapfd); 239 free(ondiskbuf); 240 nvlist_free(mapnvl); 241 return (rv); 242 } 243 244 rv = lseek(mapfd, 0, 0); 245 if (rv == -1) { 246 logmsg(MSG_ERROR, 247 gettext("Unable to seek to start of devid cache " 248 "file: %s (%d)\n"), strerror(errno), errno); 249 (void) close(mapfd); 250 free(ondiskbuf); 251 nvlist_free(mapnvl); 252 return (-1); 253 } 254 255 if (write(mapfd, ondiskbuf, newsz) != newsz) { 256 logmsg(MSG_ERROR, 257 gettext("Unable to completely write out " 258 "on-disk devid cache file: %s\n"), strerror(errno)); 259 (void) close(mapfd); 260 nvlist_free(mapnvl); 261 free(ondiskbuf); 262 return (errno); 263 } 264 } /* !readonlyroot */ 265 266 /* Now we can process the command line args */ 267 if (globarg == MPX_PHYSICAL) { 268 report_map(devicep, BOOT); 269 } else if (globarg == MPX_BOOTPATH) { 270 rv = print_bootpath(); 271 di_fini(devinfo_root); 272 return (rv); 273 } else if (globarg == MPX_UPDATEVFSTAB) { 274 rv = update_vfstab(); 275 di_fini(devinfo_root); 276 return (rv); 277 } else if (globarg != MPX_INIT) { 278 if (globarg & MPX_LIST) 279 list_devs(guid, limctrl); 280 281 if (globarg == MPX_MAP) 282 report_map(devicep, NONBOOT); 283 } else { 284 logmsg(MSG_INFO, "\nprivate devid cache file initialised\n"); 285 } 286 287 nvlist_free(mapnvl); 288 di_fini(devinfo_root); 289 return (0); 290 } 291 292 static void 293 usage() 294 { 295 (void) fprintf(stderr, 296 gettext("usage: stmsboot_util -b | -m devname | " 297 "-l <ctrl> | -L | [-g] | -n | -N | -i | -p devname\n")); 298 (void) fprintf(stderr, "\n\n"); 299 (void) fprintf(stderr, gettext("\t-h\tprint this usage message\n")); 300 (void) fprintf(stderr, gettext("\t-b\tretrieve the system's bootpath " 301 "setting\n")); 302 (void) fprintf(stderr, gettext("\t-m devname\n")); 303 (void) fprintf(stderr, gettext("\t\tReports the current mapping for " 304 "devname\n")); 305 (void) fprintf(stderr, gettext("\t-g\tprint the GUID for MPxIO-capable " 306 "devices. This\n")); 307 (void) fprintf(stderr, gettext("\t\toption is only valid with the -L " 308 "or -l options\n")); 309 (void) fprintf(stderr, gettext("\t-L | -l <ctrl>\n")); 310 (void) fprintf(stderr, gettext("\t\tList the 'native' to 'MPxIO' " 311 "device mappings. If <ctrl>\n")); 312 (void) fprintf(stderr, gettext("\t\tis specified, only print mappings " 313 "for those devices\n")); 314 (void) fprintf(stderr, gettext("\t\tattached via the specified " 315 "controller.\n")); 316 (void) fprintf(stderr, gettext("\t-i\tinitialise the private devid " 317 "cache file and exit\n")); 318 (void) fprintf(stderr, gettext("\t\tThis option excludes all " 319 "others.\n")); 320 (void) fprintf(stderr, gettext("\t-n\tprint the devfs paths for " 321 "multipath-capable\n")); 322 (void) fprintf(stderr, gettext("\t\tcontroller ports.\n")); 323 (void) fprintf(stderr, gettext("\t-N\tprint the device aliases of " 324 "multipath-capable\n")); 325 (void) fprintf(stderr, gettext("\t\tcontroller ports.\n")); 326 (void) fprintf(stderr, gettext("\t-p\tdevname\n")); 327 (void) fprintf(stderr, gettext("\t\tThis option provides the physical " 328 "devfs path for\n")); 329 (void) fprintf(stderr, gettext("\t\ta specific device (devname). Used " 330 "to set the bootpath\n")); 331 (void) fprintf(stderr, gettext("\t\tvariable on x86/x64 systems\n")); 332 (void) fprintf(stderr, gettext("\t-u\ttranslates device mappings in " 333 "/etc/vfstab as \n")); 334 (void) fprintf(stderr, gettext("\t\trequired. The output is written " 335 "to /etc/mpxio/vfstab.new\n\n")); 336 exit(2); 337 } 338 339 static void 340 parse_args(int argc, char *argv[]) 341 { 342 char opt; 343 344 if (argc == 1) 345 usage(); 346 347 /* 348 * -b prints the bootpath property 349 * -d turns on debug mode for this utility (copious output!) 350 * -D drvname 351 * if supplied, indicates that we're going to operate on 352 * devices attached to this driver. 353 * -g if (-l or -L), prints guids for devices rather than paths 354 * -h prints the usage() help text. 355 * -i initialises the cache file and exits. 356 * -l controller 357 * list non-STMS to STMS device name mappings for the specific 358 * controller, when MPxIO is enabled only. 359 * -L list non-STMS to STMS device name mappings for all controllers 360 * when MPxIO is enabled only. 361 * -m devname 362 * prints the device path (/dev/rdsk) that devname maps to 363 * in the currently-running system. 364 * -n 365 * if supplied, returns name of STMS-capable controller nodes. 366 * If the -D drvname option is specified as well, we only report 367 * nodes attached with drvname. 368 * -N 369 * same as the -n option, except that we only print the 370 * node-name (dev_info :: devi_node_name). Multiple instances 371 * through the libdevinfo snapshot are uniqified and separated 372 * by the "|" character for direct use by egrep(1). 373 * -p devname 374 * prints the physical devfs path for devname. Only used to 375 * determine the bootpath. 376 * -u 377 * remaps devices in /etc/vfstab, saving the newly generated 378 * file to /etc/mpxio/vfstab.new. If we have any remapped 379 * devices, exit with status 0, otherwise -1 for error. 380 */ 381 while ((opt = getopt(argc, argv, "bdD:ghil:Lm:nNp:u")) != EOF) { 382 switch (opt) { 383 case 'b': 384 globarg = MPX_BOOTPATH; 385 break; 386 case 'd': 387 debugflag = 1; 388 break; 389 case 'D': 390 if ((drvlimit = calloc(1, MAXMODCONFNAME)) == NULL) { 391 logmsg(MSG_ERROR, 392 gettext("Unable to allocate memory for a " 393 "driver name: %s\n"), strerror(errno)); 394 exit(errno); 395 } 396 bcopy(optarg, drvlimit, strlen(optarg)); 397 /* update this if adding support for a new driver */ 398 if ((strncmp(drvlimit, "fp", 2) == NULL) && 399 (strncmp(drvlimit, "mpt", 3) == NULL)) { 400 logmsg(MSG_ERROR, 401 gettext("invalid parent driver (%s) " 402 "specified"), drvlimit); 403 usage(); 404 } 405 break; 406 case 'h': 407 /* Just drop out and print the usage() output */ 408 globarg = MPX_USAGE; 409 break; 410 case 'i': 411 globarg = MPX_INIT; 412 break; 413 case 'l': 414 globarg |= MPX_LIST; 415 limctrl = (int)atol(optarg); 416 if (limctrl < 0) { 417 logmsg(MSG_INFO, 418 gettext("invalid controller number " 419 "(%d), checking all controllers\n"), 420 limctrl); 421 } 422 break; 423 case 'L': 424 globarg |= MPX_LIST; 425 break; 426 case 'g': 427 guid = 1; 428 break; 429 case 'm': 430 globarg = MPX_MAP; 431 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 432 logmsg(MSG_ERROR, 433 gettext("Unable to allocate space for a " 434 "device name\n")); 435 exit(errno); 436 } 437 devicep = strdup(optarg); 438 break; 439 case 'N': 440 cap_N_option = 1; 441 globarg = MPX_CAPABLE_CTRL; 442 break; 443 case 'n': 444 globarg = MPX_CAPABLE_CTRL; 445 break; 446 case 'p': 447 globarg = MPX_PHYSICAL; 448 if ((devicep = calloc(1, MAXPATHLEN)) == NULL) { 449 logmsg(MSG_ERROR, 450 gettext("Unable to allocate space for a " 451 "device name\n")); 452 exit(errno); 453 } 454 devicep = strdup(optarg); 455 break; 456 case 'u': 457 globarg = MPX_UPDATEVFSTAB; 458 break; 459 default: 460 logmsg(MSG_ERROR, 461 gettext("Invalid command line option (%c)\n"), 462 opt); 463 usage(); 464 } 465 } 466 467 if ((globarg >= MPX_USAGE) || (guid && (globarg != MPX_LIST))) 468 usage(); 469 470 if ((drvlimit != NULL) && 471 ((globarg != MPX_LIST) && 472 (globarg != MPX_CAPABLE_CTRL))) 473 usage(); 474 } 475 476 static void 477 logmsg(int level, const char *msg, ...) 478 { 479 va_list ap; 480 481 if ((level >= MSG_ERROR) || 482 ((debugflag > 0) && (level >= MSG_INFO))) { 483 (void) fprintf(stdout, "stmsboot: "); 484 va_start(ap, msg); 485 (void) vfprintf(stdout, msg, ap); 486 va_end(ap); 487 } 488 } 489 490 /* 491 * It's up to the caller to do any sorting or pretty-printing of the device 492 * mappings we report. Since we're storing the device links as just the cXtYdZ 493 * part, we'll add /dev/rdsk/ back on when we print the listing so we maintain 494 * compatibility with previous versions of this tool. There's a little bit 495 * of footwork involved to make sure that we show all the paths to a device 496 * rather than just the first one we stashed away. 497 */ 498 static void 499 list_devs(int listguids, int ctrl) 500 { 501 nvlist_t *thisdevnvl; 502 nvpair_t *pair; 503 char *diskpath, *livepath, *key, *querydev; 504 char *matchctrl = NULL; 505 char checkctrl[MAXPATHLEN]; 506 int rv; 507 508 if (!mpxenabled) { 509 logmsg(MSG_ERROR, gettext("MPxIO is not enabled\n")); 510 return; 511 } 512 513 if (listguids) { 514 (void) printf(gettext("non-STMS device name\t\t\tGUID\n" 515 "------------------------------------------" 516 "------------------------\n")); 517 } else { 518 (void) printf(gettext("non-STMS device name\t\t\t" 519 "STMS device name\n" 520 "------------------------------------------" 521 "------------------------\n")); 522 } 523 524 bzero(checkctrl, MAXPATHLEN); 525 pair = NULL; 526 while ((pair = nvlist_next_nvpair(mapnvl, pair)) 527 != NULL) { 528 boolean_t livescsivhcip = B_FALSE; 529 530 if ((((rv = nvpair_value_string(pair, &querydev)) < 0) || 531 ((key = nvpair_name(pair)) == NULL)) || 532 ((strstr(key, "/pci") != NULL) || 533 (strstr(key, "/sbus") != NULL) || 534 (strstr(key, "/scsi_vhci") != NULL) || 535 (strncmp(key, "id1", 3) == 0))) { 536 logmsg(MSG_INFO, 537 "list_devs: rv = %d; (%s) is not a devlink, " 538 "continuing.\n", rv, 539 (key != NULL) ? key : "null"); 540 querydev = NULL; 541 continue; 542 } 543 544 (void) nvlist_lookup_nvlist(mapnvl, querydev, &thisdevnvl); 545 (void) nvlist_lookup_boolean_value(thisdevnvl, NVL_MPXEN, 546 &livescsivhcip); 547 (void) nvlist_lookup_string(thisdevnvl, NVL_MPXPATH, 548 &livepath); 549 550 if ((!livescsivhcip) || 551 (livescsivhcip && 552 (strncmp(key, livepath, strlen(key)) == 0))) 553 continue; 554 555 (void) nvlist_lookup_string(thisdevnvl, NVL_PATH, 556 &diskpath); 557 558 logmsg(MSG_INFO, 559 "list_devs: %s :: %s ::%s :: MPXEN (%s)\n", 560 key, diskpath, livepath, 561 ((livescsivhcip) ? "TRUE" : "FALSE")); 562 563 if (ctrl > -1) { 564 (void) sprintf(checkctrl, "c%dt", ctrl); 565 matchctrl = strstr(key, checkctrl); 566 if (matchctrl == NULL) 567 continue; 568 } 569 if (listguids != 0) { 570 char *tempguid; 571 ddi_devid_t curdevid; 572 int rv; 573 574 rv = devid_str_decode(querydev, &curdevid, NULL); 575 if (rv == -1) { 576 logmsg(MSG_INFO, "Unable to decode devid %s\n", 577 key); 578 continue; 579 } 580 tempguid = devid_to_guid(curdevid); 581 if (tempguid != NULL) 582 (void) printf("/dev/rdsk/%s\t%s\n", 583 diskpath, tempguid); 584 585 devid_free_guid(tempguid); 586 devid_free(curdevid); 587 continue; 588 } 589 590 (void) printf("/dev/rdsk/%s\t/dev/rdsk/%s\n", 591 (strstr(key, diskpath) == NULL) ? key : diskpath, 592 livepath); 593 } 594 } 595 596 /* 597 * We get passed a device name which we search the mapnvl for. If we find 598 * it, we print the mapping as it is found. It is up to the caller of this 599 * utility to do any pretty-printing of the results. If a device listed on 600 * the command line does not exist in the mapnvl, then we print NOT_MAPPED. 601 * Otherwise we print the command-line device name as it maps to what is 602 * stashed in the mapnvl - even if that's a "no change" device mapping. 603 * 604 * Example output (-p maps to physpath=BOOT) 605 * # /lib/mpxio/stmsboot_util -p \ 606 * /pci@0,0/pci1022,7450@2/pci1000,3060@3/sd@1,0:a 607 * /scsi_vhci/disk@g500000e011e17720:a 608 * 609 * Or the reverse: 610 * # /lib/mpxio/stmsboot_util -p /scsi_vhci/disk@g500000e011e17720:a 611 * /pci@0,0/pci1022,7450@2/pci1000,3060@3/sd@1,0:a 612 * 613 * For the -m option, used when we're trying to find the root device mapping: 614 * 615 * # /lib/mpxio/stmsboot_util -m /dev/dsk/c2t0d0s2 616 * /dev/dsk/c3t500000E011637CF0d0s2 617 */ 618 static void 619 report_map(char *argdev, int physpath) 620 { 621 nvlist_t *thisdev; 622 int rv = 0; 623 char *thisdevid; 624 char *mpxpath = NULL; 625 char *prefixt = NULL; 626 char *prefixp = NULL; 627 char *stripdev = NULL; 628 char *slice = NULL; 629 boolean_t mpxenp; 630 uint_t slicelen = 0; 631 632 mpxenp = B_FALSE; 633 634 if ((prefixt = calloc(1, strlen(argdev) + 1)) == NULL) { 635 logmsg(MSG_INFO, "Unable to allocate memory\n"); 636 (void) printf("NOT_MAPPED\n"); 637 return; 638 } 639 640 (void) strlcpy(prefixt, argdev, strlen(argdev) + 1); 641 642 slice = strrchr(argdev, (physpath == BOOT) ? ':' : 's'); 643 if (slice != NULL) { 644 slicelen = strlen(slice); 645 if (slicelen > 3) 646 /* invalid size - max is 3 chars */ 647 slicelen = 0; 648 } 649 650 if ((stripdev = calloc(1, strlen(prefixt) + 1)) == NULL) { 651 logmsg(MSG_INFO, "Unable to allocate memory\n"); 652 (void) printf("NOT_MAPPED\n"); 653 free(prefixt); 654 return; 655 } 656 657 if ((strstr(prefixt, "/scsi_vhci") == NULL) && 658 (strstr(prefixt, "/pci") == NULL) && 659 (strstr(prefixt, "/sbus") == NULL)) { 660 prefixp = strrchr(prefixt, '/'); 661 (void) strlcpy(stripdev, 662 (prefixp == NULL) ? prefixt : prefixp + 1, 663 (prefixp == NULL) ? 664 strlen(prefixt) + 1: strlen(prefixp) + 1); 665 if (prefixp != NULL) 666 prefixt[strlen(argdev) - strlen(prefixp) + 1] = '\0'; 667 } else { 668 if (physpath != BOOT) { 669 logmsg(MSG_INFO, "Invalid device path provided\n"); 670 (void) printf("NOT_MAPPED\n"); 671 free(stripdev); 672 free(prefixt); 673 return; 674 } 675 (void) strlcpy(stripdev, argdev, strlen(argdev) + 1); 676 } 677 678 logmsg(MSG_INFO, 679 "stripdev (%s), prefixt(%s), prefixp(%s), slice(%s)\n", 680 (stripdev == NULL) ? "null" : stripdev, 681 (prefixt == NULL) ? "null" : prefixt, 682 (prefixp == NULL) ? "null" : prefixp, 683 (slice == NULL) ? "null" : slice); 684 685 if (slicelen > 0) 686 stripdev[strlen(stripdev) - slicelen] = '\0'; 687 688 /* search for the shortened version */ 689 rv = nvlist_lookup_string(mapnvl, stripdev, &thisdevid); 690 if (rv) { 691 if (physpath != BOOT) { 692 logmsg(MSG_INFO, 693 "searched mapnvl for '%s', got %s (%d)\n", 694 stripdev, strerror(rv), rv); 695 (void) printf("NOT_MAPPED\n"); 696 free(stripdev); 697 free(prefixt); 698 return; 699 } 700 } 701 702 logmsg(MSG_INFO, "device %s has devid %s\n", stripdev, thisdevid); 703 704 if (nvlist_lookup_nvlist(mapnvl, thisdevid, &thisdev) != 0) { 705 logmsg(MSG_INFO, "device (%s) in mapnvl but " 706 "not mapped!\n", thisdevid); 707 (void) printf("NOT_MAPPED\n"); 708 free(stripdev); 709 free(prefixt); 710 return; 711 } 712 713 /* quick exit */ 714 if (!mpxenabled && (strstr(argdev, "/pci") != NULL || 715 strstr(argdev, "/sbus") != NULL)) { 716 (void) printf("%s\n", argdev); 717 free(stripdev); 718 free(prefixt); 719 return; 720 } 721 722 (void) nvlist_lookup_boolean_value(thisdev, NVL_MPXEN, &mpxenp); 723 724 if (physpath == BOOT) { 725 (void) nvlist_lookup_string(thisdev, NVL_PHYSPATH, &mpxpath); 726 if ((strstr(argdev, "/scsi_vhci") != NULL) && 727 (strncmp(argdev, mpxpath, strlen(mpxpath)) == 0)) { 728 /* Need to translate vhci to phci */ 729 char *realpath; 730 731 if ((realpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 732 logmsg(MSG_ERROR, 733 gettext("Unable to allocate " 734 "memory for a path element\n")); 735 free(stripdev); 736 free(prefixt); 737 return; 738 } 739 vhci_to_phci(stripdev, realpath); 740 (void) printf("%s%s\n", realpath, 741 ((slicelen > 0) && slice != NULL) ? slice : ""); 742 free(realpath); 743 } else { 744 (void) printf("%s%s\n", mpxpath, 745 ((slicelen > 0) && slice != NULL) ? slice : ""); 746 } 747 } else { 748 (void) nvlist_lookup_string(thisdev, 749 ((readonlyroot) ? NVL_PHYSPATH : 750 ((mpxenp == B_TRUE) ? NVL_MPXPATH : NVL_PATH)), 751 &mpxpath); 752 logmsg(MSG_INFO, "mpxpath = %s\n", 753 (mpxpath == NULL) ? "null" : mpxpath); 754 if (readonlyroot || 755 (strstr(mpxpath, "/scsi_vhci") != NULL) || 756 (strstr(mpxpath, "/pci") != NULL) || 757 (strstr(mpxpath, "/sbus") != NULL)) { 758 /* 759 * If we see a physical path here it means that 760 * devlinks aren't fully initialised yet, so we 761 * are still in maintenance/single-user mode. 762 */ 763 (void) printf("/devices%s:%c\n", mpxpath, 764 slice[1] + '1'); 765 } else { 766 (void) printf("%s%s%s\n", 767 (prefixt[0] == '/') ? prefixt : "", 768 mpxpath, 769 ((slicelen > 0) && slice != NULL) ? slice : ""); 770 } 771 } 772 free(prefixt); 773 free(stripdev); 774 } 775 776 /* 777 * Validate the in-kernel and on-disk forms of our devid cache, 778 * returns -1 for unfixable error and 0 for success. 779 */ 780 static int 781 validate_devnvl() 782 { 783 di_node_t curnode; 784 int rv1 = -1; 785 int rv2 = -1; 786 787 /* 788 * Method: we walk through the kernel's concept of the device tree 789 * looking for "ssd" then "sd" nodes. 790 * We check to see whether the device's devid is already in our nvlist 791 * (on disk) nvlist cache file. If it is, we check that it's components 792 * match what we've got already and fill any missing fields. 793 * If the devid isn't in our on-disk nvlist already then we add it 794 * and populate the property nvpairs. 795 * 796 * At the end of this function we should have this program's concept 797 * of the devid-keyed nvlist matching what is in the ondisk form which 798 * is ready to be written out. 799 * If we can't do this, then we return -1. 800 */ 801 curnode = di_drv_first_node("ssd", devinfo_root); 802 if (curnode != DI_NODE_NIL) 803 rv1 = mpxio_nvl_boilerplate(curnode); 804 805 curnode = di_drv_first_node("sd", devinfo_root); 806 if (curnode != DI_NODE_NIL) 807 rv2 = mpxio_nvl_boilerplate(curnode); 808 809 if (rv1 + rv2 == -2) 810 return (-1); 811 812 return (0); 813 } 814 815 static int 816 mpxio_nvl_boilerplate(di_node_t curnode) 817 { 818 int rv; 819 char *strdevid; 820 ddi_devid_t curdevid; 821 nvlist_t *newnvl; 822 823 for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { 824 errno = 0; 825 826 curdevid = NULL; 827 get_devid(curnode, &curdevid); 828 if (curdevid == NULL) 829 /* 830 * There's no devid registered for this device 831 * so it's not cool enough to play with us 832 */ 833 continue; 834 835 strdevid = devid_str_encode(curdevid, NULL); 836 /* does this exist in the on-disk cache? */ 837 rv = nvlist_lookup_nvlist(mapnvl, strdevid, &newnvl); 838 if (rv == ENOENT) { 839 logmsg(MSG_INFO, "nvlist for %s not found\n", strdevid); 840 /* no, so alloc a new nvl to store it */ 841 if (nvlist_alloc(&newnvl, NV_UNIQUE_NAME, 0) != 0) { 842 logmsg(MSG_ERROR, 843 gettext("Unable to allocate space for " 844 "a devid property list: %s\n"), 845 strerror(errno)); 846 return (-1); 847 } 848 } else { 849 if ((rv != ENOTSUP) && (rv != EINVAL)) 850 logmsg(MSG_INFO, 851 "%s exists in ondisknvl, verifying\n", 852 strdevid); 853 } 854 855 if (popcheck_devnvl(curnode, newnvl, strdevid) != 0) { 856 logmsg(MSG_ERROR, 857 gettext("Unable to populate devid nvpair " 858 "for device with devid %s\n"), 859 strdevid); 860 devid_str_free(strdevid); 861 nvlist_free(newnvl); 862 return (-1); 863 } 864 865 /* Now add newnvl into our cache. */ 866 errno = 0; 867 rv = nvlist_add_nvlist(mapnvl, strdevid, newnvl); 868 if (rv) { 869 logmsg(MSG_ERROR, 870 gettext("Unable to add device (devid %s) " 871 "to in-kernel nvl: %s (%d)\n"), 872 strdevid, strerror(rv), rv); 873 devid_str_free(strdevid); 874 nvlist_free(newnvl); 875 return (-1); 876 } 877 logmsg(MSG_INFO, 878 gettext("added device (devid %s) to mapnvl\n\n"), 879 strdevid); 880 devid_str_free(strdevid); 881 } 882 return (0); 883 } 884 885 /* 886 * Operates on a single di_node_t, collecting all the device properties 887 * that we need. devnvl is allocated by the caller, and we add our nvpairs 888 * to it if they don't already exist. 889 * 890 * We are _only_ interested in devices which have a devid. We pull in 891 * devices even when they're excluded via stmsboot -D (driver), because 892 * we don't want to miss out on any devid data that might be handy later. 893 */ 894 static int 895 popcheck_devnvl(di_node_t thisnode, nvlist_t *devnvl, char *strdevid) 896 { 897 char *path = NULL; 898 char *curpath = NULL; 899 char *devfspath = NULL; 900 int scsivhciparent = 0; 901 int rv = 0; 902 boolean_t mpxenp = B_FALSE; 903 904 errno = 0; 905 devfspath = di_devfs_path(thisnode); 906 if (devfspath == NULL) { 907 logmsg(MSG_ERROR, 908 gettext("Unable to determine devfs path for node: %s\n"), 909 strerror(errno)); 910 return (-1); 911 } 912 913 /* Add a convenient devfspath to devid inverse map */ 914 if (nvlist_add_string(mapnvl, devfspath, strdevid) != 0) { 915 logmsg(MSG_ERROR, 916 gettext("Unable to add device path %s with devid " 917 "%s to mapnvl\n"), devfspath, strdevid); 918 return (-1); 919 } 920 if (strncmp(di_driver_name(di_parent_node(thisnode)), 921 "scsi_vhci", 9) == 0) { 922 scsivhciparent = 1; 923 if (!mpxenabled) 924 mpxenabled++; 925 926 rv = nvlist_lookup_boolean_value(devnvl, NVL_MPXEN, &mpxenp); 927 if (rv || (mpxenp == B_FALSE)) { 928 rv = nvlist_add_boolean_value(devnvl, 929 NVL_MPXEN, B_TRUE); 930 if (rv) { 931 logmsg(MSG_ERROR, 932 gettext("Unable to add property %s " 933 "(set to B_TRUE) for device %s: " 934 "%s (%d)\n"), 935 NVL_MPXEN, devfspath, 936 strerror(rv), rv); 937 return (-1); 938 } 939 logmsg(MSG_INFO, "NVL_MPXEN :: (B_FALSE->B_TRUE)\n"); 940 } 941 } else { 942 /* turn _off_ the flag if it was enabled */ 943 rv = nvlist_add_boolean_value(devnvl, NVL_MPXEN, B_FALSE); 944 if (rv) { 945 logmsg(MSG_ERROR, 946 gettext("Unable to add property %s " 947 "(set to B_FALSE) for device %s: %s (%d)\n"), 948 NVL_MPXEN, devfspath, 949 strerror(rv), rv); 950 return (-1); 951 } 952 logmsg(MSG_INFO, "NVL_MPXEN :: (B_TRUE-> B_FALSE)\n"); 953 } 954 955 rv = nvlist_add_string(devnvl, NVL_PHYSPATH, devfspath); 956 if (rv) { 957 logmsg(MSG_ERROR, 958 gettext("Unable to add physical device path (%s) " 959 "property to nvl\n")); 960 return (-1); 961 } 962 963 if ((curpath = calloc(1, MAXPATHLEN)) == NULL) { 964 logmsg(MSG_ERROR, 965 gettext("Unable to allocate space for current path\n")); 966 return (-1); 967 } 968 curpath = find_link(thisnode); 969 if (curpath == NULL) { 970 if (readonlyroot) { 971 return (0); 972 } 973 logmsg(MSG_ERROR, 974 gettext("Unable to determine device path for node %s\n"), 975 devfspath); 976 return (-1); 977 } 978 979 rv = nvlist_lookup_string(devnvl, NVL_MPXPATH, &path); 980 981 if (path == NULL && scsivhciparent) 982 (void) nvlist_add_string(devnvl, NVL_MPXPATH, curpath); 983 984 if (!scsivhciparent) { 985 (void) nvlist_add_string(devnvl, NVL_PATH, curpath); 986 path = curpath; 987 } 988 989 /* 990 * This next block provides the path to devid inverse mapping 991 * that other functions require 992 */ 993 if (path != NULL) { 994 if (nvlist_add_string(mapnvl, path, strdevid) != 0) { 995 logmsg(MSG_ERROR, 996 gettext("Unable to add device %s with devid " 997 "%s to mapnvl\n"), path, strdevid); 998 return (-1); 999 } 1000 logmsg(MSG_INFO, "popcheck_devnvl: added path %s :: %s\n", 1001 path, strdevid); 1002 if (nvlist_add_string(mapnvl, curpath, strdevid) != 0) { 1003 logmsg(MSG_ERROR, 1004 gettext("Unable to add device %s with devid " 1005 "%s to mapnvl: %s\n"), 1006 curpath, strdevid, strerror(errno)); 1007 return (-1); 1008 } 1009 logmsg(MSG_INFO, "popcheck_devnvl: added curpath %s :: %s\n", 1010 curpath, strdevid); 1011 } 1012 if (scsivhciparent) { 1013 if (nvlist_add_string(devnvl, NVL_MPXPATH, curpath) != 0) { 1014 logmsg(MSG_ERROR, 1015 gettext("Unable to add property %s for device " 1016 "%s: %s\n"), 1017 NVL_MPXPATH, devfspath, strerror(errno)); 1018 return (-1); 1019 } else { 1020 logmsg(MSG_INFO, "added curpath (%s) as NVL_MPXPATH " 1021 "to devnvl for devid %s\n", curpath, strdevid); 1022 } 1023 } 1024 return (0); 1025 } 1026 1027 static void 1028 print_mpx_capable(di_node_t curnode) 1029 { 1030 char *prop; 1031 char *path; 1032 char *aliases = NULL; 1033 1034 if (cap_N_option) { 1035 aliases = calloc(1, MAXPATHLEN + 1); 1036 if (aliases == NULL) { 1037 logmsg(MSG_ERROR, 1038 gettext("Unable to allocate memory for a device " 1039 "alias list\n")); 1040 return; 1041 } 1042 } 1043 1044 for (; curnode != DI_NODE_NIL; curnode = di_drv_next_node(curnode)) { 1045 if (di_prop_lookup_strings(DDI_DEV_T_ANY, curnode, 1046 "initiator-port", &prop) >= 0) { 1047 if ((path = di_devfs_path(curnode)) == NULL) { 1048 logmsg(MSG_INFO, 1049 "Unable to find devfs path for device " 1050 "%s: %s\n", &curnode, strerror(errno)); 1051 continue; 1052 } 1053 if (cap_N_option) { 1054 char *nodename = di_node_name(curnode); 1055 /* nodename is never going to be null */ 1056 if (strstr(aliases, nodename) == NULL) 1057 /* haven't seen this nodename before */ 1058 (void) snprintf(aliases, 1059 MAXPATHLEN + 1, "%s|%s", 1060 ((aliases != NULL) ? aliases : ""), 1061 nodename); 1062 } else 1063 (void) printf("%s\n", path); 1064 } 1065 } 1066 if (cap_N_option) 1067 (void) printf("%s\n", aliases); 1068 } 1069 1070 static int 1071 link_cb(di_devlink_t devlink, void *arg) 1072 { 1073 const char *result; 1074 1075 result = di_devlink_path(devlink); 1076 if (result == NULL) { 1077 arg = (void *)"(null)"; 1078 } else { 1079 (void) strlcpy(arg, result, strlen(result)); 1080 } 1081 logmsg(MSG_INFO, "\nlink_cb::linkdata->resultstr = %s\n", 1082 ((result != NULL) ? result : "(null)")); 1083 return (DI_WALK_CONTINUE); 1084 } 1085 1086 static char * 1087 find_link(di_node_t cnode) 1088 { 1089 di_minor_t devminor = DI_MINOR_NIL; 1090 di_devlink_handle_t hdl; 1091 char *devfspath = NULL; 1092 char *minorpath = NULL; 1093 char *linkname = NULL; 1094 char *cbresult = NULL; 1095 1096 devfspath = di_devfs_path(cnode); 1097 if (cnode == DI_NODE_NIL) { 1098 logmsg(MSG_ERROR, 1099 gettext("find_ctrl must be called with non-null " 1100 "di_node_t\n")); 1101 return (NULL); 1102 } 1103 logmsg(MSG_INFO, "find_link: devfspath %s\n", devfspath); 1104 1105 if (((cbresult = calloc(1, MAXPATHLEN)) == NULL) || 1106 ((minorpath = calloc(1, MAXPATHLEN)) == NULL) || 1107 ((linkname = calloc(1, MAXPATHLEN)) == NULL)) { 1108 logmsg(MSG_ERROR, "unable to allocate space for dev link\n"); 1109 return (NULL); 1110 } 1111 1112 devminor = di_minor_next(cnode, devminor); 1113 hdl = di_devlink_init(di_devfs_minor_path(devminor), DI_MAKE_LINK); 1114 if (hdl == NULL) { 1115 logmsg((readonlyroot ? MSG_INFO : MSG_ERROR), 1116 gettext("unable to take devlink snapshot: %s\n"), 1117 strerror(errno)); 1118 return (NULL); 1119 } 1120 1121 linkname = "^dsk/"; 1122 (void) snprintf(minorpath, MAXPATHLEN, "%s:c", devfspath); 1123 1124 errno = 0; 1125 if (di_devlink_walk(hdl, linkname, minorpath, DI_PRIMARY_LINK, 1126 (void *)cbresult, link_cb) < 0) { 1127 logmsg(MSG_ERROR, 1128 gettext("Unable to walk devlink snapshot for %s: %s\n"), 1129 minorpath, strerror(errno)); 1130 return (NULL); 1131 } 1132 1133 if (di_devlink_fini(&hdl) < 0) { 1134 logmsg(MSG_ERROR, 1135 gettext("Unable to close devlink snapshot: %s\n"), 1136 strerror(errno)); 1137 } 1138 if (strstr(cbresult, "dsk/") == NULL) 1139 return (devfspath); 1140 1141 bzero(minorpath, MAXPATHLEN); 1142 /* strip off the trailing "s2" */ 1143 bcopy(cbresult, minorpath, strlen(cbresult) - 1); 1144 /* Now strip off the /dev/dsk/ prefix for output flexibility */ 1145 linkname = strrchr(minorpath, '/'); 1146 return (++linkname); 1147 } 1148 1149 /* 1150 * handle case where device has been probed but its target driver is not 1151 * attached so enumeration has not quite finished. Opening the /devices 1152 * pathname will force the kernel to finish the enumeration process and 1153 * let us get the data we need. 1154 */ 1155 static void 1156 get_devid(di_node_t node, ddi_devid_t *thisdevid) 1157 { 1158 int fd; 1159 char realpath[MAXPATHLEN]; 1160 char *openpath = di_devfs_path(node); 1161 1162 errno = 0; 1163 bzero(realpath, MAXPATHLEN); 1164 if (strstr(openpath, "/devices") == NULL) { 1165 (void) snprintf(realpath, MAXPATHLEN, 1166 "/devices%s:c,raw", openpath); 1167 fd = open(realpath, O_RDONLY|O_NDELAY); 1168 } else { 1169 fd = open(openpath, O_RDONLY|O_NDELAY); 1170 } 1171 1172 if (fd < 0) { 1173 logmsg(MSG_INFO, "Unable to open path %s: %s\n", 1174 openpath, strerror(errno)); 1175 return; 1176 } 1177 1178 if (devid_get(fd, thisdevid) != 0) { 1179 logmsg(MSG_INFO, 1180 "'%s' node (%s) without a devid registered\n", 1181 di_driver_name(node), di_devfs_path(node)); 1182 } 1183 (void) close(fd); 1184 } 1185 1186 static int 1187 print_bootpath() 1188 { 1189 char *bootprop = NULL; 1190 1191 if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root, 1192 "bootpath", &bootprop) >= 0) { 1193 (void) printf("%s\n", bootprop); 1194 return (0); 1195 } else if (di_prop_lookup_strings(DDI_DEV_T_ANY, devinfo_root, 1196 "boot-path", &bootprop) >= 0) { 1197 (void) printf("%s\n", bootprop); 1198 return (0); 1199 } else { 1200 (void) printf("ERROR: no bootpath/boot-path property found\n"); 1201 return (ENOENT); 1202 } 1203 } 1204 1205 /* 1206 * We only call this routine if we have a scsi_vhci node and must 1207 * determine the actual physical path of its first online client 1208 * path. 1209 */ 1210 static void 1211 vhci_to_phci(char *devpath, char *physpath) 1212 { 1213 sv_iocdata_t ioc; 1214 sv_path_info_t *pi; 1215 int vhci_fd; 1216 int rv; 1217 uint_t npaths = 0; 1218 1219 vhci_fd = open(VHCI_CTL_NODE, O_RDWR); 1220 if (vhci_fd < 0) 1221 goto failure; 1222 1223 bzero(&ioc, sizeof (sv_iocdata_t)); 1224 ioc.client = devpath; 1225 ioc.ret_elem = &npaths; 1226 rv = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc); 1227 if (rv || npaths == 0) { 1228 logmsg(MSG_INFO, 1229 "SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO ioctl() failed, " 1230 "%s (%d)\n", strerror(rv), rv); 1231 goto failure; 1232 } 1233 1234 bzero(&ioc, sizeof (sv_iocdata_t)); 1235 ioc.client = devpath; 1236 ioc.buf_elem = npaths; 1237 ioc.ret_elem = &npaths; 1238 if ((ioc.ret_buf = calloc(npaths, sizeof (sv_path_info_t))) 1239 == NULL) 1240 goto failure; 1241 rv = ioctl(vhci_fd, SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO, &ioc); 1242 if (rv || npaths == 0) { 1243 logmsg(MSG_INFO, 1244 "SCSI_VHCI_GET_CLIENT_MULTIPATH_INFO ioctl() (#2) " 1245 "failed, %s (%d)\n", strerror(rv), rv); 1246 goto failure; 1247 } 1248 1249 if (ioc.buf_elem < npaths) 1250 npaths = ioc.buf_elem; 1251 1252 pi = (sv_path_info_t *)ioc.ret_buf; 1253 while (npaths--) { 1254 if (pi->ret_state == MDI_PATHINFO_STATE_ONLINE) { 1255 char nodename[4]; 1256 1257 bzero(nodename, 4); 1258 /* A hack, but nicer than a platform-specific ifdef */ 1259 if (strstr(devpath, "ssd") != NULL) { 1260 (void) snprintf(nodename, 4, "ssd"); 1261 } else { 1262 (void) snprintf(nodename, 4, "sd"); 1263 } 1264 (void) snprintf(physpath, MAXPATHLEN, "%s/%s@%s", 1265 pi->device.ret_phci, nodename, pi->ret_addr); 1266 free(ioc.ret_buf); 1267 return; 1268 } 1269 pi++; 1270 } 1271 1272 failure: 1273 (void) snprintf(physpath, MAXPATHLEN, "NOT_MAPPED"); 1274 } 1275 1276 /* 1277 * Write /etc/vfstab to /etc/vfstab.new, with any remapped device 1278 * names substituted. 1279 * 1280 * Returns: 1281 * 0 successful operation 1282 * -1 failed 1283 */ 1284 static int 1285 update_vfstab() 1286 { 1287 FILE *fdin, *fdout; 1288 char *buf, *tmpbuf; 1289 char fname[MAXPATHLEN]; 1290 int rv = -1, rval = -1; 1291 char cdev[MAXPATHLEN]; 1292 char bdev[MAXPATHLEN]; 1293 char mntpt[MAXPATHLEN]; 1294 char fstype[512]; 1295 char fsckpass[512]; 1296 char mntboot[512]; 1297 char mntopt[MAXPATHLEN]; 1298 char fmt[80]; 1299 char *prefixt = NULL; 1300 char *curdev = NULL; 1301 char *thisdevid = NULL; 1302 char *slice = NULL; 1303 nvlist_t *thisdev; 1304 boolean_t devmpx = B_FALSE; 1305 1306 buf = calloc(1, MAXPATHLEN); 1307 tmpbuf = calloc(1, MAXPATHLEN); 1308 if (buf == NULL || tmpbuf == NULL) 1309 return (-1); 1310 1311 (void) snprintf(fname, MAXPATHLEN, "/etc/mpxio/vfstab.new"); 1312 1313 fdin = fopen("/etc/vfstab", "r"); 1314 fdout = fopen(fname, "w+"); 1315 if (fdin == NULL || fdout == NULL) { 1316 logmsg(MSG_INFO, "Unable to open vfstab or create a backup " 1317 "vfstab %s\n"); 1318 return (-1); 1319 } 1320 1321 (void) snprintf(fmt, sizeof (fmt), 1322 "%%%ds %%%ds %%%ds %%%ds %%%ds %%%ds %%%ds", sizeof (bdev) - 1, 1323 sizeof (cdev) - 1, sizeof (mntpt) - 1, sizeof (fstype) - 1, 1324 sizeof (fsckpass) - 1, sizeof (mntboot) - 1, sizeof (mntopt) - 1); 1325 1326 while (fgets(buf, MAXPATHLEN, fdin) != NULL) { 1327 if (strlen(buf) == (MAXPATHLEN - 1) && 1328 buf[MAXPATHLEN-2] != '\n') { 1329 logmsg(MSG_ERROR, 1330 gettext("/etc/vfstab line length too long, " 1331 "exceeded %2$d: \"%3$s\"\n"), 1332 MAXPATHLEN - 2, buf); 1333 goto out; 1334 } 1335 1336 prefixt = NULL; 1337 curdev = NULL; 1338 slice = NULL; 1339 thisdevid = NULL; 1340 thisdev = NULL; 1341 1342 /* LINTED - variable format specifier */ 1343 rv = sscanf(buf, fmt, bdev, cdev, mntpt, fstype, fsckpass, 1344 mntboot, mntopt); 1345 1346 /* 1347 * Walk through the lines in the input file (/etc/vfstab), 1348 * skipping anything which is _not_ a COGD (common or garden 1349 * disk), ie all the /devices, /system, /dev/md, /dev/vx and 1350 * /dev/zvol and so forth. 1351 */ 1352 if ((rv == 7) && (bdev[0] == '/') && 1353 (strstr(bdev, "/dev/dsk"))) { 1354 slice = strrchr(bdev, 's'); 1355 /* take a copy, strip off /dev/dsk/ */ 1356 prefixt = strrchr(bdev, 'c'); 1357 prefixt[strlen(bdev) - 9 - strlen(slice)] = '\0'; 1358 slice++; /* advance past the s */ 1359 rval = nvlist_lookup_string(mapnvl, prefixt, 1360 &thisdevid); 1361 if (rval) { 1362 /* Whoa, where did this device go?! */ 1363 logmsg(MSG_INFO, 1364 "error looking up device %s\n", prefixt); 1365 /* Comment-out this line in the new version */ 1366 (void) snprintf(tmpbuf, MAXPATHLEN, 1367 "# DEVICE NOT FOUND %s", buf); 1368 (void) fprintf(fdout, "%s", tmpbuf); 1369 continue; 1370 } else { 1371 /* The device exists in our mapnvl */ 1372 (void) nvlist_lookup_nvlist(mapnvl, thisdevid, 1373 &thisdev); 1374 (void) nvlist_lookup_boolean_value(thisdev, 1375 NVL_MPXEN, &devmpx); 1376 (void) nvlist_lookup_string(thisdev, 1377 ((devmpx == B_TRUE) 1378 ? NVL_MPXPATH : NVL_PATH), 1379 &curdev); 1380 } 1381 } 1382 1383 if ((prefixt != NULL) && (curdev != NULL) && 1384 (rv = (strncmp(prefixt, curdev, strlen(prefixt)) != 0))) { 1385 /* Mapping change for this device */ 1386 if (strcmp(fstype, "swap") == 0) { 1387 (void) snprintf(tmpbuf, MAXPATHLEN, 1388 "/dev/dsk/%ss%s\t-\t-\tswap\t" 1389 "%s\t%s\t%s\n", 1390 curdev, slice, fsckpass, mntboot, mntopt); 1391 } else { 1392 (void) snprintf(tmpbuf, MAXPATHLEN, 1393 "/dev/dsk/%ss%s\t/dev/rdsk/%ss%s\t" 1394 "%s\t%s\t%s\t%s\t%s\n", 1395 curdev, slice, curdev, slice, 1396 mntpt, fstype, fsckpass, mntboot, mntopt); 1397 } 1398 errno = 0; 1399 (void) fprintf(fdout, "%s", tmpbuf); 1400 } else { 1401 (void) fprintf(fdout, "%s", buf); 1402 } 1403 1404 errno = 0; 1405 if (fflush(fdout) != 0) { 1406 logmsg(MSG_ERROR, 1407 gettext("fprintf failed to write to %s: %s (%d)\n"), 1408 fname, strerror(errno), errno); 1409 goto out; 1410 } 1411 } 1412 out: 1413 (void) fclose(fdin); 1414 (void) fclose(fdout); 1415 free(buf); 1416 free(tmpbuf); 1417 return (errno); 1418 } 1419