1 /* $OpenBSD: cmd.c,v 1.62 2014/06/27 20:35:37 tobias Exp $ */ 2 3 /* 4 * Copyright (c) 1997-1999 Michael Shalayeff 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/param.h> 30 #include <sys/reboot.h> 31 32 #include <libsa.h> 33 #include <lib/libkern/funcs.h> 34 35 #include "cmd.h" 36 37 #define CTRL(c) ((c)&0x1f) 38 39 static int Xboot(void); 40 static int Xecho(void); 41 static int Xhelp(void); 42 static int Xls(void); 43 static int Xnop(void); 44 static int Xreboot(void); 45 static int Xstty(void); 46 static int Xtime(void); 47 #ifdef MACHINE_CMD 48 static int Xmachine(void); 49 extern const struct cmd_table MACHINE_CMD[]; 50 #endif 51 extern int Xset(void); 52 extern int Xenv(void); 53 54 #ifdef CHECK_SKIP_CONF 55 extern int CHECK_SKIP_CONF(void); 56 #endif 57 58 extern const struct cmd_table cmd_set[]; 59 const struct cmd_table cmd_table[] = { 60 {"#", CMDT_CMD, Xnop}, /* XXX must be first */ 61 {"boot", CMDT_CMD, Xboot}, 62 {"echo", CMDT_CMD, Xecho}, 63 {"env", CMDT_CMD, Xenv}, 64 {"help", CMDT_CMD, Xhelp}, 65 {"ls", CMDT_CMD, Xls}, 66 #ifdef MACHINE_CMD 67 {"machine",CMDT_MDC, Xmachine}, 68 #endif 69 {"reboot", CMDT_CMD, Xreboot}, 70 {"set", CMDT_SET, Xset}, 71 {"stty", CMDT_CMD, Xstty}, 72 {"time", CMDT_CMD, Xtime}, 73 {NULL, 0}, 74 }; 75 76 static void ls(char *, struct stat *); 77 static int readline(char *, size_t, int); 78 char *nextword(char *); 79 static char *whatcmd(const struct cmd_table **ct, char *); 80 static char *qualify(char *); 81 82 char cmd_buf[CMD_BUFF_SIZE]; 83 84 int 85 getcmd(void) 86 { 87 cmd.cmd = NULL; 88 89 if (!readline(cmd_buf, sizeof(cmd_buf), cmd.timeout)) 90 cmd.cmd = cmd_table; 91 92 return docmd(); 93 } 94 95 int 96 read_conf(void) 97 { 98 #ifndef INSECURE 99 struct stat sb; 100 #endif 101 int fd, rc = 0; 102 103 #ifdef CHECK_SKIP_CONF 104 if (CHECK_SKIP_CONF()) { 105 printf("boot.conf processing skipped at operator request\n"); 106 cmd.timeout = 0; 107 return -1; /* Pretend file wasn't found */ 108 } 109 #endif 110 111 if ((fd = open(qualify(cmd.conf), 0)) < 0) { 112 if (errno != ENOENT && errno != ENXIO) { 113 printf("open(%s): %s\n", cmd.path, strerror(errno)); 114 return 0; 115 } 116 return -1; 117 } 118 119 #ifndef INSECURE 120 (void) fstat(fd, &sb); 121 if (sb.st_uid || (sb.st_mode & 2)) { 122 printf("non-secure %s, will not proceed\n", cmd.path); 123 close(fd); 124 return -1; 125 } 126 #endif 127 128 do { 129 char *p = cmd_buf; 130 131 cmd.cmd = NULL; 132 133 do { 134 rc = read(fd, p, 1); 135 } while (rc > 0 && *p++ != '\n' && 136 (p-cmd_buf) < sizeof(cmd_buf)); 137 138 if (rc < 0) { /* Error from read() */ 139 printf("%s: %s\n", cmd.path, strerror(errno)); 140 break; 141 } 142 143 if (rc == 0) { /* eof from read() */ 144 if (p != cmd_buf) { /* Line w/o trailing \n */ 145 *p = '\0'; 146 rc = docmd(); 147 break; 148 } 149 } else { /* rc > 0, read a char */ 150 p--; /* Get back to last character */ 151 152 if (*p != '\n') { /* Line was too long */ 153 printf("%s: line too long\n", cmd.path); 154 155 /* Don't want to run the truncated command */ 156 rc = -1; 157 } 158 159 *p = '\0'; 160 } 161 162 } while (rc > 0 && !(rc = docmd())); 163 164 close(fd); 165 return rc; 166 } 167 168 int 169 docmd(void) 170 { 171 char *p = NULL; 172 const struct cmd_table *ct = cmd_table, *cs; 173 174 cmd.argc = 1; 175 if (cmd.cmd == NULL) { 176 177 /* command */ 178 for (p = cmd_buf; *p == ' ' || *p == '\t'; p++) 179 ; 180 if (*p == '#' || *p == '\0') { /* comment or empty string */ 181 #ifdef DEBUG 182 printf("rem\n"); 183 #endif 184 return 0; 185 } 186 ct = cmd_table; 187 cs = NULL; 188 cmd.argv[cmd.argc] = p; /* in case it's shortcut boot */ 189 p = whatcmd(&ct, p); 190 if (ct == NULL) { 191 cmd.argc++; 192 ct = cmd_table; 193 } else if (ct->cmd_type == CMDT_SET && p != NULL) { 194 cs = cmd_set; 195 #ifdef MACHINE_CMD 196 } else if (ct->cmd_type == CMDT_MDC && p != NULL) { 197 cs = MACHINE_CMD; 198 #endif 199 } 200 201 if (cs != NULL) { 202 p = whatcmd(&cs, p); 203 if (cs == NULL) { 204 printf("%s: syntax error\n", ct->cmd_name); 205 return 0; 206 } 207 ct = cs; 208 } 209 cmd.cmd = ct; 210 } 211 212 cmd.argv[0] = ct->cmd_name; 213 while (p && cmd.argc+1 < sizeof(cmd.argv) / sizeof(cmd.argv[0])) { 214 cmd.argv[cmd.argc++] = p; 215 p = nextword(p); 216 } 217 cmd.argv[cmd.argc] = NULL; 218 219 return (*cmd.cmd->cmd_exec)(); 220 } 221 222 static char * 223 whatcmd(const struct cmd_table **ct, char *p) 224 { 225 char *q; 226 int l; 227 228 q = nextword(p); 229 230 for (l = 0; p[l]; l++) 231 ; 232 233 while ((*ct)->cmd_name != NULL && strncmp(p, (*ct)->cmd_name, l)) 234 (*ct)++; 235 236 if ((*ct)->cmd_name == NULL) 237 *ct = NULL; 238 239 return q; 240 } 241 242 static int 243 readline(char *buf, size_t n, int to) 244 { 245 #ifdef DEBUG 246 extern int debug; 247 #endif 248 char *p = buf, ch; 249 250 /* Only do timeout if greater than 0 */ 251 if (to > 0) { 252 u_long i = 0; 253 time_t tt = getsecs() + to; 254 #ifdef DEBUG 255 if (debug > 2) 256 printf ("readline: timeout(%d) at %u\n", to, tt); 257 #endif 258 /* check for timeout expiration less often 259 (for some very constrained archs) */ 260 while (!cnischar()) 261 if (!(i++ % 1000) && (getsecs() >= tt)) 262 break; 263 264 if (!cnischar()) { 265 strlcpy(buf, "boot", 5); 266 putchar('\n'); 267 return strlen(buf); 268 } 269 } else 270 while (!cnischar()) 271 ; 272 273 /* User has typed something. Turn off timeouts. */ 274 cmd.timeout = 0; 275 276 while (1) { 277 switch ((ch = getchar())) { 278 case CTRL('u'): 279 while (p > buf) { 280 putchar('\177'); 281 p--; 282 } 283 continue; 284 case '\n': 285 case '\r': 286 *p = '\0'; 287 break; 288 case '\b': 289 case '\177': 290 if (p > buf) { 291 putchar('\177'); 292 p--; 293 } 294 continue; 295 default: 296 if (ch >= ' ' && ch < '\177') { 297 if (p - buf < n-1) 298 *p++ = ch; 299 else { 300 putchar('\007'); 301 putchar('\177'); 302 } 303 } 304 continue; 305 } 306 break; 307 } 308 309 return p - buf; 310 } 311 312 /* 313 * Search for spaces/tabs after the current word. If found, \0 the 314 * first one. Then pass a pointer to the first character of the 315 * next word, or NULL if there is no next word. 316 */ 317 char * 318 nextword(char *p) 319 { 320 /* skip blanks */ 321 while (*p && *p != '\t' && *p != ' ') 322 p++; 323 if (*p) { 324 *p++ = '\0'; 325 while (*p == '\t' || *p == ' ') 326 p++; 327 } 328 if (*p == '\0') 329 p = NULL; 330 return p; 331 } 332 333 static void 334 print_help(const struct cmd_table *ct) 335 { 336 for (; ct->cmd_name != NULL; ct++) 337 printf(" %s", ct->cmd_name); 338 putchar('\n'); 339 } 340 341 static int 342 Xhelp(void) 343 { 344 printf("commands:"); 345 print_help(cmd_table); 346 #ifdef MACHINE_CMD 347 return Xmachine(); 348 #else 349 return 0; 350 #endif 351 } 352 353 #ifdef MACHINE_CMD 354 static int 355 Xmachine(void) 356 { 357 printf("machine:"); 358 print_help(MACHINE_CMD); 359 return 0; 360 } 361 #endif 362 363 static int 364 Xecho(void) 365 { 366 int i; 367 368 for (i = 1; i < cmd.argc; i++) 369 printf("%s ", cmd.argv[i]); 370 putchar('\n'); 371 return 0; 372 } 373 374 static int 375 Xstty(void) 376 { 377 int sp; 378 char *cp; 379 dev_t dev; 380 381 if (cmd.argc == 1) 382 printf("%s speed is %d\n", ttyname(0), cnspeed(0, -1)); 383 else { 384 dev = ttydev(cmd.argv[1]); 385 if (dev == NODEV) 386 printf("%s not a console device\n", cmd.argv[1]); 387 else { 388 if (cmd.argc == 2) 389 printf("%s speed is %d\n", cmd.argv[1], 390 cnspeed(dev, -1)); 391 else { 392 sp = 0; 393 for (cp = cmd.argv[2]; *cp && isdigit(*cp); cp++) 394 sp = sp * 10 + (*cp - '0'); 395 cnspeed(dev, sp); 396 } 397 } 398 } 399 400 return 0; 401 } 402 403 static int 404 Xtime(void) 405 { 406 time_t tt = getsecs(); 407 408 if (cmd.argc == 1) 409 printf(ctime(&tt)); 410 else { 411 } 412 413 return 0; 414 } 415 416 static int 417 Xls(void) 418 { 419 struct stat sb; 420 char *p; 421 int fd; 422 423 if (stat(qualify((cmd.argv[1]? cmd.argv[1]: "/.")), &sb) < 0) { 424 printf("stat(%s): %s\n", cmd.path, strerror(errno)); 425 return 0; 426 } 427 428 if ((sb.st_mode & S_IFMT) != S_IFDIR) 429 ls(cmd.path, &sb); 430 else { 431 if ((fd = opendir(cmd.path)) < 0) { 432 printf ("opendir(%s): %s\n", cmd.path, 433 strerror(errno)); 434 return 0; 435 } 436 437 /* no strlen in lib !!! */ 438 for (p = cmd.path; *p; p++) 439 ; 440 *p++ = '/'; 441 *p = '\0'; 442 443 while(readdir(fd, p) >= 0) { 444 if (stat(cmd.path, &sb) < 0) 445 printf("stat(%s): %s\n", cmd.path, 446 strerror(errno)); 447 else 448 ls(p, &sb); 449 } 450 closedir (fd); 451 } 452 return 0; 453 } 454 455 #define lsrwx(mode,s) \ 456 putchar ((mode) & S_IROTH? 'r' : '-'); \ 457 putchar ((mode) & S_IWOTH? 'w' : '-'); \ 458 putchar ((mode) & S_IXOTH? *(s): (s)[1]); 459 460 static void 461 ls(char *name, struct stat *sb) 462 { 463 putchar("-fc-d-b---l-s-w-"[(sb->st_mode & S_IFMT) >> 12]); 464 lsrwx(sb->st_mode >> 6, (sb->st_mode & S_ISUID? "sS" : "x-")); 465 lsrwx(sb->st_mode >> 3, (sb->st_mode & S_ISGID? "sS" : "x-")); 466 lsrwx(sb->st_mode , (sb->st_mode & S_ISTXT? "tT" : "x-")); 467 468 printf (" %u,%u\t%lu\t%s\n", sb->st_uid, sb->st_gid, 469 (u_long)sb->st_size, name); 470 } 471 #undef lsrwx 472 473 int doboot = 1; 474 475 static int 476 Xnop(void) 477 { 478 if (doboot) { 479 doboot = 0; 480 return (Xboot()); 481 } 482 483 return 0; 484 } 485 486 static int 487 Xboot(void) 488 { 489 if (cmd.argc > 1 && cmd.argv[1][0] != '-') { 490 qualify((cmd.argv[1]? cmd.argv[1]: cmd.image)); 491 if (bootparse(2)) 492 return 0; 493 } else { 494 if (bootparse(1)) 495 return 0; 496 snprintf(cmd.path, sizeof cmd.path, "%s:%s", 497 cmd.bootdev, cmd.image); 498 } 499 500 return 1; 501 } 502 503 /* 504 * Qualifies the path adding necessary dev 505 */ 506 507 static char * 508 qualify(char *name) 509 { 510 char *p; 511 512 for (p = name; *p; p++) 513 if (*p == ':') 514 break; 515 if (*p == ':') 516 strlcpy(cmd.path, name, sizeof(cmd.path)); 517 else 518 snprintf(cmd.path, sizeof cmd.path, "%s:%s", 519 cmd.bootdev, name); 520 return cmd.path; 521 } 522 523 static int 524 Xreboot(void) 525 { 526 printf("Rebooting...\n"); 527 exit(); 528 return 0; /* just in case */ 529 } 530 531