1 /*
2 * ipmish.c
3 *
4 * MontaVista IPMI basic UI to use the main UI code.
5 *
6 * Author: MontaVista Software, Inc.
7 * Corey Minyard <minyard@mvista.com>
8 * source@mvista.com
9 *
10 * Copyright 2002,2003 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 <config.h>
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include <errno.h>
41 #include <termios.h>
42 #include <unistd.h>
43 #include <signal.h>
44 #include <OpenIPMI/selector.h>
45 #include <OpenIPMI/ipmiif.h>
46 #include <OpenIPMI/ipmi_conn.h>
47 #include <OpenIPMI/ipmi_err.h>
48 #include <OpenIPMI/ipmi_posix.h>
49 #include <OpenIPMI/ipmi_glib.h>
50 #include <OpenIPMI/ipmi_tcl.h>
51 #include <OpenIPMI/ipmi_cmdlang.h>
52 #include <OpenIPMI/ipmi_debug.h>
53 #include <readline/readline.h>
54 #include <readline/history.h>
55
56 #ifdef HAVE_GLIB
57 #include <glib.h>
58 #endif
59
60 /* Internal includes, do not use in your programs */
61 #include <OpenIPMI/internal/ipmi_malloc.h>
62
63 #ifdef HAVE_UCDSNMP
64 # ifdef HAVE_NETSNMP
65 # include <net-snmp/net-snmp-config.h>
66 # include <net-snmp/net-snmp-includes.h>
67 # elif defined(HAVE_ALT_UCDSNMP_DIR)
68 # include <ucd-snmp/asn1.h>
69 # include <ucd-snmp/snmp_api.h>
70 # include <ucd-snmp/snmp.h>
71 # else
72 # include <asn1.h>
73 # include <snmp_api.h>
74 # include <snmp.h>
75 # endif
76 #endif
77
78 extern os_handler_t ipmi_debug_os_handlers;
79 struct selector_s *debug_sel;
80
81 os_hnd_fd_id_t *term_fd_id;
82
83 static int done = 0;
84 static int evcount = 0;
85 static int handling_input = 0;
86 static int cmd_redisp = 1;
87 #ifdef HAVE_UCDSNMP
88 static int do_snmp = 0;
89 #endif
90
91 static void user_input_ready(int fd, void *data, os_hnd_fd_id_t *id);
92
93 static void
redraw_cmdline(int force)94 redraw_cmdline(int force)
95 {
96 int redisp = cmd_redisp;
97
98 if (force)
99 redisp = 1;
100 if (!done && handling_input && redisp) {
101 rl_redisplay();
102 fflush(stdout);
103 }
104 }
105
106 static void
my_vlog(os_handler_t * handler,const char * format,enum ipmi_log_type_e log_type,va_list ap)107 my_vlog(os_handler_t *handler,
108 const char *format,
109 enum ipmi_log_type_e log_type,
110 va_list ap)
111 {
112 int do_nl = 1;
113 static int last_was_cont = 0;
114
115 if (handling_input && !last_was_cont && !done && cmd_redisp)
116 fputc('\n', stdout);
117
118 last_was_cont = 0;
119 switch(log_type) {
120 case IPMI_LOG_INFO:
121 printf("INFO: ");
122 break;
123
124 case IPMI_LOG_WARNING:
125 printf("WARN: ");
126 break;
127
128 case IPMI_LOG_SEVERE:
129 printf("SEVR: ");
130 break;
131
132 case IPMI_LOG_FATAL:
133 printf("FATL: ");
134 break;
135
136 case IPMI_LOG_ERR_INFO:
137 printf("EINF: ");
138 break;
139
140 case IPMI_LOG_DEBUG_START:
141 do_nl = 0;
142 last_was_cont = 1;
143 /* FALLTHROUGH */
144 case IPMI_LOG_DEBUG:
145 printf("DEBG: ");
146 break;
147
148 case IPMI_LOG_DEBUG_CONT:
149 last_was_cont = 1;
150 do_nl = 0;
151 /* FALLTHROUGH */
152 case IPMI_LOG_DEBUG_END:
153 break;
154 }
155
156 vprintf(format, ap);
157 if (do_nl) {
158 printf("\n");
159 redraw_cmdline(0);
160 }
161 }
162
163 #ifdef HAVE_GLIB
glib_handle_log(const gchar * log_domain,GLogLevelFlags log_level,const gchar * message,gpointer user_data)164 void glib_handle_log(const gchar *log_domain,
165 GLogLevelFlags log_level,
166 const gchar *message,
167 gpointer user_data)
168 {
169 char *pfx = "";
170
171 if (log_level & G_LOG_LEVEL_ERROR)
172 pfx = "FATL: ";
173 else if (log_level & G_LOG_LEVEL_CRITICAL)
174 pfx = "SEVR: ";
175 else if (log_level & G_LOG_LEVEL_WARNING)
176 pfx = "WARN: ";
177 else if (log_level & G_LOG_LEVEL_MESSAGE)
178 pfx = "EINF: ";
179 else if (log_level & G_LOG_LEVEL_INFO)
180 pfx = "INFO: ";
181 else if (log_level & G_LOG_LEVEL_DEBUG)
182 pfx = "DEBG: ";
183 printf("%s%s\n", pfx, message);
184 redraw_cmdline(0);
185 }
186 #endif
187
188 static void
enable_term_fd(ipmi_cmdlang_t * cmdlang)189 enable_term_fd(ipmi_cmdlang_t *cmdlang)
190 {
191 int rv;
192
193 if (term_fd_id)
194 return;
195
196 rv = cmdlang->os_hnd->add_fd_to_wait_for(cmdlang->os_hnd, 0,
197 user_input_ready,
198 cmdlang,
199 NULL, &term_fd_id);
200 if (rv) {
201 fprintf(stderr, "error enabling terminal handler, giving up\n");
202 exit(1);
203 }
204 }
205
206 static void
disable_term_fd(ipmi_cmdlang_t * cmdlang)207 disable_term_fd(ipmi_cmdlang_t *cmdlang)
208 {
209 int rv;
210
211 if (!term_fd_id)
212 return;
213
214 rv = cmdlang->os_hnd->remove_fd_to_wait_for(cmdlang->os_hnd, term_fd_id);
215 if (rv) {
216 fprintf(stderr, "error removing terminal handler, giving up\n");
217 exit(1);
218 }
219 term_fd_id = NULL;
220 }
221
222 #ifdef HAVE_UCDSNMP
223 #define IPMI_OID_SIZE 9
224 static oid ipmi_oid[IPMI_OID_SIZE] = {1,3,6,1,4,1,3183,1,1};
snmp_input(int op,struct snmp_session * session,int reqid,struct snmp_pdu * pdu,void * magic)225 int snmp_input(int op,
226 struct snmp_session *session,
227 int reqid,
228 struct snmp_pdu *pdu,
229 void *magic)
230 {
231 struct sockaddr_in *src_ip;
232 uint32_t specific;
233 struct variable_list *var;
234
235 #ifdef HAVE_NETSNMP
236 if (op != NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE)
237 goto out;
238 #else
239 if (op != RECEIVED_MESSAGE)
240 goto out;
241 #endif
242 if (pdu->command != SNMP_MSG_TRAP)
243 goto out;
244 if (snmp_oid_compare(ipmi_oid, IPMI_OID_SIZE,
245 pdu->enterprise, pdu->enterprise_length)
246 != 0)
247 {
248 goto out;
249 }
250 if (pdu->trap_type != SNMP_TRAP_ENTERPRISESPECIFIC)
251 goto out;
252
253 src_ip = (struct sockaddr_in *) &pdu->agent_addr;
254 specific = pdu->specific_type;
255
256 var = pdu->variables;
257 if (var == NULL)
258 goto out;
259 if (var->type != ASN_OCTET_STR)
260 goto out;
261 if (snmp_oid_compare(ipmi_oid, IPMI_OID_SIZE, var->name, var->name_length)
262 != 0)
263 {
264 goto out;
265 }
266 if (var->val_len < 46)
267 goto out;
268
269 ipmi_handle_snmp_trap_data(src_ip,
270 sizeof(*src_ip),
271 IPMI_EXTERN_ADDR_IP,
272 specific,
273 var->val.string,
274 var->val_len);
275
276 out:
277 return 1;
278 }
279
280 #ifdef HAVE_NETSNMP
281 static int
snmp_pre_parse(netsnmp_session * session,netsnmp_transport * transport,void * transport_data,int transport_data_length)282 snmp_pre_parse(netsnmp_session * session, netsnmp_transport *transport,
283 void *transport_data, int transport_data_length)
284 {
285 return 1;
286 }
287 #else
288 static int
snmp_pre_parse(struct snmp_session * session,snmp_ipaddr from)289 snmp_pre_parse(struct snmp_session *session, snmp_ipaddr from)
290 {
291 return 1;
292 }
293 #endif
294
295 static struct snmp_session *snmp_session;
296
297 struct snmp_fd_data {
298 int fd;
299 os_hnd_fd_id_t *id;
300 struct snmp_fd_data *next;
301 };
302
303 static struct snmp_fd_data *snmpfd = NULL;
304 os_hnd_timer_id_t *snmp_timer = NULL;
305
306 static void
snmp_check_read_fds(int fd,void * cb_data,os_hnd_fd_id_t * id)307 snmp_check_read_fds(int fd, void *cb_data, os_hnd_fd_id_t *id)
308 {
309 fd_set fdset;
310
311 FD_ZERO(&fdset);
312 FD_SET(fd, &fdset);
313 snmp_read(&fdset);
314 }
315
316 static void
snmp_check_timeout(void * cb_data,os_hnd_timer_id_t * id)317 snmp_check_timeout(void *cb_data, os_hnd_timer_id_t *id)
318 {
319 snmp_timeout();
320 }
321
322 static void
snmp_setup_fds(os_handler_t * os_hnd)323 snmp_setup_fds(os_handler_t *os_hnd)
324 {
325 int nfds = 0, block = 0, i, rv;
326 fd_set fdset;
327 struct timeval tv;
328 struct snmp_fd_data *fdd, *nfdd, *prev = NULL;
329
330 if (!do_snmp)
331 return;
332
333 FD_ZERO(&fdset);
334 tv.tv_sec = 0;
335 tv.tv_usec = 0;
336 snmp_select_info(&nfds, &fdset, &tv, &block);
337
338 /* Run through the list. Since the list is kept sorted, we only
339 need one pass. */
340 fdd = snmpfd;
341 for (i = 0; i < nfds; i++) {
342 if (!FD_ISSET(i, &fdset))
343 continue;
344
345 if (fdd) {
346 if (fdd->fd == i) {
347 /* Didn't change. */
348 prev = fdd;
349 fdd = fdd->next;
350 continue;
351 }
352 if (fdd->fd < i) {
353 /* Current one was deleted. */
354 os_hnd->remove_fd_to_wait_for(os_hnd, fdd->id);
355 if (prev)
356 prev->next = fdd->next;
357 else
358 snmpfd = fdd->next;
359 os_hnd->mem_free(fdd);
360 continue;
361 }
362 }
363
364 /* New one to add. */
365 nfdd = os_hnd->mem_alloc(sizeof(*fdd));
366 if (!nfdd) {
367 rv = ENOMEM;
368 goto err;
369 }
370 nfdd->fd = i;
371 rv = os_hnd->add_fd_to_wait_for(os_hnd, i, snmp_check_read_fds,
372 NULL, NULL, &nfdd->id);
373 if (rv)
374 goto err;
375
376 /* Insert after */
377 if (fdd) {
378 nfdd->next = fdd->next;
379 fdd->next = nfdd;
380 } else {
381 nfdd->next = NULL;
382 snmpfd = fdd;
383 }
384 }
385
386 if (!block) {
387 os_hnd->stop_timer(os_hnd, snmp_timer);
388 } else {
389 os_hnd->stop_timer(os_hnd, snmp_timer);
390 os_hnd->start_timer(os_hnd, snmp_timer, &tv, snmp_check_timeout, NULL);
391 }
392 return;
393
394 err:
395 fprintf(stderr, "Error handling SNMP fd data: %s\n", strerror(rv));
396 exit(1);
397 }
398
399 static int
snmp_init(os_handler_t * os_hnd)400 snmp_init(os_handler_t *os_hnd)
401 {
402 struct snmp_session session;
403 #ifdef HAVE_NETSNMP
404 netsnmp_transport *transport = NULL;
405 static char *snmp_default_port = "udp:162";
406 int rv;
407
408 rv = os_hnd->alloc_timer(os_hnd, &snmp_timer);
409 if (rv) {
410 fprintf(stderr, "Could not allocate SNMP timer\n");
411 return -1;
412 }
413
414 netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID,
415 NETSNMP_DS_LIB_MIB_ERRORS,
416 0);
417
418 init_snmp("ipmish");
419
420 transport = netsnmp_tdomain_transport(snmp_default_port, 1, "udp");
421 if (!transport) {
422 snmp_sess_perror("ipmish", &session);
423 return -1;
424 }
425 #else
426 void *transport = NULL;
427 #endif
428 snmp_sess_init(&session);
429 session.peername = SNMP_DEFAULT_PEERNAME;
430 session.version = SNMP_DEFAULT_VERSION;
431 session.community_len = SNMP_DEFAULT_COMMUNITY_LEN;
432 session.retries = SNMP_DEFAULT_RETRIES;
433 session.timeout = SNMP_DEFAULT_TIMEOUT;
434 session.local_port = SNMP_TRAP_PORT;
435 session.callback = snmp_input;
436 session.callback_magic = transport;
437 session.authenticator = NULL;
438 session.isAuthoritative = SNMP_SESS_UNKNOWNAUTH;
439
440 #ifdef HAVE_NETSNMP
441 snmp_session = snmp_add(&session, transport, snmp_pre_parse, NULL);
442 #else
443 snmp_session = snmp_open_ex(&session, snmp_pre_parse,
444 NULL, NULL, NULL, NULL);
445 #endif
446 if (snmp_session == NULL) {
447 snmp_sess_perror("ipmish", &session);
448 return -1;
449 }
450
451 return 0;
452 }
453 #else
snmp_setup_fds(os_handler_t * os_hnd)454 static void snmp_setup_fds(os_handler_t *os_hnd) { }
455 #endif /* HAVE_UCDSNMP */
456
457 typedef struct out_data_s
458 {
459 FILE *stream;
460 int indent;
461 } out_data_t;
462
463 static int columns = 80;
464
465 static void
out_help(FILE * s,int indent,const char * name,const char * v)466 out_help(FILE *s, int indent, const char *name, const char *v)
467 {
468 int pos, endpos;
469 const char *endword;
470 const char *endspace;
471
472 pos = fprintf(s, "%*s%s ", indent, "", name);
473 while (*v) {
474 endword = v;
475 while (isspace(*endword)) {
476 if (*endword == '\n') {
477 v = endword + 1;
478 fprintf(s, "\n%*s", indent+2, "");
479 pos = indent + 2;
480 }
481 endword++;
482 }
483 endspace = endword;
484 while (*endword && !isspace(*endword))
485 endword++;
486 endpos = pos + endword - v;
487 if (endpos > columns) {
488 v = endspace;
489 fprintf(s, "\n%*s", indent+2, "");
490 pos = indent + 2;
491 }
492 fwrite(v, 1, endword-v, s);
493 pos += endword - v;
494 v = endword;
495 }
496 fputc('\n', s);
497 }
498
499 static void
out_value(ipmi_cmdlang_t * info,const char * name,const char * value)500 out_value(ipmi_cmdlang_t *info, const char *name, const char *value)
501 {
502 out_data_t *out_data = info->user_data;
503
504 if (value) {
505 if (info->help) {
506 out_help(out_data->stream, out_data->indent*2, name, value);
507 } else {
508 fprintf(out_data->stream, "%*s%s: %s\n", out_data->indent*2, "",
509 name, value);
510 }
511 } else
512 fprintf(out_data->stream, "%*s%s\n", out_data->indent*2, "", name);
513 fflush(out_data->stream);
514 }
515
516 static void
out_binary(ipmi_cmdlang_t * info,const char * name,const char * value,unsigned int len)517 out_binary(ipmi_cmdlang_t *info, const char *name, const char *value,
518 unsigned int len)
519 {
520 out_data_t *out_data = info->user_data;
521 unsigned char *data = (unsigned char *) value;
522 int indent2 = (out_data->indent * 2) + strlen(name) + 1;
523 unsigned int i;
524 char *sep = ":";
525
526 if (info->help)
527 sep = "";
528
529 fprintf(out_data->stream, "%*s%s%s", out_data->indent*2, "", name, sep);
530 for (i=0; i<len; i++) {
531 if ((i != 0) && ((i % 8) == 0))
532 fprintf(out_data->stream, "\n%*s", indent2, "");
533 fprintf(out_data->stream, " 0x%2.2x", (data[i] & 0xff));
534 }
535 fprintf(out_data->stream, "\n");
536
537 fflush(out_data->stream);
538 }
539
540 static void
out_unicode(ipmi_cmdlang_t * info,const char * name,const char * value,unsigned int len)541 out_unicode(ipmi_cmdlang_t *info, const char *name, const char *value,
542 unsigned int len)
543 {
544 out_binary(info, name, value, len);
545 }
546
547 static void
down_level(ipmi_cmdlang_t * info)548 down_level(ipmi_cmdlang_t *info)
549 {
550 out_data_t *out_data = info->user_data;
551
552 out_data->indent++;
553 }
554
555 static void
up_level(ipmi_cmdlang_t * info)556 up_level(ipmi_cmdlang_t *info)
557 {
558 out_data_t *out_data = info->user_data;
559
560 out_data->indent--;
561 }
562
563 static void cmd_done(ipmi_cmdlang_t *info);
564
565 static out_data_t lout_data =
566 {
567 .stream = NULL,
568 .indent = 0,
569 };
570 static char cmdlang_objstr[IPMI_MAX_NAME_LEN];
571 static ipmi_cmdlang_t cmdlang =
572 {
573 .out = out_value,
574 .out_binary = out_binary,
575 .out_unicode = out_unicode,
576 .down = down_level,
577 .up = up_level,
578 .done = cmd_done,
579
580 .os_hnd = NULL,
581
582 .user_data = &lout_data,
583
584 .objstr = cmdlang_objstr,
585 .objstr_len = sizeof(cmdlang_objstr),
586 };
587
588 int *done_ptr = NULL;
589
590 static void
cmd_done(ipmi_cmdlang_t * info)591 cmd_done(ipmi_cmdlang_t *info)
592 {
593 out_data_t *out_data = info->user_data;
594
595 if (info->err) {
596 char errval[128];
597 if (!info->location)
598 info->location = "";
599 if (strlen(info->objstr) == 0) {
600 fprintf(out_data->stream, "error: %s: %s (0x%x, %s)\n",
601 info->location, info->errstr,
602 info->err,
603 ipmi_get_error_string(info->err, errval, sizeof(errval)));
604 } else {
605 fprintf(out_data->stream, "error: %s %s: %s (0x%x, %s)\n",
606 info->location, info->objstr, info->errstr,
607 info->err,
608 ipmi_get_error_string(info->err, errval, sizeof(errval)));
609 }
610 if (info->errstr_dynalloc)
611 ipmi_mem_free(info->errstr);
612 info->errstr_dynalloc = 0;
613 info->errstr = NULL;
614 info->location = NULL;
615 info->objstr[0] = '\0';
616 info->err = 0;
617 }
618
619 if (done_ptr) {
620 *done_ptr = 1;
621 } else {
622 handling_input = 1;
623 redraw_cmdline(1);
624 enable_term_fd(info);
625 fflush(out_data->stream);
626 }
627 }
628
629 void
ipmi_cmdlang_global_err(char * objstr,char * location,char * errstr,int errval)630 ipmi_cmdlang_global_err(char *objstr,
631 char *location,
632 char *errstr,
633 int errval)
634 {
635 if (handling_input && !done && cmd_redisp)
636 fputc('\n', stdout);
637 if (objstr)
638 fprintf(stderr, "global error: %s %s: %s (0x%x)", location, objstr,
639 errstr, errval);
640 else
641 fprintf(stderr, "global error: %s: %s (0x%x)", location,
642 errstr, errval);
643 evcount = 0;
644 redraw_cmdline(0);
645 }
646
647 void
ipmi_cmdlang_report_event(ipmi_cmdlang_event_t * event)648 ipmi_cmdlang_report_event(ipmi_cmdlang_event_t *event)
649 {
650 unsigned int level, len;
651 enum ipmi_cmdlang_out_types type;
652 char *name, *value;
653 int indent2;
654 unsigned int i;
655
656 if (handling_input && !done && cmd_redisp)
657 fputc('\n', stdout);
658 ipmi_cmdlang_event_restart(event);
659 printf("Event\n");
660 while (ipmi_cmdlang_event_next_field(event, &level, &type, &name, &len,
661 &value))
662 {
663 switch (type) {
664 case IPMI_CMDLANG_STRING:
665 if (value)
666 printf(" %*s%s: %s\n", level*2, "", name, value);
667 else
668 printf(" %*s%s\n", level*2, "", name);
669 break;
670
671 case IPMI_CMDLANG_BINARY:
672 case IPMI_CMDLANG_UNICODE:
673 indent2 = (level * 2) + strlen(name) + 1;
674 printf(" %*s%s:", level*2, "", name);
675 for (i=0; i<len; i++) {
676 if ((i != 0) && ((i % 8) == 0))
677 printf("\n %*s", indent2, "");
678 printf(" 0x%2.2x", value[i] & 0xff);
679 }
680 printf("\n");
681
682 fflush(stdout);
683 break;
684 }
685 }
686 evcount = 0;
687 redraw_cmdline(0);
688 }
689
690 static void
user_input_ready(int fd,void * data,os_hnd_fd_id_t * id)691 user_input_ready(int fd, void *data, os_hnd_fd_id_t *id)
692 {
693 rl_callback_read_char();
694 }
695
696 static void
rl_ipmish_cb_handler(char * cmdline)697 rl_ipmish_cb_handler(char *cmdline)
698 {
699 char *expansion = NULL;
700 int result;
701
702 if (cmdline == NULL) {
703 done = 1;
704 evcount = 1; /* Force a newline */
705 return;
706 }
707 result = history_expand(cmdline, &expansion);
708 if (result < 0 || result == 2) {
709 fprintf(stderr, "%s\n", expansion);
710 } else if (expansion && strlen(expansion)){
711 cmdlang.err = 0;
712 cmdlang.errstr = NULL;
713 cmdlang.errstr_dynalloc = 0;
714 cmdlang.location = NULL;
715 handling_input = 0;
716 add_history(expansion);
717 ipmi_cmdlang_handle(&cmdlang, expansion);
718 }
719 if (expansion)
720 free(expansion);
721 }
722
723 static void
cleanup_term(void)724 cleanup_term(void)
725 {
726 rl_callback_handler_remove();
727 disable_term_fd(&cmdlang);
728 }
729
730 static void cleanup_sig(int sig);
731
732 static void
setup_term(os_handler_t * os_hnd)733 setup_term(os_handler_t *os_hnd)
734 {
735 signal(SIGINT, cleanup_sig);
736 signal(SIGPIPE, cleanup_sig);
737 signal(SIGUSR1, cleanup_sig);
738 signal(SIGUSR2, cleanup_sig);
739 #ifdef SIGPWR
740 signal(SIGPWR, cleanup_sig);
741 #endif
742
743 stifle_history(500);
744 rl_callback_handler_install("> ", rl_ipmish_cb_handler);
745 lout_data.stream = stdout;
746
747 cmdlang.os_hnd = os_hnd;
748 }
749
750 static void
redisp_cmd(ipmi_cmd_info_t * cmd_info)751 redisp_cmd(ipmi_cmd_info_t *cmd_info)
752 {
753 ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
754 int curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info);
755 int argc = ipmi_cmdlang_get_argc(cmd_info);
756 char **argv = ipmi_cmdlang_get_argv(cmd_info);
757 int redisp;
758
759 if ((argc - curr_arg) < 1) {
760 /* Not enough parameters */
761 cmdlang->errstr = "Not enough parameters";
762 cmdlang->err = EINVAL;
763 goto out_err;
764 }
765
766 ipmi_cmdlang_get_bool(argv[curr_arg], &redisp, cmd_info);
767 if (cmdlang->err) {
768 cmdlang->errstr = "redisp setting invalid";
769 goto out_err;
770 }
771 curr_arg++;
772
773 cmd_redisp = redisp;
774
775 ipmi_cmdlang_out(cmd_info, "redisp set", NULL);
776
777 out_err:
778 cmdlang->location = "ipmish.c(redisp_cmd)";
779 }
780
781 static void
exit_cmd(ipmi_cmd_info_t * cmd_info)782 exit_cmd(ipmi_cmd_info_t *cmd_info)
783 {
784 done = 1;
785 evcount = 0;
786 ipmi_cmdlang_out(cmd_info, "Exiting ipmish", NULL);
787 }
788
789 static int read_nest = 0;
790 static void
read_cmd(ipmi_cmd_info_t * cmd_info)791 read_cmd(ipmi_cmd_info_t *cmd_info)
792 {
793 ipmi_cmdlang_t *cmdlang = ipmi_cmdinfo_get_cmdlang(cmd_info);
794 int cdone;
795 char cmdline[256];
796 FILE *s;
797 out_data_t my_out_data;
798 ipmi_cmdlang_t my_cmdlang = *cmdlang;
799 int curr_arg = ipmi_cmdlang_get_curr_arg(cmd_info);
800 int argc = ipmi_cmdlang_get_argc(cmd_info);
801 char **argv = ipmi_cmdlang_get_argv(cmd_info);
802 int *saved_done_ptr;
803 char *fname;
804
805 if ((argc - curr_arg) < 1) {
806 cmdlang->errstr = "No filename entered";
807 cmdlang->err = EINVAL;
808 goto out_err;
809 }
810
811 fname = argv[curr_arg];
812 curr_arg++;
813 s = fopen(fname, "r");
814 if (!s) {
815 cmdlang->errstr = "Unable to openfile";
816 cmdlang->err = errno;
817 goto out_err;
818 }
819
820 if (!read_nest) {
821 handling_input = 0;
822 disable_term_fd(cmdlang);
823 }
824 read_nest++;
825 saved_done_ptr = done_ptr;
826
827 /* not record the file's commands into history */
828 while (fgets(cmdline, sizeof(cmdline), s)) {
829 my_out_data.stream = stdout;
830 my_out_data.indent = 0;
831 my_cmdlang.user_data = &my_out_data;
832 cdone = 0;
833 done_ptr = &cdone;
834 printf("> %s", cmdline);
835 fflush(stdout);
836 ipmi_cmdlang_handle(&my_cmdlang, cmdline);
837 while (!cdone) {
838 snmp_setup_fds(cmdlang->os_hnd);
839 cmdlang->os_hnd->perform_one_op(cmdlang->os_hnd, NULL);
840 }
841 done_ptr = NULL;
842 }
843 fclose(s);
844
845 done_ptr = saved_done_ptr;
846 read_nest--;
847 if (!read_nest) {
848 handling_input = 1;
849 enable_term_fd(cmdlang);
850 }
851
852 ipmi_cmdlang_out(cmd_info, "File read", fname);
853
854 return;
855
856 out_err:
857 cmdlang->location = "ipmish.c(read_cmd)";
858 }
859
860 static void
setup_cmds(void)861 setup_cmds(void)
862 {
863 int rv;
864
865 rv = ipmi_cmdlang_reg_cmd(NULL,
866 "redisp_cmd",
867 "on|off - If an asynchronous event comes in,"
868 " redisplay the current working command. This"
869 " is on by default.",
870 redisp_cmd, NULL, NULL, NULL);
871 if (rv) {
872 fprintf(stderr, "Error adding exit command: 0x%x\n", rv);
873 exit(1);
874 }
875
876 rv = ipmi_cmdlang_reg_cmd(NULL,
877 "exit",
878 "- leave the program",
879 exit_cmd, NULL, NULL, NULL);
880 if (rv) {
881 fprintf(stderr, "Error adding exit command: 0x%x\n", rv);
882 exit(1);
883 }
884
885 rv = ipmi_cmdlang_reg_cmd(NULL,
886 "read",
887 "<file> - Read commands from the file and"
888 " execute them",
889 read_cmd, NULL, NULL, NULL);
890 if (rv) {
891 fprintf(stderr, "Error adding read command: 0x%x\n", rv);
892 exit(1);
893 }
894 }
895
896 static void
domain_down(void * cb_data)897 domain_down(void *cb_data)
898 {
899 int *count = cb_data;
900 (*count)--;
901 }
902
903 static void
shutdown_domain_handler(ipmi_domain_t * domain,void * cb_data)904 shutdown_domain_handler(ipmi_domain_t *domain, void *cb_data)
905 {
906 int *count = cb_data;
907 int rv;
908
909 rv = ipmi_domain_close(domain, domain_down, cb_data);
910 if (!rv)
911 (*count)++;
912 }
913
914 static void
cleanup_sig(int sig)915 cleanup_sig(int sig)
916 {
917 fprintf(stderr, "Exiting due to signal %d\n", sig);
918 done = 0;
919 ipmi_domain_iterate_domains(shutdown_domain_handler, &done);
920 while (done) {
921 snmp_setup_fds(cmdlang.os_hnd);
922 cmdlang.os_hnd->perform_one_op(cmdlang.os_hnd, NULL);
923 }
924 cleanup_term();
925 exit(1);
926 }
927
928 typedef struct exec_list_s
929 {
930 char *str;
931 struct exec_list_s *next;
932 } exec_list_t;
933 static exec_list_t *execs, *execs_tail;
934
935 static void
add_exec_str(char * str)936 add_exec_str(char *str)
937 {
938 exec_list_t *e;
939
940 e = malloc(sizeof(*e));
941 if (!e) {
942 fprintf(stderr, "Out of memory");
943 exit(1);
944 }
945 e->str = str;
946 e->next = NULL;
947 if (execs)
948 execs_tail->next = e;
949 else
950 execs = e;
951 execs_tail = e;
952 }
953
954 static char *usage_str =
955 "%s is a program that gives access to the OpenIPMI library from a command\n"
956 "line. It is designed to be script driven. Format is:\n"
957 " %s [options]\n"
958 "Options are:\n"
959 " --execute <string> - execute the given string at startup. This may be\n"
960 " entered multiple times for multiple commands.\n"
961 " -x <string> - same as --execute\n"
962 " --dlock - turn on lock debugging.\n"
963 " --dmem - turn on memory debugging.\n"
964 " --drawmsg - turn on raw message tracing.\n"
965 " --dmsg - turn on message tracing debugging.\n"
966 " --dmsgerr - turn on printing out low-level message errors.\n"
967 #ifdef HAVE_GLIB
968 " --glib - use glib for the OS handler.\n"
969 #endif
970 #ifdef HAVE_TCL
971 " --tcl - use tcl for the OS handler.\n"
972 #endif
973 #ifdef HAVE_UCDSNMP
974 " --snmp - turn on SNMP trap handling.\n"
975 #endif
976 " --help - This output.\n"
977 ;
usage(char * name)978 static void usage(char *name)
979 {
980 fprintf(stderr, usage_str, name, name);
981 }
982
983 int
main(int argc,char * argv[])984 main(int argc, char *argv[])
985 {
986 int rv;
987 int curr_arg = 1;
988 const char *arg;
989 os_handler_t *os_hnd;
990 int use_debug_os = 0;
991 char *colstr;
992 #ifdef HAVE_GLIB
993 int use_glib = 0;
994 #endif
995 #ifdef HAVE_TCL
996 int use_tcl = 0;
997 #endif
998
999 colstr = getenv("COLUMNS");
1000 if (colstr) {
1001 int tmp = strtoul(colstr, NULL, 0);
1002 if (tmp)
1003 columns = tmp;
1004 }
1005
1006 while ((curr_arg < argc) && (argv[curr_arg][0] == '-')) {
1007 arg = argv[curr_arg];
1008 curr_arg++;
1009 if (strcmp(arg, "--") == 0) {
1010 break;
1011 } else if ((strcmp(arg, "-x") == 0) || (strcmp(arg, "--execute") == 0))
1012 {
1013 if (curr_arg >= argc) {
1014 fprintf(stderr, "No option given for %s", arg);
1015 usage(argv[0]);
1016 return 1;
1017 }
1018 add_exec_str(argv[curr_arg]);
1019 curr_arg++;
1020 } else if (strcmp(arg, "--dlock") == 0) {
1021 DEBUG_LOCKS_ENABLE();
1022 use_debug_os = 1;
1023 } else if (strcmp(arg, "--dmem") == 0) {
1024 DEBUG_MALLOC_ENABLE();
1025 } else if (strcmp(arg, "--drawmsg") == 0) {
1026 DEBUG_RAWMSG_ENABLE();
1027 } else if (strcmp(arg, "--dmsg") == 0) {
1028 DEBUG_MSG_ENABLE();
1029 } else if (strcmp(arg, "--dmsgerr") == 0) {
1030 DEBUG_MSG_ERR_ENABLE();
1031 #ifdef HAVE_UCDSNMP
1032 } else if (strcmp(arg, "--snmp") == 0) {
1033 do_snmp = 1;
1034 #endif
1035 #ifdef HAVE_GLIB
1036 } else if (strcmp(arg, "--glib") == 0) {
1037 use_glib = 1;
1038 #endif
1039 #ifdef HAVE_TCL
1040 } else if (strcmp(arg, "--tcl") == 0) {
1041 use_tcl = 1;
1042 #endif
1043 } else if (strcmp(arg, "--help") == 0) {
1044 usage(argv[0]);
1045 return 0;
1046 } else {
1047 fprintf(stderr, "Unknown option: %s\n", arg);
1048 usage(argv[0]);
1049 return 1;
1050 }
1051 }
1052
1053 rl_initialize();
1054
1055 if (use_debug_os) {
1056 os_hnd = &ipmi_debug_os_handlers;
1057 rv = sel_alloc_selector_nothread(&debug_sel);
1058 if (rv) {
1059 fprintf(stderr, "Could not allocate selector\n");
1060 return 1;
1061 }
1062 #ifdef HAVE_GLIB
1063 } else if (use_glib) {
1064 g_thread_init(NULL);
1065 os_hnd = ipmi_glib_get_os_handler(0);
1066 if (!os_hnd) {
1067 fprintf(stderr,
1068 "ipmi_smi_setup_con: Unable to allocate os handler\n");
1069 return 1;
1070 }
1071 g_log_set_handler("OpenIPMI",
1072 G_LOG_LEVEL_ERROR
1073 | G_LOG_LEVEL_CRITICAL
1074 | G_LOG_LEVEL_WARNING
1075 | G_LOG_LEVEL_MESSAGE
1076 | G_LOG_LEVEL_INFO
1077 | G_LOG_LEVEL_DEBUG
1078 | G_LOG_FLAG_FATAL,
1079 glib_handle_log,
1080 NULL);
1081 #endif
1082 #ifdef HAVE_TCL
1083 } else if (use_tcl) {
1084 os_hnd = ipmi_tcl_get_os_handler(0);
1085 if (!os_hnd) {
1086 fprintf(stderr,
1087 "ipmi_smi_setup_con: Unable to allocate os handler\n");
1088 return 1;
1089 }
1090 #endif
1091 } else {
1092 os_hnd = ipmi_posix_setup_os_handler();
1093 if (!os_hnd) {
1094 fprintf(stderr,
1095 "ipmi_smi_setup_con: Unable to allocate os handler\n");
1096 return 1;
1097 }
1098 }
1099
1100 os_hnd->set_log_handler(os_hnd, my_vlog);
1101
1102 /* Initialize the OpenIPMI library. */
1103 ipmi_init(os_hnd);
1104
1105 #ifdef HAVE_UCDSNMP
1106 if (do_snmp) {
1107 if (snmp_init(os_hnd) < 0)
1108 return 1;
1109 }
1110 #endif
1111
1112 rv = ipmi_cmdlang_init(os_hnd);
1113 if (rv) {
1114 fprintf(stderr, "Unable to initialize command processor: 0x%x\n", rv);
1115 return 1;
1116 }
1117
1118 setup_cmds();
1119
1120 setup_term(os_hnd);
1121
1122 while (execs) {
1123 exec_list_t *e = execs;
1124 int cdone = 0;
1125 read_nest = 1;
1126 execs = e->next;
1127 printf("> %s\n", e->str);
1128 fflush(stdout);
1129 done_ptr = &cdone;
1130 rl_ipmish_cb_handler(e->str);
1131 while (!cdone) {
1132 snmp_setup_fds(os_hnd);
1133 os_hnd->perform_one_op(os_hnd, NULL);
1134 }
1135 done_ptr = NULL;
1136 free(e);
1137 read_nest = 0;
1138 }
1139
1140 fflush(stdout);
1141
1142 handling_input = 1;
1143 enable_term_fd(&cmdlang);
1144
1145 while (!done) {
1146 snmp_setup_fds(os_hnd);
1147 os_hnd->perform_one_op(os_hnd, NULL);
1148 }
1149
1150 cleanup_term();
1151
1152 /* Shut down all existing domains. */
1153
1154 done = 0;
1155 ipmi_domain_iterate_domains(shutdown_domain_handler, &done);
1156 while (done) {
1157 snmp_setup_fds(os_hnd);
1158 os_hnd->perform_one_op(os_hnd, NULL);
1159 }
1160
1161 ipmi_cmdlang_cleanup();
1162 ipmi_shutdown();
1163
1164 ipmi_debug_malloc_cleanup();
1165
1166 os_hnd->free_os_handler(os_hnd);
1167
1168 /* remove the prompt which editline printed */
1169 printf("\b\b \b\b");
1170 if (evcount)
1171 printf("\n");
1172 fflush(stdout);
1173
1174 if (rv)
1175 return 1;
1176 return 0;
1177 }
1178