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