15a7763bfSjmcp /* 25a7763bfSjmcp * CDDL HEADER START 35a7763bfSjmcp * 45a7763bfSjmcp * The contents of this file are subject to the terms of the 55a7763bfSjmcp * Common Development and Distribution License (the "License"). 65a7763bfSjmcp * You may not use this file except in compliance with the License. 75a7763bfSjmcp * 85a7763bfSjmcp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 95a7763bfSjmcp * or http://www.opensolaris.org/os/licensing. 105a7763bfSjmcp * See the License for the specific language governing permissions 115a7763bfSjmcp * and limitations under the License. 125a7763bfSjmcp * 135a7763bfSjmcp * When distributing Covered Code, include this CDDL HEADER in each 145a7763bfSjmcp * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 155a7763bfSjmcp * If applicable, add the following below this CDDL HEADER, with the 165a7763bfSjmcp * fields enclosed by brackets "[]" replaced with your own identifying 175a7763bfSjmcp * information: Portions Copyright [yyyy] [name of copyright owner] 185a7763bfSjmcp * 195a7763bfSjmcp * CDDL HEADER END 205a7763bfSjmcp */ 215a7763bfSjmcp /* 2287d06e46Speihong huang * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 235a7763bfSjmcp * Use is subject to license terms. 245a7763bfSjmcp */ 255a7763bfSjmcp 265a7763bfSjmcp /* 275a7763bfSjmcp * fwflash.c 285a7763bfSjmcp */ 295a7763bfSjmcp #include <stdio.h> 305a7763bfSjmcp #include <stdlib.h> 315a7763bfSjmcp #include <unistd.h> 325a7763bfSjmcp #include <strings.h> 335a7763bfSjmcp #include <errno.h> 345a7763bfSjmcp #include <sys/queue.h> 355a7763bfSjmcp #include <signal.h> 365a7763bfSjmcp #include <locale.h> 375a7763bfSjmcp #include <sys/stat.h> 385a7763bfSjmcp #include <sys/types.h> 395a7763bfSjmcp #include <sys/param.h> 405a7763bfSjmcp #include <fcntl.h> 415a7763bfSjmcp #include <dlfcn.h> 425a7763bfSjmcp #include <dirent.h> 435a7763bfSjmcp #include <sys/varargs.h> 445a7763bfSjmcp #include <libintl.h> /* for gettext(3c) */ 455a7763bfSjmcp #include <libdevinfo.h> 464196e263SSherry Moore #include <libscf_priv.h> 475a7763bfSjmcp #include <fwflash/fwflash.h> 48c4800545Sjmcp #include <sys/modctl.h> /* for MAXMODCONFNAME */ 495a7763bfSjmcp 505a7763bfSjmcp 515a7763bfSjmcp #if !defined(lint) 525a7763bfSjmcp /* embedded software license agreement */ 535a7763bfSjmcp static char *sla [] = { "Copyright 2007 Sun Microsystems, Inc., 4150 Network " 545a7763bfSjmcp "Circle, Santa Clara, California 95054, U.S.A. All rights reserved. U.S. " 555a7763bfSjmcp "Government Rights - Commercial software. Government users are subject to the " 565a7763bfSjmcp "Sun Microsystems, Inc. standard license agreement and applicable provisions " 575a7763bfSjmcp "of the FAR and its supplements. Use is subject to license terms. Parts of " 585a7763bfSjmcp "the product may be derived from Berkeley BSD systems, licensed from the " 595a7763bfSjmcp "University of California. UNIX is a registered trademark in the U.S. and in " 605a7763bfSjmcp "other countries, exclusively licensed through X/Open Company, Ltd.Sun, Sun " 615a7763bfSjmcp "Microsystems, the Sun logo and Solaris are trademarks or registered " 625a7763bfSjmcp "trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This " 635a7763bfSjmcp "product is covered and controlled by U.S. Export Control laws and may be " 645a7763bfSjmcp "subject to the export or import laws in other countries. Nuclear, missile, " 655a7763bfSjmcp "chemical biological weapons or nuclear maritime end uses or end users, " 665a7763bfSjmcp "whether direct or indirect, are strictly prohibited. Export or reexport " 675a7763bfSjmcp "to countries subject to U.S. embargo or to entities identified on U.S. export " 685a7763bfSjmcp "exclusion lists, including, but not limited to, the denied persons and " 695a7763bfSjmcp "specially designated nationals lists is strictly prohibited." }; 705a7763bfSjmcp #endif /* lint */ 715a7763bfSjmcp 725a7763bfSjmcp /* global arg list */ 735a7763bfSjmcp int fwflash_arg_list = 0; 745a7763bfSjmcp char *filelist[10]; 755a7763bfSjmcp 76*a799b1e7Speihong huang /* exposed global args */ 77*a799b1e7Speihong huang di_node_t rootnode; 78*a799b1e7Speihong huang struct PLUGINLIST *fw_pluginlist; 79*a799b1e7Speihong huang struct DEVICELIST *fw_devices; 80*a799b1e7Speihong huang struct vrfyplugin *verifier; 81*a799b1e7Speihong huang struct fw_plugin *self; 82*a799b1e7Speihong huang int fwflash_debug = 0; 83*a799b1e7Speihong huang 845a7763bfSjmcp /* are we writing to flash? */ 855a7763bfSjmcp static int fwflash_in_write = 0; 865a7763bfSjmcp 875a7763bfSjmcp /* 885a7763bfSjmcp * If we *must* track the version string for fwflash, then 895a7763bfSjmcp * we should do so in this common file rather than the header 905a7763bfSjmcp * file since it will then be in sync with what the customer 91f1c23465SJames C. McPherson * sees. We should deprecate the "-v" option since it is not 92f1c23465SJames C. McPherson * actually of any use - it doesn't line up with Mercurial's 93f1c23465SJames C. McPherson * concept of the changeset. 945a7763bfSjmcp */ 95d65b419eSXinChen #define FWFLASH_VERSION "v1.8" 965a7763bfSjmcp #define FWFLASH_PROG_NAME "fwflash" 975a7763bfSjmcp 985a7763bfSjmcp static int get_fileopts(char *options); 995a7763bfSjmcp static int flash_device_list(); 1005a7763bfSjmcp static int flash_load_plugins(); 1015a7763bfSjmcp static int fwflash_update(char *device, char *filename, int flags); 1025a7763bfSjmcp static int fwflash_read_file(char *device, char *filename); 1035a7763bfSjmcp static int fwflash_list_fw(char *class); 1045a7763bfSjmcp static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg); 1055a7763bfSjmcp static void fwflash_intr(int sig); 1065a7763bfSjmcp static void fwflash_handle_signals(void); 107f1c23465SJames C. McPherson static void fwflash_usage(char *arg); 1085a7763bfSjmcp static void fwflash_version(void); 1095a7763bfSjmcp static int confirm_target(struct devicelist *thisdev, char *file); 1105a7763bfSjmcp 1115a7763bfSjmcp /* 1125a7763bfSjmcp * FWFlash main code 1135a7763bfSjmcp */ 1145a7763bfSjmcp int 115f8bf33c3SShantkumar Hiremath main(int argc, char **argv) 116f8bf33c3SShantkumar Hiremath { 1175a7763bfSjmcp int rv = FWFLASH_SUCCESS; 1185a7763bfSjmcp int i; 1195a7763bfSjmcp char ch; 1205a7763bfSjmcp char *read_file; 1215a7763bfSjmcp extern char *optarg; 1225a7763bfSjmcp char *devclass = NULL; 1235a7763bfSjmcp char *devpath = NULL; 1245a7763bfSjmcp 1255a7763bfSjmcp /* local variables from env */ 1265a7763bfSjmcp (void) setlocale(LC_ALL, ""); 1275a7763bfSjmcp 1285a7763bfSjmcp #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1295a7763bfSjmcp #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ 1305a7763bfSjmcp #endif 1315a7763bfSjmcp 1325a7763bfSjmcp (void) textdomain(TEXT_DOMAIN); 1335a7763bfSjmcp 1345a7763bfSjmcp read_file = NULL; 1355a7763bfSjmcp 1365a7763bfSjmcp if (argc < 2) { 1375a7763bfSjmcp /* no args supplied */ 1385a7763bfSjmcp fwflash_usage(NULL); 1395a7763bfSjmcp return (FWFLASH_FAILURE); 1405a7763bfSjmcp } 1415a7763bfSjmcp 14287d06e46Speihong huang while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:")) != EOF) { 1435a7763bfSjmcp switch (ch) { 1445a7763bfSjmcp case 'h': 1455a7763bfSjmcp fwflash_arg_list |= FWFLASH_HELP_FLAG; 1465a7763bfSjmcp break; 1475a7763bfSjmcp case 'v': 1485a7763bfSjmcp fwflash_arg_list |= FWFLASH_VER_FLAG; 1495a7763bfSjmcp break; 1505a7763bfSjmcp case 'y': 1515a7763bfSjmcp fwflash_arg_list |= FWFLASH_YES_FLAG; 1525a7763bfSjmcp break; 1535a7763bfSjmcp case 'l': 1545a7763bfSjmcp fwflash_arg_list |= FWFLASH_LIST_FLAG; 1555a7763bfSjmcp break; 1565a7763bfSjmcp case 'c': 1575a7763bfSjmcp fwflash_arg_list |= FWFLASH_CLASS_FLAG; 1585a7763bfSjmcp /* we validate later */ 1595a7763bfSjmcp devclass = strdup(optarg); 1605a7763bfSjmcp break; 1615a7763bfSjmcp case 'd': 1625a7763bfSjmcp fwflash_arg_list |= FWFLASH_DEVICE_FLAG; 1635a7763bfSjmcp devpath = strdup(optarg); 1645a7763bfSjmcp break; 1655a7763bfSjmcp case 'f': 1665a7763bfSjmcp fwflash_arg_list |= FWFLASH_FW_FLAG; 1675a7763bfSjmcp if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) { 168f1c23465SJames C. McPherson fwflash_usage(NULL); 1695a7763bfSjmcp return (FWFLASH_FAILURE); 1705a7763bfSjmcp } 1715a7763bfSjmcp break; 1725a7763bfSjmcp case 'r': 1735a7763bfSjmcp fwflash_arg_list |= FWFLASH_READ_FLAG; 1745a7763bfSjmcp read_file = strdup(optarg); 1755a7763bfSjmcp break; 1765a7763bfSjmcp case 'Q': 1775a7763bfSjmcp /* NOT in the manpage */ 1785a7763bfSjmcp fwflash_debug = 1; 1795a7763bfSjmcp break; 1805a7763bfSjmcp /* illegal options */ 1815a7763bfSjmcp default: 1825a7763bfSjmcp fwflash_usage(optarg); 1835a7763bfSjmcp return (FWFLASH_FAILURE); 1845a7763bfSjmcp } 1855a7763bfSjmcp } 1865a7763bfSjmcp 1875a7763bfSjmcp /* Do Help */ 1885a7763bfSjmcp if ((fwflash_arg_list & FWFLASH_HELP_FLAG) || 1895a7763bfSjmcp ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) && 1905a7763bfSjmcp !((fwflash_arg_list & FWFLASH_FW_FLAG) || 1915a7763bfSjmcp (fwflash_arg_list & FWFLASH_READ_FLAG)))) { 192f1c23465SJames C. McPherson fwflash_usage(NULL); 1935a7763bfSjmcp return (FWFLASH_SUCCESS); 1945a7763bfSjmcp } 1955a7763bfSjmcp 1965a7763bfSjmcp /* Do Version */ 1975a7763bfSjmcp if (fwflash_arg_list == FWFLASH_VER_FLAG) { 1985a7763bfSjmcp fwflash_version(); 1995a7763bfSjmcp return (FWFLASH_SUCCESS); 2005a7763bfSjmcp } 2015a7763bfSjmcp 2025a7763bfSjmcp /* generate global list of devices */ 2035a7763bfSjmcp if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) { 2045a7763bfSjmcp logmsg(MSG_ERROR, 2055a7763bfSjmcp gettext("Unable to load fwflash plugins\n")); 2065a7763bfSjmcp fwflash_intr(0); 2075a7763bfSjmcp return (rv); 2085a7763bfSjmcp } 2095a7763bfSjmcp 2105a7763bfSjmcp if ((rv = flash_device_list()) != FWFLASH_SUCCESS) { 2115a7763bfSjmcp logmsg(MSG_ERROR, 2125a7763bfSjmcp gettext("No flashable devices in this system\n")); 2135a7763bfSjmcp fwflash_intr(0); 2145a7763bfSjmcp return (rv); 2155a7763bfSjmcp } 2165a7763bfSjmcp 2175a7763bfSjmcp /* Do list */ 2185a7763bfSjmcp if (fwflash_arg_list == (FWFLASH_LIST_FLAG) || 2195a7763bfSjmcp fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) { 2205a7763bfSjmcp rv = fwflash_list_fw(devclass); 2215a7763bfSjmcp fwflash_intr(0); 2225a7763bfSjmcp return (rv); 2235a7763bfSjmcp } 2245a7763bfSjmcp 2255a7763bfSjmcp fwflash_handle_signals(); 2265a7763bfSjmcp 2275a7763bfSjmcp /* Do flash update (write) */ 2285a7763bfSjmcp if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) || 2295a7763bfSjmcp (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG | 2305a7763bfSjmcp FWFLASH_YES_FLAG))) { 2314196e263SSherry Moore int fastreboot_disabled = 0; 2325a7763bfSjmcp /* the update function handles the real arg parsing */ 2335a7763bfSjmcp i = 0; 2345a7763bfSjmcp while (filelist[i] != NULL) { 2355a7763bfSjmcp if ((rv = fwflash_update(devpath, filelist[i], 2365a7763bfSjmcp fwflash_arg_list)) == FWFLASH_SUCCESS) { 2375a7763bfSjmcp /* failed ops have already been noted */ 2384196e263SSherry Moore if (!fastreboot_disabled && 2394196e263SSherry Moore scf_fastreboot_default_set_transient( 2404196e263SSherry Moore B_FALSE) != SCF_SUCCESS) 2414196e263SSherry Moore logmsg(MSG_ERROR, gettext( 2424196e263SSherry Moore "Failed to disable fast " 2434196e263SSherry Moore "reboot.\n")); 2444196e263SSherry Moore else 2454196e263SSherry Moore fastreboot_disabled = 1; 2465a7763bfSjmcp logmsg(MSG_ERROR, 2475a7763bfSjmcp gettext("New firmware will be activated " 2485a7763bfSjmcp "after you reboot\n\n")); 2495a7763bfSjmcp } 2505a7763bfSjmcp ++i; 2515a7763bfSjmcp } 2525a7763bfSjmcp 2535a7763bfSjmcp fwflash_intr(0); 2545a7763bfSjmcp return (rv); 2555a7763bfSjmcp } 2565a7763bfSjmcp 2575a7763bfSjmcp /* Do flash read */ 2585a7763bfSjmcp if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) || 2595a7763bfSjmcp (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG | 2605a7763bfSjmcp FWFLASH_YES_FLAG))) { 2615a7763bfSjmcp rv = fwflash_read_file(devpath, read_file); 2625a7763bfSjmcp fwflash_intr(0); 2635a7763bfSjmcp return (rv); 2645a7763bfSjmcp } 2655a7763bfSjmcp 2665a7763bfSjmcp fwflash_usage(NULL); 2675a7763bfSjmcp 2685a7763bfSjmcp return (FWFLASH_FAILURE); 2695a7763bfSjmcp } 2705a7763bfSjmcp 2715a7763bfSjmcp 2725a7763bfSjmcp static int 273f8bf33c3SShantkumar Hiremath flash_load_plugins() 274f8bf33c3SShantkumar Hiremath { 2755a7763bfSjmcp 2765a7763bfSjmcp int rval = FWFLASH_SUCCESS; 2775a7763bfSjmcp DIR *dirp; 2785a7763bfSjmcp struct dirent *plugdir; 2795a7763bfSjmcp char *plugname; 2805a7763bfSjmcp struct fw_plugin *tmpplug; 2815a7763bfSjmcp struct pluginlist *tmpelem; 2825a7763bfSjmcp void *sym; 2835a7763bfSjmcp char *fwplugdirpath, *tempdirpath; 2845a7763bfSjmcp 2855a7763bfSjmcp 2865a7763bfSjmcp #define CLOSEFREE() { \ 2875a7763bfSjmcp (void) dlclose(tmpplug->handle); \ 2885a7763bfSjmcp free(tmpplug); } 2895a7763bfSjmcp 2905a7763bfSjmcp /* 2915a7763bfSjmcp * Procedure: 2925a7763bfSjmcp * 2935a7763bfSjmcp * cd /usr/lib/fwflash/identify 2945a7763bfSjmcp * open each .so file found therein 2955a7763bfSjmcp * dlopen(.sofile) 2965a7763bfSjmcp * if it's one of our plugins, add it to fw_pluginlist; 2975a7763bfSjmcp * 2985a7763bfSjmcp * functions we need here include dlopen and dlsym. 2995a7763bfSjmcp * 3005a7763bfSjmcp * If we get to the end and fw_pluginlist struct is empty, 3015a7763bfSjmcp * return FWFLASH_FAILURE so we return to the shell. 3025a7763bfSjmcp */ 3035a7763bfSjmcp 3045a7763bfSjmcp if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 3055a7763bfSjmcp logmsg(MSG_ERROR, 3065a7763bfSjmcp gettext("Unable to malloc %d bytes while " 3075a7763bfSjmcp "trying to load plugins: %s\n"), 3085a7763bfSjmcp MAXPATHLEN + 1, strerror(errno)); 3095a7763bfSjmcp return (FWFLASH_FAILURE); 3105a7763bfSjmcp } 3115a7763bfSjmcp 3125a7763bfSjmcp tempdirpath = getenv("FWPLUGINDIR"); 3135a7763bfSjmcp 3145a7763bfSjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 3155a7763bfSjmcp (void) strlcpy(fwplugdirpath, tempdirpath, 3165a7763bfSjmcp strlen(tempdirpath) + 1); 3175a7763bfSjmcp } else { 3185a7763bfSjmcp (void) strlcpy(fwplugdirpath, FWPLUGINDIR, 3195a7763bfSjmcp strlen(FWPLUGINDIR) + 1); 3205a7763bfSjmcp } 3215a7763bfSjmcp 3225a7763bfSjmcp if ((dirp = opendir(fwplugdirpath)) == NULL) { 3235a7763bfSjmcp logmsg(MSG_ERROR, 324c4800545Sjmcp gettext("Unable to open %s\n"), 3255a7763bfSjmcp fwplugdirpath); 3265a7763bfSjmcp return (errno); 3275a7763bfSjmcp } 3285a7763bfSjmcp 3295a7763bfSjmcp if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1)) 3305a7763bfSjmcp == NULL) { 3315a7763bfSjmcp logmsg(MSG_ERROR, 3325a7763bfSjmcp gettext("Unable to malloc %d bytes while " 3335a7763bfSjmcp "trying to load plugins: %s\n"), 3345a7763bfSjmcp MAXPATHLEN + 1 + sizeof (struct dirent), 3355a7763bfSjmcp strerror(errno)); 3365a7763bfSjmcp return (FWFLASH_FAILURE); 3375a7763bfSjmcp } 3385a7763bfSjmcp 3395a7763bfSjmcp if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin))) 3405a7763bfSjmcp == NULL) { 3415a7763bfSjmcp logmsg(MSG_ERROR, 3425a7763bfSjmcp gettext("Unable to malloc %d bytes while " 3435a7763bfSjmcp "trying to load plugins: %s\n"), 344d65b419eSXinChen sizeof (struct fw_plugin), strerror(errno)); 3455a7763bfSjmcp return (FWFLASH_FAILURE); 3465a7763bfSjmcp } 3475a7763bfSjmcp 3485a7763bfSjmcp TAILQ_INIT(fw_pluginlist); 3495a7763bfSjmcp 3505a7763bfSjmcp while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) { 3515a7763bfSjmcp 3525a7763bfSjmcp errno = 0; /* remove chance of false results */ 3535a7763bfSjmcp 3545a7763bfSjmcp if ((plugdir->d_name[0] == '.') || 3555a7763bfSjmcp (strstr(plugdir->d_name, ".so") == NULL)) { 3565a7763bfSjmcp continue; 3575a7763bfSjmcp } 3585a7763bfSjmcp 3595a7763bfSjmcp if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) { 3605a7763bfSjmcp logmsg(MSG_ERROR, 3615a7763bfSjmcp gettext("Unable to malloc %d bytes while " 3625a7763bfSjmcp "trying to load plugins: %s\n"), 3635a7763bfSjmcp MAXPATHLEN + 1, strerror(errno)); 3645a7763bfSjmcp return (FWFLASH_FAILURE); 3655a7763bfSjmcp } 3665a7763bfSjmcp 3675a7763bfSjmcp (void) snprintf(plugname, MAXPATHLEN, "%s/%s", 3685a7763bfSjmcp fwplugdirpath, plugdir->d_name); 3695a7763bfSjmcp 3705a7763bfSjmcp /* start allocating storage */ 3715a7763bfSjmcp if ((tmpelem = calloc(1, sizeof (struct pluginlist))) 3725a7763bfSjmcp == NULL) { 3735a7763bfSjmcp logmsg(MSG_ERROR, 3745a7763bfSjmcp gettext("Unable to malloc %d bytes while " 3755a7763bfSjmcp "trying to load plugins: %s\n"), 3765a7763bfSjmcp sizeof (struct pluginlist), strerror(errno)); 3775a7763bfSjmcp return (FWFLASH_FAILURE); 3785a7763bfSjmcp } 3795a7763bfSjmcp 3805a7763bfSjmcp if ((tmpplug = calloc(1, sizeof (struct fw_plugin))) 3815a7763bfSjmcp == NULL) { 3825a7763bfSjmcp logmsg(MSG_ERROR, 3835a7763bfSjmcp gettext("Unable to malloc %d bytes while " 3845a7763bfSjmcp "trying to load plugins: %s\n"), 3855a7763bfSjmcp sizeof (struct fw_plugin), strerror(errno)); 3865a7763bfSjmcp return (FWFLASH_FAILURE); 3875a7763bfSjmcp } 3885a7763bfSjmcp 3895a7763bfSjmcp /* load 'er up! */ 3905a7763bfSjmcp tmpplug->handle = dlopen(plugname, RTLD_NOW); 3915a7763bfSjmcp if (tmpplug->handle == NULL) { 3925a7763bfSjmcp free(tmpplug); 3935a7763bfSjmcp continue; /* assume there are other plugins */ 3945a7763bfSjmcp } 3955a7763bfSjmcp 3965a7763bfSjmcp if ((tmpplug->filename = calloc(1, strlen(plugname) + 1)) 3975a7763bfSjmcp == NULL) { 3985a7763bfSjmcp logmsg(MSG_ERROR, 3995a7763bfSjmcp gettext("Unable to allocate %d bytes for plugin " 4005a7763bfSjmcp "filename %s:%s\n"), 4015a7763bfSjmcp strlen(plugname) + 1, plugname, 4025a7763bfSjmcp strerror(errno)); 4035a7763bfSjmcp return (rval); 4045a7763bfSjmcp } 4055a7763bfSjmcp 4065a7763bfSjmcp (void) strlcpy(tmpplug->filename, plugname, 4075a7763bfSjmcp strlen(plugname) + 1); 4085a7763bfSjmcp 4095a7763bfSjmcp /* now sanity check the file */ 4105a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "drivername")) 4115a7763bfSjmcp != NULL) { 4125a7763bfSjmcp /* max length of drivername */ 413c4800545Sjmcp tmpplug->drvname = calloc(1, MAXMODCONFNAME); 414c4800545Sjmcp 415c4800545Sjmcp /* are we doing double-time? */ 416c4800545Sjmcp if (strncmp((char *)sym, plugdir->d_name, 417c4800545Sjmcp MAXMODCONFNAME) != 0) { 418c4800545Sjmcp char *tempnm = calloc(1, MAXMODCONFNAME); 419c4800545Sjmcp 420d65b419eSXinChen (void) memcpy(tempnm, plugdir->d_name, 421d65b419eSXinChen MAXMODCONFNAME); 422c4800545Sjmcp (void) strlcpy(tmpplug->drvname, 423c4800545Sjmcp strtok(tempnm, "."), 424c4800545Sjmcp strlen(plugdir->d_name) + 1); 425c4800545Sjmcp free(tempnm); 426c4800545Sjmcp } else { 427c4800545Sjmcp (void) strlcpy(tmpplug->drvname, 428c4800545Sjmcp (char *)sym, strlen(sym) + 1); 429c4800545Sjmcp } 4305a7763bfSjmcp } else { 4315a7763bfSjmcp CLOSEFREE(); 4325a7763bfSjmcp continue; 4335a7763bfSjmcp } 4345a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "fw_readfw")) 4355a7763bfSjmcp != NULL) { 4365a7763bfSjmcp tmpplug->fw_readfw = (int (*)())sym; 4375a7763bfSjmcp } else { 4385a7763bfSjmcp CLOSEFREE(); 4395a7763bfSjmcp continue; 4405a7763bfSjmcp } 4415a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "fw_writefw")) 4425a7763bfSjmcp != NULL) { 4435a7763bfSjmcp tmpplug->fw_writefw = (int (*)())sym; 4445a7763bfSjmcp } else { 4455a7763bfSjmcp CLOSEFREE(); 4465a7763bfSjmcp continue; 4475a7763bfSjmcp } 4485a7763bfSjmcp 4495a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "fw_identify")) 4505a7763bfSjmcp != NULL) { 4515a7763bfSjmcp tmpplug->fw_identify = 4525a7763bfSjmcp (int (*)(int))sym; 4535a7763bfSjmcp } else { 4545a7763bfSjmcp CLOSEFREE(); 4555a7763bfSjmcp continue; 4565a7763bfSjmcp } 4575a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "fw_devinfo")) 4585a7763bfSjmcp != NULL) { 4595a7763bfSjmcp tmpplug->fw_devinfo = 4605a7763bfSjmcp (int (*)(struct devicelist *))sym; 4615a7763bfSjmcp } else { 4625a7763bfSjmcp CLOSEFREE(); 4635a7763bfSjmcp continue; 4645a7763bfSjmcp } 4655a7763bfSjmcp 466d65b419eSXinChen if ((sym = dlsym(tmpplug->handle, "plugin_version")) 467d65b419eSXinChen != NULL) { 468d65b419eSXinChen if ((*(int *)sym) >= FWPLUGIN_VERSION_2) { 469d65b419eSXinChen if ((sym = dlsym(tmpplug->handle, 470d65b419eSXinChen "fw_cleanup")) != NULL) { 471d65b419eSXinChen tmpplug->fw_cleanup = 472d65b419eSXinChen (void (*)(struct devicelist *))sym; 473d65b419eSXinChen } else { 474d65b419eSXinChen logmsg(MSG_ERROR, 475d65b419eSXinChen gettext("ERROR: v2 plugin (%s) " 476d65b419eSXinChen "has no fw_cleanup function\n"), 477d65b419eSXinChen tmpplug->filename); 478d65b419eSXinChen CLOSEFREE(); 479d65b419eSXinChen continue; 480d65b419eSXinChen } 481d65b419eSXinChen } else { 482d65b419eSXinChen logmsg(MSG_INFO, 483d65b419eSXinChen "Identification plugin %s defined " 484d65b419eSXinChen "plugin_version < FWPLUGIN_VERSION_2 !"); 485d65b419eSXinChen } 486d65b419eSXinChen } 487d65b419eSXinChen 488c4800545Sjmcp if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME)) 4895a7763bfSjmcp == NULL) { 4905a7763bfSjmcp logmsg(MSG_ERROR, 491c4800545Sjmcp gettext("Unable to allocate space for a" 4925a7763bfSjmcp "drivername %s\n"), 4935a7763bfSjmcp tmpplug->drvname); 4945a7763bfSjmcp return (FWFLASH_FAILURE); 4955a7763bfSjmcp } 4965a7763bfSjmcp 4975a7763bfSjmcp (void) strlcpy(tmpelem->drvname, tmpplug->drvname, 4985a7763bfSjmcp strlen(tmpplug->drvname) + 1); 4995a7763bfSjmcp 5005a7763bfSjmcp if ((tmpelem->filename = calloc(1, 5015a7763bfSjmcp strlen(tmpplug->filename) + 1)) == NULL) { 5025a7763bfSjmcp logmsg(MSG_ERROR, 5035a7763bfSjmcp gettext("Unable to allocate %d bytes for " 5045a7763bfSjmcp "filename %s\n"), 5055a7763bfSjmcp strlen(tmpplug->filename) + 1, 506c4800545Sjmcp tmpplug->filename); 5075a7763bfSjmcp return (FWFLASH_FAILURE); 5085a7763bfSjmcp } 5095a7763bfSjmcp 5105a7763bfSjmcp (void) strlcpy(tmpelem->filename, plugname, 5115a7763bfSjmcp strlen(plugname) + 1); 5125a7763bfSjmcp tmpelem->plugin = tmpplug; 5135a7763bfSjmcp 5145a7763bfSjmcp /* CONSTCOND */ 5155a7763bfSjmcp TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin); 5165a7763bfSjmcp } 5175a7763bfSjmcp 5185a7763bfSjmcp if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) { 5195a7763bfSjmcp return (FWFLASH_FAILURE); 5205a7763bfSjmcp } 5215a7763bfSjmcp 5225a7763bfSjmcp if (errno != 0) { 5235a7763bfSjmcp logmsg(MSG_ERROR, 5245a7763bfSjmcp gettext("Error reading directory entry in %s\n"), 5255a7763bfSjmcp fwplugdirpath); 5265a7763bfSjmcp rval = errno; 5275a7763bfSjmcp } 5285a7763bfSjmcp 529d65b419eSXinChen free(fwplugdirpath); 530d65b419eSXinChen free(plugdir); 5315a7763bfSjmcp (void) closedir(dirp); 5325a7763bfSjmcp return (rval); 5335a7763bfSjmcp } 5345a7763bfSjmcp 5355a7763bfSjmcp /* 5365a7763bfSjmcp * fwflash_load_verifier dlload()s the appropriate firmware image 5375a7763bfSjmcp * verification plugin, and attaches the designated fwimg's fd to 5385a7763bfSjmcp * the vrfyplugin structure so we only have to load the image in 5395a7763bfSjmcp * one place. 5405a7763bfSjmcp */ 5415a7763bfSjmcp int 542f8bf33c3SShantkumar Hiremath fwflash_load_verifier(char *drv, char *vendorid, char *fwimg) 543f8bf33c3SShantkumar Hiremath { 5445a7763bfSjmcp 5455a7763bfSjmcp int rv = FWFLASH_FAILURE; 5465a7763bfSjmcp int imgfd; 5475a7763bfSjmcp char *fwvrfydirpath, *tempdirpath, *filename; 5485a7763bfSjmcp char *clean; /* for the space-removed vid */ 5495a7763bfSjmcp struct stat fwstat; 5505a7763bfSjmcp struct vrfyplugin *vrfy; 5515a7763bfSjmcp void *vrfysym; 5525a7763bfSjmcp 5535a7763bfSjmcp /* 5545a7763bfSjmcp * To make flashing multiple firmware images somewhat more 5555a7763bfSjmcp * efficient, we start this function by checking whether a 5565a7763bfSjmcp * verifier for this device has already been loaded. If it 5575a7763bfSjmcp * has been loaded, we replace the imgfile information, and 5585a7763bfSjmcp * then continue as if we were loading for the first time. 5595a7763bfSjmcp */ 5605a7763bfSjmcp 5615a7763bfSjmcp if (verifier != NULL) { 5625a7763bfSjmcp verifier->imgsize = 0; 5635a7763bfSjmcp verifier->flashbuf = 0; /* set by the verifier function */ 5645a7763bfSjmcp 565d65b419eSXinChen if (verifier->imgfile != NULL) { 566d65b419eSXinChen free(verifier->imgfile); 567d65b419eSXinChen verifier->imgfile = NULL; 568d65b419eSXinChen } 5695a7763bfSjmcp 570d65b419eSXinChen if (verifier->fwimage != NULL) { 571d65b419eSXinChen free(verifier->fwimage); 572d65b419eSXinChen verifier->fwimage = NULL; 573d65b419eSXinChen } 5745a7763bfSjmcp } else { 5755a7763bfSjmcp if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 5765a7763bfSjmcp logmsg(MSG_ERROR, 5775a7763bfSjmcp gettext("Unable to allocate space for a firmware " 5785a7763bfSjmcp "verifier file(1)")); 5795a7763bfSjmcp return (rv); 5805a7763bfSjmcp } 5815a7763bfSjmcp 5825a7763bfSjmcp if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) { 5835a7763bfSjmcp logmsg(MSG_ERROR, 5845a7763bfSjmcp gettext("Unable to allocate space " 5855a7763bfSjmcp "for a firmware verifier file(2)")); 586d65b419eSXinChen free(fwvrfydirpath); 5875a7763bfSjmcp return (rv); 5885a7763bfSjmcp } 5895a7763bfSjmcp 5905a7763bfSjmcp /* 591d65b419eSXinChen * Since SCSI devices can have a vendor id of up to 8 592d65b419eSXinChen * left-aligned and _space-padded_ characters, we first need to 593d65b419eSXinChen * strip off any space characters before we try to make a 594d65b419eSXinChen * filename out of it 5955a7763bfSjmcp */ 5965a7763bfSjmcp clean = strtok(vendorid, " "); 5975a7763bfSjmcp if (clean == NULL) { 5985a7763bfSjmcp /* invalid vendorid, something's really wrong */ 5995a7763bfSjmcp logmsg(MSG_ERROR, 6005a7763bfSjmcp gettext("Invalid vendorid (null) specified for " 6015a7763bfSjmcp "device\n")); 602d65b419eSXinChen free(filename); 603d65b419eSXinChen free(fwvrfydirpath); 6045a7763bfSjmcp return (rv); 6055a7763bfSjmcp } 6065a7763bfSjmcp 6075a7763bfSjmcp tempdirpath = getenv("FWVERIFYPLUGINDIR"); 6085a7763bfSjmcp 6095a7763bfSjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 6105a7763bfSjmcp (void) strlcpy(fwvrfydirpath, tempdirpath, 6115a7763bfSjmcp strlen(tempdirpath) + 1); 6125a7763bfSjmcp } else { 6135a7763bfSjmcp (void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR, 6145a7763bfSjmcp strlen(FWVERIFYPLUGINDIR) + 1); 6155a7763bfSjmcp } 6165a7763bfSjmcp 6175a7763bfSjmcp if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) { 6185a7763bfSjmcp logmsg(MSG_ERROR, 6195a7763bfSjmcp gettext("Unable to allocate space " 6205a7763bfSjmcp "for a firmware verifier structure")); 6215a7763bfSjmcp free(filename); 6225a7763bfSjmcp free(fwvrfydirpath); 623d65b419eSXinChen return (rv); 6245a7763bfSjmcp } 6255a7763bfSjmcp 6265a7763bfSjmcp errno = 0; /* false positive removal */ 6275a7763bfSjmcp 628d65b419eSXinChen (void) snprintf(filename, MAXPATHLEN, "%s/%s-%s.so", 6295a7763bfSjmcp fwvrfydirpath, drv, clean); 630d65b419eSXinChen if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) { 631d65b419eSXinChen logmsg(MSG_INFO, gettext(dlerror())); 632d65b419eSXinChen logmsg(MSG_INFO, 633d65b419eSXinChen gettext("\nUnable to open verification plugin " 634d65b419eSXinChen "%s. Looking for %s-GENERIC plugin instead.\n"), 635d65b419eSXinChen filename, drv); 636d65b419eSXinChen 637d65b419eSXinChen /* Try the drv-GENERIC.so form, _then_ die */ 638d65b419eSXinChen bzero(filename, strlen(filename) + 1); 639d65b419eSXinChen (void) snprintf(filename, MAXPATHLEN, 640d65b419eSXinChen "%s/%s-GENERIC.so", fwvrfydirpath, drv); 641d65b419eSXinChen 642d65b419eSXinChen if ((vrfy->handle = dlopen(filename, RTLD_NOW)) 643d65b419eSXinChen == NULL) { 644d65b419eSXinChen logmsg(MSG_INFO, gettext(dlerror())); 645d65b419eSXinChen logmsg(MSG_ERROR, 646d65b419eSXinChen gettext("\nUnable to open either " 647d65b419eSXinChen "verification plugin %s/%s-%s.so or " 648d65b419eSXinChen "generic plugin %s.\nUnable to verify " 649d65b419eSXinChen "firmware image. Aborting.\n"), 650d65b419eSXinChen fwvrfydirpath, drv, clean, filename); 651d65b419eSXinChen free(filename); 652d65b419eSXinChen free(fwvrfydirpath); 653d65b419eSXinChen return (rv); 654d65b419eSXinChen } 655d65b419eSXinChen } 6565a7763bfSjmcp 6575a7763bfSjmcp if ((vrfy->filename = calloc(1, strlen(filename) + 1)) 6585a7763bfSjmcp == NULL) { 6595a7763bfSjmcp logmsg(MSG_ERROR, 6605a7763bfSjmcp gettext("Unable to allocate space to store " 6615a7763bfSjmcp "a verifier filename\n")); 6625a7763bfSjmcp free(filename); 6635a7763bfSjmcp free(fwvrfydirpath); 6645a7763bfSjmcp free(vrfy->handle); 665d65b419eSXinChen return (rv); 6665a7763bfSjmcp } 6675a7763bfSjmcp (void) strlcpy(vrfy->filename, filename, strlen(filename) + 1); 6685a7763bfSjmcp 6695a7763bfSjmcp if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) { 6705a7763bfSjmcp logmsg(MSG_ERROR, 6715a7763bfSjmcp gettext("%s is an invalid firmware verification " 6725a7763bfSjmcp "plugin."), filename); 6735a7763bfSjmcp (void) dlclose(vrfy->handle); 6745a7763bfSjmcp free(filename); 6755a7763bfSjmcp free(fwvrfydirpath); 6765a7763bfSjmcp free(vrfy); 677d65b419eSXinChen return (rv); 6785a7763bfSjmcp } else { 6795a7763bfSjmcp vrfy->vendorvrfy = 6805a7763bfSjmcp (int (*)(struct devicelist *))vrfysym; 6815a7763bfSjmcp } 6825a7763bfSjmcp 6835a7763bfSjmcp vrfysym = dlsym(vrfy->handle, "vendor"); 6845a7763bfSjmcp 6855a7763bfSjmcp if (vrfysym == NULL) { 6865a7763bfSjmcp logmsg(MSG_ERROR, 6875a7763bfSjmcp gettext("Invalid vendor (null) in verification " 6885a7763bfSjmcp "plugin %s\n"), filename); 6895a7763bfSjmcp (void) dlclose(vrfy->handle); 6905a7763bfSjmcp free(vrfy); 691d65b419eSXinChen return (rv); 6925a7763bfSjmcp } else { 6935a7763bfSjmcp if (strncmp(vendorid, (char *)vrfysym, 6945a7763bfSjmcp strlen(vendorid)) != 0) { 6955a7763bfSjmcp logmsg(MSG_INFO, 6965a7763bfSjmcp "Using a sym-linked (%s -> %s) " 697d65b419eSXinChen "verification plugin\n", 6985a7763bfSjmcp vendorid, vrfysym); 6995a7763bfSjmcp vrfy->vendor = calloc(1, strlen(vendorid) + 1); 7005a7763bfSjmcp } else { 7015a7763bfSjmcp vrfy->vendor = calloc(1, strlen(vrfysym) + 1); 7025a7763bfSjmcp } 7035a7763bfSjmcp (void) strlcpy(vrfy->vendor, (char *)vrfysym, 7045a7763bfSjmcp strlen(vendorid) + 1); 7055a7763bfSjmcp } 7065a7763bfSjmcp 7075a7763bfSjmcp verifier = vrfy; /* a convenience variable */ 708d65b419eSXinChen free(filename); 709d65b419eSXinChen free(fwvrfydirpath); 7105a7763bfSjmcp } 7115a7763bfSjmcp 7125a7763bfSjmcp /* 7135a7763bfSjmcp * We don't do any verification that the fw image file is in 7145a7763bfSjmcp * an approved location, but it's easy enough to modify this 7155a7763bfSjmcp * function to do so. The verification plugin should provide 7165a7763bfSjmcp * sufficient protection. 7175a7763bfSjmcp */ 7185a7763bfSjmcp 7195a7763bfSjmcp if ((imgfd = open(fwimg, O_RDONLY)) < 0) { 7205a7763bfSjmcp logmsg(MSG_ERROR, 7215a7763bfSjmcp gettext("Unable to open designated firmware " 7225a7763bfSjmcp "image file %s: %s\n"), 7235a7763bfSjmcp (fwimg != NULL) ? fwimg : "(null)", 7245a7763bfSjmcp strerror(errno)); 7255a7763bfSjmcp rv = FWFLASH_FAILURE; 7265a7763bfSjmcp goto cleanup; 7275a7763bfSjmcp } 7285a7763bfSjmcp 7295a7763bfSjmcp if (stat(fwimg, &fwstat) == -1) { 7305a7763bfSjmcp logmsg(MSG_ERROR, 7315a7763bfSjmcp gettext("Unable to stat() firmware image file " 7325a7763bfSjmcp "%s: %s\n"), 7335a7763bfSjmcp fwimg, strerror(errno)); 7345a7763bfSjmcp rv = FWFLASH_FAILURE; 7355a7763bfSjmcp goto cleanup; 7365a7763bfSjmcp } else { 7375a7763bfSjmcp verifier->imgsize = fwstat.st_size; 7385a7763bfSjmcp if ((verifier->fwimage = calloc(1, verifier->imgsize)) 7395a7763bfSjmcp == NULL) { 7405a7763bfSjmcp logmsg(MSG_ERROR, 7415a7763bfSjmcp gettext("Unable to load firmware image " 7425a7763bfSjmcp "%s: %s\n"), 7435a7763bfSjmcp fwimg, strerror(errno)); 7445a7763bfSjmcp rv = FWFLASH_FAILURE; 7455a7763bfSjmcp goto cleanup; 7465a7763bfSjmcp } 7475a7763bfSjmcp } 7485a7763bfSjmcp 7495a7763bfSjmcp errno = 0; 7505a7763bfSjmcp if ((rv = read(imgfd, verifier->fwimage, 7515a7763bfSjmcp (size_t)verifier->imgsize)) < verifier->imgsize) { 7525a7763bfSjmcp /* we haven't read enough data, bail */ 7535a7763bfSjmcp logmsg(MSG_ERROR, 7545a7763bfSjmcp gettext("Failed to read sufficient data " 7555a7763bfSjmcp "(got %d bytes, expected %d bytes) from " 7565a7763bfSjmcp "firmware image file %s: %s\n"), 7575a7763bfSjmcp rv, verifier->imgsize, 758d65b419eSXinChen verifier->filename, strerror(errno)); 7595a7763bfSjmcp rv = FWFLASH_FAILURE; 7605a7763bfSjmcp } else { 7615a7763bfSjmcp rv = FWFLASH_SUCCESS; 7625a7763bfSjmcp } 7635a7763bfSjmcp 7645a7763bfSjmcp if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) { 7655a7763bfSjmcp logmsg(MSG_ERROR, 7665a7763bfSjmcp gettext("Unable to save name of firmware image\n")); 7675a7763bfSjmcp rv = FWFLASH_FAILURE; 7685a7763bfSjmcp } else { 7695a7763bfSjmcp (void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1); 7705a7763bfSjmcp } 7715a7763bfSjmcp 7725a7763bfSjmcp if (rv != FWFLASH_SUCCESS) { 7735a7763bfSjmcp /* cleanup and let's get outta here */ 7745a7763bfSjmcp cleanup: 7755a7763bfSjmcp free(verifier->filename); 7765a7763bfSjmcp free(verifier->vendor); 7775a7763bfSjmcp 778d65b419eSXinChen if (!(fwflash_arg_list & FWFLASH_READ_FLAG) && 779d65b419eSXinChen verifier->fwimage) 7805a7763bfSjmcp free(verifier->fwimage); 7815a7763bfSjmcp 7825a7763bfSjmcp verifier->filename = NULL; 7835a7763bfSjmcp verifier->vendor = NULL; 7845a7763bfSjmcp verifier->vendorvrfy = NULL; 7855a7763bfSjmcp verifier->fwimage = NULL; 7865a7763bfSjmcp (void) dlclose(verifier->handle); 7875a7763bfSjmcp verifier->handle = NULL; 7885a7763bfSjmcp free(verifier); 7895a7763bfSjmcp if (imgfd >= 0) { 7905a7763bfSjmcp (void) close(imgfd); 7915a7763bfSjmcp } 7925a7763bfSjmcp verifier = NULL; 7935a7763bfSjmcp } 7945a7763bfSjmcp 7955a7763bfSjmcp return (rv); 7965a7763bfSjmcp } 7975a7763bfSjmcp 7985a7763bfSjmcp /* 7995a7763bfSjmcp * cycles through the global list of plugins to find 8005a7763bfSjmcp * each flashable device, which is added to fw_devices 8015a7763bfSjmcp * 8025a7763bfSjmcp * Each plugin's identify routine must allocated storage 8035a7763bfSjmcp * as required. 8045a7763bfSjmcp * 8055a7763bfSjmcp * Each plugin's identify routine must return 8065a7763bfSjmcp * FWFLASH_FAILURE if it cannot find any devices 8075a7763bfSjmcp * which it handles. 8085a7763bfSjmcp */ 8095a7763bfSjmcp static int 8105a7763bfSjmcp flash_device_list() 8115a7763bfSjmcp { 8125a7763bfSjmcp int rv = FWFLASH_FAILURE; 8135a7763bfSjmcp int startidx = 0; 8145a7763bfSjmcp int sumrv = 0; 8155a7763bfSjmcp struct pluginlist *plugins; 8165a7763bfSjmcp 8175a7763bfSjmcp /* we open rootnode here, and close it in fwflash_intr */ 818d65b419eSXinChen if ((rootnode = di_init("/", DINFOCPYALL|DINFOFORCE)) == DI_NODE_NIL) { 8195a7763bfSjmcp logmsg(MSG_ERROR, 8205a7763bfSjmcp gettext("Unable to take device tree snapshot: %s\n"), 8215a7763bfSjmcp strerror(errno)); 8225a7763bfSjmcp return (rv); 8235a7763bfSjmcp } 8245a7763bfSjmcp 8255a7763bfSjmcp if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) { 8265a7763bfSjmcp logmsg(MSG_ERROR, 8275a7763bfSjmcp gettext("Unable to malloc %d bytes while " 8285a7763bfSjmcp "trying to find devices: %s\n"), 8295a7763bfSjmcp sizeof (struct devicelist), strerror(errno)); 8305a7763bfSjmcp return (FWFLASH_FAILURE); 8315a7763bfSjmcp } 8325a7763bfSjmcp 8335a7763bfSjmcp /* CONSTCOND */ 8345a7763bfSjmcp TAILQ_INIT(fw_devices); 8355a7763bfSjmcp 8365a7763bfSjmcp TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) { 8375a7763bfSjmcp self = plugins->plugin; 8385a7763bfSjmcp rv = plugins->plugin->fw_identify(startidx); 8395a7763bfSjmcp 8405a7763bfSjmcp logmsg(MSG_INFO, 8415a7763bfSjmcp gettext("fwflash:flash_device_list() got %d from " 8425a7763bfSjmcp "identify routine\n"), rv); 8435a7763bfSjmcp 8445a7763bfSjmcp /* only bump startidx if we've found at least one device */ 8455a7763bfSjmcp if (rv == FWFLASH_SUCCESS) { 8465a7763bfSjmcp startidx += 100; 8475a7763bfSjmcp sumrv++; 8485a7763bfSjmcp } else { 8495a7763bfSjmcp logmsg(MSG_INFO, 8505a7763bfSjmcp gettext("No flashable devices attached with " 8515a7763bfSjmcp "the %s driver in this system\n"), 8525a7763bfSjmcp plugins->drvname); 8535a7763bfSjmcp } 8545a7763bfSjmcp } 8555a7763bfSjmcp 8565a7763bfSjmcp if (sumrv > 0) 8575a7763bfSjmcp rv = FWFLASH_SUCCESS; 8585a7763bfSjmcp 8595a7763bfSjmcp return (rv); 8605a7763bfSjmcp } 8615a7763bfSjmcp 8625a7763bfSjmcp static int 8635a7763bfSjmcp fwflash_list_fw(char *class) 8645a7763bfSjmcp { 8655a7763bfSjmcp int rv = 0; 8665a7763bfSjmcp struct devicelist *curdev; 8675a7763bfSjmcp int header = 1; 8685a7763bfSjmcp 8695a7763bfSjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 8705a7763bfSjmcp 8715a7763bfSjmcp /* we're either class-conscious, or we're not */ 8725a7763bfSjmcp if (((class != NULL) && 8735a7763bfSjmcp ((strncmp(curdev->classname, "ALL", 3) == 0) || 8745a7763bfSjmcp (strcmp(curdev->classname, class) == 0))) || 8755a7763bfSjmcp (class == NULL)) { 8765a7763bfSjmcp 8775a7763bfSjmcp if (header != 0) { 8785a7763bfSjmcp (void) fprintf(stdout, 8795a7763bfSjmcp gettext("List of available devices:\n")); 8805a7763bfSjmcp header--; 8815a7763bfSjmcp } 8825a7763bfSjmcp /* 8835a7763bfSjmcp * If any plugin's fw_devinfo() function returns 8845a7763bfSjmcp * FWFLASH_FAILURE then we want to keep track of 8855a7763bfSjmcp * it. _Most_ plugins should always return 8865a7763bfSjmcp * FWFLASH_SUCCESS from this function. The only 8875a7763bfSjmcp * exception known at this point is the tavor plugin. 8885a7763bfSjmcp */ 8895a7763bfSjmcp rv += curdev->plugin->fw_devinfo(curdev); 8905a7763bfSjmcp } 8915a7763bfSjmcp } 8925a7763bfSjmcp return (rv); 8935a7763bfSjmcp } 8945a7763bfSjmcp 8955a7763bfSjmcp static int 896f1c23465SJames C. McPherson fwflash_update(char *device, char *filename, int flags) 897f1c23465SJames C. McPherson { 8985a7763bfSjmcp 8995a7763bfSjmcp int rv = FWFLASH_FAILURE; 9005a7763bfSjmcp int needsfree = 0; 901c4800545Sjmcp int found = 0; 9025a7763bfSjmcp struct devicelist *curdev; 9035a7763bfSjmcp char *realfile; 9045a7763bfSjmcp 9055a7763bfSjmcp /* 9065a7763bfSjmcp * Here's how we operate: 9075a7763bfSjmcp * 9085a7763bfSjmcp * We perform some basic checks on the args, then walk 9095a7763bfSjmcp * through the device list looking for the device which 9105a7763bfSjmcp * matches. We then load the appropriate verifier for the 9115a7763bfSjmcp * image file and device, verify the image, then call the 9125a7763bfSjmcp * fw_writefw() function of the appropriate plugin. 9135a7763bfSjmcp * 9145a7763bfSjmcp * There is no "force" flag to enable you to flash a firmware 9155a7763bfSjmcp * image onto an incompatible device because the verifier 9165a7763bfSjmcp * will return FWFLASH_FAILURE if the image doesn't match. 9175a7763bfSjmcp */ 9185a7763bfSjmcp 9195a7763bfSjmcp /* new firmware filename and device desc */ 9205a7763bfSjmcp if (filename == NULL) { 9215a7763bfSjmcp logmsg(MSG_ERROR, 9225a7763bfSjmcp gettext("Invalid firmware filename (null)\n")); 9235a7763bfSjmcp return (FWFLASH_FAILURE); 9245a7763bfSjmcp } 9255a7763bfSjmcp 9265a7763bfSjmcp if (device == NULL) { 9275a7763bfSjmcp logmsg(MSG_ERROR, 9285a7763bfSjmcp gettext("Invalid device requested (null)\n")); 9295a7763bfSjmcp return (FWFLASH_FAILURE); 9305a7763bfSjmcp } 9315a7763bfSjmcp 9325a7763bfSjmcp if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) { 9335a7763bfSjmcp logmsg(MSG_ERROR, 9345a7763bfSjmcp gettext("Unable to allocate space for device " 935c4800545Sjmcp "filename, operation might fail if %s is" 9365a7763bfSjmcp "a symbolic link\n"), 9375a7763bfSjmcp device); 9385a7763bfSjmcp realfile = device; 9395a7763bfSjmcp } else { 9405a7763bfSjmcp /* 9415a7763bfSjmcp * If realpath() succeeds, then we have a valid 9425a7763bfSjmcp * device filename in realfile. 9435a7763bfSjmcp */ 9445a7763bfSjmcp if (realpath(device, realfile) == NULL) { 9455a7763bfSjmcp logmsg(MSG_ERROR, 9465a7763bfSjmcp gettext("Unable to resolve device filename" 9475a7763bfSjmcp ": %s\n"), 9485a7763bfSjmcp strerror(errno)); 9495a7763bfSjmcp /* tidy up */ 9505a7763bfSjmcp free(realfile); 9515a7763bfSjmcp /* realpath didn't succeed, use fallback */ 9525a7763bfSjmcp realfile = device; 9535a7763bfSjmcp } else { 9545a7763bfSjmcp needsfree = 1; 9555a7763bfSjmcp } 9565a7763bfSjmcp } 9575a7763bfSjmcp 9585a7763bfSjmcp logmsg(MSG_INFO, 9595a7763bfSjmcp gettext("fwflash_update: fw_filename (%s) device (%s)\n"), 9605a7763bfSjmcp filename, device); 9615a7763bfSjmcp 9625a7763bfSjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 9635a7763bfSjmcp if (strcmp(curdev->access_devname, realfile) == 0) { 964c4800545Sjmcp found++; 9655a7763bfSjmcp rv = fwflash_load_verifier(curdev->drvname, 9665a7763bfSjmcp curdev->ident->vid, filename); 9675a7763bfSjmcp if (rv == FWFLASH_FAILURE) { 9685a7763bfSjmcp logmsg(MSG_ERROR, 9695a7763bfSjmcp gettext("Unable to load verifier " 9705a7763bfSjmcp "for device %s\n"), 9715a7763bfSjmcp curdev->access_devname); 9725a7763bfSjmcp return (FWFLASH_FAILURE); 9735a7763bfSjmcp } 9745a7763bfSjmcp rv = verifier->vendorvrfy(curdev); 9755a7763bfSjmcp if (rv == FWFLASH_FAILURE) { 9765a7763bfSjmcp /* the verifier prints a message */ 9775a7763bfSjmcp logmsg(MSG_INFO, 9785a7763bfSjmcp "verifier (%s) for %s :: %s returned " 9795a7763bfSjmcp "FWFLASH_FAILURE\n", 9805a7763bfSjmcp verifier->filename, 9815a7763bfSjmcp filename, curdev->access_devname); 9825a7763bfSjmcp return (rv); 9835a7763bfSjmcp } 9845a7763bfSjmcp 985f1c23465SJames C. McPherson if (((flags & FWFLASH_YES_FLAG) == FWFLASH_YES_FLAG) || 9865a7763bfSjmcp (rv = confirm_target(curdev, filename)) == 9875a7763bfSjmcp FWFLASH_YES_FLAG) { 9885a7763bfSjmcp logmsg(MSG_INFO, 9895a7763bfSjmcp "about to flash using plugin %s\n", 9905a7763bfSjmcp curdev->plugin->filename); 9915a7763bfSjmcp rv = curdev->plugin->fw_writefw(curdev, 9925a7763bfSjmcp filename); 9935a7763bfSjmcp if (rv == FWFLASH_FAILURE) { 9945a7763bfSjmcp logmsg(MSG_ERROR, 9955a7763bfSjmcp gettext("Failed to flash " 9965a7763bfSjmcp "firmware file %s on " 9975a7763bfSjmcp "device %s: %d\n"), 9985a7763bfSjmcp filename, 9995a7763bfSjmcp curdev->access_devname, rv); 10005a7763bfSjmcp } 10015a7763bfSjmcp } else { 10025a7763bfSjmcp logmsg(MSG_ERROR, 10035a7763bfSjmcp gettext("Flash operation not confirmed " 10045a7763bfSjmcp "by user\n"), 10055a7763bfSjmcp curdev->access_devname); 10065a7763bfSjmcp rv = FWFLASH_FAILURE; 10075a7763bfSjmcp } 10085a7763bfSjmcp } 10095a7763bfSjmcp } 10105a7763bfSjmcp 1011c4800545Sjmcp if (!found) 1012c4800545Sjmcp /* report the same device that the user passed in */ 1013c4800545Sjmcp logmsg(MSG_ERROR, 1014c4800545Sjmcp gettext("Device %s does not appear " 1015c4800545Sjmcp "to be flashable\n"), 1016c4800545Sjmcp ((strncmp(device, realfile, strlen(device)) == 0) ? 1017d65b419eSXinChen realfile : device)); 1018c4800545Sjmcp 10195a7763bfSjmcp if (needsfree) 10205a7763bfSjmcp free(realfile); 10215a7763bfSjmcp 10225a7763bfSjmcp return (rv); 10235a7763bfSjmcp } 10245a7763bfSjmcp 10255a7763bfSjmcp /* 10265a7763bfSjmcp * We validate that the device path is in our global device list and 10275a7763bfSjmcp * that the filename exists, then palm things off to the relevant plugin. 10285a7763bfSjmcp */ 10295a7763bfSjmcp static int 10305a7763bfSjmcp fwflash_read_file(char *device, char *filename) 10315a7763bfSjmcp { 10325a7763bfSjmcp struct devicelist *curdev; 10335a7763bfSjmcp int rv; 1034f8bf33c3SShantkumar Hiremath int found = 0; 10355a7763bfSjmcp 10365a7763bfSjmcp /* new firmware filename and device desc */ 10375a7763bfSjmcp 10385a7763bfSjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 10395a7763bfSjmcp if (strncmp(curdev->access_devname, device, 10405a7763bfSjmcp MAXPATHLEN) == 0) { 10415a7763bfSjmcp rv = curdev->plugin->fw_readfw(curdev, filename); 10425a7763bfSjmcp 10435a7763bfSjmcp if (rv != FWFLASH_SUCCESS) 10445a7763bfSjmcp logmsg(MSG_ERROR, 10455a7763bfSjmcp gettext("Unable to write out firmware " 10465a7763bfSjmcp "image for %s to file %s\n"), 10475a7763bfSjmcp curdev->access_devname, filename); 1048f8bf33c3SShantkumar Hiremath found++; 10495a7763bfSjmcp } 10505a7763bfSjmcp 10515a7763bfSjmcp } 1052f8bf33c3SShantkumar Hiremath 1053f8bf33c3SShantkumar Hiremath if (!found) { 10545a7763bfSjmcp logmsg(MSG_ERROR, 10555a7763bfSjmcp gettext("No device matching %s was found.\n"), 10565a7763bfSjmcp device); 10575a7763bfSjmcp rv = FWFLASH_FAILURE; 10585a7763bfSjmcp } 10595a7763bfSjmcp 10605a7763bfSjmcp return (rv); 10615a7763bfSjmcp } 10625a7763bfSjmcp 10635a7763bfSjmcp static void 10645a7763bfSjmcp fwflash_usage(char *arg) 10655a7763bfSjmcp { 10665a7763bfSjmcp 10675a7763bfSjmcp (void) fprintf(stderr, "\n"); 10685a7763bfSjmcp if (arg != NULL) { 10695a7763bfSjmcp logmsg(MSG_ERROR, 10705a7763bfSjmcp gettext("Invalid argument (%s) supplied\n"), arg); 10715a7763bfSjmcp } 10725a7763bfSjmcp 10735a7763bfSjmcp (void) fprintf(stderr, "\n"); 10745a7763bfSjmcp 10755a7763bfSjmcp (void) fprintf(stdout, gettext("Usage:\n\t")); 10765a7763bfSjmcp (void) fprintf(stdout, gettext("fwflash [-l [-c device_class " 10775a7763bfSjmcp "| ALL]] | [-v] | [-h]\n\t")); 10785a7763bfSjmcp (void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3" 10795a7763bfSjmcp ",... | -r file] [-y] -d device_path\n\n")); 10805a7763bfSjmcp (void) fprintf(stdout, "\n"); /* workaround for xgettext */ 10815a7763bfSjmcp 10825a7763bfSjmcp (void) fprintf(stdout, 10835a7763bfSjmcp gettext("\t-l\t\tlist flashable devices in this system\n" 10845a7763bfSjmcp "\t-c device_class limit search to a specific class\n" 10855a7763bfSjmcp "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n" 10865a7763bfSjmcp "\t-v\t\tprint version number of fwflash utility\n" 1087f8bf33c3SShantkumar Hiremath "\t-h\t\tprint this usage message\n\n")); 10885a7763bfSjmcp (void) fprintf(stdout, 10895a7763bfSjmcp gettext("\t-f file1,file2,file3,...\n" 10905a7763bfSjmcp "\t\t\tfirmware image file list to flash\n" 10915a7763bfSjmcp "\t-r file\t\tfile to dump device firmware to\n" 10925a7763bfSjmcp "\t-y\t\tanswer Yes/Y/y to prompts\n" 10935a7763bfSjmcp "\t-d device_path\tpathname of device to be flashed\n\n")); 10945a7763bfSjmcp 10955a7763bfSjmcp (void) fprintf(stdout, 10965a7763bfSjmcp gettext("\tIf -d device_path is specified, then one of -f " 10975a7763bfSjmcp "<files>\n" 10985a7763bfSjmcp "\tor -r <file> must also be specified\n\n")); 10995a7763bfSjmcp 11005a7763bfSjmcp (void) fprintf(stdout, 11015a7763bfSjmcp gettext("\tIf multiple firmware images are required to be " 11025a7763bfSjmcp "flashed\n" 11035a7763bfSjmcp "\tthey must be listed together, separated by commas. The\n" 11045a7763bfSjmcp "\timages will be flashed in the order specified.\n\n")); 11055a7763bfSjmcp 11065a7763bfSjmcp (void) fprintf(stdout, "\n"); 11075a7763bfSjmcp } 11085a7763bfSjmcp 11095a7763bfSjmcp static void 11105a7763bfSjmcp fwflash_version(void) 11115a7763bfSjmcp { 11125a7763bfSjmcp (void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME); 11135a7763bfSjmcp (void) fprintf(stdout, gettext("version %s\n"), 11145a7763bfSjmcp FWFLASH_VERSION); 11155a7763bfSjmcp } 11165a7763bfSjmcp 11175a7763bfSjmcp static void 11185a7763bfSjmcp fwflash_intr(int sig) 11195a7763bfSjmcp { 11205a7763bfSjmcp 11215a7763bfSjmcp struct devicelist *thisdev; 11225a7763bfSjmcp struct pluginlist *thisplug; 11235a7763bfSjmcp 11245a7763bfSjmcp (void) signal(SIGINT, SIG_IGN); 11255a7763bfSjmcp (void) signal(SIGTERM, SIG_IGN); 1126c4800545Sjmcp (void) signal(SIGABRT, SIG_IGN); 1127d65b419eSXinChen 11285a7763bfSjmcp if (fwflash_in_write) { 11295a7763bfSjmcp (void) fprintf(stderr, 11305a7763bfSjmcp gettext("WARNING: firmware image may be corrupted\n\t")); 11315a7763bfSjmcp (void) fprintf(stderr, 11325a7763bfSjmcp gettext("Reflash firmware before rebooting!\n")); 11335a7763bfSjmcp } 11345a7763bfSjmcp 11355a7763bfSjmcp if (sig > 0) { 11365a7763bfSjmcp (void) logmsg(MSG_ERROR, gettext("\n")); 11375a7763bfSjmcp (void) logmsg(MSG_ERROR, 11385a7763bfSjmcp gettext("fwflash exiting due to signal (%d)\n"), sig); 11395a7763bfSjmcp } 11405a7763bfSjmcp 11415a7763bfSjmcp /* 11425a7763bfSjmcp * we need to close everything down properly, so 11435a7763bfSjmcp * call the plugin closure routines 11445a7763bfSjmcp */ 11455a7763bfSjmcp if (fw_devices != NULL) { 11465a7763bfSjmcp TAILQ_FOREACH(thisdev, fw_devices, nextdev) { 1147d65b419eSXinChen if (thisdev->plugin->fw_cleanup != NULL) { 1148d65b419eSXinChen /* 1149d65b419eSXinChen * If we've got a cleanup routine, it 1150d65b419eSXinChen * cleans up _everything_ for thisdev 1151d65b419eSXinChen */ 1152d65b419eSXinChen thisdev->plugin->fw_cleanup(thisdev); 1153d65b419eSXinChen } else { 11545a7763bfSjmcp /* free the components first */ 11555a7763bfSjmcp free(thisdev->access_devname); 11565a7763bfSjmcp free(thisdev->drvname); 11575a7763bfSjmcp free(thisdev->classname); 1158c4800545Sjmcp if (thisdev->ident != NULL) 11595a7763bfSjmcp free(thisdev->ident); 1160d65b419eSXinChen /* We don't free address[] for old plugins */ 11615a7763bfSjmcp thisdev->ident = NULL; 1162d65b419eSXinChen thisdev->plugin = NULL; 1163d65b419eSXinChen } 11645a7763bfSjmcp /* CONSTCOND */ 11655a7763bfSjmcp TAILQ_REMOVE(fw_devices, thisdev, nextdev); 11665a7763bfSjmcp } 11675a7763bfSjmcp } 11685a7763bfSjmcp 11695a7763bfSjmcp if (fw_pluginlist != NULL) { 11705a7763bfSjmcp TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) { 11715a7763bfSjmcp free(thisplug->filename); 11725a7763bfSjmcp free(thisplug->drvname); 11735a7763bfSjmcp free(thisplug->plugin->filename); 11745a7763bfSjmcp free(thisplug->plugin->drvname); 11755a7763bfSjmcp thisplug->filename = NULL; 11765a7763bfSjmcp thisplug->drvname = NULL; 11775a7763bfSjmcp thisplug->plugin->filename = NULL; 11785a7763bfSjmcp thisplug->plugin->drvname = NULL; 11795a7763bfSjmcp thisplug->plugin->fw_readfw = NULL; 11805a7763bfSjmcp thisplug->plugin->fw_writefw = NULL; 11815a7763bfSjmcp thisplug->plugin->fw_identify = NULL; 11825a7763bfSjmcp thisplug->plugin->fw_devinfo = NULL; 1183d65b419eSXinChen thisplug->plugin->fw_cleanup = NULL; 11845a7763bfSjmcp (void) dlclose(thisplug->plugin->handle); 11855a7763bfSjmcp thisplug->plugin->handle = NULL; 11865a7763bfSjmcp free(thisplug->plugin); 11875a7763bfSjmcp thisplug->plugin = NULL; 11885a7763bfSjmcp /* CONSTCOND */ 11895a7763bfSjmcp TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin); 11905a7763bfSjmcp } 11915a7763bfSjmcp } 11925a7763bfSjmcp 11935a7763bfSjmcp if (verifier != NULL) { 11945a7763bfSjmcp free(verifier->filename); 11955a7763bfSjmcp free(verifier->vendor); 1196c4800545Sjmcp free(verifier->imgfile); 1197c4800545Sjmcp free(verifier->fwimage); 11985a7763bfSjmcp verifier->filename = NULL; 11995a7763bfSjmcp verifier->vendor = NULL; 12005a7763bfSjmcp verifier->vendorvrfy = NULL; 1201c4800545Sjmcp verifier->imgfile = NULL; 1202c4800545Sjmcp verifier->fwimage = NULL; 12035a7763bfSjmcp (void) dlclose(verifier->handle); 12045a7763bfSjmcp verifier->handle = NULL; 12055a7763bfSjmcp free(verifier); 12065a7763bfSjmcp } 12075a7763bfSjmcp di_fini(rootnode); 1208d65b419eSXinChen 1209d65b419eSXinChen if (sig > 0) 1210d65b419eSXinChen exit(FWFLASH_FAILURE); 12115a7763bfSjmcp } 12125a7763bfSjmcp 12135a7763bfSjmcp static void 12145a7763bfSjmcp fwflash_handle_signals(void) 12155a7763bfSjmcp { 12165a7763bfSjmcp if (signal(SIGINT, fwflash_intr) == SIG_ERR) { 12175a7763bfSjmcp perror("signal"); 12185a7763bfSjmcp exit(FWFLASH_FAILURE); 12195a7763bfSjmcp } 12205a7763bfSjmcp 12215a7763bfSjmcp if (signal(SIGTERM, fwflash_intr) == SIG_ERR) { 12225a7763bfSjmcp perror("signal"); 12235a7763bfSjmcp exit(FWFLASH_FAILURE); 12245a7763bfSjmcp } 12255a7763bfSjmcp } 12265a7763bfSjmcp 12275a7763bfSjmcp static int 12285a7763bfSjmcp confirm_target(struct devicelist *thisdev, char *file) 12295a7763bfSjmcp { 12305a7763bfSjmcp int resp; 12315a7763bfSjmcp 1232c4800545Sjmcp (void) fflush(stdin); 1233c4800545Sjmcp (void) printf(gettext("About to update firmware on %s\n"), 1234c4800545Sjmcp thisdev->access_devname); 1235d65b419eSXinChen (void) printf(gettext("with file %s.\n" 1236d65b419eSXinChen "Do you want to continue? (Y/N): "), file); 12375a7763bfSjmcp 12385a7763bfSjmcp resp = getchar(); 12395a7763bfSjmcp if (resp == 'Y' || resp == 'y') { 12405a7763bfSjmcp return (FWFLASH_YES_FLAG); 12415a7763bfSjmcp } else { 12425a7763bfSjmcp logmsg(MSG_INFO, "flash operation NOT confirmed.\n"); 12435a7763bfSjmcp } 12445a7763bfSjmcp 12455a7763bfSjmcp (void) fflush(stdin); 12465a7763bfSjmcp return (FWFLASH_FAILURE); 12475a7763bfSjmcp } 12485a7763bfSjmcp 12495a7763bfSjmcp int 12505a7763bfSjmcp get_fileopts(char *options) 12515a7763bfSjmcp { 12525a7763bfSjmcp 12535a7763bfSjmcp int i; 12545a7763bfSjmcp char *files; 12555a7763bfSjmcp 12565a7763bfSjmcp if (files = strtok(options, ",")) { 12575a7763bfSjmcp /* we have more than one */ 12585a7763bfSjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 12595a7763bfSjmcp logmsg(MSG_ERROR, 12605a7763bfSjmcp gettext("Unable to allocate space for " 12615a7763bfSjmcp "a firmware image filename\n")); 12625a7763bfSjmcp return (FWFLASH_FAILURE); 12635a7763bfSjmcp } 12645a7763bfSjmcp (void) strlcpy(filelist[0], files, strlen(files) + 1); 12655a7763bfSjmcp i = 1; 12665a7763bfSjmcp 12675a7763bfSjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 12685a7763bfSjmcp filelist[0]); 12695a7763bfSjmcp 12705a7763bfSjmcp 12715a7763bfSjmcp while (files = strtok(NULL, ",")) { 12725a7763bfSjmcp if ((filelist[i] = calloc(1, MAXPATHLEN + 1)) 12735a7763bfSjmcp == NULL) { 12745a7763bfSjmcp logmsg(MSG_ERROR, 12755a7763bfSjmcp gettext("Unable to allocate space for " 12765a7763bfSjmcp "a firmware image filename\n")); 12775a7763bfSjmcp return (FWFLASH_FAILURE); 12785a7763bfSjmcp } 12795a7763bfSjmcp (void) strlcpy(filelist[i], files, 12805a7763bfSjmcp strlen(files) + 1); 12815a7763bfSjmcp logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n", 12825a7763bfSjmcp i, filelist[i]); 12835a7763bfSjmcp ++i; 12845a7763bfSjmcp } 12855a7763bfSjmcp } else { 12865a7763bfSjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 12875a7763bfSjmcp logmsg(MSG_ERROR, 12885a7763bfSjmcp gettext("Unable to allocate space for " 12895a7763bfSjmcp "a firmware image filename\n")); 12905a7763bfSjmcp return (FWFLASH_FAILURE); 12915a7763bfSjmcp } 12925a7763bfSjmcp (void) strlcpy(filelist[0], options, strlen(files) + 1); 12935a7763bfSjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 12945a7763bfSjmcp filelist[0]); 12955a7763bfSjmcp } 12965a7763bfSjmcp return (FWFLASH_SUCCESS); 12975a7763bfSjmcp } 12985a7763bfSjmcp 12995a7763bfSjmcp /* 13005a7763bfSjmcp * code reuse - cheerfully borrowed from stmsboot_util.c 13015a7763bfSjmcp */ 13025a7763bfSjmcp void 1303d65b419eSXinChen logmsg(int severity, const char *msg, ...) 1304d65b419eSXinChen { 13055a7763bfSjmcp va_list ap; 13065a7763bfSjmcp 13075a7763bfSjmcp if ((severity > MSG_INFO) || 13085a7763bfSjmcp ((severity == MSG_INFO) && (fwflash_debug > 0))) { 13095a7763bfSjmcp (void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME); 13105a7763bfSjmcp va_start(ap, msg); 13115a7763bfSjmcp (void) vfprintf(stderr, msg, ap); 13125a7763bfSjmcp va_end(ap); 13135a7763bfSjmcp } 13145a7763bfSjmcp } 1315