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