8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / fwflash / common / fwflash.c
blob59c3588f2435381b60cfda5224ff50e9816bd183
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
26 * fwflash.c
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <strings.h>
32 #include <errno.h>
33 #include <sys/queue.h>
34 #include <signal.h>
35 #include <locale.h>
36 #include <sys/stat.h>
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <fcntl.h>
40 #include <dlfcn.h>
41 #include <dirent.h>
42 #include <sys/varargs.h>
43 #include <libintl.h> /* for gettext(3c) */
44 #include <libdevinfo.h>
45 #include <libscf_priv.h>
46 #include <fwflash/fwflash.h>
47 #include <sys/modctl.h> /* for MAXMODCONFNAME */
49 /* global arg list */
50 int fwflash_arg_list = 0;
51 char *filelist[10];
53 /* exposed global args */
54 di_node_t rootnode;
55 struct PLUGINLIST *fw_pluginlist;
56 struct DEVICELIST *fw_devices;
57 struct vrfyplugin *verifier;
58 struct fw_plugin *self;
59 int fwflash_debug = 0;
61 /* are we writing to flash? */
62 static int fwflash_in_write = 0;
65 * If we *must* track the version string for fwflash, then
66 * we should do so in this common file rather than the header
67 * file since it will then be in sync with what the customer
68 * sees. We should deprecate the "-v" option since it is not
69 * actually of any use - it doesn't line up with Mercurial's
70 * concept of the changeset.
72 #define FWFLASH_VERSION "v1.9"
73 #define FWFLASH_PROG_NAME "fwflash"
75 static int get_fileopts(char *options);
76 static int flash_device_list();
77 static int flash_load_plugins();
78 static int fwflash_update(char *device, char *filename, int flags);
79 static int fwflash_read_file(char *device, char *filename);
80 static int fwflash_list_fw(char *class);
81 static int fwflash_load_verifier(char *drv, char *vendorid, char *fwimg);
82 static void fwflash_intr(int sig);
83 static void fwflash_handle_signals(void);
84 static void fwflash_usage(char *arg);
85 static void fwflash_version(void);
86 static int confirm_target(struct devicelist *thisdev, char *file);
89 * FWFlash main code
91 int
92 main(int argc, char **argv)
94 int rv = FWFLASH_SUCCESS;
95 int i;
96 char ch;
97 char *read_file;
98 extern char *optarg;
99 char *devclass = NULL;
100 char *devpath = NULL;
102 /* local variables from env */
103 (void) setlocale(LC_ALL, "");
105 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
106 #define TEXT_DOMAIN "SYS_TEST" /* Use this only if it isn't. */
107 #endif
109 (void) textdomain(TEXT_DOMAIN);
111 read_file = NULL;
113 if (argc < 2) {
114 /* no args supplied */
115 fwflash_usage(NULL);
116 return (FWFLASH_FAILURE);
119 while ((ch = getopt(argc, argv, "hvylc:f:r:Qd:")) != EOF) {
120 switch (ch) {
121 case 'h':
122 fwflash_arg_list |= FWFLASH_HELP_FLAG;
123 break;
124 case 'v':
125 fwflash_arg_list |= FWFLASH_VER_FLAG;
126 break;
127 case 'y':
128 fwflash_arg_list |= FWFLASH_YES_FLAG;
129 break;
130 case 'l':
131 fwflash_arg_list |= FWFLASH_LIST_FLAG;
132 break;
133 case 'c':
134 fwflash_arg_list |= FWFLASH_CLASS_FLAG;
135 /* we validate later */
136 devclass = strdup(optarg);
137 break;
138 case 'd':
139 fwflash_arg_list |= FWFLASH_DEVICE_FLAG;
140 devpath = strdup(optarg);
141 break;
142 case 'f':
143 fwflash_arg_list |= FWFLASH_FW_FLAG;
144 if ((rv = get_fileopts(optarg)) != FWFLASH_SUCCESS) {
145 fwflash_usage(NULL);
146 return (FWFLASH_FAILURE);
148 break;
149 case 'r':
150 fwflash_arg_list |= FWFLASH_READ_FLAG;
151 read_file = strdup(optarg);
152 break;
153 case 'Q':
154 /* NOT in the manpage */
155 fwflash_debug = 1;
156 break;
157 /* illegal options */
158 default:
159 fwflash_usage(optarg);
160 return (FWFLASH_FAILURE);
164 /* Do Help */
165 if ((fwflash_arg_list & FWFLASH_HELP_FLAG) ||
166 ((fwflash_arg_list & FWFLASH_DEVICE_FLAG) &&
167 !((fwflash_arg_list & FWFLASH_FW_FLAG) ||
168 (fwflash_arg_list & FWFLASH_READ_FLAG)))) {
169 fwflash_usage(NULL);
170 return (FWFLASH_SUCCESS);
173 /* Do Version */
174 if (fwflash_arg_list == FWFLASH_VER_FLAG) {
175 fwflash_version();
176 return (FWFLASH_SUCCESS);
179 /* generate global list of devices */
180 if ((rv = flash_load_plugins()) != FWFLASH_SUCCESS) {
181 logmsg(MSG_ERROR,
182 gettext("Unable to load fwflash plugins\n"));
183 fwflash_intr(0);
184 return (rv);
187 if ((rv = flash_device_list()) != FWFLASH_SUCCESS) {
188 logmsg(MSG_ERROR,
189 gettext("No flashable devices in this system\n"));
190 fwflash_intr(0);
191 return (rv);
194 /* Do list */
195 if (fwflash_arg_list == (FWFLASH_LIST_FLAG) ||
196 fwflash_arg_list == (FWFLASH_LIST_FLAG | FWFLASH_CLASS_FLAG)) {
197 rv = fwflash_list_fw(devclass);
198 fwflash_intr(0);
199 return (rv);
202 fwflash_handle_signals();
204 /* Do flash update (write) */
205 if ((fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG)) ||
206 (fwflash_arg_list == (FWFLASH_FW_FLAG | FWFLASH_DEVICE_FLAG |
207 FWFLASH_YES_FLAG))) {
208 int fastreboot_disabled = 0;
209 /* the update function handles the real arg parsing */
210 i = 0;
211 while (filelist[i] != NULL) {
212 if ((rv = fwflash_update(devpath, filelist[i],
213 fwflash_arg_list)) == FWFLASH_SUCCESS) {
214 /* failed ops have already been noted */
215 if (!fastreboot_disabled &&
216 scf_fastreboot_default_set_transient(
217 B_FALSE) != SCF_SUCCESS)
218 logmsg(MSG_ERROR, gettext(
219 "Failed to disable fast "
220 "reboot.\n"));
221 else
222 fastreboot_disabled = 1;
223 logmsg(MSG_ERROR,
224 gettext("New firmware will be activated "
225 "after you reboot\n\n"));
227 ++i;
230 fwflash_intr(0);
231 return (rv);
234 /* Do flash read */
235 if ((fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG)) ||
236 (fwflash_arg_list == (FWFLASH_READ_FLAG | FWFLASH_DEVICE_FLAG |
237 FWFLASH_YES_FLAG))) {
238 rv = fwflash_read_file(devpath, read_file);
239 fwflash_intr(0);
240 return (rv);
243 fwflash_usage(NULL);
245 return (FWFLASH_FAILURE);
249 static int
250 flash_load_plugins()
253 int rval = FWFLASH_SUCCESS;
254 DIR *dirp;
255 struct dirent *plugdir;
256 char *plugname;
257 struct fw_plugin *tmpplug;
258 struct pluginlist *tmpelem;
259 void *sym;
260 char *fwplugdirpath, *tempdirpath;
263 #define CLOSEFREE() { \
264 (void) dlclose(tmpplug->handle); \
265 free(tmpplug); }
268 * Procedure:
270 * cd /usr/lib/fwflash/identify
271 * open each .so file found therein
272 * dlopen(.sofile)
273 * if it's one of our plugins, add it to fw_pluginlist;
275 * functions we need here include dlopen and dlsym.
277 * If we get to the end and fw_pluginlist struct is empty,
278 * return FWFLASH_FAILURE so we return to the shell.
281 if ((fwplugdirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
282 logmsg(MSG_ERROR,
283 gettext("Unable to malloc %d bytes while "
284 "trying to load plugins: %s\n"),
285 MAXPATHLEN + 1, strerror(errno));
286 return (FWFLASH_FAILURE);
289 tempdirpath = getenv("FWPLUGINDIR");
291 if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
292 (void) strlcpy(fwplugdirpath, tempdirpath,
293 strlen(tempdirpath) + 1);
294 } else {
295 (void) strlcpy(fwplugdirpath, FWPLUGINDIR,
296 strlen(FWPLUGINDIR) + 1);
299 if ((dirp = opendir(fwplugdirpath)) == NULL) {
300 logmsg(MSG_ERROR,
301 gettext("Unable to open %s\n"),
302 fwplugdirpath);
303 return (errno);
306 if ((plugdir = calloc(1, sizeof (struct dirent) + MAXPATHLEN + 1))
307 == NULL) {
308 logmsg(MSG_ERROR,
309 gettext("Unable to malloc %d bytes while "
310 "trying to load plugins: %s\n"),
311 MAXPATHLEN + 1 + sizeof (struct dirent),
312 strerror(errno));
313 return (FWFLASH_FAILURE);
316 if ((fw_pluginlist = calloc(1, sizeof (struct fw_plugin)))
317 == NULL) {
318 logmsg(MSG_ERROR,
319 gettext("Unable to malloc %d bytes while "
320 "trying to load plugins: %s\n"),
321 sizeof (struct fw_plugin), strerror(errno));
322 return (FWFLASH_FAILURE);
325 TAILQ_INIT(fw_pluginlist);
327 while ((readdir_r(dirp, plugdir, &plugdir) == 0) && (plugdir != NULL)) {
329 errno = 0; /* remove chance of false results */
331 if ((plugdir->d_name[0] == '.') ||
332 (strstr(plugdir->d_name, ".so") == NULL)) {
333 continue;
336 if ((plugname = calloc(1, MAXPATHLEN + 1)) == NULL) {
337 logmsg(MSG_ERROR,
338 gettext("Unable to malloc %d bytes while "
339 "trying to load plugins: %s\n"),
340 MAXPATHLEN + 1, strerror(errno));
341 return (FWFLASH_FAILURE);
344 (void) snprintf(plugname, MAXPATHLEN, "%s/%s",
345 fwplugdirpath, plugdir->d_name);
347 /* start allocating storage */
348 if ((tmpelem = calloc(1, sizeof (struct pluginlist)))
349 == NULL) {
350 logmsg(MSG_ERROR,
351 gettext("Unable to malloc %d bytes while "
352 "trying to load plugins: %s\n"),
353 sizeof (struct pluginlist), strerror(errno));
354 return (FWFLASH_FAILURE);
357 if ((tmpplug = calloc(1, sizeof (struct fw_plugin)))
358 == NULL) {
359 logmsg(MSG_ERROR,
360 gettext("Unable to malloc %d bytes while "
361 "trying to load plugins: %s\n"),
362 sizeof (struct fw_plugin), strerror(errno));
363 return (FWFLASH_FAILURE);
366 /* load 'er up! */
367 tmpplug->handle = dlopen(plugname, RTLD_NOW);
368 if (tmpplug->handle == NULL) {
369 free(tmpplug);
370 continue; /* assume there are other plugins */
373 if ((tmpplug->filename = calloc(1, strlen(plugname) + 1))
374 == NULL) {
375 logmsg(MSG_ERROR,
376 gettext("Unable to allocate %d bytes for plugin "
377 "filename %s:%s\n"),
378 strlen(plugname) + 1, plugname,
379 strerror(errno));
380 return (rval);
383 (void) strlcpy(tmpplug->filename, plugname,
384 strlen(plugname) + 1);
386 /* now sanity check the file */
387 if ((sym = dlsym(tmpplug->handle, "drivername"))
388 != NULL) {
389 /* max length of drivername */
390 tmpplug->drvname = calloc(1, MAXMODCONFNAME);
392 /* are we doing double-time? */
393 if (strncmp((char *)sym, plugdir->d_name,
394 MAXMODCONFNAME) != 0) {
395 char *tempnm = calloc(1, MAXMODCONFNAME);
397 (void) memcpy(tempnm, plugdir->d_name,
398 MAXMODCONFNAME);
399 (void) strlcpy(tmpplug->drvname,
400 strtok(tempnm, "."),
401 strlen(plugdir->d_name) + 1);
402 free(tempnm);
403 } else {
404 (void) strlcpy(tmpplug->drvname,
405 (char *)sym, strlen(sym) + 1);
407 } else {
408 CLOSEFREE();
409 continue;
411 if ((sym = dlsym(tmpplug->handle, "fw_readfw"))
412 != NULL) {
413 tmpplug->fw_readfw = (int (*)())sym;
414 } else {
415 CLOSEFREE();
416 continue;
418 if ((sym = dlsym(tmpplug->handle, "fw_writefw"))
419 != NULL) {
420 tmpplug->fw_writefw = (int (*)())sym;
421 } else {
422 CLOSEFREE();
423 continue;
426 if ((sym = dlsym(tmpplug->handle, "fw_identify"))
427 != NULL) {
428 tmpplug->fw_identify =
429 (int (*)(int))sym;
430 } else {
431 CLOSEFREE();
432 continue;
434 if ((sym = dlsym(tmpplug->handle, "fw_devinfo"))
435 != NULL) {
436 tmpplug->fw_devinfo =
437 (int (*)(struct devicelist *))sym;
438 } else {
439 CLOSEFREE();
440 continue;
443 if ((sym = dlsym(tmpplug->handle, "plugin_version"))
444 != NULL) {
445 if ((*(int *)sym) >= FWPLUGIN_VERSION_2) {
446 if ((sym = dlsym(tmpplug->handle,
447 "fw_cleanup")) != NULL) {
448 tmpplug->fw_cleanup =
449 (void (*)(struct devicelist *))sym;
450 } else {
451 logmsg(MSG_ERROR,
452 gettext("ERROR: v2 plugin (%s) "
453 "has no fw_cleanup function\n"),
454 tmpplug->filename);
455 CLOSEFREE();
456 continue;
458 } else {
459 logmsg(MSG_INFO,
460 "Identification plugin %s defined "
461 "plugin_version < FWPLUGIN_VERSION_2 !");
465 if ((tmpelem->drvname = calloc(1, MAXMODCONFNAME))
466 == NULL) {
467 logmsg(MSG_ERROR,
468 gettext("Unable to allocate space for a"
469 "drivername %s\n"),
470 tmpplug->drvname);
471 return (FWFLASH_FAILURE);
474 (void) strlcpy(tmpelem->drvname, tmpplug->drvname,
475 strlen(tmpplug->drvname) + 1);
477 if ((tmpelem->filename = calloc(1,
478 strlen(tmpplug->filename) + 1)) == NULL) {
479 logmsg(MSG_ERROR,
480 gettext("Unable to allocate %d bytes for "
481 "filename %s\n"),
482 strlen(tmpplug->filename) + 1,
483 tmpplug->filename);
484 return (FWFLASH_FAILURE);
487 (void) strlcpy(tmpelem->filename, plugname,
488 strlen(plugname) + 1);
489 tmpelem->plugin = tmpplug;
491 /* CONSTCOND */
492 TAILQ_INSERT_TAIL(fw_pluginlist, tmpelem, nextplugin);
495 if ((plugdir == NULL) && TAILQ_EMPTY(fw_pluginlist)) {
496 return (FWFLASH_FAILURE);
499 if (errno != 0) {
500 logmsg(MSG_ERROR,
501 gettext("Error reading directory entry in %s\n"),
502 fwplugdirpath);
503 rval = errno;
506 free(fwplugdirpath);
507 free(plugdir);
508 (void) closedir(dirp);
509 return (rval);
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.
519 fwflash_load_verifier(char *drv, char *vendorid, char *fwimg)
522 int rv = FWFLASH_FAILURE;
523 int imgfd;
524 char *fwvrfydirpath, *tempdirpath, *filename;
525 char *clean; /* for the space-removed vid */
526 struct stat fwstat;
527 struct vrfyplugin *vrfy;
528 void *vrfysym;
531 * To make flashing multiple firmware images somewhat more
532 * efficient, we start this function by checking whether a
533 * verifier for this device has already been loaded. If it
534 * has been loaded, we replace the imgfile information, and
535 * then continue as if we were loading for the first time.
538 if (verifier != NULL) {
539 verifier->imgsize = 0;
540 verifier->flashbuf = 0; /* set by the verifier function */
542 if (verifier->imgfile != NULL) {
543 free(verifier->imgfile);
544 verifier->imgfile = NULL;
547 if (verifier->fwimage != NULL) {
548 free(verifier->fwimage);
549 verifier->fwimage = NULL;
551 } else {
552 if ((fwvrfydirpath = calloc(1, MAXPATHLEN + 1)) == NULL) {
553 logmsg(MSG_ERROR,
554 gettext("Unable to allocate space for a firmware "
555 "verifier file(1)"));
556 return (rv);
559 if ((filename = calloc(1, MAXPATHLEN + 1)) == NULL) {
560 logmsg(MSG_ERROR,
561 gettext("Unable to allocate space "
562 "for a firmware verifier file(2)"));
563 free(fwvrfydirpath);
564 return (rv);
568 * Since SCSI devices can have a vendor id of up to 8
569 * left-aligned and _space-padded_ characters, we first need to
570 * strip off any space characters before we try to make a
571 * filename out of it
573 clean = strtok(vendorid, " ");
574 if (clean == NULL) {
575 /* invalid vendorid, something's really wrong */
576 logmsg(MSG_ERROR,
577 gettext("Invalid vendorid (null) specified for "
578 "device\n"));
579 free(filename);
580 free(fwvrfydirpath);
581 return (rv);
584 tempdirpath = getenv("FWVERIFYPLUGINDIR");
586 if ((fwflash_debug > 0) && (tempdirpath != NULL)) {
587 (void) strlcpy(fwvrfydirpath, tempdirpath,
588 strlen(tempdirpath) + 1);
589 } else {
590 (void) strlcpy(fwvrfydirpath, FWVERIFYPLUGINDIR,
591 strlen(FWVERIFYPLUGINDIR) + 1);
594 if ((vrfy = calloc(1, sizeof (struct vrfyplugin))) == NULL) {
595 logmsg(MSG_ERROR,
596 gettext("Unable to allocate space "
597 "for a firmware verifier structure"));
598 free(filename);
599 free(fwvrfydirpath);
600 return (rv);
603 errno = 0; /* false positive removal */
605 (void) snprintf(filename, MAXPATHLEN, "%s/%s-%s.so",
606 fwvrfydirpath, drv, clean);
607 if ((vrfy->handle = dlopen(filename, RTLD_NOW)) == NULL) {
608 logmsg(MSG_INFO, gettext(dlerror()));
609 logmsg(MSG_INFO,
610 gettext("\nUnable to open verification plugin "
611 "%s. Looking for %s-GENERIC plugin instead.\n"),
612 filename, drv);
614 /* Try the drv-GENERIC.so form, _then_ die */
615 bzero(filename, strlen(filename) + 1);
616 (void) snprintf(filename, MAXPATHLEN,
617 "%s/%s-GENERIC.so", fwvrfydirpath, drv);
619 if ((vrfy->handle = dlopen(filename, RTLD_NOW))
620 == NULL) {
621 logmsg(MSG_INFO, gettext(dlerror()));
622 logmsg(MSG_ERROR,
623 gettext("\nUnable to open either "
624 "verification plugin %s/%s-%s.so or "
625 "generic plugin %s.\nUnable to verify "
626 "firmware image. Aborting.\n"),
627 fwvrfydirpath, drv, clean, filename);
628 free(filename);
629 free(fwvrfydirpath);
630 return (rv);
634 if ((vrfy->filename = calloc(1, strlen(filename) + 1))
635 == NULL) {
636 logmsg(MSG_ERROR,
637 gettext("Unable to allocate space to store "
638 "a verifier filename\n"));
639 free(filename);
640 free(fwvrfydirpath);
641 free(vrfy->handle);
642 return (rv);
644 (void) strlcpy(vrfy->filename, filename, strlen(filename) + 1);
646 if ((vrfysym = dlsym(vrfy->handle, "vendorvrfy")) == NULL) {
647 logmsg(MSG_ERROR,
648 gettext("%s is an invalid firmware verification "
649 "plugin."), filename);
650 (void) dlclose(vrfy->handle);
651 free(filename);
652 free(fwvrfydirpath);
653 free(vrfy);
654 return (rv);
655 } else {
656 vrfy->vendorvrfy =
657 (int (*)(struct devicelist *))vrfysym;
660 vrfysym = dlsym(vrfy->handle, "vendor");
662 if (vrfysym == NULL) {
663 logmsg(MSG_ERROR,
664 gettext("Invalid vendor (null) in verification "
665 "plugin %s\n"), filename);
666 (void) dlclose(vrfy->handle);
667 free(vrfy);
668 return (rv);
669 } else {
670 if (strncmp(vendorid, (char *)vrfysym,
671 strlen(vendorid)) != 0) {
672 logmsg(MSG_INFO,
673 "Using a sym-linked (%s -> %s) "
674 "verification plugin\n",
675 vendorid, vrfysym);
676 vrfy->vendor = calloc(1, strlen(vendorid) + 1);
677 } else {
678 vrfy->vendor = calloc(1, strlen(vrfysym) + 1);
680 (void) strlcpy(vrfy->vendor, (char *)vrfysym,
681 strlen(vendorid) + 1);
684 verifier = vrfy; /* a convenience variable */
685 free(filename);
686 free(fwvrfydirpath);
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.
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;
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;
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 verifier->filename, strerror(errno));
736 rv = FWFLASH_FAILURE;
737 } else {
738 rv = FWFLASH_SUCCESS;
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);
749 if (rv != FWFLASH_SUCCESS) {
750 /* cleanup and let's get outta here */
751 cleanup:
752 free(verifier->filename);
753 free(verifier->vendor);
755 if (!(fwflash_arg_list & FWFLASH_READ_FLAG) &&
756 verifier->fwimage)
757 free(verifier->fwimage);
759 verifier->filename = NULL;
760 verifier->vendor = NULL;
761 verifier->vendorvrfy = NULL;
762 verifier->fwimage = NULL;
763 (void) dlclose(verifier->handle);
764 verifier->handle = NULL;
765 free(verifier);
766 if (imgfd >= 0) {
767 (void) close(imgfd);
769 verifier = NULL;
772 return (rv);
776 * cycles through the global list of plugins to find
777 * each flashable device, which is added to fw_devices
779 * Each plugin's identify routine must allocated storage
780 * as required.
782 * Each plugin's identify routine must return
783 * FWFLASH_FAILURE if it cannot find any devices
784 * which it handles.
786 static int
787 flash_device_list()
789 int rv = FWFLASH_FAILURE;
790 int startidx = 0;
791 int sumrv = 0;
792 struct pluginlist *plugins;
794 /* we open rootnode here, and close it in fwflash_intr */
795 if ((rootnode = di_init("/", DINFOCPYALL|DINFOFORCE)) == DI_NODE_NIL) {
796 logmsg(MSG_ERROR,
797 gettext("Unable to take device tree snapshot: %s\n"),
798 strerror(errno));
799 return (rv);
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);
810 /* CONSTCOND */
811 TAILQ_INIT(fw_devices);
813 TAILQ_FOREACH(plugins, fw_pluginlist, nextplugin) {
814 self = plugins->plugin;
815 rv = plugins->plugin->fw_identify(startidx);
817 logmsg(MSG_INFO,
818 gettext("fwflash:flash_device_list() got %d from "
819 "identify routine\n"), rv);
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);
833 if (sumrv > 0)
834 rv = FWFLASH_SUCCESS;
836 return (rv);
839 static int
840 fwflash_list_fw(char *class)
842 int rv = 0;
843 struct devicelist *curdev;
844 int header = 1;
846 TAILQ_FOREACH(curdev, fw_devices, nextdev) {
848 /* we're either class-conscious, or we're not */
849 if (((class != NULL) &&
850 ((strncmp(curdev->classname, "ALL", 3) == 0) ||
851 (strcmp(curdev->classname, class) == 0))) ||
852 (class == NULL)) {
854 if (header != 0) {
855 (void) fprintf(stdout,
856 gettext("List of available devices:\n"));
857 header--;
860 * If any plugin's fw_devinfo() function returns
861 * FWFLASH_FAILURE then we want to keep track of
862 * it. _Most_ plugins should always return
863 * FWFLASH_SUCCESS from this function. The only
864 * exception known at this point is the tavor plugin.
866 rv += curdev->plugin->fw_devinfo(curdev);
869 return (rv);
872 static int
873 fwflash_update(char *device, char *filename, int flags)
876 int rv = FWFLASH_FAILURE;
877 int needsfree = 0;
878 int found = 0;
879 struct devicelist *curdev;
880 char *realfile;
883 * Here's how we operate:
885 * We perform some basic checks on the args, then walk
886 * through the device list looking for the device which
887 * matches. We then load the appropriate verifier for the
888 * image file and device, verify the image, then call the
889 * fw_writefw() function of the appropriate plugin.
891 * There is no "force" flag to enable you to flash a firmware
892 * image onto an incompatible device because the verifier
893 * will return FWFLASH_FAILURE if the image doesn't match.
896 /* new firmware filename and device desc */
897 if (filename == NULL) {
898 logmsg(MSG_ERROR,
899 gettext("Invalid firmware filename (null)\n"));
900 return (FWFLASH_FAILURE);
903 if (device == NULL) {
904 logmsg(MSG_ERROR,
905 gettext("Invalid device requested (null)\n"));
906 return (FWFLASH_FAILURE);
909 if ((realfile = calloc(1, PATH_MAX + 1)) == NULL) {
910 logmsg(MSG_ERROR,
911 gettext("Unable to allocate space for device "
912 "filename, operation might fail if %s is"
913 "a symbolic link\n"),
914 device);
915 realfile = device;
916 } else {
918 * If realpath() succeeds, then we have a valid
919 * device filename in realfile.
921 if (realpath(device, realfile) == NULL) {
922 logmsg(MSG_ERROR,
923 gettext("Unable to resolve device filename"
924 ": %s\n"),
925 strerror(errno));
926 /* tidy up */
927 free(realfile);
928 /* realpath didn't succeed, use fallback */
929 realfile = device;
930 } else {
931 needsfree = 1;
935 logmsg(MSG_INFO,
936 gettext("fwflash_update: fw_filename (%s) device (%s)\n"),
937 filename, device);
939 TAILQ_FOREACH(curdev, fw_devices, nextdev) {
940 if (strcmp(curdev->access_devname, realfile) == 0) {
941 found++;
942 rv = fwflash_load_verifier(curdev->drvname,
943 curdev->ident->vid, filename);
944 if (rv == FWFLASH_FAILURE) {
945 logmsg(MSG_ERROR,
946 gettext("Unable to load verifier "
947 "for device %s\n"),
948 curdev->access_devname);
949 return (FWFLASH_FAILURE);
951 rv = verifier->vendorvrfy(curdev);
952 if (rv == FWFLASH_FAILURE) {
953 /* the verifier prints a message */
954 logmsg(MSG_INFO,
955 "verifier (%s) for %s :: %s returned "
956 "FWFLASH_FAILURE\n",
957 verifier->filename,
958 filename, curdev->access_devname);
959 return (rv);
962 if (((flags & FWFLASH_YES_FLAG) == FWFLASH_YES_FLAG) ||
963 (rv = confirm_target(curdev, filename)) ==
964 FWFLASH_YES_FLAG) {
965 logmsg(MSG_INFO,
966 "about to flash using plugin %s\n",
967 curdev->plugin->filename);
968 rv = curdev->plugin->fw_writefw(curdev,
969 filename);
970 if (rv == FWFLASH_FAILURE) {
971 logmsg(MSG_ERROR,
972 gettext("Failed to flash "
973 "firmware file %s on "
974 "device %s: %d\n"),
975 filename,
976 curdev->access_devname, rv);
978 } else {
979 logmsg(MSG_ERROR,
980 gettext("Flash operation not confirmed "
981 "by user\n"),
982 curdev->access_devname);
983 rv = FWFLASH_FAILURE;
988 if (!found)
989 /* report the same device that the user passed in */
990 logmsg(MSG_ERROR,
991 gettext("Device %s does not appear "
992 "to be flashable\n"),
993 ((strncmp(device, realfile, strlen(device)) == 0) ?
994 realfile : device));
996 if (needsfree)
997 free(realfile);
999 return (rv);
1003 * We validate that the device path is in our global device list and
1004 * that the filename exists, then palm things off to the relevant plugin.
1006 static int
1007 fwflash_read_file(char *device, char *filename)
1009 struct devicelist *curdev;
1010 int rv;
1011 int found = 0;
1013 /* new firmware filename and device desc */
1015 TAILQ_FOREACH(curdev, fw_devices, nextdev) {
1016 if (strncmp(curdev->access_devname, device,
1017 MAXPATHLEN) == 0) {
1018 rv = curdev->plugin->fw_readfw(curdev, filename);
1020 if (rv != FWFLASH_SUCCESS)
1021 logmsg(MSG_ERROR,
1022 gettext("Unable to write out firmware "
1023 "image for %s to file %s\n"),
1024 curdev->access_devname, filename);
1025 found++;
1030 if (!found) {
1031 logmsg(MSG_ERROR,
1032 gettext("No device matching %s was found.\n"),
1033 device);
1034 rv = FWFLASH_FAILURE;
1037 return (rv);
1040 static void
1041 fwflash_usage(char *arg)
1044 (void) fprintf(stderr, "\n");
1045 if (arg != NULL) {
1046 logmsg(MSG_ERROR,
1047 gettext("Invalid argument (%s) supplied\n"), arg);
1050 (void) fprintf(stderr, "\n");
1052 (void) fprintf(stdout, gettext("Usage:\n\t"));
1053 (void) fprintf(stdout, gettext("fwflash [-l [-c device_class "
1054 "| ALL]] | [-v] | [-h]\n\t"));
1055 (void) fprintf(stdout, gettext("fwflash [-f file1,file2,file3"
1056 ",... | -r file] [-y] -d device_path\n\n"));
1057 (void) fprintf(stdout, "\n"); /* workaround for xgettext */
1059 (void) fprintf(stdout,
1060 gettext("\t-l\t\tlist flashable devices in this system\n"
1061 "\t-c device_class limit search to a specific class\n"
1062 "\t\t\teg IB for InfiniBand, ses for SCSI Enclosures\n"
1063 "\t-v\t\tprint version number of fwflash utility\n"
1064 "\t-h\t\tprint this usage message\n\n"));
1065 (void) fprintf(stdout,
1066 gettext("\t-f file1,file2,file3,...\n"
1067 "\t\t\tfirmware image file list to flash\n"
1068 "\t-r file\t\tfile to dump device firmware to\n"
1069 "\t-y\t\tanswer Yes/Y/y to prompts\n"
1070 "\t-d device_path\tpathname of device to be flashed\n\n"));
1072 (void) fprintf(stdout,
1073 gettext("\tIf -d device_path is specified, then one of -f "
1074 "<files>\n"
1075 "\tor -r <file> must also be specified\n\n"));
1077 (void) fprintf(stdout,
1078 gettext("\tIf multiple firmware images are required to be "
1079 "flashed\n"
1080 "\tthey must be listed together, separated by commas. The\n"
1081 "\timages will be flashed in the order specified.\n\n"));
1083 (void) fprintf(stdout, "\n");
1086 static void
1087 fwflash_version(void)
1089 (void) fprintf(stdout, gettext("\n%s: "), FWFLASH_PROG_NAME);
1090 (void) fprintf(stdout, gettext("version %s\n"),
1091 FWFLASH_VERSION);
1094 static void
1095 fwflash_intr(int sig)
1098 struct devicelist *thisdev;
1099 struct pluginlist *thisplug;
1101 (void) signal(SIGINT, SIG_IGN);
1102 (void) signal(SIGTERM, SIG_IGN);
1103 (void) signal(SIGABRT, SIG_IGN);
1105 if (fwflash_in_write) {
1106 (void) fprintf(stderr,
1107 gettext("WARNING: firmware image may be corrupted\n\t"));
1108 (void) fprintf(stderr,
1109 gettext("Reflash firmware before rebooting!\n"));
1112 if (sig > 0) {
1113 (void) logmsg(MSG_ERROR, gettext("\n"));
1114 (void) logmsg(MSG_ERROR,
1115 gettext("fwflash exiting due to signal (%d)\n"), sig);
1119 * we need to close everything down properly, so
1120 * call the plugin closure routines
1122 if (fw_devices != NULL) {
1123 TAILQ_FOREACH(thisdev, fw_devices, nextdev) {
1124 if (thisdev->plugin->fw_cleanup != NULL) {
1126 * If we've got a cleanup routine, it
1127 * cleans up _everything_ for thisdev
1129 thisdev->plugin->fw_cleanup(thisdev);
1130 } else {
1131 /* free the components first */
1132 free(thisdev->access_devname);
1133 free(thisdev->drvname);
1134 free(thisdev->classname);
1135 if (thisdev->ident != NULL)
1136 free(thisdev->ident);
1137 /* We don't free address[] for old plugins */
1138 thisdev->ident = NULL;
1139 thisdev->plugin = NULL;
1141 /* CONSTCOND */
1142 TAILQ_REMOVE(fw_devices, thisdev, nextdev);
1146 if (fw_pluginlist != NULL) {
1147 TAILQ_FOREACH(thisplug, fw_pluginlist, nextplugin) {
1148 free(thisplug->filename);
1149 free(thisplug->drvname);
1150 free(thisplug->plugin->filename);
1151 free(thisplug->plugin->drvname);
1152 thisplug->filename = NULL;
1153 thisplug->drvname = NULL;
1154 thisplug->plugin->filename = NULL;
1155 thisplug->plugin->drvname = NULL;
1156 thisplug->plugin->fw_readfw = NULL;
1157 thisplug->plugin->fw_writefw = NULL;
1158 thisplug->plugin->fw_identify = NULL;
1159 thisplug->plugin->fw_devinfo = NULL;
1160 thisplug->plugin->fw_cleanup = NULL;
1161 (void) dlclose(thisplug->plugin->handle);
1162 thisplug->plugin->handle = NULL;
1163 free(thisplug->plugin);
1164 thisplug->plugin = NULL;
1165 /* CONSTCOND */
1166 TAILQ_REMOVE(fw_pluginlist, thisplug, nextplugin);
1170 if (verifier != NULL) {
1171 free(verifier->filename);
1172 free(verifier->vendor);
1173 free(verifier->imgfile);
1174 free(verifier->fwimage);
1175 verifier->filename = NULL;
1176 verifier->vendor = NULL;
1177 verifier->vendorvrfy = NULL;
1178 verifier->imgfile = NULL;
1179 verifier->fwimage = NULL;
1180 (void) dlclose(verifier->handle);
1181 verifier->handle = NULL;
1182 free(verifier);
1184 di_fini(rootnode);
1186 if (sig > 0)
1187 exit(FWFLASH_FAILURE);
1190 static void
1191 fwflash_handle_signals(void)
1193 if (signal(SIGINT, fwflash_intr) == SIG_ERR) {
1194 perror("signal");
1195 exit(FWFLASH_FAILURE);
1198 if (signal(SIGTERM, fwflash_intr) == SIG_ERR) {
1199 perror("signal");
1200 exit(FWFLASH_FAILURE);
1204 static int
1205 confirm_target(struct devicelist *thisdev, char *file)
1207 int resp;
1209 (void) fflush(stdin);
1210 (void) printf(gettext("About to update firmware on %s\n"),
1211 thisdev->access_devname);
1212 (void) printf(gettext("with file %s.\n"
1213 "Do you want to continue? (Y/N): "), file);
1215 resp = getchar();
1216 if (resp == 'Y' || resp == 'y') {
1217 return (FWFLASH_YES_FLAG);
1218 } else {
1219 logmsg(MSG_INFO, "flash operation NOT confirmed.\n");
1222 (void) fflush(stdin);
1223 return (FWFLASH_FAILURE);
1227 get_fileopts(char *options)
1230 int i;
1231 char *files;
1233 if (files = strtok(options, ",")) {
1234 /* we have more than one */
1235 if ((filelist[0] = calloc(1, MAXPATHLEN + 1)) == NULL) {
1236 logmsg(MSG_ERROR,
1237 gettext("Unable to allocate space for "
1238 "a firmware image filename\n"));
1239 return (FWFLASH_FAILURE);
1241 (void) strlcpy(filelist[0], files, strlen(files) + 1);
1242 i = 1;
1244 logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
1245 filelist[0]);
1248 while (files = strtok(NULL, ",")) {
1249 if ((filelist[i] = calloc(1, MAXPATHLEN + 1))
1250 == NULL) {
1251 logmsg(MSG_ERROR,
1252 gettext("Unable to allocate space for "
1253 "a firmware image filename\n"));
1254 return (FWFLASH_FAILURE);
1256 (void) strlcpy(filelist[i], files,
1257 strlen(files) + 1);
1258 logmsg(MSG_INFO, "fwflash: filelist[%d]: %s\n",
1259 i, filelist[i]);
1260 ++i;
1262 } else {
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);
1269 (void) strlcpy(filelist[0], options, strlen(files) + 1);
1270 logmsg(MSG_INFO, "fwflash: filelist[0]: %s\n",
1271 filelist[0]);
1273 return (FWFLASH_SUCCESS);
1277 * code reuse - cheerfully borrowed from stmsboot_util.c
1279 void
1280 logmsg(int severity, const char *msg, ...)
1282 va_list ap;
1284 if ((severity > MSG_INFO) ||
1285 ((severity == MSG_INFO) && (fwflash_debug > 0))) {
1286 (void) fprintf(stderr, "%s: ", FWFLASH_PROG_NAME);
1287 va_start(ap, msg);
1288 (void) vfprintf(stderr, msg, ap);
1289 va_end(ap);