1 /*
2 * Copyright (C) 2008-2015 FreeIPMI Core Team
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 *
17 */
18
19 #if HAVE_CONFIG_H
20 #include "config.h"
21 #endif /* HAVE_CONFIG_H */
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #if STDC_HEADERS
26 #include <string.h>
27 #endif /* STDC_HEADERS */
28 #include <limits.h>
29 #include <assert.h>
30
31 #include <freeipmi/freeipmi.h>
32
33 #include "ipmi-oem.h"
34 #include "ipmi-oem-argp.h"
35 #include "ipmi-oem-common.h"
36
37 #include "freeipmi-portability.h"
38 #include "pstdout.h"
39
40 int
ipmi_oem_check_response_and_completion_code(ipmi_oem_state_data_t * state_data,const void * bytes_rs,unsigned int bytes_rs_len,unsigned int expected_bytes_rs_len,uint8_t cmd,uint8_t netfn,Ipmi_oem_comp_code_strerror comp_code_strerror)41 ipmi_oem_check_response_and_completion_code (ipmi_oem_state_data_t *state_data,
42 const void *bytes_rs,
43 unsigned int bytes_rs_len,
44 unsigned int expected_bytes_rs_len,
45 uint8_t cmd,
46 uint8_t netfn,
47 Ipmi_oem_comp_code_strerror comp_code_strerror)
48 {
49 const uint8_t *bytes_rs_ptr = bytes_rs;
50
51 assert (state_data);
52 assert (bytes_rs);
53
54 if (bytes_rs_len < expected_bytes_rs_len)
55 {
56 if (bytes_rs_len >= 2 && bytes_rs_ptr[1] != IPMI_COMP_CODE_COMMAND_SUCCESS)
57 goto output_comp_code_error;
58
59 pstdout_fprintf (state_data->pstate,
60 stderr,
61 "%s:%s invalid response length: %u, expected %u\n",
62 state_data->prog_data->args->oem_id,
63 state_data->prog_data->args->oem_command,
64 bytes_rs_len,
65 expected_bytes_rs_len);
66 return (-1);
67 }
68
69 output_comp_code_error:
70 if (bytes_rs_ptr[1] != IPMI_COMP_CODE_COMMAND_SUCCESS)
71 {
72 char errbuf[IPMI_OEM_ERR_BUFLEN + 1];
73
74 memset (errbuf, '\0', IPMI_OEM_ERR_BUFLEN + 1);
75
76 if (comp_code_strerror)
77 {
78 int ret;
79
80 if ((ret = comp_code_strerror (state_data,
81 bytes_rs_ptr[1], /* completion code */
82 cmd,
83 netfn,
84 errbuf,
85 IPMI_OEM_ERR_BUFLEN)) < 0)
86 snprintf (errbuf, IPMI_OEM_ERR_BUFLEN, "completion-code = 0x%X", bytes_rs_ptr[1]);
87
88 if (!ret)
89 goto standard_output_comp_code_error;
90 }
91 else
92 {
93 standard_output_comp_code_error:
94 if (ipmi_completion_code_strerror_r (cmd, /* cmd */
95 netfn, /* network function */
96 bytes_rs_ptr[1], /* completion code */
97 errbuf,
98 IPMI_OEM_ERR_BUFLEN) < 0)
99 {
100 #if 0
101 pstdout_perror (state_data->pstate, "ipmi_completion_code_strerror_r");
102 #endif
103 snprintf (errbuf, IPMI_OEM_ERR_BUFLEN, "completion-code = 0x%X", bytes_rs_ptr[1]);
104 }
105 }
106
107 pstdout_fprintf (state_data->pstate,
108 stderr,
109 "%s:%s failed: %s\n",
110 state_data->prog_data->args->oem_id,
111 state_data->prog_data->args->oem_command,
112 errbuf);
113 return (-1);
114 }
115
116 return (0);
117 }
118
119 int
ipmi_oem_parse_key_value(ipmi_oem_state_data_t * state_data,unsigned int option_num,char ** key,char ** value)120 ipmi_oem_parse_key_value (ipmi_oem_state_data_t *state_data,
121 unsigned int option_num,
122 char **key,
123 char **value)
124 {
125 char *tempstr = NULL;
126 char *tempptr = NULL;
127 char *tempkey = NULL;
128 char *tempvalue = NULL;
129 int rv = -1;
130
131 assert (state_data);
132 assert (key);
133 assert (value);
134
135 if (!(tempstr = strdup (state_data->prog_data->args->oem_options[option_num])))
136 {
137 pstdout_perror (state_data->pstate, "strdup");
138 goto cleanup;
139 }
140
141 tempptr = strchr (tempstr, '=');
142 if (!tempptr)
143 {
144 pstdout_fprintf (state_data->pstate,
145 stderr,
146 "%s:%s invalid OEM option argument '%s' : no equal sign\n",
147 state_data->prog_data->args->oem_id,
148 state_data->prog_data->args->oem_command,
149 state_data->prog_data->args->oem_options[option_num]);
150 goto cleanup;
151 }
152
153 (*tempptr) = '\0';
154 tempptr++;
155
156 if (!(tempkey = strdup (tempstr)))
157 {
158 pstdout_perror (state_data->pstate, "strdup");
159 goto cleanup;
160 }
161
162 if (!(tempvalue = strdup (tempptr)))
163 {
164 pstdout_perror (state_data->pstate, "strdup");
165 goto cleanup;
166 }
167
168 (*key) = tempkey;
169 (*value) = tempvalue;
170
171 rv = 0;
172 cleanup:
173 free (tempstr);
174 if (rv < 0)
175 {
176 free (tempkey);
177 free (tempvalue);
178 }
179 return (rv);
180 }
181
182 int
ipmi_oem_parse_enable(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint8_t * enable)183 ipmi_oem_parse_enable (ipmi_oem_state_data_t *state_data,
184 unsigned int option_num,
185 const char *value,
186 uint8_t *enable)
187 {
188 assert (state_data);
189 assert (value);
190 assert (enable);
191
192 if (strcasecmp (value, "enable") && strcasecmp (value, "disable"))
193 {
194 pstdout_fprintf (state_data->pstate,
195 stderr,
196 "%s:%s invalid OEM option argument '%s' : invalid value\n",
197 state_data->prog_data->args->oem_id,
198 state_data->prog_data->args->oem_command,
199 state_data->prog_data->args->oem_options[option_num]);
200 return (-1);
201 }
202
203 if (!strcasecmp (value, "enable"))
204 (*enable) = 1;
205 else
206 (*enable) = 0;
207
208 return (0);
209 }
210
211 int
ipmi_oem_parse_1_byte_field(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint8_t * value_out)212 ipmi_oem_parse_1_byte_field (ipmi_oem_state_data_t *state_data,
213 unsigned int option_num,
214 const char *value,
215 uint8_t *value_out)
216 {
217 unsigned int temp;
218 char *ptr = NULL;
219
220 assert (state_data);
221 assert (value);
222 assert (value_out);
223
224 errno = 0;
225
226 temp = strtoul (value, &ptr, 10);
227
228 if (errno
229 || ptr[0] != '\0'
230 || temp > UCHAR_MAX)
231 {
232 pstdout_fprintf (state_data->pstate,
233 stderr,
234 "%s:%s invalid OEM option argument '%s' : invalid value\n",
235 state_data->prog_data->args->oem_id,
236 state_data->prog_data->args->oem_command,
237 state_data->prog_data->args->oem_options[option_num]);
238 return (-1);
239 }
240
241 (*value_out) = temp;
242 return (0);
243 }
244
245 int
ipmi_oem_parse_2_byte_field(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint16_t * value_out)246 ipmi_oem_parse_2_byte_field (ipmi_oem_state_data_t *state_data,
247 unsigned int option_num,
248 const char *value,
249 uint16_t *value_out)
250 {
251 unsigned int temp;
252 char *ptr = NULL;
253
254 assert (state_data);
255 assert (value);
256 assert (value_out);
257
258 errno = 0;
259
260 temp = strtoul (value, &ptr, 10);
261
262 if (errno
263 || ptr[0] != '\0'
264 || temp > USHRT_MAX)
265 {
266 pstdout_fprintf (state_data->pstate,
267 stderr,
268 "%s:%s invalid OEM option argument '%s' : invalid value\n",
269 state_data->prog_data->args->oem_id,
270 state_data->prog_data->args->oem_command,
271 state_data->prog_data->args->oem_options[option_num]);
272 return (-1);
273 }
274
275 (*value_out) = temp;
276 return (0);
277 }
278
279 int
ipmi_oem_parse_4_byte_field(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint32_t * value_out)280 ipmi_oem_parse_4_byte_field (ipmi_oem_state_data_t *state_data,
281 unsigned int option_num,
282 const char *value,
283 uint32_t *value_out)
284 {
285 unsigned int temp;
286 char *ptr = NULL;
287
288 assert (state_data);
289 assert (value);
290 assert (value_out);
291
292 errno = 0;
293
294 temp = strtoul (value, &ptr, 10);
295
296 if (errno
297 || ptr[0] != '\0')
298 {
299 pstdout_fprintf (state_data->pstate,
300 stderr,
301 "%s:%s invalid OEM option argument '%s' : invalid value\n",
302 state_data->prog_data->args->oem_id,
303 state_data->prog_data->args->oem_command,
304 state_data->prog_data->args->oem_options[option_num]);
305 return (-1);
306 }
307
308 (*value_out) = temp;
309 return (0);
310 }
311
312 int
ipmi_oem_parse_unsigned_int_range(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint32_t * value_out,unsigned int min,unsigned int max)313 ipmi_oem_parse_unsigned_int_range (ipmi_oem_state_data_t *state_data,
314 unsigned int option_num,
315 const char *value,
316 uint32_t *value_out,
317 unsigned int min,
318 unsigned int max)
319 {
320 unsigned int temp;
321 char *ptr = NULL;
322
323 assert (state_data);
324 assert (value);
325 assert (value_out);
326 assert (min < max);
327
328 errno = 0;
329
330 temp = strtoul (value, &ptr, 10);
331
332 if (errno
333 || ptr[0] != '\0')
334 {
335 pstdout_fprintf (state_data->pstate,
336 stderr,
337 "%s:%s invalid OEM option argument '%s' : invalid value\n",
338 state_data->prog_data->args->oem_id,
339 state_data->prog_data->args->oem_command,
340 state_data->prog_data->args->oem_options[option_num]);
341 return (-1);
342 }
343
344 if (temp < min
345 || temp > max)
346 {
347 pstdout_fprintf (state_data->pstate,
348 stderr,
349 "%s:%s invalid OEM option argument '%s' : out of range\n",
350 state_data->prog_data->args->oem_id,
351 state_data->prog_data->args->oem_command,
352 state_data->prog_data->args->oem_options[option_num]);
353 return (-1);
354 }
355
356 (*value_out) = temp;
357 return (0);
358 }
359
360 int
ipmi_oem_parse_ip_address(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint32_t * ip_address)361 ipmi_oem_parse_ip_address (ipmi_oem_state_data_t *state_data,
362 unsigned int option_num,
363 const char *value,
364 uint32_t *ip_address)
365 {
366 unsigned int b1, b2, b3, b4;
367 uint32_t temp;
368 int ret;
369
370 assert (state_data);
371 assert (value);
372 assert (ip_address);
373
374 if ((ret = sscanf (value,
375 "%u.%u.%u.%u",
376 &b1,
377 &b2,
378 &b3,
379 &b4)) < 0)
380 {
381 pstdout_fprintf (state_data->pstate,
382 stderr,
383 "%s:%s invalid IP address '%s'\n",
384 state_data->prog_data->args->oem_id,
385 state_data->prog_data->args->oem_command,
386 state_data->prog_data->args->oem_options[option_num]);
387 return (-1);
388 }
389
390 if (ret != 4)
391 {
392 pstdout_fprintf (state_data->pstate,
393 stderr,
394 "%s:%s invalid IP address '%s'\n",
395 state_data->prog_data->args->oem_id,
396 state_data->prog_data->args->oem_command,
397 state_data->prog_data->args->oem_options[option_num]);
398 return (-1);
399 }
400
401 temp = 0;
402 temp |= (uint32_t)b1;
403 temp |= ((uint32_t)b2 << 8);
404 temp |= ((uint32_t)b3 << 16);
405 temp |= ((uint32_t)b4 << 24);
406
407 (*ip_address) = temp;
408 return (0);
409
410 }
411
412 int
ipmi_oem_parse_string(ipmi_oem_state_data_t * state_data,unsigned int option_num,const char * value,uint8_t * string_length,char * stringbuf,unsigned int stringbuflen)413 ipmi_oem_parse_string (ipmi_oem_state_data_t *state_data,
414 unsigned int option_num,
415 const char *value,
416 uint8_t *string_length,
417 char *stringbuf,
418 unsigned int stringbuflen)
419 {
420 assert (state_data);
421 assert (value);
422 assert (string_length);
423 assert (stringbuf);
424 assert (stringbuflen);
425
426 if (strlen (value) > stringbuflen)
427 {
428 pstdout_fprintf (state_data->pstate,
429 stderr,
430 "%s:%s invalid OEM option argument '%s' : string length too long\n",
431 state_data->prog_data->args->oem_id,
432 state_data->prog_data->args->oem_command,
433 state_data->prog_data->args->oem_options[option_num]);
434 return (-1);
435 }
436
437 (*string_length) = strlen (value);
438
439 /* use memcpy, do not need NULL termination */
440 if ((*string_length))
441 memcpy (stringbuf,
442 value,
443 (*string_length));
444
445 return (0);
446 }
447
448 int
ipmi_oem_get_system_info_string(ipmi_oem_state_data_t * state_data,uint8_t parameter_selector,uint8_t set_selector,uint8_t block_selector,char * string,unsigned int string_len,unsigned int * string_len_ret)449 ipmi_oem_get_system_info_string (ipmi_oem_state_data_t *state_data,
450 uint8_t parameter_selector,
451 uint8_t set_selector,
452 uint8_t block_selector,
453 char *string,
454 unsigned int string_len,
455 unsigned int *string_len_ret)
456 {
457 fiid_obj_t obj_cmd_rs = NULL;
458 uint8_t configuration_parameter_data[IPMI_OEM_MAX_BYTES];
459 int len;
460 int rv = -1;
461
462 assert (state_data);
463 assert (string);
464 assert (string_len);
465
466 if (!(obj_cmd_rs = fiid_obj_create (tmpl_cmd_get_system_info_parameters_rs)))
467 {
468 pstdout_fprintf (state_data->pstate,
469 stderr,
470 "fiid_obj_create: %s\n",
471 strerror (errno));
472 goto cleanup;
473 }
474
475 if (ipmi_cmd_get_system_info_parameters (state_data->ipmi_ctx,
476 IPMI_GET_SYSTEM_INFO_PARAMETER,
477 parameter_selector,
478 set_selector,
479 block_selector,
480 obj_cmd_rs) < 0)
481 {
482 if ((ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_BAD_COMPLETION_CODE
483 && ipmi_check_completion_code (obj_cmd_rs,
484 IPMI_COMP_CODE_GET_SYSTEM_INFO_PARAMETERS_PARAMETER_NOT_SUPPORTED) == 1)
485 || (ipmi_ctx_errnum (state_data->ipmi_ctx) == IPMI_ERR_COMMAND_INVALID_OR_UNSUPPORTED
486 && ipmi_check_completion_code (obj_cmd_rs,
487 IPMI_COMP_CODE_INVALID_DATA_FIELD_IN_REQUEST) == 1))
488 {
489 pstdout_fprintf (state_data->pstate,
490 stderr,
491 "%s:%s '%s' option not supported on this system\n",
492 state_data->prog_data->args->oem_id,
493 state_data->prog_data->args->oem_command,
494 state_data->prog_data->args->oem_options[0]);
495 goto cleanup;
496 }
497
498 pstdout_fprintf (state_data->pstate,
499 stderr,
500 "ipmi_cmd_get_system_info_parameters: %s\n",
501 ipmi_ctx_errormsg (state_data->ipmi_ctx));
502 goto cleanup;
503 }
504
505 if ((len = fiid_obj_get_data (obj_cmd_rs,
506 "configuration_parameter_data",
507 configuration_parameter_data,
508 IPMI_OEM_MAX_BYTES)) < 0)
509 {
510 pstdout_fprintf (state_data->pstate,
511 stderr,
512 "fiid_obj_get_data: 'configuration_parameter_data': %s\n",
513 fiid_obj_errormsg (obj_cmd_rs));
514 goto cleanup;
515 }
516
517 if (len > string_len)
518 {
519 pstdout_fprintf (state_data->pstate,
520 stderr,
521 "buffer overflow\n");
522 goto cleanup;
523 }
524
525 memcpy (string,
526 &(configuration_parameter_data[0]),
527 len);
528
529 if (string_len_ret)
530 (*string_len_ret) = len;
531
532 rv = 0;
533 cleanup:
534 fiid_obj_destroy (obj_cmd_rs);
535 return (rv);
536 }
537