diff options
-rw-r--r-- | com32/include/unistd.h | 4 | ||||
-rw-r--r-- | com32/rosh/rosh.c | 658 | ||||
-rw-r--r-- | com32/rosh/rosh.h | 18 | ||||
-rw-r--r-- | core/pxelinux.asm | 21 | ||||
-rw-r--r-- | core/writedec.inc | 5 | ||||
-rw-r--r-- | modules/Makefile | 2 | ||||
-rw-r--r-- | modules/ver.asm | 606 |
7 files changed, 1057 insertions, 257 deletions
diff --git a/com32/include/unistd.h b/com32/include/unistd.h index fc514f10..9e13381a 100644 --- a/com32/include/unistd.h +++ b/com32/include/unistd.h @@ -28,6 +28,10 @@ __extern int chdir(const char *); __extern unsigned int sleep(unsigned int); __extern unsigned int msleep(unsigned int); +__extern int getopt(int, char *const *, const char *); +__extern char *optarg; +__extern int optind, opterr, optopt; + /* Standard file descriptor numbers. */ #define STDIN_FILENO 0 #define STDOUT_FILENO 1 diff --git a/com32/rosh/rosh.c b/com32/rosh/rosh.c index 9efa35ef..12e09995 100644 --- a/com32/rosh/rosh.c +++ b/com32/rosh/rosh.c @@ -20,7 +20,12 @@ /* * ToDos: - * rosh_ls(): sorted; then multiple columns + * prompt: Allow left/right arrow, home/end and more? + * commands Break into argv/argc-like array + * rosh_cfg: allow -s <file> to change config + * rosh_ls(): sorted; then multiple columns + * prompt: Possibly honor timeout on initial entry for usage as UI + * Also possibly honor totaltimeout */ /*#define DO_DEBUG 1 @@ -38,8 +43,10 @@ #define APP_NAME "rosh" #define APP_AUTHOR "Gene Cumm" #define APP_YEAR "2010" -#define APP_VER "beta-b068" +#define APP_VER "beta-b089" +/* Print version information to stdout + */ void rosh_version(int vtype) { char env[256]; @@ -52,6 +59,8 @@ void rosh_version(int vtype) } } +/* Print beta message and if DO_DEBUG/DO_DEBUG2 are active + */ void print_beta(void) { puts(rosh_beta_str); @@ -119,32 +128,156 @@ int rosh_parse_sp_1(char *dest, const char *src, const int ipos) return epos; } +/* + * parse_args1: Try 1 at parsing a string to an argc/argv pair. use free_args1 to free memory malloc'd + * + * Derived from com32/lib/sys/argv.c:__parse_argv() + * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + */ +int parse_args1(char ***iargv, const char *istr) +{ + int argc = 0; + const char *p; + char *q, *r, *args, **arg; + int sp = 1; //, qt = 0; /* Was a space; inside a quote */ + + /* Scan 1: Length */ + /* I could eliminate this if I knew a max length, like strncpy() */ + int len = strlen(istr); + + /* Scan 2: Copy, nullify and make argc */ + if (!(args = malloc(len + 1))) + goto fail_args; + q = args; + for (p = istr;; p++) { + if (*p <= ' ') { + if (!sp) { + sp = 1; + *q++ = '\0'; + } + } else { + if (sp) { + argc++; + sp = 0; + } + *q++ = *p; + } + if (!*p) + break; + } + + q--; /* Point q to final null */ + /* Scan 3: Build array of pointers */ + if (!(*iargv = malloc((argc + 1) * sizeof(char *)))) + goto fail_args_ptr; + arg = *iargv; + arg[argc] = NULL; /* Nullify the last pointer */ + if (*args != '\0') + *arg++ = args; + for (r = args; r < q ; r++) { + if (*r == '\0') { + *arg++ = r + 1; + } + } + +fail_args: + return argc; +fail_args_ptr: + free(args); + return 0; +} + +/* Free argv created by parse_args1() + * argv Argument Values + */ +void free_args1(char ***argv) +{ + char *s; + s = **argv; + free(*argv); + free(s); +} + +/* Convert a string to an argc/argv pair + * str String to parse + * argv Argument Values + * returns Argument Count + */ +int rosh_str2argv(char ***argv, const char *str) +{ + return parse_args1(argv, str); +} + +/* Free an argv created by rosh_str2argv() + * argv Argument Values to free + */ +void rosh_free_argv(char ***argv) +{ + free_args1(argv); +} + +/* Print the contents of an argc/argv pair + * argc Argument Count + * argv Argument Values + */ +void rosh_pr_argv(int argc, char *argv[]) +{ + int i; + for (i = 0; i < argc; i++) { + printf("%s%s", argv[i], (i < argc)? " " : ""); + } + puts(""); +} + +/* Print the contents of an argc/argv pair verbosely + * argc Argument Count + * argv Argument Values + */ +void rosh_pr_argv_v(int argc, char *argv[]) +{ + int i; + for (i = 0; i < argc; i++) { + printf("%4d '%s'\n", i, argv[i]); + } +} + +/* Reset the getopt() environment + */ +void rosh_getopt_reset(void) +{ + optind = 0; + optopt = 0; +} + /* Display help * type Help type - * cmdstr Command string + * cmdstr Command for which help is requested */ void rosh_help(int type, const char *cmdstr) { - const char *istr; - istr = cmdstr; switch (type) { case 2: - istr += rosh_search_nonsp(cmdstr, rosh_search_sp(cmdstr, 0)); - if ((cmdstr == NULL) || (strcmp(istr, "") == 0)) { + if ((cmdstr == NULL) || (strcmp(cmdstr, "") == 0)) { rosh_version(0); puts(rosh_help_str2); } else { - switch (istr[0]) { + switch (cmdstr[0]) { + case 'c': + puts(rosh_help_cd_str); + break; case 'l': puts(rosh_help_ls_str); break; default: - printf(rosh_help_str_adv, istr); + printf(rosh_help_str_adv, cmdstr); } } break; case 1: default: + if (cmdstr) + printf("%s: %s: unknown command\n", APP_NAME, cmdstr); rosh_version(0); puts(rosh_help_str1); } @@ -194,11 +327,13 @@ void rosh_error(const int ierrno, const char *cmdstr, const char *filestr) /* Concatenate command line arguments into one string * cmdstr Output command string + * cmdlen Length of cmdstr * argc Argument Count * argv Argument Values * barg Beginning Argument */ -int rosh_argcat(char *cmdstr, const int argc, char *argv[], const int barg) +int rosh_argcat(char *cmdstr, const int cmdlen, const int argc, char *argv[], + const int barg) { int i, arglen, curpos; /* index, argument length, current position in cmdstr */ @@ -207,15 +342,15 @@ int rosh_argcat(char *cmdstr, const int argc, char *argv[], const int barg) for (i = barg; i < argc; i++) { arglen = strlen(argv[i]); /* Theoretically, this should never be met in SYSLINUX */ - if ((curpos + arglen) > (ROSH_CMD_SZ - 1)) - arglen = (ROSH_CMD_SZ - 1) - curpos; + if ((curpos + arglen) > (cmdlen - 1)) + arglen = (cmdlen - 1) - curpos; memcpy(cmdstr + curpos, argv[i], arglen); curpos += arglen; - if (curpos >= (ROSH_CMD_SZ - 1)) { + if (curpos >= (cmdlen - 1)) { /* Hopefully, curpos should not be greater than - (ROSH_CMD_SZ - 1) */ + (cmdlen - 1) */ /* Still need a '\0' at the last character */ - cmdstr[(ROSH_CMD_SZ - 1)] = 0; + cmdstr[(cmdlen - 1)] = 0; break; /* Escape out of the for() loop; We can no longer process anything more */ } else { @@ -285,26 +420,19 @@ void rosh_qualify_filestr(char *filestr, const char *ifilstr, } /* Concatenate multiple files to stdout - * cmdstr command string to process + * argc Argument Count + * argv Argument Values */ -void rosh_cat(const char *cmdstr) +void rosh_cat(int argc, char *argv[]) { FILE *f; - char filestr[ROSH_PATH_SZ]; char buf[ROSH_BUF_SZ]; - int numrd; - int cmdpos; + int i, numrd; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* Initialization */ - filestr[0] = 0; - cmdpos = 0; - /* skip the first word */ - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - while (strlen(filestr) > 0) { - printf("--File = '%s'\n", filestr); - f = fopen(filestr, "r"); + for (i = 0; i < argc; i++) { + printf("--File = '%s'\n", argv[i]); + errno = 0; + f = fopen(argv[i], "r"); if (f != NULL) { numrd = fread(buf, 1, ROSH_BUF_SZ, f); while (numrd > 0) { @@ -313,36 +441,37 @@ void rosh_cat(const char *cmdstr) } fclose(f); } else { - rosh_error(errno, "cat", filestr); + rosh_error(errno, "cat", argv[i]); errno = 0; } - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); } } /* rosh_cat */ /* Change PWD (Present Working Directory) - * cmdstr command string to process + * argc Argument count + * argv Argument values * ipwdstr Initial PWD */ -void rosh_cd(const char *cmdstr, const char *ipwdstr) +void rosh_cd(int argc, char *argv[], const char *ipwdstr) { - int rv; + int rv = 0; +#ifdef DO_DEBUG char filestr[ROSH_PATH_SZ]; - int cmdpos; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* Initialization */ - filestr[0] = 0; - cmdpos = 0; - rv = 0; - /* skip the first word */ - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - if (strlen(filestr) != 0) - rv = chdir(filestr); - else +#endif /* DO_DEBUG */ + ROSH_DEBUG("CMD: \n"); + ROSH_DEBUG_ARGV_V(argc, argv); + errno = 0; + if (argc == 2) + rv = chdir(argv[1]); + else if (argc == 1) rv = chdir(ipwdstr); + else + rosh_help(2, argv[0]); if (rv != 0) { - rosh_error(errno, "cd", filestr); + if (argc == 2) + rosh_error(errno, "cd", argv[1]); + else + rosh_error(errno, "cd", ipwdstr); errno = 0; } else { #ifdef DO_DEBUG @@ -359,31 +488,61 @@ void rosh_cfg(void) printf("CFG: '%s'\n", syslinux_config_file()); } /* rosh_cfg */ -/* Process optstr to optarr - * optstr option string to process - * optarr option array to populate +/* Echo a string back to the screen + * cmdstr command string to process */ -void rosh_ls_arg_opt(const char *optstr, int *optarr) +void rosh_echo(const char *cmdstr) { - char *cpos; - cpos = strchr(optstr, 'l'); - if (cpos) { - optarr[0] = cpos - optstr; - } else { - optarr[0] = -1; - } - cpos = strchr(optstr, 'F'); - if (cpos) { - optarr[1] = cpos - optstr; + int bpos = 0; + ROSH_DEBUG("CMD: '%s'\n", cmdstr); + bpos = rosh_search_nonsp(cmdstr, rosh_search_sp(cmdstr, 0)); + if (bpos > 1) { + ROSH_DEBUG(" bpos=%d\n", bpos); + printf("'%s'\n", cmdstr + bpos); } else { - optarr[1] = -1; + puts(""); } - cpos = strchr(optstr, 'i'); - if (cpos) { - optarr[2] = cpos - optstr; - } else { - optarr[2] = -1; +} /* rosh_echo */ + +/* Process argc/argv to optarr + * argc Argument count + * argv Argument values + * optarr option array to populate + */ +void rosh_ls_arg_opt(int argc, char *argv[], int optarr[]) +{ + int rv = 0; + + optarr[0] = -1; + optarr[1] = -1; + optarr[2] = -1; + rosh_getopt_reset(); + while (rv != -1) { + ROSH_DEBUG2("getopt optind=%d rv=%d\n", optind, rv); + rv = getopt(argc, argv, rosh_ls_opt_str); + switch (rv) { + case 'l': + case 0: + optarr[0] = 1; + break; + case 'F': + case 1: + optarr[1] = 1; + break; + case 'i': + case 2: + optarr[2] = 1; + break; + case '?': + case -1: + default: + ROSH_DEBUG2("getopt optind=%d rv=%d\n", optind, rv); + break; + } } + ROSH_DEBUG2(" end getopt optind=%d rv=%d\n", optind, rv); + ROSH_DEBUG2("\tIn rosh_ls_arg_opt() opt[0]=%d\topt[1]=%d\topt[2]=%d\n", optarr[0], optarr[1], + optarr[2]); } /* rosh_ls_arg_opt */ /* Retrieve the size of a file argument @@ -435,6 +594,7 @@ int rosh_ls_de_size_mode(struct dirent *de, mode_t * st_mode) filestr2[file2pos] = '/'; } strcpy(filestr2 + file2pos + 1, de->d_name);*/ + errno = 0; status = stat(de->d_name, &fdstat); ROSH_DEBUG2("\t--stat()=%d\terr=%d\n", status, errno); if (errno) { @@ -628,14 +788,17 @@ void rosh_ls_arg_dir(const char *filestr, DIR * d, const int *optarr) int filepos; filepos = 0; + errno = 0; while ((de = readdir(d))) { filepos++; rosh_ls_arg_dir_de(de, optarr); } - if (errno) + if (errno) { rosh_error(errno, "ls:arg_dir", filestr); - else if (filepos == 0) + errno = 0; + } else { if (filepos == 0) ROSH_DEBUG("0 files found"); + } } /* rosh_ls_arg_dir */ /* Simple directory listing for one argument (file/directory) based on @@ -667,9 +830,13 @@ void rosh_ls_arg(const char *filestr, const int *optarr) if (status == 0) { if (S_ISDIR(fdstat.st_mode)) { ROSH_DEBUG("PATH '%s' is a directory\n", filestr); - d = opendir(filestr); - rosh_ls_arg_dir(filestr, d, optarr); - closedir(d); + if ((d = opendir(filestr))) { + rosh_ls_arg_dir(filestr, d, optarr); + closedir(d); + } else { + rosh_error(errno, "ls", filestr); + errno = 0; + } } else { de.d_ino = rosh_ls_d_ino(&fdstat); de.d_type = (IFTODT(fdstat.st_mode)); @@ -712,71 +879,37 @@ int rosh_ls_parse_opt(const char *filestr, char *optstr) return ret; } /* rosh_ls_parse_opt */ -/* List Directory based on cmdstr and pwdstr - * cmdstr command string to process - * pwdstr Present Working Directory string +/* List Directory + * argc Argument count + * argv Argument values */ -void rosh_ls(const char *cmdstr) +void rosh_ls(int argc, char *argv[]) { - char filestr[ROSH_PATH_SZ]; - char optstr[ROSH_OPT_SZ]; /* Options string */ - int cmdpos, tpos; /* Position within cmdstr, temp position */ - int numargs; /* number of non-option arguments */ - int argpos; /* number of non-option arguments processed */ int optarr[3]; + int i; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* Initialization */ - filestr[0] = 0; - optstr[0] = 0; - cmdpos = 0; - numargs = 0; - argpos = 0; - /* skip the first word */ - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - tpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - /* If there are no real arguments, substitute PWD */ - if (strlen(filestr) == 0) { - strcpy(filestr, "."); - cmdpos = tpos; - } else { /* Parse for command line options */ - while (strlen(filestr) > 0) { - numargs += rosh_ls_parse_opt(filestr, optstr); - tpos = rosh_parse_sp_1(filestr, cmdstr, tpos); - } - if (numargs == 0) { - strcpy(filestr, "."); - cmdpos = tpos; - } else { - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - } - } + rosh_ls_arg_opt(argc, argv, optarr); + ROSH_DEBUG2("In ls()\n"); + ROSH_DEBUG2_ARGV_V(argc, argv); #ifdef DO_DEBUG - if (!strchr(optstr, 'l')) - strcat(optstr, "l"); + optarr[0] = 2; #endif /* DO_DEBUG */ - rosh_ls_arg_opt(optstr, optarr); - ROSH_DEBUG("\tfopt: '%s'\n", optstr); - while (strlen(filestr) > 0) { - if (rosh_ls_parse_opt(filestr, NULL)) { - rosh_ls_arg(filestr, optarr); - argpos++; - } - if (argpos < numargs) - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - else - break; + ROSH_DEBUG2(" argc=%d; optind=%d\n", argc, optind); + if (optind >= argc) + rosh_ls_arg(".", optarr); + for (i = optind; i < argc; i++) { + rosh_ls_arg(argv[i], optarr); } } /* rosh_ls */ /* Simple directory listing; calls rosh_ls() - * cmdstr command string to process - * pwdstr Present Working Directory string + * argc Argument count + * argv Argument values */ -void rosh_dir(const char *cmdstr) +void rosh_dir(int argc, char *argv[]) { ROSH_DEBUG(" dir implemented as ls\n"); - rosh_ls(cmdstr); + rosh_ls(argc, argv); } /* rosh_dir */ /* Page through a buffer string @@ -874,22 +1007,19 @@ void rosh_more_fd(int fd, int rows, int cols, char *scrbuf) } /* rosh_more_fd */ /* Page through a file like the more command - * cmdstr command string to process - * ipwdstr Initial PWD + * argc Argument Count + * argv Argument Values */ -void rosh_more(const char *cmdstr) +void rosh_more(int argc, char *argv[]) { - int fd; - char filestr[ROSH_PATH_SZ]; - int cmdpos; + int fd, i; +/* char filestr[ROSH_PATH_SZ]; + int cmdpos;*/ int rows, cols; char *scrbuf; int ret; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* Initialization */ - filestr[0] = 0; - cmdpos = 0; + ROSH_DEBUG_ARGV_V(argc, argv); ret = getscreensize(1, &rows, &cols); if (ret) { ROSH_DEBUG("getscreensize() fail(%d); fall back\n", ret); @@ -906,24 +1036,21 @@ void rosh_more(const char *cmdstr) if (!scrbuf) return; - /* skip the first word */ - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - if (strlen(filestr) > 0) { + if (argc) { /* There is no need to mess up the console if we don't have a file */ rosh_console_raw(); - while (strlen(filestr) > 0) { - printf("--File = '%s'\n", filestr); - fd = open(filestr, O_RDONLY); + for (i = 0; i < argc; i++) { + printf("--File = '%s'\n", argv[i]); + errno = 0; + fd = open(argv[i], O_RDONLY); if (fd != -1) { rosh_more_fd(fd, rows, cols, scrbuf); close(fd); } else { - rosh_error(errno, "more", filestr); + rosh_error(errno, "more", argv[i]); errno = 0; } - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); } rosh_console_std(); } @@ -931,26 +1058,20 @@ void rosh_more(const char *cmdstr) } /* rosh_more */ /* Page a file with rewind - * cmdstr command string to process - * pwdstr Present Working Directory string - * ipwdstr Initial PWD + * argc Argument Count + * argv Argument Values */ -void rosh_less(const char *cmdstr) +void rosh_less(int argc, char *argv[]) { printf(" less implemented as more (for now)\n"); - rosh_more(cmdstr); + rosh_more(argc, argv); } /* rosh_less */ /* Show PWD - * cmdstr command string to process */ -void rosh_pwd(const char *cmdstr) +void rosh_pwd(void) { - int istr; char pwdstr[ROSH_PATH_SZ]; - if (cmdstr) - istr = 0; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); errno = 0; if (getcwd(pwdstr, ROSH_PATH_SZ)) { printf("%s\n", pwdstr); @@ -958,190 +1079,223 @@ void rosh_pwd(const char *cmdstr) rosh_error(errno, "pwd", ""); errno = 0; } - istr = htonl(*(int *)pwdstr); - ROSH_DEBUG2(" --%08X\n", istr); } /* rosh_pwd */ -/* Reboot +/* Reboot; use warm reboot if one of certain options set + * argc Argument count + * argv Argument values */ -void rosh_reboot(void) +void rosh_reboot(int argc, char *argv[]) { -// char cmdstr[ROSH_CMD_SZ]; -// printf - syslinux_reboot(0); + int rtype = 0; + if (argc) { + /* For now, just use the first */ + switch (argv[0][0]) { + case '1': + case 's': + case 'w': + rtype = 1; + break; + case '-': + switch (argv[0][1]) { + case '1': + case 's': + case 'w': + rtype = 1; + break; + } + break; + } + } + syslinux_reboot(rtype); } /* rosh_reboot */ /* Run a boot string, calling syslinux_run_command - * cmdstr command string to process + * argc Argument count + * argv Argument values */ -void rosh_run(const char *cmdstr) +void rosh_run(int argc, char *argv[]) { - int cmdpos; - char *cmdptr; + char cmdstr[ROSH_CMD_SZ]; + int len; - cmdpos = 0; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* skip the first word */ - cmdpos = rosh_search_sp(cmdstr, cmdpos); - /* skip spaces */ - cmdpos = rosh_search_nonsp(cmdstr, cmdpos); - cmdptr = (char *)(cmdstr + cmdpos); - printf("--run: '%s'\n", cmdptr); - syslinux_run_command(cmdptr); + len = rosh_argcat(cmdstr, ROSH_CMD_SZ, argc, argv, 0); + if (len) { + printf("--run: '%s'\n", cmdstr); + syslinux_run_command(cmdstr); + } else { + printf(APP_NAME ":run: No arguments\n"); + } } /* rosh_run */ -/* Process a single command string and call handling function - * cmdstr command string to process +/* Process an argc/argv pair and call handling function + * argc Argument count + * argv Argument values * ipwdstr Initial Present Working Directory string * returns Whether to exit prompt */ -char rosh_command(const char *cmdstr, const char *ipwdstr) +char rosh_command(int argc, char *argv[], const char *ipwdstr) { - char do_exit; - char tstr[ROSH_CMD_SZ]; + char do_exit = false; int tlen; - do_exit = false; - ROSH_DEBUG("--cmd:'%s'\n", cmdstr); - tlen = rosh_parse_sp_1(tstr, cmdstr, 0); - switch (cmdstr[0]) { + tlen = strlen(argv[0]); + ROSH_DEBUG_ARGV_V(argc, argv); + switch (argv[0][0]) { case 'e': case 'E': case 'q': case 'Q': - if ((strncasecmp("exit", tstr, tlen) == 0) || - (strncasecmp("quit", tstr, tlen) == 0)) - do_exit = true; - else - rosh_help(1, NULL); + switch (argv[0][1]) { + case 0: + case 'x': + case 'X': + case 'u': + case 'U': + if ((strncasecmp("exit", argv[0], tlen) == 0) || + (strncasecmp("quit", argv[0], tlen) == 0)) + do_exit = true; + else + rosh_help(1, argv[0]); + break; + case 'c': + case 'C': + if (strncasecmp("echo", argv[0], tlen) == 0) + rosh_pr_argv(argc - 1, &argv[1]); + else + rosh_help(1, argv[0]); + break; + default: + rosh_help(1, argv[0]); + } break; case 'c': case 'C': /* run 'cd' 'cat' 'cfg' */ - switch (cmdstr[1]) { + switch (argv[0][1]) { case 'a': case 'A': - if (strncasecmp("cat", tstr, tlen) == 0) - rosh_cat(cmdstr); + if (strncasecmp("cat", argv[0], tlen) == 0) + rosh_cat(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'd': case 'D': - if (strncasecmp("cd", tstr, tlen) == 0) - rosh_cd(cmdstr, ipwdstr); + if (strncasecmp("cd", argv[0], tlen) == 0) + rosh_cd(argc, argv, ipwdstr); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'f': case 'F': - if (strncasecmp("cfg", tstr, tlen) == 0) + if (strncasecmp("cfg", argv[0], tlen) == 0) rosh_cfg(); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; default: - rosh_help(1, NULL); + rosh_help(1, argv[0]); } break; case 'd': case 'D': /* run 'dir' */ - if (strncasecmp("dir", tstr, tlen) == 0) - rosh_dir(cmdstr); + if (strncasecmp("dir", argv[0], tlen) == 0) + rosh_dir(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'h': case 'H': case '?': - if ((strncasecmp("help", tstr, tlen) == 0) || (tlen == 1)) - rosh_help(2, cmdstr); + if ((strncasecmp("help", argv[0], tlen) == 0) || (tlen == 1)) + rosh_help(2, argv[1]); else rosh_help(1, NULL); break; case 'l': case 'L': /* run 'ls' 'less' */ - switch (cmdstr[1]) { + switch (argv[0][1]) { case 0: - case ' ': case 's': case 'S': - if (strncasecmp("ls", tstr, tlen) == 0) - rosh_ls(cmdstr); + if (strncasecmp("ls", argv[0], tlen) == 0) + rosh_ls(argc, argv); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'e': case 'E': - if (strncasecmp("less", tstr, tlen) == 0) - rosh_less(cmdstr); + if (strncasecmp("less", argv[0], tlen) == 0) + rosh_less(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; default: - rosh_help(1, NULL); + rosh_help(1, argv[0]); } break; case 'm': case 'M': - switch (cmdstr[1]) { + switch (argv[0][1]) { case 'a': case 'A': - if (strncasecmp("man", tstr, tlen) == 0) - rosh_help(2, cmdstr); + if (strncasecmp("man", argv[0], tlen) == 0) + rosh_help(2, argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'o': case 'O': - if (strncasecmp("more", tstr, tlen) == 0) - rosh_more(cmdstr); + if (strncasecmp("more", argv[0], tlen) == 0) + rosh_more(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; default: - rosh_help(1, NULL); + rosh_help(1, argv[0]); } break; case 'p': case 'P': /* run 'pwd' */ - if (strncasecmp("pwd", tstr, tlen) == 0) - rosh_pwd(cmdstr); + if (strncasecmp("pwd", argv[0], tlen) == 0) + rosh_pwd(); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'r': case 'R': /* run 'run' */ - switch (cmdstr[1]) { + switch (argv[0][1]) { case 0: - case ' ': case 'e': case 'E': - if (strncasecmp("reboot", tstr, tlen) == 0) - rosh_reboot(); + if (strncasecmp("reboot", argv[0], tlen) == 0) + rosh_reboot(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'u': case 'U': - if (strncasecmp("run", tstr, tlen) == 0) - rosh_run(cmdstr); + if (strncasecmp("run", argv[0], tlen) == 0) + rosh_run(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; + default: + rosh_help(1, argv[0]); } break; case 'v': case 'V': - if (strncasecmp("version", tstr, tlen) == 0) + if (strncasecmp("version", argv[0], tlen) == 0) rosh_version(1); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 0: case '\n': break; default: - rosh_help(1, NULL); - } /* switch(cmdstr[0]) */ + rosh_help(1, argv[0]); + } /* switch(argv[0][0]) */ return do_exit; } /* rosh_command */ @@ -1150,29 +1304,29 @@ char rosh_command(const char *cmdstr, const char *ipwdstr) * icmdstr Initial command line string * returns Exit status */ -int rosh_prompt(const char *icmdstr) +int rosh_prompt(int iargc, char *iargv[]) { int rv; char cmdstr[ROSH_CMD_SZ]; char ipwdstr[ROSH_PATH_SZ]; char do_exit; - char *c; + char **argv; + int argc; rv = 0; do_exit = false; if (!getcwd(ipwdstr, ROSH_PATH_SZ)) strcpy(ipwdstr, "./"); - if (icmdstr[0] != '\0') - do_exit = rosh_command(icmdstr, ipwdstr); + if (iargc > 1) + do_exit = rosh_command(iargc - 1, &iargv[1], ipwdstr); while (!(do_exit)) { /* Extra preceeding newline */ printf("\nrosh: "); /* Read a line from console */ if (fgets(cmdstr, ROSH_CMD_SZ, stdin)) { - /* remove newline from input string */ - c = strchr(cmdstr, '\n'); - *c = 0; - do_exit = rosh_command(cmdstr, ipwdstr); + argc = rosh_str2argv(&argv, cmdstr); + do_exit = rosh_command(argc, argv, ipwdstr); + rosh_free_argv(&argv); } else { do_exit = false; } @@ -1183,19 +1337,21 @@ int rosh_prompt(const char *icmdstr) int main(int argc, char *argv[]) { int rv; - char cmdstr[ROSH_CMD_SZ]; /* Initialization */ rv = 0; rosh_console_std(); - if (argc != 1) { - rv = rosh_argcat(cmdstr, argc, argv, 1); - } else { + if (argc == 1) { rosh_version(0); print_beta(); - cmdstr[0] = '\0'; + } else { +#ifdef DO_DEBUG + char cmdstr[ROSH_CMD_SZ]; + rosh_argcat(cmdstr, ROSH_CMD_SZ, argc, argv, 1); + ROSH_DEBUG("arg='%s'\n", cmdstr); +#endif } - rv = rosh_prompt(cmdstr); - printf("--Exiting '%s'\n", APP_NAME); + rv = rosh_prompt(argc, argv); + printf("--Exiting '" APP_NAME "'\n"); return rv; } diff --git a/com32/rosh/rosh.h b/com32/rosh/rosh.h index b016e2f2..cabf556a 100644 --- a/com32/rosh/rosh.h +++ b/com32/rosh/rosh.h @@ -36,26 +36,32 @@ #include <sys/stat.h> /* fstat() */ #include <fcntl.h> /* open(); open mode macros */ #include <dirent.h> /* fdopendir() opendir() readdir() closedir() DIR */ -#include <unistd.h> /* getcwd() */ +#include <unistd.h> /* getcwd() getopt() */ #include <errno.h> /* errno; error macros */ #include <netinet/in.h> /* For htonl/ntohl/htons/ntohs */ #include <ctype.h> /* isspace() */ #include <getkey.h> #include <consoles.h> /* console_ansi_raw() console_ansi_std() */ +// #include <getopt.h> /* getopt_long() */ #ifdef DO_DEBUG # define ROSH_DEBUG printf +# define ROSH_DEBUG_ARGV_V rosh_pr_argv_v /* define ROSH_DEBUG(f, ...) printf (f, ## __VA_ARGS__) */ # ifdef DO_DEBUG2 # define ROSH_DEBUG2 printf +# define ROSH_DEBUG2_ARGV_V rosh_pr_argv_v # else /* DO_DEBUG2 */ /* This forces a format argument into the function call */ # define ROSH_DEBUG2(f, ...) ((void)0) +# define ROSH_DEBUG2_ARGV_V(argc, argv) ((void)0) # endif /* DO_DEBUG2 */ #else /* DO_DEBUG */ # define ROSH_DEBUG(f, ...) ((void)0) +# define ROSH_DEBUG_ARGV_V(argc, argv) ((void)0) # define ROSH_DEBUG2(f, ...) ((void)0) +# define ROSH_DEBUG2_ARGV_V(argc, argv) ((void)0) #endif /* DO_DEBUG */ #ifdef __COM32__ @@ -135,10 +141,10 @@ static inline int getscreensize(int fd, int *rows, int *cols) str = NULL; if (fd == 1) { ioctl(0, TIOCGWINSZ, &ws); -/* if (rows) + if (rows) *rows = ws.ws_row; if (cols) - *cols = ws.ws_col;*/ + *cols = ws.ws_col; if (rows && !*rows) { str = getenv("LINES"); if (str) @@ -235,6 +241,10 @@ const char rosh_beta_str[] = const char rosh_cd_norun_str[] = " -- cd (Change Directory) not implemented for use with run and exit.\n"; +const char rosh_help_cd_str[] = "cd Change directory\n\ + with no argument, return to original directory from entry to rosh\n\ + with one argument, change to that directory"; + const char rosh_help_ls_str[] = "ls List contents of current directory\n\ -l Long format\n\ -i Inode; print Inode of file\n\ @@ -259,4 +269,6 @@ const char rosh_help_str2[] = const char rosh_help_str_adv[] = "No additional help available for '%s'"; +const char rosh_ls_opt_str[] = "lFi"; + #endif /* Not ROSH_H */ diff --git a/core/pxelinux.asm b/core/pxelinux.asm index a46b3da5..e8818a6c 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -365,6 +365,16 @@ pxenv: pushfd pushad + ; We may be removing ourselves from memory + cmp bx,0073h ; PXENV_RESTART_TFTP + jz .disable_timer + cmp bx,00E5h ; gPXE PXENV_FILE_EXEC + jnz .store_stack + +.disable_timer: + call timer_cleanup + +.store_stack: mov [cs:PXEStack],sp mov [cs:PXEStack+2],ss lss sp,[cs:InitStack] @@ -391,6 +401,17 @@ pxenv: ; This clobbers the AX return, but we already saved it into ; the PXEStatus variable. popad + + ; If the call failed, it could return. + cmp bx,0073h + jz .enable_timer + cmp bx,00E5h + jnz .pop_flags + +.enable_timer: + call timer_init + +.pop_flags: popfd ; Restore flags (incl. IF, DF) ret diff --git a/core/writedec.inc b/core/writedec.inc index bfac0997..19e47968 100644 --- a/core/writedec.inc +++ b/core/writedec.inc @@ -37,6 +37,7 @@ writedec_common: xor cx,cx ; Number of digits .cloop: + mov edx,0 div ebx inc cx push dx @@ -53,5 +54,5 @@ writedec_common: popad ret -writechr: - ret +; writechr: +; ret diff --git a/modules/Makefile b/modules/Makefile index f3183641..9b50bb23 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -19,7 +19,7 @@ include $(topdir)/MCONFIG.embedded INCLUDES = -I$(com32)/include -BINS = pxechain.com poweroff.com int18.com +BINS = pxechain.com poweroff.com int18.com ver.com all: $(BINS) diff --git a/modules/ver.asm b/modules/ver.asm new file mode 100644 index 00000000..8ef63faf --- /dev/null +++ b/modules/ver.asm @@ -0,0 +1,606 @@ +; **************************************************************************** +; +; ver.asm +; +; A COMBOOT/DOS COM program to display the version of the system +; (Syslinux, DOS, or DRMK) +; +; Copyright (C) 2009-2010 Gene Cumm +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, Inc., 53 Temple Place Ste 330, +; Boston MA 02111-1307, USA; either version 2 of the License, or +; (at your option) any later version; incorporated herein by reference. +; +; **************************************************************************** + +; %define DEBUG + + section .text + org 0x100 + +_start: + call crlf + mov si,info_str + call writestr + call getdosver + call chkprn_dosver + jnz .end + call chkprn_syslinux + call crlf +.end: +; pop ds + ret + + +; chkprn_syslinux +chkprn_syslinux: +%ifdef DEBUG + mov si,may_sysl_str + call writestr +%endif + cmp eax,59530000h + jne .end + cmp ebx,4C530000h + jne .end + cmp ecx,4E490000h + jne .end + cmp edx,58550000h + jne .end +.is_syslinux: + pushad +%ifdef DEBUG + mov si,is_sysl_str + call writestr +%endif +.get_sysl_ver: + mov ax,0001h + int 22h +; AX=0001h [2.00] Get Version +; +; Input: AX 0001h +; Output: AX number of INT 22h API functions available +; CH Syslinux major version number +; CL Syslinux minor version number +; DL Syslinux derivative ID (e.g. 32h = PXELINUX) +; ES:SI Syslinux version string +; ES:DI Syslinux copyright string +%ifdef DEBUG + push si + push cs + pop ds + mov si,gotver_str + call writestr + pop si +%endif + +.prn_ver_str: + mov si,syslban_str + call writestr + push ds + push es + pop ds + call writestr + call crlf + pop ds +.prn_var: + cmp dl,31h + je .var_sysl + cmp dl,32h + je .var_pxel + cmp dl,33h + je .var_isol + cmp dl,34h + je .var_extl + jmp .var_unk +.var_sysl: + mov si,sysl_str + call writestr + jmp .prn_lnxsp +.var_pxel: + mov si,pxel_str + call writestr + jmp .prn_lnxsp +.var_isol: + mov si,isol_str + call writestr + jmp .prn_lnxsp +.var_extl: + mov si,extl_str + call writestr +; jmp .prn_lnxsp +.prn_lnxsp: + mov si,linsp_str + call writestr + jmp .prn_ver +.var_unk: + mov si,unkvar_str + call writestr +.prn_ver: +%ifdef DEBUG + push si + push cs + pop ds + mov si,prn_ver_str + call writestr + pop si +%endif +.prn_ver_maj: + mov al,ch + call writedecb + mov dl,'.' + call writechr_dl +.prn_ver_min: + mov al,cl +; cmp al,10 +; jae .min_wri +; mov al,'0' +; call writechr +; mov al,cl +; .min_wri: +; call writedecb + call writedecb2 + +.end_prn: + popad +.end: + ret + +; chkprn_dosver Check and print DOS version; +; Input Data from INT21 AH=30h +; AH Major version of DOS or 0 +; AL Minor Version +; BH DOS type +; BL:CX 24-bit OEM serial number +; Return +; ZF Unset if DOS, Set if not DOS (AX=0) +chkprn_dosver: + and ax,ax ; cmp ax,0 + jz .end +.is_dos: + push eax + push edx + push si +%ifdef DEBUG + mov si,is_dos_str + call writestr + call crlf + call prnreg_gp_l + call crlf +%endif +.var_prn: + cmp bh,0 + je .var_pcdos + cmp bh,0FFh + je .var_msdos + cmp bh,0FDh + je .var_freedos + cmp bh,0DEh + je .var_drmk + jmp .var_unk +.var_pcdos: + mov si,pcdos_str + call writestr + jmp .var_end +.var_msdos: + mov si,msdos_str + call writestr + jmp .var_end +.var_freedos: + mov si,freedos_str + call writestr + jmp .var_end +.var_drmk: + mov si,drmk_str + call writestr + jmp .var_end +.var_unk: + mov si,unkdos_str + call writestr + mov si,spparen_str + call writestr + push eax + mov al,bh + call writehex2 + pop eax + mov si,parensp_str + call writestr +; jmp .var_end +.var_end: + call prn_dosver_num + call crlf +.subver: + pop si + pop edx + pop eax + cmp bh,0FFh + je .msdos_ver + cmp bh,0DEh + jne .end_ver +.drmk_ver: + call getprn_drmkver +; jmp .end_ver ; DRMK returns Extended/True DOS +.msdos_ver: + cmp al,5 + jb .end_ver + call getprn_msdosver +.end_ver: + and ax,ax ; Unset ZF +.end: + ret + +; prn_dosver_num Print the numerical DOS version +; Input Data from INT21 AH=30h +; AH Major version of DOS or 0 +; AL Minor Version +; BH DOS type +; BL:CX 24-bit OEM serial number +prn_dosver_num: + push eax + push edx + push si + pushfd +.vmaj_prn: + call writedecb +; call writehex2 + mov dl,'.' + call writechr_dl +.vmin_prn: + mov al,ah + call writedecb +; call writehex2 +.serial: ; Skip if 0 + cmp bl,0 + jne .ser_start + cmp cx,0 + je .end +.ser_start: + mov si,spparen_str + call writestr + mov si,zerox_str + call writestr +.ser_bl: + mov al,bl + call writehex2 +.ser_cx: + mov ax,cx + call writehex4 +.serial_end: + mov si,parensp_str + call writestr +.end: + popfd + pop si + pop edx + pop eax + ret + +; getdosver Get the DOS version +; Return Version or 0 + SYSLINUX message +; EAX Part 1 +; EBX Part 2 +; ECX Part 3 +; EDX Part 4 +getdosver: + mov ecx,0 + mov edx,0 + mov ebx,0 + mov eax,3000h + int 21h + ret + +; getmsdosver Get the Extended MS-DOS version +; Returns Version +; EAX Part 1 +; EBX Part 2 +; ECX Part 3 +; EDX Part 4 +getmsdosver: + mov ecx,0 + mov edx,0 + mov ebx,0 + mov eax,3306h + int 21h + ret + +; getprn_msdosver +getprn_msdosver: + pushad + pushfd + call getmsdosver +%ifdef DEBUG + call prnreg_gp_l + call crlf +%endif + mov si,dosext_str + call writestr + mov eax,ebx + mov ebx,0 + mov ecx,edx + call prn_dosver_num +.end: + popfd + popad + ret + +; getdrmkver: Get the DRMK-specifc OS version +; Returns Version +; AX OS Version +; DX Patch Version +getdrmkver: + mov ax,4452h + int 21h + ret + +; getdrmkver: Get the DRMK-specifc Kernel build info +; Returns Kernel build info +; AX Kernel build date in DOS 16-bit format +; [ES:BX] Kernel private data +getdrmkbld: + mov ax,4458h + int 21h + ret + +; getprn_drmkver: Get/Print DRMK-specific Version info +getprn_drmkver: + pushad + pushfd +.getver: + call getdrmkver +.prnosver: ; "OS Version" + mov si,osver_str + call writestr + mov si,zerox_str + call writestr +; mov ax,0 + call writehex4 + call crlf +.prnpatchver: ; "Patch Version" + mov si,patchver_str + call writestr + mov si,zerox_str + call writestr + mov ax,dx + call writehex4 + call crlf +.getbld: + call getdrmkbld +.prnkernbld: ; "Kernel Build Date" + mov si,kernbld_str + call writestr + call writedate_ax + call crlf +.prnkernprvaddr: + mov si,prvdat_str + call writestr + mov ax,es + call writehex4 + mov dl,':' + call writechr_dl + mov ax,bx + call writehex4 + call crlf +%ifdef DEBUG +.prnkernprv: + mov di,[es:bx] + mov ax,di + call writehex4 + call crlf + mov si,2 + mov cx,8 +.prnkernprv2: + push cx + mov cx,8 +.prnkernprv1: + mov eax,[es:bx+si] + call writehex8 + cmp cx,1 + jbe .prnkern0dash + mov ax,'-' + call writechr +.prnkern0dash: + add si,4 + sub di,4 + cmp di,0 + jbe .prnkernprvend + loop .prnkernprv1 + call crlf + pop cx + loop .prnkernprv2 + jmp .end +.prnkernprvend: + pop cx +%endif +.end: + popfd + popad + ret + +;writedate_ax Write a date in AX in ISO8601 big endian format +; Input +; AX Date in 16-bit DOS format +; 2006-01-11 +; 0011010 0001 01011 +writedate_ax: + pushad + pushfd + mov dx,ax +%ifdef DEBUG + call writehex4 + call crlf +%endif +.year: + shr ax,9 + add ax,1980 + call writedecw + mov al,'-' + call writechr + mov ax,dx +.month: + shr ax,5 + and ax,0Fh +; cmp ax,10 +; jae .month_wri +; mov cx,ax +; mov ax,'0' +; call writechr +; mov ax,cx +; .month_wri: +; call writedecb + call writedecb2 + mov al,'-' + call writechr + mov ax,dx +.day: + and ax,1Fh +; cmp ax,10 +; jae .day_wri +; mov cx,ax +; mov ax,'0' +; call writechr +; mov ax,cx +; .day_wri: +; call writedecb + call writedecb2 +.end: + popfd + popad + ret + +; writechr_dl Write a character to the console saving AX +; Input +; DL character to write +writechr_dl: + push ax + mov ah,02h + int 21h +.end: + pop ax + ret + +; writechr_al Write a character to the console saving AX +; Input +; AL character to write +writechr: +writechr_al: + push dx + mov dl,al + call writechr_dl +.end: pop dx + ret + +; writedecb[23] Print byte as fixed width +; Input +; AL number to write +writedecb3: + pushfd + cmp al,100 + jae .skip + push ax + mov ax,'0' + call writechr + pop ax +.skip: popfd +writedecb2: + pushfd + cmp al,10 + jae .skip + push ax + mov ax,'0' + call writechr + pop ax +.skip: popfd + call writedecb + ret + + +; prnreg_gp_l Dump GP registers (Long) +prnreg_gp_l: + push eax + push si + call crlf + mov si,sp2_str + call writestr + mov si,eax_str + call writestr + call writehex8 + mov si,sp2_str + call writestr + mov si,ecx_str + call writestr + mov eax,ecx + call writehex8 + mov si,sp2_str + call writestr + mov si,edx_str + call writestr + mov eax,edx + call writehex8 + mov si,sp2_str + call writestr + mov si,ebx_str + call writestr + mov eax,ebx + call writehex8 + call crlf + pop si + pop eax +.end: + ret + +; is_zf +is_zf: + push si + jz .true +.false: + mov si,zero_not_str + call writestr + jmp .end +.true: + mov si,zero_is_str + call writestr +.end: + pop si + ret + +%include "../core/macros.inc" ; CR/LF +%include "../core/writestr.inc" ; String output +%include "../core/writehex.inc" ; Hexadecimal output +%include "../core/writedec.inc" ; Decimal output + + section .data +info_str db 'Ver.com b026', CR, LF, 0 +is_dos_str db 'Found DOS', CR, LF, 0 +is_sysl_str db 'Found a Syslinux variant', CR, LF, 0 +is_drmk_str db 'Found DRMK', CR, LF, 0 +may_sysl_str db 'Maybe Syslinux variant', CR, LF, 0 +gotver_str db 'Got the version back', CR, LF, 0 +prn_ver_str db 'Printing version number', CR, LF, 0 +syslban_str db 'Syslinux banner: ',0 +sysl_str db 'SYS', 0 +pxel_str db 'PXE', 0 +isol_str db 'ISO', 0 +extl_str db 'EXT', 0 +linsp_str db 'LINUX ', 0 +unkvar_str db 'Unkown-Variant ', 0 +pcdos_str db 'PC-DOS ', 0 +msdos_str db 'MS-DOS ', 0 +freedos_str db 'FreeDOS ', 0 +unkdos_str db 'Unknown-DOS ', 0 +drmk_str db 'DRMK ', 0 +dosext_str db ' Extended DOS version: ', 0 +osver_str db ' OS Version: ', 0 +patchver_str db ' Patch Version: ', 0 +kernbld_str db ' Kernel Build Date: ', 0 +prvdat_str db ' Private Data Ptr: ', 0 +spparen_str db ' (', 0 +zerox_str db '0x', 0 +parensp_str db ') ', 0 +eax_str db 'EAX=', 0 +ebx_str db 'EBX=', 0 +ecx_str db 'ECX=', 0 +edx_str db 'EDX=', 0 +sp2_str db ' ', 0 +zero_not_str db ' NOT_Zero ',0 +zero_is_str db ' IS_Zero ',0 |