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