1 /*
2 * Copyright (c) 2003, 2004 Sun Microsystems, Inc. All Rights Reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * Redistribution of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *
11 * Redistribution in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * Neither the name of Sun Microsystems, Inc. or the names of
16 * contributors may be used to endorse or promote products derived
17 * from this software without specific prior written permission.
18 *
19 * This software is provided "AS IS," without a warranty of any kind.
20 * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21 * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22 * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23 * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
24 * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25 * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
26 * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27 * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28 * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29 * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30 * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31 */
32
33 #include <stdio.h>
34 #include <unistd.h>
35 #include <errno.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <ctype.h>
39
40 #include <ipmitool/helper.h>
41 #include <ipmitool/log.h>
42 #include <ipmitool/ipmi.h>
43 #include <ipmitool/ipmi_intf.h>
44 #include <ipmitool/ipmi_session.h>
45 #include <ipmitool/ipmi_main.h>
46
47 #ifdef HAVE_CONFIG_H
48 # include <config.h>
49 #endif
50
51 #define EXEC_BUF_SIZE 2048
52 #define EXEC_ARG_SIZE 64
53 #define MAX_PORT 65535
54
55 extern const struct valstr ipmi_privlvl_vals[];
56 extern const struct valstr ipmi_authtype_session_vals[];
57
58 #ifdef HAVE_READLINE
59
60 /* avoid warnings errors due to non-ANSI type declarations in readline.h */
61 #define _FUNCTION_DEF
62 #define USE_VARARGS
63 #define PREFER_STDARG
64
65 #include <readline/readline.h>
66 #include <readline/history.h>
67 #define RL_PROMPT "ipmitool> "
68 #define RL_TIMEOUT 30
69
70 static struct ipmi_intf * shell_intf;
71
72 /* This function attempts to keep lan sessions active
73 * so they do not time out waiting for user input. The
74 * readline timeout is set to 1 second but lan session
75 * timeout is ~60 seconds.
76 */
rl_event_keepalive(void)77 static int rl_event_keepalive(void)
78 {
79 static int internal_timer = 0;
80
81 if (shell_intf == NULL)
82 return -1;
83 if (shell_intf->keepalive == NULL)
84 return 0;
85 #if defined (RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0402
86 if (internal_timer++ < RL_TIMEOUT)
87 #else
88 /* In readline < 4.2 keyboard timeout hardcoded to 0.1 second */
89 if (internal_timer++ < RL_TIMEOUT * 10)
90 #endif
91 return 0;
92
93 internal_timer = 0;
94 shell_intf->keepalive(shell_intf);
95
96 return 0;
97 }
98
ipmi_shell_main(struct ipmi_intf * intf,int argc,char ** argv)99 int ipmi_shell_main(struct ipmi_intf * intf, int argc, char ** argv)
100 {
101 char *ptr, *pbuf, **ap, *__argv[EXEC_ARG_SIZE];
102 int __argc, rc=0;
103
104 rl_readline_name = "ipmitool";
105
106 /* this essentially disables command completion
107 * until its implemented right, otherwise we get
108 * the current directory contents... */
109 rl_bind_key('\t', rl_insert);
110
111 if (intf->keepalive) {
112 /* hook to keep lan sessions active */
113 shell_intf = intf;
114 rl_event_hook = rl_event_keepalive;
115 #if defined(RL_READLINE_VERSION) && RL_READLINE_VERSION >= 0x0402
116 /* There is a bug in readline 4.2 and later (at least on FreeBSD and NetBSD):
117 * timeout equal or greater than 1 second causes an infinite loop. */
118 rl_set_keyboard_input_timeout(1000 * 1000 - 1);
119 #endif
120 }
121
122 while ((pbuf = (char *)readline(RL_PROMPT)) != NULL) {
123 if (strlen(pbuf) == 0) {
124 free(pbuf);
125 pbuf = NULL;
126 continue;
127 }
128 if (strncmp(pbuf, "quit", 4) == 0 ||
129 strncmp(pbuf, "exit", 4) == 0) {
130 free(pbuf);
131 pbuf = NULL;
132 return 0;
133 }
134 if (strncmp(pbuf, "help", 4) == 0 ||
135 strncmp(pbuf, "?", 1) == 0) {
136 ipmi_cmd_print(intf->cmdlist);
137 free(pbuf);
138 pbuf = NULL;
139 continue;
140 }
141
142 /* for the all-important up arrow :) */
143 add_history(pbuf);
144
145 /* change "" and '' with spaces in the middle to ~ */
146 ptr = pbuf;
147 while (*ptr != '\0') {
148 if (*ptr == '"') {
149 ptr++;
150 while (*ptr != '"' && *ptr != '\0') {
151 if (isspace((int)*ptr))
152 *ptr = '~';
153 ptr++;
154 }
155 }
156 if (*ptr == '\'') {
157 ptr++;
158 while (*ptr != '\'' && *ptr != '\0') {
159 if (isspace((int)*ptr))
160 *ptr = '~';
161 ptr++;
162 }
163 }
164 ptr++;
165 }
166
167 __argc = 0;
168 ap = __argv;
169
170 for (*ap = strtok(pbuf, " \t");
171 *ap != NULL;
172 *ap = strtok(NULL, " \t")) {
173 __argc++;
174
175 ptr = *ap;
176 if (*ptr == '\'') {
177 memmove(ptr, ptr+1, strlen(ptr));
178 while (*ptr != '\'' && *ptr != '\0') {
179 if (*ptr == '~')
180 *ptr = ' ';
181 ptr++;
182 }
183 *ptr = '\0';
184 }
185 if (*ptr == '"') {
186 memmove(ptr, ptr+1, strlen(ptr));
187 while (*ptr != '"' && *ptr != '\0') {
188 if (*ptr == '~')
189 *ptr = ' ';
190 ptr++;
191 }
192 *ptr = '\0';
193 }
194
195 if (**ap != '\0') {
196 if (++ap >= &__argv[EXEC_ARG_SIZE])
197 break;
198 }
199 }
200
201 if (__argc && __argv[0])
202 rc = ipmi_cmd_run(intf,
203 __argv[0],
204 __argc-1,
205 &(__argv[1]));
206
207 free(pbuf);
208 pbuf = NULL;
209 }
210 printf("\n");
211 return rc;
212 }
213
214 #else /* HAVE_READLINE */
215
216 int
ipmi_shell_main(struct ipmi_intf * intf,int argc,char ** argv)217 ipmi_shell_main(struct ipmi_intf * intf, int argc, char ** argv)
218 {
219 lprintf(LOG_ERR, "Compiled without readline, shell is disabled");
220 return -1;
221 }
222
223 #endif /* HAVE_READLINE */
224
ipmi_echo_main(struct ipmi_intf * intf,int argc,char ** argv)225 int ipmi_echo_main(struct ipmi_intf * intf, int argc, char ** argv)
226 {
227 int i;
228
229 for (i=0; i<argc; i++) {
230 printf("%s ", argv[i]);
231 }
232 printf("\n");
233
234 return 0;
235 }
236
237 static void
ipmi_set_usage(void)238 ipmi_set_usage(void)
239 {
240 lprintf(LOG_NOTICE, "Usage: set <option> <value>\n");
241 lprintf(LOG_NOTICE, "Options are:");
242 lprintf(LOG_NOTICE, " hostname <host> Session hostname");
243 lprintf(LOG_NOTICE, " username <user> Session username");
244 lprintf(LOG_NOTICE, " password <pass> Session password");
245 lprintf(LOG_NOTICE, " privlvl <level> Session privilege level force");
246 lprintf(LOG_NOTICE, " authtype <type> Authentication type force");
247 lprintf(LOG_NOTICE, " localaddr <addr> Local IPMB address");
248 lprintf(LOG_NOTICE, " targetaddr <addr> Remote target IPMB address");
249 lprintf(LOG_NOTICE, " port <port> Remote RMCP port");
250 lprintf(LOG_NOTICE, " csv [level] enable output in comma separated format");
251 lprintf(LOG_NOTICE, " verbose [level] Verbose level");
252 lprintf(LOG_NOTICE, "");
253 }
254
ipmi_set_main(struct ipmi_intf * intf,int argc,char ** argv)255 int ipmi_set_main(struct ipmi_intf * intf, int argc, char ** argv)
256 {
257 if (argc == 0 || strncmp(argv[0], "help", 4) == 0) {
258 ipmi_set_usage();
259 return -1;
260 }
261
262 /* these options can have no arguments */
263 if (strncmp(argv[0], "verbose", 7) == 0) {
264 if (argc > 1) {
265 if (str2int(argv[1], &verbose) != 0) {
266 lprintf(LOG_ERR,
267 "Given verbose '%s' argument is invalid.",
268 argv[1]);
269 return (-1);
270 }
271 } else {
272 verbose = verbose + 1;
273 }
274 return 0;
275 }
276 if (strncmp(argv[0], "csv", 3) == 0) {
277 if (argc > 1) {
278 if (str2int(argv[1], &csv_output) != 0) {
279 lprintf(LOG_ERR,
280 "Given csv '%s' argument is invalid.",
281 argv[1]);
282 return (-1);
283 }
284 } else {
285 csv_output = 1;
286 }
287 return 0;
288 }
289
290 /* the rest need an argument */
291 if (argc == 1) {
292 ipmi_set_usage();
293 return -1;
294 }
295
296 if (strncmp(argv[0], "host", 4) == 0 ||
297 strncmp(argv[0], "hostname", 8) == 0) {
298 ipmi_intf_session_set_hostname(intf, argv[1]);
299 if (intf->session == NULL) {
300 lprintf(LOG_ERR, "Failed to set session hostname.");
301 return (-1);
302 }
303 printf("Set session hostname to %s\n",
304 intf->ssn_params.hostname);
305 }
306 else if (strncmp(argv[0], "user", 4) == 0 ||
307 strncmp(argv[0], "username", 8) == 0) {
308 ipmi_intf_session_set_username(intf, argv[1]);
309 if (intf->session == NULL) {
310 lprintf(LOG_ERR, "Failed to set session username.");
311 return (-1);
312 }
313 printf("Set session username to %s\n",
314 intf->ssn_params.username);
315 }
316 else if (strncmp(argv[0], "pass", 4) == 0 ||
317 strncmp(argv[0], "password", 8) == 0) {
318 ipmi_intf_session_set_password(intf, argv[1]);
319 if (intf->session == NULL) {
320 lprintf(LOG_ERR, "Failed to set session password.");
321 return (-1);
322 }
323 printf("Set session password\n");
324 }
325 else if (strncmp(argv[0], "authtype", 8) == 0) {
326 int authtype;
327 authtype = str2val(argv[1], ipmi_authtype_session_vals);
328 if (authtype == 0xFF) {
329 lprintf(LOG_ERR, "Invalid authtype: %s",
330 argv[1]);
331 return (-1);
332 }
333 ipmi_intf_session_set_authtype(intf, authtype);
334 if (intf->session == NULL) {
335 lprintf(LOG_ERR, "Failed to set session authtype.");
336 return (-1);
337 }
338 printf("Set session authtype to %s\n",
339 val2str(intf->ssn_params.authtype_set,
340 ipmi_authtype_session_vals));
341 }
342 else if (strncmp(argv[0], "privlvl", 7) == 0) {
343 int privlvl;
344 privlvl = str2val(argv[1], ipmi_privlvl_vals);
345 if (privlvl == 0xFF) {
346 lprintf(LOG_ERR, "Invalid privilege level: %s",
347 argv[1]);
348 return (-1);
349 }
350 ipmi_intf_session_set_privlvl(intf, privlvl);
351 if (intf->session == NULL) {
352 lprintf(LOG_ERR,
353 "Failed to set session privilege level.");
354 return (-1);
355 }
356 printf("Set session privilege level to %s\n",
357 val2str(intf->ssn_params.privlvl,
358 ipmi_privlvl_vals));
359 }
360 else if (strncmp(argv[0], "port", 4) == 0) {
361 int port = 0;
362 if (str2int(argv[1], &port) != 0 || port > MAX_PORT) {
363 lprintf(LOG_ERR, "Given port '%s' is invalid.",
364 argv[1]);
365 return (-1);
366 }
367 ipmi_intf_session_set_port(intf, port);
368 if (intf->session == NULL) {
369 lprintf(LOG_ERR, "Failed to set session port.");
370 return (-1);
371 }
372 printf("Set session port to %d\n", intf->ssn_params.port);
373 }
374 else if (strncmp(argv[0], "localaddr", 9) == 0) {
375 uint8_t my_addr = 0;
376 if (str2uchar(argv[1], &my_addr) != 0) {
377 lprintf(LOG_ERR, "Given localaddr '%s' is invalid.",
378 argv[1]);
379 return (-1);
380 }
381 intf->my_addr = my_addr;
382 printf("Set local IPMB address to 0x%02x\n", intf->my_addr);
383 }
384 else if (strncmp(argv[0], "targetaddr", 10) == 0) {
385 uint8_t target_addr = 0;
386 if (str2uchar(argv[1], &target_addr) != 0) {
387 lprintf(LOG_ERR, "Given targetaddr '%s' is invalid.",
388 argv[1]);
389 return (-1);
390 }
391 intf->target_addr = target_addr;
392 printf("Set remote IPMB address to 0x%02x\n", intf->target_addr);
393 }
394 else {
395 ipmi_set_usage();
396 return -1;
397 }
398 return 0;
399 }
400
ipmi_exec_main(struct ipmi_intf * intf,int argc,char ** argv)401 int ipmi_exec_main(struct ipmi_intf * intf, int argc, char ** argv)
402 {
403 FILE * fp;
404 char buf[EXEC_BUF_SIZE];
405 char * ptr, * tok, * ret, * tmp;
406 int __argc, i, r;
407 char * __argv[EXEC_ARG_SIZE];
408 int rc=0;
409
410 if (argc < 1) {
411 lprintf(LOG_ERR, "Usage: exec <filename>");
412 return -1;
413 }
414
415 fp = ipmi_open_file_read(argv[0]);
416 if (fp == NULL)
417 return -1;
418
419 while (feof(fp) == 0) {
420 ret = fgets(buf, EXEC_BUF_SIZE, fp);
421 if (ret == NULL)
422 continue;
423
424 /* clip off optional comment tail indicated by # */
425 ptr = strchr(buf, '#');
426 if (ptr)
427 *ptr = '\0';
428 else
429 ptr = buf + strlen(buf);
430
431 /* change "" and '' with spaces in the middle to ~ */
432 ptr = buf;
433 while (*ptr != '\0') {
434 if (*ptr == '"') {
435 ptr++;
436 while (*ptr != '"' && *ptr != '\0') {
437 if (isspace((int)*ptr))
438 *ptr = '~';
439 ptr++;
440 }
441 }
442 if (*ptr == '\'') {
443 ptr++;
444 while (*ptr != '\'' && *ptr != '\0') {
445 if (isspace((int)*ptr))
446 *ptr = '~';
447 ptr++;
448 }
449 }
450 ptr++;
451 }
452
453 /* clip off trailing and leading whitespace */
454 ptr--;
455 while (isspace((int)*ptr) && ptr >= buf)
456 *ptr-- = '\0';
457 ptr = buf;
458 while (isspace((int)*ptr))
459 ptr++;
460 if (strlen(ptr) == 0)
461 continue;
462
463 /* parse it and make argument list */
464 __argc = 0;
465 for (tok = strtok(ptr, " "); tok != NULL; tok = strtok(NULL, " ")) {
466 if (__argc < EXEC_ARG_SIZE) {
467 __argv[__argc++] = strdup(tok);
468 if (__argv[__argc-1] == NULL) {
469 lprintf(LOG_ERR, "ipmitool: malloc failure");
470 if (fp) {
471 fclose(fp);
472 fp = NULL;
473 }
474 return -1;
475 }
476 tmp = __argv[__argc-1];
477 if (*tmp == '\'') {
478 memmove(tmp, tmp+1, strlen(tmp));
479 while (*tmp != '\'' && *tmp != '\0') {
480 if (*tmp == '~')
481 *tmp = ' ';
482 tmp++;
483 }
484 *tmp = '\0';
485 }
486 if (*tmp == '"') {
487 memmove(tmp, tmp+1, strlen(tmp));
488 while (*tmp != '"' && *tmp != '\0') {
489 if (*tmp == '~')
490 *tmp = ' ';
491 tmp++;
492 }
493 *tmp = '\0';
494 }
495 }
496 }
497
498 /* now run the command, save the result if not successful */
499 r = ipmi_cmd_run(intf, __argv[0], __argc-1, &(__argv[1]));
500 if (r != 0)
501 rc = r;
502
503 /* free argument list */
504 for (i=0; i<__argc; i++) {
505 if (__argv[i] != NULL) {
506 free(__argv[i]);
507 __argv[i] = NULL;
508 }
509 }
510 }
511
512 fclose(fp);
513 return rc;
514 }
515