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