xref: /openbmc/ipmitool/src/ipmishell.c (revision 531569ec)
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  */
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 
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
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 
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
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 
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->session->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->session->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->session->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->session->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->session->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 
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