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 2008 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 * fwflash.c 30 */ 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <unistd.h> 34 #include <strings.h> 35 #include <ctype.h> 36 #include <errno.h> 37 #include <sys/queue.h> 38 #include <signal.h> 39 #include <locale.h> 40 #include <sys/stat.h> 41 #include <sys/types.h> 42 #include <sys/param.h> 43 #include <fcntl.h> 44 #include <dlfcn.h> 45 #include <dirent.h> 46 #include <link.h> 47 #include <sys/varargs.h> 48 #include <libintl.h> /* for gettext(3c) */ 49 #include <libdevinfo.h> 50 #include <note.h> 51 52 #include <fwflash/fwflash.h> 53 54 55 #if !defined(lint) 56 /* embedded software license agreement */ 57 static char *sla [] = { "Copyright 2007 Sun Microsystems, Inc., 4150 Network " 58 "Circle, Santa Clara, California 95054, U.S.A. All rights reserved. U.S. " 59 "Government Rights - Commercial software. Government users are subject to the " 60 "Sun Microsystems, Inc. standard license agreement and applicable provisions " 61 "of the FAR and its supplements. Use is subject to license terms. Parts of " 62 "the product may be derived from Berkeley BSD systems, licensed from the " 63 "University of California. UNIX is a registered trademark in the U.S. and in " 64 "other countries, exclusively licensed through X/Open Company, Ltd.Sun, Sun " 65 "Microsystems, the Sun logo and Solaris are trademarks or registered " 66 "trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This " 67 "product is covered and controlled by U.S. Export Control laws and may be " 68 "subject to the export or import laws in other countries. Nuclear, missile, " 69 "chemical biological weapons or nuclear maritime end uses or end users, " 70 "whether direct or indirect, are strictly prohibited. Export or reexport " 71 "to countries subject to U.S. embargo or to entities identified on U.S. export " 72 "exclusion lists, including, but not limited to, the denied persons and " 73 "specially designated nationals lists is strictly prohibited." }; 74 #endif /* lint */ 75 76 /* global arg list */ 77 int fwflash_arg_list = 0; 78 char *filelist[10]; 79 80 81 /* are we writing to flash? */ 82 static int fwflash_in_write = 0; 83 84 /* 85 * If we *must* track the version string for fwflash, then 86 * we should do so in this common file rather than the header 87 * file since it will then be in sync with what the customer 88 * sees 89 */ 90 91 92 #define FWFLASH_VERSION "%I%" 93 #define FWFLASH_PROG_NAME "fwflash" 94 95 96 97 static int get_fileopts(char *options); 98 static int flash_device_list(); 99 static int flash_load_plugins(); 100 static int fwflash_update(char *device, char *filename, int flags); 101 static int fwflash_read_file(char *device, char *filename); 102 static int fwflash_list_fw(char *class); 103 static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg); 104 static void fwflash_intr(int sig); 105 static void fwflash_handle_signals(void); 106 static void fwflash_usage(); 107 static void fwflash_help(void); 108 static void fwflash_version(void); 109 static int confirm_target(struct devicelist *thisdev, char *file); 110 111 112 113 114 /* 115 * FWFlash main code 116 */ 117 int 118 main(int argc, char **argv) { 119 int rv = FWFLASH_SUCCESS; 120 int i; 121 char ch; 122 char *read_file; 123 extern char *optarg; 124 char *devclass = NULL; 125 char *devpath = NULL; 126 127 128 129 /* local variables from env */ 130 (void) setlocale(LC_ALL, ""); 131 132 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 133 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ 134 #endif 135 136 (void) textdomain(TEXT_DOMAIN); 137 138 139 read_file = NULL; 140 141 if (argc < 2) { 142 /* no args supplied */ 143 fwflash_usage(NULL); 144 return (FWFLASH_FAILURE); 145 } 146 147 148 while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:")) != EOF) { 149 switch (ch) { 150 case 'h': 151 fwflash_arg_list |= FWFLASH_HELP_FLAG; 152 break; 153 154 case 'v': 155 fwflash_arg_list |= FWFLASH_VER_FLAG; 156 break; 157 158 case 'y': 159 fwflash_arg_list |= FWFLASH_YES_FLAG; 160 break; 161 162 case 'l': 163 fwflash_arg_list |= FWFLASH_LIST_FLAG; 164 break; 165 166 case 'c': 167 fwflash_arg_list |= FWFLASH_CLASS_FLAG; 168 /* we validate later */ 169 devclass = strdup(optarg); 170 break; 171 172 case 'd': 173 fwflash_arg_list |= FWFLASH_DEVICE_FLAG; 174 devpath = strdup(optarg); 175 break; 176 177 case 'f': 178 fwflash_arg_list |= FWFLASH_FW_FLAG; 179 if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) { 180 fwflash_help(); 181 return (FWFLASH_FAILURE); 182 } 183 break; 184 185 case 'r': 186 fwflash_arg_list |= FWFLASH_READ_FLAG; 187 read_file = strdup(optarg); 188 break; 189 190 case 'Q': 191 /* NOT in the manpage */ 192 fwflash_debug = 1; 193 break; 194 195 /* illegal options */ 196 default: 197 fwflash_usage(optarg); 198 return (FWFLASH_FAILURE); 199 } 200 } 201 202 /* Do Help */ 203 if ((fwflash_arg_list & FWFLASH_HELP_FLAG) || 204 ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) && 205 !((fwflash_arg_list & FWFLASH_FW_FLAG) || 206 (fwflash_arg_list & FWFLASH_READ_FLAG)))) { 207 fwflash_help(); 208 return (FWFLASH_SUCCESS); 209 } 210 211 /* Do Version */ 212 if (fwflash_arg_list == FWFLASH_VER_FLAG) { 213 fwflash_version(); 214 return (FWFLASH_SUCCESS); 215 } 216 217 /* generate global list of devices */ 218 if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) { 219 logmsg(MSG_ERROR, 220 gettext("Unable to load fwflash plugins\n")); 221 fwflash_intr(0); 222 return (rv); 223 } 224 225 if ((rv = flash_device_list()) != FWFLASH_SUCCESS) { 226 logmsg(MSG_ERROR, 227 gettext("No flashable devices in this system\n")); 228 fwflash_intr(0); 229 return (rv); 230 } 231 232 /* Do list */ 233 if (fwflash_arg_list == (FWFLASH_LIST_FLAG) || 234 fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) { 235 rv = fwflash_list_fw(devclass); 236 fwflash_intr(0); 237 return (rv); 238 } 239 240 fwflash_handle_signals(); 241 242 /* Do flash update (write) */ 243 if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) || 244 (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG | 245 FWFLASH_YES_FLAG))) { 246 /* the update function handles the real arg parsing */ 247 i = 0; 248 while (filelist[i] != NULL) { 249 if ((rv = fwflash_update(devpath, filelist[i], 250 fwflash_arg_list)) == FWFLASH_SUCCESS) { 251 /* failed ops have already been noted */ 252 logmsg(MSG_ERROR, 253 gettext("New firmware will be activated " 254 "after you reboot\n\n")); 255 } 256 ++i; 257 } 258 259 fwflash_intr(0); 260 return (rv); 261 } 262 263 /* Do flash read */ 264 if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) || 265 (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG | 266 FWFLASH_YES_FLAG))) { 267 rv = fwflash_read_file(devpath, read_file); 268 fwflash_intr(0); 269 return (rv); 270 } 271 272 fwflash_usage(NULL); 273 274 return (FWFLASH_FAILURE); 275 } 276 277 278 279 280 281 static int 282 flash_load_plugins() { 283 284 int rval = FWFLASH_SUCCESS; 285 DIR *dirp; 286 struct dirent *plugdir; 287 char *plugname; 288 struct fw_plugin *tmpplug; 289 struct pluginlist *tmpelem; 290 void *sym; 291 char *fwplugdirpath, *tempdirpath; 292 293 294 #define CLOSEFREE() { \ 295 (void) dlclose(tmpplug->handle); \ 296 free(tmpplug); } 297 298 299 /* 300 * Procedure: 301 * 302 * cd /usr/lib/fwflash/identify 303 * open each .so file found therein 304 * dlopen(.sofile) 305 * if it's one of our plugins, add it to fw_pluginlist; 306 * 307 * functions we need here include dlopen and dlsym. 308 * 309 * If we get to the end and fw_pluginlist struct is empty, 310 * return FWFLASH_FAILURE so we return to the shell. 311 */ 312 313 if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 314 logmsg(MSG_ERROR, 315 gettext("Unable to malloc %d bytes while " 316 "trying to load plugins: %s\n"), 317 MAXPATHLEN + 1, strerror(errno)); 318 return (FWFLASH_FAILURE); 319 } 320 321 tempdirpath = getenv("FWPLUGINDIR"); 322 323 if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 324 (void) strlcpy(fwplugdirpath, tempdirpath, 325 strlen(tempdirpath) + 1); 326 } else { 327 (void) strlcpy(fwplugdirpath, FWPLUGINDIR, 328 strlen(FWPLUGINDIR) + 1); 329 } 330 331 if ((dirp = opendir(fwplugdirpath)) == NULL) { 332 logmsg(MSG_ERROR, 333 gettext("Unable to open %s!\n"), 334 fwplugdirpath); 335 return (errno); 336 } 337 338 if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1)) 339 == NULL) { 340 logmsg(MSG_ERROR, 341 gettext("Unable to malloc %d bytes while " 342 "trying to load plugins: %s\n"), 343 MAXPATHLEN + 1 + sizeof (struct dirent), 344 strerror(errno)); 345 return (FWFLASH_FAILURE); 346 } 347 348 if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin))) 349 == NULL) { 350 logmsg(MSG_ERROR, 351 gettext("Unable to malloc %d bytes while " 352 "trying to load plugins: %s\n"), 353 sizeof (struct fw_plugin) + 1, strerror(errno)); 354 return (FWFLASH_FAILURE); 355 } 356 357 NOTE(CONSTCOND) 358 TAILQ_INIT(fw_pluginlist); 359 360 while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) { 361 362 errno = 0; /* remove chance of false results */ 363 364 if ((plugdir->d_name[0] == '.') || 365 (strstr(plugdir->d_name, ".so") == NULL)) { 366 continue; 367 } 368 369 if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) { 370 logmsg(MSG_ERROR, 371 gettext("Unable to malloc %d bytes while " 372 "trying to load plugins: %s\n"), 373 MAXPATHLEN + 1, strerror(errno)); 374 return (FWFLASH_FAILURE); 375 } 376 377 (void) snprintf(plugname, MAXPATHLEN, "%s/%s", 378 fwplugdirpath, plugdir->d_name); 379 380 /* start allocating storage */ 381 if ((tmpelem = calloc(1, sizeof (struct pluginlist))) 382 == NULL) { 383 logmsg(MSG_ERROR, 384 gettext("Unable to malloc %d bytes while " 385 "trying to load plugins: %s\n"), 386 sizeof (struct pluginlist), strerror(errno)); 387 return (FWFLASH_FAILURE); 388 } 389 390 if ((tmpplug = calloc(1, sizeof (struct fw_plugin))) 391 == NULL) { 392 logmsg(MSG_ERROR, 393 gettext("Unable to malloc %d bytes while " 394 "trying to load plugins: %s\n"), 395 sizeof (struct fw_plugin), strerror(errno)); 396 return (FWFLASH_FAILURE); 397 } 398 399 /* load 'er up! */ 400 tmpplug->handle = dlopen(plugname, RTLD_NOW); 401 if (tmpplug->handle == NULL) { 402 free(tmpplug); 403 continue; /* assume there are other plugins */ 404 } 405 406 if ((tmpplug->filename = calloc(1, strlen(plugname) + 1)) 407 == NULL) { 408 logmsg(MSG_ERROR, 409 gettext("Unable to allocate %d bytes for plugin " 410 "filename %s:%s\n"), 411 strlen(plugname) + 1, plugname, 412 strerror(errno)); 413 return (rval); 414 } 415 416 (void) strlcpy(tmpplug->filename, plugname, 417 strlen(plugname) + 1); 418 419 /* now sanity check the file */ 420 if ((sym = dlsym(tmpplug->handle, "drivername")) 421 != NULL) { 422 /* max length of drivername */ 423 tmpplug->drvname = calloc(1, 17); 424 (void) strlcpy(tmpplug->drvname, (char *)sym, 17); 425 } else { 426 CLOSEFREE(); 427 continue; 428 } 429 if ((sym = dlsym(tmpplug->handle, "fw_readfw")) 430 != NULL) { 431 tmpplug->fw_readfw = (int (*)())sym; 432 } else { 433 CLOSEFREE(); 434 continue; 435 } 436 if ((sym = dlsym(tmpplug->handle, "fw_writefw")) 437 != NULL) { 438 tmpplug->fw_writefw = (int (*)())sym; 439 } else { 440 CLOSEFREE(); 441 continue; 442 } 443 444 if ((sym = dlsym(tmpplug->handle, "fw_identify")) 445 != NULL) { 446 tmpplug->fw_identify = 447 (int (*)(int))sym; 448 } else { 449 CLOSEFREE(); 450 continue; 451 } 452 if ((sym = dlsym(tmpplug->handle, "fw_devinfo")) 453 != NULL) { 454 tmpplug->fw_devinfo = 455 (int (*)(struct devicelist *))sym; 456 } else { 457 CLOSEFREE(); 458 continue; 459 } 460 461 if ((tmpelem->drvname = calloc(1, 17)) 462 == NULL) { 463 logmsg(MSG_ERROR, 464 gettext("Unable to allocate 17 bytes for " 465 "drivername %s\n"), 466 tmpplug->drvname); 467 return (FWFLASH_FAILURE); 468 } 469 470 (void) strlcpy(tmpelem->drvname, tmpplug->drvname, 471 strlen(tmpplug->drvname) + 1); 472 473 if ((tmpelem->filename = calloc(1, 474 strlen(tmpplug->filename) + 1)) == NULL) { 475 logmsg(MSG_ERROR, 476 gettext("Unable to allocate %d bytes for " 477 "filename %s\n"), 478 strlen(tmpplug->filename) + 1, 479 tmpplug->drvname); 480 return (FWFLASH_FAILURE); 481 } 482 483 (void) strlcpy(tmpelem->filename, plugname, 484 strlen(plugname) + 1); 485 tmpelem->plugin = tmpplug; 486 487 /* CONSTCOND */ 488 TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin); 489 } 490 491 if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) { 492 return (FWFLASH_FAILURE); 493 } 494 495 496 if (errno != 0) { 497 logmsg(MSG_ERROR, 498 gettext("Error reading directory entry in %s\n"), 499 fwplugdirpath); 500 (void) closedir(dirp); 501 rval = errno; 502 } 503 504 (void) free(fwplugdirpath); 505 (void) free(plugdir); 506 (void) closedir(dirp); 507 return (rval); 508 } 509 510 511 512 /* 513 * fwflash_load_verifier dlload()s the appropriate firmware image 514 * verification plugin, and attaches the designated fwimg's fd to 515 * the vrfyplugin structure so we only have to load the image in 516 * one place. 517 */ 518 int 519 fwflash_load_verifier(char *drv, char *vendorid, char *fwimg) { 520 521 int rv = FWFLASH_FAILURE; 522 int imgfd; 523 char *fwvrfydirpath, *tempdirpath, *filename; 524 char *clean; /* for the space-removed vid */ 525 526 struct stat fwstat; 527 struct vrfyplugin *vrfy; 528 void *vrfysym; 529 530 531 /* 532 * To make flashing multiple firmware images somewhat more 533 * efficient, we start this function by checking whether a 534 * verifier for this device has already been loaded. If it 535 * has been loaded, we replace the imgfile information, and 536 * then continue as if we were loading for the first time. 537 */ 538 539 if (verifier != NULL) { 540 verifier->imgsize = 0; 541 verifier->flashbuf = 0; /* set by the verifier function */ 542 543 if (verifier->imgfile != NULL) 544 (void) free(verifier->imgfile); 545 546 if (verifier->fwimage != NULL) 547 (void) free(verifier->fwimage); 548 } else { 549 if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 550 logmsg(MSG_ERROR, 551 gettext("Unable to allocate space for a firmware " 552 "verifier file(1)")); 553 return (rv); 554 } 555 556 if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) { 557 logmsg(MSG_ERROR, 558 gettext("Unable to allocate space " 559 "for a firmware verifier file(2)")); 560 return (rv); 561 } 562 563 /* 564 * Since SCSI devices can have a vendor id of up to 8 left-aligned 565 * and _space-padded_ characters, we first need to strip off any 566 * space characters before we try to make a filename out of it 567 */ 568 clean = strtok(vendorid, " "); 569 if (clean == NULL) { 570 /* invalid vendorid, something's really wrong */ 571 logmsg(MSG_ERROR, 572 gettext("Invalid vendorid (null) specified for " 573 "device\n")); 574 return (rv); 575 } 576 577 tempdirpath = getenv("FWVERIFYPLUGINDIR"); 578 579 if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 580 (void) strlcpy(fwvrfydirpath, tempdirpath, 581 strlen(tempdirpath) + 1); 582 } else { 583 (void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR, 584 strlen(FWVERIFYPLUGINDIR) + 1); 585 } 586 587 if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) { 588 logmsg(MSG_ERROR, 589 gettext("Unable to allocate space " 590 "for a firmware verifier structure")); 591 free(filename); 592 free(fwvrfydirpath); 593 return (FWFLASH_FAILURE); 594 } 595 596 errno = 0; /* false positive removal */ 597 598 (void) snprintf(filename, strlen(fwvrfydirpath) + 599 strlen(drv) + 7 + strlen(clean), "%s/%s-%s.so\0", 600 fwvrfydirpath, drv, clean); 601 602 if ((vrfy->filename = calloc(1, strlen(filename) + 1)) 603 == NULL) { 604 logmsg(MSG_ERROR, 605 gettext("Unable to allocate space to store " 606 "a verifier filename\n")); 607 free(filename); 608 free(fwvrfydirpath); 609 free(vrfy->handle); 610 return (FWFLASH_FAILURE); 611 } 612 613 (void) strlcpy(vrfy->filename, filename, strlen(filename) + 1); 614 615 if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) { 616 logmsg(MSG_ERROR, gettext(dlerror())); 617 logmsg(MSG_ERROR, 618 gettext("Unable to open verification plugin " 619 "%s.\nUnable to verify firmware image. " 620 "Aborting.\n"), 621 filename); 622 free(filename); 623 free(fwvrfydirpath); 624 return (FWFLASH_FAILURE); 625 } 626 627 if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) { 628 logmsg(MSG_ERROR, 629 gettext("%s is an invalid firmware verification " 630 "plugin."), filename); 631 (void) dlclose(vrfy->handle); 632 free(filename); 633 free(fwvrfydirpath); 634 free(vrfy); 635 return (FWFLASH_FAILURE); 636 } else { 637 vrfy->vendorvrfy = 638 (int (*)(struct devicelist *))vrfysym; 639 } 640 641 vrfysym = dlsym(vrfy->handle, "vendor"); 642 643 if (vrfysym == NULL) { 644 logmsg(MSG_ERROR, 645 gettext("Invalid vendor (null) in verification " 646 "plugin %s\n"), filename); 647 (void) dlclose(vrfy->handle); 648 free(vrfy); 649 return (NULL); 650 } else { 651 if (strncmp(vendorid, (char *)vrfysym, 652 strlen(vendorid)) != 0) { 653 logmsg(MSG_INFO, 654 "Using a sym-linked (%s -> %s) " 655 "verification plugin", 656 vendorid, vrfysym); 657 vrfy->vendor = calloc(1, strlen(vendorid) + 1); 658 } else { 659 vrfy->vendor = calloc(1, strlen(vrfysym) + 1); 660 } 661 (void) strlcpy(vrfy->vendor, (char *)vrfysym, 662 strlen(vendorid) + 1); 663 } 664 665 verifier = vrfy; /* a convenience variable */ 666 } 667 668 669 /* 670 * We don't do any verification that the fw image file is in 671 * an approved location, but it's easy enough to modify this 672 * function to do so. The verification plugin should provide 673 * sufficient protection. 674 */ 675 676 if ((imgfd = open(fwimg, O_RDONLY)) < 0) { 677 logmsg(MSG_ERROR, 678 gettext("Unable to open designated firmware " 679 "image file %s: %s\n"), 680 (fwimg != NULL) ? fwimg : "(null)", 681 strerror(errno)); 682 rv = FWFLASH_FAILURE; 683 goto cleanup; 684 } 685 686 if (stat(fwimg, &fwstat) == -1) { 687 logmsg(MSG_ERROR, 688 gettext("Unable to stat() firmware image file " 689 "%s: %s\n"), 690 fwimg, strerror(errno)); 691 rv = FWFLASH_FAILURE; 692 goto cleanup; 693 } else { 694 verifier->imgsize = fwstat.st_size; 695 if ((verifier->fwimage = calloc(1, verifier->imgsize)) 696 == NULL) { 697 logmsg(MSG_ERROR, 698 gettext("Unable to load firmware image " 699 "%s: %s\n"), 700 fwimg, strerror(errno)); 701 rv = FWFLASH_FAILURE; 702 goto cleanup; 703 } 704 } 705 706 errno = 0; 707 if ((rv = read(imgfd, verifier->fwimage, 708 (size_t)verifier->imgsize)) < verifier->imgsize) { 709 /* we haven't read enough data, bail */ 710 logmsg(MSG_ERROR, 711 gettext("Failed to read sufficient data " 712 "(got %d bytes, expected %d bytes) from " 713 "firmware image file %s: %s\n"), 714 rv, verifier->imgsize, 715 filename, strerror(errno)); 716 rv = FWFLASH_FAILURE; 717 } else { 718 rv = FWFLASH_SUCCESS; 719 } 720 721 if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) { 722 logmsg(MSG_ERROR, 723 gettext("Unable to save name of firmware image\n")); 724 rv = FWFLASH_FAILURE; 725 } else { 726 (void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1); 727 } 728 729 if (rv != FWFLASH_SUCCESS) { 730 /* cleanup and let's get outta here */ 731 cleanup: 732 free(verifier->filename); 733 free(verifier->vendor); 734 735 if (!(fwflash_arg_list & FWFLASH_READ_FLAG)) 736 free(verifier->fwimage); 737 738 verifier->filename = NULL; 739 verifier->vendor = NULL; 740 verifier->vendorvrfy = NULL; 741 verifier->fwimage = NULL; 742 (void) dlclose(verifier->handle); 743 verifier->handle = NULL; 744 free(verifier); 745 if (imgfd >= 0) { 746 (void) close(imgfd); 747 } 748 verifier = NULL; 749 } 750 751 return (rv); 752 } 753 754 755 756 /* 757 * cycles through the global list of plugins to find 758 * each flashable device, which is added to fw_devices 759 * 760 * Each plugin's identify routine must allocated storage 761 * as required. 762 * 763 * Each plugin's identify routine must return 764 * FWFLASH_FAILURE if it cannot find any devices 765 * which it handles. 766 */ 767 static int 768 flash_device_list() 769 { 770 int rv = FWFLASH_FAILURE; 771 int startidx = 0; 772 int sumrv = 0; 773 struct pluginlist *plugins; 774 775 776 /* we open rootnode here, and close it in fwflash_intr */ 777 if ((rootnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 778 logmsg(MSG_ERROR, 779 gettext("Unable to take device tree snapshot: %s\n"), 780 strerror(errno)); 781 return (rv); 782 } 783 784 if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) { 785 logmsg(MSG_ERROR, 786 gettext("Unable to malloc %d bytes while " 787 "trying to find devices: %s\n"), 788 sizeof (struct devicelist), strerror(errno)); 789 return (FWFLASH_FAILURE); 790 } 791 792 /* CONSTCOND */ 793 TAILQ_INIT(fw_devices); 794 795 TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) { 796 self = plugins->plugin; 797 rv = plugins->plugin->fw_identify(startidx); 798 799 logmsg(MSG_INFO, 800 gettext("fwflash:flash_device_list() got %d from " 801 "identify routine\n"), rv); 802 803 /* only bump startidx if we've found at least one device */ 804 if (rv == FWFLASH_SUCCESS) { 805 startidx += 100; 806 sumrv++; 807 } else { 808 logmsg(MSG_INFO, 809 gettext("No flashable devices attached with " 810 "the %s driver in this system\n"), 811 plugins->drvname); 812 } 813 } 814 815 if (sumrv > 0) 816 rv = FWFLASH_SUCCESS; 817 818 return (rv); 819 } 820 821 822 823 824 static int 825 fwflash_list_fw(char *class) 826 { 827 int rv = 0; 828 struct devicelist *curdev; 829 int header = 1; 830 831 832 TAILQ_FOREACH(curdev, fw_devices, nextdev) { 833 834 /* we're either class-conscious, or we're not */ 835 if (((class != NULL) && 836 ((strncmp(curdev->classname, "ALL", 3) == 0) || 837 (strcmp(curdev->classname, class) == 0))) || 838 (class == NULL)) { 839 840 if (header != 0) { 841 (void) fprintf(stdout, 842 gettext("List of available devices:\n")); 843 header--; 844 } 845 /* 846 * If any plugin's fw_devinfo() function returns 847 * FWFLASH_FAILURE then we want to keep track of 848 * it. _Most_ plugins should always return 849 * FWFLASH_SUCCESS from this function. The only 850 * exception known at this point is the tavor plugin. 851 */ 852 rv += curdev->plugin->fw_devinfo(curdev); 853 } 854 } 855 856 857 return (rv); 858 } 859 860 861 static int 862 fwflash_update(char *device, char *filename, int flags) { 863 864 865 int rv = FWFLASH_FAILURE; 866 int needsfree = 0; 867 struct devicelist *curdev; 868 char *realfile; 869 870 871 /* 872 * Here's how we operate: 873 * 874 * We perform some basic checks on the args, then walk 875 * through the device list looking for the device which 876 * matches. We then load the appropriate verifier for the 877 * image file and device, verify the image, then call the 878 * fw_writefw() function of the appropriate plugin. 879 * 880 * There is no "force" flag to enable you to flash a firmware 881 * image onto an incompatible device because the verifier 882 * will return FWFLASH_FAILURE if the image doesn't match. 883 * 884 */ 885 886 887 /* new firmware filename and device desc */ 888 if (filename == NULL) { 889 logmsg(MSG_ERROR, 890 gettext("Invalid firmware filename (null)\n")); 891 return (FWFLASH_FAILURE); 892 } 893 894 if (device == NULL) { 895 logmsg(MSG_ERROR, 896 gettext("Invalid device requested (null)\n")); 897 return (FWFLASH_FAILURE); 898 } 899 900 if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) { 901 logmsg(MSG_ERROR, 902 gettext("Unable to allocate space for device " 903 "filename, operation might fail\nif %s is" 904 "a symbolic link\n"), 905 device); 906 realfile = device; 907 } else { 908 /* 909 * If realpath() succeeds, then we have a valid 910 * device filename in realfile. 911 */ 912 if (realpath(device, realfile) == NULL) { 913 logmsg(MSG_ERROR, 914 gettext("Unable to resolve device filename" 915 ": %s\n"), 916 strerror(errno)); 917 /* tidy up */ 918 free(realfile); 919 /* realpath didn't succeed, use fallback */ 920 realfile = device; 921 } else { 922 needsfree = 1; 923 } 924 } 925 926 logmsg(MSG_INFO, 927 gettext("fwflash_update: fw_filename (%s) device (%s)\n"), 928 filename, device); 929 930 TAILQ_FOREACH(curdev, fw_devices, nextdev) { 931 932 if (strcmp(curdev->access_devname, realfile) == 0) { 933 rv = fwflash_load_verifier(curdev->drvname, 934 curdev->ident->vid, filename); 935 if (rv == FWFLASH_FAILURE) { 936 logmsg(MSG_ERROR, 937 gettext("Unable to load verifier " 938 "for device %s\n"), 939 curdev->access_devname); 940 return (FWFLASH_FAILURE); 941 } 942 rv = verifier->vendorvrfy(curdev); 943 if (rv == FWFLASH_FAILURE) { 944 /* the verifier prints a message */ 945 logmsg(MSG_INFO, 946 "verifier (%s) for %s :: %s returned " 947 "FWFLASH_FAILURE\n", 948 verifier->filename, 949 filename, curdev->access_devname); 950 return (rv); 951 } 952 953 if ((flags == FWFLASH_YES_FLAG) || 954 (rv = confirm_target(curdev, filename)) == 955 FWFLASH_YES_FLAG) { 956 logmsg(MSG_INFO, 957 "about to flash using plugin %s\n", 958 curdev->plugin->filename); 959 rv = curdev->plugin->fw_writefw(curdev, 960 filename); 961 if (rv == FWFLASH_FAILURE) { 962 logmsg(MSG_ERROR, 963 gettext("Failed to flash " 964 "firmware file %s on " 965 "device %s: %d\n"), 966 filename, 967 curdev->access_devname, rv); 968 } 969 } else { 970 logmsg(MSG_ERROR, 971 gettext("Flash operation not confirmed " 972 "by user\n"), 973 curdev->access_devname); 974 rv = FWFLASH_FAILURE; 975 } 976 } 977 } 978 979 if (needsfree) 980 free(realfile); 981 982 return (rv); 983 } 984 985 /* 986 * We validate that the device path is in our global device list and 987 * that the filename exists, then palm things off to the relevant plugin. 988 */ 989 990 static int 991 fwflash_read_file(char *device, char *filename) 992 { 993 struct devicelist *curdev; 994 int rv; 995 int notfound = 0; 996 997 /* new firmware filename and device desc */ 998 999 TAILQ_FOREACH(curdev, fw_devices, nextdev) { 1000 if (strncmp(curdev->access_devname, device, 1001 MAXPATHLEN) == 0) { 1002 rv = curdev->plugin->fw_readfw(curdev, filename); 1003 1004 if (rv != FWFLASH_SUCCESS) 1005 logmsg(MSG_ERROR, 1006 gettext("Unable to write out firmware " 1007 "image for %s to file %s\n"), 1008 curdev->access_devname, filename); 1009 } else { 1010 notfound++; 1011 } 1012 1013 } 1014 if (notfound) { 1015 logmsg(MSG_ERROR, 1016 gettext("No device matching %s was found.\n"), 1017 device); 1018 rv = FWFLASH_FAILURE; 1019 } 1020 1021 return (rv); 1022 } 1023 1024 static void 1025 fwflash_usage(char *arg) 1026 { 1027 1028 (void) fprintf(stderr, "\n"); 1029 if (arg != NULL) { 1030 logmsg(MSG_ERROR, 1031 gettext("Invalid argument (%s) supplied\n"), arg); 1032 } 1033 1034 (void) fprintf(stderr, "\n"); 1035 1036 (void) fprintf(stdout, gettext("Usage:\n\t")); 1037 (void) fprintf(stdout, gettext("fwflash [-l [-c device_class " 1038 "| ALL]] | [-v] | [-h]\n\t")); 1039 (void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3" 1040 ",... | -r file] [-y] -d device_path\n\n")); 1041 (void) fprintf(stdout, "\n"); /* workaround for xgettext */ 1042 1043 (void) fprintf(stdout, 1044 gettext("\t-l\t\tlist flashable devices in this system\n" 1045 "\t-c device_class limit search to a specific class\n" 1046 "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n" 1047 "\t-v\t\tprint version number of fwflash utility\n" 1048 "\t-h\t\tprint this usage mesage\n\n")); 1049 (void) fprintf(stdout, 1050 gettext("\t-f file1,file2,file3,...\n" 1051 "\t\t\tfirmware image file list to flash\n" 1052 "\t-r file\t\tfile to dump device firmware to\n" 1053 "\t-y\t\tanswer Yes/Y/y to prompts\n" 1054 "\t-d device_path\tpathname of device to be flashed\n\n")); 1055 1056 (void) fprintf(stdout, 1057 gettext("\tIf -d device_path is specified, then one of -f " 1058 "<files>\n" 1059 "\tor -r <file> must also be specified\n\n")); 1060 1061 (void) fprintf(stdout, 1062 gettext("\tIf multiple firmware images are required to be " 1063 "flashed\n" 1064 "\tthey must be listed together, separated by commas. The\n" 1065 "\timages will be flashed in the order specified.\n\n")); 1066 1067 1068 (void) fprintf(stdout, "\n"); 1069 } 1070 1071 1072 1073 1074 1075 1076 1077 static void 1078 fwflash_version(void) 1079 { 1080 (void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME); 1081 (void) fprintf(stdout, gettext("version %s\n"), 1082 FWFLASH_VERSION); 1083 1084 1085 } 1086 1087 static void 1088 fwflash_help(void) 1089 { 1090 fwflash_usage(NULL); 1091 } 1092 1093 /* ARGSUSED */ 1094 static void 1095 fwflash_intr(int sig) 1096 { 1097 1098 struct devicelist *thisdev; 1099 struct pluginlist *thisplug; 1100 1101 1102 (void) signal(SIGINT, SIG_IGN); 1103 (void) signal(SIGTERM, SIG_IGN); 1104 if (fwflash_in_write) { 1105 (void) fprintf(stderr, 1106 gettext("WARNING: firmware image may be corrupted\n\t")); 1107 (void) fprintf(stderr, 1108 gettext("Reflash firmware before rebooting!\n")); 1109 } 1110 1111 if (sig > 0) { 1112 (void) logmsg(MSG_ERROR, gettext("\n")); 1113 (void) logmsg(MSG_ERROR, 1114 gettext("fwflash exiting due to signal (%d)\n"), sig); 1115 } 1116 1117 /* 1118 * we need to close everything down properly, so 1119 * call the plugin closure routines 1120 */ 1121 1122 if (fw_devices != NULL) { 1123 1124 TAILQ_FOREACH(thisdev, fw_devices, nextdev) { 1125 /* free the components first */ 1126 free(thisdev->access_devname); 1127 free(thisdev->drvname); 1128 free(thisdev->classname); 1129 if (thisdev->ident != NULL) { 1130 free(thisdev->ident->vid); 1131 free(thisdev->ident->pid); 1132 free(thisdev->ident->revid); 1133 free(thisdev->ident); 1134 } 1135 thisdev->ident = NULL; 1136 thisdev->plugin = NULL; /* we free this elsewhere */ 1137 /* CONSTCOND */ 1138 TAILQ_REMOVE(fw_devices, thisdev, nextdev); 1139 } 1140 } 1141 1142 1143 if (fw_pluginlist != NULL) { 1144 1145 TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) { 1146 free(thisplug->filename); 1147 free(thisplug->drvname); 1148 free(thisplug->plugin->filename); 1149 free(thisplug->plugin->drvname); 1150 thisplug->filename = NULL; 1151 thisplug->drvname = NULL; 1152 thisplug->plugin->filename = NULL; 1153 thisplug->plugin->drvname = NULL; 1154 thisplug->plugin->fw_readfw = NULL; 1155 thisplug->plugin->fw_writefw = NULL; 1156 thisplug->plugin->fw_identify = NULL; 1157 thisplug->plugin->fw_devinfo = NULL; 1158 (void) dlclose(thisplug->plugin->handle); 1159 thisplug->plugin->handle = NULL; 1160 free(thisplug->plugin); 1161 thisplug->plugin = NULL; 1162 /* CONSTCOND */ 1163 TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin); 1164 1165 } 1166 } 1167 1168 1169 if (verifier != NULL) { 1170 free(verifier->filename); 1171 free(verifier->vendor); 1172 verifier->filename = NULL; 1173 verifier->vendor = NULL; 1174 verifier->vendorvrfy = NULL; 1175 (void) dlclose(verifier->handle); 1176 verifier->handle = NULL; 1177 free(verifier); 1178 } 1179 1180 di_fini(rootnode); 1181 } 1182 1183 static void 1184 fwflash_handle_signals(void) 1185 { 1186 if (signal(SIGINT, fwflash_intr) == SIG_ERR) { 1187 perror("signal"); 1188 exit(FWFLASH_FAILURE); 1189 } 1190 1191 if (signal(SIGTERM, fwflash_intr) == SIG_ERR) { 1192 perror("signal"); 1193 exit(FWFLASH_FAILURE); 1194 } 1195 } 1196 1197 static int 1198 confirm_target(struct devicelist *thisdev, char *file) 1199 { 1200 int resp; 1201 1202 (void) printf(gettext("About to update firmware on:\n " 1203 "%s\nwith file %s.\n" 1204 "Do you want to continue? (Y/N): "), 1205 thisdev->access_devname, file); 1206 1207 resp = getchar(); 1208 if (resp == 'Y' || resp == 'y') { 1209 return (FWFLASH_YES_FLAG); 1210 } else { 1211 logmsg(MSG_INFO, "flash operation NOT confirmed.\n"); 1212 } 1213 1214 (void) fflush(stdin); 1215 1216 return (FWFLASH_FAILURE); 1217 } 1218 1219 int 1220 get_fileopts(char *options) 1221 { 1222 1223 int i; 1224 char *files; 1225 1226 1227 if (files = strtok(options, ",")) { 1228 /* we have more than one */ 1229 if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 1230 logmsg(MSG_ERROR, 1231 gettext("Unable to allocate space for " 1232 "a firmware image filename\n")); 1233 return (FWFLASH_FAILURE); 1234 } 1235 (void) strlcpy(filelist[0], files, strlen(files) + 1); 1236 i = 1; 1237 1238 logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 1239 filelist[0]); 1240 1241 1242 while (files = strtok(NULL, ",")) { 1243 if ((filelist[i] = calloc(1, MAXPATHLEN + 1)) 1244 == NULL) { 1245 logmsg(MSG_ERROR, 1246 gettext("Unable to allocate space for " 1247 "a firmware image filename\n")); 1248 return (FWFLASH_FAILURE); 1249 } 1250 (void) strlcpy(filelist[i], files, 1251 strlen(files) + 1); 1252 logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n", 1253 i, filelist[i]); 1254 ++i; 1255 } 1256 } else { 1257 if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 1258 logmsg(MSG_ERROR, 1259 gettext("Unable to allocate space for " 1260 "a firmware image filename\n")); 1261 return (FWFLASH_FAILURE); 1262 } 1263 (void) strlcpy(filelist[0], options, strlen(files) + 1); 1264 logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 1265 filelist[0]); 1266 } 1267 return (FWFLASH_SUCCESS); 1268 1269 } 1270 1271 1272 1273 /* 1274 * code reuse - cheerfully borrowed from stmsboot_util.c 1275 */ 1276 void 1277 logmsg(int severity, char *msg, ...) { 1278 1279 va_list ap; 1280 1281 1282 if ((severity > MSG_INFO) || 1283 ((severity == MSG_INFO) && (fwflash_debug > 0))) { 1284 1285 (void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME); 1286 va_start(ap, msg); 1287 /* LINTED - format specifier */ 1288 (void) vfprintf(stderr, msg, ap); 1289 va_end(ap); 1290 } 1291 } 1292