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