Print this page
10102 libnvfru needs smatch fixes
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libfru/libnvfru/nvfru.c
+++ new/usr/src/lib/libfru/libnvfru/nvfru.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21
22 22 /*
23 23 * Copyright (c) 2014 Gary Mills
24 24 *
25 25 * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
26 + *
27 + * Copyright (c) 2018, Joyent, Inc.
26 28 */
27 29
28 30 #include <stdio.h>
29 31 #include <stdlib.h>
30 32 #include <stdint.h>
31 33 #include <strings.h>
32 34 #include <assert.h>
33 35 #include <pthread.h>
34 36 #include <sys/byteorder.h>
35 37 #include <sys/types.h>
36 38 #include <sys/nvpair.h>
37 39
38 40 #include "libfru.h"
39 41 #include "libfrup.h"
40 42 #include "fru_tag.h"
41 43 #include "libfrureg.h"
42 44 #include "nvfru.h"
43 45
44 46 #define NUM_ITER_BYTES 4
45 47 #define HEAD_ITER 0
46 48 #define TAIL_ITER 1
47 49 #define NUM_ITER 2
48 50 #define MAX_ITER 3
49 51 #define TIMESTRINGLEN 128
50 52
51 53 #define PARSE_TIME 1
52 54
53 55 static pthread_mutex_t gLock = PTHREAD_MUTEX_INITIALIZER;
54 56
55 57
56 58
57 59 static void
58 60 convert_field(const uint8_t *field, const fru_regdef_t *def, const char *path,
59 61 nvlist_t *nv)
60 62 {
61 63 char timestring[TIMESTRINGLEN];
62 64 int i;
63 65 uint64_t value;
64 66 time_t timefield;
65 67
66 68 switch (def->dataType) {
67 69 case FDTYPE_Binary:
68 70 assert(def->payloadLen <= sizeof (value));
69 71 switch (def->dispType) {
70 72 #if PARSE_TIME == 1
71 73 case FDISP_Time:
72 74 if (def->payloadLen > sizeof (timefield)) {
73 75 /* too big for formatting */
74 76 return;
75 77 }
76 78 (void) memcpy(&timefield, field, sizeof (timefield));
77 79 timefield = BE_32(timefield);
78 80 if (strftime(timestring, sizeof (timestring), "%c",
79 81 localtime(&timefield)) == 0) {
80 82 /* buffer too small */
81 83 return;
82 84 }
83 85 (void) nvlist_add_string(nv, path, timestring);
84 86 return;
85 87 #endif
86 88
87 89 case FDISP_Binary:
88 90 case FDISP_Octal:
89 91 case FDISP_Decimal:
90 92 case FDISP_Hex:
91 93 default:
92 94 value = 0;
93 95 (void) memcpy((((uint8_t *)&value) +
94 96 sizeof (value) - def->payloadLen),
95 97 field, def->payloadLen);
96 98 value = BE_64(value);
97 99 switch (def->payloadLen) {
98 100 case 1:
99 101 (void) nvlist_add_uint8(nv, path,
100 102 (uint8_t)value);
101 103 break;
102 104 case 2:
103 105 (void) nvlist_add_uint16(nv, path,
104 106 (uint16_t)value);
105 107 break;
106 108 case 4:
107 109 (void) nvlist_add_uint32(nv, path,
108 110 (uint32_t)value);
109 111 break;
110 112 default:
111 113 (void) nvlist_add_uint64(nv, path, value);
112 114 }
113 115 return;
114 116 }
115 117
116 118 case FDTYPE_ASCII:
117 119 (void) nvlist_add_string(nv, path, (char *)field);
118 120 return;
119 121
120 122 case FDTYPE_Enumeration:
121 123 value = 0;
122 124 (void) memcpy((((uint8_t *)&value) + sizeof (value) -
123 125 def->payloadLen), field, def->payloadLen);
124 126 value = BE_64(value);
125 127 for (i = 0; i < def->enumCount; i++) {
126 128 if (def->enumTable[i].value == value) {
127 129 (void) nvlist_add_string(nv, path,
128 130 def->enumTable[i].text);
129 131 return;
130 132 }
131 133 }
132 134 }
133 135
134 136 /* nothing matched above, use byte array */
135 137 (void) nvlist_add_byte_array(nv, path, (uchar_t *)field,
136 138 def->payloadLen);
137 139 }
138 140
139 141
140 142
141 143 static void
142 144 convert_element(const uint8_t *data, const fru_regdef_t *def, char *ppath,
143 145 nvlist_t *nv, boolean_t from_iter)
144 146 {
145 147 int i;
146 148 char *path;
147 149
148 150 /* construct path */
149 151 if ((def->iterationCount == 0) &&
150 152 (def->iterationType != FRU_NOT_ITERATED)) {
151 153 path = ppath;
152 154 } else {
153 155 path = (char *)def->name;
154 156 }
155 157
156 158 /* iteration, record and field */
157 159 if (def->iterationCount) {
158 160 int iterlen, n;
159 161 uint8_t head, num;
160 162 fru_regdef_t newdef;
161 163 nvlist_t **nv_elems;
162 164 char num_str[32];
163 165
164 166 iterlen = (def->payloadLen - NUM_ITER_BYTES) /
165 167 def->iterationCount;
166 168
167 169 /*
168 170 * make a new element definition to describe the components of
169 171 * the iteration.
170 172 */
171 173 (void) memcpy(&newdef, def, sizeof (newdef));
172 174 newdef.iterationCount = 0;
173 175 newdef.payloadLen = iterlen;
174 176
175 177 /* validate the content of the iteration control bytes */
176 178 if ((data[HEAD_ITER] >= def->iterationCount) ||
177 179 (data[NUM_ITER] > def->iterationCount) ||
178 180 (data[MAX_ITER] != def->iterationCount)) {
179 181 /* invalid. show all iterations */
180 182 head = 0;
181 183 num = def->iterationCount;
182 184 } else {
183 185 head = data[HEAD_ITER];
184 186 num = data[NUM_ITER];
185 187 }
186 188
187 189 nv_elems = (nvlist_t **)malloc(num * sizeof (nvlist_t *));
188 190 if (!nv_elems)
189 191 return;
190 192 for (i = head, n = 0, data += sizeof (uint32_t); n < num;
191 193 i = ((i + 1) % def->iterationCount), n++) {
192 194 if (nvlist_alloc(&nv_elems[n], NV_UNIQUE_NAME, 0) != 0)
193 195 return;
194 196 (void) snprintf(num_str, sizeof (num_str), "%d", n);
195 197 convert_element((data + i*iterlen), &newdef, num_str,
196 198 nv_elems[n], B_TRUE);
197 199 }
198 200 (void) nvlist_add_nvlist_array(nv, path, nv_elems, num);
199 201
200 202 } else if (def->dataType == FDTYPE_Record) {
201 203 const fru_regdef_t *component;
202 204 nvlist_t *nv_record;
203 205
204 206 if (!from_iter) {
205 207 if (nvlist_alloc(&nv_record, NV_UNIQUE_NAME, 0) != 0) {
206 208 return;
207 209 }
208 210 } else {
209 211 nv_record = nv;
210 212 }
211 213
212 214 for (i = 0; i < def->enumCount; i++,
213 215 data += component->payloadLen) {
214 216 component = fru_reg_lookup_def_by_name(
215 217 def->enumTable[i].text);
216 218 convert_element(data, component, "", nv_record,
217 219 B_FALSE);
218 220 }
219 221
220 222 (void) nvlist_add_nvlist(nv, path, nv_record);
221 223
222 224 } else {
223 225 convert_field(data, def, path, nv);
224 226 }
225 227 }
226 228
227 229
228 230 static fru_regdef_t *
229 231 alloc_unknown_fru_regdef(void)
230 232 {
231 233 fru_regdef_t *p;
232 234
233 235 p = malloc(sizeof (fru_regdef_t));
234 236 if (!p) {
235 237 return (NULL);
236 238 }
237 239 p->version = REGDEF_VERSION;
238 240 p->name = NULL;
239 241 p->tagType = -1;
240 242 p->tagDense = -1;
241 243 p->payloadLen = -1;
242 244 p->dataLength = -1;
243 245 p->dataType = FDTYPE_ByteArray;
244 246 p->dispType = FDISP_Hex;
245 247 p->purgeable = FRU_WHICH_UNDEFINED;
246 248 p->relocatable = FRU_WHICH_UNDEFINED;
247 249 p->enumCount = 0;
248 250 p-> enumTable = NULL;
249 251 p->iterationCount = 0;
250 252 p->iterationType = FRU_NOT_ITERATED;
251 253 p->exampleString = NULL;
252 254
253 255 return (p);
254 256 }
255 257
256 258 static int
257 259 convert_packet(fru_tag_t *tag, uint8_t *payload, size_t length, void *args)
258 260 {
259 261 int tag_type;
260 262 size_t payload_length;
261 263 const fru_regdef_t *def;
262 264 nvlist_t *nv = (nvlist_t *)args;
263 265 char tagname[sizeof ("?_0123456789_0123456789")];
264 266 tag_type = get_tag_type(tag);
265 267 payload_length = 0;
266 268
267 269 /* check for unrecognized tag */
268 270 if ((tag_type == -1) ||
269 271 ((payload_length = get_payload_length(tag)) != length)) {
270 272 fru_regdef_t *unknown;
271 273
272 274 unknown = alloc_unknown_fru_regdef();
273 275 unknown->payloadLen = length;
274 276 unknown->dataLength = unknown->payloadLen;
275 277
276 278 if (tag_type == -1) {
277 279 (void) snprintf(tagname, sizeof (tagname),
278 280 "INVALID");
279 281 } else {
280 282 (void) snprintf(tagname, sizeof (tagname),
281 283 "%s_%u_%u_%u", get_tagtype_str(tag_type),
282 284 get_tag_dense(tag), payload_length, length);
283 285 }
284 286 unknown->name = tagname;
285 287 convert_element(payload, unknown, "", nv, B_FALSE);
286 288 free(unknown);
287 289
288 290 } else if ((def = fru_reg_lookup_def_by_tag(*tag)) == NULL) {
289 291 fru_regdef_t *unknown;
290 292
291 293 unknown = alloc_unknown_fru_regdef();
292 294 unknown->payloadLen = length;
293 295 unknown->dataLength = unknown->payloadLen;
294 296
295 297 (void) snprintf(tagname, sizeof (tagname), "%s_%u_%u",
296 298 get_tagtype_str(tag_type),
297 299 unknown->tagDense, payload_length);
298 300
299 301 unknown->name = tagname;
300 302 convert_element(payload, unknown, "", nv, B_FALSE);
301 303 free(unknown);
302 304
303 305 } else {
304 306
305 307 convert_element(payload, def, "", nv, B_FALSE);
306 308
307 309 }
308 310
309 311 return (FRU_SUCCESS);
310 312 }
311 313
312 314
313 315 static int
314 316 convert_packets_in_segment(fru_seghdl_t segment, void *args)
315 317 {
316 318 char *name;
317 319 int ret;
318 320 nvlist_t *nv = (nvlist_t *)args;
319 321 nvlist_t *nv_segment;
320 322
321 323 ret = fru_get_segment_name(segment, &name);
322 324 if (ret != FRU_SUCCESS) {
323 325 return (ret);
324 326 }
325 327
326 328 /* create a new nvlist for each segment */
327 329 ret = nvlist_alloc(&nv_segment, NV_UNIQUE_NAME, 0);
328 330 if (ret) {
329 331 free(name);
330 332 return (FRU_FAILURE);
331 333 }
332 334
333 335 /* convert the segment to an nvlist */
334 336 ret = fru_for_each_packet(segment, convert_packet, nv_segment);
335 337 if (ret != FRU_SUCCESS) {
336 338 nvlist_free(nv_segment);
337 339 free(name);
338 340 return (ret);
339 341 }
340 342
341 343 /* add the nvlist for this segment */
342 344 (void) nvlist_add_nvlist(nv, name, nv_segment);
343 345
344 346 free(name);
345 347
346 348 return (FRU_SUCCESS);
347 349 }
348 350
349 351
350 352 static int
351 353 convert_fru(fru_nodehdl_t hdl, nvlist_t **nvlist)
352 354 {
353 355 int err;
354 356 nvlist_t *nv;
355 357 fru_node_t fru_type;
356 358
357 359 if (fru_get_node_type(hdl, &fru_type) != FRU_SUCCESS) {
358 360 return (-1);
359 361 }
360 362
361 363 if (fru_type != FRU_NODE_CONTAINER) {
362 364 return (-1);
363 365 }
364 366
365 367 err = nvlist_alloc(&nv, NV_UNIQUE_NAME, 0);
366 368 if (err) {
367 369 return (err);
368 370 }
369 371
370 372 if (fru_for_each_segment(hdl, convert_packets_in_segment, nv) !=
371 373 FRU_SUCCESS) {
372 374 nvlist_free(nv);
373 375 return (-1);
374 376 }
375 377
376 378 *nvlist = nv;
377 379
378 380 return (0);
379 381 }
380 382
381 383
382 384 int
383 385 rawfru_to_nvlist(uint8_t *buffer, size_t bufsize, char *cont_type,
384 386 nvlist_t **nvlist)
385 387 {
386 388 fru_errno_t fru_err;
387 389 fru_nodehdl_t hdl;
388 390 int err;
389 391
390 392 (void) pthread_mutex_lock(&gLock);
391 393 fru_err = fru_open_data_source("raw", buffer, bufsize, cont_type,
392 394 NULL);
393 395 if (fru_err != FRU_SUCCESS) {
394 396 (void) pthread_mutex_unlock(&gLock);
↓ open down ↓ |
359 lines elided |
↑ open up ↑ |
395 397 return (-1);
396 398 }
397 399 fru_err = fru_get_root(&hdl);
398 400 if (fru_err != FRU_SUCCESS) {
399 401 (void) pthread_mutex_unlock(&gLock);
400 402 return (-1);
401 403 }
402 404
403 405 err = convert_fru(hdl, nvlist);
404 406
405 - fru_close_data_source();
407 + (void) fru_close_data_source();
406 408
407 409 (void) pthread_mutex_unlock(&gLock);
408 410
409 411 return (err);
410 412 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX