1 /* $OpenBSD: cmd.c,v 1.50 2003/06/02 20:20:54 mickey 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 30 #include <sys/param.h> 31 #include <libsa.h> 32 #include <sys/reboot.h> 33 #include <lib/libkern/funcs.h> 34 #include "cmd.h" 35 36 #define CTRL(c) ((c)&0x1f) 37 38 static int Xboot(void); 39 static int Xecho(void); 40 static int Xhelp(void); 41 static int Xls(void); 42 static int Xnop(void); 43 static int Xreboot(void); 44 static int Xstty(void); 45 static int Xtime(void); 46 #ifdef MACHINE_CMD 47 static int Xmachine(void); 48 extern const struct cmd_table MACHINE_CMD[]; 49 #endif 50 extern int Xset(void); 51 extern int Xenv(void); 52 53 extern const struct cmd_table cmd_set[]; 54 const struct cmd_table cmd_table[] = { 55 {"#", CMDT_CMD, Xnop}, /* XXX must be first */ 56 {"boot", CMDT_CMD, Xboot}, 57 {"echo", CMDT_CMD, Xecho}, 58 {"env", CMDT_CMD, Xenv}, 59 {"help", CMDT_CMD, Xhelp}, 60 {"ls", CMDT_CMD, Xls}, 61 #ifdef MACHINE_CMD 62 {"machine",CMDT_MDC, Xmachine}, 63 #endif 64 {"reboot", CMDT_CMD, Xreboot}, 65 {"set", CMDT_SET, Xset}, 66 {"stty", CMDT_CMD, Xstty}, 67 {"time", CMDT_CMD, Xtime}, 68 {NULL, 0}, 69 }; 70 71 static void ls(char *, register struct stat *); 72 static int readline(register char *, size_t, int); 73 char *nextword(register char *); 74 static char *whatcmd(register const struct cmd_table **ct, register char *); 75 static int docmd(void); 76 static char *qualify(char *); 77 78 char cmd_buf[133]; 79 80 int 81 getcmd() 82 { 83 cmd.cmd = NULL; 84 85 if (!readline(cmd_buf, sizeof(cmd_buf), cmd.timeout)) 86 cmd.cmd = cmd_table; 87 88 return docmd(); 89 } 90 91 int 92 read_conf() 93 { 94 #ifndef INSECURE 95 struct stat sb; 96 #endif 97 int fd, eof = 0; 98 99 if ((fd = open(qualify(cmd.conf), 0)) < 0) { 100 if (errno != ENOENT && errno != ENXIO) { 101 printf("open(%s): %s\n", cmd.path, strerror(errno)); 102 return 0; 103 } 104 return -1; 105 } 106 107 #ifndef INSECURE 108 (void) fstat(fd, &sb); 109 if (sb.st_uid || (sb.st_mode & 2)) { 110 printf("non-secure %s, will not proceed\n", cmd.path); 111 close(fd); 112 return -1; 113 } 114 #endif 115 116 do { 117 register char *p = cmd_buf; 118 119 cmd.cmd = NULL; 120 121 do { 122 eof = read(fd, p, 1); 123 } while (eof > 0 && *p++ != '\n'); 124 125 if (eof < 0) 126 printf("%s: %s\n", cmd.path, strerror(errno)); 127 else 128 *--p = '\0'; 129 130 } while (eof > 0 && !(eof = docmd())); 131 132 close(fd); 133 return eof; 134 } 135 136 static int 137 docmd() 138 { 139 register char *p = NULL; 140 const struct cmd_table *ct = cmd_table, *cs; 141 142 cmd.argc = 1; 143 if (cmd.cmd == NULL) { 144 145 /* command */ 146 for (p = cmd_buf; *p && (*p == ' ' || *p == '\t'); p++) 147 ; 148 if (*p == '#' || *p == '\0') { /* comment or empty string */ 149 #ifdef DEBUG 150 printf("rem\n"); 151 #endif 152 return 0; 153 } 154 ct = cmd_table; 155 cs = NULL; 156 cmd.argv[cmd.argc] = p; /* in case it's shortcut boot */ 157 p = whatcmd(&ct, p); 158 if (ct == NULL) { 159 cmd.argc++; 160 ct = cmd_table; 161 } else if (ct->cmd_type == CMDT_SET && p != NULL) { 162 cs = cmd_set; 163 #ifdef MACHINE_CMD 164 } else if (ct->cmd_type == CMDT_MDC && p != NULL) { 165 cs = MACHINE_CMD; 166 #endif 167 } 168 169 if (cs != NULL) { 170 p = whatcmd(&cs, p); 171 if (cs == NULL) { 172 printf("%s: syntax error\n", ct->cmd_name); 173 return 0; 174 } 175 ct = cs; 176 } 177 cmd.cmd = ct; 178 } 179 180 cmd.argv[0] = ct->cmd_name; 181 while (p && cmd.argc+1 < sizeof(cmd.argv) / sizeof(cmd.argv[0])) { 182 cmd.argv[cmd.argc++] = p; 183 p = nextword(p); 184 } 185 cmd.argv[cmd.argc] = NULL; 186 187 return (*cmd.cmd->cmd_exec)(); 188 } 189 190 static char * 191 whatcmd(ct, p) 192 register const struct cmd_table **ct; 193 register char *p; 194 { 195 register char *q; 196 register int l; 197 198 q = nextword(p); 199 200 for (l = 0; p[l]; l++) 201 ; 202 203 while ((*ct)->cmd_name != NULL && strncmp(p, (*ct)->cmd_name, l)) 204 (*ct)++; 205 206 if ((*ct)->cmd_name == NULL) 207 *ct = NULL; 208 209 return q; 210 } 211 212 static int 213 readline(buf, n, to) 214 register char *buf; 215 size_t n; 216 int to; 217 { 218 #ifdef DEBUG 219 extern int debug; 220 #endif 221 register char *p = buf, ch; 222 223 /* Only do timeout if greater than 0 */ 224 if (to > 0) { 225 u_long i = 0; 226 time_t tt = getsecs() + to; 227 #ifdef DEBUG 228 if (debug > 2) 229 printf ("readline: timeout(%d) at %u\n", to, tt); 230 #endif 231 /* check for timeout expiration less often 232 (for some very constrained archs) */ 233 while (!cnischar()) 234 if (!(i++ % 1000) && (getsecs() >= tt)) 235 break; 236 237 if (!cnischar()) { 238 strlcpy(buf, "boot", 5); 239 putchar('\n'); 240 return strlen(buf); 241 } 242 } else 243 while (!cnischar()) 244 ; 245 246 while (1) { 247 switch ((ch = getchar())) { 248 case CTRL('u'): 249 while (p > buf) { 250 putchar('\177'); 251 p--; 252 } 253 continue; 254 case '\n': 255 case '\r': 256 p[1] = *p = '\0'; 257 break; 258 case '\b': 259 case '\177': 260 if (p > buf) { 261 putchar('\177'); 262 p--; 263 } 264 continue; 265 default: 266 if (p - buf < n-1) 267 *p++ = ch; 268 else { 269 putchar('\007'); 270 putchar('\177'); 271 } 272 continue; 273 } 274 break; 275 } 276 277 return p - buf; 278 } 279 280 /* 281 * Search for spaces/tabs after the current word. If found, \0 the 282 * first one. Then pass a pointer to the first character of the 283 * next word, or NULL if there is no next word. 284 */ 285 char * 286 nextword(p) 287 register char *p; 288 { 289 /* skip blanks */ 290 while (*p && *p != '\t' && *p != ' ') 291 p++; 292 if (*p) { 293 *p++ = '\0'; 294 while (*p == '\t' || *p == ' ') 295 p++; 296 } 297 if (*p == '\0') 298 p = NULL; 299 return p; 300 } 301 302 static void 303 print_help(ct) 304 register const struct cmd_table *ct; 305 { 306 for (; ct->cmd_name != NULL; ct++) 307 printf(" %s", ct->cmd_name); 308 putchar('\n'); 309 } 310 311 static int 312 Xhelp() 313 { 314 printf("commands:"); 315 print_help(cmd_table); 316 #ifdef MACHINE_CMD 317 return Xmachine(); 318 #else 319 return 0; 320 #endif 321 } 322 323 #ifdef MACHINE_CMD 324 static int 325 Xmachine() 326 { 327 printf("machine:"); 328 print_help(MACHINE_CMD); 329 return 0; 330 } 331 #endif 332 333 static int 334 Xecho() 335 { 336 register int i; 337 for (i = 1; i < cmd.argc; i++) 338 printf("%s ", cmd.argv[i]); 339 putchar('\n'); 340 return 0; 341 } 342 343 static int 344 Xstty() 345 { 346 register int sp; 347 register char *cp; 348 dev_t dev; 349 350 if (cmd.argc == 1) 351 printf("%s speed is %d\n", ttyname(0), cnspeed(0, -1)); 352 else { 353 dev = ttydev(cmd.argv[1]); 354 if (dev == NODEV) 355 printf("%s not a console device\n", cmd.argv[1]); 356 else { 357 if (cmd.argc == 2) 358 printf("%s speed is %d\n", cmd.argv[1], 359 cnspeed(dev, -1)); 360 else { 361 sp = 0; 362 for (cp = cmd.argv[2]; *cp && isdigit(*cp); cp++) 363 sp = sp * 10 + (*cp - '0'); 364 cnspeed(dev, sp); 365 } 366 } 367 } 368 369 return 0; 370 } 371 372 static int 373 Xtime() 374 { 375 time_t tt = getsecs(); 376 377 if (cmd.argc == 1) 378 printf(ctime(&tt)); 379 else { 380 } 381 382 return 0; 383 } 384 385 static int 386 Xls() 387 { 388 struct stat sb; 389 register char *p; 390 int fd; 391 392 if (stat(qualify((cmd.argv[1]? cmd.argv[1]: "/.")), &sb) < 0) { 393 printf("stat(%s): %s\n", cmd.path, strerror(errno)); 394 return 0; 395 } 396 397 if ((sb.st_mode & S_IFMT) != S_IFDIR) 398 ls(cmd.path, &sb); 399 else { 400 if ((fd = opendir(cmd.path)) < 0) { 401 printf ("opendir(%s): %s\n", cmd.path, 402 strerror(errno)); 403 return 0; 404 } 405 406 /* no strlen in lib !!! */ 407 for (p = cmd.path; *p; p++) 408 ; 409 *p++ = '/'; 410 *p = '\0'; 411 412 while(readdir(fd, p) >= 0) { 413 if (stat(cmd.path, &sb) < 0) 414 printf("stat(%s): %s\n", cmd.path, 415 strerror(errno)); 416 else 417 ls(p, &sb); 418 } 419 closedir (fd); 420 } 421 return 0; 422 } 423 424 #define lsrwx(mode,s) \ 425 putchar ((mode) & S_IROTH? 'r' : '-'); \ 426 putchar ((mode) & S_IWOTH? 'w' : '-'); \ 427 putchar ((mode) & S_IXOTH? *(s): (s)[1]); 428 429 static void 430 ls(name, sb) 431 register char *name; 432 register struct stat *sb; 433 { 434 putchar("-fc-d-b---l-s-w-"[(sb->st_mode & S_IFMT) >> 12]); 435 lsrwx(sb->st_mode >> 6, (sb->st_mode & S_ISUID? "sS" : "x-")); 436 lsrwx(sb->st_mode >> 3, (sb->st_mode & S_ISGID? "sS" : "x-")); 437 lsrwx(sb->st_mode , (sb->st_mode & S_ISTXT? "tT" : "x-")); 438 439 printf (" %u,%u\t%lu\t%s\n", sb->st_uid, sb->st_gid, 440 (u_long)sb->st_size, name); 441 } 442 #undef lsrwx 443 444 int doboot = 1; 445 446 static int 447 Xnop() 448 { 449 if (doboot) { 450 doboot = 0; 451 return (Xboot()); 452 } 453 454 return 0; 455 } 456 457 static int 458 Xboot() 459 { 460 if (cmd.argc > 1 && cmd.argv[1][0] != '-') { 461 qualify((cmd.argv[1]? cmd.argv[1]: cmd.image)); 462 if (bootparse(2)) 463 return 0; 464 } else { 465 if (bootparse(1)) 466 return 0; 467 snprintf(cmd.path, sizeof cmd.path, "%s:%s", 468 cmd.bootdev, cmd.image); 469 } 470 471 return 1; 472 } 473 474 /* 475 * Qualifies the path adding neccessary dev 476 */ 477 478 static char * 479 qualify(name) 480 char *name; 481 { 482 register char *p; 483 484 for (p = name; *p; p++) 485 if (*p == ':') 486 break; 487 if (*p == ':') 488 strlcpy(cmd.path, name, sizeof(cmd.path)); 489 else 490 snprintf(cmd.path, sizeof cmd.path, "%s:%s", 491 cmd.bootdev, name); 492 return cmd.path; 493 } 494 495 static int 496 Xreboot() 497 { 498 printf("Rebooting...\n"); 499 exit(); 500 return 0; /* just in case */ 501 } 502 503