xref: /illumos-gate/usr/src/cmd/fwflash/common/fwflash.c (revision 4196e26398ab7019943a8f276006fa66937b4425)
15a7763bfSjmcp /*
25a7763bfSjmcp  * CDDL HEADER START
35a7763bfSjmcp  *
45a7763bfSjmcp  * The contents of this file are subject to the terms of the
55a7763bfSjmcp  * Common Development and Distribution License (the "License").
65a7763bfSjmcp  * You may not use this file except in compliance with the License.
75a7763bfSjmcp  *
85a7763bfSjmcp  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95a7763bfSjmcp  * or http://www.opensolaris.org/os/licensing.
105a7763bfSjmcp  * See the License for the specific language governing permissions
115a7763bfSjmcp  * and limitations under the License.
125a7763bfSjmcp  *
135a7763bfSjmcp  * When distributing Covered Code, include this CDDL HEADER in each
145a7763bfSjmcp  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155a7763bfSjmcp  * If applicable, add the following below this CDDL HEADER, with the
165a7763bfSjmcp  * fields enclosed by brackets "[]" replaced with your own identifying
175a7763bfSjmcp  * information: Portions Copyright [yyyy] [name of copyright owner]
185a7763bfSjmcp  *
195a7763bfSjmcp  * CDDL HEADER END
205a7763bfSjmcp  */
215a7763bfSjmcp /*
2287d06e46Speihong huang  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235a7763bfSjmcp  * Use is subject to license terms.
245a7763bfSjmcp  */
255a7763bfSjmcp 
265a7763bfSjmcp /*
275a7763bfSjmcp  * fwflash.c
285a7763bfSjmcp  */
295a7763bfSjmcp #include <stdio.h>
305a7763bfSjmcp #include <stdlib.h>
315a7763bfSjmcp #include <unistd.h>
325a7763bfSjmcp #include <strings.h>
335a7763bfSjmcp #include <errno.h>
345a7763bfSjmcp #include <sys/queue.h>
355a7763bfSjmcp #include <signal.h>
365a7763bfSjmcp #include <locale.h>
375a7763bfSjmcp #include <sys/stat.h>
385a7763bfSjmcp #include <sys/types.h>
395a7763bfSjmcp #include <sys/param.h>
405a7763bfSjmcp #include <fcntl.h>
415a7763bfSjmcp #include <dlfcn.h>
425a7763bfSjmcp #include <dirent.h>
435a7763bfSjmcp #include <sys/varargs.h>
445a7763bfSjmcp #include <libintl.h> /* for gettext(3c) */
455a7763bfSjmcp #include <libdevinfo.h>
46*4196e263SSherry Moore #include <libscf_priv.h>
475a7763bfSjmcp #include <fwflash/fwflash.h>
48c4800545Sjmcp #include <sys/modctl.h> /* for MAXMODCONFNAME */
495a7763bfSjmcp 
505a7763bfSjmcp 
515a7763bfSjmcp #if !defined(lint)
525a7763bfSjmcp /* embedded software license agreement */
535a7763bfSjmcp static char *sla [] = { "Copyright 2007 Sun Microsystems, Inc., 4150 Network "
545a7763bfSjmcp "Circle, Santa Clara, California 95054, U.S.A. All rights reserved. U.S. "
555a7763bfSjmcp "Government Rights - Commercial software.  Government users are subject to the "
565a7763bfSjmcp "Sun Microsystems, Inc. standard license agreement and applicable provisions "
575a7763bfSjmcp "of the FAR and its supplements.  Use is subject to license terms.  Parts of "
585a7763bfSjmcp "the product may be derived from Berkeley BSD systems, licensed from the "
595a7763bfSjmcp "University of California. UNIX is a registered trademark in the U.S. and in "
605a7763bfSjmcp "other countries, exclusively licensed through X/Open Company, Ltd.Sun, Sun "
615a7763bfSjmcp "Microsystems, the Sun logo and Solaris are trademarks or registered "
625a7763bfSjmcp "trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This "
635a7763bfSjmcp "product is covered and controlled by U.S. Export Control laws and may be "
645a7763bfSjmcp "subject to the export or import laws in other countries.  Nuclear, missile, "
655a7763bfSjmcp "chemical biological weapons or nuclear maritime end uses or end users, "
665a7763bfSjmcp "whether direct or indirect, are strictly prohibited.  Export or reexport "
675a7763bfSjmcp "to countries subject to U.S. embargo or to entities identified on U.S. export "
685a7763bfSjmcp "exclusion lists, including, but not limited to, the denied persons and "
695a7763bfSjmcp "specially designated nationals lists is strictly prohibited." };
705a7763bfSjmcp #endif	/* lint */
715a7763bfSjmcp 
725a7763bfSjmcp /* global arg list */
735a7763bfSjmcp int	fwflash_arg_list = 0;
745a7763bfSjmcp char	*filelist[10];
755a7763bfSjmcp 
765a7763bfSjmcp /* are we writing to flash? */
775a7763bfSjmcp static int fwflash_in_write = 0;
785a7763bfSjmcp 
795a7763bfSjmcp /*
805a7763bfSjmcp  * If we *must* track the version string for fwflash, then
815a7763bfSjmcp  * we should do so in this common file rather than the header
825a7763bfSjmcp  * file since it will then be in sync with what the customer
83f1c23465SJames C. McPherson  * sees. We should deprecate the "-v" option since it is not
84f1c23465SJames C. McPherson  * actually of any use - it doesn't line up with Mercurial's
85f1c23465SJames C. McPherson  * concept of the changeset.
865a7763bfSjmcp  */
87d65b419eSXinChen #define	FWFLASH_VERSION		"v1.8"
885a7763bfSjmcp #define	FWFLASH_PROG_NAME	"fwflash"
895a7763bfSjmcp 
905a7763bfSjmcp static int get_fileopts(char *options);
915a7763bfSjmcp static int flash_device_list();
925a7763bfSjmcp static int flash_load_plugins();
935a7763bfSjmcp static int fwflash_update(char *device, char *filename, int flags);
945a7763bfSjmcp static int fwflash_read_file(char *device, char *filename);
955a7763bfSjmcp static int fwflash_list_fw(char *class);
965a7763bfSjmcp static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg);
975a7763bfSjmcp static void fwflash_intr(int sig);
985a7763bfSjmcp static void fwflash_handle_signals(void);
99f1c23465SJames C. McPherson static void fwflash_usage(char *arg);
1005a7763bfSjmcp static void fwflash_version(void);
1015a7763bfSjmcp static int confirm_target(struct devicelist *thisdev, char *file);
1025a7763bfSjmcp 
1035a7763bfSjmcp /*
1045a7763bfSjmcp  * FWFlash main code
1055a7763bfSjmcp  */
1065a7763bfSjmcp int
107f8bf33c3SShantkumar Hiremath main(int argc, char **argv)
108f8bf33c3SShantkumar Hiremath {
1095a7763bfSjmcp 	int		rv = FWFLASH_SUCCESS;
1105a7763bfSjmcp 	int		i;
1115a7763bfSjmcp 	char		ch;
1125a7763bfSjmcp 	char		*read_file;
1135a7763bfSjmcp 	extern char	*optarg;
1145a7763bfSjmcp 	char		*devclass = NULL;
1155a7763bfSjmcp 	char		*devpath = NULL;
1165a7763bfSjmcp 
1175a7763bfSjmcp 	/* local variables from env */
1185a7763bfSjmcp 	(void) setlocale(LC_ALL, "");
1195a7763bfSjmcp 
1205a7763bfSjmcp #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
1215a7763bfSjmcp #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it isn't. */
1225a7763bfSjmcp #endif
1235a7763bfSjmcp 
1245a7763bfSjmcp 	(void) textdomain(TEXT_DOMAIN);
1255a7763bfSjmcp 
1265a7763bfSjmcp 	read_file = NULL;
1275a7763bfSjmcp 
1285a7763bfSjmcp 	if (argc < 2) {
1295a7763bfSjmcp 		/* no args supplied */
1305a7763bfSjmcp 		fwflash_usage(NULL);
1315a7763bfSjmcp 		return (FWFLASH_FAILURE);
1325a7763bfSjmcp 	}
1335a7763bfSjmcp 
13487d06e46Speihong huang 	while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:")) != EOF) {
1355a7763bfSjmcp 		switch (ch) {
1365a7763bfSjmcp 		case 'h':
1375a7763bfSjmcp 			fwflash_arg_list |= FWFLASH_HELP_FLAG;
1385a7763bfSjmcp 			break;
1395a7763bfSjmcp 		case 'v':
1405a7763bfSjmcp 			fwflash_arg_list |= FWFLASH_VER_FLAG;
1415a7763bfSjmcp 			break;
1425a7763bfSjmcp 		case 'y':
1435a7763bfSjmcp 			fwflash_arg_list |= FWFLASH_YES_FLAG;
1445a7763bfSjmcp 			break;
1455a7763bfSjmcp 		case 'l':
1465a7763bfSjmcp 			fwflash_arg_list |= FWFLASH_LIST_FLAG;
1475a7763bfSjmcp 			break;
1485a7763bfSjmcp 		case 'c':
1495a7763bfSjmcp 			fwflash_arg_list |= FWFLASH_CLASS_FLAG;
1505a7763bfSjmcp 			/* we validate later */
1515a7763bfSjmcp 			devclass = strdup(optarg);
1525a7763bfSjmcp 			break;
1535a7763bfSjmcp 		case 'd':
1545a7763bfSjmcp 			fwflash_arg_list |= FWFLASH_DEVICE_FLAG;
1555a7763bfSjmcp 			devpath = strdup(optarg);
1565a7763bfSjmcp 			break;
1575a7763bfSjmcp 		case 'f':
1585a7763bfSjmcp 			fwflash_arg_list |= FWFLASH_FW_FLAG;
1595a7763bfSjmcp 			if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) {
160f1c23465SJames C. McPherson 				fwflash_usage(NULL);
1615a7763bfSjmcp 				return (FWFLASH_FAILURE);
1625a7763bfSjmcp 			}
1635a7763bfSjmcp 			break;
1645a7763bfSjmcp 		case 'r':
1655a7763bfSjmcp 			fwflash_arg_list |= FWFLASH_READ_FLAG;
1665a7763bfSjmcp 			read_file = strdup(optarg);
1675a7763bfSjmcp 			break;
1685a7763bfSjmcp 		case 'Q':
1695a7763bfSjmcp 			/* NOT in the manpage */
1705a7763bfSjmcp 			fwflash_debug = 1;
1715a7763bfSjmcp 			break;
1725a7763bfSjmcp 		/* illegal options */
1735a7763bfSjmcp 		default:
1745a7763bfSjmcp 			fwflash_usage(optarg);
1755a7763bfSjmcp 			return (FWFLASH_FAILURE);
1765a7763bfSjmcp 		}
1775a7763bfSjmcp 	}
1785a7763bfSjmcp 
1795a7763bfSjmcp 	/* Do Help */
1805a7763bfSjmcp 	if ((fwflash_arg_list & FWFLASH_HELP_FLAG) ||
1815a7763bfSjmcp 	    ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) &&
1825a7763bfSjmcp 	    !((fwflash_arg_list & FWFLASH_FW_FLAG) ||
1835a7763bfSjmcp 	    (fwflash_arg_list & FWFLASH_READ_FLAG)))) {
184f1c23465SJames C. McPherson 		fwflash_usage(NULL);
1855a7763bfSjmcp 		return (FWFLASH_SUCCESS);
1865a7763bfSjmcp 	}
1875a7763bfSjmcp 
1885a7763bfSjmcp 	/* Do Version */
1895a7763bfSjmcp 	if (fwflash_arg_list == FWFLASH_VER_FLAG) {
1905a7763bfSjmcp 		fwflash_version();
1915a7763bfSjmcp 		return (FWFLASH_SUCCESS);
1925a7763bfSjmcp 	}
1935a7763bfSjmcp 
1945a7763bfSjmcp 	/* generate global list of devices */
1955a7763bfSjmcp 	if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) {
1965a7763bfSjmcp 		logmsg(MSG_ERROR,
1975a7763bfSjmcp 		    gettext("Unable to load fwflash plugins\n"));
1985a7763bfSjmcp 		fwflash_intr(0);
1995a7763bfSjmcp 		return (rv);
2005a7763bfSjmcp 	}
2015a7763bfSjmcp 
2025a7763bfSjmcp 	if ((rv = flash_device_list()) != FWFLASH_SUCCESS) {
2035a7763bfSjmcp 		logmsg(MSG_ERROR,
2045a7763bfSjmcp 		    gettext("No flashable devices in this system\n"));
2055a7763bfSjmcp 		fwflash_intr(0);
2065a7763bfSjmcp 		return (rv);
2075a7763bfSjmcp 	}
2085a7763bfSjmcp 
2095a7763bfSjmcp 	/* Do list */
2105a7763bfSjmcp 	if (fwflash_arg_list == (FWFLASH_LIST_FLAG) ||
2115a7763bfSjmcp 	    fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) {
2125a7763bfSjmcp 		rv = fwflash_list_fw(devclass);
2135a7763bfSjmcp 		fwflash_intr(0);
2145a7763bfSjmcp 		return (rv);
2155a7763bfSjmcp 	}
2165a7763bfSjmcp 
2175a7763bfSjmcp 	fwflash_handle_signals();
2185a7763bfSjmcp 
2195a7763bfSjmcp 	/* Do flash update (write) */
2205a7763bfSjmcp 	if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) ||
2215a7763bfSjmcp 	    (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG |
2225a7763bfSjmcp 	    FWFLASH_YES_FLAG))) {
223*4196e263SSherry Moore 		int fastreboot_disabled = 0;
2245a7763bfSjmcp 		/* the update function handles the real arg parsing */
2255a7763bfSjmcp 		i = 0;
2265a7763bfSjmcp 		while (filelist[i] != NULL) {
2275a7763bfSjmcp 			if ((rv = fwflash_update(devpath, filelist[i],
2285a7763bfSjmcp 			    fwflash_arg_list)) == FWFLASH_SUCCESS) {
2295a7763bfSjmcp 				/* failed ops have already been noted */
230*4196e263SSherry Moore 				if (!fastreboot_disabled &&
231*4196e263SSherry Moore 				    scf_fastreboot_default_set_transient(
232*4196e263SSherry Moore 				    B_FALSE) != SCF_SUCCESS)
233*4196e263SSherry Moore 					logmsg(MSG_ERROR, gettext(
234*4196e263SSherry Moore 					    "Failed to disable fast "
235*4196e263SSherry Moore 					    "reboot.\n"));
236*4196e263SSherry Moore 				else
237*4196e263SSherry Moore 					fastreboot_disabled = 1;
2385a7763bfSjmcp 				logmsg(MSG_ERROR,
2395a7763bfSjmcp 				    gettext("New firmware will be activated "
2405a7763bfSjmcp 				    "after you reboot\n\n"));
2415a7763bfSjmcp 			}
2425a7763bfSjmcp 			++i;
2435a7763bfSjmcp 		}
2445a7763bfSjmcp 
2455a7763bfSjmcp 		fwflash_intr(0);
2465a7763bfSjmcp 		return (rv);
2475a7763bfSjmcp 	}
2485a7763bfSjmcp 
2495a7763bfSjmcp 	/* Do flash read */
2505a7763bfSjmcp 	if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) ||
2515a7763bfSjmcp 	    (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG |
2525a7763bfSjmcp 	    FWFLASH_YES_FLAG))) {
2535a7763bfSjmcp 		rv = fwflash_read_file(devpath, read_file);
2545a7763bfSjmcp 		fwflash_intr(0);
2555a7763bfSjmcp 		return (rv);
2565a7763bfSjmcp 	}
2575a7763bfSjmcp 
2585a7763bfSjmcp 	fwflash_usage(NULL);
2595a7763bfSjmcp 
2605a7763bfSjmcp 	return (FWFLASH_FAILURE);
2615a7763bfSjmcp }
2625a7763bfSjmcp 
2635a7763bfSjmcp 
2645a7763bfSjmcp static int
265f8bf33c3SShantkumar Hiremath flash_load_plugins()
266f8bf33c3SShantkumar Hiremath {
2675a7763bfSjmcp 
2685a7763bfSjmcp 	int rval = FWFLASH_SUCCESS;
2695a7763bfSjmcp 	DIR *dirp;
2705a7763bfSjmcp 	struct dirent *plugdir;
2715a7763bfSjmcp 	char *plugname;
2725a7763bfSjmcp 	struct fw_plugin *tmpplug;
2735a7763bfSjmcp 	struct pluginlist *tmpelem;
2745a7763bfSjmcp 	void *sym;
2755a7763bfSjmcp 	char *fwplugdirpath, *tempdirpath;
2765a7763bfSjmcp 
2775a7763bfSjmcp 
2785a7763bfSjmcp #define	CLOSEFREE()	{			\
2795a7763bfSjmcp 	(void) dlclose(tmpplug->handle);	\
2805a7763bfSjmcp 	free(tmpplug); }
2815a7763bfSjmcp 
2825a7763bfSjmcp 	/*
2835a7763bfSjmcp 	 * Procedure:
2845a7763bfSjmcp 	 *
2855a7763bfSjmcp 	 * cd /usr/lib/fwflash/identify
2865a7763bfSjmcp 	 * open each .so file found therein
2875a7763bfSjmcp 	 * dlopen(.sofile)
2885a7763bfSjmcp 	 * if it's one of our plugins, add it to fw_pluginlist;
2895a7763bfSjmcp 	 *
2905a7763bfSjmcp 	 * functions we need here include dlopen and dlsym.
2915a7763bfSjmcp 	 *
2925a7763bfSjmcp 	 * If we get to the end and fw_pluginlist struct is empty,
2935a7763bfSjmcp 	 * return FWFLASH_FAILURE so we return to the shell.
2945a7763bfSjmcp 	 */
2955a7763bfSjmcp 
2965a7763bfSjmcp 	if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
2975a7763bfSjmcp 		logmsg(MSG_ERROR,
2985a7763bfSjmcp 		    gettext("Unable to malloc %d bytes while "
2995a7763bfSjmcp 		    "trying to load plugins: %s\n"),
3005a7763bfSjmcp 		    MAXPATHLEN + 1, strerror(errno));
3015a7763bfSjmcp 		return (FWFLASH_FAILURE);
3025a7763bfSjmcp 	}
3035a7763bfSjmcp 
3045a7763bfSjmcp 	tempdirpath = getenv("FWPLUGINDIR");
3055a7763bfSjmcp 
3065a7763bfSjmcp 	if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
3075a7763bfSjmcp 		(void) strlcpy(fwplugdirpath, tempdirpath,
3085a7763bfSjmcp 		    strlen(tempdirpath) + 1);
3095a7763bfSjmcp 	} else {
3105a7763bfSjmcp 		(void) strlcpy(fwplugdirpath, FWPLUGINDIR,
3115a7763bfSjmcp 		    strlen(FWPLUGINDIR) + 1);
3125a7763bfSjmcp 	}
3135a7763bfSjmcp 
3145a7763bfSjmcp 	if ((dirp = opendir(fwplugdirpath)) == NULL) {
3155a7763bfSjmcp 		logmsg(MSG_ERROR,
316c4800545Sjmcp 		    gettext("Unable to open %s\n"),
3175a7763bfSjmcp 		    fwplugdirpath);
3185a7763bfSjmcp 		return (errno);
3195a7763bfSjmcp 	}
3205a7763bfSjmcp 
3215a7763bfSjmcp 	if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1))
3225a7763bfSjmcp 	    == NULL) {
3235a7763bfSjmcp 		logmsg(MSG_ERROR,
3245a7763bfSjmcp 		    gettext("Unable to malloc %d bytes while "
3255a7763bfSjmcp 		    "trying to load plugins: %s\n"),
3265a7763bfSjmcp 		    MAXPATHLEN + 1 + sizeof (struct dirent),
3275a7763bfSjmcp 		    strerror(errno));
3285a7763bfSjmcp 		return (FWFLASH_FAILURE);
3295a7763bfSjmcp 	}
3305a7763bfSjmcp 
3315a7763bfSjmcp 	if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin)))
3325a7763bfSjmcp 	    == NULL) {
3335a7763bfSjmcp 		logmsg(MSG_ERROR,
3345a7763bfSjmcp 		    gettext("Unable to malloc %d bytes while "
3355a7763bfSjmcp 		    "trying to load plugins: %s\n"),
336d65b419eSXinChen 		    sizeof (struct fw_plugin), strerror(errno));
3375a7763bfSjmcp 		return (FWFLASH_FAILURE);
3385a7763bfSjmcp 	}
3395a7763bfSjmcp 
3405a7763bfSjmcp 	TAILQ_INIT(fw_pluginlist);
3415a7763bfSjmcp 
3425a7763bfSjmcp 	while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) {
3435a7763bfSjmcp 
3445a7763bfSjmcp 		errno = 0; /* remove chance of false results */
3455a7763bfSjmcp 
3465a7763bfSjmcp 		if ((plugdir->d_name[0] == '.') ||
3475a7763bfSjmcp 		    (strstr(plugdir->d_name, ".so") == NULL)) {
3485a7763bfSjmcp 			continue;
3495a7763bfSjmcp 		}
3505a7763bfSjmcp 
3515a7763bfSjmcp 		if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) {
3525a7763bfSjmcp 			logmsg(MSG_ERROR,
3535a7763bfSjmcp 			    gettext("Unable to malloc %d bytes while "
3545a7763bfSjmcp 			    "trying to load plugins: %s\n"),
3555a7763bfSjmcp 			    MAXPATHLEN + 1, strerror(errno));
3565a7763bfSjmcp 			return (FWFLASH_FAILURE);
3575a7763bfSjmcp 		}
3585a7763bfSjmcp 
3595a7763bfSjmcp 		(void) snprintf(plugname, MAXPATHLEN, "%s/%s",
3605a7763bfSjmcp 		    fwplugdirpath, plugdir->d_name);
3615a7763bfSjmcp 
3625a7763bfSjmcp 		/* start allocating storage */
3635a7763bfSjmcp 		if ((tmpelem = calloc(1, sizeof (struct pluginlist)))
3645a7763bfSjmcp 		    == NULL) {
3655a7763bfSjmcp 			logmsg(MSG_ERROR,
3665a7763bfSjmcp 			    gettext("Unable to malloc %d bytes while "
3675a7763bfSjmcp 			    "trying to load plugins: %s\n"),
3685a7763bfSjmcp 			    sizeof (struct pluginlist), strerror(errno));
3695a7763bfSjmcp 			return (FWFLASH_FAILURE);
3705a7763bfSjmcp 		}
3715a7763bfSjmcp 
3725a7763bfSjmcp 		if ((tmpplug = calloc(1, sizeof (struct fw_plugin)))
3735a7763bfSjmcp 		    == NULL) {
3745a7763bfSjmcp 			logmsg(MSG_ERROR,
3755a7763bfSjmcp 			    gettext("Unable to malloc %d bytes while "
3765a7763bfSjmcp 			    "trying to load plugins: %s\n"),
3775a7763bfSjmcp 			    sizeof (struct fw_plugin), strerror(errno));
3785a7763bfSjmcp 			return (FWFLASH_FAILURE);
3795a7763bfSjmcp 		}
3805a7763bfSjmcp 
3815a7763bfSjmcp 		/* load 'er up! */
3825a7763bfSjmcp 		tmpplug->handle = dlopen(plugname, RTLD_NOW);
3835a7763bfSjmcp 		if (tmpplug->handle == NULL) {
3845a7763bfSjmcp 			free(tmpplug);
3855a7763bfSjmcp 			continue; /* assume there are other plugins */
3865a7763bfSjmcp 		}
3875a7763bfSjmcp 
3885a7763bfSjmcp 		if ((tmpplug->filename = calloc(1, strlen(plugname) + 1))
3895a7763bfSjmcp 		    == NULL) {
3905a7763bfSjmcp 			logmsg(MSG_ERROR,
3915a7763bfSjmcp 			    gettext("Unable to allocate %d bytes for plugin "
3925a7763bfSjmcp 			    "filename %s:%s\n"),
3935a7763bfSjmcp 			    strlen(plugname) + 1, plugname,
3945a7763bfSjmcp 			    strerror(errno));
3955a7763bfSjmcp 			return (rval);
3965a7763bfSjmcp 		}
3975a7763bfSjmcp 
3985a7763bfSjmcp 		(void) strlcpy(tmpplug->filename, plugname,
3995a7763bfSjmcp 		    strlen(plugname) + 1);
4005a7763bfSjmcp 
4015a7763bfSjmcp 		/* now sanity check the file */
4025a7763bfSjmcp 		if ((sym = dlsym(tmpplug->handle, "drivername"))
4035a7763bfSjmcp 		    != NULL) {
4045a7763bfSjmcp 			/* max length of drivername */
405c4800545Sjmcp 			tmpplug->drvname = calloc(1, MAXMODCONFNAME);
406c4800545Sjmcp 
407c4800545Sjmcp 			/* are we doing double-time? */
408c4800545Sjmcp 			if (strncmp((char *)sym, plugdir->d_name,
409c4800545Sjmcp 			    MAXMODCONFNAME) != 0) {
410c4800545Sjmcp 				char *tempnm = calloc(1, MAXMODCONFNAME);
411c4800545Sjmcp 
412d65b419eSXinChen 				(void) memcpy(tempnm, plugdir->d_name,
413d65b419eSXinChen 				    MAXMODCONFNAME);
414c4800545Sjmcp 				(void) strlcpy(tmpplug->drvname,
415c4800545Sjmcp 				    strtok(tempnm, "."),
416c4800545Sjmcp 				    strlen(plugdir->d_name) + 1);
417c4800545Sjmcp 				free(tempnm);
418c4800545Sjmcp 			} else {
419c4800545Sjmcp 				(void) strlcpy(tmpplug->drvname,
420c4800545Sjmcp 				    (char *)sym, strlen(sym) + 1);
421c4800545Sjmcp 			}
4225a7763bfSjmcp 		} else {
4235a7763bfSjmcp 			CLOSEFREE();
4245a7763bfSjmcp 			continue;
4255a7763bfSjmcp 		}
4265a7763bfSjmcp 		if ((sym = dlsym(tmpplug->handle, "fw_readfw"))
4275a7763bfSjmcp 		    != NULL) {
4285a7763bfSjmcp 			tmpplug->fw_readfw = (int (*)())sym;
4295a7763bfSjmcp 		} else {
4305a7763bfSjmcp 			CLOSEFREE();
4315a7763bfSjmcp 			continue;
4325a7763bfSjmcp 		}
4335a7763bfSjmcp 		if ((sym = dlsym(tmpplug->handle, "fw_writefw"))
4345a7763bfSjmcp 		    != NULL) {
4355a7763bfSjmcp 			tmpplug->fw_writefw = (int (*)())sym;
4365a7763bfSjmcp 		} else {
4375a7763bfSjmcp 			CLOSEFREE();
4385a7763bfSjmcp 			continue;
4395a7763bfSjmcp 		}
4405a7763bfSjmcp 
4415a7763bfSjmcp 		if ((sym = dlsym(tmpplug->handle, "fw_identify"))
4425a7763bfSjmcp 		    != NULL) {
4435a7763bfSjmcp 			tmpplug->fw_identify =
4445a7763bfSjmcp 			    (int (*)(int))sym;
4455a7763bfSjmcp 		} else {
4465a7763bfSjmcp 			CLOSEFREE();
4475a7763bfSjmcp 			continue;
4485a7763bfSjmcp 		}
4495a7763bfSjmcp 		if ((sym = dlsym(tmpplug->handle, "fw_devinfo"))
4505a7763bfSjmcp 		    != NULL) {
4515a7763bfSjmcp 			tmpplug->fw_devinfo =
4525a7763bfSjmcp 			    (int (*)(struct devicelist *))sym;
4535a7763bfSjmcp 		} else {
4545a7763bfSjmcp 			CLOSEFREE();
4555a7763bfSjmcp 			continue;
4565a7763bfSjmcp 		}
4575a7763bfSjmcp 
458d65b419eSXinChen 		if ((sym = dlsym(tmpplug->handle, "plugin_version"))
459d65b419eSXinChen 		    != NULL) {
460d65b419eSXinChen 			if ((*(int *)sym) >= FWPLUGIN_VERSION_2) {
461d65b419eSXinChen 				if ((sym = dlsym(tmpplug->handle,
462d65b419eSXinChen 				    "fw_cleanup")) != NULL) {
463d65b419eSXinChen 					tmpplug->fw_cleanup =
464d65b419eSXinChen 					    (void (*)(struct devicelist *))sym;
465d65b419eSXinChen 				} else {
466d65b419eSXinChen 					logmsg(MSG_ERROR,
467d65b419eSXinChen 					    gettext("ERROR: v2 plugin (%s) "
468d65b419eSXinChen 					    "has no fw_cleanup function\n"),
469d65b419eSXinChen 					    tmpplug->filename);
470d65b419eSXinChen 					CLOSEFREE();
471d65b419eSXinChen 					continue;
472d65b419eSXinChen 				}
473d65b419eSXinChen 			} else {
474d65b419eSXinChen 				logmsg(MSG_INFO,
475d65b419eSXinChen 				    "Identification plugin %s defined "
476d65b419eSXinChen 				    "plugin_version < FWPLUGIN_VERSION_2 !");
477d65b419eSXinChen 			}
478d65b419eSXinChen 		}
479d65b419eSXinChen 
480c4800545Sjmcp 		if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME))
4815a7763bfSjmcp 		    == NULL) {
4825a7763bfSjmcp 			logmsg(MSG_ERROR,
483c4800545Sjmcp 			    gettext("Unable to allocate space for a"
4845a7763bfSjmcp 			    "drivername %s\n"),
4855a7763bfSjmcp 			    tmpplug->drvname);
4865a7763bfSjmcp 			return (FWFLASH_FAILURE);
4875a7763bfSjmcp 		}
4885a7763bfSjmcp 
4895a7763bfSjmcp 		(void) strlcpy(tmpelem->drvname, tmpplug->drvname,
4905a7763bfSjmcp 		    strlen(tmpplug->drvname) + 1);
4915a7763bfSjmcp 
4925a7763bfSjmcp 		if ((tmpelem->filename = calloc(1,
4935a7763bfSjmcp 		    strlen(tmpplug->filename) + 1)) == NULL) {
4945a7763bfSjmcp 			logmsg(MSG_ERROR,
4955a7763bfSjmcp 			    gettext("Unable to allocate %d bytes for "
4965a7763bfSjmcp 			    "filename %s\n"),
4975a7763bfSjmcp 			    strlen(tmpplug->filename) + 1,
498c4800545Sjmcp 			    tmpplug->filename);
4995a7763bfSjmcp 			return (FWFLASH_FAILURE);
5005a7763bfSjmcp 		}
5015a7763bfSjmcp 
5025a7763bfSjmcp 		(void) strlcpy(tmpelem->filename, plugname,
5035a7763bfSjmcp 		    strlen(plugname) + 1);
5045a7763bfSjmcp 		tmpelem->plugin = tmpplug;
5055a7763bfSjmcp 
5065a7763bfSjmcp 		/* CONSTCOND */
5075a7763bfSjmcp 		TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin);
5085a7763bfSjmcp 	}
5095a7763bfSjmcp 
5105a7763bfSjmcp 	if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) {
5115a7763bfSjmcp 		return (FWFLASH_FAILURE);
5125a7763bfSjmcp 	}
5135a7763bfSjmcp 
5145a7763bfSjmcp 	if (errno != 0) {
5155a7763bfSjmcp 		logmsg(MSG_ERROR,
5165a7763bfSjmcp 		    gettext("Error reading directory entry in %s\n"),
5175a7763bfSjmcp 		    fwplugdirpath);
5185a7763bfSjmcp 		rval = errno;
5195a7763bfSjmcp 	}
5205a7763bfSjmcp 
521d65b419eSXinChen 	free(fwplugdirpath);
522d65b419eSXinChen 	free(plugdir);
5235a7763bfSjmcp 	(void) closedir(dirp);
5245a7763bfSjmcp 	return (rval);
5255a7763bfSjmcp }
5265a7763bfSjmcp 
5275a7763bfSjmcp /*
5285a7763bfSjmcp  * fwflash_load_verifier dlload()s the appropriate firmware image
5295a7763bfSjmcp  * verification plugin, and attaches the designated fwimg's fd to
5305a7763bfSjmcp  * the vrfyplugin structure so we only have to load the image in
5315a7763bfSjmcp  * one place.
5325a7763bfSjmcp  */
5335a7763bfSjmcp int
534f8bf33c3SShantkumar Hiremath fwflash_load_verifier(char *drv, char *vendorid, char *fwimg)
535f8bf33c3SShantkumar Hiremath {
5365a7763bfSjmcp 
5375a7763bfSjmcp 	int rv = FWFLASH_FAILURE;
5385a7763bfSjmcp 	int imgfd;
5395a7763bfSjmcp 	char *fwvrfydirpath, *tempdirpath, *filename;
5405a7763bfSjmcp 	char *clean; /* for the space-removed vid */
5415a7763bfSjmcp 	struct stat fwstat;
5425a7763bfSjmcp 	struct vrfyplugin *vrfy;
5435a7763bfSjmcp 	void *vrfysym;
5445a7763bfSjmcp 
5455a7763bfSjmcp 	/*
5465a7763bfSjmcp 	 * To make flashing multiple firmware images somewhat more
5475a7763bfSjmcp 	 * efficient, we start this function by checking whether a
5485a7763bfSjmcp 	 * verifier for this device has already been loaded. If it
5495a7763bfSjmcp 	 * has been loaded, we replace the imgfile information, and
5505a7763bfSjmcp 	 * then continue as if we were loading for the first time.
5515a7763bfSjmcp 	 */
5525a7763bfSjmcp 
5535a7763bfSjmcp 	if (verifier != NULL) {
5545a7763bfSjmcp 		verifier->imgsize = 0;
5555a7763bfSjmcp 		verifier->flashbuf = 0; /* set by the verifier function */
5565a7763bfSjmcp 
557d65b419eSXinChen 		if (verifier->imgfile != NULL) {
558d65b419eSXinChen 			free(verifier->imgfile);
559d65b419eSXinChen 			verifier->imgfile = NULL;
560d65b419eSXinChen 		}
5615a7763bfSjmcp 
562d65b419eSXinChen 		if (verifier->fwimage != NULL) {
563d65b419eSXinChen 			free(verifier->fwimage);
564d65b419eSXinChen 			verifier->fwimage = NULL;
565d65b419eSXinChen 		}
5665a7763bfSjmcp 	} else {
5675a7763bfSjmcp 		if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
5685a7763bfSjmcp 			logmsg(MSG_ERROR,
5695a7763bfSjmcp 			    gettext("Unable to allocate space for a firmware "
5705a7763bfSjmcp 			    "verifier file(1)"));
5715a7763bfSjmcp 			return (rv);
5725a7763bfSjmcp 		}
5735a7763bfSjmcp 
5745a7763bfSjmcp 		if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) {
5755a7763bfSjmcp 			logmsg(MSG_ERROR,
5765a7763bfSjmcp 			    gettext("Unable to allocate space "
5775a7763bfSjmcp 			    "for a firmware verifier file(2)"));
578d65b419eSXinChen 			free(fwvrfydirpath);
5795a7763bfSjmcp 			return (rv);
5805a7763bfSjmcp 		}
5815a7763bfSjmcp 
5825a7763bfSjmcp 		/*
583d65b419eSXinChen 		 * Since SCSI devices can have a vendor id of up to 8
584d65b419eSXinChen 		 * left-aligned and _space-padded_ characters, we first need to
585d65b419eSXinChen 		 * strip off any space characters before we try to make a
586d65b419eSXinChen 		 * filename out of it
5875a7763bfSjmcp 		 */
5885a7763bfSjmcp 		clean = strtok(vendorid, " ");
5895a7763bfSjmcp 		if (clean == NULL) {
5905a7763bfSjmcp 			/* invalid vendorid, something's really wrong */
5915a7763bfSjmcp 			logmsg(MSG_ERROR,
5925a7763bfSjmcp 			    gettext("Invalid vendorid (null) specified for "
5935a7763bfSjmcp 			    "device\n"));
594d65b419eSXinChen 			free(filename);
595d65b419eSXinChen 			free(fwvrfydirpath);
5965a7763bfSjmcp 			return (rv);
5975a7763bfSjmcp 		}
5985a7763bfSjmcp 
5995a7763bfSjmcp 		tempdirpath = getenv("FWVERIFYPLUGINDIR");
6005a7763bfSjmcp 
6015a7763bfSjmcp 		if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
6025a7763bfSjmcp 			(void) strlcpy(fwvrfydirpath, tempdirpath,
6035a7763bfSjmcp 			    strlen(tempdirpath) + 1);
6045a7763bfSjmcp 		} else {
6055a7763bfSjmcp 			(void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR,
6065a7763bfSjmcp 			    strlen(FWVERIFYPLUGINDIR) + 1);
6075a7763bfSjmcp 		}
6085a7763bfSjmcp 
6095a7763bfSjmcp 		if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) {
6105a7763bfSjmcp 			logmsg(MSG_ERROR,
6115a7763bfSjmcp 			    gettext("Unable to allocate space "
6125a7763bfSjmcp 			    "for a firmware verifier structure"));
6135a7763bfSjmcp 			free(filename);
6145a7763bfSjmcp 			free(fwvrfydirpath);
615d65b419eSXinChen 			return (rv);
6165a7763bfSjmcp 		}
6175a7763bfSjmcp 
6185a7763bfSjmcp 		errno = 0; /* false positive removal */
6195a7763bfSjmcp 
620d65b419eSXinChen 		(void) snprintf(filename, MAXPATHLEN, "%s/%s-%s.so",
6215a7763bfSjmcp 		    fwvrfydirpath, drv, clean);
622d65b419eSXinChen 		if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) {
623d65b419eSXinChen 			logmsg(MSG_INFO, gettext(dlerror()));
624d65b419eSXinChen 			logmsg(MSG_INFO,
625d65b419eSXinChen 			    gettext("\nUnable to open verification plugin "
626d65b419eSXinChen 			    "%s. Looking for %s-GENERIC plugin instead.\n"),
627d65b419eSXinChen 			    filename, drv);
628d65b419eSXinChen 
629d65b419eSXinChen 			/* Try the drv-GENERIC.so form, _then_ die */
630d65b419eSXinChen 			bzero(filename, strlen(filename) + 1);
631d65b419eSXinChen 			(void) snprintf(filename, MAXPATHLEN,
632d65b419eSXinChen 			    "%s/%s-GENERIC.so", fwvrfydirpath, drv);
633d65b419eSXinChen 
634d65b419eSXinChen 			if ((vrfy->handle = dlopen(filename, RTLD_NOW))
635d65b419eSXinChen 			    == NULL) {
636d65b419eSXinChen 				logmsg(MSG_INFO, gettext(dlerror()));
637d65b419eSXinChen 				logmsg(MSG_ERROR,
638d65b419eSXinChen 				    gettext("\nUnable to open either "
639d65b419eSXinChen 				    "verification plugin %s/%s-%s.so or "
640d65b419eSXinChen 				    "generic plugin %s.\nUnable to verify "
641d65b419eSXinChen 				    "firmware image. Aborting.\n"),
642d65b419eSXinChen 				    fwvrfydirpath, drv, clean, filename);
643d65b419eSXinChen 				free(filename);
644d65b419eSXinChen 				free(fwvrfydirpath);
645d65b419eSXinChen 				return (rv);
646d65b419eSXinChen 			}
647d65b419eSXinChen 		}
6485a7763bfSjmcp 
6495a7763bfSjmcp 		if ((vrfy->filename = calloc(1, strlen(filename) + 1))
6505a7763bfSjmcp 		    == NULL) {
6515a7763bfSjmcp 			logmsg(MSG_ERROR,
6525a7763bfSjmcp 			    gettext("Unable to allocate space to store "
6535a7763bfSjmcp 			    "a verifier filename\n"));
6545a7763bfSjmcp 			free(filename);
6555a7763bfSjmcp 			free(fwvrfydirpath);
6565a7763bfSjmcp 			free(vrfy->handle);
657d65b419eSXinChen 			return (rv);
6585a7763bfSjmcp 		}
6595a7763bfSjmcp 		(void) strlcpy(vrfy->filename, filename, strlen(filename) + 1);
6605a7763bfSjmcp 
6615a7763bfSjmcp 		if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) {
6625a7763bfSjmcp 			logmsg(MSG_ERROR,
6635a7763bfSjmcp 			    gettext("%s is an invalid firmware verification "
6645a7763bfSjmcp 			    "plugin."), filename);
6655a7763bfSjmcp 			(void) dlclose(vrfy->handle);
6665a7763bfSjmcp 			free(filename);
6675a7763bfSjmcp 			free(fwvrfydirpath);
6685a7763bfSjmcp 			free(vrfy);
669d65b419eSXinChen 			return (rv);
6705a7763bfSjmcp 		} else {
6715a7763bfSjmcp 			vrfy->vendorvrfy =
6725a7763bfSjmcp 			    (int (*)(struct devicelist *))vrfysym;
6735a7763bfSjmcp 		}
6745a7763bfSjmcp 
6755a7763bfSjmcp 		vrfysym = dlsym(vrfy->handle, "vendor");
6765a7763bfSjmcp 
6775a7763bfSjmcp 		if (vrfysym == NULL) {
6785a7763bfSjmcp 			logmsg(MSG_ERROR,
6795a7763bfSjmcp 			    gettext("Invalid vendor (null) in verification "
6805a7763bfSjmcp 			    "plugin %s\n"), filename);
6815a7763bfSjmcp 			(void) dlclose(vrfy->handle);
6825a7763bfSjmcp 			free(vrfy);
683d65b419eSXinChen 			return (rv);
6845a7763bfSjmcp 		} else {
6855a7763bfSjmcp 			if (strncmp(vendorid, (char *)vrfysym,
6865a7763bfSjmcp 			    strlen(vendorid)) != 0) {
6875a7763bfSjmcp 				logmsg(MSG_INFO,
6885a7763bfSjmcp 				    "Using a sym-linked (%s -> %s) "
689d65b419eSXinChen 				    "verification plugin\n",
6905a7763bfSjmcp 				    vendorid, vrfysym);
6915a7763bfSjmcp 				vrfy->vendor = calloc(1, strlen(vendorid) + 1);
6925a7763bfSjmcp 			} else {
6935a7763bfSjmcp 				vrfy->vendor = calloc(1, strlen(vrfysym) + 1);
6945a7763bfSjmcp 			}
6955a7763bfSjmcp 			(void) strlcpy(vrfy->vendor, (char *)vrfysym,
6965a7763bfSjmcp 			    strlen(vendorid) + 1);
6975a7763bfSjmcp 		}
6985a7763bfSjmcp 
6995a7763bfSjmcp 		verifier = vrfy; /* a convenience variable */
700d65b419eSXinChen 		free(filename);
701d65b419eSXinChen 		free(fwvrfydirpath);
7025a7763bfSjmcp 	}
7035a7763bfSjmcp 
7045a7763bfSjmcp 	/*
7055a7763bfSjmcp 	 * We don't do any verification that the fw image file is in
7065a7763bfSjmcp 	 * an approved location, but it's easy enough to modify this
7075a7763bfSjmcp 	 * function to do so. The verification plugin should provide
7085a7763bfSjmcp 	 * sufficient protection.
7095a7763bfSjmcp 	 */
7105a7763bfSjmcp 
7115a7763bfSjmcp 	if ((imgfd = open(fwimg, O_RDONLY)) < 0) {
7125a7763bfSjmcp 		logmsg(MSG_ERROR,
7135a7763bfSjmcp 		    gettext("Unable to open designated firmware "
7145a7763bfSjmcp 		    "image file %s: %s\n"),
7155a7763bfSjmcp 		    (fwimg != NULL) ? fwimg : "(null)",
7165a7763bfSjmcp 		    strerror(errno));
7175a7763bfSjmcp 		rv = FWFLASH_FAILURE;
7185a7763bfSjmcp 		goto cleanup;
7195a7763bfSjmcp 	}
7205a7763bfSjmcp 
7215a7763bfSjmcp 	if (stat(fwimg, &fwstat) == -1) {
7225a7763bfSjmcp 		logmsg(MSG_ERROR,
7235a7763bfSjmcp 		    gettext("Unable to stat() firmware image file "
7245a7763bfSjmcp 		    "%s: %s\n"),
7255a7763bfSjmcp 		    fwimg, strerror(errno));
7265a7763bfSjmcp 		rv = FWFLASH_FAILURE;
7275a7763bfSjmcp 		goto cleanup;
7285a7763bfSjmcp 	} else {
7295a7763bfSjmcp 		verifier->imgsize = fwstat.st_size;
7305a7763bfSjmcp 		if ((verifier->fwimage = calloc(1, verifier->imgsize))
7315a7763bfSjmcp 		    == NULL) {
7325a7763bfSjmcp 			logmsg(MSG_ERROR,
7335a7763bfSjmcp 			    gettext("Unable to load firmware image "
7345a7763bfSjmcp 			    "%s: %s\n"),
7355a7763bfSjmcp 			    fwimg, strerror(errno));
7365a7763bfSjmcp 			rv = FWFLASH_FAILURE;
7375a7763bfSjmcp 			goto cleanup;
7385a7763bfSjmcp 		}
7395a7763bfSjmcp 	}
7405a7763bfSjmcp 
7415a7763bfSjmcp 	errno = 0;
7425a7763bfSjmcp 	if ((rv = read(imgfd, verifier->fwimage,
7435a7763bfSjmcp 	    (size_t)verifier->imgsize)) < verifier->imgsize) {
7445a7763bfSjmcp 		/* we haven't read enough data, bail */
7455a7763bfSjmcp 		logmsg(MSG_ERROR,
7465a7763bfSjmcp 		    gettext("Failed to read sufficient data "
7475a7763bfSjmcp 		    "(got %d bytes, expected %d bytes) from "
7485a7763bfSjmcp 		    "firmware image file %s: %s\n"),
7495a7763bfSjmcp 		    rv, verifier->imgsize,
750d65b419eSXinChen 		    verifier->filename, strerror(errno));
7515a7763bfSjmcp 		rv = FWFLASH_FAILURE;
7525a7763bfSjmcp 	} else {
7535a7763bfSjmcp 		rv = FWFLASH_SUCCESS;
7545a7763bfSjmcp 	}
7555a7763bfSjmcp 
7565a7763bfSjmcp 	if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) {
7575a7763bfSjmcp 		logmsg(MSG_ERROR,
7585a7763bfSjmcp 		    gettext("Unable to save name of firmware image\n"));
7595a7763bfSjmcp 		rv = FWFLASH_FAILURE;
7605a7763bfSjmcp 	} else {
7615a7763bfSjmcp 		(void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1);
7625a7763bfSjmcp 	}
7635a7763bfSjmcp 
7645a7763bfSjmcp 	if (rv != FWFLASH_SUCCESS) {
7655a7763bfSjmcp 		/* cleanup and let's get outta here */
7665a7763bfSjmcp cleanup:
7675a7763bfSjmcp 		free(verifier->filename);
7685a7763bfSjmcp 		free(verifier->vendor);
7695a7763bfSjmcp 
770d65b419eSXinChen 		if (!(fwflash_arg_list & FWFLASH_READ_FLAG) &&
771d65b419eSXinChen 		    verifier->fwimage)
7725a7763bfSjmcp 			free(verifier->fwimage);
7735a7763bfSjmcp 
7745a7763bfSjmcp 		verifier->filename = NULL;
7755a7763bfSjmcp 		verifier->vendor = NULL;
7765a7763bfSjmcp 		verifier->vendorvrfy = NULL;
7775a7763bfSjmcp 		verifier->fwimage = NULL;
7785a7763bfSjmcp 		(void) dlclose(verifier->handle);
7795a7763bfSjmcp 		verifier->handle = NULL;
7805a7763bfSjmcp 		free(verifier);
7815a7763bfSjmcp 		if (imgfd >= 0) {
7825a7763bfSjmcp 			(void) close(imgfd);
7835a7763bfSjmcp 		}
7845a7763bfSjmcp 		verifier = NULL;
7855a7763bfSjmcp 	}
7865a7763bfSjmcp 
7875a7763bfSjmcp 	return (rv);
7885a7763bfSjmcp }
7895a7763bfSjmcp 
7905a7763bfSjmcp /*
7915a7763bfSjmcp  * cycles through the global list of plugins to find
7925a7763bfSjmcp  * each flashable device, which is added to fw_devices
7935a7763bfSjmcp  *
7945a7763bfSjmcp  * Each plugin's identify routine must allocated storage
7955a7763bfSjmcp  * as required.
7965a7763bfSjmcp  *
7975a7763bfSjmcp  * Each plugin's identify routine must return
7985a7763bfSjmcp  * FWFLASH_FAILURE if it cannot find any devices
7995a7763bfSjmcp  * which it handles.
8005a7763bfSjmcp  */
8015a7763bfSjmcp static int
8025a7763bfSjmcp flash_device_list()
8035a7763bfSjmcp {
8045a7763bfSjmcp 	int rv = FWFLASH_FAILURE;
8055a7763bfSjmcp 	int startidx = 0;
8065a7763bfSjmcp 	int sumrv = 0;
8075a7763bfSjmcp 	struct pluginlist *plugins;
8085a7763bfSjmcp 
8095a7763bfSjmcp 	/* we open rootnode here, and close it in fwflash_intr */
810d65b419eSXinChen 	if ((rootnode = di_init("/", DINFOCPYALL|DINFOFORCE)) == DI_NODE_NIL) {
8115a7763bfSjmcp 		logmsg(MSG_ERROR,
8125a7763bfSjmcp 		    gettext("Unable to take device tree snapshot: %s\n"),
8135a7763bfSjmcp 		    strerror(errno));
8145a7763bfSjmcp 		return (rv);
8155a7763bfSjmcp 	}
8165a7763bfSjmcp 
8175a7763bfSjmcp 	if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) {
8185a7763bfSjmcp 		logmsg(MSG_ERROR,
8195a7763bfSjmcp 		    gettext("Unable to malloc %d bytes while "
8205a7763bfSjmcp 		    "trying to find devices: %s\n"),
8215a7763bfSjmcp 		    sizeof (struct devicelist), strerror(errno));
8225a7763bfSjmcp 		return (FWFLASH_FAILURE);
8235a7763bfSjmcp 	}
8245a7763bfSjmcp 
8255a7763bfSjmcp 	/* CONSTCOND */
8265a7763bfSjmcp 	TAILQ_INIT(fw_devices);
8275a7763bfSjmcp 
8285a7763bfSjmcp 	TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) {
8295a7763bfSjmcp 		self = plugins->plugin;
8305a7763bfSjmcp 		rv = plugins->plugin->fw_identify(startidx);
8315a7763bfSjmcp 
8325a7763bfSjmcp 		logmsg(MSG_INFO,
8335a7763bfSjmcp 		    gettext("fwflash:flash_device_list() got %d from "
8345a7763bfSjmcp 		    "identify routine\n"), rv);
8355a7763bfSjmcp 
8365a7763bfSjmcp 		/* only bump startidx if we've found at least one device */
8375a7763bfSjmcp 		if (rv == FWFLASH_SUCCESS) {
8385a7763bfSjmcp 			startidx += 100;
8395a7763bfSjmcp 			sumrv++;
8405a7763bfSjmcp 		} else {
8415a7763bfSjmcp 			logmsg(MSG_INFO,
8425a7763bfSjmcp 			    gettext("No flashable devices attached with "
8435a7763bfSjmcp 			    "the %s driver in this system\n"),
8445a7763bfSjmcp 			    plugins->drvname);
8455a7763bfSjmcp 		}
8465a7763bfSjmcp 	}
8475a7763bfSjmcp 
8485a7763bfSjmcp 	if (sumrv > 0)
8495a7763bfSjmcp 		rv = FWFLASH_SUCCESS;
8505a7763bfSjmcp 
8515a7763bfSjmcp 	return (rv);
8525a7763bfSjmcp }
8535a7763bfSjmcp 
8545a7763bfSjmcp static int
8555a7763bfSjmcp fwflash_list_fw(char *class)
8565a7763bfSjmcp {
8575a7763bfSjmcp 	int rv = 0;
8585a7763bfSjmcp 	struct devicelist *curdev;
8595a7763bfSjmcp 	int header = 1;
8605a7763bfSjmcp 
8615a7763bfSjmcp 	TAILQ_FOREACH(curdev, fw_devices, nextdev) {
8625a7763bfSjmcp 
8635a7763bfSjmcp 		/* we're either class-conscious, or we're not */
8645a7763bfSjmcp 		if (((class != NULL) &&
8655a7763bfSjmcp 		    ((strncmp(curdev->classname, "ALL", 3) == 0) ||
8665a7763bfSjmcp 		    (strcmp(curdev->classname, class) == 0))) ||
8675a7763bfSjmcp 		    (class == NULL)) {
8685a7763bfSjmcp 
8695a7763bfSjmcp 			if (header != 0) {
8705a7763bfSjmcp 				(void) fprintf(stdout,
8715a7763bfSjmcp 				    gettext("List of available devices:\n"));
8725a7763bfSjmcp 				header--;
8735a7763bfSjmcp 			}
8745a7763bfSjmcp 			/*
8755a7763bfSjmcp 			 * If any plugin's fw_devinfo() function returns
8765a7763bfSjmcp 			 * FWFLASH_FAILURE then we want to keep track of
8775a7763bfSjmcp 			 * it. _Most_ plugins should always return
8785a7763bfSjmcp 			 * FWFLASH_SUCCESS from this function. The only
8795a7763bfSjmcp 			 * exception known at this point is the tavor plugin.
8805a7763bfSjmcp 			 */
8815a7763bfSjmcp 			rv += curdev->plugin->fw_devinfo(curdev);
8825a7763bfSjmcp 		}
8835a7763bfSjmcp 	}
8845a7763bfSjmcp 	return (rv);
8855a7763bfSjmcp }
8865a7763bfSjmcp 
8875a7763bfSjmcp static int
888f1c23465SJames C. McPherson fwflash_update(char *device, char *filename, int flags)
889f1c23465SJames C. McPherson {
8905a7763bfSjmcp 
8915a7763bfSjmcp 	int rv = FWFLASH_FAILURE;
8925a7763bfSjmcp 	int needsfree = 0;
893c4800545Sjmcp 	int found = 0;
8945a7763bfSjmcp 	struct devicelist *curdev;
8955a7763bfSjmcp 	char *realfile;
8965a7763bfSjmcp 
8975a7763bfSjmcp 	/*
8985a7763bfSjmcp 	 * Here's how we operate:
8995a7763bfSjmcp 	 *
9005a7763bfSjmcp 	 * We perform some basic checks on the args, then walk
9015a7763bfSjmcp 	 * through the device list looking for the device which
9025a7763bfSjmcp 	 * matches. We then load the appropriate verifier for the
9035a7763bfSjmcp 	 * image file and device, verify the image, then call the
9045a7763bfSjmcp 	 * fw_writefw() function of the appropriate plugin.
9055a7763bfSjmcp 	 *
9065a7763bfSjmcp 	 * There is no "force" flag to enable you to flash a firmware
9075a7763bfSjmcp 	 * image onto an incompatible device because the verifier
9085a7763bfSjmcp 	 * will return FWFLASH_FAILURE if the image doesn't match.
9095a7763bfSjmcp 	 */
9105a7763bfSjmcp 
9115a7763bfSjmcp 	/* new firmware filename and device desc */
9125a7763bfSjmcp 	if (filename == NULL) {
9135a7763bfSjmcp 		logmsg(MSG_ERROR,
9145a7763bfSjmcp 		    gettext("Invalid firmware filename (null)\n"));
9155a7763bfSjmcp 		return (FWFLASH_FAILURE);
9165a7763bfSjmcp 	}
9175a7763bfSjmcp 
9185a7763bfSjmcp 	if (device == NULL) {
9195a7763bfSjmcp 		logmsg(MSG_ERROR,
9205a7763bfSjmcp 		    gettext("Invalid device requested (null)\n"));
9215a7763bfSjmcp 		return (FWFLASH_FAILURE);
9225a7763bfSjmcp 	}
9235a7763bfSjmcp 
9245a7763bfSjmcp 	if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) {
9255a7763bfSjmcp 		logmsg(MSG_ERROR,
9265a7763bfSjmcp 		    gettext("Unable to allocate space for device "
927c4800545Sjmcp 		    "filename, operation might fail if %s is"
9285a7763bfSjmcp 		    "a symbolic link\n"),
9295a7763bfSjmcp 		    device);
9305a7763bfSjmcp 		realfile = device;
9315a7763bfSjmcp 	} else {
9325a7763bfSjmcp 		/*
9335a7763bfSjmcp 		 * If realpath() succeeds, then we have a valid
9345a7763bfSjmcp 		 * device filename in realfile.
9355a7763bfSjmcp 		 */
9365a7763bfSjmcp 		if (realpath(device, realfile) == NULL) {
9375a7763bfSjmcp 			logmsg(MSG_ERROR,
9385a7763bfSjmcp 			    gettext("Unable to resolve device filename"
9395a7763bfSjmcp 			    ": %s\n"),
9405a7763bfSjmcp 			    strerror(errno));
9415a7763bfSjmcp 			/* tidy up */
9425a7763bfSjmcp 			free(realfile);
9435a7763bfSjmcp 			/* realpath didn't succeed, use fallback */
9445a7763bfSjmcp 			realfile = device;
9455a7763bfSjmcp 		} else {
9465a7763bfSjmcp 			needsfree = 1;
9475a7763bfSjmcp 		}
9485a7763bfSjmcp 	}
9495a7763bfSjmcp 
9505a7763bfSjmcp 	logmsg(MSG_INFO,
9515a7763bfSjmcp 	    gettext("fwflash_update: fw_filename (%s) device (%s)\n"),
9525a7763bfSjmcp 	    filename, device);
9535a7763bfSjmcp 
9545a7763bfSjmcp 	TAILQ_FOREACH(curdev, fw_devices, nextdev) {
9555a7763bfSjmcp 		if (strcmp(curdev->access_devname, realfile) == 0) {
956c4800545Sjmcp 			found++;
9575a7763bfSjmcp 			rv = fwflash_load_verifier(curdev->drvname,
9585a7763bfSjmcp 			    curdev->ident->vid, filename);
9595a7763bfSjmcp 			if (rv == FWFLASH_FAILURE) {
9605a7763bfSjmcp 				logmsg(MSG_ERROR,
9615a7763bfSjmcp 				    gettext("Unable to load verifier "
9625a7763bfSjmcp 				    "for device %s\n"),
9635a7763bfSjmcp 				    curdev->access_devname);
9645a7763bfSjmcp 				return (FWFLASH_FAILURE);
9655a7763bfSjmcp 			}
9665a7763bfSjmcp 			rv = verifier->vendorvrfy(curdev);
9675a7763bfSjmcp 			if (rv == FWFLASH_FAILURE) {
9685a7763bfSjmcp 				/* the verifier prints a message */
9695a7763bfSjmcp 				logmsg(MSG_INFO,
9705a7763bfSjmcp 				    "verifier (%s) for %s :: %s returned "
9715a7763bfSjmcp 				    "FWFLASH_FAILURE\n",
9725a7763bfSjmcp 				    verifier->filename,
9735a7763bfSjmcp 				    filename, curdev->access_devname);
9745a7763bfSjmcp 				return (rv);
9755a7763bfSjmcp 			}
9765a7763bfSjmcp 
977f1c23465SJames C. McPherson 			if (((flags & FWFLASH_YES_FLAG) == FWFLASH_YES_FLAG) ||
9785a7763bfSjmcp 			    (rv = confirm_target(curdev, filename)) ==
9795a7763bfSjmcp 			    FWFLASH_YES_FLAG) {
9805a7763bfSjmcp 				logmsg(MSG_INFO,
9815a7763bfSjmcp 				    "about to flash using plugin %s\n",
9825a7763bfSjmcp 				    curdev->plugin->filename);
9835a7763bfSjmcp 				rv = curdev->plugin->fw_writefw(curdev,
9845a7763bfSjmcp 				    filename);
9855a7763bfSjmcp 				if (rv == FWFLASH_FAILURE) {
9865a7763bfSjmcp 					logmsg(MSG_ERROR,
9875a7763bfSjmcp 					    gettext("Failed to flash "
9885a7763bfSjmcp 					    "firmware file %s on "
9895a7763bfSjmcp 					    "device %s: %d\n"),
9905a7763bfSjmcp 					    filename,
9915a7763bfSjmcp 					    curdev->access_devname, rv);
9925a7763bfSjmcp 				}
9935a7763bfSjmcp 			} else {
9945a7763bfSjmcp 				logmsg(MSG_ERROR,
9955a7763bfSjmcp 				    gettext("Flash operation not confirmed "
9965a7763bfSjmcp 				    "by user\n"),
9975a7763bfSjmcp 				    curdev->access_devname);
9985a7763bfSjmcp 				rv = FWFLASH_FAILURE;
9995a7763bfSjmcp 			}
10005a7763bfSjmcp 		}
10015a7763bfSjmcp 	}
10025a7763bfSjmcp 
1003c4800545Sjmcp 	if (!found)
1004c4800545Sjmcp 		/* report the same device that the user passed in */
1005c4800545Sjmcp 		logmsg(MSG_ERROR,
1006c4800545Sjmcp 		    gettext("Device %s does not appear "
1007c4800545Sjmcp 		    "to be flashable\n"),
1008c4800545Sjmcp 		    ((strncmp(device, realfile, strlen(device)) == 0) ?
1009d65b419eSXinChen 		    realfile : device));
1010c4800545Sjmcp 
10115a7763bfSjmcp 	if (needsfree)
10125a7763bfSjmcp 		free(realfile);
10135a7763bfSjmcp 
10145a7763bfSjmcp 	return (rv);
10155a7763bfSjmcp }
10165a7763bfSjmcp 
10175a7763bfSjmcp /*
10185a7763bfSjmcp  * We validate that the device path is in our global device list and
10195a7763bfSjmcp  * that the filename exists, then palm things off to the relevant plugin.
10205a7763bfSjmcp  */
10215a7763bfSjmcp static int
10225a7763bfSjmcp fwflash_read_file(char *device, char *filename)
10235a7763bfSjmcp {
10245a7763bfSjmcp 	struct devicelist *curdev;
10255a7763bfSjmcp 	int rv;
1026f8bf33c3SShantkumar Hiremath 	int found = 0;
10275a7763bfSjmcp 
10285a7763bfSjmcp 	/* new firmware filename and device desc */
10295a7763bfSjmcp 
10305a7763bfSjmcp 	TAILQ_FOREACH(curdev, fw_devices, nextdev) {
10315a7763bfSjmcp 		if (strncmp(curdev->access_devname, device,
10325a7763bfSjmcp 		    MAXPATHLEN) == 0) {
10335a7763bfSjmcp 			rv = curdev->plugin->fw_readfw(curdev, filename);
10345a7763bfSjmcp 
10355a7763bfSjmcp 			if (rv != FWFLASH_SUCCESS)
10365a7763bfSjmcp 				logmsg(MSG_ERROR,
10375a7763bfSjmcp 				    gettext("Unable to write out firmware "
10385a7763bfSjmcp 				    "image for %s to file %s\n"),
10395a7763bfSjmcp 				    curdev->access_devname, filename);
1040f8bf33c3SShantkumar Hiremath 			found++;
10415a7763bfSjmcp 		}
10425a7763bfSjmcp 
10435a7763bfSjmcp 	}
1044f8bf33c3SShantkumar Hiremath 
1045f8bf33c3SShantkumar Hiremath 	if (!found) {
10465a7763bfSjmcp 		logmsg(MSG_ERROR,
10475a7763bfSjmcp 		    gettext("No device matching %s was found.\n"),
10485a7763bfSjmcp 		    device);
10495a7763bfSjmcp 		rv = FWFLASH_FAILURE;
10505a7763bfSjmcp 	}
10515a7763bfSjmcp 
10525a7763bfSjmcp 	return (rv);
10535a7763bfSjmcp }
10545a7763bfSjmcp 
10555a7763bfSjmcp static void
10565a7763bfSjmcp fwflash_usage(char *arg)
10575a7763bfSjmcp {
10585a7763bfSjmcp 
10595a7763bfSjmcp 	(void) fprintf(stderr, "\n");
10605a7763bfSjmcp 	if (arg != NULL) {
10615a7763bfSjmcp 		logmsg(MSG_ERROR,
10625a7763bfSjmcp 		    gettext("Invalid argument (%s) supplied\n"), arg);
10635a7763bfSjmcp 	}
10645a7763bfSjmcp 
10655a7763bfSjmcp 	(void) fprintf(stderr, "\n");
10665a7763bfSjmcp 
10675a7763bfSjmcp 	(void) fprintf(stdout, gettext("Usage:\n\t"));
10685a7763bfSjmcp 	(void) fprintf(stdout, gettext("fwflash [-l [-c device_class "
10695a7763bfSjmcp 	    "| ALL]] | [-v] | [-h]\n\t"));
10705a7763bfSjmcp 	(void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3"
10715a7763bfSjmcp 	    ",... | -r file] [-y] -d device_path\n\n"));
10725a7763bfSjmcp 	(void) fprintf(stdout, "\n"); /* workaround for xgettext */
10735a7763bfSjmcp 
10745a7763bfSjmcp 	(void) fprintf(stdout,
10755a7763bfSjmcp 	    gettext("\t-l\t\tlist flashable devices in this system\n"
10765a7763bfSjmcp 	    "\t-c device_class limit search to a specific class\n"
10775a7763bfSjmcp 	    "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n"
10785a7763bfSjmcp 	    "\t-v\t\tprint version number of fwflash utility\n"
1079f8bf33c3SShantkumar Hiremath 	    "\t-h\t\tprint this usage message\n\n"));
10805a7763bfSjmcp 	(void) fprintf(stdout,
10815a7763bfSjmcp 	    gettext("\t-f file1,file2,file3,...\n"
10825a7763bfSjmcp 	    "\t\t\tfirmware image file list to flash\n"
10835a7763bfSjmcp 	    "\t-r file\t\tfile to dump device firmware to\n"
10845a7763bfSjmcp 	    "\t-y\t\tanswer Yes/Y/y to prompts\n"
10855a7763bfSjmcp 	    "\t-d device_path\tpathname of device to be flashed\n\n"));
10865a7763bfSjmcp 
10875a7763bfSjmcp 	(void) fprintf(stdout,
10885a7763bfSjmcp 	    gettext("\tIf -d device_path is specified, then one of -f "
10895a7763bfSjmcp 	    "<files>\n"
10905a7763bfSjmcp 	    "\tor -r <file> must also be specified\n\n"));
10915a7763bfSjmcp 
10925a7763bfSjmcp 	(void) fprintf(stdout,
10935a7763bfSjmcp 	    gettext("\tIf multiple firmware images are required to be "
10945a7763bfSjmcp 	    "flashed\n"
10955a7763bfSjmcp 	    "\tthey must be listed together, separated by commas. The\n"
10965a7763bfSjmcp 	    "\timages will be flashed in the order specified.\n\n"));
10975a7763bfSjmcp 
10985a7763bfSjmcp 	(void) fprintf(stdout, "\n");
10995a7763bfSjmcp }
11005a7763bfSjmcp 
11015a7763bfSjmcp static void
11025a7763bfSjmcp fwflash_version(void)
11035a7763bfSjmcp {
11045a7763bfSjmcp 	(void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME);
11055a7763bfSjmcp 	(void) fprintf(stdout, gettext("version %s\n"),
11065a7763bfSjmcp 	    FWFLASH_VERSION);
11075a7763bfSjmcp }
11085a7763bfSjmcp 
11095a7763bfSjmcp static void
11105a7763bfSjmcp fwflash_intr(int sig)
11115a7763bfSjmcp {
11125a7763bfSjmcp 
11135a7763bfSjmcp 	struct devicelist *thisdev;
11145a7763bfSjmcp 	struct pluginlist *thisplug;
11155a7763bfSjmcp 
11165a7763bfSjmcp 	(void) signal(SIGINT, SIG_IGN);
11175a7763bfSjmcp 	(void) signal(SIGTERM, SIG_IGN);
1118c4800545Sjmcp 	(void) signal(SIGABRT, SIG_IGN);
1119d65b419eSXinChen 
11205a7763bfSjmcp 	if (fwflash_in_write) {
11215a7763bfSjmcp 		(void) fprintf(stderr,
11225a7763bfSjmcp 		    gettext("WARNING: firmware image may be corrupted\n\t"));
11235a7763bfSjmcp 		(void) fprintf(stderr,
11245a7763bfSjmcp 		    gettext("Reflash firmware before rebooting!\n"));
11255a7763bfSjmcp 	}
11265a7763bfSjmcp 
11275a7763bfSjmcp 	if (sig > 0) {
11285a7763bfSjmcp 		(void) logmsg(MSG_ERROR, gettext("\n"));
11295a7763bfSjmcp 		(void) logmsg(MSG_ERROR,
11305a7763bfSjmcp 		    gettext("fwflash exiting due to signal (%d)\n"), sig);
11315a7763bfSjmcp 	}
11325a7763bfSjmcp 
11335a7763bfSjmcp 	/*
11345a7763bfSjmcp 	 * we need to close everything down properly, so
11355a7763bfSjmcp 	 * call the plugin closure routines
11365a7763bfSjmcp 	 */
11375a7763bfSjmcp 	if (fw_devices != NULL) {
11385a7763bfSjmcp 		TAILQ_FOREACH(thisdev, fw_devices, nextdev) {
1139d65b419eSXinChen 			if (thisdev->plugin->fw_cleanup != NULL) {
1140d65b419eSXinChen 				/*
1141d65b419eSXinChen 				 * If we've got a cleanup routine, it
1142d65b419eSXinChen 				 * cleans up _everything_ for thisdev
1143d65b419eSXinChen 				 */
1144d65b419eSXinChen 				thisdev->plugin->fw_cleanup(thisdev);
1145d65b419eSXinChen 			} else {
11465a7763bfSjmcp 				/* free the components first */
11475a7763bfSjmcp 				free(thisdev->access_devname);
11485a7763bfSjmcp 				free(thisdev->drvname);
11495a7763bfSjmcp 				free(thisdev->classname);
1150c4800545Sjmcp 				if (thisdev->ident != NULL)
11515a7763bfSjmcp 					free(thisdev->ident);
1152d65b419eSXinChen 				/* We don't free address[] for old plugins */
11535a7763bfSjmcp 				thisdev->ident = NULL;
1154d65b419eSXinChen 				thisdev->plugin = NULL;
1155d65b419eSXinChen 			}
11565a7763bfSjmcp 			/* CONSTCOND */
11575a7763bfSjmcp 			TAILQ_REMOVE(fw_devices, thisdev, nextdev);
11585a7763bfSjmcp 		}
11595a7763bfSjmcp 	}
11605a7763bfSjmcp 
11615a7763bfSjmcp 	if (fw_pluginlist != NULL) {
11625a7763bfSjmcp 		TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) {
11635a7763bfSjmcp 			free(thisplug->filename);
11645a7763bfSjmcp 			free(thisplug->drvname);
11655a7763bfSjmcp 			free(thisplug->plugin->filename);
11665a7763bfSjmcp 			free(thisplug->plugin->drvname);
11675a7763bfSjmcp 			thisplug->filename = NULL;
11685a7763bfSjmcp 			thisplug->drvname = NULL;
11695a7763bfSjmcp 			thisplug->plugin->filename = NULL;
11705a7763bfSjmcp 			thisplug->plugin->drvname = NULL;
11715a7763bfSjmcp 			thisplug->plugin->fw_readfw = NULL;
11725a7763bfSjmcp 			thisplug->plugin->fw_writefw = NULL;
11735a7763bfSjmcp 			thisplug->plugin->fw_identify = NULL;
11745a7763bfSjmcp 			thisplug->plugin->fw_devinfo = NULL;
1175d65b419eSXinChen 			thisplug->plugin->fw_cleanup = NULL;
11765a7763bfSjmcp 			(void) dlclose(thisplug->plugin->handle);
11775a7763bfSjmcp 			thisplug->plugin->handle = NULL;
11785a7763bfSjmcp 			free(thisplug->plugin);
11795a7763bfSjmcp 			thisplug->plugin = NULL;
11805a7763bfSjmcp 			/* CONSTCOND */
11815a7763bfSjmcp 			TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin);
11825a7763bfSjmcp 		}
11835a7763bfSjmcp 	}
11845a7763bfSjmcp 
11855a7763bfSjmcp 	if (verifier != NULL) {
11865a7763bfSjmcp 		free(verifier->filename);
11875a7763bfSjmcp 		free(verifier->vendor);
1188c4800545Sjmcp 		free(verifier->imgfile);
1189c4800545Sjmcp 		free(verifier->fwimage);
11905a7763bfSjmcp 		verifier->filename = NULL;
11915a7763bfSjmcp 		verifier->vendor = NULL;
11925a7763bfSjmcp 		verifier->vendorvrfy = NULL;
1193c4800545Sjmcp 		verifier->imgfile = NULL;
1194c4800545Sjmcp 		verifier->fwimage = NULL;
11955a7763bfSjmcp 		(void) dlclose(verifier->handle);
11965a7763bfSjmcp 		verifier->handle = NULL;
11975a7763bfSjmcp 		free(verifier);
11985a7763bfSjmcp 	}
11995a7763bfSjmcp 	di_fini(rootnode);
1200d65b419eSXinChen 
1201d65b419eSXinChen 	if (sig > 0)
1202d65b419eSXinChen 		exit(FWFLASH_FAILURE);
12035a7763bfSjmcp }
12045a7763bfSjmcp 
12055a7763bfSjmcp static void
12065a7763bfSjmcp fwflash_handle_signals(void)
12075a7763bfSjmcp {
12085a7763bfSjmcp 	if (signal(SIGINT, fwflash_intr) == SIG_ERR) {
12095a7763bfSjmcp 		perror("signal");
12105a7763bfSjmcp 		exit(FWFLASH_FAILURE);
12115a7763bfSjmcp 	}
12125a7763bfSjmcp 
12135a7763bfSjmcp 	if (signal(SIGTERM, fwflash_intr) == SIG_ERR) {
12145a7763bfSjmcp 		perror("signal");
12155a7763bfSjmcp 		exit(FWFLASH_FAILURE);
12165a7763bfSjmcp 	}
12175a7763bfSjmcp }
12185a7763bfSjmcp 
12195a7763bfSjmcp static int
12205a7763bfSjmcp confirm_target(struct devicelist *thisdev, char *file)
12215a7763bfSjmcp {
12225a7763bfSjmcp 	int resp;
12235a7763bfSjmcp 
1224c4800545Sjmcp 	(void) fflush(stdin);
1225c4800545Sjmcp 	(void) printf(gettext("About to update firmware on %s\n"),
1226c4800545Sjmcp 	    thisdev->access_devname);
1227d65b419eSXinChen 	(void) printf(gettext("with file %s.\n"
1228d65b419eSXinChen 	    "Do you want to continue? (Y/N): "), file);
12295a7763bfSjmcp 
12305a7763bfSjmcp 	resp = getchar();
12315a7763bfSjmcp 	if (resp == 'Y' || resp == 'y') {
12325a7763bfSjmcp 		return (FWFLASH_YES_FLAG);
12335a7763bfSjmcp 	} else {
12345a7763bfSjmcp 		logmsg(MSG_INFO, "flash operation NOT confirmed.\n");
12355a7763bfSjmcp 	}
12365a7763bfSjmcp 
12375a7763bfSjmcp 	(void) fflush(stdin);
12385a7763bfSjmcp 	return (FWFLASH_FAILURE);
12395a7763bfSjmcp }
12405a7763bfSjmcp 
12415a7763bfSjmcp int
12425a7763bfSjmcp get_fileopts(char *options)
12435a7763bfSjmcp {
12445a7763bfSjmcp 
12455a7763bfSjmcp 	int i;
12465a7763bfSjmcp 	char *files;
12475a7763bfSjmcp 
12485a7763bfSjmcp 	if (files = strtok(options, ",")) {
12495a7763bfSjmcp 		/* we have more than one */
12505a7763bfSjmcp 		if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == 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[0], files, strlen(files) + 1);
12575a7763bfSjmcp 		i = 1;
12585a7763bfSjmcp 
12595a7763bfSjmcp 		logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
12605a7763bfSjmcp 		    filelist[0]);
12615a7763bfSjmcp 
12625a7763bfSjmcp 
12635a7763bfSjmcp 		while (files = strtok(NULL, ",")) {
12645a7763bfSjmcp 			if ((filelist[i] = calloc(1, MAXPATHLEN + 1))
12655a7763bfSjmcp 			    == NULL) {
12665a7763bfSjmcp 				logmsg(MSG_ERROR,
12675a7763bfSjmcp 				    gettext("Unable to allocate space for "
12685a7763bfSjmcp 				    "a firmware image filename\n"));
12695a7763bfSjmcp 				return (FWFLASH_FAILURE);
12705a7763bfSjmcp 			}
12715a7763bfSjmcp 			(void) strlcpy(filelist[i], files,
12725a7763bfSjmcp 			    strlen(files) + 1);
12735a7763bfSjmcp 			logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n",
12745a7763bfSjmcp 			    i, filelist[i]);
12755a7763bfSjmcp 			++i;
12765a7763bfSjmcp 		}
12775a7763bfSjmcp 	} else {
12785a7763bfSjmcp 		if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
12795a7763bfSjmcp 			logmsg(MSG_ERROR,
12805a7763bfSjmcp 			    gettext("Unable to allocate space for "
12815a7763bfSjmcp 			    "a firmware image filename\n"));
12825a7763bfSjmcp 			return (FWFLASH_FAILURE);
12835a7763bfSjmcp 		}
12845a7763bfSjmcp 		(void) strlcpy(filelist[0], options, strlen(files) + 1);
12855a7763bfSjmcp 		logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
12865a7763bfSjmcp 		    filelist[0]);
12875a7763bfSjmcp 	}
12885a7763bfSjmcp 	return (FWFLASH_SUCCESS);
12895a7763bfSjmcp }
12905a7763bfSjmcp 
12915a7763bfSjmcp /*
12925a7763bfSjmcp  * code reuse - cheerfully borrowed from stmsboot_util.c
12935a7763bfSjmcp  */
12945a7763bfSjmcp void
1295d65b419eSXinChen logmsg(int severity, const char *msg, ...)
1296d65b419eSXinChen {
12975a7763bfSjmcp 	va_list ap;
12985a7763bfSjmcp 
12995a7763bfSjmcp 	if ((severity > MSG_INFO) ||
13005a7763bfSjmcp 	    ((severity == MSG_INFO) && (fwflash_debug > 0))) {
13015a7763bfSjmcp 		(void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME);
13025a7763bfSjmcp 		va_start(ap, msg);
13035a7763bfSjmcp 		(void) vfprintf(stderr, msg, ap);
13045a7763bfSjmcp 		va_end(ap);
13055a7763bfSjmcp 	}
13065a7763bfSjmcp }
1307