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