cmd.c 9.9 KB

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