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