Home | History | Annotate | Download | only in common
      1 /*
      2  * CDDL HEADER START
      3  *
      4  * The contents of this file are subject to the terms of the
      5  * Common Development and Distribution License (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 /*
     27  * fwflash.c
     28  */
     29 #include <stdio.h>
     30 #include <stdlib.h>
     31 #include <unistd.h>
     32 #include <strings.h>
     33 #include <errno.h>
     34 #include <sys/queue.h>
     35 #include <signal.h>
     36 #include <locale.h>
     37 #include <sys/stat.h>
     38 #include <sys/types.h>
     39 #include <sys/param.h>
     40 #include <fcntl.h>
     41 #include <dlfcn.h>
     42 #include <dirent.h>
     43 #include <sys/varargs.h>
     44 #include <libintl.h> /* for gettext(3c) */
     45 #include <libdevinfo.h>
     46 #include <libscf_priv.h>
     47 #include <fwflash/fwflash.h>
     48 #include <sys/modctl.h> /* for MAXMODCONFNAME */
     49 
     50 
     51 #if !defined(lint)
     52 /* embedded software license agreement */
     53 static char *sla [] = { "Copyright 2009 Sun Microsystems, Inc., 4150 Network "
     54 "Circle, Santa Clara, California 95054, U.S.A. All rights reserved. U.S. "
     55 "Government Rights - Commercial software.  Government users are subject to the "
     56 "Sun Microsystems, Inc. standard license agreement and applicable provisions "
     57 "of the FAR and its supplements.  Use is subject to license terms.  Parts of "
     58 "the product may be derived from Berkeley BSD systems, licensed from the "
     59 "University of California. UNIX is a registered trademark in the U.S. and in "
     60 "other countries, exclusively licensed through X/Open Company, Ltd.Sun, Sun "
     61 "Microsystems, the Sun logo and Solaris are trademarks or registered "
     62 "trademarks of Sun Microsystems, Inc. in the U.S. and other countries. This "
     63 "product is covered and controlled by U.S. Export Control laws and may be "
     64 "subject to the export or import laws in other countries.  Nuclear, missile, "
     65 "chemical biological weapons or nuclear maritime end uses or end users, "
     66 "whether direct or indirect, are strictly prohibited.  Export or reexport "
     67 "to countries subject to U.S. embargo or to entities identified on U.S. export "
     68 "exclusion lists, including, but not limited to, the denied persons and "
     69 "specially designated nationals lists is strictly prohibited." };
     70 #endif	/* lint */
     71 
     72 /* global arg list */
     73 int	fwflash_arg_list = 0;
     74 char	*filelist[10];
     75 
     76 /* exposed global args */
     77 di_node_t rootnode;
     78 struct PLUGINLIST *fw_pluginlist;
     79 struct DEVICELIST *fw_devices;
     80 struct vrfyplugin *verifier;
     81 struct fw_plugin *self;
     82 int fwflash_debug = 0;
     83 
     84 /* are we writing to flash? */
     85 static int fwflash_in_write = 0;
     86 
     87 /*
     88  * If we *must* track the version string for fwflash, then
     89  * we should do so in this common file rather than the header
     90  * file since it will then be in sync with what the customer
     91  * sees. We should deprecate the "-v" option since it is not
     92  * actually of any use - it doesn't line up with Mercurial's
     93  * concept of the changeset.
     94  */
     95 #define	FWFLASH_VERSION		"v1.9"
     96 #define	FWFLASH_PROG_NAME	"fwflash"
     97 
     98 static int get_fileopts(char *options);
     99 static int flash_device_list();
    100 static int flash_load_plugins();
    101 static int fwflash_update(char *device, char *filename, int flags);
    102 static int fwflash_read_file(char *device, char *filename);
    103 static int fwflash_list_fw(char *class);
    104 static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg);
    105 static void fwflash_intr(int sig);
    106 static void fwflash_handle_signals(void);
    107 static void fwflash_usage(char *arg);
    108 static void fwflash_version(void);
    109 static int confirm_target(struct devicelist *thisdev, char *file);
    110 
    111 /*
    112  * FWFlash main code
    113  */
    114 int
    115 main(int argc, char **argv)
    116 {
    117 	int		rv = FWFLASH_SUCCESS;
    118 	int		i;
    119 	char		ch;
    120 	char		*read_file;
    121 	extern char	*optarg;
    122 	char		*devclass = NULL;
    123 	char		*devpath = NULL;
    124 
    125 	/* local variables from env */
    126 	(void) setlocale(LC_ALL, "");
    127 
    128 #if !defined(TEXT_DOMAIN)		/* Should be defined by cc -D */
    129 #define	TEXT_DOMAIN	"SYS_TEST"	/* Use this only if it isn't. */
    130 #endif
    131 
    132 	(void) textdomain(TEXT_DOMAIN);
    133 
    134 	read_file = NULL;
    135 
    136 	if (argc < 2) {
    137 		/* no args supplied */
    138 		fwflash_usage(NULL);
    139 		return (FWFLASH_FAILURE);
    140 	}
    141 
    142 	while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:")) != EOF) {
    143 		switch (ch) {
    144 		case 'h':
    145 			fwflash_arg_list |= FWFLASH_HELP_FLAG;
    146 			break;
    147 		case 'v':
    148 			fwflash_arg_list |= FWFLASH_VER_FLAG;
    149 			break;
    150 		case 'y':
    151 			fwflash_arg_list |= FWFLASH_YES_FLAG;
    152 			break;
    153 		case 'l':
    154 			fwflash_arg_list |= FWFLASH_LIST_FLAG;
    155 			break;
    156 		case 'c':
    157 			fwflash_arg_list |= FWFLASH_CLASS_FLAG;
    158 			/* we validate later */
    159 			devclass = strdup(optarg);
    160 			break;
    161 		case 'd':
    162 			fwflash_arg_list |= FWFLASH_DEVICE_FLAG;
    163 			devpath = strdup(optarg);
    164 			break;
    165 		case 'f':
    166 			fwflash_arg_list |= FWFLASH_FW_FLAG;
    167 			if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) {
    168 				fwflash_usage(NULL);
    169 				return (FWFLASH_FAILURE);
    170 			}
    171 			break;
    172 		case 'r':
    173 			fwflash_arg_list |= FWFLASH_READ_FLAG;
    174 			read_file = strdup(optarg);
    175 			break;
    176 		case 'Q':
    177 			/* NOT in the manpage */
    178 			fwflash_debug = 1;
    179 			break;
    180 		/* illegal options */
    181 		default:
    182 			fwflash_usage(optarg);
    183 			return (FWFLASH_FAILURE);
    184 		}
    185 	}
    186 
    187 	/* Do Help */
    188 	if ((fwflash_arg_list & FWFLASH_HELP_FLAG) ||
    189 	    ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) &&
    190 	    !((fwflash_arg_list & FWFLASH_FW_FLAG) ||
    191 	    (fwflash_arg_list & FWFLASH_READ_FLAG)))) {
    192 		fwflash_usage(NULL);
    193 		return (FWFLASH_SUCCESS);
    194 	}
    195 
    196 	/* Do Version */
    197 	if (fwflash_arg_list == FWFLASH_VER_FLAG) {
    198 		fwflash_version();
    199 		return (FWFLASH_SUCCESS);
    200 	}
    201 
    202 	/* generate global list of devices */
    203 	if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) {
    204 		logmsg(MSG_ERROR,
    205 		    gettext("Unable to load fwflash plugins\n"));
    206 		fwflash_intr(0);
    207 		return (rv);
    208 	}
    209 
    210 	if ((rv = flash_device_list()) != FWFLASH_SUCCESS) {
    211 		logmsg(MSG_ERROR,
    212 		    gettext("No flashable devices in this system\n"));
    213 		fwflash_intr(0);
    214 		return (rv);
    215 	}
    216 
    217 	/* Do list */
    218 	if (fwflash_arg_list == (FWFLASH_LIST_FLAG) ||
    219 	    fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) {
    220 		rv = fwflash_list_fw(devclass);
    221 		fwflash_intr(0);
    222 		return (rv);
    223 	}
    224 
    225 	fwflash_handle_signals();
    226 
    227 	/* Do flash update (write) */
    228 	if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) ||
    229 	    (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG |
    230 	    FWFLASH_YES_FLAG))) {
    231 		int fastreboot_disabled = 0;
    232 		/* the update function handles the real arg parsing */
    233 		i = 0;
    234 		while (filelist[i] != NULL) {
    235 			if ((rv = fwflash_update(devpath, filelist[i],
    236 			    fwflash_arg_list)) == FWFLASH_SUCCESS) {
    237 				/* failed ops have already been noted */
    238 				if (!fastreboot_disabled &&
    239 				    scf_fastreboot_default_set_transient(
    240 				    B_FALSE) != SCF_SUCCESS)
    241 					logmsg(MSG_ERROR, gettext(
    242 					    "Failed to disable fast "
    243 					    "reboot.\n"));
    244 				else
    245 					fastreboot_disabled = 1;
    246 				logmsg(MSG_ERROR,
    247 				    gettext("New firmware will be activated "
    248 				    "after you reboot\n\n"));
    249 			}
    250 			++i;
    251 		}
    252 
    253 		fwflash_intr(0);
    254 		return (rv);
    255 	}
    256 
    257 	/* Do flash read */
    258 	if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) ||
    259 	    (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG |
    260 	    FWFLASH_YES_FLAG))) {
    261 		rv = fwflash_read_file(devpath, read_file);
    262 		fwflash_intr(0);
    263 		return (rv);
    264 	}
    265 
    266 	fwflash_usage(NULL);
    267 
    268 	return (FWFLASH_FAILURE);
    269 }
    270 
    271 
    272 static int
    273 flash_load_plugins()
    274 {
    275 
    276 	int rval = FWFLASH_SUCCESS;
    277 	DIR *dirp;
    278 	struct dirent *plugdir;
    279 	char *plugname;
    280 	struct fw_plugin *tmpplug;
    281 	struct pluginlist *tmpelem;
    282 	void *sym;
    283 	char *fwplugdirpath, *tempdirpath;
    284 
    285 
    286 #define	CLOSEFREE()	{			\
    287 	(void) dlclose(tmpplug->handle);	\
    288 	free(tmpplug); }
    289 
    290 	/*
    291 	 * Procedure:
    292 	 *
    293 	 * cd /usr/lib/fwflash/identify
    294 	 * open each .so file found therein
    295 	 * dlopen(.sofile)
    296 	 * if it's one of our plugins, add it to fw_pluginlist;
    297 	 *
    298 	 * functions we need here include dlopen and dlsym.
    299 	 *
    300 	 * If we get to the end and fw_pluginlist struct is empty,
    301 	 * return FWFLASH_FAILURE so we return to the shell.
    302 	 */
    303 
    304 	if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
    305 		logmsg(MSG_ERROR,
    306 		    gettext("Unable to malloc %d bytes while "
    307 		    "trying to load plugins: %s\n"),
    308 		    MAXPATHLEN + 1, strerror(errno));
    309 		return (FWFLASH_FAILURE);
    310 	}
    311 
    312 	tempdirpath = getenv("FWPLUGINDIR");
    313 
    314 	if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
    315 		(void) strlcpy(fwplugdirpath, tempdirpath,
    316 		    strlen(tempdirpath) + 1);
    317 	} else {
    318 		(void) strlcpy(fwplugdirpath, FWPLUGINDIR,
    319 		    strlen(FWPLUGINDIR) + 1);
    320 	}
    321 
    322 	if ((dirp = opendir(fwplugdirpath)) == NULL) {
    323 		logmsg(MSG_ERROR,
    324 		    gettext("Unable to open %s\n"),
    325 		    fwplugdirpath);
    326 		return (errno);
    327 	}
    328 
    329 	if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1))
    330 	    == NULL) {
    331 		logmsg(MSG_ERROR,
    332 		    gettext("Unable to malloc %d bytes while "
    333 		    "trying to load plugins: %s\n"),
    334 		    MAXPATHLEN + 1 + sizeof (struct dirent),
    335 		    strerror(errno));
    336 		return (FWFLASH_FAILURE);
    337 	}
    338 
    339 	if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin)))
    340 	    == NULL) {
    341 		logmsg(MSG_ERROR,
    342 		    gettext("Unable to malloc %d bytes while "
    343 		    "trying to load plugins: %s\n"),
    344 		    sizeof (struct fw_plugin), strerror(errno));
    345 		return (FWFLASH_FAILURE);
    346 	}
    347 
    348 	TAILQ_INIT(fw_pluginlist);
    349 
    350 	while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) {
    351 
    352 		errno = 0; /* remove chance of false results */
    353 
    354 		if ((plugdir->d_name[0] == '.') ||
    355 		    (strstr(plugdir->d_name, ".so") == NULL)) {
    356 			continue;
    357 		}
    358 
    359 		if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) {
    360 			logmsg(MSG_ERROR,
    361 			    gettext("Unable to malloc %d bytes while "
    362 			    "trying to load plugins: %s\n"),
    363 			    MAXPATHLEN + 1, strerror(errno));
    364 			return (FWFLASH_FAILURE);
    365 		}
    366 
    367 		(void) snprintf(plugname, MAXPATHLEN, "%s/%s",
    368 		    fwplugdirpath, plugdir->d_name);
    369 
    370 		/* start allocating storage */
    371 		if ((tmpelem = calloc(1, sizeof (struct pluginlist)))
    372 		    == NULL) {
    373 			logmsg(MSG_ERROR,
    374 			    gettext("Unable to malloc %d bytes while "
    375 			    "trying to load plugins: %s\n"),
    376 			    sizeof (struct pluginlist), strerror(errno));
    377 			return (FWFLASH_FAILURE);
    378 		}
    379 
    380 		if ((tmpplug = calloc(1, sizeof (struct fw_plugin)))
    381 		    == NULL) {
    382 			logmsg(MSG_ERROR,
    383 			    gettext("Unable to malloc %d bytes while "
    384 			    "trying to load plugins: %s\n"),
    385 			    sizeof (struct fw_plugin), strerror(errno));
    386 			return (FWFLASH_FAILURE);
    387 		}
    388 
    389 		/* load 'er up! */
    390 		tmpplug->handle = dlopen(plugname, RTLD_NOW);
    391 		if (tmpplug->handle == NULL) {
    392 			free(tmpplug);
    393 			continue; /* assume there are other plugins */
    394 		}
    395 
    396 		if ((tmpplug->filename = calloc(1, strlen(plugname) + 1))
    397 		    == NULL) {
    398 			logmsg(MSG_ERROR,
    399 			    gettext("Unable to allocate %d bytes for plugin "
    400 			    "filename %s:%s\n"),
    401 			    strlen(plugname) + 1, plugname,
    402 			    strerror(errno));
    403 			return (rval);
    404 		}
    405 
    406 		(void) strlcpy(tmpplug->filename, plugname,
    407 		    strlen(plugname) + 1);
    408 
    409 		/* now sanity check the file */
    410 		if ((sym = dlsym(tmpplug->handle, "drivername"))
    411 		    != NULL) {
    412 			/* max length of drivername */
    413 			tmpplug->drvname = calloc(1, MAXMODCONFNAME);
    414 
    415 			/* are we doing double-time? */
    416 			if (strncmp((char *)sym, plugdir->d_name,
    417 			    MAXMODCONFNAME) != 0) {
    418 				char *tempnm = calloc(1, MAXMODCONFNAME);
    419 
    420 				(void) memcpy(tempnm, plugdir->d_name,
    421 				    MAXMODCONFNAME);
    422 				(void) strlcpy(tmpplug->drvname,
    423 				    strtok(tempnm, "."),
    424 				    strlen(plugdir->d_name) + 1);
    425 				free(tempnm);
    426 			} else {
    427 				(void) strlcpy(tmpplug->drvname,
    428 				    (char *)sym, strlen(sym) + 1);
    429 			}
    430 		} else {
    431 			CLOSEFREE();
    432 			continue;
    433 		}
    434 		if ((sym = dlsym(tmpplug->handle, "fw_readfw"))
    435 		    != NULL) {
    436 			tmpplug->fw_readfw = (int (*)())sym;
    437 		} else {
    438 			CLOSEFREE();
    439 			continue;
    440 		}
    441 		if ((sym = dlsym(tmpplug->handle, "fw_writefw"))
    442 		    != NULL) {
    443 			tmpplug->fw_writefw = (int (*)())sym;
    444 		} else {
    445 			CLOSEFREE();
    446 			continue;
    447 		}
    448 
    449 		if ((sym = dlsym(tmpplug->handle, "fw_identify"))
    450 		    != NULL) {
    451 			tmpplug->fw_identify =
    452 			    (int (*)(int))sym;
    453 		} else {
    454 			CLOSEFREE();
    455 			continue;
    456 		}
    457 		if ((sym = dlsym(tmpplug->handle, "fw_devinfo"))
    458 		    != NULL) {
    459 			tmpplug->fw_devinfo =
    460 			    (int (*)(struct devicelist *))sym;
    461 		} else {
    462 			CLOSEFREE();
    463 			continue;
    464 		}
    465 
    466 		if ((sym = dlsym(tmpplug->handle, "plugin_version"))
    467 		    != NULL) {
    468 			if ((*(int *)sym) >= FWPLUGIN_VERSION_2) {
    469 				if ((sym = dlsym(tmpplug->handle,
    470 				    "fw_cleanup")) != NULL) {
    471 					tmpplug->fw_cleanup =
    472 					    (void (*)(struct devicelist *))sym;
    473 				} else {
    474 					logmsg(MSG_ERROR,
    475 					    gettext("ERROR: v2 plugin (%s) "
    476 					    "has no fw_cleanup function\n"),
    477 					    tmpplug->filename);
    478 					CLOSEFREE();
    479 					continue;
    480 				}
    481 			} else {
    482 				logmsg(MSG_INFO,
    483 				    "Identification plugin %s defined "
    484 				    "plugin_version < FWPLUGIN_VERSION_2 !");
    485 			}
    486 		}
    487 
    488 		if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME))
    489 		    == NULL) {
    490 			logmsg(MSG_ERROR,
    491 			    gettext("Unable to allocate space for a"
    492 			    "drivername %s\n"),
    493 			    tmpplug->drvname);
    494 			return (FWFLASH_FAILURE);
    495 		}
    496 
    497 		(void) strlcpy(tmpelem->drvname, tmpplug->drvname,
    498 		    strlen(tmpplug->drvname) + 1);
    499 
    500 		if ((tmpelem->filename = calloc(1,
    501 		    strlen(tmpplug->filename) + 1)) == NULL) {
    502 			logmsg(MSG_ERROR,
    503 			    gettext("Unable to allocate %d bytes for "
    504 			    "filename %s\n"),
    505 			    strlen(tmpplug->filename) + 1,
    506 			    tmpplug->filename);
    507 			return (FWFLASH_FAILURE);
    508 		}
    509 
    510 		(void) strlcpy(tmpelem->filename, plugname,
    511 		    strlen(plugname) + 1);
    512 		tmpelem->plugin = tmpplug;
    513 
    514 		/* CONSTCOND */
    515 		TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin);
    516 	}
    517 
    518 	if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) {
    519 		return (FWFLASH_FAILURE);
    520 	}
    521 
    522 	if (errno != 0) {
    523 		logmsg(MSG_ERROR,
    524 		    gettext("Error reading directory entry in %s\n"),
    525 		    fwplugdirpath);
    526 		rval = errno;
    527 	}
    528 
    529 	free(fwplugdirpath);
    530 	free(plugdir);
    531 	(void) closedir(dirp);
    532 	return (rval);
    533 }
    534 
    535 /*
    536  * fwflash_load_verifier dlload()s the appropriate firmware image
    537  * verification plugin, and attaches the designated fwimg's fd to
    538  * the vrfyplugin structure so we only have to load the image in
    539  * one place.
    540  */
    541 int
    542 fwflash_load_verifier(char *drv, char *vendorid, char *fwimg)
    543 {
    544 
    545 	int rv = FWFLASH_FAILURE;
    546 	int imgfd;
    547 	char *fwvrfydirpath, *tempdirpath, *filename;
    548 	char *clean; /* for the space-removed vid */
    549 	struct stat fwstat;
    550 	struct vrfyplugin *vrfy;
    551 	void *vrfysym;
    552 
    553 	/*
    554 	 * To make flashing multiple firmware images somewhat more
    555 	 * efficient, we start this function by checking whether a
    556 	 * verifier for this device has already been loaded. If it
    557 	 * has been loaded, we replace the imgfile information, and
    558 	 * then continue as if we were loading for the first time.
    559 	 */
    560 
    561 	if (verifier != NULL) {
    562 		verifier->imgsize = 0;
    563 		verifier->flashbuf = 0; /* set by the verifier function */
    564 
    565 		if (verifier->imgfile != NULL) {
    566 			free(verifier->imgfile);
    567 			verifier->imgfile = NULL;
    568 		}
    569 
    570 		if (verifier->fwimage != NULL) {
    571 			free(verifier->fwimage);
    572 			verifier->fwimage = NULL;
    573 		}
    574 	} else {
    575 		if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
    576 			logmsg(MSG_ERROR,
    577 			    gettext("Unable to allocate space for a firmware "
    578 			    "verifier file(1)"));
    579 			return (rv);
    580 		}
    581 
    582 		if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) {
    583 			logmsg(MSG_ERROR,
    584 			    gettext("Unable to allocate space "
    585 			    "for a firmware verifier file(2)"));
    586 			free(fwvrfydirpath);
    587 			return (rv);
    588 		}
    589 
    590 		/*
    591 		 * Since SCSI devices can have a vendor id of up to 8
    592 		 * left-aligned and _space-padded_ characters, we first need to
    593 		 * strip off any space characters before we try to make a
    594 		 * filename out of it
    595 		 */
    596 		clean = strtok(vendorid, " ");
    597 		if (clean == NULL) {
    598 			/* invalid vendorid, something's really wrong */
    599 			logmsg(MSG_ERROR,
    600 			    gettext("Invalid vendorid (null) specified for "
    601 			    "device\n"));
    602 			free(filename);
    603 			free(fwvrfydirpath);
    604 			return (rv);
    605 		}
    606 
    607 		tempdirpath = getenv("FWVERIFYPLUGINDIR");
    608 
    609 		if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
    610 			(void) strlcpy(fwvrfydirpath, tempdirpath,
    611 			    strlen(tempdirpath) + 1);
    612 		} else {
    613 			(void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR,
    614 			    strlen(FWVERIFYPLUGINDIR) + 1);
    615 		}
    616 
    617 		if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) {
    618 			logmsg(MSG_ERROR,
    619 			    gettext("Unable to allocate space "
    620 			    "for a firmware verifier structure"));
    621 			free(filename);
    622 			free(fwvrfydirpath);
    623 			return (rv);
    624 		}
    625 
    626 		errno = 0; /* false positive removal */
    627 
    628 		(void) snprintf(filename, MAXPATHLEN, "%s/%s-%s.so",
    629 		    fwvrfydirpath, drv, clean);
    630 		if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) {
    631 			logmsg(MSG_INFO, gettext(dlerror()));
    632 			logmsg(MSG_INFO,
    633 			    gettext("\nUnable to open verification plugin "
    634 			    "%s. Looking for %s-GENERIC plugin instead.\n"),
    635 			    filename, drv);
    636 
    637 			/* Try the drv-GENERIC.so form, _then_ die */
    638 			bzero(filename, strlen(filename) + 1);
    639 			(void) snprintf(filename, MAXPATHLEN,
    640 			    "%s/%s-GENERIC.so", fwvrfydirpath, drv);
    641 
    642 			if ((vrfy->handle = dlopen(filename, RTLD_NOW))
    643 			    == NULL) {
    644 				logmsg(MSG_INFO, gettext(dlerror()));
    645 				logmsg(MSG_ERROR,
    646 				    gettext("\nUnable to open either "
    647 				    "verification plugin %s/%s-%s.so or "
    648 				    "generic plugin %s.\nUnable to verify "
    649 				    "firmware image. Aborting.\n"),
    650 				    fwvrfydirpath, drv, clean, filename);
    651 				free(filename);
    652 				free(fwvrfydirpath);
    653 				return (rv);
    654 			}
    655 		}
    656 
    657 		if ((vrfy->filename = calloc(1, strlen(filename) + 1))
    658 		    == NULL) {
    659 			logmsg(MSG_ERROR,
    660 			    gettext("Unable to allocate space to store "
    661 			    "a verifier filename\n"));
    662 			free(filename);
    663 			free(fwvrfydirpath);
    664 			free(vrfy->handle);
    665 			return (rv);
    666 		}
    667 		(void) strlcpy(vrfy->filename, filename, strlen(filename) + 1);
    668 
    669 		if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) {
    670 			logmsg(MSG_ERROR,
    671 			    gettext("%s is an invalid firmware verification "
    672 			    "plugin."), filename);
    673 			(void) dlclose(vrfy->handle);
    674 			free(filename);
    675 			free(fwvrfydirpath);
    676 			free(vrfy);
    677 			return (rv);
    678 		} else {
    679 			vrfy->vendorvrfy =
    680 			    (int (*)(struct devicelist *))vrfysym;
    681 		}
    682 
    683 		vrfysym = dlsym(vrfy->handle, "vendor");
    684 
    685 		if (vrfysym == NULL) {
    686 			logmsg(MSG_ERROR,
    687 			    gettext("Invalid vendor (null) in verification "
    688 			    "plugin %s\n"), filename);
    689 			(void) dlclose(vrfy->handle);
    690 			free(vrfy);
    691 			return (rv);
    692 		} else {
    693 			if (strncmp(vendorid, (char *)vrfysym,
    694 			    strlen(vendorid)) != 0) {
    695 				logmsg(MSG_INFO,
    696 				    "Using a sym-linked (%s -> %s) "
    697 				    "verification plugin\n",
    698 				    vendorid, vrfysym);
    699 				vrfy->vendor = calloc(1, strlen(vendorid) + 1);
    700 			} else {
    701 				vrfy->vendor = calloc(1, strlen(vrfysym) + 1);
    702 			}
    703 			(void) strlcpy(vrfy->vendor, (char *)vrfysym,
    704 			    strlen(vendorid) + 1);
    705 		}
    706 
    707 		verifier = vrfy; /* a convenience variable */
    708 		free(filename);
    709 		free(fwvrfydirpath);
    710 	}
    711 
    712 	/*
    713 	 * We don't do any verification that the fw image file is in
    714 	 * an approved location, but it's easy enough to modify this
    715 	 * function to do so. The verification plugin should provide
    716 	 * sufficient protection.
    717 	 */
    718 
    719 	if ((imgfd = open(fwimg, O_RDONLY)) < 0) {
    720 		logmsg(MSG_ERROR,
    721 		    gettext("Unable to open designated firmware "
    722 		    "image file %s: %s\n"),
    723 		    (fwimg != NULL) ? fwimg : "(null)",
    724 		    strerror(errno));
    725 		rv = FWFLASH_FAILURE;
    726 		goto cleanup;
    727 	}
    728 
    729 	if (stat(fwimg, &fwstat) == -1) {
    730 		logmsg(MSG_ERROR,
    731 		    gettext("Unable to stat() firmware image file "
    732 		    "%s: %s\n"),
    733 		    fwimg, strerror(errno));
    734 		rv = FWFLASH_FAILURE;
    735 		goto cleanup;
    736 	} else {
    737 		verifier->imgsize = fwstat.st_size;
    738 		if ((verifier->fwimage = calloc(1, verifier->imgsize))
    739 		    == NULL) {
    740 			logmsg(MSG_ERROR,
    741 			    gettext("Unable to load firmware image "
    742 			    "%s: %s\n"),
    743 			    fwimg, strerror(errno));
    744 			rv = FWFLASH_FAILURE;
    745 			goto cleanup;
    746 		}
    747 	}
    748 
    749 	errno = 0;
    750 	if ((rv = read(imgfd, verifier->fwimage,
    751 	    (size_t)verifier->imgsize)) < verifier->imgsize) {
    752 		/* we haven't read enough data, bail */
    753 		logmsg(MSG_ERROR,
    754 		    gettext("Failed to read sufficient data "
    755 		    "(got %d bytes, expected %d bytes) from "
    756 		    "firmware image file %s: %s\n"),
    757 		    rv, verifier->imgsize,
    758 		    verifier->filename, strerror(errno));
    759 		rv = FWFLASH_FAILURE;
    760 	} else {
    761 		rv = FWFLASH_SUCCESS;
    762 	}
    763 
    764 	if ((verifier->imgfile = calloc(1, strlen(fwimg) + 1)) == NULL) {
    765 		logmsg(MSG_ERROR,
    766 		    gettext("Unable to save name of firmware image\n"));
    767 		rv = FWFLASH_FAILURE;
    768 	} else {
    769 		(void) strlcpy(verifier->imgfile, fwimg, strlen(fwimg) + 1);
    770 	}
    771 
    772 	if (rv != FWFLASH_SUCCESS) {
    773 		/* cleanup and let's get outta here */
    774 cleanup:
    775 		free(verifier->filename);
    776 		free(verifier->vendor);
    777 
    778 		if (!(fwflash_arg_list & FWFLASH_READ_FLAG) &&
    779 		    verifier->fwimage)
    780 			free(verifier->fwimage);
    781 
    782 		verifier->filename = NULL;
    783 		verifier->vendor = NULL;
    784 		verifier->vendorvrfy = NULL;
    785 		verifier->fwimage = NULL;
    786 		(void) dlclose(verifier->handle);
    787 		verifier->handle = NULL;
    788 		free(verifier);
    789 		if (imgfd >= 0) {
    790 			(void) close(imgfd);
    791 		}
    792 		verifier = NULL;
    793 	}
    794 
    795 	return (rv);
    796 }
    797 
    798 /*
    799  * cycles through the global list of plugins to find
    800  * each flashable device, which is added to fw_devices
    801  *
    802  * Each plugin's identify routine must allocated storage
    803  * as required.
    804  *
    805  * Each plugin's identify routine must return
    806  * FWFLASH_FAILURE if it cannot find any devices
    807  * which it handles.
    808  */
    809 static int
    810 flash_device_list()
    811 {
    812 	int rv = FWFLASH_FAILURE;
    813 	int startidx = 0;
    814 	int sumrv = 0;
    815 	struct pluginlist *plugins;
    816 
    817 	/* we open rootnode here, and close it in fwflash_intr */
    818 	if ((rootnode = di_init("/", DINFOCPYALL|DINFOFORCE)) == DI_NODE_NIL) {
    819 		logmsg(MSG_ERROR,
    820 		    gettext("Unable to take device tree snapshot: %s\n"),
    821 		    strerror(errno));
    822 		return (rv);
    823 	}
    824 
    825 	if ((fw_devices = calloc(1, sizeof (struct devicelist))) == NULL) {
    826 		logmsg(MSG_ERROR,
    827 		    gettext("Unable to malloc %d bytes while "
    828 		    "trying to find devices: %s\n"),
    829 		    sizeof (struct devicelist), strerror(errno));
    830 		return (FWFLASH_FAILURE);
    831 	}
    832 
    833 	/* CONSTCOND */
    834 	TAILQ_INIT(fw_devices);
    835 
    836 	TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) {
    837 		self = plugins->plugin;
    838 		rv = plugins->plugin->fw_identify(startidx);
    839 
    840 		logmsg(MSG_INFO,
    841 		    gettext("fwflash:flash_device_list() got %d from "
    842 		    "identify routine\n"), rv);
    843 
    844 		/* only bump startidx if we've found at least one device */
    845 		if (rv == FWFLASH_SUCCESS) {
    846 			startidx += 100;
    847 			sumrv++;
    848 		} else {
    849 			logmsg(MSG_INFO,
    850 			    gettext("No flashable devices attached with "
    851 			    "the %s driver in this system\n"),
    852 			    plugins->drvname);
    853 		}
    854 	}
    855 
    856 	if (sumrv > 0)
    857 		rv = FWFLASH_SUCCESS;
    858 
    859 	return (rv);
    860 }
    861 
    862 static int
    863 fwflash_list_fw(char *class)
    864 {
    865 	int rv = 0;
    866 	struct devicelist *curdev;
    867 	int header = 1;
    868 
    869 	TAILQ_FOREACH(curdev, fw_devices, nextdev) {
    870 
    871 		/* we're either class-conscious, or we're not */
    872 		if (((class != NULL) &&
    873 		    ((strncmp(curdev->classname, "ALL", 3) == 0) ||
    874 		    (strcmp(curdev->classname, class) == 0))) ||
    875 		    (class == NULL)) {
    876 
    877 			if (header != 0) {
    878 				(void) fprintf(stdout,
    879 				    gettext("List of available devices:\n"));
    880 				header--;
    881 			}
    882 			/*
    883 			 * If any plugin's fw_devinfo() function returns
    884 			 * FWFLASH_FAILURE then we want to keep track of
    885 			 * it. _Most_ plugins should always return
    886 			 * FWFLASH_SUCCESS from this function. The only
    887 			 * exception known at this point is the tavor plugin.
    888 			 */
    889 			rv += curdev->plugin->fw_devinfo(curdev);
    890 		}
    891 	}
    892 	return (rv);
    893 }
    894 
    895 static int
    896 fwflash_update(char *device, char *filename, int flags)
    897 {
    898 
    899 	int rv = FWFLASH_FAILURE;
    900 	int needsfree = 0;
    901 	int found = 0;
    902 	struct devicelist *curdev;
    903 	char *realfile;
    904 
    905 	/*
    906 	 * Here's how we operate:
    907 	 *
    908 	 * We perform some basic checks on the args, then walk
    909 	 * through the device list looking for the device which
    910 	 * matches. We then load the appropriate verifier for the
    911 	 * image file and device, verify the image, then call the
    912 	 * fw_writefw() function of the appropriate plugin.
    913 	 *
    914 	 * There is no "force" flag to enable you to flash a firmware
    915 	 * image onto an incompatible device because the verifier
    916 	 * will return FWFLASH_FAILURE if the image doesn't match.
    917 	 */
    918 
    919 	/* new firmware filename and device desc */
    920 	if (filename == NULL) {
    921 		logmsg(MSG_ERROR,
    922 		    gettext("Invalid firmware filename (null)\n"));
    923 		return (FWFLASH_FAILURE);
    924 	}
    925 
    926 	if (device == NULL) {
    927 		logmsg(MSG_ERROR,
    928 		    gettext("Invalid device requested (null)\n"));
    929 		return (FWFLASH_FAILURE);
    930 	}
    931 
    932 	if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) {
    933 		logmsg(MSG_ERROR,
    934 		    gettext("Unable to allocate space for device "
    935 		    "filename, operation might fail if %s is"
    936 		    "a symbolic link\n"),
    937 		    device);
    938 		realfile = device;
    939 	} else {
    940 		/*
    941 		 * If realpath() succeeds, then we have a valid
    942 		 * device filename in realfile.
    943 		 */
    944 		if (realpath(device, realfile) == NULL) {
    945 			logmsg(MSG_ERROR,
    946 			    gettext("Unable to resolve device filename"
    947 			    ": %s\n"),
    948 			    strerror(errno));
    949 			/* tidy up */
    950 			free(realfile);
    951 			/* realpath didn't succeed, use fallback */
    952 			realfile = device;
    953 		} else {
    954 			needsfree = 1;
    955 		}
    956 	}
    957 
    958 	logmsg(MSG_INFO,
    959 	    gettext("fwflash_update: fw_filename (%s) device (%s)\n"),
    960 	    filename, device);
    961 
    962 	TAILQ_FOREACH(curdev, fw_devices, nextdev) {
    963 		if (strcmp(curdev->access_devname, realfile) == 0) {
    964 			found++;
    965 			rv = fwflash_load_verifier(curdev->drvname,
    966 			    curdev->ident->vid, filename);
    967 			if (rv == FWFLASH_FAILURE) {
    968 				logmsg(MSG_ERROR,
    969 				    gettext("Unable to load verifier "
    970 				    "for device %s\n"),
    971 				    curdev->access_devname);
    972 				return (FWFLASH_FAILURE);
    973 			}
    974 			rv = verifier->vendorvrfy(curdev);
    975 			if (rv == FWFLASH_FAILURE) {
    976 				/* the verifier prints a message */
    977 				logmsg(MSG_INFO,
    978 				    "verifier (%s) for %s :: %s returned "
    979 				    "FWFLASH_FAILURE\n",
    980 				    verifier->filename,
    981 				    filename, curdev->access_devname);
    982 				return (rv);
    983 			}
    984 
    985 			if (((flags & FWFLASH_YES_FLAG) == FWFLASH_YES_FLAG) ||
    986 			    (rv = confirm_target(curdev, filename)) ==
    987 			    FWFLASH_YES_FLAG) {
    988 				logmsg(MSG_INFO,
    989 				    "about to flash using plugin %s\n",
    990 				    curdev->plugin->filename);
    991 				rv = curdev->plugin->fw_writefw(curdev,
    992 				    filename);
    993 				if (rv == FWFLASH_FAILURE) {
    994 					logmsg(MSG_ERROR,
    995 					    gettext("Failed to flash "
    996 					    "firmware file %s on "
    997 					    "device %s: %d\n"),
    998 					    filename,
    999 					    curdev->access_devname, rv);
   1000 				}
   1001 			} else {
   1002 				logmsg(MSG_ERROR,
   1003 				    gettext("Flash operation not confirmed "
   1004 				    "by user\n"),
   1005 				    curdev->access_devname);
   1006 				rv = FWFLASH_FAILURE;
   1007 			}
   1008 		}
   1009 	}
   1010 
   1011 	if (!found)
   1012 		/* report the same device that the user passed in */
   1013 		logmsg(MSG_ERROR,
   1014 		    gettext("Device %s does not appear "
   1015 		    "to be flashable\n"),
   1016 		    ((strncmp(device, realfile, strlen(device)) == 0) ?
   1017 		    realfile : device));
   1018 
   1019 	if (needsfree)
   1020 		free(realfile);
   1021 
   1022 	return (rv);
   1023 }
   1024 
   1025 /*
   1026  * We validate that the device path is in our global device list and
   1027  * that the filename exists, then palm things off to the relevant plugin.
   1028  */
   1029 static int
   1030 fwflash_read_file(char *device, char *filename)
   1031 {
   1032 	struct devicelist *curdev;
   1033 	int rv;
   1034 	int found = 0;
   1035 
   1036 	/* new firmware filename and device desc */
   1037 
   1038 	TAILQ_FOREACH(curdev, fw_devices, nextdev) {
   1039 		if (strncmp(curdev->access_devname, device,
   1040 		    MAXPATHLEN) == 0) {
   1041 			rv = curdev->plugin->fw_readfw(curdev, filename);
   1042 
   1043 			if (rv != FWFLASH_SUCCESS)
   1044 				logmsg(MSG_ERROR,
   1045 				    gettext("Unable to write out firmware "
   1046 				    "image for %s to file %s\n"),
   1047 				    curdev->access_devname, filename);
   1048 			found++;
   1049 		}
   1050 
   1051 	}
   1052 
   1053 	if (!found) {
   1054 		logmsg(MSG_ERROR,
   1055 		    gettext("No device matching %s was found.\n"),
   1056 		    device);
   1057 		rv = FWFLASH_FAILURE;
   1058 	}
   1059 
   1060 	return (rv);
   1061 }
   1062 
   1063 static void
   1064 fwflash_usage(char *arg)
   1065 {
   1066 
   1067 	(void) fprintf(stderr, "\n");
   1068 	if (arg != NULL) {
   1069 		logmsg(MSG_ERROR,
   1070 		    gettext("Invalid argument (%s) supplied\n"), arg);
   1071 	}
   1072 
   1073 	(void) fprintf(stderr, "\n");
   1074 
   1075 	(void) fprintf(stdout, gettext("Usage:\n\t"));
   1076 	(void) fprintf(stdout, gettext("fwflash [-l [-c device_class "
   1077 	    "| ALL]] | [-v] | [-h]\n\t"));
   1078 	(void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3"
   1079 	    ",... | -r file] [-y] -d device_path\n\n"));
   1080 	(void) fprintf(stdout, "\n"); /* workaround for xgettext */
   1081 
   1082 	(void) fprintf(stdout,
   1083 	    gettext("\t-l\t\tlist flashable devices in this system\n"
   1084 	    "\t-c device_class limit search to a specific class\n"
   1085 	    "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n"
   1086 	    "\t-v\t\tprint version number of fwflash utility\n"
   1087 	    "\t-h\t\tprint this usage message\n\n"));
   1088 	(void) fprintf(stdout,
   1089 	    gettext("\t-f file1,file2,file3,...\n"
   1090 	    "\t\t\tfirmware image file list to flash\n"
   1091 	    "\t-r file\t\tfile to dump device firmware to\n"
   1092 	    "\t-y\t\tanswer Yes/Y/y to prompts\n"
   1093 	    "\t-d device_path\tpathname of device to be flashed\n\n"));
   1094 
   1095 	(void) fprintf(stdout,
   1096 	    gettext("\tIf -d device_path is specified, then one of -f "
   1097 	    "<files>\n"
   1098 	    "\tor -r <file> must also be specified\n\n"));
   1099 
   1100 	(void) fprintf(stdout,
   1101 	    gettext("\tIf multiple firmware images are required to be "
   1102 	    "flashed\n"
   1103 	    "\tthey must be listed together, separated by commas. The\n"
   1104 	    "\timages will be flashed in the order specified.\n\n"));
   1105 
   1106 	(void) fprintf(stdout, "\n");
   1107 }
   1108 
   1109 static void
   1110 fwflash_version(void)
   1111 {
   1112 	(void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME);
   1113 	(void) fprintf(stdout, gettext("version %s\n"),
   1114 	    FWFLASH_VERSION);
   1115 }
   1116 
   1117 static void
   1118 fwflash_intr(int sig)
   1119 {
   1120 
   1121 	struct devicelist *thisdev;
   1122 	struct pluginlist *thisplug;
   1123 
   1124 	(void) signal(SIGINT, SIG_IGN);
   1125 	(void) signal(SIGTERM, SIG_IGN);
   1126 	(void) signal(SIGABRT, SIG_IGN);
   1127 
   1128 	if (fwflash_in_write) {
   1129 		(void) fprintf(stderr,
   1130 		    gettext("WARNING: firmware image may be corrupted\n\t"));
   1131 		(void) fprintf(stderr,
   1132 		    gettext("Reflash firmware before rebooting!\n"));
   1133 	}
   1134 
   1135 	if (sig > 0) {
   1136 		(void) logmsg(MSG_ERROR, gettext("\n"));
   1137 		(void) logmsg(MSG_ERROR,
   1138 		    gettext("fwflash exiting due to signal (%d)\n"), sig);
   1139 	}
   1140 
   1141 	/*
   1142 	 * we need to close everything down properly, so
   1143 	 * call the plugin closure routines
   1144 	 */
   1145 	if (fw_devices != NULL) {
   1146 		TAILQ_FOREACH(thisdev, fw_devices, nextdev) {
   1147 			if (thisdev->plugin->fw_cleanup != NULL) {
   1148 				/*
   1149 				 * If we've got a cleanup routine, it
   1150 				 * cleans up _everything_ for thisdev
   1151 				 */
   1152 				thisdev->plugin->fw_cleanup(thisdev);
   1153 			} else {
   1154 				/* free the components first */
   1155 				free(thisdev->access_devname);
   1156 				free(thisdev->drvname);
   1157 				free(thisdev->classname);
   1158 				if (thisdev->ident != NULL)
   1159 					free(thisdev->ident);
   1160 				/* We don't free address[] for old plugins */
   1161 				thisdev->ident = NULL;
   1162 				thisdev->plugin = NULL;
   1163 			}
   1164 			/* CONSTCOND */
   1165 			TAILQ_REMOVE(fw_devices, thisdev, nextdev);
   1166 		}
   1167 	}
   1168 
   1169 	if (fw_pluginlist != NULL) {
   1170 		TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) {
   1171 			free(thisplug->filename);
   1172 			free(thisplug->drvname);
   1173 			free(thisplug->plugin->filename);
   1174 			free(thisplug->plugin->drvname);
   1175 			thisplug->filename = NULL;
   1176 			thisplug->drvname = NULL;
   1177 			thisplug->plugin->filename = NULL;
   1178 			thisplug->plugin->drvname = NULL;
   1179 			thisplug->plugin->fw_readfw = NULL;
   1180 			thisplug->plugin->fw_writefw = NULL;
   1181 			thisplug->plugin->fw_identify = NULL;
   1182 			thisplug->plugin->fw_devinfo = NULL;
   1183 			thisplug->plugin->fw_cleanup = NULL;
   1184 			(void) dlclose(thisplug->plugin->handle);
   1185 			thisplug->plugin->handle = NULL;
   1186 			free(thisplug->plugin);
   1187 			thisplug->plugin = NULL;
   1188 			/* CONSTCOND */
   1189 			TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin);
   1190 		}
   1191 	}
   1192 
   1193 	if (verifier != NULL) {
   1194 		free(verifier->filename);
   1195 		free(verifier->vendor);
   1196 		free(verifier->imgfile);
   1197 		free(verifier->fwimage);
   1198 		verifier->filename = NULL;
   1199 		verifier->vendor = NULL;
   1200 		verifier->vendorvrfy = NULL;
   1201 		verifier->imgfile = NULL;
   1202 		verifier->fwimage = NULL;
   1203 		(void) dlclose(verifier->handle);
   1204 		verifier->handle = NULL;
   1205 		free(verifier);
   1206 	}
   1207 	di_fini(rootnode);
   1208 
   1209 	if (sig > 0)
   1210 		exit(FWFLASH_FAILURE);
   1211 }
   1212 
   1213 static void
   1214 fwflash_handle_signals(void)
   1215 {
   1216 	if (signal(SIGINT, fwflash_intr) == SIG_ERR) {
   1217 		perror("signal");
   1218 		exit(FWFLASH_FAILURE);
   1219 	}
   1220 
   1221 	if (signal(SIGTERM, fwflash_intr) == SIG_ERR) {
   1222 		perror("signal");
   1223 		exit(FWFLASH_FAILURE);
   1224 	}
   1225 }
   1226 
   1227 static int
   1228 confirm_target(struct devicelist *thisdev, char *file)
   1229 {
   1230 	int resp;
   1231 
   1232 	(void) fflush(stdin);
   1233 	(void) printf(gettext("About to update firmware on %s\n"),
   1234 	    thisdev->access_devname);
   1235 	(void) printf(gettext("with file %s.\n"
   1236 	    "Do you want to continue? (Y/N): "), file);
   1237 
   1238 	resp = getchar();
   1239 	if (resp == 'Y' || resp == 'y') {
   1240 		return (FWFLASH_YES_FLAG);
   1241 	} else {
   1242 		logmsg(MSG_INFO, "flash operation NOT confirmed.\n");
   1243 	}
   1244 
   1245 	(void) fflush(stdin);
   1246 	return (FWFLASH_FAILURE);
   1247 }
   1248 
   1249 int
   1250 get_fileopts(char *options)
   1251 {
   1252 
   1253 	int i;
   1254 	char *files;
   1255 
   1256 	if (files = strtok(options, ",")) {
   1257 		/* we have more than one */
   1258 		if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
   1259 			logmsg(MSG_ERROR,
   1260 			    gettext("Unable to allocate space for "
   1261 			    "a firmware image filename\n"));
   1262 			return (FWFLASH_FAILURE);
   1263 		}
   1264 		(void) strlcpy(filelist[0], files, strlen(files) + 1);
   1265 		i = 1;
   1266 
   1267 		logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
   1268 		    filelist[0]);
   1269 
   1270 
   1271 		while (files = strtok(NULL, ",")) {
   1272 			if ((filelist[i] = calloc(1, MAXPATHLEN + 1))
   1273 			    == NULL) {
   1274 				logmsg(MSG_ERROR,
   1275 				    gettext("Unable to allocate space for "
   1276 				    "a firmware image filename\n"));
   1277 				return (FWFLASH_FAILURE);
   1278 			}
   1279 			(void) strlcpy(filelist[i], files,
   1280 			    strlen(files) + 1);
   1281 			logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n",
   1282 			    i, filelist[i]);
   1283 			++i;
   1284 		}
   1285 	} else {
   1286 		if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
   1287 			logmsg(MSG_ERROR,
   1288 			    gettext("Unable to allocate space for "
   1289 			    "a firmware image filename\n"));
   1290 			return (FWFLASH_FAILURE);
   1291 		}
   1292 		(void) strlcpy(filelist[0], options, strlen(files) + 1);
   1293 		logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
   1294 		    filelist[0]);
   1295 	}
   1296 	return (FWFLASH_SUCCESS);
   1297 }
   1298 
   1299 /*
   1300  * code reuse - cheerfully borrowed from stmsboot_util.c
   1301  */
   1302 void
   1303 logmsg(int severity, const char *msg, ...)
   1304 {
   1305 	va_list ap;
   1306 
   1307 	if ((severity > MSG_INFO) ||
   1308 	    ((severity == MSG_INFO) && (fwflash_debug > 0))) {
   1309 		(void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME);
   1310 		va_start(ap, msg);
   1311 		(void) vfprintf(stderr, msg, ap);
   1312 		va_end(ap);
   1313 	}
   1314 }
   1315