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