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