16489Sjmcp /*
26489Sjmcp  * CDDL HEADER START
36489Sjmcp  *
46489Sjmcp  * The contents of this file are subject to the terms of the
56489Sjmcp  * Common Development and Distribution License (the "License").
66489Sjmcp  * You may not use this file except in compliance with the License.
76489Sjmcp  *
86489Sjmcp  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96489Sjmcp  * or http://www.opensolaris.org/os/licensing.
106489Sjmcp  * See the License for the specific language governing permissions
116489Sjmcp  * and limitations under the License.
126489Sjmcp  *
136489Sjmcp  * When distributing Covered Code, include this CDDL HEADER in each
146489Sjmcp  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156489Sjmcp  * If applicable, add the following below this CDDL HEADER, with the
166489Sjmcp  * fields enclosed by brackets "[]" replaced with your own identifying
176489Sjmcp  * information: Portions Copyright [yyyy] [name of copyright owner]
186489Sjmcp  *
196489Sjmcp  * CDDL HEADER END
206489Sjmcp  */
216489Sjmcp /*
229560SPei-Hong.Huang@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
236489Sjmcp  * Use is subject to license terms.
246489Sjmcp  */
256489Sjmcp 
266489Sjmcp /*
276489Sjmcp  * fwflash.c
286489Sjmcp  */
296489Sjmcp #include <stdio.h>
306489Sjmcp #include <stdlib.h>
316489Sjmcp #include <unistd.h>
326489Sjmcp #include <strings.h>
336489Sjmcp #include <errno.h>
346489Sjmcp #include <sys/queue.h>
356489Sjmcp #include <signal.h>
366489Sjmcp #include <locale.h>
376489Sjmcp #include <sys/stat.h>
386489Sjmcp #include <sys/types.h>
396489Sjmcp #include <sys/param.h>
406489Sjmcp #include <fcntl.h>
416489Sjmcp #include <dlfcn.h>
426489Sjmcp #include <dirent.h>
436489Sjmcp #include <sys/varargs.h>
446489Sjmcp #include <libintl.h> /* for gettext(3c) */
456489Sjmcp #include <libdevinfo.h>
469862SSherry.Moore@Sun.COM #include <libscf_priv.h>
476489Sjmcp #include <fwflash/fwflash.h>
486846Sjmcp #include <sys/modctl.h> /* for MAXMODCONFNAME */
496489Sjmcp 
506489Sjmcp 
516489Sjmcp #if !defined(lint)
526489Sjmcp /* embedded software license agreement */
536489Sjmcp static char *sla [] = { "Copyright 2007 Sun Microsystems, Inc., 4150 Network "
546489Sjmcp "Circle, Santa Clara, California 95054, U.S.A. All rights reserved. U.S. "
556489Sjmcp "Government Rights - Commercial software.  Government users are subject to the "
566489Sjmcp "Sun Microsystems, Inc. standard license agreement and applicable provisions "
576489Sjmcp "of the FAR and its supplements.  Use is subject to license terms.  Parts of "
586489Sjmcp "the product may be derived from Berkeley BSD systems, licensed from the "
596489Sjmcp "University of California. UNIX is a registered trademark in the U.S. and in "
606489Sjmcp "other countries, exclusively licensed through X/Open Company, Ltd.Sun, Sun "
616489Sjmcp "Microsystems, the Sun logo and Solaris are trademarks or registered "
626489Sjmcp "trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This "
636489Sjmcp "product is covered and controlled by U.S. Export Control laws and may be "
646489Sjmcp "subject to the export or import laws in other countries.  Nuclear, missile, "
656489Sjmcp "chemical biological weapons or nuclear maritime end uses or end users, "
666489Sjmcp "whether direct or indirect, are strictly prohibited.  Export or reexport "
676489Sjmcp "to countries subject to U.S. embargo or to entities identified on U.S. export "
686489Sjmcp "exclusion lists, including, but not limited to, the denied persons and "
696489Sjmcp "specially designated nationals lists is strictly prohibited." };
706489Sjmcp #endif	/* lint */
716489Sjmcp 
726489Sjmcp /* global arg list */
736489Sjmcp int	fwflash_arg_list = 0;
746489Sjmcp char	*filelist[10];
756489Sjmcp 
76*10507SPei-Hong.Huang@Sun.COM /* exposed global args */
77*10507SPei-Hong.Huang@Sun.COM di_node_t rootnode;
78*10507SPei-Hong.Huang@Sun.COM struct PLUGINLIST *fw_pluginlist;
79*10507SPei-Hong.Huang@Sun.COM struct DEVICELIST *fw_devices;
80*10507SPei-Hong.Huang@Sun.COM struct vrfyplugin *verifier;
81*10507SPei-Hong.Huang@Sun.COM struct fw_plugin *self;
82*10507SPei-Hong.Huang@Sun.COM int fwflash_debug = 0;
83*10507SPei-Hong.Huang@Sun.COM 
846489Sjmcp /* are we writing to flash? */
856489Sjmcp static int fwflash_in_write = 0;
866489Sjmcp 
876489Sjmcp /*
886489Sjmcp  * If we *must* track the version string for fwflash, then
896489Sjmcp  * we should do so in this common file rather than the header
906489Sjmcp  * file since it will then be in sync with what the customer
917317SJames.McPherson@Sun.COM  * sees. We should deprecate the "-v" option since it is not
927317SJames.McPherson@Sun.COM  * actually of any use - it doesn't line up with Mercurial's
937317SJames.McPherson@Sun.COM  * concept of the changeset.
946489Sjmcp  */
959683SXin.Chen@Sun.COM #define	FWFLASH_VERSION		"v1.8"
966489Sjmcp #define	FWFLASH_PROG_NAME	"fwflash"
976489Sjmcp 
986489Sjmcp static int get_fileopts(char *options);
996489Sjmcp static int flash_device_list();
1006489Sjmcp static int flash_load_plugins();
1016489Sjmcp static int fwflash_update(char *device, char *filename, int flags);
1026489Sjmcp static int fwflash_read_file(char *device, char *filename);
1036489Sjmcp static int fwflash_list_fw(char *class);
1046489Sjmcp static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg);
1056489Sjmcp static void fwflash_intr(int sig);
1066489Sjmcp static void fwflash_handle_signals(void);
1077317SJames.McPherson@Sun.COM static void fwflash_usage(char *arg);
1086489Sjmcp static void fwflash_version(void);
1096489Sjmcp static int confirm_target(struct devicelist *thisdev, char *file);
1106489Sjmcp 
1116489Sjmcp /*
1126489Sjmcp  * FWFlash main code
1136489Sjmcp  */
1146489Sjmcp int
1158031SShantkumar.Hiremath@Sun.COM main(int argc, char **argv)
1168031SShantkumar.Hiremath@Sun.COM {
1176489Sjmcp 	int		rv = FWFLASH_SUCCESS;
1186489Sjmcp 	int		i;
1196489Sjmcp 	char		ch;
1206489Sjmcp 	char		*read_file;
1216489Sjmcp 	extern char	*optarg;
1226489Sjmcp 	char		*devclass = NULL;
1236489Sjmcp 	char		*devpath = NULL;
1246489Sjmcp 
1256489Sjmcp 	/* local variables from env */
1266489Sjmcp 	(void) setlocale(LC_ALL, "");
1276489Sjmcp 
1286489Sjmcp #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
1296489Sjmcp #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it isn't. */
1306489Sjmcp #endif
1316489Sjmcp 
1326489Sjmcp 	(void) textdomain(TEXT_DOMAIN);
1336489Sjmcp 
1346489Sjmcp 	read_file = NULL;
1356489Sjmcp 
1366489Sjmcp 	if (argc < 2) {
1376489Sjmcp 		/* no args supplied */
1386489Sjmcp 		fwflash_usage(NULL);
1396489Sjmcp 		return (FWFLASH_FAILURE);
1406489Sjmcp 	}
1416489Sjmcp 
1429560SPei-Hong.Huang@Sun.COM 	while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:")) != EOF) {
1436489Sjmcp 		switch (ch) {
1446489Sjmcp 		case 'h':
1456489Sjmcp 			fwflash_arg_list |= FWFLASH_HELP_FLAG;
1466489Sjmcp 			break;
1476489Sjmcp 		case 'v':
1486489Sjmcp 			fwflash_arg_list |= FWFLASH_VER_FLAG;
1496489Sjmcp 			break;
1506489Sjmcp 		case 'y':
1516489Sjmcp 			fwflash_arg_list |= FWFLASH_YES_FLAG;
1526489Sjmcp 			break;
1536489Sjmcp 		case 'l':
1546489Sjmcp 			fwflash_arg_list |= FWFLASH_LIST_FLAG;
1556489Sjmcp 			break;
1566489Sjmcp 		case 'c':
1576489Sjmcp 			fwflash_arg_list |= FWFLASH_CLASS_FLAG;
1586489Sjmcp 			/* we validate later */
1596489Sjmcp 			devclass = strdup(optarg);
1606489Sjmcp 			break;
1616489Sjmcp 		case 'd':
1626489Sjmcp 			fwflash_arg_list |= FWFLASH_DEVICE_FLAG;
1636489Sjmcp 			devpath = strdup(optarg);
1646489Sjmcp 			break;
1656489Sjmcp 		case 'f':
1666489Sjmcp 			fwflash_arg_list |= FWFLASH_FW_FLAG;
1676489Sjmcp 			if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) {
1687317SJames.McPherson@Sun.COM 				fwflash_usage(NULL);
1696489Sjmcp 				return (FWFLASH_FAILURE);
1706489Sjmcp 			}
1716489Sjmcp 			break;
1726489Sjmcp 		case 'r':
1736489Sjmcp 			fwflash_arg_list |= FWFLASH_READ_FLAG;
1746489Sjmcp 			read_file = strdup(optarg);
1756489Sjmcp 			break;
1766489Sjmcp 		case 'Q':
1776489Sjmcp 			/* NOT in the manpage */
1786489Sjmcp 			fwflash_debug = 1;
1796489Sjmcp 			break;
1806846Sjmcp 		/* illegal options */
1816489Sjmcp 		default:
1826489Sjmcp 			fwflash_usage(optarg);
1836489Sjmcp 			return (FWFLASH_FAILURE);
1846489Sjmcp 		}
1856489Sjmcp 	}
1866489Sjmcp 
1876489Sjmcp 	/* Do Help */
1886489Sjmcp 	if ((fwflash_arg_list & FWFLASH_HELP_FLAG) ||
1896489Sjmcp 	    ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) &&
1908031SShantkumar.Hiremath@Sun.COM 	    !((fwflash_arg_list & FWFLASH_FW_FLAG) ||
1918031SShantkumar.Hiremath@Sun.COM 	    (fwflash_arg_list & FWFLASH_READ_FLAG)))) {
1927317SJames.McPherson@Sun.COM 		fwflash_usage(NULL);
1936489Sjmcp 		return (FWFLASH_SUCCESS);
1946489Sjmcp 	}
1956489Sjmcp 
1966489Sjmcp 	/* Do Version */
1976489Sjmcp 	if (fwflash_arg_list == FWFLASH_VER_FLAG) {
1986489Sjmcp 		fwflash_version();
1996489Sjmcp 		return (FWFLASH_SUCCESS);
2006489Sjmcp 	}
2016489Sjmcp 
2026489Sjmcp 	/* generate global list of devices */
2036489Sjmcp 	if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) {
2046489Sjmcp 		logmsg(MSG_ERROR,
2056489Sjmcp 		    gettext("Unable to load fwflash plugins\n"));
2066489Sjmcp 		fwflash_intr(0);
2076489Sjmcp 		return (rv);
2086489Sjmcp 	}
2096489Sjmcp 
2106489Sjmcp 	if ((rv = flash_device_list()) != FWFLASH_SUCCESS) {
2116489Sjmcp 		logmsg(MSG_ERROR,
2126489Sjmcp 		    gettext("No flashable devices in this system\n"));
2136489Sjmcp 		fwflash_intr(0);
2146489Sjmcp 		return (rv);
2156489Sjmcp 	}
2166489Sjmcp 
2176489Sjmcp 	/* Do list */
2186489Sjmcp 	if (fwflash_arg_list == (FWFLASH_LIST_FLAG) ||
2196489Sjmcp 	    fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) {
2206489Sjmcp 		rv = fwflash_list_fw(devclass);
2216489Sjmcp 		fwflash_intr(0);
2226489Sjmcp 		return (rv);
2236489Sjmcp 	}
2246489Sjmcp 
2256489Sjmcp 	fwflash_handle_signals();
2266489Sjmcp 
2276489Sjmcp 	/* Do flash update (write) */
2286489Sjmcp 	if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) ||
2296489Sjmcp 	    (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG |
2308031SShantkumar.Hiremath@Sun.COM 	    FWFLASH_YES_FLAG))) {
2319862SSherry.Moore@Sun.COM 		int fastreboot_disabled = 0;
2326489Sjmcp 		/* the update function handles the real arg parsing */
2336489Sjmcp 		i = 0;
2346489Sjmcp 		while (filelist[i] != NULL) {
2356489Sjmcp 			if ((rv = fwflash_update(devpath, filelist[i],
2366489Sjmcp 			    fwflash_arg_list)) == FWFLASH_SUCCESS) {
2376489Sjmcp 				/* failed ops have already been noted */
2389862SSherry.Moore@Sun.COM 				if (!fastreboot_disabled &&
2399862SSherry.Moore@Sun.COM 				    scf_fastreboot_default_set_transient(
2409862SSherry.Moore@Sun.COM 				    B_FALSE) != SCF_SUCCESS)
2419862SSherry.Moore@Sun.COM 					logmsg(MSG_ERROR, gettext(
2429862SSherry.Moore@Sun.COM 					    "Failed to disable fast "
2439862SSherry.Moore@Sun.COM 					    "reboot.\n"));
2449862SSherry.Moore@Sun.COM 				else
2459862SSherry.Moore@Sun.COM 					fastreboot_disabled = 1;
2466489Sjmcp 				logmsg(MSG_ERROR,
2476489Sjmcp 				    gettext("New firmware will be activated "
2488031SShantkumar.Hiremath@Sun.COM 				    "after you reboot\n\n"));
2496489Sjmcp 			}
2506489Sjmcp 			++i;
2516489Sjmcp 		}
2526489Sjmcp 
2536489Sjmcp 		fwflash_intr(0);
2546489Sjmcp 		return (rv);
2556489Sjmcp 	}
2566489Sjmcp 
2576489Sjmcp 	/* Do flash read */
2586489Sjmcp 	if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) ||
2596489Sjmcp 	    (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG |
2608031SShantkumar.Hiremath@Sun.COM 	    FWFLASH_YES_FLAG))) {
2616489Sjmcp 		rv = fwflash_read_file(devpath, read_file);
2626489Sjmcp 		fwflash_intr(0);
2636489Sjmcp 		return (rv);
2646489Sjmcp 	}
2656489Sjmcp 
2666489Sjmcp 	fwflash_usage(NULL);
2676489Sjmcp 
2686489Sjmcp 	return (FWFLASH_FAILURE);
2696489Sjmcp }
2706489Sjmcp 
2716489Sjmcp 
2726489Sjmcp static int
2738031SShantkumar.Hiremath@Sun.COM flash_load_plugins()
2748031SShantkumar.Hiremath@Sun.COM {
2756489Sjmcp 
2766489Sjmcp 	int rval = FWFLASH_SUCCESS;
2776489Sjmcp 	DIR *dirp;
2786489Sjmcp 	struct dirent *plugdir;
2796489Sjmcp 	char *plugname;
2806489Sjmcp 	struct fw_plugin *tmpplug;
2816489Sjmcp 	struct pluginlist *tmpelem;
2826489Sjmcp 	void *sym;
2836489Sjmcp 	char *fwplugdirpath, *tempdirpath;
2846489Sjmcp 
2856489Sjmcp 
2866489Sjmcp #define	CLOSEFREE()	{			\
2876489Sjmcp 	(void) dlclose(tmpplug->handle);	\
2886489Sjmcp 	free(tmpplug); }
2896489Sjmcp 
2906489Sjmcp 	/*
2916489Sjmcp 	 * Procedure:
2926489Sjmcp 	 *
2936489Sjmcp 	 * cd /usr/lib/fwflash/identify
2946489Sjmcp 	 * open each .so file found therein
2956489Sjmcp 	 * dlopen(.sofile)
2966489Sjmcp 	 * if it's one of our plugins, add it to fw_pluginlist;
2976489Sjmcp 	 *
2986489Sjmcp 	 * functions we need here include dlopen and dlsym.
2996489Sjmcp 	 *
3006489Sjmcp 	 * If we get to the end and fw_pluginlist struct is empty,
3016489Sjmcp 	 * return FWFLASH_FAILURE so we return to the shell.
3026489Sjmcp 	 */
3036489Sjmcp 
3046489Sjmcp 	if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
3056489Sjmcp 		logmsg(MSG_ERROR,
3066489Sjmcp 		    gettext("Unable to malloc %d bytes while "
3076489Sjmcp 		    "trying to load plugins: %s\n"),
3086489Sjmcp 		    MAXPATHLEN + 1, strerror(errno));
3096489Sjmcp 		return (FWFLASH_FAILURE);
3106489Sjmcp 	}
3116489Sjmcp 
3126489Sjmcp 	tempdirpath = getenv("FWPLUGINDIR");
3136489Sjmcp 
3146489Sjmcp 	if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
3156489Sjmcp 		(void) strlcpy(fwplugdirpath, tempdirpath,
3166489Sjmcp 		    strlen(tempdirpath) + 1);
3176489Sjmcp 	} else {
3186489Sjmcp 		(void) strlcpy(fwplugdirpath, FWPLUGINDIR,
3196489Sjmcp 		    strlen(FWPLUGINDIR) + 1);
3206489Sjmcp 	}
3216489Sjmcp 
3226489Sjmcp 	if ((dirp = opendir(fwplugdirpath)) == NULL) {
3236489Sjmcp 		logmsg(MSG_ERROR,
3246846Sjmcp 		    gettext("Unable to open %s\n"),
3256489Sjmcp 		    fwplugdirpath);
3266489Sjmcp 		return (errno);
3276489Sjmcp 	}
3286489Sjmcp 
3296489Sjmcp 	if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1))
3306489Sjmcp 	    == NULL) {
3316489Sjmcp 		logmsg(MSG_ERROR,
3326489Sjmcp 		    gettext("Unable to malloc %d bytes while "
3336489Sjmcp 		    "trying to load plugins: %s\n"),
3346489Sjmcp 		    MAXPATHLEN + 1 + sizeof (struct dirent),
3356489Sjmcp 		    strerror(errno));
3366489Sjmcp 		return (FWFLASH_FAILURE);
3376489Sjmcp 	}
3386489Sjmcp 
3396489Sjmcp 	if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin)))
3406489Sjmcp 	    == NULL) {
3416489Sjmcp 		logmsg(MSG_ERROR,
3426489Sjmcp 		    gettext("Unable to malloc %d bytes while "
3438031SShantkumar.Hiremath@Sun.COM 		    "trying to load plugins: %s\n"),
3449683SXin.Chen@Sun.COM 		    sizeof (struct fw_plugin), strerror(errno));
3456489Sjmcp 		return (FWFLASH_FAILURE);
3466489Sjmcp 	}
3476489Sjmcp 
3486489Sjmcp 	TAILQ_INIT(fw_pluginlist);
3496489Sjmcp 
3506489Sjmcp 	while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) {
3516489Sjmcp 
3526489Sjmcp 		errno = 0; /* remove chance of false results */
3536489Sjmcp 
3546489Sjmcp 		if ((plugdir->d_name[0] == '.') ||
3556489Sjmcp 		    (strstr(plugdir->d_name, ".so") == NULL)) {
3566489Sjmcp 			continue;
3576489Sjmcp 		}
3586489Sjmcp 
3596489Sjmcp 		if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) {
3606489Sjmcp 			logmsg(MSG_ERROR,
3616489Sjmcp 			    gettext("Unable to malloc %d bytes while "
3628031SShantkumar.Hiremath@Sun.COM 			    "trying to load plugins: %s\n"),
3636489Sjmcp 			    MAXPATHLEN + 1, strerror(errno));
3646489Sjmcp 			return (FWFLASH_FAILURE);
3656489Sjmcp 		}
3666489Sjmcp 
3676489Sjmcp 		(void) snprintf(plugname, MAXPATHLEN, "%s/%s",
3686489Sjmcp 		    fwplugdirpath, plugdir->d_name);
3696489Sjmcp 
3706489Sjmcp 		/* start allocating storage */
3716489Sjmcp 		if ((tmpelem = calloc(1, sizeof (struct pluginlist)))
3726489Sjmcp 		    == NULL) {
3736489Sjmcp 			logmsg(MSG_ERROR,
3746489Sjmcp 			    gettext("Unable to malloc %d bytes while "
3758031SShantkumar.Hiremath@Sun.COM 			    "trying to load plugins: %s\n"),
3766489Sjmcp 			    sizeof (struct pluginlist), strerror(errno));
3776489Sjmcp 			return (FWFLASH_FAILURE);
3786489Sjmcp 		}
3796489Sjmcp 
3806489Sjmcp 		if ((tmpplug = calloc(1, sizeof (struct fw_plugin)))
3816489Sjmcp 		    == NULL) {
3826489Sjmcp 			logmsg(MSG_ERROR,
3836489Sjmcp 			    gettext("Unable to malloc %d bytes while "
3846489Sjmcp 			    "trying to load plugins: %s\n"),
3856489Sjmcp 			    sizeof (struct fw_plugin), strerror(errno));
3866489Sjmcp 			return (FWFLASH_FAILURE);
3876489Sjmcp 		}
3886489Sjmcp 
3896489Sjmcp 		/* load 'er up! */
3906489Sjmcp 		tmpplug->handle = dlopen(plugname, RTLD_NOW);
3916489Sjmcp 		if (tmpplug->handle == NULL) {
3926489Sjmcp 			free(tmpplug);
3936489Sjmcp 			continue; /* assume there are other plugins */
3946489Sjmcp 		}
3956489Sjmcp 
3966489Sjmcp 		if ((tmpplug->filename = calloc(1, strlen(plugname) + 1))
3976489Sjmcp 		    == NULL) {
3986489Sjmcp 			logmsg(MSG_ERROR,
3996489Sjmcp 			    gettext("Unable to allocate %d bytes for plugin "
4008031SShantkumar.Hiremath@Sun.COM 			    "filename %s:%s\n"),
4016489Sjmcp 			    strlen(plugname) + 1, plugname,
4026489Sjmcp 			    strerror(errno));
4036489Sjmcp 			return (rval);
4046489Sjmcp 		}
4056489Sjmcp 
4066489Sjmcp 		(void) strlcpy(tmpplug->filename, plugname,
4076489Sjmcp 		    strlen(plugname) + 1);
4086489Sjmcp 
4096489Sjmcp 		/* now sanity check the file */
4106489Sjmcp 		if ((sym = dlsym(tmpplug->handle, "drivername"))
4116489Sjmcp 		    != NULL) {
4126489Sjmcp 			/* max length of drivername */
4136846Sjmcp 			tmpplug->drvname = calloc(1, MAXMODCONFNAME);
4146846Sjmcp 
4156846Sjmcp 			/* are we doing double-time? */
4166846Sjmcp 			if (strncmp((char *)sym, plugdir->d_name,
4176846Sjmcp 			    MAXMODCONFNAME) != 0) {
4186846Sjmcp 				char *tempnm = calloc(1, MAXMODCONFNAME);
4196846Sjmcp 
4209683SXin.Chen@Sun.COM 				(void) memcpy(tempnm, plugdir->d_name,
4219683SXin.Chen@Sun.COM 				    MAXMODCONFNAME);
4226846Sjmcp 				(void) strlcpy(tmpplug->drvname,
4236846Sjmcp 				    strtok(tempnm, "."),
4246846Sjmcp 				    strlen(plugdir->d_name) + 1);
4256846Sjmcp 				free(tempnm);
4266846Sjmcp 			} else {
4276846Sjmcp 				(void) strlcpy(tmpplug->drvname,
4286846Sjmcp 				    (char *)sym, strlen(sym) + 1);
4296846Sjmcp 			}
4306489Sjmcp 		} else {
4316489Sjmcp 			CLOSEFREE();
4326489Sjmcp 			continue;
4336489Sjmcp 		}
4346489Sjmcp 		if ((sym = dlsym(tmpplug->handle, "fw_readfw"))
4356489Sjmcp 		    != NULL) {
4366489Sjmcp 			tmpplug->fw_readfw = (int (*)())sym;
4376489Sjmcp 		} else {
4386489Sjmcp 			CLOSEFREE();
4396489Sjmcp 			continue;
4406489Sjmcp 		}
4416489Sjmcp 		if ((sym = dlsym(tmpplug->handle, "fw_writefw"))
4426489Sjmcp 		    != NULL) {
4436489Sjmcp 			tmpplug->fw_writefw = (int (*)())sym;
4446489Sjmcp 		} else {
4456489Sjmcp 			CLOSEFREE();
4466489Sjmcp 			continue;
4476489Sjmcp 		}
4486489Sjmcp 
4496489Sjmcp 		if ((sym = dlsym(tmpplug->handle, "fw_identify"))
4506489Sjmcp 		    != NULL) {
4516489Sjmcp 			tmpplug->fw_identify =
4526489Sjmcp 			    (int (*)(int))sym;
4536489Sjmcp 		} else {
4546489Sjmcp 			CLOSEFREE();
4556489Sjmcp 			continue;
4566489Sjmcp 		}
4576489Sjmcp 		if ((sym = dlsym(tmpplug->handle, "fw_devinfo"))
4586489Sjmcp 		    != NULL) {
4596489Sjmcp 			tmpplug->fw_devinfo =
4606489Sjmcp 			    (int (*)(struct devicelist *))sym;
4616489Sjmcp 		} else {
4626489Sjmcp 			CLOSEFREE();
4636489Sjmcp 			continue;
4646489Sjmcp 		}
4656489Sjmcp 
4669683SXin.Chen@Sun.COM 		if ((sym = dlsym(tmpplug->handle, "plugin_version"))
4679683SXin.Chen@Sun.COM 		    != NULL) {
4689683SXin.Chen@Sun.COM 			if ((*(int *)sym) >= FWPLUGIN_VERSION_2) {
4699683SXin.Chen@Sun.COM 				if ((sym = dlsym(tmpplug->handle,
4709683SXin.Chen@Sun.COM 				    "fw_cleanup")) != NULL) {
4719683SXin.Chen@Sun.COM 					tmpplug->fw_cleanup =
4729683SXin.Chen@Sun.COM 					    (void (*)(struct devicelist *))sym;
4739683SXin.Chen@Sun.COM 				} else {
4749683SXin.Chen@Sun.COM 					logmsg(MSG_ERROR,
4759683SXin.Chen@Sun.COM 					    gettext("ERROR: v2 plugin (%s) "
4769683SXin.Chen@Sun.COM 					    "has no fw_cleanup function\n"),
4779683SXin.Chen@Sun.COM 					    tmpplug->filename);
4789683SXin.Chen@Sun.COM 					CLOSEFREE();
4799683SXin.Chen@Sun.COM 					continue;
4809683SXin.Chen@Sun.COM 				}
4819683SXin.Chen@Sun.COM 			} else {
4829683SXin.Chen@Sun.COM 				logmsg(MSG_INFO,
4839683SXin.Chen@Sun.COM 				    "Identification plugin %s defined "
4849683SXin.Chen@Sun.COM 				    "plugin_version < FWPLUGIN_VERSION_2 !");
4859683SXin.Chen@Sun.COM 			}
4869683SXin.Chen@Sun.COM 		}
4879683SXin.Chen@Sun.COM 
4886846Sjmcp 		if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME))
4896489Sjmcp 		    == NULL) {
4906489Sjmcp 			logmsg(MSG_ERROR,
4916846Sjmcp 			    gettext("Unable to allocate space for a"
4928031SShantkumar.Hiremath@Sun.COM 			    "drivername %s\n"),
4936489Sjmcp 			    tmpplug->drvname);
4946489Sjmcp 			return (FWFLASH_FAILURE);
4956489Sjmcp 		}
4966489Sjmcp 
4976489Sjmcp 		(void) strlcpy(tmpelem->drvname, tmpplug->drvname,
4986489Sjmcp 		    strlen(tmpplug->drvname) + 1);
4996489Sjmcp 
5006489Sjmcp 		if ((tmpelem->filename = calloc(1,
5016489Sjmcp 		    strlen(tmpplug->filename) + 1)) == NULL) {
5026489Sjmcp 			logmsg(MSG_ERROR,
5036489Sjmcp 			    gettext("Unable to allocate %d bytes for "
5048031SShantkumar.Hiremath@Sun.COM 			    "filename %s\n"),
5056489Sjmcp 			    strlen(tmpplug->filename) + 1,
5066846Sjmcp 			    tmpplug->filename);
5076489Sjmcp 			return (FWFLASH_FAILURE);
5086489Sjmcp 		}
5096489Sjmcp 
5106489Sjmcp 		(void) strlcpy(tmpelem->filename, plugname,
5116489Sjmcp 		    strlen(plugname) + 1);
5126489Sjmcp 		tmpelem->plugin = tmpplug;
5136489Sjmcp 
5146489Sjmcp 		/* CONSTCOND */
5156489Sjmcp 		TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin);
5166489Sjmcp 	}
5176489Sjmcp 
5186489Sjmcp 	if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) {
5196489Sjmcp 		return (FWFLASH_FAILURE);
5206489Sjmcp 	}
5216489Sjmcp 
5226489Sjmcp 	if (errno != 0) {
5236489Sjmcp 		logmsg(MSG_ERROR,
5246489Sjmcp 		    gettext("Error reading directory entry in %s\n"),
5256489Sjmcp 		    fwplugdirpath);
5266489Sjmcp 		rval = errno;
5276489Sjmcp 	}
5286489Sjmcp 
5299683SXin.Chen@Sun.COM 	free(fwplugdirpath);
5309683SXin.Chen@Sun.COM 	free(plugdir);
5316489Sjmcp 	(void) closedir(dirp);
5326489Sjmcp 	return (rval);
5336489Sjmcp }
5346489Sjmcp 
5356489Sjmcp /*
5366489Sjmcp  * fwflash_load_verifier dlload()s the appropriate firmware image
5376489Sjmcp  * verification plugin, and attaches the designated fwimg's fd to
5386489Sjmcp  * the vrfyplugin structure so we only have to load the image in
5396489Sjmcp  * one place.
5406489Sjmcp  */
5416489Sjmcp int
5428031SShantkumar.Hiremath@Sun.COM fwflash_load_verifier(char *drv, char *vendorid, char *fwimg)
5438031SShantkumar.Hiremath@Sun.COM {
5446489Sjmcp 
5456489Sjmcp 	int rv = FWFLASH_FAILURE;
5466489Sjmcp 	int imgfd;
5476489Sjmcp 	char *fwvrfydirpath, *tempdirpath, *filename;
5486489Sjmcp 	char *clean; /* for the space-removed vid */
5496489Sjmcp 	struct stat fwstat;
5506489Sjmcp 	struct vrfyplugin *vrfy;
5516489Sjmcp 	void *vrfysym;
5526489Sjmcp 
5536489Sjmcp 	/*
5546489Sjmcp 	 * To make flashing multiple firmware images somewhat more
5556489Sjmcp 	 * efficient, we start this function by checking whether a
5566489Sjmcp 	 * verifier for this device has already been loaded. If it
5576489Sjmcp 	 * has been loaded, we replace the imgfile information, and
5586489Sjmcp 	 * then continue as if we were loading for the first time.
5596489Sjmcp 	 */
5606489Sjmcp 
5616489Sjmcp 	if (verifier != NULL) {
5626489Sjmcp 		verifier->imgsize = 0;
5636489Sjmcp 		verifier->flashbuf = 0; /* set by the verifier function */
5646489Sjmcp 
5659683SXin.Chen@Sun.COM 		if (verifier->imgfile != NULL) {
5669683SXin.Chen@Sun.COM 			free(verifier->imgfile);
5679683SXin.Chen@Sun.COM 			verifier->imgfile = NULL;
5689683SXin.Chen@Sun.COM 		}
5696489Sjmcp 
5709683SXin.Chen@Sun.COM 		if (verifier->fwimage != NULL) {
5719683SXin.Chen@Sun.COM 			free(verifier->fwimage);
5729683SXin.Chen@Sun.COM 			verifier->fwimage = NULL;
5739683SXin.Chen@Sun.COM 		}
5746489Sjmcp 	} else {
5756489Sjmcp 		if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
5766489Sjmcp 			logmsg(MSG_ERROR,
5776489Sjmcp 			    gettext("Unable to allocate space for a firmware "
5788031SShantkumar.Hiremath@Sun.COM 			    "verifier file(1)"));
5796489Sjmcp 			return (rv);
5806489Sjmcp 		}
5816489Sjmcp 
5826489Sjmcp 		if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) {
5836489Sjmcp 			logmsg(MSG_ERROR,
5846489Sjmcp 			    gettext("Unable to allocate space "
5856489Sjmcp 			    "for a firmware verifier file(2)"));
5869683SXin.Chen@Sun.COM 			free(fwvrfydirpath);
5876489Sjmcp 			return (rv);
5886489Sjmcp 		}
5896489Sjmcp 
5909683SXin.Chen@Sun.COM 		/*
5919683SXin.Chen@Sun.COM 		 * Since SCSI devices can have a vendor id of up to 8
5929683SXin.Chen@Sun.COM 		 * left-aligned and _space-padded_ characters, we first need to
5939683SXin.Chen@Sun.COM 		 * strip off any space characters before we try to make a
5949683SXin.Chen@Sun.COM 		 * filename out of it
5959683SXin.Chen@Sun.COM 		 */
5966489Sjmcp 		clean = strtok(vendorid, " ");
5976489Sjmcp 		if (clean == NULL) {
5986489Sjmcp 			/* invalid vendorid, something's really wrong */
5996489Sjmcp 			logmsg(MSG_ERROR,
6006489Sjmcp 			    gettext("Invalid vendorid (null) specified for "
6018031SShantkumar.Hiremath@Sun.COM 			    "device\n"));
6029683SXin.Chen@Sun.COM 			free(filename);
6039683SXin.Chen@Sun.COM 			free(fwvrfydirpath);
6046489Sjmcp 			return (rv);
6056489Sjmcp 		}
6066489Sjmcp 
6076489Sjmcp 		tempdirpath = getenv("FWVERIFYPLUGINDIR");
6086489Sjmcp 
6096489Sjmcp 		if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
6106489Sjmcp 			(void) strlcpy(fwvrfydirpath, tempdirpath,
6116489Sjmcp 			    strlen(tempdirpath) + 1);
6126489Sjmcp 		} else {
6136489Sjmcp 			(void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR,
6146489Sjmcp 			    strlen(FWVERIFYPLUGINDIR) + 1);
6156489Sjmcp 		}
6166489Sjmcp 
6176489Sjmcp 		if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) {
6186489Sjmcp 			logmsg(MSG_ERROR,
6196489Sjmcp 			    gettext("Unable to allocate space "
6206489Sjmcp 			    "for a firmware verifier structure"));
6216489Sjmcp 			free(filename);
6226489Sjmcp 			free(fwvrfydirpath);
6239683SXin.Chen@Sun.COM 			return (rv);
6246489Sjmcp 		}
6256489Sjmcp 
6266489Sjmcp 		errno = 0; /* false positive removal */
6276489Sjmcp 
6289683SXin.Chen@Sun.COM 		(void) snprintf(filename, MAXPATHLEN, "%s/%s-%s.so",
6296489Sjmcp 		    fwvrfydirpath, drv, clean);
6309683SXin.Chen@Sun.COM 		if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) {
6319683SXin.Chen@Sun.COM 			logmsg(MSG_INFO, gettext(dlerror()));
6329683SXin.Chen@Sun.COM 			logmsg(MSG_INFO,
6339683SXin.Chen@Sun.COM 			    gettext("\nUnable to open verification plugin "
6349683SXin.Chen@Sun.COM 			    "%s. Looking for %s-GENERIC plugin instead.\n"),
6359683SXin.Chen@Sun.COM 			    filename, drv);
6369683SXin.Chen@Sun.COM 
6379683SXin.Chen@Sun.COM 			/* Try the drv-GENERIC.so form, _then_ die */
6389683SXin.Chen@Sun.COM 			bzero(filename, strlen(filename) + 1);
6399683SXin.Chen@Sun.COM 			(void) snprintf(filename, MAXPATHLEN,
6409683SXin.Chen@Sun.COM 			    "%s/%s-GENERIC.so", fwvrfydirpath, drv);
6419683SXin.Chen@Sun.COM 
6429683SXin.Chen@Sun.COM 			if ((vrfy->handle = dlopen(filename, RTLD_NOW))
6439683SXin.Chen@Sun.COM 			    == NULL) {
6449683SXin.Chen@Sun.COM 				logmsg(MSG_INFO, gettext(dlerror()));
6459683SXin.Chen@Sun.COM 				logmsg(MSG_ERROR,
6469683SXin.Chen@Sun.COM 				    gettext("\nUnable to open either "
6479683SXin.Chen@Sun.COM 				    "verification plugin %s/%s-%s.so or "
6489683SXin.Chen@Sun.COM 				    "generic plugin %s.\nUnable to verify "
6499683SXin.Chen@Sun.COM 				    "firmware image. Aborting.\n"),
6509683SXin.Chen@Sun.COM 				    fwvrfydirpath, drv, clean, filename);
6519683SXin.Chen@Sun.COM 				free(filename);
6529683SXin.Chen@Sun.COM 				free(fwvrfydirpath);
6539683SXin.Chen@Sun.COM 				return (rv);
6549683SXin.Chen@Sun.COM 			}
6559683SXin.Chen@Sun.COM 		}
6566489Sjmcp 
6576489Sjmcp 		if ((vrfy->filename = calloc(1, strlen(filename) + 1))
6586489Sjmcp 		    == NULL) {
6596489Sjmcp 			logmsg(MSG_ERROR,
6606489Sjmcp 			    gettext("Unable to allocate space to store "
6618031SShantkumar.Hiremath@Sun.COM 			    "a verifier filename\n"));
6626489Sjmcp 			free(filename);
6636489Sjmcp 			free(fwvrfydirpath);
6646489Sjmcp 			free(vrfy->handle);
6659683SXin.Chen@Sun.COM 			return (rv);
6666489Sjmcp 		}
6676489Sjmcp 		(void) strlcpy(vrfy->filename, filename, strlen(filename) + 1);
6686489Sjmcp 
6696489Sjmcp 		if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) {
6706489Sjmcp 			logmsg(MSG_ERROR,
6716489Sjmcp 			    gettext("%s is an invalid firmware verification "
6728031SShantkumar.Hiremath@Sun.COM 			    "plugin."), filename);
6736489Sjmcp 			(void) dlclose(vrfy->handle);
6746489Sjmcp 			free(filename);
6756489Sjmcp 			free(fwvrfydirpath);
6766489Sjmcp 			free(vrfy);
6779683SXin.Chen@Sun.COM 			return (rv);
6786489Sjmcp 		} else {
6796489Sjmcp 			vrfy->vendorvrfy =
6806489Sjmcp 			    (int (*)(struct devicelist *))vrfysym;
6816489Sjmcp 		}
6826489Sjmcp 
6836489Sjmcp 		vrfysym = dlsym(vrfy->handle, "vendor");
6846489Sjmcp 
6856489Sjmcp 		if (vrfysym == NULL) {
6866489Sjmcp 			logmsg(MSG_ERROR,
6876489Sjmcp 			    gettext("Invalid vendor (null) in verification "
6888031SShantkumar.Hiremath@Sun.COM 			    "plugin %s\n"), filename);
6896489Sjmcp 			(void) dlclose(vrfy->handle);
6906489Sjmcp 			free(vrfy);
6919683SXin.Chen@Sun.COM 			return (rv);
6926489Sjmcp 		} else {
6936489Sjmcp 			if (strncmp(vendorid, (char *)vrfysym,
6946489Sjmcp 			    strlen(vendorid)) != 0) {
6956489Sjmcp 				logmsg(MSG_INFO,
6966489Sjmcp 				    "Using a sym-linked (%s -> %s) "
6979683SXin.Chen@Sun.COM 				    "verification plugin\n",
6986489Sjmcp 				    vendorid, vrfysym);
6996489Sjmcp 				vrfy->vendor = calloc(1, strlen(vendorid) + 1);
7006489Sjmcp 			} else {
7016489Sjmcp 				vrfy->vendor = calloc(1, strlen(vrfysym) + 1);
7026489Sjmcp 			}
7036489Sjmcp 			(void) strlcpy(vrfy->vendor, (char *)vrfysym,
7046489Sjmcp 			    strlen(vendorid) + 1);
7056489Sjmcp 		}
7066489Sjmcp 
7076489Sjmcp 		verifier = vrfy; /* a convenience variable */
7089683SXin.Chen@Sun.COM 		free(filename);
7099683SXin.Chen@Sun.COM 		free(fwvrfydirpath);
7106489Sjmcp 	}
7116489Sjmcp 
7126489Sjmcp 	/*
7136489Sjmcp 	 * We don't do any verification that the fw image file is in
7146489Sjmcp 	 * an approved location, but it's easy enough to modify this
7156489Sjmcp 	 * function to do so. The verification plugin should provide
7166489Sjmcp 	 * sufficient protection.
7176489Sjmcp 	 */
7186489Sjmcp 
7196489Sjmcp 	if ((imgfd = open(fwimg, O_RDONLY)) < 0) {
7206489Sjmcp 		logmsg(MSG_ERROR,
7216489Sjmcp 		    gettext("Unable to open designated firmware "
7228031SShantkumar.Hiremath@Sun.COM 		    "image file %s: %s\n"),
7236489Sjmcp 		    (fwimg != NULL) ? fwimg : "(null)",
7246489Sjmcp 		    strerror(errno));
7256489Sjmcp 		rv = FWFLASH_FAILURE;
7266489Sjmcp 		goto cleanup;
7276489Sjmcp 	}
7286489Sjmcp 
7296489Sjmcp 	if (stat(fwimg, &fwstat) == -1) {
7306489Sjmcp 		logmsg(MSG_ERROR,
7316489Sjmcp 		    gettext("Unable to stat() firmware image file "
7328031SShantkumar.Hiremath@Sun.COM 		    "%s: %s\n"),
7336489Sjmcp 		    fwimg, strerror(errno));
7346489Sjmcp 		rv = FWFLASH_FAILURE;
7356489Sjmcp 		goto cleanup;
7366489Sjmcp 	} else {
7376489Sjmcp 		verifier->imgsize = fwstat.st_size;
7386489Sjmcp 		if ((verifier->fwimage = calloc(1, verifier->imgsize))
7396489Sjmcp 		    == NULL) {
7406489Sjmcp 			logmsg(MSG_ERROR,
7416489Sjmcp 			    gettext("Unable to load firmware image "
7428031SShantkumar.Hiremath@Sun.COM 			    "%s: %s\n"),
7436489Sjmcp 			    fwimg, strerror(errno));
7446489Sjmcp 			rv = FWFLASH_FAILURE;
7456489Sjmcp 			goto cleanup;
7466489Sjmcp 		}
7476489Sjmcp 	}
7486489Sjmcp 
7496489Sjmcp 	errno = 0;
7506489Sjmcp 	if ((rv = read(imgfd, verifier->fwimage,
7516489Sjmcp 	    (size_t)verifier->imgsize)) < verifier->imgsize) {
7526489Sjmcp 		/* we haven't read enough data, bail */
7536489Sjmcp 		logmsg(MSG_ERROR,
7546489Sjmcp 		    gettext("Failed to read sufficient data "
7558031SShantkumar.Hiremath@Sun.COM 		    "(got %d bytes, expected %d bytes) from "
7568031SShantkumar.Hiremath@Sun.COM 		    "firmware image file %s: %s\n"),
7576489Sjmcp 		    rv, verifier->imgsize,
7589683SXin.Chen@Sun.COM 		    verifier->filename, strerror(errno));
7596489Sjmcp 		rv = FWFLASH_FAILURE;
7606489Sjmcp 	} else {
7616489Sjmcp 		rv = FWFLASH_SUCCESS;
7626489Sjmcp 	}
7636489Sjmcp 
7646489Sjmcp 	if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) {
7656489Sjmcp 		logmsg(MSG_ERROR,
7666489Sjmcp 		    gettext("Unable to save name of firmware image\n"));
7676489Sjmcp 		rv = FWFLASH_FAILURE;
7686489Sjmcp 	} else {
7696489Sjmcp 		(void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1);
7706489Sjmcp 	}
7716489Sjmcp 
7726489Sjmcp 	if (rv != FWFLASH_SUCCESS) {
7736489Sjmcp 		/* cleanup and let's get outta here */
7746489Sjmcp cleanup:
7756489Sjmcp 		free(verifier->filename);
7766489Sjmcp 		free(verifier->vendor);
7776489Sjmcp 
7789683SXin.Chen@Sun.COM 		if (!(fwflash_arg_list & FWFLASH_READ_FLAG) &&
7799683SXin.Chen@Sun.COM 		    verifier->fwimage)
7806489Sjmcp 			free(verifier->fwimage);
7816489Sjmcp 
7826489Sjmcp 		verifier->filename = NULL;
7836489Sjmcp 		verifier->vendor = NULL;
7846489Sjmcp 		verifier->vendorvrfy = NULL;
7856489Sjmcp 		verifier->fwimage = NULL;
7866489Sjmcp 		(void) dlclose(verifier->handle);
7876489Sjmcp 		verifier->handle = NULL;
7886489Sjmcp 		free(verifier);
7896489Sjmcp 		if (imgfd >= 0) {
7906489Sjmcp 			(void) close(imgfd);
7916489Sjmcp 		}
7926489Sjmcp 		verifier = NULL;
7936489Sjmcp 	}
7946489Sjmcp 
7956489Sjmcp 	return (rv);
7966489Sjmcp }
7976489Sjmcp 
7986489Sjmcp /*
7996489Sjmcp  * cycles through the global list of plugins to find
8006489Sjmcp  * each flashable device, which is added to fw_devices
8016489Sjmcp  *
8026489Sjmcp  * Each plugin's identify routine must allocated storage
8036489Sjmcp  * as required.
8046489Sjmcp  *
8056489Sjmcp  * Each plugin's identify routine must return
8066489Sjmcp  * FWFLASH_FAILURE if it cannot find any devices
8076489Sjmcp  * which it handles.
8086489Sjmcp  */
8096489Sjmcp static int
8106489Sjmcp flash_device_list()
8116489Sjmcp {
8126489Sjmcp 	int rv = FWFLASH_FAILURE;
8136489Sjmcp 	int startidx = 0;
8146489Sjmcp 	int sumrv = 0;
8156489Sjmcp 	struct pluginlist *plugins;
8166489Sjmcp 
8176489Sjmcp 	/* we open rootnode here, and close it in fwflash_intr */
8189683SXin.Chen@Sun.COM 	if ((rootnode = di_init("/", DINFOCPYALL|DINFOFORCE)) == DI_NODE_NIL) {
8196489Sjmcp 		logmsg(MSG_ERROR,
8206489Sjmcp 		    gettext("Unable to take device tree snapshot: %s\n"),
8216489Sjmcp 		    strerror(errno));
8226489Sjmcp 		return (rv);
8236489Sjmcp 	}
8246489Sjmcp 
8256489Sjmcp 	if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) {
8266489Sjmcp 		logmsg(MSG_ERROR,
8276489Sjmcp 		    gettext("Unable to malloc %d bytes while "
8286489Sjmcp 		    "trying to find devices: %s\n"),
8296489Sjmcp 		    sizeof (struct devicelist), strerror(errno));
8306489Sjmcp 		return (FWFLASH_FAILURE);
8316489Sjmcp 	}
8326489Sjmcp 
8336489Sjmcp 	/* CONSTCOND */
8346489Sjmcp 	TAILQ_INIT(fw_devices);
8356489Sjmcp 
8366489Sjmcp 	TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) {
8376489Sjmcp 		self = plugins->plugin;
8386489Sjmcp 		rv = plugins->plugin->fw_identify(startidx);
8396489Sjmcp 
8406489Sjmcp 		logmsg(MSG_INFO,
8416489Sjmcp 		    gettext("fwflash:flash_device_list() got %d from "
8426489Sjmcp 		    "identify routine\n"), rv);
8436489Sjmcp 
8446489Sjmcp 		/* only bump startidx if we've found at least one device */
8456489Sjmcp 		if (rv == FWFLASH_SUCCESS) {
8466489Sjmcp 			startidx += 100;
8476489Sjmcp 			sumrv++;
8486489Sjmcp 		} else {
8496489Sjmcp 			logmsg(MSG_INFO,
8506489Sjmcp 			    gettext("No flashable devices attached with "
8516489Sjmcp 			    "the %s driver in this system\n"),
8526489Sjmcp 			    plugins->drvname);
8536489Sjmcp 		}
8546489Sjmcp 	}
8556489Sjmcp 
8566489Sjmcp 	if (sumrv > 0)
8576489Sjmcp 		rv = FWFLASH_SUCCESS;
8586489Sjmcp 
8596489Sjmcp 	return (rv);
8606489Sjmcp }
8616489Sjmcp 
8626489Sjmcp static int
8636489Sjmcp fwflash_list_fw(char *class)
8646489Sjmcp {
8656489Sjmcp 	int rv = 0;
8666489Sjmcp 	struct devicelist *curdev;
8676489Sjmcp 	int header = 1;
8686489Sjmcp 
8696489Sjmcp 	TAILQ_FOREACH(curdev, fw_devices, nextdev) {
8706489Sjmcp 
8716489Sjmcp 		/* we're either class-conscious, or we're not */
8726489Sjmcp 		if (((class != NULL) &&
8736489Sjmcp 		    ((strncmp(curdev->classname, "ALL", 3) == 0) ||
8746489Sjmcp 		    (strcmp(curdev->classname, class) == 0))) ||
8756489Sjmcp 		    (class == NULL)) {
8766489Sjmcp 
8776489Sjmcp 			if (header != 0) {
8786489Sjmcp 				(void) fprintf(stdout,
8796489Sjmcp 				    gettext("List of available devices:\n"));
8806489Sjmcp 				header--;
8816489Sjmcp 			}
8826489Sjmcp 			/*
8836489Sjmcp 			 * If any plugin's fw_devinfo() function returns
8846489Sjmcp 			 * FWFLASH_FAILURE then we want to keep track of
8856489Sjmcp 			 * it. _Most_ plugins should always return
8866489Sjmcp 			 * FWFLASH_SUCCESS from this function. The only
8876489Sjmcp 			 * exception known at this point is the tavor plugin.
8886489Sjmcp 			 */
8896489Sjmcp 			rv += curdev->plugin->fw_devinfo(curdev);
8906489Sjmcp 		}
8916489Sjmcp 	}
8926489Sjmcp 	return (rv);
8936489Sjmcp }
8946489Sjmcp 
8956489Sjmcp static int
8967317SJames.McPherson@Sun.COM fwflash_update(char *device, char *filename, int flags)
8977317SJames.McPherson@Sun.COM {
8986489Sjmcp 
8996489Sjmcp 	int rv = FWFLASH_FAILURE;
9006489Sjmcp 	int needsfree = 0;
9016846Sjmcp 	int found = 0;
9026489Sjmcp 	struct devicelist *curdev;
9036489Sjmcp 	char *realfile;
9046489Sjmcp 
9056489Sjmcp 	/*
9066489Sjmcp 	 * Here's how we operate:
9076489Sjmcp 	 *
9086489Sjmcp 	 * We perform some basic checks on the args, then walk
9096489Sjmcp 	 * through the device list looking for the device which
9106489Sjmcp 	 * matches. We then load the appropriate verifier for the
9116489Sjmcp 	 * image file and device, verify the image, then call the
9126489Sjmcp 	 * fw_writefw() function of the appropriate plugin.
9136489Sjmcp 	 *
9146489Sjmcp 	 * There is no "force" flag to enable you to flash a firmware
9156489Sjmcp 	 * image onto an incompatible device because the verifier
9166489Sjmcp 	 * will return FWFLASH_FAILURE if the image doesn't match.
9176489Sjmcp 	 */
9186489Sjmcp 
9196489Sjmcp 	/* new firmware filename and device desc */
9206489Sjmcp 	if (filename == NULL) {
9216489Sjmcp 		logmsg(MSG_ERROR,
9226489Sjmcp 		    gettext("Invalid firmware filename (null)\n"));
9236489Sjmcp 		return (FWFLASH_FAILURE);
9246489Sjmcp 	}
9256489Sjmcp 
9266489Sjmcp 	if (device == NULL) {
9276489Sjmcp 		logmsg(MSG_ERROR,
9286489Sjmcp 		    gettext("Invalid device requested (null)\n"));
9296489Sjmcp 		return (FWFLASH_FAILURE);
9306489Sjmcp 	}
9316489Sjmcp 
9326489Sjmcp 	if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) {
9336489Sjmcp 		logmsg(MSG_ERROR,
9346489Sjmcp 		    gettext("Unable to allocate space for device "
9357317SJames.McPherson@Sun.COM 		    "filename, operation might fail if %s is"
9367317SJames.McPherson@Sun.COM 		    "a symbolic link\n"),
9376489Sjmcp 		    device);
9386489Sjmcp 		realfile = device;
9396489Sjmcp 	} else {
9406489Sjmcp 		/*
9416489Sjmcp 		 * If realpath() succeeds, then we have a valid
9426489Sjmcp 		 * device filename in realfile.
9436489Sjmcp 		 */
9446489Sjmcp 		if (realpath(device, realfile) == NULL) {
9456489Sjmcp 			logmsg(MSG_ERROR,
9466489Sjmcp 			    gettext("Unable to resolve device filename"
9477317SJames.McPherson@Sun.COM 			    ": %s\n"),
9486489Sjmcp 			    strerror(errno));
9496489Sjmcp 			/* tidy up */
9506489Sjmcp 			free(realfile);
9516489Sjmcp 			/* realpath didn't succeed, use fallback */
9526489Sjmcp 			realfile = device;
9536489Sjmcp 		} else {
9546489Sjmcp 			needsfree = 1;
9556489Sjmcp 		}
9566489Sjmcp 	}
9576489Sjmcp 
9586489Sjmcp 	logmsg(MSG_INFO,
9596489Sjmcp 	    gettext("fwflash_update: fw_filename (%s) device (%s)\n"),
9606489Sjmcp 	    filename, device);
9616489Sjmcp 
9626489Sjmcp 	TAILQ_FOREACH(curdev, fw_devices, nextdev) {
9636489Sjmcp 		if (strcmp(curdev->access_devname, realfile) == 0) {
9646846Sjmcp 			found++;
9656489Sjmcp 			rv = fwflash_load_verifier(curdev->drvname,
9666489Sjmcp 			    curdev->ident->vid, filename);
9676489Sjmcp 			if (rv == FWFLASH_FAILURE) {
9686489Sjmcp 				logmsg(MSG_ERROR,
9696489Sjmcp 				    gettext("Unable to load verifier "
9707317SJames.McPherson@Sun.COM 				    "for device %s\n"),
9716489Sjmcp 				    curdev->access_devname);
9726489Sjmcp 				return (FWFLASH_FAILURE);
9736489Sjmcp 			}
9746489Sjmcp 			rv = verifier->vendorvrfy(curdev);
9756489Sjmcp 			if (rv == FWFLASH_FAILURE) {
9766489Sjmcp 				/* the verifier prints a message */
9776489Sjmcp 				logmsg(MSG_INFO,
9786489Sjmcp 				    "verifier (%s) for %s :: %s returned "
9796489Sjmcp 				    "FWFLASH_FAILURE\n",
9806489Sjmcp 				    verifier->filename,
9816489Sjmcp 				    filename, curdev->access_devname);
9826489Sjmcp 				return (rv);
9836489Sjmcp 			}
9846489Sjmcp 
9857317SJames.McPherson@Sun.COM 			if (((flags & FWFLASH_YES_FLAG) == FWFLASH_YES_FLAG) ||
9866489Sjmcp 			    (rv = confirm_target(curdev, filename)) ==
9876489Sjmcp 			    FWFLASH_YES_FLAG) {
9886489Sjmcp 				logmsg(MSG_INFO,
9896489Sjmcp 				    "about to flash using plugin %s\n",
9906489Sjmcp 				    curdev->plugin->filename);
9916489Sjmcp 				rv = curdev->plugin->fw_writefw(curdev,
9926489Sjmcp 				    filename);
9936489Sjmcp 				if (rv == FWFLASH_FAILURE) {
9946489Sjmcp 					logmsg(MSG_ERROR,
9956489Sjmcp 					    gettext("Failed to flash "
9967317SJames.McPherson@Sun.COM 					    "firmware file %s on "
9977317SJames.McPherson@Sun.COM 					    "device %s: %d\n"),
9986489Sjmcp 					    filename,
9996489Sjmcp 					    curdev->access_devname, rv);
10006489Sjmcp 				}
10016489Sjmcp 			} else {
10026489Sjmcp 				logmsg(MSG_ERROR,
10036489Sjmcp 				    gettext("Flash operation not confirmed "
10047317SJames.McPherson@Sun.COM 				    "by user\n"),
10056489Sjmcp 				    curdev->access_devname);
10066489Sjmcp 				rv = FWFLASH_FAILURE;
10076489Sjmcp 			}
10086489Sjmcp 		}
10096489Sjmcp 	}
10106489Sjmcp 
10116846Sjmcp 	if (!found)
10126846Sjmcp 		/* report the same device that the user passed in */
10136846Sjmcp 		logmsg(MSG_ERROR,
10146846Sjmcp 		    gettext("Device %s does not appear "
10156846Sjmcp 		    "to be flashable\n"),
10166846Sjmcp 		    ((strncmp(device, realfile, strlen(device)) == 0) ?
10179683SXin.Chen@Sun.COM 		    realfile : device));
10186846Sjmcp 
10196489Sjmcp 	if (needsfree)
10206489Sjmcp 		free(realfile);
10216489Sjmcp 
10226489Sjmcp 	return (rv);
10236489Sjmcp }
10246489Sjmcp 
10256489Sjmcp /*
10266489Sjmcp  * We validate that the device path is in our global device list and
10276489Sjmcp  * that the filename exists, then palm things off to the relevant plugin.
10286489Sjmcp  */
10296489Sjmcp static int
10306489Sjmcp fwflash_read_file(char *device, char *filename)
10316489Sjmcp {
10326489Sjmcp 	struct devicelist *curdev;
10336489Sjmcp 	int rv;
10348031SShantkumar.Hiremath@Sun.COM 	int found = 0;
10356489Sjmcp 
10366489Sjmcp 	/* new firmware filename and device desc */
10376489Sjmcp 
10386489Sjmcp 	TAILQ_FOREACH(curdev, fw_devices, nextdev) {
10396489Sjmcp 		if (strncmp(curdev->access_devname, device,
10406489Sjmcp 		    MAXPATHLEN) == 0) {
10416489Sjmcp 			rv = curdev->plugin->fw_readfw(curdev, filename);
10426489Sjmcp 
10436489Sjmcp 			if (rv != FWFLASH_SUCCESS)
10446489Sjmcp 				logmsg(MSG_ERROR,
10456489Sjmcp 				    gettext("Unable to write out firmware "
10466489Sjmcp 				    "image for %s to file %s\n"),
10476489Sjmcp 				    curdev->access_devname, filename);
10488031SShantkumar.Hiremath@Sun.COM 			found++;
10496489Sjmcp 		}
10506489Sjmcp 
10516489Sjmcp 	}
10528031SShantkumar.Hiremath@Sun.COM 
10538031SShantkumar.Hiremath@Sun.COM 	if (!found) {
10546489Sjmcp 		logmsg(MSG_ERROR,
10556489Sjmcp 		    gettext("No device matching %s was found.\n"),
10566489Sjmcp 		    device);
10576489Sjmcp 		rv = FWFLASH_FAILURE;
10586489Sjmcp 	}
10596489Sjmcp 
10606489Sjmcp 	return (rv);
10616489Sjmcp }
10626489Sjmcp 
10636489Sjmcp static void
10646489Sjmcp fwflash_usage(char *arg)
10656489Sjmcp {
10666489Sjmcp 
10676489Sjmcp 	(void) fprintf(stderr, "\n");
10686489Sjmcp 	if (arg != NULL) {
10696489Sjmcp 		logmsg(MSG_ERROR,
10706489Sjmcp 		    gettext("Invalid argument (%s) supplied\n"), arg);
10716489Sjmcp 	}
10726489Sjmcp 
10736489Sjmcp 	(void) fprintf(stderr, "\n");
10746489Sjmcp 
10756489Sjmcp 	(void) fprintf(stdout, gettext("Usage:\n\t"));
10766489Sjmcp 	(void) fprintf(stdout, gettext("fwflash [-l [-c device_class "
10776489Sjmcp 	    "| ALL]] | [-v] | [-h]\n\t"));
10786489Sjmcp 	(void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3"
10796489Sjmcp 	    ",... | -r file] [-y] -d device_path\n\n"));
10806489Sjmcp 	(void) fprintf(stdout, "\n"); /* workaround for xgettext */
10816489Sjmcp 
10826489Sjmcp 	(void) fprintf(stdout,
10836489Sjmcp 	    gettext("\t-l\t\tlist flashable devices in this system\n"
10846489Sjmcp 	    "\t-c device_class limit search to a specific class\n"
10856489Sjmcp 	    "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n"
10866489Sjmcp 	    "\t-v\t\tprint version number of fwflash utility\n"
10878031SShantkumar.Hiremath@Sun.COM 	    "\t-h\t\tprint this usage message\n\n"));
10886489Sjmcp 	(void) fprintf(stdout,
10896489Sjmcp 	    gettext("\t-f file1,file2,file3,...\n"
10906489Sjmcp 	    "\t\t\tfirmware image file list to flash\n"
10916489Sjmcp 	    "\t-r file\t\tfile to dump device firmware to\n"
10926489Sjmcp 	    "\t-y\t\tanswer Yes/Y/y to prompts\n"
10936489Sjmcp 	    "\t-d device_path\tpathname of device to be flashed\n\n"));
10946489Sjmcp 
10956489Sjmcp 	(void) fprintf(stdout,
10966489Sjmcp 	    gettext("\tIf -d device_path is specified, then one of -f "
10976489Sjmcp 	    "<files>\n"
10986489Sjmcp 	    "\tor -r <file> must also be specified\n\n"));
10996489Sjmcp 
11006489Sjmcp 	(void) fprintf(stdout,
11016489Sjmcp 	    gettext("\tIf multiple firmware images are required to be "
11026489Sjmcp 	    "flashed\n"
11036489Sjmcp 	    "\tthey must be listed together, separated by commas. The\n"
11046489Sjmcp 	    "\timages will be flashed in the order specified.\n\n"));
11056489Sjmcp 
11066489Sjmcp 	(void) fprintf(stdout, "\n");
11076489Sjmcp }
11086489Sjmcp 
11096489Sjmcp static void
11106489Sjmcp fwflash_version(void)
11116489Sjmcp {
11126489Sjmcp 	(void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME);
11136489Sjmcp 	(void) fprintf(stdout, gettext("version %s\n"),
11146489Sjmcp 	    FWFLASH_VERSION);
11156489Sjmcp }
11166489Sjmcp 
11176489Sjmcp static void
11186489Sjmcp fwflash_intr(int sig)
11196489Sjmcp {
11206489Sjmcp 
11216489Sjmcp 	struct devicelist *thisdev;
11226489Sjmcp 	struct pluginlist *thisplug;
11236489Sjmcp 
11246489Sjmcp 	(void) signal(SIGINT, SIG_IGN);
11256489Sjmcp 	(void) signal(SIGTERM, SIG_IGN);
11266846Sjmcp 	(void) signal(SIGABRT, SIG_IGN);
11279683SXin.Chen@Sun.COM 
11286489Sjmcp 	if (fwflash_in_write) {
11296489Sjmcp 		(void) fprintf(stderr,
11306489Sjmcp 		    gettext("WARNING: firmware image may be corrupted\n\t"));
11316489Sjmcp 		(void) fprintf(stderr,
11326489Sjmcp 		    gettext("Reflash firmware before rebooting!\n"));
11336489Sjmcp 	}
11346489Sjmcp 
11356489Sjmcp 	if (sig > 0) {
11366489Sjmcp 		(void) logmsg(MSG_ERROR, gettext("\n"));
11376489Sjmcp 		(void) logmsg(MSG_ERROR,
11386489Sjmcp 		    gettext("fwflash exiting due to signal (%d)\n"), sig);
11396489Sjmcp 	}
11406489Sjmcp 
11416489Sjmcp 	/*
11426489Sjmcp 	 * we need to close everything down properly, so
11436489Sjmcp 	 * call the plugin closure routines
11446489Sjmcp 	 */
11456489Sjmcp 	if (fw_devices != NULL) {
11466489Sjmcp 		TAILQ_FOREACH(thisdev, fw_devices, nextdev) {
11479683SXin.Chen@Sun.COM 			if (thisdev->plugin->fw_cleanup != NULL) {
11489683SXin.Chen@Sun.COM 				/*
11499683SXin.Chen@Sun.COM 				 * If we've got a cleanup routine, it
11509683SXin.Chen@Sun.COM 				 * cleans up _everything_ for thisdev
11519683SXin.Chen@Sun.COM 				 */
11529683SXin.Chen@Sun.COM 				thisdev->plugin->fw_cleanup(thisdev);
11539683SXin.Chen@Sun.COM 			} else {
11549683SXin.Chen@Sun.COM 				/* free the components first */
11559683SXin.Chen@Sun.COM 				free(thisdev->access_devname);
11569683SXin.Chen@Sun.COM 				free(thisdev->drvname);
11579683SXin.Chen@Sun.COM 				free(thisdev->classname);
11589683SXin.Chen@Sun.COM 				if (thisdev->ident != NULL)
11599683SXin.Chen@Sun.COM 					free(thisdev->ident);
11609683SXin.Chen@Sun.COM 				/* We don't free address[] for old plugins */
11619683SXin.Chen@Sun.COM 				thisdev->ident = NULL;
11629683SXin.Chen@Sun.COM 				thisdev->plugin = NULL;
11639683SXin.Chen@Sun.COM 			}
11646489Sjmcp 			/* CONSTCOND */
11656489Sjmcp 			TAILQ_REMOVE(fw_devices, thisdev, nextdev);
11666489Sjmcp 		}
11676489Sjmcp 	}
11686489Sjmcp 
11696489Sjmcp 	if (fw_pluginlist != NULL) {
11706489Sjmcp 		TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) {
11716489Sjmcp 			free(thisplug->filename);
11726489Sjmcp 			free(thisplug->drvname);
11736489Sjmcp 			free(thisplug->plugin->filename);
11746489Sjmcp 			free(thisplug->plugin->drvname);
11756489Sjmcp 			thisplug->filename = NULL;
11766489Sjmcp 			thisplug->drvname = NULL;
11776489Sjmcp 			thisplug->plugin->filename = NULL;
11786489Sjmcp 			thisplug->plugin->drvname = NULL;
11796489Sjmcp 			thisplug->plugin->fw_readfw = NULL;
11806489Sjmcp 			thisplug->plugin->fw_writefw = NULL;
11816489Sjmcp 			thisplug->plugin->fw_identify = NULL;
11826489Sjmcp 			thisplug->plugin->fw_devinfo = NULL;
11839683SXin.Chen@Sun.COM 			thisplug->plugin->fw_cleanup = NULL;
11846489Sjmcp 			(void) dlclose(thisplug->plugin->handle);
11856489Sjmcp 			thisplug->plugin->handle = NULL;
11866489Sjmcp 			free(thisplug->plugin);
11876489Sjmcp 			thisplug->plugin = NULL;
11886489Sjmcp 			/* CONSTCOND */
11896489Sjmcp 			TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin);
11906489Sjmcp 		}
11916489Sjmcp 	}
11926489Sjmcp 
11936489Sjmcp 	if (verifier != NULL) {
11946489Sjmcp 		free(verifier->filename);
11956489Sjmcp 		free(verifier->vendor);
11966846Sjmcp 		free(verifier->imgfile);
11976846Sjmcp 		free(verifier->fwimage);
11986489Sjmcp 		verifier->filename = NULL;
11996489Sjmcp 		verifier->vendor = NULL;
12006489Sjmcp 		verifier->vendorvrfy = NULL;
12016846Sjmcp 		verifier->imgfile = NULL;
12026846Sjmcp 		verifier->fwimage = NULL;
12036489Sjmcp 		(void) dlclose(verifier->handle);
12046489Sjmcp 		verifier->handle = NULL;
12056489Sjmcp 		free(verifier);
12066489Sjmcp 	}
12076489Sjmcp 	di_fini(rootnode);
12089683SXin.Chen@Sun.COM 
12099683SXin.Chen@Sun.COM 	if (sig > 0)
12109683SXin.Chen@Sun.COM 		exit(FWFLASH_FAILURE);
12116489Sjmcp }
12126489Sjmcp 
12136489Sjmcp static void
12146489Sjmcp fwflash_handle_signals(void)
12156489Sjmcp {
12166489Sjmcp 	if (signal(SIGINT, fwflash_intr) == SIG_ERR) {
12176489Sjmcp 		perror("signal");
12186489Sjmcp 		exit(FWFLASH_FAILURE);
12196489Sjmcp 	}
12206489Sjmcp 
12216489Sjmcp 	if (signal(SIGTERM, fwflash_intr) == SIG_ERR) {
12226489Sjmcp 		perror("signal");
12236489Sjmcp 		exit(FWFLASH_FAILURE);
12246489Sjmcp 	}
12256489Sjmcp }
12266489Sjmcp 
12276489Sjmcp static int
12286489Sjmcp confirm_target(struct devicelist *thisdev, char *file)
12296489Sjmcp {
12306489Sjmcp 	int resp;
12316489Sjmcp 
12326846Sjmcp 	(void) fflush(stdin);
12336846Sjmcp 	(void) printf(gettext("About to update firmware on %s\n"),
12346846Sjmcp 	    thisdev->access_devname);
12359683SXin.Chen@Sun.COM 	(void) printf(gettext("with file %s.\n"
12369683SXin.Chen@Sun.COM 	    "Do you want to continue? (Y/N): "), file);
12376489Sjmcp 
12386489Sjmcp 	resp = getchar();
12396489Sjmcp 	if (resp == 'Y' || resp == 'y') {
12406489Sjmcp 		return (FWFLASH_YES_FLAG);
12416489Sjmcp 	} else {
12426489Sjmcp 		logmsg(MSG_INFO, "flash operation NOT confirmed.\n");
12436489Sjmcp 	}
12446489Sjmcp 
12456489Sjmcp 	(void) fflush(stdin);
12466489Sjmcp 	return (FWFLASH_FAILURE);
12476489Sjmcp }
12486489Sjmcp 
12496489Sjmcp int
12506489Sjmcp get_fileopts(char *options)
12516489Sjmcp {
12526489Sjmcp 
12536489Sjmcp 	int i;
12546489Sjmcp 	char *files;
12556489Sjmcp 
12566489Sjmcp 	if (files = strtok(options, ",")) {
12576489Sjmcp 		/* we have more than one */
12586489Sjmcp 		if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
12596489Sjmcp 			logmsg(MSG_ERROR,
12606489Sjmcp 			    gettext("Unable to allocate space for "
12616489Sjmcp 			    "a firmware image filename\n"));
12626489Sjmcp 			return (FWFLASH_FAILURE);
12636489Sjmcp 		}
12646489Sjmcp 		(void) strlcpy(filelist[0], files, strlen(files) + 1);
12656489Sjmcp 		i = 1;
12666489Sjmcp 
12676489Sjmcp 		logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
12686489Sjmcp 		    filelist[0]);
12696489Sjmcp 
12706489Sjmcp 
12716489Sjmcp 		while (files = strtok(NULL, ",")) {
12726489Sjmcp 			if ((filelist[i] = calloc(1, MAXPATHLEN + 1))
12736489Sjmcp 			    == NULL) {
12746489Sjmcp 				logmsg(MSG_ERROR,
12756489Sjmcp 				    gettext("Unable to allocate space for "
12766489Sjmcp 				    "a firmware image filename\n"));
12776489Sjmcp 				return (FWFLASH_FAILURE);
12786489Sjmcp 			}
12796489Sjmcp 			(void) strlcpy(filelist[i], files,
12806489Sjmcp 			    strlen(files) + 1);
12816489Sjmcp 			logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n",
12826489Sjmcp 			    i, filelist[i]);
12836489Sjmcp 			++i;
12846489Sjmcp 		}
12856489Sjmcp 	} else {
12866489Sjmcp 		if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
12876489Sjmcp 			logmsg(MSG_ERROR,
12886489Sjmcp 			    gettext("Unable to allocate space for "
12896489Sjmcp 			    "a firmware image filename\n"));
12906489Sjmcp 			return (FWFLASH_FAILURE);
12916489Sjmcp 		}
12926489Sjmcp 		(void) strlcpy(filelist[0], options, strlen(files) + 1);
12936489Sjmcp 		logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
12946489Sjmcp 		    filelist[0]);
12956489Sjmcp 	}
12966489Sjmcp 	return (FWFLASH_SUCCESS);
12976489Sjmcp }
12986489Sjmcp 
12996489Sjmcp /*
13006489Sjmcp  * code reuse - cheerfully borrowed from stmsboot_util.c
13016489Sjmcp  */
13026489Sjmcp void
13039683SXin.Chen@Sun.COM logmsg(int severity, const char *msg, ...)
13049683SXin.Chen@Sun.COM {
13056489Sjmcp 	va_list ap;
13066489Sjmcp 
13076489Sjmcp 	if ((severity > MSG_INFO) ||
13086489Sjmcp 	    ((severity == MSG_INFO) && (fwflash_debug > 0))) {
13096489Sjmcp 		(void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME);
13106489Sjmcp 		va_start(ap, msg);
13116489Sjmcp 		(void) vfprintf(stderr, msg, ap);
13126489Sjmcp 		va_end(ap);
13136489Sjmcp 	}
13146489Sjmcp }
1315