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