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