16489Sjmcp /* 26489Sjmcp * CDDL HEADER START 36489Sjmcp * 46489Sjmcp * The contents of this file are subject to the terms of the 56489Sjmcp * Common Development and Distribution License (the "License"). 66489Sjmcp * You may not use this file except in compliance with the License. 76489Sjmcp * 86489Sjmcp * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 96489Sjmcp * or http://www.opensolaris.org/os/licensing. 106489Sjmcp * See the License for the specific language governing permissions 116489Sjmcp * and limitations under the License. 126489Sjmcp * 136489Sjmcp * When distributing Covered Code, include this CDDL HEADER in each 146489Sjmcp * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 156489Sjmcp * If applicable, add the following below this CDDL HEADER, with the 166489Sjmcp * fields enclosed by brackets "[]" replaced with your own identifying 176489Sjmcp * information: Portions Copyright [yyyy] [name of copyright owner] 186489Sjmcp * 196489Sjmcp * CDDL HEADER END 206489Sjmcp */ 216489Sjmcp /* 226489Sjmcp * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 236489Sjmcp * Use is subject to license terms. 246489Sjmcp */ 256489Sjmcp 266489Sjmcp #pragma ident "%Z%%M% %I% %E% SMI" 276489Sjmcp 286489Sjmcp /* 296489Sjmcp * fwflash.c 306489Sjmcp */ 316489Sjmcp #include <stdio.h> 326489Sjmcp #include <stdlib.h> 336489Sjmcp #include <unistd.h> 346489Sjmcp #include <strings.h> 356489Sjmcp #include <ctype.h> 366489Sjmcp #include <errno.h> 376489Sjmcp #include <sys/queue.h> 386489Sjmcp #include <signal.h> 396489Sjmcp #include <locale.h> 406489Sjmcp #include <sys/stat.h> 416489Sjmcp #include <sys/types.h> 426489Sjmcp #include <sys/param.h> 436489Sjmcp #include <fcntl.h> 446489Sjmcp #include <dlfcn.h> 456489Sjmcp #include <dirent.h> 466489Sjmcp #include <link.h> 476489Sjmcp #include <sys/varargs.h> 486489Sjmcp #include <libintl.h> /* for gettext(3c) */ 496489Sjmcp #include <libdevinfo.h> 506489Sjmcp #include <note.h> 516489Sjmcp #include <fwflash/fwflash.h> 52*6846Sjmcp #include <sys/modctl.h> /* for MAXMODCONFNAME */ 536489Sjmcp 546489Sjmcp 556489Sjmcp #if !defined(lint) 566489Sjmcp /* embedded software license agreement */ 576489Sjmcp static char *sla [] = { "Copyright 2007 Sun Microsystems, Inc., 4150 Network " 586489Sjmcp "Circle, Santa Clara, California 95054, U.S.A. All rights reserved. U.S. " 596489Sjmcp "Government Rights - Commercial software. Government users are subject to the " 606489Sjmcp "Sun Microsystems, Inc. standard license agreement and applicable provisions " 616489Sjmcp "of the FAR and its supplements. Use is subject to license terms. Parts of " 626489Sjmcp "the product may be derived from Berkeley BSD systems, licensed from the " 636489Sjmcp "University of California. UNIX is a registered trademark in the U.S. and in " 646489Sjmcp "other countries, exclusively licensed through X/Open Company, Ltd.Sun, Sun " 656489Sjmcp "Microsystems, the Sun logo and Solaris are trademarks or registered " 666489Sjmcp "trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This " 676489Sjmcp "product is covered and controlled by U.S. Export Control laws and may be " 686489Sjmcp "subject to the export or import laws in other countries. Nuclear, missile, " 696489Sjmcp "chemical biological weapons or nuclear maritime end uses or end users, " 706489Sjmcp "whether direct or indirect, are strictly prohibited. Export or reexport " 716489Sjmcp "to countries subject to U.S. embargo or to entities identified on U.S. export " 726489Sjmcp "exclusion lists, including, but not limited to, the denied persons and " 736489Sjmcp "specially designated nationals lists is strictly prohibited." }; 746489Sjmcp #endif /* lint */ 756489Sjmcp 766489Sjmcp /* global arg list */ 776489Sjmcp int fwflash_arg_list = 0; 786489Sjmcp char *filelist[10]; 796489Sjmcp 806489Sjmcp 816489Sjmcp /* are we writing to flash? */ 826489Sjmcp static int fwflash_in_write = 0; 836489Sjmcp 846489Sjmcp /* 856489Sjmcp * If we *must* track the version string for fwflash, then 866489Sjmcp * we should do so in this common file rather than the header 876489Sjmcp * file since it will then be in sync with what the customer 886489Sjmcp * sees 896489Sjmcp */ 906489Sjmcp 916489Sjmcp 926489Sjmcp #define FWFLASH_VERSION "%I%" 936489Sjmcp #define FWFLASH_PROG_NAME "fwflash" 946489Sjmcp 956489Sjmcp 966489Sjmcp 976489Sjmcp static int get_fileopts(char *options); 986489Sjmcp static int flash_device_list(); 996489Sjmcp static int flash_load_plugins(); 1006489Sjmcp static int fwflash_update(char *device, char *filename, int flags); 1016489Sjmcp static int fwflash_read_file(char *device, char *filename); 1026489Sjmcp static int fwflash_list_fw(char *class); 1036489Sjmcp static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg); 1046489Sjmcp static void fwflash_intr(int sig); 1056489Sjmcp static void fwflash_handle_signals(void); 1066489Sjmcp static void fwflash_usage(); 1076489Sjmcp static void fwflash_help(void); 1086489Sjmcp static void fwflash_version(void); 1096489Sjmcp static int confirm_target(struct devicelist *thisdev, char *file); 1106489Sjmcp 1116489Sjmcp 1126489Sjmcp 1136489Sjmcp 1146489Sjmcp /* 1156489Sjmcp * FWFlash main code 1166489Sjmcp */ 1176489Sjmcp int 1186489Sjmcp main(int argc, char **argv) { 1196489Sjmcp int rv = FWFLASH_SUCCESS; 1206489Sjmcp int i; 1216489Sjmcp char ch; 1226489Sjmcp char *read_file; 1236489Sjmcp extern char *optarg; 1246489Sjmcp char *devclass = NULL; 1256489Sjmcp char *devpath = NULL; 1266489Sjmcp 1276489Sjmcp 1286489Sjmcp 1296489Sjmcp /* local variables from env */ 1306489Sjmcp (void) setlocale(LC_ALL, ""); 1316489Sjmcp 1326489Sjmcp #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */ 1336489Sjmcp #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */ 1346489Sjmcp #endif 1356489Sjmcp 1366489Sjmcp (void) textdomain(TEXT_DOMAIN); 1376489Sjmcp 1386489Sjmcp 1396489Sjmcp read_file = NULL; 1406489Sjmcp 1416489Sjmcp if (argc < 2) { 1426489Sjmcp /* no args supplied */ 1436489Sjmcp fwflash_usage(NULL); 1446489Sjmcp return (FWFLASH_FAILURE); 1456489Sjmcp } 1466489Sjmcp 1476489Sjmcp 148*6846Sjmcp while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:M")) != EOF) { 1496489Sjmcp switch (ch) { 1506489Sjmcp case 'h': 1516489Sjmcp fwflash_arg_list |= FWFLASH_HELP_FLAG; 1526489Sjmcp break; 1536489Sjmcp 1546489Sjmcp case 'v': 1556489Sjmcp fwflash_arg_list |= FWFLASH_VER_FLAG; 1566489Sjmcp break; 1576489Sjmcp 1586489Sjmcp case 'y': 1596489Sjmcp fwflash_arg_list |= FWFLASH_YES_FLAG; 1606489Sjmcp break; 1616489Sjmcp 1626489Sjmcp case 'l': 1636489Sjmcp fwflash_arg_list |= FWFLASH_LIST_FLAG; 1646489Sjmcp break; 1656489Sjmcp 1666489Sjmcp case 'c': 1676489Sjmcp fwflash_arg_list |= FWFLASH_CLASS_FLAG; 1686489Sjmcp /* we validate later */ 1696489Sjmcp devclass = strdup(optarg); 1706489Sjmcp break; 1716489Sjmcp 1726489Sjmcp case 'd': 1736489Sjmcp fwflash_arg_list |= FWFLASH_DEVICE_FLAG; 1746489Sjmcp devpath = strdup(optarg); 1756489Sjmcp break; 1766489Sjmcp 1776489Sjmcp case 'f': 1786489Sjmcp fwflash_arg_list |= FWFLASH_FW_FLAG; 1796489Sjmcp if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) { 1806489Sjmcp fwflash_help(); 1816489Sjmcp return (FWFLASH_FAILURE); 1826489Sjmcp } 1836489Sjmcp break; 1846489Sjmcp 1856489Sjmcp case 'r': 1866489Sjmcp fwflash_arg_list |= FWFLASH_READ_FLAG; 1876489Sjmcp read_file = strdup(optarg); 1886489Sjmcp break; 1896489Sjmcp 1906489Sjmcp case 'Q': 1916489Sjmcp /* NOT in the manpage */ 1926489Sjmcp fwflash_debug = 1; 1936489Sjmcp break; 194*6846Sjmcp case 'M': 195*6846Sjmcp /* NOT in the manpage */ 196*6846Sjmcp #if (MANUFACTURING_MODE > 0) 197*6846Sjmcp manufacturing_mode = 1; 198*6846Sjmcp logmsg(MSG_WARN, "Enabling Manufacturing Mode " 199*6846Sjmcp "operations. This can be destructive!\n"); 200*6846Sjmcp break; 201*6846Sjmcp #endif 202*6846Sjmcp /* illegal options */ 2036489Sjmcp default: 2046489Sjmcp fwflash_usage(optarg); 2056489Sjmcp return (FWFLASH_FAILURE); 2066489Sjmcp } 2076489Sjmcp } 2086489Sjmcp 2096489Sjmcp /* Do Help */ 2106489Sjmcp if ((fwflash_arg_list & FWFLASH_HELP_FLAG) || 2116489Sjmcp ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) && 2126489Sjmcp !((fwflash_arg_list & FWFLASH_FW_FLAG) || 2136489Sjmcp (fwflash_arg_list & FWFLASH_READ_FLAG)))) { 2146489Sjmcp fwflash_help(); 2156489Sjmcp return (FWFLASH_SUCCESS); 2166489Sjmcp } 2176489Sjmcp 2186489Sjmcp /* Do Version */ 2196489Sjmcp if (fwflash_arg_list == FWFLASH_VER_FLAG) { 2206489Sjmcp fwflash_version(); 2216489Sjmcp return (FWFLASH_SUCCESS); 2226489Sjmcp } 2236489Sjmcp 2246489Sjmcp /* generate global list of devices */ 2256489Sjmcp if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) { 2266489Sjmcp logmsg(MSG_ERROR, 2276489Sjmcp gettext("Unable to load fwflash plugins\n")); 2286489Sjmcp fwflash_intr(0); 2296489Sjmcp return (rv); 2306489Sjmcp } 2316489Sjmcp 2326489Sjmcp if ((rv = flash_device_list()) != FWFLASH_SUCCESS) { 2336489Sjmcp logmsg(MSG_ERROR, 2346489Sjmcp gettext("No flashable devices in this system\n")); 2356489Sjmcp fwflash_intr(0); 2366489Sjmcp return (rv); 2376489Sjmcp } 2386489Sjmcp 2396489Sjmcp /* Do list */ 2406489Sjmcp if (fwflash_arg_list == (FWFLASH_LIST_FLAG) || 2416489Sjmcp fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) { 2426489Sjmcp rv = fwflash_list_fw(devclass); 2436489Sjmcp fwflash_intr(0); 2446489Sjmcp return (rv); 2456489Sjmcp } 2466489Sjmcp 2476489Sjmcp fwflash_handle_signals(); 2486489Sjmcp 2496489Sjmcp /* Do flash update (write) */ 2506489Sjmcp if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) || 2516489Sjmcp (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG | 2526489Sjmcp FWFLASH_YES_FLAG))) { 2536489Sjmcp /* the update function handles the real arg parsing */ 2546489Sjmcp i = 0; 2556489Sjmcp while (filelist[i] != NULL) { 2566489Sjmcp if ((rv = fwflash_update(devpath, filelist[i], 2576489Sjmcp fwflash_arg_list)) == FWFLASH_SUCCESS) { 2586489Sjmcp /* failed ops have already been noted */ 2596489Sjmcp logmsg(MSG_ERROR, 2606489Sjmcp gettext("New firmware will be activated " 2616489Sjmcp "after you reboot\n\n")); 2626489Sjmcp } 2636489Sjmcp ++i; 2646489Sjmcp } 2656489Sjmcp 2666489Sjmcp fwflash_intr(0); 2676489Sjmcp return (rv); 2686489Sjmcp } 2696489Sjmcp 2706489Sjmcp /* Do flash read */ 2716489Sjmcp if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) || 2726489Sjmcp (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG | 2736489Sjmcp FWFLASH_YES_FLAG))) { 2746489Sjmcp rv = fwflash_read_file(devpath, read_file); 2756489Sjmcp fwflash_intr(0); 2766489Sjmcp return (rv); 2776489Sjmcp } 2786489Sjmcp 2796489Sjmcp fwflash_usage(NULL); 2806489Sjmcp 2816489Sjmcp return (FWFLASH_FAILURE); 2826489Sjmcp } 2836489Sjmcp 2846489Sjmcp 2856489Sjmcp 2866489Sjmcp 2876489Sjmcp 2886489Sjmcp static int 2896489Sjmcp flash_load_plugins() { 2906489Sjmcp 2916489Sjmcp int rval = FWFLASH_SUCCESS; 2926489Sjmcp DIR *dirp; 2936489Sjmcp struct dirent *plugdir; 2946489Sjmcp char *plugname; 2956489Sjmcp struct fw_plugin *tmpplug; 2966489Sjmcp struct pluginlist *tmpelem; 2976489Sjmcp void *sym; 2986489Sjmcp char *fwplugdirpath, *tempdirpath; 2996489Sjmcp 3006489Sjmcp 3016489Sjmcp #define CLOSEFREE() { \ 3026489Sjmcp (void) dlclose(tmpplug->handle); \ 3036489Sjmcp free(tmpplug); } 3046489Sjmcp 3056489Sjmcp 3066489Sjmcp /* 3076489Sjmcp * Procedure: 3086489Sjmcp * 3096489Sjmcp * cd /usr/lib/fwflash/identify 3106489Sjmcp * open each .so file found therein 3116489Sjmcp * dlopen(.sofile) 3126489Sjmcp * if it's one of our plugins, add it to fw_pluginlist; 3136489Sjmcp * 3146489Sjmcp * functions we need here include dlopen and dlsym. 3156489Sjmcp * 3166489Sjmcp * If we get to the end and fw_pluginlist struct is empty, 3176489Sjmcp * return FWFLASH_FAILURE so we return to the shell. 3186489Sjmcp */ 3196489Sjmcp 3206489Sjmcp if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 3216489Sjmcp logmsg(MSG_ERROR, 3226489Sjmcp gettext("Unable to malloc %d bytes while " 3236489Sjmcp "trying to load plugins: %s\n"), 3246489Sjmcp MAXPATHLEN + 1, strerror(errno)); 3256489Sjmcp return (FWFLASH_FAILURE); 3266489Sjmcp } 3276489Sjmcp 3286489Sjmcp tempdirpath = getenv("FWPLUGINDIR"); 3296489Sjmcp 3306489Sjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 3316489Sjmcp (void) strlcpy(fwplugdirpath, tempdirpath, 3326489Sjmcp strlen(tempdirpath) + 1); 3336489Sjmcp } else { 3346489Sjmcp (void) strlcpy(fwplugdirpath, FWPLUGINDIR, 3356489Sjmcp strlen(FWPLUGINDIR) + 1); 3366489Sjmcp } 3376489Sjmcp 3386489Sjmcp if ((dirp = opendir(fwplugdirpath)) == NULL) { 3396489Sjmcp logmsg(MSG_ERROR, 340*6846Sjmcp gettext("Unable to open %s\n"), 3416489Sjmcp fwplugdirpath); 3426489Sjmcp return (errno); 3436489Sjmcp } 3446489Sjmcp 3456489Sjmcp if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1)) 3466489Sjmcp == NULL) { 3476489Sjmcp logmsg(MSG_ERROR, 3486489Sjmcp gettext("Unable to malloc %d bytes while " 3496489Sjmcp "trying to load plugins: %s\n"), 3506489Sjmcp MAXPATHLEN + 1 + sizeof (struct dirent), 3516489Sjmcp strerror(errno)); 3526489Sjmcp return (FWFLASH_FAILURE); 3536489Sjmcp } 3546489Sjmcp 3556489Sjmcp if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin))) 3566489Sjmcp == NULL) { 3576489Sjmcp logmsg(MSG_ERROR, 3586489Sjmcp gettext("Unable to malloc %d bytes while " 3596489Sjmcp "trying to load plugins: %s\n"), 3606489Sjmcp sizeof (struct fw_plugin) + 1, strerror(errno)); 3616489Sjmcp return (FWFLASH_FAILURE); 3626489Sjmcp } 3636489Sjmcp 3646489Sjmcp NOTE(CONSTCOND) 3656489Sjmcp TAILQ_INIT(fw_pluginlist); 3666489Sjmcp 3676489Sjmcp while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) { 3686489Sjmcp 3696489Sjmcp errno = 0; /* remove chance of false results */ 3706489Sjmcp 3716489Sjmcp if ((plugdir->d_name[0] == '.') || 3726489Sjmcp (strstr(plugdir->d_name, ".so") == NULL)) { 3736489Sjmcp continue; 3746489Sjmcp } 3756489Sjmcp 3766489Sjmcp if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) { 3776489Sjmcp logmsg(MSG_ERROR, 3786489Sjmcp gettext("Unable to malloc %d bytes while " 3796489Sjmcp "trying to load plugins: %s\n"), 3806489Sjmcp MAXPATHLEN + 1, strerror(errno)); 3816489Sjmcp return (FWFLASH_FAILURE); 3826489Sjmcp } 3836489Sjmcp 3846489Sjmcp (void) snprintf(plugname, MAXPATHLEN, "%s/%s", 3856489Sjmcp fwplugdirpath, plugdir->d_name); 3866489Sjmcp 3876489Sjmcp /* start allocating storage */ 3886489Sjmcp if ((tmpelem = calloc(1, sizeof (struct pluginlist))) 3896489Sjmcp == NULL) { 3906489Sjmcp logmsg(MSG_ERROR, 3916489Sjmcp gettext("Unable to malloc %d bytes while " 3926489Sjmcp "trying to load plugins: %s\n"), 3936489Sjmcp sizeof (struct pluginlist), strerror(errno)); 3946489Sjmcp return (FWFLASH_FAILURE); 3956489Sjmcp } 3966489Sjmcp 3976489Sjmcp if ((tmpplug = calloc(1, sizeof (struct fw_plugin))) 3986489Sjmcp == NULL) { 3996489Sjmcp logmsg(MSG_ERROR, 4006489Sjmcp gettext("Unable to malloc %d bytes while " 4016489Sjmcp "trying to load plugins: %s\n"), 4026489Sjmcp sizeof (struct fw_plugin), strerror(errno)); 4036489Sjmcp return (FWFLASH_FAILURE); 4046489Sjmcp } 4056489Sjmcp 4066489Sjmcp /* load 'er up! */ 4076489Sjmcp tmpplug->handle = dlopen(plugname, RTLD_NOW); 4086489Sjmcp if (tmpplug->handle == NULL) { 4096489Sjmcp free(tmpplug); 4106489Sjmcp continue; /* assume there are other plugins */ 4116489Sjmcp } 4126489Sjmcp 4136489Sjmcp if ((tmpplug->filename = calloc(1, strlen(plugname) + 1)) 4146489Sjmcp == NULL) { 4156489Sjmcp logmsg(MSG_ERROR, 4166489Sjmcp gettext("Unable to allocate %d bytes for plugin " 4176489Sjmcp "filename %s:%s\n"), 4186489Sjmcp strlen(plugname) + 1, plugname, 4196489Sjmcp strerror(errno)); 4206489Sjmcp return (rval); 4216489Sjmcp } 4226489Sjmcp 4236489Sjmcp (void) strlcpy(tmpplug->filename, plugname, 4246489Sjmcp strlen(plugname) + 1); 4256489Sjmcp 4266489Sjmcp /* now sanity check the file */ 4276489Sjmcp if ((sym = dlsym(tmpplug->handle, "drivername")) 4286489Sjmcp != NULL) { 4296489Sjmcp /* max length of drivername */ 430*6846Sjmcp tmpplug->drvname = calloc(1, MAXMODCONFNAME); 431*6846Sjmcp 432*6846Sjmcp /* are we doing double-time? */ 433*6846Sjmcp if (strncmp((char *)sym, plugdir->d_name, 434*6846Sjmcp MAXMODCONFNAME) != 0) { 435*6846Sjmcp char *tempnm = calloc(1, MAXMODCONFNAME); 436*6846Sjmcp 437*6846Sjmcp memcpy(tempnm, plugdir->d_name, MAXMODCONFNAME); 438*6846Sjmcp (void) strlcpy(tmpplug->drvname, 439*6846Sjmcp strtok(tempnm, "."), 440*6846Sjmcp strlen(plugdir->d_name) + 1); 441*6846Sjmcp free(tempnm); 442*6846Sjmcp } else { 443*6846Sjmcp (void) strlcpy(tmpplug->drvname, 444*6846Sjmcp (char *)sym, strlen(sym) + 1); 445*6846Sjmcp } 4466489Sjmcp } else { 4476489Sjmcp CLOSEFREE(); 4486489Sjmcp continue; 4496489Sjmcp } 4506489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_readfw")) 4516489Sjmcp != NULL) { 4526489Sjmcp tmpplug->fw_readfw = (int (*)())sym; 4536489Sjmcp } else { 4546489Sjmcp CLOSEFREE(); 4556489Sjmcp continue; 4566489Sjmcp } 4576489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_writefw")) 4586489Sjmcp != NULL) { 4596489Sjmcp tmpplug->fw_writefw = (int (*)())sym; 4606489Sjmcp } else { 4616489Sjmcp CLOSEFREE(); 4626489Sjmcp continue; 4636489Sjmcp } 4646489Sjmcp 4656489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_identify")) 4666489Sjmcp != NULL) { 4676489Sjmcp tmpplug->fw_identify = 4686489Sjmcp (int (*)(int))sym; 4696489Sjmcp } else { 4706489Sjmcp CLOSEFREE(); 4716489Sjmcp continue; 4726489Sjmcp } 4736489Sjmcp if ((sym = dlsym(tmpplug->handle, "fw_devinfo")) 4746489Sjmcp != NULL) { 4756489Sjmcp tmpplug->fw_devinfo = 4766489Sjmcp (int (*)(struct devicelist *))sym; 4776489Sjmcp } else { 4786489Sjmcp CLOSEFREE(); 4796489Sjmcp continue; 4806489Sjmcp } 4816489Sjmcp 482*6846Sjmcp if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME)) 4836489Sjmcp == NULL) { 4846489Sjmcp logmsg(MSG_ERROR, 485*6846Sjmcp gettext("Unable to allocate space for a" 4866489Sjmcp "drivername %s\n"), 4876489Sjmcp tmpplug->drvname); 4886489Sjmcp return (FWFLASH_FAILURE); 4896489Sjmcp } 4906489Sjmcp 4916489Sjmcp (void) strlcpy(tmpelem->drvname, tmpplug->drvname, 4926489Sjmcp strlen(tmpplug->drvname) + 1); 4936489Sjmcp 4946489Sjmcp if ((tmpelem->filename = calloc(1, 4956489Sjmcp strlen(tmpplug->filename) + 1)) == NULL) { 4966489Sjmcp logmsg(MSG_ERROR, 4976489Sjmcp gettext("Unable to allocate %d bytes for " 4986489Sjmcp "filename %s\n"), 4996489Sjmcp strlen(tmpplug->filename) + 1, 500*6846Sjmcp tmpplug->filename); 5016489Sjmcp return (FWFLASH_FAILURE); 5026489Sjmcp } 5036489Sjmcp 5046489Sjmcp (void) strlcpy(tmpelem->filename, plugname, 5056489Sjmcp strlen(plugname) + 1); 5066489Sjmcp tmpelem->plugin = tmpplug; 5076489Sjmcp 5086489Sjmcp /* CONSTCOND */ 5096489Sjmcp TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin); 5106489Sjmcp } 5116489Sjmcp 5126489Sjmcp if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) { 5136489Sjmcp return (FWFLASH_FAILURE); 5146489Sjmcp } 5156489Sjmcp 5166489Sjmcp 5176489Sjmcp if (errno != 0) { 5186489Sjmcp logmsg(MSG_ERROR, 5196489Sjmcp gettext("Error reading directory entry in %s\n"), 5206489Sjmcp fwplugdirpath); 5216489Sjmcp (void) closedir(dirp); 5226489Sjmcp rval = errno; 5236489Sjmcp } 5246489Sjmcp 5256489Sjmcp (void) free(fwplugdirpath); 5266489Sjmcp (void) free(plugdir); 5276489Sjmcp (void) closedir(dirp); 5286489Sjmcp return (rval); 5296489Sjmcp } 5306489Sjmcp 5316489Sjmcp 5326489Sjmcp 5336489Sjmcp /* 5346489Sjmcp * fwflash_load_verifier dlload()s the appropriate firmware image 5356489Sjmcp * verification plugin, and attaches the designated fwimg's fd to 5366489Sjmcp * the vrfyplugin structure so we only have to load the image in 5376489Sjmcp * one place. 5386489Sjmcp */ 5396489Sjmcp int 5406489Sjmcp fwflash_load_verifier(char *drv, char *vendorid, char *fwimg) { 5416489Sjmcp 5426489Sjmcp int rv = FWFLASH_FAILURE; 5436489Sjmcp int imgfd; 5446489Sjmcp char *fwvrfydirpath, *tempdirpath, *filename; 5456489Sjmcp char *clean; /* for the space-removed vid */ 5466489Sjmcp struct stat fwstat; 5476489Sjmcp struct vrfyplugin *vrfy; 5486489Sjmcp void *vrfysym; 5496489Sjmcp 5506489Sjmcp 5516489Sjmcp /* 5526489Sjmcp * To make flashing multiple firmware images somewhat more 5536489Sjmcp * efficient, we start this function by checking whether a 5546489Sjmcp * verifier for this device has already been loaded. If it 5556489Sjmcp * has been loaded, we replace the imgfile information, and 5566489Sjmcp * then continue as if we were loading for the first time. 5576489Sjmcp */ 5586489Sjmcp 5596489Sjmcp if (verifier != NULL) { 5606489Sjmcp verifier->imgsize = 0; 5616489Sjmcp verifier->flashbuf = 0; /* set by the verifier function */ 5626489Sjmcp 5636489Sjmcp if (verifier->imgfile != NULL) 5646489Sjmcp (void) free(verifier->imgfile); 5656489Sjmcp 5666489Sjmcp if (verifier->fwimage != NULL) 5676489Sjmcp (void) free(verifier->fwimage); 5686489Sjmcp } else { 5696489Sjmcp if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) { 5706489Sjmcp logmsg(MSG_ERROR, 5716489Sjmcp gettext("Unable to allocate space for a firmware " 5726489Sjmcp "verifier file(1)")); 5736489Sjmcp return (rv); 5746489Sjmcp } 5756489Sjmcp 5766489Sjmcp if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) { 5776489Sjmcp logmsg(MSG_ERROR, 5786489Sjmcp gettext("Unable to allocate space " 5796489Sjmcp "for a firmware verifier file(2)")); 5806489Sjmcp return (rv); 5816489Sjmcp } 5826489Sjmcp 5836489Sjmcp /* 5846489Sjmcp * Since SCSI devices can have a vendor id of up to 8 left-aligned 5856489Sjmcp * and _space-padded_ characters, we first need to strip off any 5866489Sjmcp * space characters before we try to make a filename out of it 5876489Sjmcp */ 5886489Sjmcp clean = strtok(vendorid, " "); 5896489Sjmcp if (clean == NULL) { 5906489Sjmcp /* invalid vendorid, something's really wrong */ 5916489Sjmcp logmsg(MSG_ERROR, 5926489Sjmcp gettext("Invalid vendorid (null) specified for " 5936489Sjmcp "device\n")); 5946489Sjmcp return (rv); 5956489Sjmcp } 5966489Sjmcp 5976489Sjmcp tempdirpath = getenv("FWVERIFYPLUGINDIR"); 5986489Sjmcp 5996489Sjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) { 6006489Sjmcp (void) strlcpy(fwvrfydirpath, tempdirpath, 6016489Sjmcp strlen(tempdirpath) + 1); 6026489Sjmcp } else { 6036489Sjmcp (void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR, 6046489Sjmcp strlen(FWVERIFYPLUGINDIR) + 1); 6056489Sjmcp } 6066489Sjmcp 6076489Sjmcp if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) { 6086489Sjmcp logmsg(MSG_ERROR, 6096489Sjmcp gettext("Unable to allocate space " 6106489Sjmcp "for a firmware verifier structure")); 6116489Sjmcp free(filename); 6126489Sjmcp free(fwvrfydirpath); 6136489Sjmcp return (FWFLASH_FAILURE); 6146489Sjmcp } 6156489Sjmcp 6166489Sjmcp errno = 0; /* false positive removal */ 6176489Sjmcp 6186489Sjmcp (void) snprintf(filename, strlen(fwvrfydirpath) + 6196489Sjmcp strlen(drv) + 7 + strlen(clean), "%s/%s-%s.so\0", 6206489Sjmcp fwvrfydirpath, drv, clean); 6216489Sjmcp 6226489Sjmcp if ((vrfy->filename = calloc(1, strlen(filename) + 1)) 6236489Sjmcp == NULL) { 6246489Sjmcp logmsg(MSG_ERROR, 6256489Sjmcp gettext("Unable to allocate space to store " 6266489Sjmcp "a verifier filename\n")); 6276489Sjmcp free(filename); 6286489Sjmcp free(fwvrfydirpath); 6296489Sjmcp free(vrfy->handle); 6306489Sjmcp return (FWFLASH_FAILURE); 6316489Sjmcp } 6326489Sjmcp 6336489Sjmcp (void) strlcpy(vrfy->filename, filename, strlen(filename) + 1); 6346489Sjmcp 6356489Sjmcp if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) { 6366489Sjmcp logmsg(MSG_ERROR, gettext(dlerror())); 6376489Sjmcp logmsg(MSG_ERROR, 6386489Sjmcp gettext("Unable to open verification plugin " 639*6846Sjmcp "%s. Unable to verify firmware image. " 6406489Sjmcp "Aborting.\n"), 6416489Sjmcp filename); 6426489Sjmcp free(filename); 6436489Sjmcp free(fwvrfydirpath); 6446489Sjmcp return (FWFLASH_FAILURE); 6456489Sjmcp } 6466489Sjmcp 6476489Sjmcp if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) { 6486489Sjmcp logmsg(MSG_ERROR, 6496489Sjmcp gettext("%s is an invalid firmware verification " 6506489Sjmcp "plugin."), filename); 6516489Sjmcp (void) dlclose(vrfy->handle); 6526489Sjmcp free(filename); 6536489Sjmcp free(fwvrfydirpath); 6546489Sjmcp free(vrfy); 6556489Sjmcp return (FWFLASH_FAILURE); 6566489Sjmcp } else { 6576489Sjmcp vrfy->vendorvrfy = 6586489Sjmcp (int (*)(struct devicelist *))vrfysym; 6596489Sjmcp } 6606489Sjmcp 6616489Sjmcp vrfysym = dlsym(vrfy->handle, "vendor"); 6626489Sjmcp 6636489Sjmcp if (vrfysym == NULL) { 6646489Sjmcp logmsg(MSG_ERROR, 6656489Sjmcp gettext("Invalid vendor (null) in verification " 6666489Sjmcp "plugin %s\n"), filename); 6676489Sjmcp (void) dlclose(vrfy->handle); 6686489Sjmcp free(vrfy); 6696489Sjmcp return (NULL); 6706489Sjmcp } else { 6716489Sjmcp if (strncmp(vendorid, (char *)vrfysym, 6726489Sjmcp strlen(vendorid)) != 0) { 6736489Sjmcp logmsg(MSG_INFO, 6746489Sjmcp "Using a sym-linked (%s -> %s) " 6756489Sjmcp "verification plugin", 6766489Sjmcp vendorid, vrfysym); 6776489Sjmcp vrfy->vendor = calloc(1, strlen(vendorid) + 1); 6786489Sjmcp } else { 6796489Sjmcp vrfy->vendor = calloc(1, strlen(vrfysym) + 1); 6806489Sjmcp } 6816489Sjmcp (void) strlcpy(vrfy->vendor, (char *)vrfysym, 6826489Sjmcp strlen(vendorid) + 1); 6836489Sjmcp } 6846489Sjmcp 6856489Sjmcp verifier = vrfy; /* a convenience variable */ 6866489Sjmcp } 6876489Sjmcp 6886489Sjmcp 6896489Sjmcp /* 6906489Sjmcp * We don't do any verification that the fw image file is in 6916489Sjmcp * an approved location, but it's easy enough to modify this 6926489Sjmcp * function to do so. The verification plugin should provide 6936489Sjmcp * sufficient protection. 6946489Sjmcp */ 6956489Sjmcp 6966489Sjmcp if ((imgfd = open(fwimg, O_RDONLY)) < 0) { 6976489Sjmcp logmsg(MSG_ERROR, 6986489Sjmcp gettext("Unable to open designated firmware " 6996489Sjmcp "image file %s: %s\n"), 7006489Sjmcp (fwimg != NULL) ? fwimg : "(null)", 7016489Sjmcp strerror(errno)); 7026489Sjmcp rv = FWFLASH_FAILURE; 7036489Sjmcp goto cleanup; 7046489Sjmcp } 7056489Sjmcp 7066489Sjmcp if (stat(fwimg, &fwstat) == -1) { 7076489Sjmcp logmsg(MSG_ERROR, 7086489Sjmcp gettext("Unable to stat() firmware image file " 7096489Sjmcp "%s: %s\n"), 7106489Sjmcp fwimg, strerror(errno)); 7116489Sjmcp rv = FWFLASH_FAILURE; 7126489Sjmcp goto cleanup; 7136489Sjmcp } else { 7146489Sjmcp verifier->imgsize = fwstat.st_size; 7156489Sjmcp if ((verifier->fwimage = calloc(1, verifier->imgsize)) 7166489Sjmcp == NULL) { 7176489Sjmcp logmsg(MSG_ERROR, 7186489Sjmcp gettext("Unable to load firmware image " 7196489Sjmcp "%s: %s\n"), 7206489Sjmcp fwimg, strerror(errno)); 7216489Sjmcp rv = FWFLASH_FAILURE; 7226489Sjmcp goto cleanup; 7236489Sjmcp } 7246489Sjmcp } 7256489Sjmcp 7266489Sjmcp errno = 0; 7276489Sjmcp if ((rv = read(imgfd, verifier->fwimage, 7286489Sjmcp (size_t)verifier->imgsize)) < verifier->imgsize) { 7296489Sjmcp /* we haven't read enough data, bail */ 7306489Sjmcp logmsg(MSG_ERROR, 7316489Sjmcp gettext("Failed to read sufficient data " 7326489Sjmcp "(got %d bytes, expected %d bytes) from " 7336489Sjmcp "firmware image file %s: %s\n"), 7346489Sjmcp rv, verifier->imgsize, 7356489Sjmcp filename, strerror(errno)); 7366489Sjmcp rv = FWFLASH_FAILURE; 7376489Sjmcp } else { 7386489Sjmcp rv = FWFLASH_SUCCESS; 7396489Sjmcp } 7406489Sjmcp 7416489Sjmcp if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) { 7426489Sjmcp logmsg(MSG_ERROR, 7436489Sjmcp gettext("Unable to save name of firmware image\n")); 7446489Sjmcp rv = FWFLASH_FAILURE; 7456489Sjmcp } else { 7466489Sjmcp (void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1); 7476489Sjmcp } 7486489Sjmcp 7496489Sjmcp if (rv != FWFLASH_SUCCESS) { 7506489Sjmcp /* cleanup and let's get outta here */ 7516489Sjmcp cleanup: 7526489Sjmcp free(verifier->filename); 7536489Sjmcp free(verifier->vendor); 7546489Sjmcp 7556489Sjmcp if (!(fwflash_arg_list & FWFLASH_READ_FLAG)) 7566489Sjmcp free(verifier->fwimage); 7576489Sjmcp 7586489Sjmcp verifier->filename = NULL; 7596489Sjmcp verifier->vendor = NULL; 7606489Sjmcp verifier->vendorvrfy = NULL; 7616489Sjmcp verifier->fwimage = NULL; 7626489Sjmcp (void) dlclose(verifier->handle); 7636489Sjmcp verifier->handle = NULL; 7646489Sjmcp free(verifier); 7656489Sjmcp if (imgfd >= 0) { 7666489Sjmcp (void) close(imgfd); 7676489Sjmcp } 7686489Sjmcp verifier = NULL; 7696489Sjmcp } 7706489Sjmcp 7716489Sjmcp return (rv); 7726489Sjmcp } 7736489Sjmcp 7746489Sjmcp 7756489Sjmcp 7766489Sjmcp /* 7776489Sjmcp * cycles through the global list of plugins to find 7786489Sjmcp * each flashable device, which is added to fw_devices 7796489Sjmcp * 7806489Sjmcp * Each plugin's identify routine must allocated storage 7816489Sjmcp * as required. 7826489Sjmcp * 7836489Sjmcp * Each plugin's identify routine must return 7846489Sjmcp * FWFLASH_FAILURE if it cannot find any devices 7856489Sjmcp * which it handles. 7866489Sjmcp */ 7876489Sjmcp static int 7886489Sjmcp flash_device_list() 7896489Sjmcp { 7906489Sjmcp int rv = FWFLASH_FAILURE; 7916489Sjmcp int startidx = 0; 7926489Sjmcp int sumrv = 0; 7936489Sjmcp struct pluginlist *plugins; 7946489Sjmcp 7956489Sjmcp 7966489Sjmcp /* we open rootnode here, and close it in fwflash_intr */ 7976489Sjmcp if ((rootnode = di_init("/", DINFOCPYALL)) == DI_NODE_NIL) { 7986489Sjmcp logmsg(MSG_ERROR, 7996489Sjmcp gettext("Unable to take device tree snapshot: %s\n"), 8006489Sjmcp strerror(errno)); 8016489Sjmcp return (rv); 8026489Sjmcp } 8036489Sjmcp 8046489Sjmcp if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) { 8056489Sjmcp logmsg(MSG_ERROR, 8066489Sjmcp gettext("Unable to malloc %d bytes while " 8076489Sjmcp "trying to find devices: %s\n"), 8086489Sjmcp sizeof (struct devicelist), strerror(errno)); 8096489Sjmcp return (FWFLASH_FAILURE); 8106489Sjmcp } 8116489Sjmcp 8126489Sjmcp /* CONSTCOND */ 8136489Sjmcp TAILQ_INIT(fw_devices); 8146489Sjmcp 8156489Sjmcp TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) { 8166489Sjmcp self = plugins->plugin; 8176489Sjmcp rv = plugins->plugin->fw_identify(startidx); 8186489Sjmcp 8196489Sjmcp logmsg(MSG_INFO, 8206489Sjmcp gettext("fwflash:flash_device_list() got %d from " 8216489Sjmcp "identify routine\n"), rv); 8226489Sjmcp 8236489Sjmcp /* only bump startidx if we've found at least one device */ 8246489Sjmcp if (rv == FWFLASH_SUCCESS) { 8256489Sjmcp startidx += 100; 8266489Sjmcp sumrv++; 8276489Sjmcp } else { 8286489Sjmcp logmsg(MSG_INFO, 8296489Sjmcp gettext("No flashable devices attached with " 8306489Sjmcp "the %s driver in this system\n"), 8316489Sjmcp plugins->drvname); 8326489Sjmcp } 8336489Sjmcp } 8346489Sjmcp 8356489Sjmcp if (sumrv > 0) 8366489Sjmcp rv = FWFLASH_SUCCESS; 8376489Sjmcp 8386489Sjmcp return (rv); 8396489Sjmcp } 8406489Sjmcp 8416489Sjmcp 8426489Sjmcp 8436489Sjmcp 8446489Sjmcp static int 8456489Sjmcp fwflash_list_fw(char *class) 8466489Sjmcp { 8476489Sjmcp int rv = 0; 8486489Sjmcp struct devicelist *curdev; 8496489Sjmcp int header = 1; 8506489Sjmcp 8516489Sjmcp 8526489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 8536489Sjmcp 8546489Sjmcp /* we're either class-conscious, or we're not */ 8556489Sjmcp if (((class != NULL) && 8566489Sjmcp ((strncmp(curdev->classname, "ALL", 3) == 0) || 8576489Sjmcp (strcmp(curdev->classname, class) == 0))) || 8586489Sjmcp (class == NULL)) { 8596489Sjmcp 8606489Sjmcp if (header != 0) { 8616489Sjmcp (void) fprintf(stdout, 8626489Sjmcp gettext("List of available devices:\n")); 8636489Sjmcp header--; 8646489Sjmcp } 8656489Sjmcp /* 8666489Sjmcp * If any plugin's fw_devinfo() function returns 8676489Sjmcp * FWFLASH_FAILURE then we want to keep track of 8686489Sjmcp * it. _Most_ plugins should always return 8696489Sjmcp * FWFLASH_SUCCESS from this function. The only 8706489Sjmcp * exception known at this point is the tavor plugin. 8716489Sjmcp */ 8726489Sjmcp rv += curdev->plugin->fw_devinfo(curdev); 8736489Sjmcp } 8746489Sjmcp } 8756489Sjmcp 8766489Sjmcp 8776489Sjmcp return (rv); 8786489Sjmcp } 8796489Sjmcp 8806489Sjmcp 8816489Sjmcp static int 8826489Sjmcp fwflash_update(char *device, char *filename, int flags) { 8836489Sjmcp 8846489Sjmcp 8856489Sjmcp int rv = FWFLASH_FAILURE; 8866489Sjmcp int needsfree = 0; 887*6846Sjmcp int found = 0; 8886489Sjmcp struct devicelist *curdev; 8896489Sjmcp char *realfile; 8906489Sjmcp 8916489Sjmcp 8926489Sjmcp /* 8936489Sjmcp * Here's how we operate: 8946489Sjmcp * 8956489Sjmcp * We perform some basic checks on the args, then walk 8966489Sjmcp * through the device list looking for the device which 8976489Sjmcp * matches. We then load the appropriate verifier for the 8986489Sjmcp * image file and device, verify the image, then call the 8996489Sjmcp * fw_writefw() function of the appropriate plugin. 9006489Sjmcp * 9016489Sjmcp * There is no "force" flag to enable you to flash a firmware 9026489Sjmcp * image onto an incompatible device because the verifier 9036489Sjmcp * will return FWFLASH_FAILURE if the image doesn't match. 9046489Sjmcp * 9056489Sjmcp */ 9066489Sjmcp 9076489Sjmcp 9086489Sjmcp /* new firmware filename and device desc */ 9096489Sjmcp if (filename == NULL) { 9106489Sjmcp logmsg(MSG_ERROR, 9116489Sjmcp gettext("Invalid firmware filename (null)\n")); 9126489Sjmcp return (FWFLASH_FAILURE); 9136489Sjmcp } 9146489Sjmcp 9156489Sjmcp if (device == NULL) { 9166489Sjmcp logmsg(MSG_ERROR, 9176489Sjmcp gettext("Invalid device requested (null)\n")); 9186489Sjmcp return (FWFLASH_FAILURE); 9196489Sjmcp } 9206489Sjmcp 9216489Sjmcp if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) { 9226489Sjmcp logmsg(MSG_ERROR, 9236489Sjmcp gettext("Unable to allocate space for device " 924*6846Sjmcp "filename, operation might fail if %s is" 9256489Sjmcp "a symbolic link\n"), 9266489Sjmcp device); 9276489Sjmcp realfile = device; 9286489Sjmcp } else { 9296489Sjmcp /* 9306489Sjmcp * If realpath() succeeds, then we have a valid 9316489Sjmcp * device filename in realfile. 9326489Sjmcp */ 9336489Sjmcp if (realpath(device, realfile) == NULL) { 9346489Sjmcp logmsg(MSG_ERROR, 9356489Sjmcp gettext("Unable to resolve device filename" 9366489Sjmcp ": %s\n"), 9376489Sjmcp strerror(errno)); 9386489Sjmcp /* tidy up */ 9396489Sjmcp free(realfile); 9406489Sjmcp /* realpath didn't succeed, use fallback */ 9416489Sjmcp realfile = device; 9426489Sjmcp } else { 9436489Sjmcp needsfree = 1; 9446489Sjmcp } 9456489Sjmcp } 9466489Sjmcp 9476489Sjmcp logmsg(MSG_INFO, 9486489Sjmcp gettext("fwflash_update: fw_filename (%s) device (%s)\n"), 9496489Sjmcp filename, device); 9506489Sjmcp 9516489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 9526489Sjmcp 9536489Sjmcp if (strcmp(curdev->access_devname, realfile) == 0) { 954*6846Sjmcp found++; 9556489Sjmcp rv = fwflash_load_verifier(curdev->drvname, 9566489Sjmcp curdev->ident->vid, filename); 9576489Sjmcp if (rv == FWFLASH_FAILURE) { 9586489Sjmcp logmsg(MSG_ERROR, 9596489Sjmcp gettext("Unable to load verifier " 9606489Sjmcp "for device %s\n"), 9616489Sjmcp curdev->access_devname); 9626489Sjmcp return (FWFLASH_FAILURE); 9636489Sjmcp } 9646489Sjmcp rv = verifier->vendorvrfy(curdev); 9656489Sjmcp if (rv == FWFLASH_FAILURE) { 9666489Sjmcp /* the verifier prints a message */ 9676489Sjmcp logmsg(MSG_INFO, 9686489Sjmcp "verifier (%s) for %s :: %s returned " 9696489Sjmcp "FWFLASH_FAILURE\n", 9706489Sjmcp verifier->filename, 9716489Sjmcp filename, curdev->access_devname); 9726489Sjmcp return (rv); 9736489Sjmcp } 9746489Sjmcp 9756489Sjmcp if ((flags == FWFLASH_YES_FLAG) || 9766489Sjmcp (rv = confirm_target(curdev, filename)) == 9776489Sjmcp FWFLASH_YES_FLAG) { 9786489Sjmcp logmsg(MSG_INFO, 9796489Sjmcp "about to flash using plugin %s\n", 9806489Sjmcp curdev->plugin->filename); 9816489Sjmcp rv = curdev->plugin->fw_writefw(curdev, 9826489Sjmcp filename); 9836489Sjmcp if (rv == FWFLASH_FAILURE) { 9846489Sjmcp logmsg(MSG_ERROR, 9856489Sjmcp gettext("Failed to flash " 9866489Sjmcp "firmware file %s on " 9876489Sjmcp "device %s: %d\n"), 9886489Sjmcp filename, 9896489Sjmcp curdev->access_devname, rv); 9906489Sjmcp } 9916489Sjmcp } else { 9926489Sjmcp logmsg(MSG_ERROR, 9936489Sjmcp gettext("Flash operation not confirmed " 9946489Sjmcp "by user\n"), 9956489Sjmcp curdev->access_devname); 9966489Sjmcp rv = FWFLASH_FAILURE; 9976489Sjmcp } 9986489Sjmcp } 9996489Sjmcp } 10006489Sjmcp 1001*6846Sjmcp if (!found) 1002*6846Sjmcp /* report the same device that the user passed in */ 1003*6846Sjmcp logmsg(MSG_ERROR, 1004*6846Sjmcp gettext("Device %s does not appear " 1005*6846Sjmcp "to be flashable\n"), 1006*6846Sjmcp ((strncmp(device, realfile, strlen(device)) == 0) ? 1007*6846Sjmcp device : realfile)); 1008*6846Sjmcp 10096489Sjmcp if (needsfree) 10106489Sjmcp free(realfile); 10116489Sjmcp 10126489Sjmcp return (rv); 10136489Sjmcp } 10146489Sjmcp 10156489Sjmcp /* 10166489Sjmcp * We validate that the device path is in our global device list and 10176489Sjmcp * that the filename exists, then palm things off to the relevant plugin. 10186489Sjmcp */ 10196489Sjmcp 10206489Sjmcp static int 10216489Sjmcp fwflash_read_file(char *device, char *filename) 10226489Sjmcp { 10236489Sjmcp struct devicelist *curdev; 10246489Sjmcp int rv; 10256489Sjmcp int notfound = 0; 10266489Sjmcp 10276489Sjmcp /* new firmware filename and device desc */ 10286489Sjmcp 10296489Sjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) { 10306489Sjmcp if (strncmp(curdev->access_devname, device, 10316489Sjmcp MAXPATHLEN) == 0) { 10326489Sjmcp rv = curdev->plugin->fw_readfw(curdev, filename); 10336489Sjmcp 10346489Sjmcp if (rv != FWFLASH_SUCCESS) 10356489Sjmcp logmsg(MSG_ERROR, 10366489Sjmcp gettext("Unable to write out firmware " 10376489Sjmcp "image for %s to file %s\n"), 10386489Sjmcp curdev->access_devname, filename); 10396489Sjmcp } else { 10406489Sjmcp notfound++; 10416489Sjmcp } 10426489Sjmcp 10436489Sjmcp } 10446489Sjmcp if (notfound) { 10456489Sjmcp logmsg(MSG_ERROR, 10466489Sjmcp gettext("No device matching %s was found.\n"), 10476489Sjmcp device); 10486489Sjmcp rv = FWFLASH_FAILURE; 10496489Sjmcp } 10506489Sjmcp 10516489Sjmcp return (rv); 10526489Sjmcp } 10536489Sjmcp 10546489Sjmcp static void 10556489Sjmcp fwflash_usage(char *arg) 10566489Sjmcp { 10576489Sjmcp 10586489Sjmcp (void) fprintf(stderr, "\n"); 10596489Sjmcp if (arg != NULL) { 10606489Sjmcp logmsg(MSG_ERROR, 10616489Sjmcp gettext("Invalid argument (%s) supplied\n"), arg); 10626489Sjmcp } 10636489Sjmcp 10646489Sjmcp (void) fprintf(stderr, "\n"); 10656489Sjmcp 10666489Sjmcp (void) fprintf(stdout, gettext("Usage:\n\t")); 10676489Sjmcp (void) fprintf(stdout, gettext("fwflash [-l [-c device_class " 10686489Sjmcp "| ALL]] | [-v] | [-h]\n\t")); 10696489Sjmcp (void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3" 10706489Sjmcp ",... | -r file] [-y] -d device_path\n\n")); 10716489Sjmcp (void) fprintf(stdout, "\n"); /* workaround for xgettext */ 10726489Sjmcp 10736489Sjmcp (void) fprintf(stdout, 10746489Sjmcp gettext("\t-l\t\tlist flashable devices in this system\n" 10756489Sjmcp "\t-c device_class limit search to a specific class\n" 10766489Sjmcp "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n" 10776489Sjmcp "\t-v\t\tprint version number of fwflash utility\n" 10786489Sjmcp "\t-h\t\tprint this usage mesage\n\n")); 10796489Sjmcp (void) fprintf(stdout, 10806489Sjmcp gettext("\t-f file1,file2,file3,...\n" 10816489Sjmcp "\t\t\tfirmware image file list to flash\n" 10826489Sjmcp "\t-r file\t\tfile to dump device firmware to\n" 10836489Sjmcp "\t-y\t\tanswer Yes/Y/y to prompts\n" 10846489Sjmcp "\t-d device_path\tpathname of device to be flashed\n\n")); 10856489Sjmcp 10866489Sjmcp (void) fprintf(stdout, 10876489Sjmcp gettext("\tIf -d device_path is specified, then one of -f " 10886489Sjmcp "<files>\n" 10896489Sjmcp "\tor -r <file> must also be specified\n\n")); 10906489Sjmcp 10916489Sjmcp (void) fprintf(stdout, 10926489Sjmcp gettext("\tIf multiple firmware images are required to be " 10936489Sjmcp "flashed\n" 10946489Sjmcp "\tthey must be listed together, separated by commas. The\n" 10956489Sjmcp "\timages will be flashed in the order specified.\n\n")); 10966489Sjmcp 10976489Sjmcp 10986489Sjmcp (void) fprintf(stdout, "\n"); 10996489Sjmcp } 11006489Sjmcp 11016489Sjmcp 11026489Sjmcp 11036489Sjmcp 11046489Sjmcp 11056489Sjmcp 11066489Sjmcp 11076489Sjmcp static void 11086489Sjmcp fwflash_version(void) 11096489Sjmcp { 11106489Sjmcp (void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME); 11116489Sjmcp (void) fprintf(stdout, gettext("version %s\n"), 11126489Sjmcp FWFLASH_VERSION); 11136489Sjmcp 11146489Sjmcp 11156489Sjmcp } 11166489Sjmcp 11176489Sjmcp static void 11186489Sjmcp fwflash_help(void) 11196489Sjmcp { 11206489Sjmcp fwflash_usage(NULL); 11216489Sjmcp } 11226489Sjmcp 11236489Sjmcp /* ARGSUSED */ 11246489Sjmcp static void 11256489Sjmcp fwflash_intr(int sig) 11266489Sjmcp { 11276489Sjmcp 11286489Sjmcp struct devicelist *thisdev; 11296489Sjmcp struct pluginlist *thisplug; 11306489Sjmcp 11316489Sjmcp 11326489Sjmcp (void) signal(SIGINT, SIG_IGN); 11336489Sjmcp (void) signal(SIGTERM, SIG_IGN); 1134*6846Sjmcp (void) signal(SIGABRT, SIG_IGN); 11356489Sjmcp if (fwflash_in_write) { 11366489Sjmcp (void) fprintf(stderr, 11376489Sjmcp gettext("WARNING: firmware image may be corrupted\n\t")); 11386489Sjmcp (void) fprintf(stderr, 11396489Sjmcp gettext("Reflash firmware before rebooting!\n")); 11406489Sjmcp } 11416489Sjmcp 11426489Sjmcp if (sig > 0) { 11436489Sjmcp (void) logmsg(MSG_ERROR, gettext("\n")); 11446489Sjmcp (void) logmsg(MSG_ERROR, 11456489Sjmcp gettext("fwflash exiting due to signal (%d)\n"), sig); 11466489Sjmcp } 11476489Sjmcp 11486489Sjmcp /* 11496489Sjmcp * we need to close everything down properly, so 11506489Sjmcp * call the plugin closure routines 11516489Sjmcp */ 11526489Sjmcp 11536489Sjmcp if (fw_devices != NULL) { 11546489Sjmcp 11556489Sjmcp TAILQ_FOREACH(thisdev, fw_devices, nextdev) { 11566489Sjmcp /* free the components first */ 11576489Sjmcp free(thisdev->access_devname); 11586489Sjmcp free(thisdev->drvname); 11596489Sjmcp free(thisdev->classname); 1160*6846Sjmcp if (thisdev->ident != NULL) 11616489Sjmcp free(thisdev->ident); 1162*6846Sjmcp 11636489Sjmcp thisdev->ident = NULL; 11646489Sjmcp thisdev->plugin = NULL; /* we free this elsewhere */ 11656489Sjmcp /* CONSTCOND */ 11666489Sjmcp TAILQ_REMOVE(fw_devices, thisdev, nextdev); 11676489Sjmcp } 11686489Sjmcp } 11696489Sjmcp 11706489Sjmcp 11716489Sjmcp if (fw_pluginlist != NULL) { 11726489Sjmcp 11736489Sjmcp TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) { 11746489Sjmcp free(thisplug->filename); 11756489Sjmcp free(thisplug->drvname); 11766489Sjmcp free(thisplug->plugin->filename); 11776489Sjmcp free(thisplug->plugin->drvname); 11786489Sjmcp thisplug->filename = NULL; 11796489Sjmcp thisplug->drvname = NULL; 11806489Sjmcp thisplug->plugin->filename = NULL; 11816489Sjmcp thisplug->plugin->drvname = NULL; 11826489Sjmcp thisplug->plugin->fw_readfw = NULL; 11836489Sjmcp thisplug->plugin->fw_writefw = NULL; 11846489Sjmcp thisplug->plugin->fw_identify = NULL; 11856489Sjmcp thisplug->plugin->fw_devinfo = NULL; 11866489Sjmcp (void) dlclose(thisplug->plugin->handle); 11876489Sjmcp thisplug->plugin->handle = NULL; 11886489Sjmcp free(thisplug->plugin); 11896489Sjmcp thisplug->plugin = NULL; 11906489Sjmcp /* CONSTCOND */ 11916489Sjmcp TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin); 11926489Sjmcp 11936489Sjmcp } 11946489Sjmcp } 11956489Sjmcp 11966489Sjmcp 11976489Sjmcp if (verifier != NULL) { 11986489Sjmcp free(verifier->filename); 11996489Sjmcp free(verifier->vendor); 1200*6846Sjmcp free(verifier->imgfile); 1201*6846Sjmcp free(verifier->fwimage); 12026489Sjmcp verifier->filename = NULL; 12036489Sjmcp verifier->vendor = NULL; 12046489Sjmcp verifier->vendorvrfy = NULL; 1205*6846Sjmcp verifier->imgfile = NULL; 1206*6846Sjmcp verifier->fwimage = NULL; 12076489Sjmcp (void) dlclose(verifier->handle); 12086489Sjmcp verifier->handle = NULL; 12096489Sjmcp free(verifier); 12106489Sjmcp } 12116489Sjmcp 12126489Sjmcp di_fini(rootnode); 12136489Sjmcp } 12146489Sjmcp 12156489Sjmcp static void 12166489Sjmcp fwflash_handle_signals(void) 12176489Sjmcp { 12186489Sjmcp if (signal(SIGINT, fwflash_intr) == SIG_ERR) { 12196489Sjmcp perror("signal"); 12206489Sjmcp exit(FWFLASH_FAILURE); 12216489Sjmcp } 12226489Sjmcp 12236489Sjmcp if (signal(SIGTERM, fwflash_intr) == SIG_ERR) { 12246489Sjmcp perror("signal"); 12256489Sjmcp exit(FWFLASH_FAILURE); 12266489Sjmcp } 12276489Sjmcp } 12286489Sjmcp 12296489Sjmcp static int 12306489Sjmcp confirm_target(struct devicelist *thisdev, char *file) 12316489Sjmcp { 12326489Sjmcp int resp; 12336489Sjmcp 1234*6846Sjmcp (void) fflush(stdin); 1235*6846Sjmcp 1236*6846Sjmcp (void) printf(gettext("About to update firmware on %s\n"), 1237*6846Sjmcp thisdev->access_devname); 1238*6846Sjmcp (void) printf(gettext("with file %s. Do you want to continue? " 1239*6846Sjmcp "(Y/N): "), file); 12406489Sjmcp 12416489Sjmcp resp = getchar(); 12426489Sjmcp if (resp == 'Y' || resp == 'y') { 12436489Sjmcp return (FWFLASH_YES_FLAG); 12446489Sjmcp } else { 12456489Sjmcp logmsg(MSG_INFO, "flash operation NOT confirmed.\n"); 12466489Sjmcp } 12476489Sjmcp 12486489Sjmcp (void) fflush(stdin); 12496489Sjmcp 12506489Sjmcp return (FWFLASH_FAILURE); 12516489Sjmcp } 12526489Sjmcp 12536489Sjmcp int 12546489Sjmcp get_fileopts(char *options) 12556489Sjmcp { 12566489Sjmcp 12576489Sjmcp int i; 12586489Sjmcp char *files; 12596489Sjmcp 12606489Sjmcp 12616489Sjmcp if (files = strtok(options, ",")) { 12626489Sjmcp /* we have more than one */ 12636489Sjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 12646489Sjmcp logmsg(MSG_ERROR, 12656489Sjmcp gettext("Unable to allocate space for " 12666489Sjmcp "a firmware image filename\n")); 12676489Sjmcp return (FWFLASH_FAILURE); 12686489Sjmcp } 12696489Sjmcp (void) strlcpy(filelist[0], files, strlen(files) + 1); 12706489Sjmcp i = 1; 12716489Sjmcp 12726489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 12736489Sjmcp filelist[0]); 12746489Sjmcp 12756489Sjmcp 12766489Sjmcp while (files = strtok(NULL, ",")) { 12776489Sjmcp if ((filelist[i] = calloc(1, MAXPATHLEN + 1)) 12786489Sjmcp == NULL) { 12796489Sjmcp logmsg(MSG_ERROR, 12806489Sjmcp gettext("Unable to allocate space for " 12816489Sjmcp "a firmware image filename\n")); 12826489Sjmcp return (FWFLASH_FAILURE); 12836489Sjmcp } 12846489Sjmcp (void) strlcpy(filelist[i], files, 12856489Sjmcp strlen(files) + 1); 12866489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n", 12876489Sjmcp i, filelist[i]); 12886489Sjmcp ++i; 12896489Sjmcp } 12906489Sjmcp } else { 12916489Sjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) { 12926489Sjmcp logmsg(MSG_ERROR, 12936489Sjmcp gettext("Unable to allocate space for " 12946489Sjmcp "a firmware image filename\n")); 12956489Sjmcp return (FWFLASH_FAILURE); 12966489Sjmcp } 12976489Sjmcp (void) strlcpy(filelist[0], options, strlen(files) + 1); 12986489Sjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n", 12996489Sjmcp filelist[0]); 13006489Sjmcp } 13016489Sjmcp return (FWFLASH_SUCCESS); 13026489Sjmcp 13036489Sjmcp } 13046489Sjmcp 13056489Sjmcp 13066489Sjmcp 13076489Sjmcp /* 13086489Sjmcp * code reuse - cheerfully borrowed from stmsboot_util.c 13096489Sjmcp */ 13106489Sjmcp void 13116489Sjmcp logmsg(int severity, char *msg, ...) { 13126489Sjmcp 13136489Sjmcp va_list ap; 13146489Sjmcp 13156489Sjmcp 13166489Sjmcp if ((severity > MSG_INFO) || 13176489Sjmcp ((severity == MSG_INFO) && (fwflash_debug > 0))) { 13186489Sjmcp 13196489Sjmcp (void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME); 13206489Sjmcp va_start(ap, msg); 13216489Sjmcp /* LINTED - format specifier */ 13226489Sjmcp (void) vfprintf(stderr, msg, ap); 13236489Sjmcp va_end(ap); 13246489Sjmcp } 13256489Sjmcp } 1326