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