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