1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2020 Oxide Computer Company
14 */
15
16 #include <sys/types.h>
17 #include <sys/stat.h>
18 #include <fcntl.h>
19 #include <errno.h>
20 #include <sys/mdb_modapi.h>
21 #include <sys/smbios_impl.h>
22 #include <unistd.h>
23
24 /*
25 * Unfortunately, we're in a bit of a bind. Because of the situation we're in,
26 * we cannot use string.h directly as it declares ffs() which is also declared
27 * in sys/systm.h. sys/systm.h is being pulled in because mdb is building with
28 * _KERNEL. Therefore we have to manually declare an extern delaration for
29 * strerror().
30 */
31 extern char *strerror(int);
32
33 /*
34 * Take an existing smbios_hdl_t from a dump and slurp out its memory so we can
35 * open up a new smbios handle to perform operations on.
36 */
37 static int
smbios_mdb_write(const char * path,uintptr_t addr)38 smbios_mdb_write(const char *path, uintptr_t addr)
39 {
40 smbios_hdl_t shp, *hdl;
41 void *buf;
42 int err, fd = -1;
43 int ret = DCMD_ERR;
44
45 if (mdb_vread(&shp, sizeof (shp), addr) != sizeof (shp)) {
46 mdb_warn("failed to read smbios_hdl_t at %p", addr);
47 return (DCMD_ERR);
48 }
49
50 buf = mdb_alloc(shp.sh_buflen, UM_NOSLEEP | UM_GC);
51 if (buf == NULL) {
52 mdb_warn("failed to allocate %zu bytes for the smbios "
53 "data buffer", shp.sh_buflen);
54 return (DCMD_ERR);
55 }
56
57 if (mdb_vread(buf, shp.sh_buflen, (uintptr_t)shp.sh_buf) !=
58 shp.sh_buflen) {
59 mdb_warn("failed to copy smbios data at %p", shp.sh_buf);
60 return (DCMD_ERR);
61 }
62
63 hdl = smbios_bufopen(&shp.sh_ent, buf, shp.sh_buflen, SMB_VERSION, 0,
64 &err);
65 if (hdl == NULL) {
66 mdb_warn("failed to load smbios data: %s\n",
67 smbios_errmsg(err));
68 return (DCMD_ERR);
69 }
70
71 if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
72 mdb_warn("failed to open output file %s: %s\n", path,
73 strerror(errno));
74 goto out;
75 }
76
77 if (smbios_write(hdl, fd) != 0) {
78 mdb_warn("failed to write smbios data to %s: %s\n", path,
79 smbios_errmsg(smbios_errno(hdl)));
80 ret = DCMD_ERR;
81 } else {
82 ret = DCMD_OK;
83 }
84 out:
85 if (fd != -1) {
86 (void) close(fd);
87 }
88 smbios_close(hdl);
89 return (ret);
90 }
91
92 static int
smbios_mdb_smbios(uintptr_t addr,uint_t flags,int argc,const mdb_arg_t * argv)93 smbios_mdb_smbios(uintptr_t addr, uint_t flags, int argc,
94 const mdb_arg_t *argv)
95 {
96 const char *wpath = NULL;
97
98 if (!(flags & DCMD_ADDRSPEC)) {
99 mdb_warn("missing required smbios_hdl_t\n");
100 return (DCMD_USAGE);
101 }
102
103 if (mdb_getopts(argc, argv, 'w', MDB_OPT_STR, &wpath, NULL) != argc) {
104 return (DCMD_USAGE);
105 }
106
107 if (wpath != NULL) {
108 return (smbios_mdb_write(wpath, addr));
109 }
110
111 return (DCMD_USAGE);
112 }
113
114 static void
smbios_mdb_help(void)115 smbios_mdb_help(void)
116 {
117 mdb_printf("Given a pointer to an smbios_hdl_t take the following "
118 "actions:\n\n"
119 "\t-w path\t\tWrite SMBIOS data out to path\n");
120 }
121
122 static const mdb_dcmd_t smbios_dcmds[] = {
123 { "smbios", ":[-w path]", "Manipulate an smbios handle",
124 smbios_mdb_smbios, smbios_mdb_help },
125 { NULL }
126 };
127
128 static const mdb_modinfo_t smbios_modinfo = {
129 MDB_API_VERSION, smbios_dcmds, NULL
130 };
131
132 const mdb_modinfo_t *
_mdb_init(void)133 _mdb_init(void)
134 {
135 return (&smbios_modinfo);
136 }
137