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