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