source: bootcd/isolinux/syslinux-6.03/com32/rosh/rosh.c

Last change on this file was e16e8f2, checked in by Edwin Eefting <edwin@datux.nl>, 3 years ago

bootstuff

  • Property mode set to 100644
File size: 30.6 KB
Line 
1/* ----------------------------------------------------------------------- *
2 *
3 *   Copyright 2008-2011 Gene Cumm - All Rights Reserved
4 *
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.
10 *
11 * ----------------------------------------------------------------------- */
12
13/*
14 * rosh.c
15 *
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.
19 */
20
21/*
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
29 */
30
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.
38 */
39#include "rosh.h"
40#include "version.h"
41
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"
47
48/* Print version information to stdout
49 */
50void rosh_version(int vtype)
51{
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);
59    }
60}
61
62/* Print beta message and if DO_DEBUG/DO_DEBUG2 are active
63 */
64void print_beta(void)
65{
66    puts(rosh_beta_str);
67    ROSH_DEBUG("DO_DEBUG active\n");
68    ROSH_DEBUG2("DO_DEBUG2 active\n");
69}
70
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
74 */
75int rosh_search_nonsp(const char *istr, const int ipos)
76{
77    int curpos;
78    char c;
79
80    curpos = ipos;
81    c = istr[curpos];
82    while (c && isspace(c))
83        c = istr[++curpos];
84    return curpos;
85}
86
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
91 */
92int rosh_search_sp(const char *istr, const int ipos)
93{
94    int curpos;
95    char c;
96
97    curpos = ipos;
98    c = istr[curpos];
99    while (c && !(isspace(c)))
100        c = istr[++curpos];
101    return curpos;
102}
103
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
109 */
110int rosh_parse_sp_1(char *dest, const char *src, const int ipos)
111{
112    int bpos, epos;             /* beginning and ending position of source string
113                                   to copy to destination string */
114
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;
127    }
128    return epos;
129}
130
131/*
132 * parse_args1: Try 1 at parsing a string to an argc/argv pair.  use free_args1 to free memory malloc'd
133 *
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
137 */
138int parse_args1(char ***iargv, const char *istr)
139{
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 */
144
145    /* Scan 1: Length */
146    /* I could eliminate this if I knew a max length, like strncpy() */
147    int len = strlen(istr);
148
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';
158            }
159        } else {
160            if (sp) {
161                argc++;
162                sp = 0;
163            }
164            *q++ = *p;
165        }
166        if (!*p)
167            break;
168    }
169
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;
181        }
182    }
183
184fail_args:
185    return argc;
186fail_args_ptr:
187    free(args);
188    return 0;
189}
190
191/* Free argv created by parse_args1()
192 *      argv    Argument Values
193 */
194void free_args1(char ***argv)
195{
196    char *s;
197    s = **argv;
198    free(*argv);
199    free(s);
200}
201
202/* Convert a string to an argc/argv pair
203 *      str     String to parse
204 *      argv    Argument Values
205 *      returns Argument Count
206 */
207int rosh_str2argv(char ***argv, const char *str)
208{
209    return parse_args1(argv, str);
210}
211
212/* Free an argv created by rosh_str2argv()
213 *      argv    Argument Values to free
214 */
215void rosh_free_argv(char ***argv)
216{
217     free_args1(argv);
218}
219
220/* Print the contents of an argc/argv pair
221 *      argc    Argument Count
222 *      argv    Argument Values
223 */
224void rosh_pr_argv(int argc, char *argv[])
225{
226    int i;
227    for (i = 0; i < argc; i++) {
228        printf("%s%s", argv[i], (i < argc)? " " : "");
229    }
230    puts("");
231}
232
233/* Print the contents of an argc/argv pair verbosely
234 *      argc    Argument Count
235 *      argv    Argument Values
236 */
237void rosh_pr_argv_v(int argc, char *argv[])
238{
239    int i;
240    for (i = 0; i < argc; i++) {
241        printf("%4d '%s'\n", i, argv[i]);
242    }
243}
244
245/* Reset the getopt() environment
246 */
247void rosh_getopt_reset(void)
248{
249    optind = 0;
250    optopt = 0;
251}
252
253/* Display help
254 *      type    Help type
255 *      cmdstr  Command for which help is requested
256 */
257void rosh_help(int type, const char *cmdstr)
258{
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);
274            }
275        }
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);
283    }
284}
285
286/* Handle most/all errors
287 *      ierrno  Input Error number
288 *      cmdstr  Command being executed to cause error
289 *      filestr File/parameter causing error
290 */
291void rosh_error(const int ierrno, const char *cmdstr, const char *filestr)
292{
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);
325    }
326}                               /* rosh_error */
327
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
334 */
335int rosh_argcat(char *cmdstr, const int cmdlen, const int argc, char *argv[],
336                const int barg)
337{
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;
360        }
361    }
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 */
368
369/*
370 * Prints a lot of the data in a struct termios
371 */
372/*
373void rosh_print_tc(struct termios *tio)
374{
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");
383}
384*/
385
386/*
387 * Attempts to get a single key from the console
388 *      returns key pressed
389 */
390int rosh_getkey(void)
391{
392    int inc;
393
394    inc = KEY_NONE;
395    while (inc == KEY_NONE)
396        inc = get_key(stdin, 6000);
397    return inc;
398}                               /* rosh_getkey */
399
400/*
401 * Qualifies a filename relative to the working directory
402 *      filestr Filename to qualify
403 *      pwdstr  working directory
404 *      returns qualified file name string
405 */
406void rosh_qualify_filestr(char *filestr, const char *ifilstr,
407                          const char *pwdstr)
408{
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;
416        }
417        strcpy(filestr + filepos, ifilstr);
418        ROSH_DEBUG("--'%s'\n", filestr);
419    }
420}
421
422/* Concatenate multiple files to stdout
423 *      argc    Argument Count
424 *      argv    Argument Values
425 */
426void rosh_cat(int argc, char *argv[])
427{
428    FILE *f;
429    char buf[ROSH_BUF_SZ];
430    int i, numrd;
431
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);
441            }
442            fclose(f);
443        } else {
444            rosh_error(errno, "cat", argv[i]);
445            errno = 0;
446        }
447    }
448}                               /* rosh_cat */
449
450/* Change PWD (Present Working Directory)
451 *      argc    Argument count
452 *      argv    Argument values
453 *      ipwdstr Initial PWD
454 */
455void rosh_cd(int argc, char *argv[], const char *ipwdstr)
456{
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 */
481    }
482}                               /* rosh_cd */
483
484/* Print the syslinux config file name
485 */
486void rosh_cfg(void)
487{
488    printf("CFG:     '%s'\n", syslinux_config_file());
489}                               /* rosh_cfg */
490
491/* Echo a string back to the screen
492 *      cmdstr  command string to process
493 */
494void rosh_echo(const char *cmdstr)
495{
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("");
504    }
505}                               /* rosh_echo */
506
507/* Process argc/argv to optarr
508 *      argc    Argument count
509 *      argv    Argument values
510 *      optarr  option array to populate
511 */
512void rosh_ls_arg_opt(int argc, char *argv[], int optarr[])
513{
514    int rv = 0;
515
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;
541        }
542    }
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 */
547
548/* Retrieve the size of a file argument
549 *      filestr directory name of directory entry
550 *      de      directory entry
551 */
552int rosh_ls_de_size(const char *filestr, struct dirent *de)
553{
554    int de_size;
555    char filestr2[ROSH_PATH_SZ];
556    int fd2, file2pos;
557    struct stat fdstat;
558
559    filestr2[0] = 0;
560    file2pos = -1;
561    if (filestr) {
562        file2pos = strlen(filestr);
563        memcpy(filestr2, filestr, file2pos);
564        filestr2[file2pos] = '/';
565    }
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 */
573
574/* Retrieve the size and mode of a file
575 *      filestr directory name of directory entry
576 *      de      directory entry
577 */
578int rosh_ls_de_size_mode(const char *filestr, struct dirent *de, mode_t * st_mode)
579{
580    int de_size;
581    char filestr2[ROSH_PATH_SZ];
582    int file2pos;
583    struct stat fdstat;
584    int status;
585
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;
598        }
599    }
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;
609    }
610    de_size = (int)fdstat.st_size;
611    *st_mode = fdstat.st_mode;
612    return de_size;
613}                               /* rosh_ls_de_size_mode */
614
615/* Returns the Inode number if fdstat contains it
616 *      fdstat  struct to extract inode from if not COM32, for now
617 */
618long rosh_ls_d_ino(struct stat *fdstat)
619{
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;
630}
631
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
635 */
636char rosh_d_type2char_human(unsigned char d_type)
637{
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 = ' ';
669    }
670    return ret;
671}                               /* rosh_d_type2char_human */
672
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
676 */
677char rosh_d_type2char_lspre(unsigned char d_type)
678{
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 = '?';
704    }
705    return ret;
706}                               /* rosh_d_type2char_lspre */
707
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
711 */
712char rosh_d_type2char_lssuf(unsigned char d_type)
713{
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 = ' ';
730    }
731    return ret;
732}                               /* rosh_d_type2char_lssuf */
733
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
737 */
738void rosh_st_mode_am2str(mode_t st_mode, char *st_mode_str)
739{
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' : '-');
743}
744
745/* Converts st_mode to an ls-style string
746 *      st_mode mode to convert
747 *      st_mode_str     string to hold converted string
748 */
749void rosh_st_mode2str(mode_t st_mode, char *st_mode_str)
750{
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 */
757
758/* Output a single entry
759 *      filestr directory name to list
760 *      de      directory entry
761 *      optarr  Array of options
762 */
763void rosh_ls_arg_dir_de(const char *filestr, struct dirent *de, const int *optarr)
764{
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);
777    }
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 */
785
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
791 */
792void rosh_ls_arg_dir(const char *filestr, DIR * d, const int *optarr)
793{
794    struct dirent *de;
795    int filepos;
796
797    filepos = 0;
798    errno = 0;
799    while ((de = readdir(d))) {
800        filepos++;
801        rosh_ls_arg_dir_de(filestr, de, optarr);
802    }
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");
808    }
809}                               /* rosh_ls_arg_dir */
810
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
816 */
817void rosh_ls_arg(const char *filestr, const int *optarr)
818{
819    struct stat fdstat;
820    int status;
821//     char filestr[ROSH_PATH_SZ];
822//     int filepos;
823    DIR *d;
824    struct dirent de;
825
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]);
833
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;
846            }
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);
855            }
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);*/
861        }
862    } else {
863        rosh_error(errno, "ls", filestr);
864        errno = 0;
865    }
866    return;
867}                               /* rosh_ls_arg */
868
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
873 */
874int rosh_ls_parse_opt(const char *filestr, char *optstr)
875{
876    int ret;
877    if (filestr[0] == '-') {
878        ret = 0;
879        if (optstr)
880            strcat(optstr, filestr + 1);
881    } else {
882        ret = 1;
883    }
884    ROSH_DEBUG("ParseOpt: '%s'\n\topt: '%s'\n\tret: %d\n", filestr, optstr,
885               ret);
886    return ret;
887}                               /* rosh_ls_parse_opt */
888
889/* List Directory
890 *      argc    Argument count
891 *      argv    Argument values
892 */
893void rosh_ls(int argc, char *argv[])
894{
895    int optarr[3];
896    int i;
897
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);
909    }
910}                               /* rosh_ls */
911
912/* Simple directory listing; calls rosh_ls()
913 *      argc    Argument count
914 *      argv    Argument values
915 */
916void rosh_dir(int argc, char *argv[])
917{
918    ROSH_DEBUG("  dir implemented as ls\n");
919    rosh_ls(argc, argv);
920}                               /* rosh_dir */
921
922/* Page through a buffer string
923 *      buf     Buffer to page through
924 */
925void rosh_more_buf(char *buf, int buflen, int rows, int cols, char *scrbuf)
926{
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 */
933
934    (void)cols;
935
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;
958            }
959        }
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;
980        }
981    }
982}                               /* rosh_more_buf */
983
984/* Page through a single file using the open file stream
985 *      fd      File Descriptor
986 */
987void rosh_more_fd(int fd, int rows, int cols, char *scrbuf)
988{
989    struct stat fdstat;
990    char *buf;
991    int bufpos;
992    int numrd;
993    FILE *f;
994
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);
1006            }
1007            fclose(f);
1008            rosh_more_buf(buf, bufpos, rows, cols, scrbuf);
1009        }
1010    } else {
1011    }
1012
1013}                               /* rosh_more_fd */
1014
1015/* Page through a file like the more command
1016 *      argc    Argument Count
1017 *      argv    Argument Values
1018 */
1019void rosh_more(int argc, char *argv[])
1020{
1021    int fd, i;
1022/*    char filestr[ROSH_PATH_SZ];
1023    int cmdpos;*/
1024    int rows, cols;
1025    char *scrbuf;
1026    int ret;
1027
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;
1038    }
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;
1044
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;
1059            }
1060        }
1061        rosh_console_std();
1062    }
1063    free(scrbuf);
1064}                               /* rosh_more */
1065
1066/* Page a file with rewind
1067 *      argc    Argument Count
1068 *      argv    Argument Values
1069 */
1070void rosh_less(int argc, char *argv[])
1071{
1072    printf("  less implemented as more (for now)\n");
1073    rosh_more(argc, argv);
1074}                               /* rosh_less */
1075
1076/* Show PWD
1077 */
1078void rosh_pwd(void)
1079{
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;
1087    }
1088}                               /* rosh_pwd */
1089
1090/* Reboot; use warm reboot if one of certain options set
1091 *      argc    Argument count
1092 *      argv    Argument values
1093 */
1094void rosh_reboot(int argc, char *argv[])
1095{
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;
1112            }
1113            break;
1114        }
1115    }
1116    syslinux_reboot(rtype);
1117}                               /* rosh_reboot */
1118
1119/* Run a boot string, calling syslinux_run_command
1120 *      argc    Argument count
1121 *      argv    Argument values
1122 */
1123void rosh_run(int argc, char *argv[])
1124{
1125    char cmdstr[ROSH_CMD_SZ];
1126    int len;
1127
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");
1134    }
1135}                               /* rosh_run */
1136
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
1142 */
1143char rosh_command(int argc, char *argv[], const char *ipwdstr)
1144{
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]);
1175        }
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]);
1203        }
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]);
1240        }
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]);
1261        }
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]);
1290        }
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 */
1307
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
1312 */
1313int rosh_prompt(int iargc, char *iargv[])
1314{
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;
1321
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;
1338        }
1339    }
1340    return rv;
1341}
1342
1343int main(int argc, char *argv[])
1344{
1345    int rv;
1346
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
1359    }
1360    rv = rosh_prompt(argc, argv);
1361    printf("--Exiting '" APP_NAME "'\n");
1362    return rv;
1363}
Note: See TracBrowser for help on using the repository browser.