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