memdisk: Force ld output format to 32-bits
[syslinux.git] / com32 / rosh / rosh.c
blob8198a2bafde9e91cca5824e282f645cd62cafa0e
1 /* ----------------------------------------------------------------------- *
3 * Copyright 2008-2011 Gene Cumm - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 53 Temple Place Ste 330,
8 * Boston MA 02111-1307, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
14 * rosh.c
16 * Read-Only shell; Simple shell system designed for SYSLINUX-derivitives.
17 * Provides minimal commands utilizing the console via stdout/stderr as the
18 * sole output devices. Designed to compile for Linux for testing/debugging.
22 * ToDos:
23 * prompt: Allow left/right arrow, home/end and more?
24 * commands Break into argv/argc-like array
25 * rosh_cfg: allow -s <file> to change config
26 * rosh_ls(): sorted; then multiple columns
27 * prompt: Possibly honor timeout on initial entry for usage as UI
28 * Also possibly honor totaltimeout
31 /*#define DO_DEBUG 1
32 //*/
33 /* Uncomment the above line for debugging output; Comment to remove */
34 /*#define DO_DEBUG2 1
35 //*/
36 /* Uncomment the above line for super-debugging output; Must have regular
37 * debugging enabled; Comment to remove.
39 #include "rosh.h"
40 #include "version.h"
42 #define APP_LONGNAME "Read-Only Shell"
43 #define APP_NAME "rosh"
44 #define APP_AUTHOR "Gene Cumm"
45 #define APP_YEAR "2010"
46 #define APP_VER "beta-b090"
48 /* Print version information to stdout
50 void rosh_version(int vtype)
52 char env[256];
53 env[0] = 0;
54 printf("%s v %s; (c) %s %s.\n\tFrom Syslinux %s, %s\n", APP_LONGNAME, APP_VER, APP_YEAR, APP_AUTHOR, VERSION_STR, DATE);
55 switch (vtype) {
56 case 1:
57 rosh_get_env_ver(env, 256);
58 printf("\tRunning on %s\n", env);
62 /* Print beta message and if DO_DEBUG/DO_DEBUG2 are active
64 void print_beta(void)
66 puts(rosh_beta_str);
67 ROSH_DEBUG("DO_DEBUG active\n");
68 ROSH_DEBUG2("DO_DEBUG2 active\n");
71 /* Search a string for first non-space (' ') character, starting at ipos
72 * istr input string to parse
73 * ipos input position to start at
75 int rosh_search_nonsp(const char *istr, const int ipos)
77 int curpos;
78 char c;
80 curpos = ipos;
81 c = istr[curpos];
82 while (c && isspace(c))
83 c = istr[++curpos];
84 return curpos;
87 /* Search a string for space (' '), returning the position of the next space
88 * or the '\0' at end of string
89 * istr input string to parse
90 * ipos input position to start at
92 int rosh_search_sp(const char *istr, const int ipos)
94 int curpos;
95 char c;
97 curpos = ipos;
98 c = istr[curpos];
99 while (c && !(isspace(c)))
100 c = istr[++curpos];
101 return curpos;
104 /* Parse a string for the first non-space string, returning the end position
105 * from src
106 * dest string to contain the first non-space string
107 * src string to parse
108 * ipos Position to start in src
110 int rosh_parse_sp_1(char *dest, const char *src, const int ipos)
112 int bpos, epos; /* beginning and ending position of source string
113 to copy to destination string */
115 bpos = 0;
116 epos = 0;
117 /* //HERE-error condition checking */
118 bpos = rosh_search_nonsp(src, ipos);
119 epos = rosh_search_sp(src, bpos);
120 if (epos > bpos) {
121 memcpy(dest, src + bpos, epos - bpos);
122 if (dest[epos - bpos] != 0)
123 dest[epos - bpos] = 0;
124 } else {
125 epos = strlen(src);
126 dest[0] = 0;
128 return epos;
132 * parse_args1: Try 1 at parsing a string to an argc/argv pair. use free_args1 to free memory malloc'd
134 * Derived from com32/lib/sys/argv.c:__parse_argv()
135 * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved
136 * Copyright 2009 Intel Corporation; author: H. Peter Anvin
138 int parse_args1(char ***iargv, const char *istr)
140 int argc = 0;
141 const char *p;
142 char *q, *r, *args, **arg;
143 int sp = 1; //, qt = 0; /* Was a space; inside a quote */
145 /* Scan 1: Length */
146 /* I could eliminate this if I knew a max length, like strncpy() */
147 int len = strlen(istr);
149 /* Scan 2: Copy, nullify and make argc */
150 if (!(args = malloc(len + 1)))
151 goto fail_args;
152 q = args;
153 for (p = istr;; p++) {
154 if (*p <= ' ') {
155 if (!sp) {
156 sp = 1;
157 *q++ = '\0';
159 } else {
160 if (sp) {
161 argc++;
162 sp = 0;
164 *q++ = *p;
166 if (!*p)
167 break;
170 q--; /* Point q to final null */
171 /* Scan 3: Build array of pointers */
172 if (!(*iargv = malloc((argc + 1) * sizeof(char *))))
173 goto fail_args_ptr;
174 arg = *iargv;
175 arg[argc] = NULL; /* Nullify the last pointer */
176 if (*args != '\0')
177 *arg++ = args;
178 for (r = args; r < q ; r++) {
179 if (*r == '\0') {
180 *arg++ = r + 1;
184 fail_args:
185 return argc;
186 fail_args_ptr:
187 free(args);
188 return 0;
191 /* Free argv created by parse_args1()
192 * argv Argument Values
194 void free_args1(char ***argv)
196 char *s;
197 s = **argv;
198 free(*argv);
199 free(s);
202 /* Convert a string to an argc/argv pair
203 * str String to parse
204 * argv Argument Values
205 * returns Argument Count
207 int rosh_str2argv(char ***argv, const char *str)
209 return parse_args1(argv, str);
212 /* Free an argv created by rosh_str2argv()
213 * argv Argument Values to free
215 void rosh_free_argv(char ***argv)
217 free_args1(argv);
220 /* Print the contents of an argc/argv pair
221 * argc Argument Count
222 * argv Argument Values
224 void rosh_pr_argv(int argc, char *argv[])
226 int i;
227 for (i = 0; i < argc; i++) {
228 printf("%s%s", argv[i], (i < argc)? " " : "");
230 puts("");
233 /* Print the contents of an argc/argv pair verbosely
234 * argc Argument Count
235 * argv Argument Values
237 void rosh_pr_argv_v(int argc, char *argv[])
239 int i;
240 for (i = 0; i < argc; i++) {
241 printf("%4d '%s'\n", i, argv[i]);
245 /* Reset the getopt() environment
247 void rosh_getopt_reset(void)
249 optind = 0;
250 optopt = 0;
253 /* Display help
254 * type Help type
255 * cmdstr Command for which help is requested
257 void rosh_help(int type, const char *cmdstr)
259 switch (type) {
260 case 2:
261 if ((cmdstr == NULL) || (strcmp(cmdstr, "") == 0)) {
262 rosh_version(0);
263 puts(rosh_help_str2);
264 } else {
265 switch (cmdstr[0]) {
266 case 'c':
267 puts(rosh_help_cd_str);
268 break;
269 case 'l':
270 puts(rosh_help_ls_str);
271 break;
272 default:
273 printf(rosh_help_str_adv, cmdstr);
276 break;
277 case 1:
278 default:
279 if (cmdstr)
280 printf("%s: %s: unknown command\n", APP_NAME, cmdstr);
281 rosh_version(0);
282 puts(rosh_help_str1);
286 /* Handle most/all errors
287 * ierrno Input Error number
288 * cmdstr Command being executed to cause error
289 * filestr File/parameter causing error
291 void rosh_error(const int ierrno, const char *cmdstr, const char *filestr)
293 printf("--ERROR: %s '%s': ", cmdstr, filestr);
294 switch (ierrno) {
295 case 0:
296 puts("NO ERROR");
297 break;
298 case ENOENT:
299 puts("not found");
300 /* SYSLinux-3.72 COM32 API returns this for a
301 directory or empty file */
302 ROSH_COM32(" (COM32) could be a directory or empty file\n");
303 break;
304 case EIO:
305 puts("I/O Error");
306 break;
307 case EBADF:
308 puts("Bad File Descriptor");
309 break;
310 case EACCES:
311 puts("Access DENIED");
312 break;
313 case ENOTDIR:
314 puts("not a directory");
315 ROSH_COM32(" (COM32) could be directory\n");
316 break;
317 case EISDIR:
318 puts("IS a directory");
319 break;
320 case ENOSYS:
321 puts("not implemented");
322 break;
323 default:
324 printf("returns error; errno=%d\n", ierrno);
326 } /* rosh_error */
328 /* Concatenate command line arguments into one string
329 * cmdstr Output command string
330 * cmdlen Length of cmdstr
331 * argc Argument Count
332 * argv Argument Values
333 * barg Beginning Argument
335 int rosh_argcat(char *cmdstr, const int cmdlen, const int argc, char *argv[],
336 const int barg)
338 int i, arglen, curpos; /* index, argument length, current position
339 in cmdstr */
340 curpos = 0;
341 cmdstr[0] = '\0'; /* Nullify string just to be sure */
342 for (i = barg; i < argc; i++) {
343 arglen = strlen(argv[i]);
344 /* Theoretically, this should never be met in SYSLINUX */
345 if ((curpos + arglen) > (cmdlen - 1))
346 arglen = (cmdlen - 1) - curpos;
347 memcpy(cmdstr + curpos, argv[i], arglen);
348 curpos += arglen;
349 if (curpos >= (cmdlen - 1)) {
350 /* Hopefully, curpos should not be greater than
351 (cmdlen - 1) */
352 /* Still need a '\0' at the last character */
353 cmdstr[(cmdlen - 1)] = 0;
354 break; /* Escape out of the for() loop;
355 We can no longer process anything more */
356 } else {
357 cmdstr[curpos] = ' ';
358 curpos += 1;
359 cmdstr[curpos] = 0;
362 /* If there's a ' ' at the end, remove it. This is normal unless
363 the maximum length is met/exceeded. */
364 if (cmdstr[curpos - 1] == ' ')
365 cmdstr[--curpos] = 0;
366 return curpos;
367 } /* rosh_argcat */
370 * Prints a lot of the data in a struct termios
373 void rosh_print_tc(struct termios *tio)
375 printf(" -- termios: ");
376 printf(".c_iflag=%04X ", tio->c_iflag);
377 printf(".c_oflag=%04X ", tio->c_oflag);
378 printf(".c_cflag=%04X ", tio->c_cflag);
379 printf(".c_lflag=%04X ", tio->c_lflag);
380 printf(".c_cc[VTIME]='%d' ", tio->c_cc[VTIME]);
381 printf(".c_cc[VMIN]='%d'", tio->c_cc[VMIN]);
382 printf("\n");
387 * Attempts to get a single key from the console
388 * returns key pressed
390 int rosh_getkey(void)
392 int inc;
394 inc = KEY_NONE;
395 while (inc == KEY_NONE)
396 inc = get_key(stdin, 6000);
397 return inc;
398 } /* rosh_getkey */
401 * Qualifies a filename relative to the working directory
402 * filestr Filename to qualify
403 * pwdstr working directory
404 * returns qualified file name string
406 void rosh_qualify_filestr(char *filestr, const char *ifilstr,
407 const char *pwdstr)
409 int filepos = 0;
410 if ((filestr) && (pwdstr) && (ifilstr)) {
411 if (ifilstr[0] != SEP) {
412 strcpy(filestr, pwdstr);
413 filepos = strlen(pwdstr);
414 if (filestr[filepos - 1] != SEP)
415 filestr[filepos++] = SEP;
417 strcpy(filestr + filepos, ifilstr);
418 ROSH_DEBUG("--'%s'\n", filestr);
422 /* Concatenate multiple files to stdout
423 * argc Argument Count
424 * argv Argument Values
426 void rosh_cat(int argc, char *argv[])
428 FILE *f;
429 char buf[ROSH_BUF_SZ];
430 int i, numrd;
432 for (i = 0; i < argc; i++) {
433 printf("--File = '%s'\n", argv[i]);
434 errno = 0;
435 f = fopen(argv[i], "r");
436 if (f != NULL) {
437 numrd = fread(buf, 1, ROSH_BUF_SZ, f);
438 while (numrd > 0) {
439 fwrite(buf, 1, numrd, stdout);
440 numrd = fread(buf, 1, ROSH_BUF_SZ, f);
442 fclose(f);
443 } else {
444 rosh_error(errno, "cat", argv[i]);
445 errno = 0;
448 } /* rosh_cat */
450 /* Change PWD (Present Working Directory)
451 * argc Argument count
452 * argv Argument values
453 * ipwdstr Initial PWD
455 void rosh_cd(int argc, char *argv[], const char *ipwdstr)
457 int rv = 0;
458 #ifdef DO_DEBUG
459 char filestr[ROSH_PATH_SZ];
460 #endif /* DO_DEBUG */
461 ROSH_DEBUG("CMD: \n");
462 ROSH_DEBUG_ARGV_V(argc, argv);
463 errno = 0;
464 if (argc == 2)
465 rv = chdir(argv[1]);
466 else if (argc == 1)
467 rv = chdir(ipwdstr);
468 else
469 rosh_help(2, argv[0]);
470 if (rv != 0) {
471 if (argc == 2)
472 rosh_error(errno, "cd", argv[1]);
473 else
474 rosh_error(errno, "cd", ipwdstr);
475 errno = 0;
476 } else {
477 #ifdef DO_DEBUG
478 if (getcwd(filestr, ROSH_PATH_SZ))
479 ROSH_DEBUG(" %s\n", filestr);
480 #endif /* DO_DEBUG */
482 } /* rosh_cd */
484 /* Print the syslinux config file name
486 void rosh_cfg(void)
488 printf("CFG: '%s'\n", syslinux_config_file());
489 } /* rosh_cfg */
491 /* Echo a string back to the screen
492 * cmdstr command string to process
494 void rosh_echo(const char *cmdstr)
496 int bpos = 0;
497 ROSH_DEBUG("CMD: '%s'\n", cmdstr);
498 bpos = rosh_search_nonsp(cmdstr, rosh_search_sp(cmdstr, 0));
499 if (bpos > 1) {
500 ROSH_DEBUG(" bpos=%d\n", bpos);
501 printf("'%s'\n", cmdstr + bpos);
502 } else {
503 puts("");
505 } /* rosh_echo */
507 /* Process argc/argv to optarr
508 * argc Argument count
509 * argv Argument values
510 * optarr option array to populate
512 void rosh_ls_arg_opt(int argc, char *argv[], int optarr[])
514 int rv = 0;
516 optarr[0] = -1;
517 optarr[1] = -1;
518 optarr[2] = -1;
519 rosh_getopt_reset();
520 while (rv != -1) {
521 ROSH_DEBUG2("getopt optind=%d rv=%d\n", optind, rv);
522 rv = getopt(argc, argv, rosh_ls_opt_str);
523 switch (rv) {
524 case 'l':
525 case 0:
526 optarr[0] = 1;
527 break;
528 case 'F':
529 case 1:
530 optarr[1] = 1;
531 break;
532 case 'i':
533 case 2:
534 optarr[2] = 1;
535 break;
536 case '?':
537 case -1:
538 default:
539 ROSH_DEBUG2("getopt optind=%d rv=%d\n", optind, rv);
540 break;
543 ROSH_DEBUG2(" end getopt optind=%d rv=%d\n", optind, rv);
544 ROSH_DEBUG2("\tIn rosh_ls_arg_opt() opt[0]=%d\topt[1]=%d\topt[2]=%d\n", optarr[0], optarr[1],
545 optarr[2]);
546 } /* rosh_ls_arg_opt */
548 /* Retrieve the size of a file argument
549 * filestr directory name of directory entry
550 * de directory entry
552 int rosh_ls_de_size(const char *filestr, struct dirent *de)
554 int de_size;
555 char filestr2[ROSH_PATH_SZ];
556 int fd2, file2pos;
557 struct stat fdstat;
559 filestr2[0] = 0;
560 file2pos = -1;
561 if (filestr) {
562 file2pos = strlen(filestr);
563 memcpy(filestr2, filestr, file2pos);
564 filestr2[file2pos] = '/';
566 strcpy(filestr2 + file2pos + 1, de->d_name);
567 fd2 = open(filestr2, O_RDONLY);
568 fstat(fd2, &fdstat);
569 fd2 = close(fd2);
570 de_size = (int)fdstat.st_size;
571 return de_size;
572 } /* rosh_ls_de_size */
574 /* Retrieve the size and mode of a file
575 * filestr directory name of directory entry
576 * de directory entry
578 int rosh_ls_de_size_mode(const char *filestr, struct dirent *de, mode_t * st_mode)
580 int de_size;
581 char filestr2[ROSH_PATH_SZ];
582 int file2pos;
583 struct stat fdstat;
584 int status;
586 filestr2[0] = 0;
587 file2pos = -1;
588 memset(&fdstat, 0, sizeof fdstat);
589 ROSH_DEBUG2("ls:dsm(%s, %s) ", filestr, de->d_name);
590 if (filestr) {
591 /* FIXME: prevent string overflow */
592 file2pos = strlen(filestr);
593 memcpy(filestr2, filestr, file2pos);
594 if (( filestr2[file2pos - 1] == SEP )) {
595 file2pos--;
596 } else {
597 filestr2[file2pos] = SEP;
600 strcpy(filestr2 + file2pos + 1, de->d_name);
601 errno = 0;
602 ROSH_DEBUG2("stat(%s) ", filestr2);
603 status = stat(filestr2, &fdstat);
604 (void)status;
605 ROSH_DEBUG2("\t--stat()=%d\terr=%d\n", status, errno);
606 if (errno) {
607 rosh_error(errno, "ls:szmd.stat", de->d_name);
608 errno = 0;
610 de_size = (int)fdstat.st_size;
611 *st_mode = fdstat.st_mode;
612 return de_size;
613 } /* rosh_ls_de_size_mode */
615 /* Returns the Inode number if fdstat contains it
616 * fdstat struct to extract inode from if not COM32, for now
618 long rosh_ls_d_ino(struct stat *fdstat)
620 long de_ino;
621 #ifdef __COM32__
622 if (fdstat)
623 de_ino = -1;
624 else
625 de_ino = 0;
626 #else /* __COM32__ */
627 de_ino = fdstat->st_ino;
628 #endif /* __COM32__ */
629 return de_ino;
632 /* Convert a d_type to a single char in human readable format
633 * d_type d_type to convert
634 * returns human readable single character; a space if other
636 char rosh_d_type2char_human(unsigned char d_type)
638 char ret;
639 switch (d_type) {
640 case DT_UNKNOWN:
641 ret = 'U';
642 break; /* Unknown */
643 case DT_FIFO:
644 ret = 'F';
645 break; /* FIFO */
646 case DT_CHR:
647 ret = 'C';
648 break; /* Char Dev */
649 case DT_DIR:
650 ret = 'D';
651 break; /* Directory */
652 case DT_BLK:
653 ret = 'B';
654 break; /* Block Dev */
655 case DT_REG:
656 ret = 'R';
657 break; /* Regular File */
658 case DT_LNK:
659 ret = 'L';
660 break; /* Link, Symbolic */
661 case DT_SOCK:
662 ret = 'S';
663 break; /* Socket */
664 case DT_WHT:
665 ret = 'W';
666 break; /* UnionFS Whiteout */
667 default:
668 ret = ' ';
670 return ret;
671 } /* rosh_d_type2char_human */
673 /* Convert a d_type to a single char by ls's prefix standards for -l
674 * d_type d_type to convert
675 * returns ls style single character; a space if other
677 char rosh_d_type2char_lspre(unsigned char d_type)
679 char ret;
680 switch (d_type) {
681 case DT_FIFO:
682 ret = 'p';
683 break;
684 case DT_CHR:
685 ret = 'c';
686 break;
687 case DT_DIR:
688 ret = 'd';
689 break;
690 case DT_BLK:
691 ret = 'b';
692 break;
693 case DT_REG:
694 ret = '-';
695 break;
696 case DT_LNK:
697 ret = 'l';
698 break;
699 case DT_SOCK:
700 ret = 's';
701 break;
702 default:
703 ret = '?';
705 return ret;
706 } /* rosh_d_type2char_lspre */
708 /* Convert a d_type to a single char by ls's classify (-F) suffix standards
709 * d_type d_type to convert
710 * returns ls style single character; a space if other
712 char rosh_d_type2char_lssuf(unsigned char d_type)
714 char ret;
715 switch (d_type) {
716 case DT_FIFO:
717 ret = '|';
718 break;
719 case DT_DIR:
720 ret = '/';
721 break;
722 case DT_LNK:
723 ret = '@';
724 break;
725 case DT_SOCK:
726 ret = '=';
727 break;
728 default:
729 ret = ' ';
731 return ret;
732 } /* rosh_d_type2char_lssuf */
734 /* Converts data in the "other" place of st_mode to a ls-style string
735 * st_mode Mode in other to analyze
736 * st_mode_str string to hold converted string
738 void rosh_st_mode_am2str(mode_t st_mode, char *st_mode_str)
740 st_mode_str[0] = ((st_mode & S_IROTH) ? 'r' : '-');
741 st_mode_str[1] = ((st_mode & S_IWOTH) ? 'w' : '-');
742 st_mode_str[2] = ((st_mode & S_IXOTH) ? 'x' : '-');
745 /* Converts st_mode to an ls-style string
746 * st_mode mode to convert
747 * st_mode_str string to hold converted string
749 void rosh_st_mode2str(mode_t st_mode, char *st_mode_str)
751 st_mode_str[0] = rosh_d_type2char_lspre(IFTODT(st_mode));
752 rosh_st_mode_am2str((st_mode & S_IRWXU) >> 6, st_mode_str + 1);
753 rosh_st_mode_am2str((st_mode & S_IRWXG) >> 3, st_mode_str + 4);
754 rosh_st_mode_am2str(st_mode & S_IRWXO, st_mode_str + 7);
755 st_mode_str[10] = 0;
756 } /* rosh_st_mode2str */
758 /* Output a single entry
759 * filestr directory name to list
760 * de directory entry
761 * optarr Array of options
763 void rosh_ls_arg_dir_de(const char *filestr, struct dirent *de, const int *optarr)
765 int de_size;
766 mode_t st_mode;
767 char st_mode_str[11];
768 st_mode = 0;
769 ROSH_DEBUG2("+");
770 if (optarr[2] > -1)
771 printf("%10d ", (int)(de->d_ino));
772 if (optarr[0] > -1) {
773 de_size = rosh_ls_de_size_mode(filestr, de, &st_mode);
774 rosh_st_mode2str(st_mode, st_mode_str);
775 ROSH_DEBUG2("%04X ", st_mode);
776 printf("%s %10d ", st_mode_str, de_size);
778 ROSH_DEBUG("'");
779 printf("%s", de->d_name);
780 ROSH_DEBUG("'");
781 if (optarr[1] > -1)
782 printf("%c", rosh_d_type2char_lssuf(de->d_type));
783 printf("\n");
784 } /* rosh_ls_arg_dir_de */
786 /* Output listing of a regular directory
787 * filestr directory name to list
788 * d the open DIR
789 * optarr Array of options
790 NOTE:This is where I could use qsort
792 void rosh_ls_arg_dir(const char *filestr, DIR * d, const int *optarr)
794 struct dirent *de;
795 int filepos;
797 filepos = 0;
798 errno = 0;
799 while ((de = readdir(d))) {
800 filepos++;
801 rosh_ls_arg_dir_de(filestr, de, optarr);
803 if (errno) {
804 rosh_error(errno, "ls:arg_dir", filestr);
805 errno = 0;
806 } else { if (filepos == 0)
807 ROSH_DEBUG("0 files found");
809 } /* rosh_ls_arg_dir */
811 /* Simple directory listing for one argument (file/directory) based on
812 * filestr and pwdstr
813 * ifilstr input filename/directory name to list
814 * pwdstr Present Working Directory string
815 * optarr Option Array
817 void rosh_ls_arg(const char *filestr, const int *optarr)
819 struct stat fdstat;
820 int status;
821 // char filestr[ROSH_PATH_SZ];
822 // int filepos;
823 DIR *d;
824 struct dirent de;
826 /* Initialization; make filestr based on leading character of ifilstr
827 and pwdstr */
828 // rosh_qualify_filestr(filestr, ifilstr, pwdstr);
829 fdstat.st_mode = 0;
830 fdstat.st_size = 0;
831 ROSH_DEBUG("\topt[0]=%d\topt[1]=%d\topt[2]=%d\n", optarr[0], optarr[1],
832 optarr[2]);
834 /* Now, the real work */
835 errno = 0;
836 status = stat(filestr, &fdstat);
837 if (status == 0) {
838 if (S_ISDIR(fdstat.st_mode)) {
839 ROSH_DEBUG("PATH '%s' is a directory\n", filestr);
840 if ((d = opendir(filestr))) {
841 rosh_ls_arg_dir(filestr, d, optarr);
842 closedir(d);
843 } else {
844 rosh_error(errno, "ls", filestr);
845 errno = 0;
847 } else {
848 de.d_ino = rosh_ls_d_ino(&fdstat);
849 de.d_type = (IFTODT(fdstat.st_mode));
850 strcpy(de.d_name, filestr);
851 if (S_ISREG(fdstat.st_mode)) {
852 ROSH_DEBUG("PATH '%s' is a regular file\n", filestr);
853 } else {
854 ROSH_DEBUG("PATH '%s' is some other file\n", filestr);
856 rosh_ls_arg_dir_de(NULL, &de, optarr);
857 /* if (ifilstr[0] == SEP)
858 rosh_ls_arg_dir_de(NULL, &de, optarr);
859 else
860 rosh_ls_arg_dir_de(pwdstr, &de, optarr);*/
862 } else {
863 rosh_error(errno, "ls", filestr);
864 errno = 0;
866 return;
867 } /* rosh_ls_arg */
869 /* Parse options that may be present in the cmdstr
870 * filestr Possible option string to parse
871 * optstr Current options
872 * returns 1 if filestr does not begin with '-' else 0
874 int rosh_ls_parse_opt(const char *filestr, char *optstr)
876 int ret;
877 if (filestr[0] == '-') {
878 ret = 0;
879 if (optstr)
880 strcat(optstr, filestr + 1);
881 } else {
882 ret = 1;
884 ROSH_DEBUG("ParseOpt: '%s'\n\topt: '%s'\n\tret: %d\n", filestr, optstr,
885 ret);
886 return ret;
887 } /* rosh_ls_parse_opt */
889 /* List Directory
890 * argc Argument count
891 * argv Argument values
893 void rosh_ls(int argc, char *argv[])
895 int optarr[3];
896 int i;
898 rosh_ls_arg_opt(argc, argv, optarr);
899 ROSH_DEBUG2("In ls()\n");
900 ROSH_DEBUG2_ARGV_V(argc, argv);
901 #ifdef DO_DEBUG
902 optarr[0] = 2;
903 #endif /* DO_DEBUG */
904 ROSH_DEBUG2(" argc=%d; optind=%d\n", argc, optind);
905 if (optind >= argc)
906 rosh_ls_arg(".", optarr);
907 for (i = optind; i < argc; i++) {
908 rosh_ls_arg(argv[i], optarr);
910 } /* rosh_ls */
912 /* Simple directory listing; calls rosh_ls()
913 * argc Argument count
914 * argv Argument values
916 void rosh_dir(int argc, char *argv[])
918 ROSH_DEBUG(" dir implemented as ls\n");
919 rosh_ls(argc, argv);
920 } /* rosh_dir */
922 /* Page through a buffer string
923 * buf Buffer to page through
925 void rosh_more_buf(char *buf, int buflen, int rows, int cols, char *scrbuf)
927 char *bufp, *bufeol, *bufeol2; /* Pointer to current and next
928 end-of-line position in buffer */
929 int bufpos, bufcnt; /* current position, count characters */
930 int inc;
931 int i, numln; /* Index, Number of lines */
932 int elpl; /* Extra lines per line read */
934 (void)cols;
936 bufpos = 0;
937 bufp = buf + bufpos;
938 bufeol = bufp;
939 numln = rows - 1;
940 ROSH_DEBUG("--(%d)\n", buflen);
941 while (bufpos < buflen) {
942 for (i = 0; i < numln; i++) {
943 bufeol2 = strchr(bufeol, '\n');
944 if (bufeol2 == NULL) {
945 bufeol = buf + buflen;
946 i = numln;
947 } else {
948 elpl = ((bufeol2 - bufeol - 1) / cols);
949 if (elpl < 0)
950 elpl = 0;
951 i += elpl;
952 ROSH_DEBUG2(" %d/%d ", elpl, i+1);
953 /* If this will not push too much, use it */
954 /* but if it's the first line, use it */
955 /* //HERE: We should probably snip the line off */
956 if ((i < numln) || (i == elpl))
957 bufeol = bufeol2 + 1;
960 ROSH_DEBUG2("\n");
961 bufcnt = bufeol - bufp;
962 printf("--(%d/%d @%d)\n", bufcnt, buflen, bufpos);
963 memcpy(scrbuf, bufp, bufcnt);
964 scrbuf[bufcnt] = 0;
965 printf("%s", scrbuf);
966 bufp = bufeol;
967 bufpos += bufcnt;
968 if (bufpos == buflen)
969 break;
970 inc = rosh_getkey();
971 numln = 1;
972 switch (inc) {
973 case KEY_CTRL('c'):
974 case 'q':
975 case 'Q':
976 bufpos = buflen;
977 break;
978 case ' ':
979 numln = rows - 1;
982 } /* rosh_more_buf */
984 /* Page through a single file using the open file stream
985 * fd File Descriptor
987 void rosh_more_fd(int fd, int rows, int cols, char *scrbuf)
989 struct stat fdstat;
990 char *buf;
991 int bufpos;
992 int numrd;
993 FILE *f;
995 fstat(fd, &fdstat);
996 if (S_ISREG(fdstat.st_mode)) {
997 buf = malloc((int)fdstat.st_size);
998 if (buf != NULL) {
999 f = fdopen(fd, "r");
1000 bufpos = 0;
1001 numrd = fread(buf, 1, (int)fdstat.st_size, f);
1002 while (numrd > 0) {
1003 bufpos += numrd;
1004 numrd = fread(buf + bufpos, 1,
1005 ((int)fdstat.st_size - bufpos), f);
1007 fclose(f);
1008 rosh_more_buf(buf, bufpos, rows, cols, scrbuf);
1010 } else {
1013 } /* rosh_more_fd */
1015 /* Page through a file like the more command
1016 * argc Argument Count
1017 * argv Argument Values
1019 void rosh_more(int argc, char *argv[])
1021 int fd, i;
1022 /* char filestr[ROSH_PATH_SZ];
1023 int cmdpos;*/
1024 int rows, cols;
1025 char *scrbuf;
1026 int ret;
1028 ROSH_DEBUG_ARGV_V(argc, argv);
1029 ret = getscreensize(1, &rows, &cols);
1030 if (ret) {
1031 ROSH_DEBUG("getscreensize() fail(%d); fall back\n", ret);
1032 ROSH_DEBUG("\tROWS='%d'\tCOLS='%d'\n", rows, cols);
1033 /* If either fail, go under normal size, just in case */
1034 if (!rows)
1035 rows = 20;
1036 if (!cols)
1037 cols = 75;
1039 ROSH_DEBUG("\tUSE ROWS='%d'\tCOLS='%d'\n", rows, cols);
1040 /* 32 bit align beginning of row and over allocate */
1041 scrbuf = malloc(rows * ((cols+3)&(INT_MAX - 3)));
1042 if (!scrbuf)
1043 return;
1045 if (argc) {
1046 /* There is no need to mess up the console if we don't have a
1047 file */
1048 rosh_console_raw();
1049 for (i = 0; i < argc; i++) {
1050 printf("--File = '%s'\n", argv[i]);
1051 errno = 0;
1052 fd = open(argv[i], O_RDONLY);
1053 if (fd != -1) {
1054 rosh_more_fd(fd, rows, cols, scrbuf);
1055 close(fd);
1056 } else {
1057 rosh_error(errno, "more", argv[i]);
1058 errno = 0;
1061 rosh_console_std();
1063 free(scrbuf);
1064 } /* rosh_more */
1066 /* Page a file with rewind
1067 * argc Argument Count
1068 * argv Argument Values
1070 void rosh_less(int argc, char *argv[])
1072 printf(" less implemented as more (for now)\n");
1073 rosh_more(argc, argv);
1074 } /* rosh_less */
1076 /* Show PWD
1078 void rosh_pwd(void)
1080 char pwdstr[ROSH_PATH_SZ];
1081 errno = 0;
1082 if (getcwd(pwdstr, ROSH_PATH_SZ)) {
1083 printf("%s\n", pwdstr);
1084 } else {
1085 rosh_error(errno, "pwd", "");
1086 errno = 0;
1088 } /* rosh_pwd */
1090 /* Reboot; use warm reboot if one of certain options set
1091 * argc Argument count
1092 * argv Argument values
1094 void rosh_reboot(int argc, char *argv[])
1096 int rtype = 0;
1097 if (argc) {
1098 /* For now, just use the first */
1099 switch (argv[0][0]) {
1100 case '1':
1101 case 's':
1102 case 'w':
1103 rtype = 1;
1104 break;
1105 case '-':
1106 switch (argv[0][1]) {
1107 case '1':
1108 case 's':
1109 case 'w':
1110 rtype = 1;
1111 break;
1113 break;
1116 syslinux_reboot(rtype);
1117 } /* rosh_reboot */
1119 /* Run a boot string, calling syslinux_run_command
1120 * argc Argument count
1121 * argv Argument values
1123 void rosh_run(int argc, char *argv[])
1125 char cmdstr[ROSH_CMD_SZ];
1126 int len;
1128 len = rosh_argcat(cmdstr, ROSH_CMD_SZ, argc, argv, 0);
1129 if (len) {
1130 printf("--run: '%s'\n", cmdstr);
1131 syslinux_run_command(cmdstr);
1132 } else {
1133 printf(APP_NAME ":run: No arguments\n");
1135 } /* rosh_run */
1137 /* Process an argc/argv pair and call handling function
1138 * argc Argument count
1139 * argv Argument values
1140 * ipwdstr Initial Present Working Directory string
1141 * returns Whether to exit prompt
1143 char rosh_command(int argc, char *argv[], const char *ipwdstr)
1145 char do_exit = false;
1146 int tlen;
1147 tlen = strlen(argv[0]);
1148 ROSH_DEBUG_ARGV_V(argc, argv);
1149 switch (argv[0][0]) {
1150 case 'e':
1151 case 'E':
1152 case 'q':
1153 case 'Q':
1154 switch (argv[0][1]) {
1155 case 0:
1156 case 'x':
1157 case 'X':
1158 case 'u':
1159 case 'U':
1160 if ((strncasecmp("exit", argv[0], tlen) == 0) ||
1161 (strncasecmp("quit", argv[0], tlen) == 0))
1162 do_exit = true;
1163 else
1164 rosh_help(1, argv[0]);
1165 break;
1166 case 'c':
1167 case 'C':
1168 if (strncasecmp("echo", argv[0], tlen) == 0)
1169 rosh_pr_argv(argc - 1, &argv[1]);
1170 else
1171 rosh_help(1, argv[0]);
1172 break;
1173 default:
1174 rosh_help(1, argv[0]);
1176 break;
1177 case 'c':
1178 case 'C': /* run 'cd' 'cat' 'cfg' */
1179 switch (argv[0][1]) {
1180 case 'a':
1181 case 'A':
1182 if (strncasecmp("cat", argv[0], tlen) == 0)
1183 rosh_cat(argc - 1, &argv[1]);
1184 else
1185 rosh_help(1, argv[0]);
1186 break;
1187 case 'd':
1188 case 'D':
1189 if (strncasecmp("cd", argv[0], tlen) == 0)
1190 rosh_cd(argc, argv, ipwdstr);
1191 else
1192 rosh_help(1, argv[0]);
1193 break;
1194 case 'f':
1195 case 'F':
1196 if (strncasecmp("cfg", argv[0], tlen) == 0)
1197 rosh_cfg();
1198 else
1199 rosh_help(1, argv[0]);
1200 break;
1201 default:
1202 rosh_help(1, argv[0]);
1204 break;
1205 case 'd':
1206 case 'D': /* run 'dir' */
1207 if (strncasecmp("dir", argv[0], tlen) == 0)
1208 rosh_dir(argc - 1, &argv[1]);
1209 else
1210 rosh_help(1, argv[0]);
1211 break;
1212 case 'h':
1213 case 'H':
1214 case '?':
1215 if ((strncasecmp("help", argv[0], tlen) == 0) || (tlen == 1))
1216 rosh_help(2, argv[1]);
1217 else
1218 rosh_help(1, NULL);
1219 break;
1220 case 'l':
1221 case 'L': /* run 'ls' 'less' */
1222 switch (argv[0][1]) {
1223 case 0:
1224 case 's':
1225 case 'S':
1226 if (strncasecmp("ls", argv[0], tlen) == 0)
1227 rosh_ls(argc, argv);
1228 else
1229 rosh_help(1, argv[0]);
1230 break;
1231 case 'e':
1232 case 'E':
1233 if (strncasecmp("less", argv[0], tlen) == 0)
1234 rosh_less(argc - 1, &argv[1]);
1235 else
1236 rosh_help(1, argv[0]);
1237 break;
1238 default:
1239 rosh_help(1, argv[0]);
1241 break;
1242 case 'm':
1243 case 'M':
1244 switch (argv[0][1]) {
1245 case 'a':
1246 case 'A':
1247 if (strncasecmp("man", argv[0], tlen) == 0)
1248 rosh_help(2, argv[1]);
1249 else
1250 rosh_help(1, argv[0]);
1251 break;
1252 case 'o':
1253 case 'O':
1254 if (strncasecmp("more", argv[0], tlen) == 0)
1255 rosh_more(argc - 1, &argv[1]);
1256 else
1257 rosh_help(1, argv[0]);
1258 break;
1259 default:
1260 rosh_help(1, argv[0]);
1262 break;
1263 case 'p':
1264 case 'P': /* run 'pwd' */
1265 if (strncasecmp("pwd", argv[0], tlen) == 0)
1266 rosh_pwd();
1267 else
1268 rosh_help(1, argv[0]);
1269 break;
1270 case 'r':
1271 case 'R': /* run 'run' */
1272 switch (argv[0][1]) {
1273 case 0:
1274 case 'e':
1275 case 'E':
1276 if (strncasecmp("reboot", argv[0], tlen) == 0)
1277 rosh_reboot(argc - 1, &argv[1]);
1278 else
1279 rosh_help(1, argv[0]);
1280 break;
1281 case 'u':
1282 case 'U':
1283 if (strncasecmp("run", argv[0], tlen) == 0)
1284 rosh_run(argc - 1, &argv[1]);
1285 else
1286 rosh_help(1, argv[0]);
1287 break;
1288 default:
1289 rosh_help(1, argv[0]);
1291 break;
1292 case 'v':
1293 case 'V':
1294 if (strncasecmp("version", argv[0], tlen) == 0)
1295 rosh_version(1);
1296 else
1297 rosh_help(1, argv[0]);
1298 break;
1299 case 0:
1300 case '\n':
1301 break;
1302 default:
1303 rosh_help(1, argv[0]);
1304 } /* switch(argv[0][0]) */
1305 return do_exit;
1306 } /* rosh_command */
1308 /* Process the prompt for commands as read from stdin and call rosh_command
1309 * to process command line string
1310 * icmdstr Initial command line string
1311 * returns Exit status
1313 int rosh_prompt(int iargc, char *iargv[])
1315 int rv;
1316 char cmdstr[ROSH_CMD_SZ];
1317 char ipwdstr[ROSH_PATH_SZ];
1318 char do_exit;
1319 char **argv;
1320 int argc;
1322 rv = 0;
1323 do_exit = false;
1324 if (!getcwd(ipwdstr, ROSH_PATH_SZ))
1325 strcpy(ipwdstr, "./");
1326 if (iargc > 1)
1327 do_exit = rosh_command(iargc - 1, &iargv[1], ipwdstr);
1328 while (!(do_exit)) {
1329 /* Extra preceeding newline */
1330 printf("\nrosh: ");
1331 /* Read a line from console */
1332 if (fgets(cmdstr, ROSH_CMD_SZ, stdin)) {
1333 argc = rosh_str2argv(&argv, cmdstr);
1334 do_exit = rosh_command(argc, argv, ipwdstr);
1335 rosh_free_argv(&argv);
1336 } else {
1337 do_exit = false;
1340 return rv;
1343 int main(int argc, char *argv[])
1345 int rv;
1347 /* Initialization */
1348 rv = 0;
1349 rosh_console_std();
1350 if (argc == 1) {
1351 rosh_version(0);
1352 print_beta();
1353 } else {
1354 #ifdef DO_DEBUG
1355 char cmdstr[ROSH_CMD_SZ];
1356 rosh_argcat(cmdstr, ROSH_CMD_SZ, argc, argv, 1);
1357 ROSH_DEBUG("arg='%s'\n", cmdstr);
1358 #endif
1360 rv = rosh_prompt(argc, argv);
1361 printf("--Exiting '" APP_NAME "'\n");
1362 return rv;