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