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