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