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 /*
22*41f7470aSXin Chen - Sun Microsystems - Beijing China * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235a7763bfSjmcp */
245a7763bfSjmcp
255a7763bfSjmcp /*
265a7763bfSjmcp * fwflash.c
275a7763bfSjmcp */
285a7763bfSjmcp #include <stdio.h>
295a7763bfSjmcp #include <stdlib.h>
305a7763bfSjmcp #include <unistd.h>
315a7763bfSjmcp #include <strings.h>
325a7763bfSjmcp #include <errno.h>
335a7763bfSjmcp #include <sys/queue.h>
345a7763bfSjmcp #include <signal.h>
355a7763bfSjmcp #include <locale.h>
365a7763bfSjmcp #include <sys/stat.h>
375a7763bfSjmcp #include <sys/types.h>
385a7763bfSjmcp #include <sys/param.h>
395a7763bfSjmcp #include <fcntl.h>
405a7763bfSjmcp #include <dlfcn.h>
415a7763bfSjmcp #include <dirent.h>
425a7763bfSjmcp #include <sys/varargs.h>
435a7763bfSjmcp #include <libintl.h> /* for gettext(3c) */
445a7763bfSjmcp #include <libdevinfo.h>
454196e263SSherry Moore #include <libscf_priv.h>
465a7763bfSjmcp #include <fwflash/fwflash.h>
47c4800545Sjmcp #include <sys/modctl.h> /* for MAXMODCONFNAME */
485a7763bfSjmcp
495a7763bfSjmcp /* global arg list */
505a7763bfSjmcp int fwflash_arg_list = 0;
515a7763bfSjmcp char *filelist[10];
525a7763bfSjmcp
53a799b1e7Speihong huang /* exposed global args */
54a799b1e7Speihong huang di_node_t rootnode;
55a799b1e7Speihong huang struct PLUGINLIST *fw_pluginlist;
56a799b1e7Speihong huang struct DEVICELIST *fw_devices;
57a799b1e7Speihong huang struct vrfyplugin *verifier;
58a799b1e7Speihong huang struct fw_plugin *self;
59a799b1e7Speihong huang int fwflash_debug = 0;
60a799b1e7Speihong huang
615a7763bfSjmcp /* are we writing to flash? */
625a7763bfSjmcp static int fwflash_in_write = 0;
635a7763bfSjmcp
645a7763bfSjmcp /*
655a7763bfSjmcp * If we *must* track the version string for fwflash, then
665a7763bfSjmcp * we should do so in this common file rather than the header
675a7763bfSjmcp * file since it will then be in sync with what the customer
68f1c23465SJames C. McPherson * sees. We should deprecate the "-v" option since it is not
69f1c23465SJames C. McPherson * actually of any use - it doesn't line up with Mercurial's
70f1c23465SJames C. McPherson * concept of the changeset.
715a7763bfSjmcp */
720bc9814fSXinChen #define FWFLASH_VERSION "v1.9"
735a7763bfSjmcp #define FWFLASH_PROG_NAME "fwflash"
745a7763bfSjmcp
755a7763bfSjmcp static int get_fileopts(char *options);
765a7763bfSjmcp static int flash_device_list();
775a7763bfSjmcp static int flash_load_plugins();
785a7763bfSjmcp static int fwflash_update(char *device, char *filename, int flags);
795a7763bfSjmcp static int fwflash_read_file(char *device, char *filename);
805a7763bfSjmcp static int fwflash_list_fw(char *class);
815a7763bfSjmcp static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg);
825a7763bfSjmcp static void fwflash_intr(int sig);
835a7763bfSjmcp static void fwflash_handle_signals(void);
84f1c23465SJames C. McPherson static void fwflash_usage(char *arg);
855a7763bfSjmcp static void fwflash_version(void);
865a7763bfSjmcp static int confirm_target(struct devicelist *thisdev, char *file);
875a7763bfSjmcp
885a7763bfSjmcp /*
895a7763bfSjmcp * FWFlash main code
905a7763bfSjmcp */
915a7763bfSjmcp int
main(int argc,char ** argv)92f8bf33c3SShantkumar Hiremath main(int argc, char **argv)
93f8bf33c3SShantkumar Hiremath {
945a7763bfSjmcp int rv = FWFLASH_SUCCESS;
955a7763bfSjmcp int i;
965a7763bfSjmcp char ch;
975a7763bfSjmcp char *read_file;
985a7763bfSjmcp extern char *optarg;
995a7763bfSjmcp char *devclass = NULL;
1005a7763bfSjmcp char *devpath = NULL;
1015a7763bfSjmcp
1025a7763bfSjmcp /* local variables from env */
1035a7763bfSjmcp (void) setlocale(LC_ALL, "");
1045a7763bfSjmcp
1055a7763bfSjmcp #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
1065a7763bfSjmcp #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */
1075a7763bfSjmcp #endif
1085a7763bfSjmcp
1095a7763bfSjmcp (void) textdomain(TEXT_DOMAIN);
1105a7763bfSjmcp
1115a7763bfSjmcp read_file = NULL;
1125a7763bfSjmcp
1135a7763bfSjmcp if (argc < 2) {
1145a7763bfSjmcp /* no args supplied */
1155a7763bfSjmcp fwflash_usage(NULL);
1165a7763bfSjmcp return (FWFLASH_FAILURE);
1175a7763bfSjmcp }
1185a7763bfSjmcp
11987d06e46Speihong huang while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:")) != EOF) {
1205a7763bfSjmcp switch (ch) {
1215a7763bfSjmcp case 'h':
1225a7763bfSjmcp fwflash_arg_list |= FWFLASH_HELP_FLAG;
1235a7763bfSjmcp break;
1245a7763bfSjmcp case 'v':
1255a7763bfSjmcp fwflash_arg_list |= FWFLASH_VER_FLAG;
1265a7763bfSjmcp break;
1275a7763bfSjmcp case 'y':
1285a7763bfSjmcp fwflash_arg_list |= FWFLASH_YES_FLAG;
1295a7763bfSjmcp break;
1305a7763bfSjmcp case 'l':
1315a7763bfSjmcp fwflash_arg_list |= FWFLASH_LIST_FLAG;
1325a7763bfSjmcp break;
1335a7763bfSjmcp case 'c':
1345a7763bfSjmcp fwflash_arg_list |= FWFLASH_CLASS_FLAG;
1355a7763bfSjmcp /* we validate later */
1365a7763bfSjmcp devclass = strdup(optarg);
1375a7763bfSjmcp break;
1385a7763bfSjmcp case 'd':
1395a7763bfSjmcp fwflash_arg_list |= FWFLASH_DEVICE_FLAG;
1405a7763bfSjmcp devpath = strdup(optarg);
1415a7763bfSjmcp break;
1425a7763bfSjmcp case 'f':
1435a7763bfSjmcp fwflash_arg_list |= FWFLASH_FW_FLAG;
1445a7763bfSjmcp if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) {
145f1c23465SJames C. McPherson fwflash_usage(NULL);
1465a7763bfSjmcp return (FWFLASH_FAILURE);
1475a7763bfSjmcp }
1485a7763bfSjmcp break;
1495a7763bfSjmcp case 'r':
1505a7763bfSjmcp fwflash_arg_list |= FWFLASH_READ_FLAG;
1515a7763bfSjmcp read_file = strdup(optarg);
1525a7763bfSjmcp break;
1535a7763bfSjmcp case 'Q':
1545a7763bfSjmcp /* NOT in the manpage */
1555a7763bfSjmcp fwflash_debug = 1;
1565a7763bfSjmcp break;
1575a7763bfSjmcp /* illegal options */
1585a7763bfSjmcp default:
1595a7763bfSjmcp fwflash_usage(optarg);
1605a7763bfSjmcp return (FWFLASH_FAILURE);
1615a7763bfSjmcp }
1625a7763bfSjmcp }
1635a7763bfSjmcp
1645a7763bfSjmcp /* Do Help */
1655a7763bfSjmcp if ((fwflash_arg_list & FWFLASH_HELP_FLAG) ||
1665a7763bfSjmcp ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) &&
1675a7763bfSjmcp !((fwflash_arg_list & FWFLASH_FW_FLAG) ||
1685a7763bfSjmcp (fwflash_arg_list & FWFLASH_READ_FLAG)))) {
169f1c23465SJames C. McPherson fwflash_usage(NULL);
1705a7763bfSjmcp return (FWFLASH_SUCCESS);
1715a7763bfSjmcp }
1725a7763bfSjmcp
1735a7763bfSjmcp /* Do Version */
1745a7763bfSjmcp if (fwflash_arg_list == FWFLASH_VER_FLAG) {
1755a7763bfSjmcp fwflash_version();
1765a7763bfSjmcp return (FWFLASH_SUCCESS);
1775a7763bfSjmcp }
1785a7763bfSjmcp
1795a7763bfSjmcp /* generate global list of devices */
1805a7763bfSjmcp if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) {
1815a7763bfSjmcp logmsg(MSG_ERROR,
1825a7763bfSjmcp gettext("Unable to load fwflash plugins\n"));
1835a7763bfSjmcp fwflash_intr(0);
1845a7763bfSjmcp return (rv);
1855a7763bfSjmcp }
1865a7763bfSjmcp
1875a7763bfSjmcp if ((rv = flash_device_list()) != FWFLASH_SUCCESS) {
1885a7763bfSjmcp logmsg(MSG_ERROR,
1895a7763bfSjmcp gettext("No flashable devices in this system\n"));
1905a7763bfSjmcp fwflash_intr(0);
1915a7763bfSjmcp return (rv);
1925a7763bfSjmcp }
1935a7763bfSjmcp
1945a7763bfSjmcp /* Do list */
1955a7763bfSjmcp if (fwflash_arg_list == (FWFLASH_LIST_FLAG) ||
1965a7763bfSjmcp fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) {
1975a7763bfSjmcp rv = fwflash_list_fw(devclass);
1985a7763bfSjmcp fwflash_intr(0);
1995a7763bfSjmcp return (rv);
2005a7763bfSjmcp }
2015a7763bfSjmcp
2025a7763bfSjmcp fwflash_handle_signals();
2035a7763bfSjmcp
2045a7763bfSjmcp /* Do flash update (write) */
2055a7763bfSjmcp if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) ||
2065a7763bfSjmcp (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG |
2075a7763bfSjmcp FWFLASH_YES_FLAG))) {
2084196e263SSherry Moore int fastreboot_disabled = 0;
2095a7763bfSjmcp /* the update function handles the real arg parsing */
2105a7763bfSjmcp i = 0;
2115a7763bfSjmcp while (filelist[i] != NULL) {
2125a7763bfSjmcp if ((rv = fwflash_update(devpath, filelist[i],
2135a7763bfSjmcp fwflash_arg_list)) == FWFLASH_SUCCESS) {
2145a7763bfSjmcp /* failed ops have already been noted */
2154196e263SSherry Moore if (!fastreboot_disabled &&
2164196e263SSherry Moore scf_fastreboot_default_set_transient(
2174196e263SSherry Moore B_FALSE) != SCF_SUCCESS)
2184196e263SSherry Moore logmsg(MSG_ERROR, gettext(
2194196e263SSherry Moore "Failed to disable fast "
2204196e263SSherry Moore "reboot.\n"));
2214196e263SSherry Moore else
2224196e263SSherry Moore fastreboot_disabled = 1;
2235a7763bfSjmcp logmsg(MSG_ERROR,
2245a7763bfSjmcp gettext("New firmware will be activated "
2255a7763bfSjmcp "after you reboot\n\n"));
2265a7763bfSjmcp }
2275a7763bfSjmcp ++i;
2285a7763bfSjmcp }
2295a7763bfSjmcp
2305a7763bfSjmcp fwflash_intr(0);
2315a7763bfSjmcp return (rv);
2325a7763bfSjmcp }
2335a7763bfSjmcp
2345a7763bfSjmcp /* Do flash read */
2355a7763bfSjmcp if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) ||
2365a7763bfSjmcp (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG |
2375a7763bfSjmcp FWFLASH_YES_FLAG))) {
2385a7763bfSjmcp rv = fwflash_read_file(devpath, read_file);
2395a7763bfSjmcp fwflash_intr(0);
2405a7763bfSjmcp return (rv);
2415a7763bfSjmcp }
2425a7763bfSjmcp
2435a7763bfSjmcp fwflash_usage(NULL);
2445a7763bfSjmcp
2455a7763bfSjmcp return (FWFLASH_FAILURE);
2465a7763bfSjmcp }
2475a7763bfSjmcp
2485a7763bfSjmcp
2495a7763bfSjmcp static int
flash_load_plugins()250f8bf33c3SShantkumar Hiremath flash_load_plugins()
251f8bf33c3SShantkumar Hiremath {
2525a7763bfSjmcp
2535a7763bfSjmcp int rval = FWFLASH_SUCCESS;
2545a7763bfSjmcp DIR *dirp;
2555a7763bfSjmcp struct dirent *plugdir;
2565a7763bfSjmcp char *plugname;
2575a7763bfSjmcp struct fw_plugin *tmpplug;
2585a7763bfSjmcp struct pluginlist *tmpelem;
2595a7763bfSjmcp void *sym;
2605a7763bfSjmcp char *fwplugdirpath, *tempdirpath;
2615a7763bfSjmcp
2625a7763bfSjmcp
2635a7763bfSjmcp #define CLOSEFREE() { \
2645a7763bfSjmcp (void) dlclose(tmpplug->handle); \
2655a7763bfSjmcp free(tmpplug); }
2665a7763bfSjmcp
2675a7763bfSjmcp /*
2685a7763bfSjmcp * Procedure:
2695a7763bfSjmcp *
2705a7763bfSjmcp * cd /usr/lib/fwflash/identify
2715a7763bfSjmcp * open each .so file found therein
2725a7763bfSjmcp * dlopen(.sofile)
2735a7763bfSjmcp * if it's one of our plugins, add it to fw_pluginlist;
2745a7763bfSjmcp *
2755a7763bfSjmcp * functions we need here include dlopen and dlsym.
2765a7763bfSjmcp *
2775a7763bfSjmcp * If we get to the end and fw_pluginlist struct is empty,
2785a7763bfSjmcp * return FWFLASH_FAILURE so we return to the shell.
2795a7763bfSjmcp */
2805a7763bfSjmcp
2815a7763bfSjmcp if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
2825a7763bfSjmcp logmsg(MSG_ERROR,
2835a7763bfSjmcp gettext("Unable to malloc %d bytes while "
2845a7763bfSjmcp "trying to load plugins: %s\n"),
2855a7763bfSjmcp MAXPATHLEN + 1, strerror(errno));
2865a7763bfSjmcp return (FWFLASH_FAILURE);
2875a7763bfSjmcp }
2885a7763bfSjmcp
2895a7763bfSjmcp tempdirpath = getenv("FWPLUGINDIR");
2905a7763bfSjmcp
2915a7763bfSjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
2925a7763bfSjmcp (void) strlcpy(fwplugdirpath, tempdirpath,
2935a7763bfSjmcp strlen(tempdirpath) + 1);
2945a7763bfSjmcp } else {
2955a7763bfSjmcp (void) strlcpy(fwplugdirpath, FWPLUGINDIR,
2965a7763bfSjmcp strlen(FWPLUGINDIR) + 1);
2975a7763bfSjmcp }
2985a7763bfSjmcp
2995a7763bfSjmcp if ((dirp = opendir(fwplugdirpath)) == NULL) {
3005a7763bfSjmcp logmsg(MSG_ERROR,
301c4800545Sjmcp gettext("Unable to open %s\n"),
3025a7763bfSjmcp fwplugdirpath);
3035a7763bfSjmcp return (errno);
3045a7763bfSjmcp }
3055a7763bfSjmcp
3065a7763bfSjmcp if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1))
3075a7763bfSjmcp == NULL) {
3085a7763bfSjmcp logmsg(MSG_ERROR,
3095a7763bfSjmcp gettext("Unable to malloc %d bytes while "
3105a7763bfSjmcp "trying to load plugins: %s\n"),
3115a7763bfSjmcp MAXPATHLEN + 1 + sizeof (struct dirent),
3125a7763bfSjmcp strerror(errno));
3135a7763bfSjmcp return (FWFLASH_FAILURE);
3145a7763bfSjmcp }
3155a7763bfSjmcp
3165a7763bfSjmcp if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin)))
3175a7763bfSjmcp == NULL) {
3185a7763bfSjmcp logmsg(MSG_ERROR,
3195a7763bfSjmcp gettext("Unable to malloc %d bytes while "
3205a7763bfSjmcp "trying to load plugins: %s\n"),
321d65b419eSXinChen sizeof (struct fw_plugin), strerror(errno));
3225a7763bfSjmcp return (FWFLASH_FAILURE);
3235a7763bfSjmcp }
3245a7763bfSjmcp
3255a7763bfSjmcp TAILQ_INIT(fw_pluginlist);
3265a7763bfSjmcp
3275a7763bfSjmcp while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) {
3285a7763bfSjmcp
3295a7763bfSjmcp errno = 0; /* remove chance of false results */
3305a7763bfSjmcp
3315a7763bfSjmcp if ((plugdir->d_name[0] == '.') ||
3325a7763bfSjmcp (strstr(plugdir->d_name, ".so") == NULL)) {
3335a7763bfSjmcp continue;
3345a7763bfSjmcp }
3355a7763bfSjmcp
3365a7763bfSjmcp if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) {
3375a7763bfSjmcp logmsg(MSG_ERROR,
3385a7763bfSjmcp gettext("Unable to malloc %d bytes while "
3395a7763bfSjmcp "trying to load plugins: %s\n"),
3405a7763bfSjmcp MAXPATHLEN + 1, strerror(errno));
3415a7763bfSjmcp return (FWFLASH_FAILURE);
3425a7763bfSjmcp }
3435a7763bfSjmcp
3445a7763bfSjmcp (void) snprintf(plugname, MAXPATHLEN, "%s/%s",
3455a7763bfSjmcp fwplugdirpath, plugdir->d_name);
3465a7763bfSjmcp
3475a7763bfSjmcp /* start allocating storage */
3485a7763bfSjmcp if ((tmpelem = calloc(1, sizeof (struct pluginlist)))
3495a7763bfSjmcp == NULL) {
3505a7763bfSjmcp logmsg(MSG_ERROR,
3515a7763bfSjmcp gettext("Unable to malloc %d bytes while "
3525a7763bfSjmcp "trying to load plugins: %s\n"),
3535a7763bfSjmcp sizeof (struct pluginlist), strerror(errno));
3545a7763bfSjmcp return (FWFLASH_FAILURE);
3555a7763bfSjmcp }
3565a7763bfSjmcp
3575a7763bfSjmcp if ((tmpplug = calloc(1, sizeof (struct fw_plugin)))
3585a7763bfSjmcp == NULL) {
3595a7763bfSjmcp logmsg(MSG_ERROR,
3605a7763bfSjmcp gettext("Unable to malloc %d bytes while "
3615a7763bfSjmcp "trying to load plugins: %s\n"),
3625a7763bfSjmcp sizeof (struct fw_plugin), strerror(errno));
3635a7763bfSjmcp return (FWFLASH_FAILURE);
3645a7763bfSjmcp }
3655a7763bfSjmcp
3665a7763bfSjmcp /* load 'er up! */
3675a7763bfSjmcp tmpplug->handle = dlopen(plugname, RTLD_NOW);
3685a7763bfSjmcp if (tmpplug->handle == NULL) {
3695a7763bfSjmcp free(tmpplug);
3705a7763bfSjmcp continue; /* assume there are other plugins */
3715a7763bfSjmcp }
3725a7763bfSjmcp
3735a7763bfSjmcp if ((tmpplug->filename = calloc(1, strlen(plugname) + 1))
3745a7763bfSjmcp == NULL) {
3755a7763bfSjmcp logmsg(MSG_ERROR,
3765a7763bfSjmcp gettext("Unable to allocate %d bytes for plugin "
3775a7763bfSjmcp "filename %s:%s\n"),
3785a7763bfSjmcp strlen(plugname) + 1, plugname,
3795a7763bfSjmcp strerror(errno));
3805a7763bfSjmcp return (rval);
3815a7763bfSjmcp }
3825a7763bfSjmcp
3835a7763bfSjmcp (void) strlcpy(tmpplug->filename, plugname,
3845a7763bfSjmcp strlen(plugname) + 1);
3855a7763bfSjmcp
3865a7763bfSjmcp /* now sanity check the file */
3875a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "drivername"))
3885a7763bfSjmcp != NULL) {
3895a7763bfSjmcp /* max length of drivername */
390c4800545Sjmcp tmpplug->drvname = calloc(1, MAXMODCONFNAME);
391c4800545Sjmcp
392c4800545Sjmcp /* are we doing double-time? */
393c4800545Sjmcp if (strncmp((char *)sym, plugdir->d_name,
394c4800545Sjmcp MAXMODCONFNAME) != 0) {
395c4800545Sjmcp char *tempnm = calloc(1, MAXMODCONFNAME);
396c4800545Sjmcp
397d65b419eSXinChen (void) memcpy(tempnm, plugdir->d_name,
398d65b419eSXinChen MAXMODCONFNAME);
399c4800545Sjmcp (void) strlcpy(tmpplug->drvname,
400c4800545Sjmcp strtok(tempnm, "."),
401c4800545Sjmcp strlen(plugdir->d_name) + 1);
402c4800545Sjmcp free(tempnm);
403c4800545Sjmcp } else {
404c4800545Sjmcp (void) strlcpy(tmpplug->drvname,
405c4800545Sjmcp (char *)sym, strlen(sym) + 1);
406c4800545Sjmcp }
4075a7763bfSjmcp } else {
4085a7763bfSjmcp CLOSEFREE();
4095a7763bfSjmcp continue;
4105a7763bfSjmcp }
4115a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "fw_readfw"))
4125a7763bfSjmcp != NULL) {
4135a7763bfSjmcp tmpplug->fw_readfw = (int (*)())sym;
4145a7763bfSjmcp } else {
4155a7763bfSjmcp CLOSEFREE();
4165a7763bfSjmcp continue;
4175a7763bfSjmcp }
4185a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "fw_writefw"))
4195a7763bfSjmcp != NULL) {
4205a7763bfSjmcp tmpplug->fw_writefw = (int (*)())sym;
4215a7763bfSjmcp } else {
4225a7763bfSjmcp CLOSEFREE();
4235a7763bfSjmcp continue;
4245a7763bfSjmcp }
4255a7763bfSjmcp
4265a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "fw_identify"))
4275a7763bfSjmcp != NULL) {
4285a7763bfSjmcp tmpplug->fw_identify =
4295a7763bfSjmcp (int (*)(int))sym;
4305a7763bfSjmcp } else {
4315a7763bfSjmcp CLOSEFREE();
4325a7763bfSjmcp continue;
4335a7763bfSjmcp }
4345a7763bfSjmcp if ((sym = dlsym(tmpplug->handle, "fw_devinfo"))
4355a7763bfSjmcp != NULL) {
4365a7763bfSjmcp tmpplug->fw_devinfo =
4375a7763bfSjmcp (int (*)(struct devicelist *))sym;
4385a7763bfSjmcp } else {
4395a7763bfSjmcp CLOSEFREE();
4405a7763bfSjmcp continue;
4415a7763bfSjmcp }
4425a7763bfSjmcp
443d65b419eSXinChen if ((sym = dlsym(tmpplug->handle, "plugin_version"))
444d65b419eSXinChen != NULL) {
445d65b419eSXinChen if ((*(int *)sym) >= FWPLUGIN_VERSION_2) {
446d65b419eSXinChen if ((sym = dlsym(tmpplug->handle,
447d65b419eSXinChen "fw_cleanup")) != NULL) {
448d65b419eSXinChen tmpplug->fw_cleanup =
449d65b419eSXinChen (void (*)(struct devicelist *))sym;
450d65b419eSXinChen } else {
451d65b419eSXinChen logmsg(MSG_ERROR,
452d65b419eSXinChen gettext("ERROR: v2 plugin (%s) "
453d65b419eSXinChen "has no fw_cleanup function\n"),
454d65b419eSXinChen tmpplug->filename);
455d65b419eSXinChen CLOSEFREE();
456d65b419eSXinChen continue;
457d65b419eSXinChen }
458d65b419eSXinChen } else {
459d65b419eSXinChen logmsg(MSG_INFO,
460d65b419eSXinChen "Identification plugin %s defined "
461d65b419eSXinChen "plugin_version < FWPLUGIN_VERSION_2 !");
462d65b419eSXinChen }
463d65b419eSXinChen }
464d65b419eSXinChen
465c4800545Sjmcp if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME))
4665a7763bfSjmcp == NULL) {
4675a7763bfSjmcp logmsg(MSG_ERROR,
468c4800545Sjmcp gettext("Unable to allocate space for a"
4695a7763bfSjmcp "drivername %s\n"),
4705a7763bfSjmcp tmpplug->drvname);
4715a7763bfSjmcp return (FWFLASH_FAILURE);
4725a7763bfSjmcp }
4735a7763bfSjmcp
4745a7763bfSjmcp (void) strlcpy(tmpelem->drvname, tmpplug->drvname,
4755a7763bfSjmcp strlen(tmpplug->drvname) + 1);
4765a7763bfSjmcp
4775a7763bfSjmcp if ((tmpelem->filename = calloc(1,
4785a7763bfSjmcp strlen(tmpplug->filename) + 1)) == NULL) {
4795a7763bfSjmcp logmsg(MSG_ERROR,
4805a7763bfSjmcp gettext("Unable to allocate %d bytes for "
4815a7763bfSjmcp "filename %s\n"),
4825a7763bfSjmcp strlen(tmpplug->filename) + 1,
483c4800545Sjmcp tmpplug->filename);
4845a7763bfSjmcp return (FWFLASH_FAILURE);
4855a7763bfSjmcp }
4865a7763bfSjmcp
4875a7763bfSjmcp (void) strlcpy(tmpelem->filename, plugname,
4885a7763bfSjmcp strlen(plugname) + 1);
4895a7763bfSjmcp tmpelem->plugin = tmpplug;
4905a7763bfSjmcp
4915a7763bfSjmcp /* CONSTCOND */
4925a7763bfSjmcp TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin);
4935a7763bfSjmcp }
4945a7763bfSjmcp
4955a7763bfSjmcp if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) {
4965a7763bfSjmcp return (FWFLASH_FAILURE);
4975a7763bfSjmcp }
4985a7763bfSjmcp
4995a7763bfSjmcp if (errno != 0) {
5005a7763bfSjmcp logmsg(MSG_ERROR,
5015a7763bfSjmcp gettext("Error reading directory entry in %s\n"),
5025a7763bfSjmcp fwplugdirpath);
5035a7763bfSjmcp rval = errno;
5045a7763bfSjmcp }
5055a7763bfSjmcp
506d65b419eSXinChen free(fwplugdirpath);
507d65b419eSXinChen free(plugdir);
5085a7763bfSjmcp (void) closedir(dirp);
5095a7763bfSjmcp return (rval);
5105a7763bfSjmcp }
5115a7763bfSjmcp
5125a7763bfSjmcp /*
5135a7763bfSjmcp * fwflash_load_verifier dlload()s the appropriate firmware image
5145a7763bfSjmcp * verification plugin, and attaches the designated fwimg's fd to
5155a7763bfSjmcp * the vrfyplugin structure so we only have to load the image in
5165a7763bfSjmcp * one place.
5175a7763bfSjmcp */
5185a7763bfSjmcp int
fwflash_load_verifier(char * drv,char * vendorid,char * fwimg)519f8bf33c3SShantkumar Hiremath fwflash_load_verifier(char *drv, char *vendorid, char *fwimg)
520f8bf33c3SShantkumar Hiremath {
5215a7763bfSjmcp
5225a7763bfSjmcp int rv = FWFLASH_FAILURE;
5235a7763bfSjmcp int imgfd;
5245a7763bfSjmcp char *fwvrfydirpath, *tempdirpath, *filename;
5255a7763bfSjmcp char *clean; /* for the space-removed vid */
5265a7763bfSjmcp struct stat fwstat;
5275a7763bfSjmcp struct vrfyplugin *vrfy;
5285a7763bfSjmcp void *vrfysym;
5295a7763bfSjmcp
5305a7763bfSjmcp /*
5315a7763bfSjmcp * To make flashing multiple firmware images somewhat more
5325a7763bfSjmcp * efficient, we start this function by checking whether a
5335a7763bfSjmcp * verifier for this device has already been loaded. If it
5345a7763bfSjmcp * has been loaded, we replace the imgfile information, and
5355a7763bfSjmcp * then continue as if we were loading for the first time.
5365a7763bfSjmcp */
5375a7763bfSjmcp
5385a7763bfSjmcp if (verifier != NULL) {
5395a7763bfSjmcp verifier->imgsize = 0;
5405a7763bfSjmcp verifier->flashbuf = 0; /* set by the verifier function */
5415a7763bfSjmcp
542d65b419eSXinChen if (verifier->imgfile != NULL) {
543d65b419eSXinChen free(verifier->imgfile);
544d65b419eSXinChen verifier->imgfile = NULL;
545d65b419eSXinChen }
5465a7763bfSjmcp
547d65b419eSXinChen if (verifier->fwimage != NULL) {
548d65b419eSXinChen free(verifier->fwimage);
549d65b419eSXinChen verifier->fwimage = NULL;
550d65b419eSXinChen }
5515a7763bfSjmcp } else {
5525a7763bfSjmcp if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
5535a7763bfSjmcp logmsg(MSG_ERROR,
5545a7763bfSjmcp gettext("Unable to allocate space for a firmware "
5555a7763bfSjmcp "verifier file(1)"));
5565a7763bfSjmcp return (rv);
5575a7763bfSjmcp }
5585a7763bfSjmcp
5595a7763bfSjmcp if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) {
5605a7763bfSjmcp logmsg(MSG_ERROR,
5615a7763bfSjmcp gettext("Unable to allocate space "
5625a7763bfSjmcp "for a firmware verifier file(2)"));
563d65b419eSXinChen free(fwvrfydirpath);
5645a7763bfSjmcp return (rv);
5655a7763bfSjmcp }
5665a7763bfSjmcp
5675a7763bfSjmcp /*
568d65b419eSXinChen * Since SCSI devices can have a vendor id of up to 8
569d65b419eSXinChen * left-aligned and _space-padded_ characters, we first need to
570d65b419eSXinChen * strip off any space characters before we try to make a
571d65b419eSXinChen * filename out of it
5725a7763bfSjmcp */
5735a7763bfSjmcp clean = strtok(vendorid, " ");
5745a7763bfSjmcp if (clean == NULL) {
5755a7763bfSjmcp /* invalid vendorid, something's really wrong */
5765a7763bfSjmcp logmsg(MSG_ERROR,
5775a7763bfSjmcp gettext("Invalid vendorid (null) specified for "
5785a7763bfSjmcp "device\n"));
579d65b419eSXinChen free(filename);
580d65b419eSXinChen free(fwvrfydirpath);
5815a7763bfSjmcp return (rv);
5825a7763bfSjmcp }
5835a7763bfSjmcp
5845a7763bfSjmcp tempdirpath = getenv("FWVERIFYPLUGINDIR");
5855a7763bfSjmcp
5865a7763bfSjmcp if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
5875a7763bfSjmcp (void) strlcpy(fwvrfydirpath, tempdirpath,
5885a7763bfSjmcp strlen(tempdirpath) + 1);
5895a7763bfSjmcp } else {
5905a7763bfSjmcp (void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR,
5915a7763bfSjmcp strlen(FWVERIFYPLUGINDIR) + 1);
5925a7763bfSjmcp }
5935a7763bfSjmcp
5945a7763bfSjmcp if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) {
5955a7763bfSjmcp logmsg(MSG_ERROR,
5965a7763bfSjmcp gettext("Unable to allocate space "
5975a7763bfSjmcp "for a firmware verifier structure"));
5985a7763bfSjmcp free(filename);
5995a7763bfSjmcp free(fwvrfydirpath);
600d65b419eSXinChen return (rv);
6015a7763bfSjmcp }
6025a7763bfSjmcp
6035a7763bfSjmcp errno = 0; /* false positive removal */
6045a7763bfSjmcp
605d65b419eSXinChen (void) snprintf(filename, MAXPATHLEN, "%s/%s-%s.so",
6065a7763bfSjmcp fwvrfydirpath, drv, clean);
607d65b419eSXinChen if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) {
608d65b419eSXinChen logmsg(MSG_INFO, gettext(dlerror()));
609d65b419eSXinChen logmsg(MSG_INFO,
610d65b419eSXinChen gettext("\nUnable to open verification plugin "
611d65b419eSXinChen "%s. Looking for %s-GENERIC plugin instead.\n"),
612d65b419eSXinChen filename, drv);
613d65b419eSXinChen
614d65b419eSXinChen /* Try the drv-GENERIC.so form, _then_ die */
615d65b419eSXinChen bzero(filename, strlen(filename) + 1);
616d65b419eSXinChen (void) snprintf(filename, MAXPATHLEN,
617d65b419eSXinChen "%s/%s-GENERIC.so", fwvrfydirpath, drv);
618d65b419eSXinChen
619d65b419eSXinChen if ((vrfy->handle = dlopen(filename, RTLD_NOW))
620d65b419eSXinChen == NULL) {
621d65b419eSXinChen logmsg(MSG_INFO, gettext(dlerror()));
622d65b419eSXinChen logmsg(MSG_ERROR,
623d65b419eSXinChen gettext("\nUnable to open either "
624d65b419eSXinChen "verification plugin %s/%s-%s.so or "
625d65b419eSXinChen "generic plugin %s.\nUnable to verify "
626d65b419eSXinChen "firmware image. Aborting.\n"),
627d65b419eSXinChen fwvrfydirpath, drv, clean, filename);
628d65b419eSXinChen free(filename);
629d65b419eSXinChen free(fwvrfydirpath);
630d65b419eSXinChen return (rv);
631d65b419eSXinChen }
632d65b419eSXinChen }
6335a7763bfSjmcp
6345a7763bfSjmcp if ((vrfy->filename = calloc(1, strlen(filename) + 1))
6355a7763bfSjmcp == NULL) {
6365a7763bfSjmcp logmsg(MSG_ERROR,
6375a7763bfSjmcp gettext("Unable to allocate space to store "
6385a7763bfSjmcp "a verifier filename\n"));
6395a7763bfSjmcp free(filename);
6405a7763bfSjmcp free(fwvrfydirpath);
6415a7763bfSjmcp free(vrfy->handle);
642d65b419eSXinChen return (rv);
6435a7763bfSjmcp }
6445a7763bfSjmcp (void) strlcpy(vrfy->filename, filename, strlen(filename) + 1);
6455a7763bfSjmcp
6465a7763bfSjmcp if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) {
6475a7763bfSjmcp logmsg(MSG_ERROR,
6485a7763bfSjmcp gettext("%s is an invalid firmware verification "
6495a7763bfSjmcp "plugin."), filename);
6505a7763bfSjmcp (void) dlclose(vrfy->handle);
6515a7763bfSjmcp free(filename);
6525a7763bfSjmcp free(fwvrfydirpath);
6535a7763bfSjmcp free(vrfy);
654d65b419eSXinChen return (rv);
6555a7763bfSjmcp } else {
6565a7763bfSjmcp vrfy->vendorvrfy =
6575a7763bfSjmcp (int (*)(struct devicelist *))vrfysym;
6585a7763bfSjmcp }
6595a7763bfSjmcp
6605a7763bfSjmcp vrfysym = dlsym(vrfy->handle, "vendor");
6615a7763bfSjmcp
6625a7763bfSjmcp if (vrfysym == NULL) {
6635a7763bfSjmcp logmsg(MSG_ERROR,
6645a7763bfSjmcp gettext("Invalid vendor (null) in verification "
6655a7763bfSjmcp "plugin %s\n"), filename);
6665a7763bfSjmcp (void) dlclose(vrfy->handle);
6675a7763bfSjmcp free(vrfy);
668d65b419eSXinChen return (rv);
6695a7763bfSjmcp } else {
6705a7763bfSjmcp if (strncmp(vendorid, (char *)vrfysym,
6715a7763bfSjmcp strlen(vendorid)) != 0) {
6725a7763bfSjmcp logmsg(MSG_INFO,
6735a7763bfSjmcp "Using a sym-linked (%s -> %s) "
674d65b419eSXinChen "verification plugin\n",
6755a7763bfSjmcp vendorid, vrfysym);
6765a7763bfSjmcp vrfy->vendor = calloc(1, strlen(vendorid) + 1);
6775a7763bfSjmcp } else {
6785a7763bfSjmcp vrfy->vendor = calloc(1, strlen(vrfysym) + 1);
6795a7763bfSjmcp }
6805a7763bfSjmcp (void) strlcpy(vrfy->vendor, (char *)vrfysym,
6815a7763bfSjmcp strlen(vendorid) + 1);
6825a7763bfSjmcp }
6835a7763bfSjmcp
6845a7763bfSjmcp verifier = vrfy; /* a convenience variable */
685d65b419eSXinChen free(filename);
686d65b419eSXinChen free(fwvrfydirpath);
6875a7763bfSjmcp }
6885a7763bfSjmcp
6895a7763bfSjmcp /*
6905a7763bfSjmcp * We don't do any verification that the fw image file is in
6915a7763bfSjmcp * an approved location, but it's easy enough to modify this
6925a7763bfSjmcp * function to do so. The verification plugin should provide
6935a7763bfSjmcp * sufficient protection.
6945a7763bfSjmcp */
6955a7763bfSjmcp
6965a7763bfSjmcp if ((imgfd = open(fwimg, O_RDONLY)) < 0) {
6975a7763bfSjmcp logmsg(MSG_ERROR,
6985a7763bfSjmcp gettext("Unable to open designated firmware "
6995a7763bfSjmcp "image file %s: %s\n"),
7005a7763bfSjmcp (fwimg != NULL) ? fwimg : "(null)",
7015a7763bfSjmcp strerror(errno));
7025a7763bfSjmcp rv = FWFLASH_FAILURE;
7035a7763bfSjmcp goto cleanup;
7045a7763bfSjmcp }
7055a7763bfSjmcp
7065a7763bfSjmcp if (stat(fwimg, &fwstat) == -1) {
7075a7763bfSjmcp logmsg(MSG_ERROR,
7085a7763bfSjmcp gettext("Unable to stat() firmware image file "
7095a7763bfSjmcp "%s: %s\n"),
7105a7763bfSjmcp fwimg, strerror(errno));
7115a7763bfSjmcp rv = FWFLASH_FAILURE;
7125a7763bfSjmcp goto cleanup;
7135a7763bfSjmcp } else {
7145a7763bfSjmcp verifier->imgsize = fwstat.st_size;
7155a7763bfSjmcp if ((verifier->fwimage = calloc(1, verifier->imgsize))
7165a7763bfSjmcp == NULL) {
7175a7763bfSjmcp logmsg(MSG_ERROR,
7185a7763bfSjmcp gettext("Unable to load firmware image "
7195a7763bfSjmcp "%s: %s\n"),
7205a7763bfSjmcp fwimg, strerror(errno));
7215a7763bfSjmcp rv = FWFLASH_FAILURE;
7225a7763bfSjmcp goto cleanup;
7235a7763bfSjmcp }
7245a7763bfSjmcp }
7255a7763bfSjmcp
7265a7763bfSjmcp errno = 0;
7275a7763bfSjmcp if ((rv = read(imgfd, verifier->fwimage,
7285a7763bfSjmcp (size_t)verifier->imgsize)) < verifier->imgsize) {
7295a7763bfSjmcp /* we haven't read enough data, bail */
7305a7763bfSjmcp logmsg(MSG_ERROR,
7315a7763bfSjmcp gettext("Failed to read sufficient data "
7325a7763bfSjmcp "(got %d bytes, expected %d bytes) from "
7335a7763bfSjmcp "firmware image file %s: %s\n"),
7345a7763bfSjmcp rv, verifier->imgsize,
735d65b419eSXinChen verifier->filename, strerror(errno));
7365a7763bfSjmcp rv = FWFLASH_FAILURE;
7375a7763bfSjmcp } else {
7385a7763bfSjmcp rv = FWFLASH_SUCCESS;
7395a7763bfSjmcp }
7405a7763bfSjmcp
7415a7763bfSjmcp if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) {
7425a7763bfSjmcp logmsg(MSG_ERROR,
7435a7763bfSjmcp gettext("Unable to save name of firmware image\n"));
7445a7763bfSjmcp rv = FWFLASH_FAILURE;
7455a7763bfSjmcp } else {
7465a7763bfSjmcp (void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1);
7475a7763bfSjmcp }
7485a7763bfSjmcp
7495a7763bfSjmcp if (rv != FWFLASH_SUCCESS) {
7505a7763bfSjmcp /* cleanup and let's get outta here */
7515a7763bfSjmcp cleanup:
7525a7763bfSjmcp free(verifier->filename);
7535a7763bfSjmcp free(verifier->vendor);
7545a7763bfSjmcp
755d65b419eSXinChen if (!(fwflash_arg_list & FWFLASH_READ_FLAG) &&
756d65b419eSXinChen verifier->fwimage)
7575a7763bfSjmcp free(verifier->fwimage);
7585a7763bfSjmcp
7595a7763bfSjmcp verifier->filename = NULL;
7605a7763bfSjmcp verifier->vendor = NULL;
7615a7763bfSjmcp verifier->vendorvrfy = NULL;
7625a7763bfSjmcp verifier->fwimage = NULL;
7635a7763bfSjmcp (void) dlclose(verifier->handle);
7645a7763bfSjmcp verifier->handle = NULL;
7655a7763bfSjmcp free(verifier);
7665a7763bfSjmcp if (imgfd >= 0) {
7675a7763bfSjmcp (void) close(imgfd);
7685a7763bfSjmcp }
7695a7763bfSjmcp verifier = NULL;
7705a7763bfSjmcp }
7715a7763bfSjmcp
7725a7763bfSjmcp return (rv);
7735a7763bfSjmcp }
7745a7763bfSjmcp
7755a7763bfSjmcp /*
7765a7763bfSjmcp * cycles through the global list of plugins to find
7775a7763bfSjmcp * each flashable device, which is added to fw_devices
7785a7763bfSjmcp *
7795a7763bfSjmcp * Each plugin's identify routine must allocated storage
7805a7763bfSjmcp * as required.
7815a7763bfSjmcp *
7825a7763bfSjmcp * Each plugin's identify routine must return
7835a7763bfSjmcp * FWFLASH_FAILURE if it cannot find any devices
7845a7763bfSjmcp * which it handles.
7855a7763bfSjmcp */
7865a7763bfSjmcp static int
flash_device_list()7875a7763bfSjmcp flash_device_list()
7885a7763bfSjmcp {
7895a7763bfSjmcp int rv = FWFLASH_FAILURE;
7905a7763bfSjmcp int startidx = 0;
7915a7763bfSjmcp int sumrv = 0;
7925a7763bfSjmcp struct pluginlist *plugins;
7935a7763bfSjmcp
7945a7763bfSjmcp /* we open rootnode here, and close it in fwflash_intr */
795d65b419eSXinChen if ((rootnode = di_init("/", DINFOCPYALL|DINFOFORCE)) == DI_NODE_NIL) {
7965a7763bfSjmcp logmsg(MSG_ERROR,
7975a7763bfSjmcp gettext("Unable to take device tree snapshot: %s\n"),
7985a7763bfSjmcp strerror(errno));
7995a7763bfSjmcp return (rv);
8005a7763bfSjmcp }
8015a7763bfSjmcp
8025a7763bfSjmcp if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) {
8035a7763bfSjmcp logmsg(MSG_ERROR,
8045a7763bfSjmcp gettext("Unable to malloc %d bytes while "
8055a7763bfSjmcp "trying to find devices: %s\n"),
8065a7763bfSjmcp sizeof (struct devicelist), strerror(errno));
8075a7763bfSjmcp return (FWFLASH_FAILURE);
8085a7763bfSjmcp }
8095a7763bfSjmcp
8105a7763bfSjmcp /* CONSTCOND */
8115a7763bfSjmcp TAILQ_INIT(fw_devices);
8125a7763bfSjmcp
8135a7763bfSjmcp TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) {
8145a7763bfSjmcp self = plugins->plugin;
8155a7763bfSjmcp rv = plugins->plugin->fw_identify(startidx);
8165a7763bfSjmcp
8175a7763bfSjmcp logmsg(MSG_INFO,
8185a7763bfSjmcp gettext("fwflash:flash_device_list() got %d from "
8195a7763bfSjmcp "identify routine\n"), rv);
8205a7763bfSjmcp
8215a7763bfSjmcp /* only bump startidx if we've found at least one device */
8225a7763bfSjmcp if (rv == FWFLASH_SUCCESS) {
8235a7763bfSjmcp startidx += 100;
8245a7763bfSjmcp sumrv++;
8255a7763bfSjmcp } else {
8265a7763bfSjmcp logmsg(MSG_INFO,
8275a7763bfSjmcp gettext("No flashable devices attached with "
8285a7763bfSjmcp "the %s driver in this system\n"),
8295a7763bfSjmcp plugins->drvname);
8305a7763bfSjmcp }
8315a7763bfSjmcp }
8325a7763bfSjmcp
8335a7763bfSjmcp if (sumrv > 0)
8345a7763bfSjmcp rv = FWFLASH_SUCCESS;
8355a7763bfSjmcp
8365a7763bfSjmcp return (rv);
8375a7763bfSjmcp }
8385a7763bfSjmcp
8395a7763bfSjmcp static int
fwflash_list_fw(char * class)8405a7763bfSjmcp fwflash_list_fw(char *class)
8415a7763bfSjmcp {
8425a7763bfSjmcp int rv = 0;
8435a7763bfSjmcp struct devicelist *curdev;
8445a7763bfSjmcp int header = 1;
8455a7763bfSjmcp
8465a7763bfSjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) {
8475a7763bfSjmcp
8485a7763bfSjmcp /* we're either class-conscious, or we're not */
8495a7763bfSjmcp if (((class != NULL) &&
8505a7763bfSjmcp ((strncmp(curdev->classname, "ALL", 3) == 0) ||
8515a7763bfSjmcp (strcmp(curdev->classname, class) == 0))) ||
8525a7763bfSjmcp (class == NULL)) {
8535a7763bfSjmcp
8545a7763bfSjmcp if (header != 0) {
8555a7763bfSjmcp (void) fprintf(stdout,
8565a7763bfSjmcp gettext("List of available devices:\n"));
8575a7763bfSjmcp header--;
8585a7763bfSjmcp }
8595a7763bfSjmcp /*
8605a7763bfSjmcp * If any plugin's fw_devinfo() function returns
8615a7763bfSjmcp * FWFLASH_FAILURE then we want to keep track of
8625a7763bfSjmcp * it. _Most_ plugins should always return
8635a7763bfSjmcp * FWFLASH_SUCCESS from this function. The only
8645a7763bfSjmcp * exception known at this point is the tavor plugin.
8655a7763bfSjmcp */
8665a7763bfSjmcp rv += curdev->plugin->fw_devinfo(curdev);
8675a7763bfSjmcp }
8685a7763bfSjmcp }
8695a7763bfSjmcp return (rv);
8705a7763bfSjmcp }
8715a7763bfSjmcp
8725a7763bfSjmcp static int
fwflash_update(char * device,char * filename,int flags)873f1c23465SJames C. McPherson fwflash_update(char *device, char *filename, int flags)
874f1c23465SJames C. McPherson {
8755a7763bfSjmcp
8765a7763bfSjmcp int rv = FWFLASH_FAILURE;
8775a7763bfSjmcp int needsfree = 0;
878c4800545Sjmcp int found = 0;
8795a7763bfSjmcp struct devicelist *curdev;
8805a7763bfSjmcp char *realfile;
8815a7763bfSjmcp
8825a7763bfSjmcp /*
8835a7763bfSjmcp * Here's how we operate:
8845a7763bfSjmcp *
8855a7763bfSjmcp * We perform some basic checks on the args, then walk
8865a7763bfSjmcp * through the device list looking for the device which
8875a7763bfSjmcp * matches. We then load the appropriate verifier for the
8885a7763bfSjmcp * image file and device, verify the image, then call the
8895a7763bfSjmcp * fw_writefw() function of the appropriate plugin.
8905a7763bfSjmcp *
8915a7763bfSjmcp * There is no "force" flag to enable you to flash a firmware
8925a7763bfSjmcp * image onto an incompatible device because the verifier
8935a7763bfSjmcp * will return FWFLASH_FAILURE if the image doesn't match.
8945a7763bfSjmcp */
8955a7763bfSjmcp
8965a7763bfSjmcp /* new firmware filename and device desc */
8975a7763bfSjmcp if (filename == NULL) {
8985a7763bfSjmcp logmsg(MSG_ERROR,
8995a7763bfSjmcp gettext("Invalid firmware filename (null)\n"));
9005a7763bfSjmcp return (FWFLASH_FAILURE);
9015a7763bfSjmcp }
9025a7763bfSjmcp
9035a7763bfSjmcp if (device == NULL) {
9045a7763bfSjmcp logmsg(MSG_ERROR,
9055a7763bfSjmcp gettext("Invalid device requested (null)\n"));
9065a7763bfSjmcp return (FWFLASH_FAILURE);
9075a7763bfSjmcp }
9085a7763bfSjmcp
9095a7763bfSjmcp if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) {
9105a7763bfSjmcp logmsg(MSG_ERROR,
9115a7763bfSjmcp gettext("Unable to allocate space for device "
912c4800545Sjmcp "filename, operation might fail if %s is"
9135a7763bfSjmcp "a symbolic link\n"),
9145a7763bfSjmcp device);
9155a7763bfSjmcp realfile = device;
9165a7763bfSjmcp } else {
9175a7763bfSjmcp /*
9185a7763bfSjmcp * If realpath() succeeds, then we have a valid
9195a7763bfSjmcp * device filename in realfile.
9205a7763bfSjmcp */
9215a7763bfSjmcp if (realpath(device, realfile) == NULL) {
9225a7763bfSjmcp logmsg(MSG_ERROR,
9235a7763bfSjmcp gettext("Unable to resolve device filename"
9245a7763bfSjmcp ": %s\n"),
9255a7763bfSjmcp strerror(errno));
9265a7763bfSjmcp /* tidy up */
9275a7763bfSjmcp free(realfile);
9285a7763bfSjmcp /* realpath didn't succeed, use fallback */
9295a7763bfSjmcp realfile = device;
9305a7763bfSjmcp } else {
9315a7763bfSjmcp needsfree = 1;
9325a7763bfSjmcp }
9335a7763bfSjmcp }
9345a7763bfSjmcp
9355a7763bfSjmcp logmsg(MSG_INFO,
9365a7763bfSjmcp gettext("fwflash_update: fw_filename (%s) device (%s)\n"),
9375a7763bfSjmcp filename, device);
9385a7763bfSjmcp
9395a7763bfSjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) {
9405a7763bfSjmcp if (strcmp(curdev->access_devname, realfile) == 0) {
941c4800545Sjmcp found++;
9425a7763bfSjmcp rv = fwflash_load_verifier(curdev->drvname,
9435a7763bfSjmcp curdev->ident->vid, filename);
9445a7763bfSjmcp if (rv == FWFLASH_FAILURE) {
9455a7763bfSjmcp logmsg(MSG_ERROR,
9465a7763bfSjmcp gettext("Unable to load verifier "
9475a7763bfSjmcp "for device %s\n"),
9485a7763bfSjmcp curdev->access_devname);
9495a7763bfSjmcp return (FWFLASH_FAILURE);
9505a7763bfSjmcp }
9515a7763bfSjmcp rv = verifier->vendorvrfy(curdev);
9525a7763bfSjmcp if (rv == FWFLASH_FAILURE) {
9535a7763bfSjmcp /* the verifier prints a message */
9545a7763bfSjmcp logmsg(MSG_INFO,
9555a7763bfSjmcp "verifier (%s) for %s :: %s returned "
9565a7763bfSjmcp "FWFLASH_FAILURE\n",
9575a7763bfSjmcp verifier->filename,
9585a7763bfSjmcp filename, curdev->access_devname);
9595a7763bfSjmcp return (rv);
9605a7763bfSjmcp }
9615a7763bfSjmcp
962f1c23465SJames C. McPherson if (((flags & FWFLASH_YES_FLAG) == FWFLASH_YES_FLAG) ||
9635a7763bfSjmcp (rv = confirm_target(curdev, filename)) ==
9645a7763bfSjmcp FWFLASH_YES_FLAG) {
9655a7763bfSjmcp logmsg(MSG_INFO,
9665a7763bfSjmcp "about to flash using plugin %s\n",
9675a7763bfSjmcp curdev->plugin->filename);
9685a7763bfSjmcp rv = curdev->plugin->fw_writefw(curdev,
9695a7763bfSjmcp filename);
9705a7763bfSjmcp if (rv == FWFLASH_FAILURE) {
9715a7763bfSjmcp logmsg(MSG_ERROR,
9725a7763bfSjmcp gettext("Failed to flash "
9735a7763bfSjmcp "firmware file %s on "
9745a7763bfSjmcp "device %s: %d\n"),
9755a7763bfSjmcp filename,
9765a7763bfSjmcp curdev->access_devname, rv);
9775a7763bfSjmcp }
9785a7763bfSjmcp } else {
9795a7763bfSjmcp logmsg(MSG_ERROR,
9805a7763bfSjmcp gettext("Flash operation not confirmed "
9815a7763bfSjmcp "by user\n"),
9825a7763bfSjmcp curdev->access_devname);
9835a7763bfSjmcp rv = FWFLASH_FAILURE;
9845a7763bfSjmcp }
9855a7763bfSjmcp }
9865a7763bfSjmcp }
9875a7763bfSjmcp
988c4800545Sjmcp if (!found)
989c4800545Sjmcp /* report the same device that the user passed in */
990c4800545Sjmcp logmsg(MSG_ERROR,
991c4800545Sjmcp gettext("Device %s does not appear "
992c4800545Sjmcp "to be flashable\n"),
993c4800545Sjmcp ((strncmp(device, realfile, strlen(device)) == 0) ?
994d65b419eSXinChen realfile : device));
995c4800545Sjmcp
9965a7763bfSjmcp if (needsfree)
9975a7763bfSjmcp free(realfile);
9985a7763bfSjmcp
9995a7763bfSjmcp return (rv);
10005a7763bfSjmcp }
10015a7763bfSjmcp
10025a7763bfSjmcp /*
10035a7763bfSjmcp * We validate that the device path is in our global device list and
10045a7763bfSjmcp * that the filename exists, then palm things off to the relevant plugin.
10055a7763bfSjmcp */
10065a7763bfSjmcp static int
fwflash_read_file(char * device,char * filename)10075a7763bfSjmcp fwflash_read_file(char *device, char *filename)
10085a7763bfSjmcp {
10095a7763bfSjmcp struct devicelist *curdev;
10105a7763bfSjmcp int rv;
1011f8bf33c3SShantkumar Hiremath int found = 0;
10125a7763bfSjmcp
10135a7763bfSjmcp /* new firmware filename and device desc */
10145a7763bfSjmcp
10155a7763bfSjmcp TAILQ_FOREACH(curdev, fw_devices, nextdev) {
10165a7763bfSjmcp if (strncmp(curdev->access_devname, device,
10175a7763bfSjmcp MAXPATHLEN) == 0) {
10185a7763bfSjmcp rv = curdev->plugin->fw_readfw(curdev, filename);
10195a7763bfSjmcp
10205a7763bfSjmcp if (rv != FWFLASH_SUCCESS)
10215a7763bfSjmcp logmsg(MSG_ERROR,
10225a7763bfSjmcp gettext("Unable to write out firmware "
10235a7763bfSjmcp "image for %s to file %s\n"),
10245a7763bfSjmcp curdev->access_devname, filename);
1025f8bf33c3SShantkumar Hiremath found++;
10265a7763bfSjmcp }
10275a7763bfSjmcp
10285a7763bfSjmcp }
1029f8bf33c3SShantkumar Hiremath
1030f8bf33c3SShantkumar Hiremath if (!found) {
10315a7763bfSjmcp logmsg(MSG_ERROR,
10325a7763bfSjmcp gettext("No device matching %s was found.\n"),
10335a7763bfSjmcp device);
10345a7763bfSjmcp rv = FWFLASH_FAILURE;
10355a7763bfSjmcp }
10365a7763bfSjmcp
10375a7763bfSjmcp return (rv);
10385a7763bfSjmcp }
10395a7763bfSjmcp
10405a7763bfSjmcp static void
fwflash_usage(char * arg)10415a7763bfSjmcp fwflash_usage(char *arg)
10425a7763bfSjmcp {
10435a7763bfSjmcp
10445a7763bfSjmcp (void) fprintf(stderr, "\n");
10455a7763bfSjmcp if (arg != NULL) {
10465a7763bfSjmcp logmsg(MSG_ERROR,
10475a7763bfSjmcp gettext("Invalid argument (%s) supplied\n"), arg);
10485a7763bfSjmcp }
10495a7763bfSjmcp
10505a7763bfSjmcp (void) fprintf(stderr, "\n");
10515a7763bfSjmcp
10525a7763bfSjmcp (void) fprintf(stdout, gettext("Usage:\n\t"));
10535a7763bfSjmcp (void) fprintf(stdout, gettext("fwflash [-l [-c device_class "
10545a7763bfSjmcp "| ALL]] | [-v] | [-h]\n\t"));
10555a7763bfSjmcp (void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3"
10565a7763bfSjmcp ",... | -r file] [-y] -d device_path\n\n"));
10575a7763bfSjmcp (void) fprintf(stdout, "\n"); /* workaround for xgettext */
10585a7763bfSjmcp
10595a7763bfSjmcp (void) fprintf(stdout,
10605a7763bfSjmcp gettext("\t-l\t\tlist flashable devices in this system\n"
10615a7763bfSjmcp "\t-c device_class limit search to a specific class\n"
10625a7763bfSjmcp "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n"
10635a7763bfSjmcp "\t-v\t\tprint version number of fwflash utility\n"
1064f8bf33c3SShantkumar Hiremath "\t-h\t\tprint this usage message\n\n"));
10655a7763bfSjmcp (void) fprintf(stdout,
10665a7763bfSjmcp gettext("\t-f file1,file2,file3,...\n"
10675a7763bfSjmcp "\t\t\tfirmware image file list to flash\n"
10685a7763bfSjmcp "\t-r file\t\tfile to dump device firmware to\n"
10695a7763bfSjmcp "\t-y\t\tanswer Yes/Y/y to prompts\n"
10705a7763bfSjmcp "\t-d device_path\tpathname of device to be flashed\n\n"));
10715a7763bfSjmcp
10725a7763bfSjmcp (void) fprintf(stdout,
10735a7763bfSjmcp gettext("\tIf -d device_path is specified, then one of -f "
10745a7763bfSjmcp "<files>\n"
10755a7763bfSjmcp "\tor -r <file> must also be specified\n\n"));
10765a7763bfSjmcp
10775a7763bfSjmcp (void) fprintf(stdout,
10785a7763bfSjmcp gettext("\tIf multiple firmware images are required to be "
10795a7763bfSjmcp "flashed\n"
10805a7763bfSjmcp "\tthey must be listed together, separated by commas. The\n"
10815a7763bfSjmcp "\timages will be flashed in the order specified.\n\n"));
10825a7763bfSjmcp
10835a7763bfSjmcp (void) fprintf(stdout, "\n");
10845a7763bfSjmcp }
10855a7763bfSjmcp
10865a7763bfSjmcp static void
fwflash_version(void)10875a7763bfSjmcp fwflash_version(void)
10885a7763bfSjmcp {
10895a7763bfSjmcp (void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME);
10905a7763bfSjmcp (void) fprintf(stdout, gettext("version %s\n"),
10915a7763bfSjmcp FWFLASH_VERSION);
10925a7763bfSjmcp }
10935a7763bfSjmcp
10945a7763bfSjmcp static void
fwflash_intr(int sig)10955a7763bfSjmcp fwflash_intr(int sig)
10965a7763bfSjmcp {
10975a7763bfSjmcp
10985a7763bfSjmcp struct devicelist *thisdev;
10995a7763bfSjmcp struct pluginlist *thisplug;
11005a7763bfSjmcp
11015a7763bfSjmcp (void) signal(SIGINT, SIG_IGN);
11025a7763bfSjmcp (void) signal(SIGTERM, SIG_IGN);
1103c4800545Sjmcp (void) signal(SIGABRT, SIG_IGN);
1104d65b419eSXinChen
11055a7763bfSjmcp if (fwflash_in_write) {
11065a7763bfSjmcp (void) fprintf(stderr,
11075a7763bfSjmcp gettext("WARNING: firmware image may be corrupted\n\t"));
11085a7763bfSjmcp (void) fprintf(stderr,
11095a7763bfSjmcp gettext("Reflash firmware before rebooting!\n"));
11105a7763bfSjmcp }
11115a7763bfSjmcp
11125a7763bfSjmcp if (sig > 0) {
11135a7763bfSjmcp (void) logmsg(MSG_ERROR, gettext("\n"));
11145a7763bfSjmcp (void) logmsg(MSG_ERROR,
11155a7763bfSjmcp gettext("fwflash exiting due to signal (%d)\n"), sig);
11165a7763bfSjmcp }
11175a7763bfSjmcp
11185a7763bfSjmcp /*
11195a7763bfSjmcp * we need to close everything down properly, so
11205a7763bfSjmcp * call the plugin closure routines
11215a7763bfSjmcp */
11225a7763bfSjmcp if (fw_devices != NULL) {
11235a7763bfSjmcp TAILQ_FOREACH(thisdev, fw_devices, nextdev) {
1124d65b419eSXinChen if (thisdev->plugin->fw_cleanup != NULL) {
1125d65b419eSXinChen /*
1126d65b419eSXinChen * If we've got a cleanup routine, it
1127d65b419eSXinChen * cleans up _everything_ for thisdev
1128d65b419eSXinChen */
1129d65b419eSXinChen thisdev->plugin->fw_cleanup(thisdev);
1130d65b419eSXinChen } else {
11315a7763bfSjmcp /* free the components first */
11325a7763bfSjmcp free(thisdev->access_devname);
11335a7763bfSjmcp free(thisdev->drvname);
11345a7763bfSjmcp free(thisdev->classname);
1135c4800545Sjmcp if (thisdev->ident != NULL)
11365a7763bfSjmcp free(thisdev->ident);
1137d65b419eSXinChen /* We don't free address[] for old plugins */
11385a7763bfSjmcp thisdev->ident = NULL;
1139d65b419eSXinChen thisdev->plugin = NULL;
1140d65b419eSXinChen }
11415a7763bfSjmcp /* CONSTCOND */
11425a7763bfSjmcp TAILQ_REMOVE(fw_devices, thisdev, nextdev);
11435a7763bfSjmcp }
11445a7763bfSjmcp }
11455a7763bfSjmcp
11465a7763bfSjmcp if (fw_pluginlist != NULL) {
11475a7763bfSjmcp TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) {
11485a7763bfSjmcp free(thisplug->filename);
11495a7763bfSjmcp free(thisplug->drvname);
11505a7763bfSjmcp free(thisplug->plugin->filename);
11515a7763bfSjmcp free(thisplug->plugin->drvname);
11525a7763bfSjmcp thisplug->filename = NULL;
11535a7763bfSjmcp thisplug->drvname = NULL;
11545a7763bfSjmcp thisplug->plugin->filename = NULL;
11555a7763bfSjmcp thisplug->plugin->drvname = NULL;
11565a7763bfSjmcp thisplug->plugin->fw_readfw = NULL;
11575a7763bfSjmcp thisplug->plugin->fw_writefw = NULL;
11585a7763bfSjmcp thisplug->plugin->fw_identify = NULL;
11595a7763bfSjmcp thisplug->plugin->fw_devinfo = NULL;
1160d65b419eSXinChen thisplug->plugin->fw_cleanup = NULL;
11615a7763bfSjmcp (void) dlclose(thisplug->plugin->handle);
11625a7763bfSjmcp thisplug->plugin->handle = NULL;
11635a7763bfSjmcp free(thisplug->plugin);
11645a7763bfSjmcp thisplug->plugin = NULL;
11655a7763bfSjmcp /* CONSTCOND */
11665a7763bfSjmcp TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin);
11675a7763bfSjmcp }
11685a7763bfSjmcp }
11695a7763bfSjmcp
11705a7763bfSjmcp if (verifier != NULL) {
11715a7763bfSjmcp free(verifier->filename);
11725a7763bfSjmcp free(verifier->vendor);
1173c4800545Sjmcp free(verifier->imgfile);
1174c4800545Sjmcp free(verifier->fwimage);
11755a7763bfSjmcp verifier->filename = NULL;
11765a7763bfSjmcp verifier->vendor = NULL;
11775a7763bfSjmcp verifier->vendorvrfy = NULL;
1178c4800545Sjmcp verifier->imgfile = NULL;
1179c4800545Sjmcp verifier->fwimage = NULL;
11805a7763bfSjmcp (void) dlclose(verifier->handle);
11815a7763bfSjmcp verifier->handle = NULL;
11825a7763bfSjmcp free(verifier);
11835a7763bfSjmcp }
11845a7763bfSjmcp di_fini(rootnode);
1185d65b419eSXinChen
1186d65b419eSXinChen if (sig > 0)
1187d65b419eSXinChen exit(FWFLASH_FAILURE);
11885a7763bfSjmcp }
11895a7763bfSjmcp
11905a7763bfSjmcp static void
fwflash_handle_signals(void)11915a7763bfSjmcp fwflash_handle_signals(void)
11925a7763bfSjmcp {
11935a7763bfSjmcp if (signal(SIGINT, fwflash_intr) == SIG_ERR) {
11945a7763bfSjmcp perror("signal");
11955a7763bfSjmcp exit(FWFLASH_FAILURE);
11965a7763bfSjmcp }
11975a7763bfSjmcp
11985a7763bfSjmcp if (signal(SIGTERM, fwflash_intr) == SIG_ERR) {
11995a7763bfSjmcp perror("signal");
12005a7763bfSjmcp exit(FWFLASH_FAILURE);
12015a7763bfSjmcp }
12025a7763bfSjmcp }
12035a7763bfSjmcp
12045a7763bfSjmcp static int
confirm_target(struct devicelist * thisdev,char * file)12055a7763bfSjmcp confirm_target(struct devicelist *thisdev, char *file)
12065a7763bfSjmcp {
12075a7763bfSjmcp int resp;
12085a7763bfSjmcp
1209c4800545Sjmcp (void) fflush(stdin);
1210c4800545Sjmcp (void) printf(gettext("About to update firmware on %s\n"),
1211c4800545Sjmcp thisdev->access_devname);
1212d65b419eSXinChen (void) printf(gettext("with file %s.\n"
1213d65b419eSXinChen "Do you want to continue? (Y/N): "), file);
12145a7763bfSjmcp
12155a7763bfSjmcp resp = getchar();
12165a7763bfSjmcp if (resp == 'Y' || resp == 'y') {
12175a7763bfSjmcp return (FWFLASH_YES_FLAG);
12185a7763bfSjmcp } else {
12195a7763bfSjmcp logmsg(MSG_INFO, "flash operation NOT confirmed.\n");
12205a7763bfSjmcp }
12215a7763bfSjmcp
12225a7763bfSjmcp (void) fflush(stdin);
12235a7763bfSjmcp return (FWFLASH_FAILURE);
12245a7763bfSjmcp }
12255a7763bfSjmcp
12265a7763bfSjmcp int
get_fileopts(char * options)12275a7763bfSjmcp get_fileopts(char *options)
12285a7763bfSjmcp {
12295a7763bfSjmcp
12305a7763bfSjmcp int i;
12315a7763bfSjmcp char *files;
12325a7763bfSjmcp
12335a7763bfSjmcp if (files = strtok(options, ",")) {
12345a7763bfSjmcp /* we have more than one */
12355a7763bfSjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
12365a7763bfSjmcp logmsg(MSG_ERROR,
12375a7763bfSjmcp gettext("Unable to allocate space for "
12385a7763bfSjmcp "a firmware image filename\n"));
12395a7763bfSjmcp return (FWFLASH_FAILURE);
12405a7763bfSjmcp }
12415a7763bfSjmcp (void) strlcpy(filelist[0], files, strlen(files) + 1);
12425a7763bfSjmcp i = 1;
12435a7763bfSjmcp
12445a7763bfSjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
12455a7763bfSjmcp filelist[0]);
12465a7763bfSjmcp
12475a7763bfSjmcp
12485a7763bfSjmcp while (files = strtok(NULL, ",")) {
12495a7763bfSjmcp if ((filelist[i] = calloc(1, MAXPATHLEN + 1))
12505a7763bfSjmcp == NULL) {
12515a7763bfSjmcp logmsg(MSG_ERROR,
12525a7763bfSjmcp gettext("Unable to allocate space for "
12535a7763bfSjmcp "a firmware image filename\n"));
12545a7763bfSjmcp return (FWFLASH_FAILURE);
12555a7763bfSjmcp }
12565a7763bfSjmcp (void) strlcpy(filelist[i], files,
12575a7763bfSjmcp strlen(files) + 1);
12585a7763bfSjmcp logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n",
12595a7763bfSjmcp i, filelist[i]);
12605a7763bfSjmcp ++i;
12615a7763bfSjmcp }
12625a7763bfSjmcp } else {
12635a7763bfSjmcp if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
12645a7763bfSjmcp logmsg(MSG_ERROR,
12655a7763bfSjmcp gettext("Unable to allocate space for "
12665a7763bfSjmcp "a firmware image filename\n"));
12675a7763bfSjmcp return (FWFLASH_FAILURE);
12685a7763bfSjmcp }
12695a7763bfSjmcp (void) strlcpy(filelist[0], options, strlen(files) + 1);
12705a7763bfSjmcp logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
12715a7763bfSjmcp filelist[0]);
12725a7763bfSjmcp }
12735a7763bfSjmcp return (FWFLASH_SUCCESS);
12745a7763bfSjmcp }
12755a7763bfSjmcp
12765a7763bfSjmcp /*
12775a7763bfSjmcp * code reuse - cheerfully borrowed from stmsboot_util.c
12785a7763bfSjmcp */
12795a7763bfSjmcp void
logmsg(int severity,const char * msg,...)1280d65b419eSXinChen logmsg(int severity, const char *msg, ...)
1281d65b419eSXinChen {
12825a7763bfSjmcp va_list ap;
12835a7763bfSjmcp
12845a7763bfSjmcp if ((severity > MSG_INFO) ||
12855a7763bfSjmcp ((severity == MSG_INFO) && (fwflash_debug > 0))) {
12865a7763bfSjmcp (void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME);
12875a7763bfSjmcp va_start(ap, msg);
12885a7763bfSjmcp (void) vfprintf(stderr, msg, ap);
12895a7763bfSjmcp va_end(ap);
12905a7763bfSjmcp }
12915a7763bfSjmcp }
1292