1 /*
2  * cmd_fru.c
3  *
4  * A command interpreter for OpenIPMI
5  *
6  * Author: MontaVista Software, Inc.
7  *         Corey Minyard <minyard@mvista.com>
8  *         source@mvista.com
9  *
10  * Copyright 2004 MontaVista Software Inc.
11  *
12  *  This program is free software; you can redistribute it and/or
13  *  modify it under the terms of the GNU Lesser General Public License
14  *  as published by the Free Software Foundation; either version 2 of
15  *  the License, or (at your option) any later version.
16  *
17  *
18  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
19  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  *  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
23  *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
24  *  OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  *  ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
26  *  TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
27  *  USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  *
29  *  You should have received a copy of the GNU Lesser General Public
30  *  License along with this program; if not, write to the Free
31  *  Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
32  */
33 
34 #include <errno.h>
35 #include <string.h>
36 #include <ctype.h>
37 #include <stdlib.h>
38 #include <stdio.h>
39 #include <OpenIPMI/ipmiif.h>
40 #include <OpenIPMI/ipmi_mc.h>
41 #include <OpenIPMI/ipmi_cmdlang.h>
42 #include <OpenIPMI/ipmi_fru.h>
43 
44 /* Internal includes, do not use in your programs */
45 #include <OpenIPMI/internal/ipmi_malloc.h>
46 
47 /* Don't pollute the namespace iwth ipmi_fru_t. */
48 void ipmi_cmdlang_dump_fru_info(ipmi_cmd_info_t *cmd_info, ipmi_fru_t *fru);
49 
50 static void
fru_list_handler(ipmi_fru_t * fru,void * cb_data)51 fru_list_handler(ipmi_fru_t *fru, void *cb_data)
52 {
53     ipmi_cmd_info_t *cmd_info = cb_data;
54     ipmi_cmdlang_t  *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
55     char            fru_name[IPMI_FRU_NAME_LEN];
56 
57     if (cmdlang->err)
58 	return;
59 
60     ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
61 
62     ipmi_cmdlang_out(cmd_info, "Name", fru_name);
63 }
64 
65 static void
fru_list(ipmi_domain_t * domain,void * cb_data)66 fru_list(ipmi_domain_t *domain, void *cb_data)
67 {
68     ipmi_cmd_info_t *cmd_info = cb_data;
69     char             domain_name[IPMI_DOMAIN_NAME_LEN];
70 
71     ipmi_domain_get_name(domain, domain_name, sizeof(domain_name));
72     ipmi_cmdlang_out(cmd_info, "Domain", NULL);
73     ipmi_cmdlang_down(cmd_info);
74     ipmi_cmdlang_out(cmd_info, "Name", domain_name);
75     ipmi_cmdlang_out(cmd_info, "FRUs", NULL);
76     ipmi_cmdlang_down(cmd_info);
77     ipmi_fru_iterate_frus(domain, fru_list_handler, cmd_info);
78     ipmi_cmdlang_up(cmd_info);
79     ipmi_cmdlang_up(cmd_info);
80 }
81 
82 static void
fru_info(ipmi_fru_t * fru,void * cb_data)83 fru_info(ipmi_fru_t *fru, void *cb_data)
84 {
85     ipmi_cmd_info_t *cmd_info = cb_data;
86     char            fru_name[IPMI_FRU_NAME_LEN];
87 
88     ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
89 
90     ipmi_cmdlang_dump_fru_info(cmd_info, fru);
91 }
92 
93 static char *areas[IPMI_FRU_FTR_NUMBER] =
94 {
95     "internal_use",
96     "chassis_info",
97     "board_info",
98     "product_info",
99     "multi_record"
100 };
101 
102 static void
fru_areainfo(ipmi_fru_t * fru,void * cb_data)103 fru_areainfo(ipmi_fru_t *fru, void *cb_data)
104 {
105     ipmi_cmd_info_t *cmd_info = cb_data;
106     char            fru_name[IPMI_FRU_NAME_LEN];
107     int             i;
108     int             rv;
109 
110     ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
111 
112     ipmi_cmdlang_out(cmd_info, "FRU", NULL);
113     ipmi_cmdlang_down(cmd_info);
114     ipmi_cmdlang_out(cmd_info, "Name", fru_name);
115     ipmi_cmdlang_out_int(cmd_info, "FRU Length",
116 			 ipmi_fru_get_data_length(fru));
117     for (i=0; i<IPMI_FRU_FTR_NUMBER; i++) {
118 	unsigned int offset, length, used_length;
119 	rv = ipmi_fru_area_get_offset(fru, i, &offset);
120 	rv |= ipmi_fru_area_get_length(fru, i, &length);
121 	rv |= ipmi_fru_area_get_used_length(fru, i, &used_length);
122 	if (rv)
123 	    continue;
124 	ipmi_cmdlang_out(cmd_info, "Area", NULL);
125 	ipmi_cmdlang_down(cmd_info);
126 	ipmi_cmdlang_out(cmd_info, "Name", areas[i]);
127 	ipmi_cmdlang_out_int(cmd_info, "Number", i);
128 	ipmi_cmdlang_out_int(cmd_info, "Offset", offset);
129 	ipmi_cmdlang_out_int(cmd_info, "Length", length);
130 	ipmi_cmdlang_out_int(cmd_info, "Used Length", used_length);
131 	ipmi_cmdlang_up(cmd_info);
132     }
133     ipmi_cmdlang_up(cmd_info);
134 }
135 
136 static void
fru_written(ipmi_domain_t * domain,ipmi_fru_t * fru,int err,void * cb_data)137 fru_written(ipmi_domain_t *domain, ipmi_fru_t *fru, int err, void *cb_data)
138 {
139     ipmi_cmd_info_t *cmd_info = cb_data;
140     ipmi_cmdlang_t  *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
141     char            fru_name[IPMI_FRU_NAME_LEN];
142 
143     if (err) {
144 	cmdlang->errstr = "Unable to write FRU";
145 	cmdlang->err = err;
146 	ipmi_fru_get_name(fru, cmdlang->objstr,
147 			  cmdlang->objstr_len);
148 	cmdlang->location = "cmd_fru.c(fru_written)";
149     } else {
150 	ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
151 	ipmi_cmdlang_out(cmd_info, "FRU written", fru_name);
152     }
153 
154     ipmi_cmdlang_cmd_info_put(cmd_info);
155 }
156 
157 static void
fru_write(ipmi_fru_t * fru,void * cb_data)158 fru_write(ipmi_fru_t *fru, void *cb_data)
159 {
160     ipmi_cmd_info_t *cmd_info = cb_data;
161     ipmi_cmdlang_t  *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
162     int             rv;
163 
164     ipmi_cmdlang_cmd_info_get(cmd_info);
165     rv = ipmi_fru_write(fru, fru_written, cmd_info);
166     if (rv) {
167 	ipmi_cmdlang_cmd_info_put(cmd_info);
168 	cmdlang->errstr = "Unable to write FRU";
169 	cmdlang->err = rv;
170 	goto out_err;
171     }
172 
173     return;
174 
175  out_err:
176     ipmi_fru_get_name(fru, cmdlang->objstr,
177 		      cmdlang->objstr_len);
178     cmdlang->location = "cmd_fru.c(fru_write)";
179 }
180 
181 static void
fru_deleted(ipmi_fru_t * fru,void * cb_data)182 fru_deleted(ipmi_fru_t *fru, void *cb_data)
183 {
184     ipmi_cmd_info_t *cmd_info = cb_data;
185     char            fru_name[IPMI_FRU_NAME_LEN];
186 
187     ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
188     ipmi_cmdlang_out(cmd_info, "FRU deleted", fru_name);
189     ipmi_cmdlang_cmd_info_put(cmd_info);
190 }
191 
192 static void
fru_close(ipmi_fru_t * fru,void * cb_data)193 fru_close(ipmi_fru_t *fru, void *cb_data)
194 {
195     ipmi_cmd_info_t *cmd_info = cb_data;
196     ipmi_cmdlang_t  *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
197     int             rv;
198 
199     ipmi_cmdlang_cmd_info_get(cmd_info);
200     /* We need to be holding our own reference to the FRU because
201        ipmi_fru_destroy will do a deref on it, but the calling code
202        will also be doing a deref.. */
203     ipmi_fru_ref(fru);
204     rv = ipmi_fru_destroy(fru, fru_deleted, cmd_info);
205     if (rv) {
206 	ipmi_cmdlang_cmd_info_put(cmd_info);
207 	cmdlang->errstr = "Unable to close domain";
208 	cmdlang->err = rv;
209 	goto out_err;
210     }
211 
212     return;
213 
214  out_err:
215     ipmi_fru_get_name(fru, cmdlang->objstr,
216 		      cmdlang->objstr_len);
217     cmdlang->location = "cmd_fru.c(fru_close)";
218 }
219 
220 static void
fru_setval(ipmi_fru_t * fru,void * cb_data)221 fru_setval(ipmi_fru_t *fru, void *cb_data)
222 {
223     ipmi_cmd_info_t *cmd_info = cb_data;
224     ipmi_cmdlang_t  *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
225     int             curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info);
226     int             argc = ipmi_cmdlang_get_argc(cmd_info);
227     char            **argv = ipmi_cmdlang_get_argv(cmd_info);
228     char            fru_name[IPMI_FRU_NAME_LEN];
229     enum ipmi_fru_data_type_e dtype;
230     int             i;
231     int             num;
232     const char      *name;
233     int             ival;
234     double          dval;
235     int             rv;
236     int             len;
237     unsigned char   *data;
238     int             j;
239     int             type;
240     int             version;
241 
242     if ((argc - curr_arg) < 2) {
243 	/* Not enough parameters */
244 	cmdlang->errstr = "Not enough parameters";
245 	cmdlang->err = EINVAL;
246 	goto out_err;
247     }
248 
249     if (strcmp(argv[curr_arg], "multi_record") == 0)
250 	goto do_multi_record;
251 
252     for (i=0; ; i++) {
253 	num = -2;
254 	rv = ipmi_fru_get(fru, i, &name, &num, &dtype, NULL, NULL, NULL, NULL);
255 	if (rv == EINVAL) {
256 	    cmdlang->errstr = "Name not found";
257 	    cmdlang->err = EINVAL;
258 	    goto out_err;
259 	}
260 	if (strcmp(name, argv[curr_arg]) == 0)
261 	    break;
262     }
263     curr_arg++;
264 
265     if (num != -2) {
266 	/* Need the number */
267 	ipmi_cmdlang_get_int(argv[curr_arg], &num, cmd_info);
268 	if (cmdlang->err) {
269 	    cmdlang->errstr = "value number";
270 	    goto out_err;
271 	}
272 	curr_arg++;
273 
274 	if ((argc - curr_arg) < 1) {
275 	    /* Not enough parameters */
276 	    cmdlang->errstr = "Not enough parameters";
277 	    cmdlang->err = EINVAL;
278 	    goto out_err;
279 	}
280     }
281 
282     switch (dtype) {
283     case IPMI_FRU_DATA_TIME:
284 	ipmi_cmdlang_get_int(argv[curr_arg], &ival, cmd_info);
285 	if (cmdlang->err) {
286 	    cmdlang->errstr = "value invalid";
287 	    goto out_err;
288 	}
289 	curr_arg++;
290 	rv = ipmi_fru_set_time_val(fru, i, num, ival);
291 	if (rv) {
292 	    cmdlang->errstr = "value invalid";
293 	    cmdlang->err = EINVAL;
294 	    goto out_err;
295 	}
296 	break;
297 
298     case IPMI_FRU_DATA_INT:
299 	ipmi_cmdlang_get_int(argv[curr_arg], &ival, cmd_info);
300 	if (cmdlang->err) {
301 	    cmdlang->errstr = "value invalid";
302 	    goto out_err;
303 	}
304 	curr_arg++;
305 	rv = ipmi_fru_set_int_val(fru, i, num, ival);
306 	if (rv) {
307 	    cmdlang->errstr = "value invalid";
308 	    cmdlang->err = EINVAL;
309 	    goto out_err;
310 	}
311 	break;
312 
313     case IPMI_FRU_DATA_BOOLEAN:
314 	ipmi_cmdlang_get_bool(argv[curr_arg], &ival, cmd_info);
315 	if (cmdlang->err) {
316 	    cmdlang->errstr = "value invalid";
317 	    goto out_err;
318 	}
319 	curr_arg++;
320 	rv = ipmi_fru_set_int_val(fru, i, num, ival);
321 	if (rv) {
322 	    cmdlang->errstr = "value invalid";
323 	    cmdlang->err = EINVAL;
324 	    goto out_err;
325 	}
326 	break;
327 
328     case IPMI_FRU_DATA_FLOAT:
329 	ipmi_cmdlang_get_double(argv[curr_arg], &dval, cmd_info);
330 	if (cmdlang->err) {
331 	    cmdlang->errstr = "value invalid";
332 	    goto out_err;
333 	}
334 	curr_arg++;
335 	rv = ipmi_fru_set_float_val(fru, i, num, dval);
336 	if (rv) {
337 	    cmdlang->errstr = "value invalid";
338 	    cmdlang->err = EINVAL;
339 	    goto out_err;
340 	}
341 	break;
342 
343     case IPMI_FRU_DATA_ASCII:
344     case IPMI_FRU_DATA_BINARY:
345     case IPMI_FRU_DATA_UNICODE:
346 	if ((argc - curr_arg) < 1) {
347 	    /* Not enough parameters */
348 	    cmdlang->errstr = "Not enough parameters";
349 	    cmdlang->err = EINVAL;
350 	    goto out_err;
351 	}
352 	if (strcasecmp(argv[curr_arg], "binary") == 0) {
353 	    dtype = IPMI_FRU_DATA_BINARY;
354 	} else if (strcasecmp(argv[curr_arg], "ascii") == 0) {
355 	    dtype = IPMI_FRU_DATA_ASCII;
356 	} else if (strcasecmp(argv[curr_arg], "unicode") == 0) {
357 	    dtype = IPMI_FRU_DATA_UNICODE;
358 	} else {
359 	    cmdlang->errstr = "Invalid data type";
360 	    cmdlang->err = EINVAL;
361 	    goto out_err;
362 	}
363 	curr_arg++;
364 	if (dtype == IPMI_FRU_DATA_ASCII) {
365 	    char *str;
366 	    int  len;
367 	    if (curr_arg < argc) {
368 		str = argv[curr_arg];
369 		len = strlen(str);
370 	    } else {
371 		str = NULL;
372 		len = 0;
373 	    }
374 	    rv = ipmi_fru_set_data_val(fru, i, num, dtype, str, len);
375 	} else {
376 	    len = argc - curr_arg;
377 
378 	    if (len == 0)
379 		data = ipmi_mem_alloc(1);
380 	    else
381 		data = ipmi_mem_alloc(len);
382 	    if (!data) {
383 		cmdlang->errstr = "Out of memory";
384 		cmdlang->err = ENOMEM;
385 		goto out_err;
386 	    }
387 	    j = 0;
388 	    while (curr_arg < argc) {
389 		ipmi_cmdlang_get_int(argv[curr_arg], &ival, cmd_info);
390 		if (cmdlang->err) {
391 		    cmdlang->errstr = "value invalid";
392 		    ipmi_mem_free(data);
393 		    goto out_err;
394 		}
395 		data[j] = ival;
396 		curr_arg++;
397 		j++;
398 	    }
399 	    rv = ipmi_fru_set_data_val(fru, i, num, dtype, (char *) data, len);
400 	    ipmi_mem_free(data);
401 	}
402 	if (rv) {
403 	    cmdlang->errstr = "Error setting data value";
404 	    cmdlang->err = rv;
405 	    goto out_err;
406 	}
407 
408     case IPMI_FRU_DATA_SUB_NODE:
409 	/* Not relevant for normal FRU data. */
410 	break;
411     }
412 
413     goto out;
414 
415  do_multi_record:
416     curr_arg++;
417     if ((argc - curr_arg) < 1) {
418 	/* Not enough parameters */
419 	cmdlang->errstr = "Not enough parameters";
420 	cmdlang->err = EINVAL;
421 	goto out_err;
422     }
423 
424     ipmi_cmdlang_get_int(argv[curr_arg], &num, cmd_info);
425     if (cmdlang->err) {
426 	cmdlang->errstr = "value number";
427 	goto out_err;
428     }
429     curr_arg++;
430 
431     if ((argc - curr_arg) == 0) {
432 	/* Deleting the record. */
433 	rv = ipmi_fru_set_multi_record(fru, num, 0, 0, NULL, 0);
434 	if (rv) {
435 	    cmdlang->errstr = "Error clearing data value";
436 	    cmdlang->err = rv;
437 	    goto out_err;
438 	}
439 	goto out;
440     }
441 
442     if ((argc - curr_arg) < 2) {
443 	/* Not enough parameters */
444 	cmdlang->errstr = "Not enough parameters";
445 	cmdlang->err = EINVAL;
446 	goto out_err;
447     }
448 
449     ipmi_cmdlang_get_int(argv[curr_arg], &type, cmd_info);
450     if (cmdlang->err) {
451 	cmdlang->errstr = "type number";
452 	goto out_err;
453     }
454     curr_arg++;
455 
456     ipmi_cmdlang_get_int(argv[curr_arg], &version, cmd_info);
457     if (cmdlang->err) {
458 	cmdlang->errstr = "version number";
459 	goto out_err;
460     }
461     curr_arg++;
462 
463     len = argc - curr_arg;
464 
465     if (len == 0)
466 	data = ipmi_mem_alloc(1);
467     else
468 	data = ipmi_mem_alloc(len);
469     if (!data) {
470 	cmdlang->errstr = "Out of memory";
471 	cmdlang->err = ENOMEM;
472 	goto out_err;
473     }
474     j = 0;
475     while (curr_arg < argc) {
476 	ipmi_cmdlang_get_int(argv[curr_arg], &ival, cmd_info);
477 	if (cmdlang->err) {
478 	    cmdlang->errstr = "value invalid";
479 	    ipmi_mem_free(data);
480 	    goto out_err;
481 	}
482 	data[j] = ival;
483 	curr_arg++;
484 	j++;
485     }
486     rv = ipmi_fru_set_multi_record(fru, num, type, version, data, len);
487     ipmi_mem_free(data);
488     if (rv) {
489 	cmdlang->errstr = "Error setting data value";
490 	cmdlang->err = rv;
491 	goto out_err;
492     }
493 
494  out:
495     ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
496     ipmi_cmdlang_out(cmd_info, "FRU value set", fru_name);
497 
498     return;
499 
500  out_err:
501     ipmi_fru_get_name(fru, cmdlang->objstr,
502 		     cmdlang->objstr_len);
503     cmdlang->location = "cmd_fru.c(fru_setval)";
504 }
505 
506 static void
get_fru_by_name(char * name,ipmi_cmdlang_t * cmdlang,unsigned int * area)507 get_fru_by_name(char *name, ipmi_cmdlang_t *cmdlang, unsigned int *area)
508 {
509     if (strcmp(name, "internal_data") == 0) {
510 	*area = IPMI_FRU_FTR_INTERNAL_USE_AREA;
511     } else if (strcmp(name, "chassis_info") == 0) {
512 	*area = IPMI_FRU_FTR_CHASSIS_INFO_AREA;
513     } else if (strcmp(name, "board_info") == 0) {
514 	*area = IPMI_FRU_FTR_BOARD_INFO_AREA  ;
515     } else if (strcmp(name, "product_info") == 0) {
516 	*area = IPMI_FRU_FTR_PRODUCT_INFO_AREA;
517     } else if (strcmp(name, "multi_record") == 0) {
518 	*area = IPMI_FRU_FTR_MULTI_RECORD_AREA;
519     } else {
520 	cmdlang->errstr = "Invalid area name";
521 	cmdlang->err = EINVAL;
522     }
523 }
524 
525 static void
fru_area_offset(ipmi_fru_t * fru,void * cb_data)526 fru_area_offset(ipmi_fru_t *fru, void *cb_data)
527 {
528     ipmi_cmd_info_t *cmd_info = cb_data;
529     ipmi_cmdlang_t  *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
530     int             curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info);
531     int             argc = ipmi_cmdlang_get_argc(cmd_info);
532     char            **argv = ipmi_cmdlang_get_argv(cmd_info);
533     char            fru_name[IPMI_FRU_NAME_LEN];
534     unsigned int    area;
535     int		    offset;
536     int             rv;
537 
538     if ((argc - curr_arg) < 2) {
539 	/* Not enough parameters */
540 	cmdlang->errstr = "Not enough parameters";
541 	cmdlang->err = EINVAL;
542 	goto out_err;
543     }
544 
545     get_fru_by_name(argv[curr_arg], cmdlang, &area);
546     if (cmdlang->err)
547 	goto out_err;
548     curr_arg++;
549 
550     ipmi_cmdlang_get_int(argv[curr_arg], &offset, cmd_info);
551     if (cmdlang->err) {
552 	cmdlang->errstr = "offset invalid";
553 	goto out_err;
554     }
555 
556     rv = ipmi_fru_area_set_offset(fru, area, offset);
557     if (rv) {
558 	cmdlang->errstr = "Error setting area offset";
559 	cmdlang->err = rv;
560 	goto out_err;
561     }
562 
563     ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
564     ipmi_cmdlang_out(cmd_info, "FRU area offset set", fru_name);
565     return;
566 
567  out_err:
568     ipmi_fru_get_name(fru, cmdlang->objstr,
569 		     cmdlang->objstr_len);
570     cmdlang->location = "cmd_fru.c(fru_area_offset)";
571 }
572 
573 static void
fru_area_length(ipmi_fru_t * fru,void * cb_data)574 fru_area_length(ipmi_fru_t *fru, void *cb_data)
575 {
576     ipmi_cmd_info_t *cmd_info = cb_data;
577     ipmi_cmdlang_t  *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
578     int             curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info);
579     int             argc = ipmi_cmdlang_get_argc(cmd_info);
580     char            **argv = ipmi_cmdlang_get_argv(cmd_info);
581     char            fru_name[IPMI_FRU_NAME_LEN];
582     unsigned int    area;
583     int		    length;
584     int             rv;
585 
586     if ((argc - curr_arg) < 2) {
587 	/* Not enough parameters */
588 	cmdlang->errstr = "Not enough parameters";
589 	cmdlang->err = EINVAL;
590 	goto out_err;
591     }
592 
593     get_fru_by_name(argv[curr_arg], cmdlang, &area);
594     if (cmdlang->err)
595 	goto out_err;
596     curr_arg++;
597 
598     ipmi_cmdlang_get_int(argv[curr_arg], &length, cmd_info);
599     if (cmdlang->err) {
600 	cmdlang->errstr = "length invalid";
601 	goto out_err;
602     }
603 
604     rv = ipmi_fru_area_set_length(fru, area, length);
605     if (rv) {
606 	cmdlang->errstr = "Error setting area length";
607 	cmdlang->err = rv;
608 	goto out_err;
609     }
610 
611     ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
612     ipmi_cmdlang_out(cmd_info, "FRU area length set", fru_name);
613     return;
614 
615  out_err:
616     ipmi_fru_get_name(fru, cmdlang->objstr,
617 		     cmdlang->objstr_len);
618     cmdlang->location = "cmd_fru.c(fru_area_length)";
619 }
620 
621 static void
fru_area_add(ipmi_fru_t * fru,void * cb_data)622 fru_area_add(ipmi_fru_t *fru, void *cb_data)
623 {
624     ipmi_cmd_info_t *cmd_info = cb_data;
625     ipmi_cmdlang_t  *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
626     int             curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info);
627     int             argc = ipmi_cmdlang_get_argc(cmd_info);
628     char            **argv = ipmi_cmdlang_get_argv(cmd_info);
629     char            fru_name[IPMI_FRU_NAME_LEN];
630     unsigned int    area;
631     int		    length, offset;
632     int             rv;
633 
634     if ((argc - curr_arg) < 3) {
635 	/* Not enough parameters */
636 	cmdlang->errstr = "Not enough parameters";
637 	cmdlang->err = EINVAL;
638 	goto out_err;
639     }
640 
641     get_fru_by_name(argv[curr_arg], cmdlang, &area);
642     if (cmdlang->err)
643 	goto out_err;
644     curr_arg++;
645 
646     ipmi_cmdlang_get_int(argv[curr_arg], &offset, cmd_info);
647     if (cmdlang->err) {
648 	cmdlang->errstr = "offset invalid";
649 	goto out_err;
650     }
651     curr_arg++;
652 
653     ipmi_cmdlang_get_int(argv[curr_arg], &length, cmd_info);
654     if (cmdlang->err) {
655 	cmdlang->errstr = "length invalid";
656 	goto out_err;
657     }
658     curr_arg++;
659 
660     rv = ipmi_fru_add_area(fru, area, offset, length);
661     if (rv) {
662 	cmdlang->errstr = "Error adding area";
663 	cmdlang->err = rv;
664 	goto out_err;
665     }
666 
667     ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
668     ipmi_cmdlang_out(cmd_info, "FRU area added", fru_name);
669     return;
670 
671  out_err:
672     ipmi_fru_get_name(fru, cmdlang->objstr,
673 		     cmdlang->objstr_len);
674     cmdlang->location = "cmd_fru.c(fru_area_add)";
675 }
676 
677 static void
fru_area_delete(ipmi_fru_t * fru,void * cb_data)678 fru_area_delete(ipmi_fru_t *fru, void *cb_data)
679 {
680     ipmi_cmd_info_t *cmd_info = cb_data;
681     ipmi_cmdlang_t  *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
682     int             curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info);
683     int             argc = ipmi_cmdlang_get_argc(cmd_info);
684     char            **argv = ipmi_cmdlang_get_argv(cmd_info);
685     char            fru_name[IPMI_FRU_NAME_LEN];
686     unsigned int    area;
687     int             rv;
688 
689     if ((argc - curr_arg) < 1) {
690 	/* Not enough parameters */
691 	cmdlang->errstr = "Not enough parameters";
692 	cmdlang->err = EINVAL;
693 	goto out_err;
694     }
695 
696     get_fru_by_name(argv[curr_arg], cmdlang, &area);
697     if (cmdlang->err)
698 	goto out_err;
699     curr_arg++;
700 
701     rv = ipmi_fru_delete_area(fru, area);
702     if (rv) {
703 	cmdlang->errstr = "Error deleting area";
704 	cmdlang->err = rv;
705 	goto out_err;
706     }
707 
708     ipmi_fru_get_name(fru, fru_name, sizeof(fru_name));
709     ipmi_cmdlang_out(cmd_info, "FRU area deleted", fru_name);
710     return;
711 
712  out_err:
713     ipmi_fru_get_name(fru, cmdlang->objstr,
714 		     cmdlang->objstr_len);
715     cmdlang->location = "cmd_fru.c(fru_area_delete)";
716 }
717 
718 static ipmi_cmdlang_cmd_t *fru_cmds;
719 
720 static ipmi_cmdlang_init_t cmds_fru[] =
721 {
722     { "fru", NULL,
723       "- Commands dealing with FRUs",
724       NULL, NULL, &fru_cmds},
725     { "list", &fru_cmds,
726       "- List all the frus in the system",
727       ipmi_cmdlang_domain_handler, fru_list,  NULL },
728     { "info", &fru_cmds,
729       "<fru> - Dump information about a FRU",
730       ipmi_cmdlang_fru_handler, fru_info, NULL },
731     { "areainfo", &fru_cmds,
732       "<fru> - Dump the info about the FRU's areas",
733       ipmi_cmdlang_fru_handler, fru_areainfo, NULL },
734     { "write", &fru_cmds,
735       "<fru> - Write the local FRU data out into the FRU",
736       ipmi_cmdlang_fru_handler, fru_write, NULL },
737     { "close", &fru_cmds,
738       "<fru> - Delete the FRU",
739       ipmi_cmdlang_fru_handler, fru_close, NULL },
740     { "setval", &fru_cmds,
741       "<fru> <name> [num] value - Set the value of a FRU element.  The"
742       " name is the record name, or multi_record.  The number is required"
743       " for fields that need it (custom and multi-record).  The value is"
744       " an a single value for integers.  For strings it is a string"
745       " type (either binary, ascii, or unicode) and the info.  Binary and"
746       " unicode data is specified as numbers.  ascii data is specified in"
747       " a string.  Note that setting a ascii value with no string will"
748       " clear the value.  Zero length strings and data is valid.  For"
749       " multi_record, the value is <type> <version> [<data> ...]",
750       ipmi_cmdlang_fru_handler, fru_setval, NULL },
751     { "area_offset", &fru_cmds,
752       "<fru> <area name> <offset> - Set the offset of the given area"
753       " to the given value.  Area names are internal_data, chassis_info,"
754       " board_info, product_info, and multi_record",
755       ipmi_cmdlang_fru_handler, fru_area_offset, NULL },
756     { "area_length", &fru_cmds,
757       "<fru> <area name> <length> - Set the length of the given area"
758       " to the given value.  Area names are internal_data, chassis_info,"
759       " board_info, product_info, and multi_record",
760       ipmi_cmdlang_fru_handler, fru_area_length, NULL },
761     { "area_add", &fru_cmds,
762       "<fru> <area name> <offset> <length> - Add the given area to the FRU",
763       ipmi_cmdlang_fru_handler, fru_area_add, NULL },
764     { "area_delete", &fru_cmds,
765       "<fru> <area name> - Delete the given area from the FRU",
766       ipmi_cmdlang_fru_handler, fru_area_delete, NULL },
767 };
768 #define CMDS_FRU_LEN (sizeof(cmds_fru)/sizeof(ipmi_cmdlang_init_t))
769 
770 int
ipmi_cmdlang_fru_init(os_handler_t * os_hnd)771 ipmi_cmdlang_fru_init(os_handler_t *os_hnd)
772 {
773     return ipmi_cmdlang_reg_table(cmds_fru, CMDS_FRU_LEN);
774 }
775