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