[syslinux] COM32 module: Read-Only shell

Gene Cumm gene.cumm at gmail.com
Sun Feb 15 14:26:37 PST 2009


Well, here's the read-only shell (rosh) that I've been working on.
It's functional but still quite rough.  My primary intention of
posting it at this time is such that people have an easy way to
demonstrate to themselves that the library calls I made work.

This should apply as a patch to the head of the "dir" branch and the
patch for c_cflag/c_lflag.  The patch is only needed for Linux(without
it, segfaults will occur).  I've designed it to compile as a COM32
module and Linux binary when using GNU C (as Syslinux currently
requires GNU C, if I read the Makefiles correctly).

-- 
-Gene

"No one ever says, 'I can't read that ASCII E-mail you sent me.'"


diff --git a/com32/rosh/MCONFIG b/com32/rosh/MCONFIG
new file mode 100644
index 0000000..02b4856
--- /dev/null
+++ b/com32/rosh/MCONFIG
@@ -0,0 +1,27 @@
+## -*- makefile -*- -------------------------------------------------------
+##
+##   Copyright 2008 H. Peter Anvin - All Rights Reserved
+##
+##   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., 51 Franklin St, Fifth Floor,
+##   Boston MA 02110-1301, USA; either version 2 of the License, or
+##   (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## COM32 GRC configurables
+##
+
+## Include the COM32 common configurables
+include ../MCONFIG
+
+# CFLAGS     = $(GCCOPT) -W -Wall -march=i386 \
+# 	     -fomit-frame-pointer -D__COM32__ \
+# 	     -nostdinc -iwithprefix include \
+# 	     -I$(com32)/libutil/include -I$(com32)/include
+# 	 -g3 -dD
+
+# LNXCFLAGS  = -I$(com32)/libutil/include -W -Wall -O -g3 -D_GNU_SOURCE -dD
+# 	 -U__GNUC__
diff --git a/com32/rosh/Makefile b/com32/rosh/Makefile
new file mode 100644
index 0000000..f92fe67
--- /dev/null
+++ b/com32/rosh/Makefile
@@ -0,0 +1,38 @@
+## -----------------------------------------------------------------------
+##
+##   Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+##
+##   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.
+##
+## -----------------------------------------------------------------------
+
+##
+## samples for syslinux users
+##
+
+topdir = ../..
+include MCONFIG
+
+rosh.o:	rosh.h
+
+rosh.lo:	rosh.h
+
+all:	rosh.lnx rosh.c32
+
+tidy dist:
+	rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+
+clean: tidy
+	rm -f *.lnx
+
+spotless: clean
+	rm -f *.lss *.c32 *.com
+	rm -f *~ \#*
+
+install:	# Don't install samples
+
+-include .*.d
diff --git a/com32/rosh/rosh.c b/com32/rosh/rosh.c
new file mode 100644
index 0000000..5eaa47d
--- /dev/null
+++ b/com32/rosh/rosh.c
@@ -0,0 +1,810 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2008 Gene Cumm - All Rights Reserved
+ *
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * rosh.c
+ *
+ * Read-Only shell; Simple shell system designed for SYSLINUX-derivitives.
+ * Provides minimal commands utilizing the console via stdout/stderr as the
+ * sole output devices.  Designed to compile for Linux for testing/debugging.
+ */
+
+/*
+ * ToDos:
+ * Change functions to use pwdstr
+ * In rosh_run() Reparse cmdstr relative to pwdstr
+ */
+
+// #define DO_DEBUG 1
+	/* Uncomment the above line for debugging output; Comment to remove */
+// #define DO_DEBUG2 1
+	/* Uncomment the above line for super-debugging output; Must have
regular debugging enabled; Comment to remove */
+
+#include "rosh.h"
+
+#define APP_LONGNAME	"Read-Only Shell"
+#define APP_NAME	"rosh"
+#define APP_AUTHOR	"Gene Cumm"
+#define APP_YEAR	"2008"
+#define APP_VER		"beta-b032"
+
+void rosh_version()
+{
+	printf("%s v %s; (c) %s %s.\n", APP_LONGNAME, APP_VER, APP_YEAR, \
+		APP_AUTHOR);
+}
+
+void rosh_help(int type)
+{
+	rosh_version();
+	switch (type) {
+	case 2:	puts(rosh_help_str2);
+		break;
+	case 1:	default:
+		puts(rosh_help_str1);
+	}
+}
+
+/* Determine if a character is whitespace
+ *	inc	input character
+ *	returns	0 if not whitespace
+ */
+int rosh_issp(char inc)
+{
+	int rv;
+	switch (inc){
+	case ' ': case '\t':
+		rv = 1;	break;
+	default: rv = 0;
+	}
+	return rv;
+}	/* ros_issp */
+
+/* Search a string for first non-space (' ') character, starting at ipos
+ *	istr	input string to parse
+ *	ipos	input position to start at
+ */
+int rosh_search_nonsp(const char *istr, const int ipos)
+{
+	int curpos;
+	char c;
+
+	curpos = ipos;
+	c = istr[curpos];
+	while (rosh_issp(c) && c != 0)
+		c = istr[++curpos];
+	return curpos;
+}
+
+/* Search a string for space (' '), returning the position of the next space
+ * or the '\0' at end of string
+ *	istr	input string to parse
+ *	ipos	input position to start at
+ */
+int rosh_search_sp(const char *istr, const int ipos)
+{
+	int curpos;
+	char c;
+
+	curpos = ipos;
+	c = istr[curpos];
+	while (!(rosh_issp(c)) && c != 0)
+		c = istr[++curpos];
+	return curpos;
+}
+
+/* Parse a string for the first non-space string, returning the end position
+ * from src
+ *	dest	string to contain the first non-space string
+ *	src	string to parse
+ *	ipos	Position to start in src
+ */
+int rosh_parse_sp_1(char *dest, const char *src, const int ipos)
+{
+	int bpos, epos;	/* beginning and ending position of source string
+		to copy to destination string */
+
+	bpos = 0;
+	epos = 0;
+/* //HERE-error condition checking */
+	bpos = rosh_search_nonsp(src, ipos);
+	epos = rosh_search_sp(src, bpos);
+	if (epos > bpos) {
+		memcpy(dest, src + bpos, epos-bpos);
+		if (dest[epos - bpos] != 0)
+			dest[epos - bpos] = 0;
+	} else {
+		epos = strlen(src);
+		dest[0] = 0;
+	}
+	return epos;
+}
+
+/* Handle most/all errors
+ *	ierrno	Input Error number
+ *	cmdstr	Command being executed to cause error
+ *	filestr	File/parameter causing error
+ */
+void rosh_error(const int ierrno, const char *cmdstr, const char *filestr)
+{
+	printf("--ERROR: %s '%s': ", cmdstr, filestr);
+	switch (ierrno) {
+	case EACCES:	printf("Access DENIED\n");
+		break;
+	case ENOENT:	printf("not found\n");
+		/* SYSLinux-3.72 COM32 API returns this for a
+				directory or empty file */
+		ROSH_COM32("  (COM32) could be a directory or empty file\n");
+		break;
+	case ENOTDIR:	printf("not a directory\n");
+		ROSH_COM32("  (COM32) could be directory\n");
+		break;
+	case ENOSYS:	printf("not implemented");
+		break;
+	default:	printf("returns error; errno=%d\n", ierrno);
+	}
+}
+
+/* Concatenate command line arguments into one string
+ *	cmdstr	Output command string
+ *	argc	Argument Count
+ *	argv	Argument Values
+ *	barg	Beginning Argument
+ */
+int rosh_argcat(char *cmdstr, const int argc, char *argv[], const int barg)
+{
+	int i, arglen, curpos;	/* index, argument length, current position
+		in cmdstr */
+	curpos = 0;
+	cmdstr[0] = '\0';	/* Nullify string just to be sure */
+	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;
+		memcpy(cmdstr + curpos, argv[i], arglen);
+		curpos += arglen;
+		if (curpos >= (ROSH_CMD_SZ - 1)) {
+			/* Hopefully, curpos should not be greater than
+				(ROSH_CMD_SZ - 1) */
+			/* Still need a '\0' at the last character */
+			cmdstr[(ROSH_CMD_SZ - 1)] = 0;
+			break;	/* Escape out of the for() loop;
+				We can no longer process anything more */
+		} else {
+			cmdstr[curpos] = ' ';
+			curpos += 1;
+			cmdstr[curpos] = 0;
+		}
+	}
+	/* If there's a ' ' at the end, remove it.  This is normal unless
+		the maximum length is met/exceeded. */
+	if (cmdstr[curpos - 1] == ' ')
+		cmdstr[--curpos] = 0;
+	return curpos;
+}	/* rosh_argcat */
+
+/*
+ * Prints a lot of the data in a struct termios
+ */
+/*
+void rosh_print_tc(struct termios *tio)
+{
+	printf("  -- termios: ");
+	printf(".c_iflag=%04X ", tio->c_iflag);
+	printf(".c_oflag=%04X ", tio->c_oflag);
+	printf(".c_cflag=%04X ", tio->c_cflag);
+	printf(".c_lflag=%04X ", tio->c_lflag);
+	printf(".c_cc[VTIME]='%d' ", tio->c_cc[VTIME]);
+	printf(".c_cc[VMIN]='%d'", tio->c_cc[VMIN]);
+	printf("\n");
+}
+*/
+
+/*
+ * Switches console over to raw input mode.  Allows get_key to get just
+ * 1 key sequence (without delay or display)
+ */
+void rosh_console_raw()
+{
+// 	struct termios itio, ntio;
+// 	tcgetattr(0, &itio);
+// 	rosh_print_tc(&itio);
+/*	ntio = itio;
+	ntio.c_lflag &= ~(ICANON|ECHO);
+	tcsetattr(0, TCSAFLUSH, &ntio);*/
+	console_ansi_raw();	/* Allows get_key to get just 1 key sequence
+		 (w/o delay or display */
+// 	tcgetattr(0, &ntio);
+// 	rosh_print_tc(&ntio);
+}
+
+/*
+ * Switches back to standard getline mode.
+ */
+void rosh_console_std()
+{
+// 	struct termios itio, ntio;
+	console_ansi_std();
+// 	tcsetattr(0, TCSANOW, &itio);
+}
+
+/*
+ * Attempts to get a single key from the console
+ *	returns	key pressed
+ */
+int rosh_getkey()
+{
+	int inc;
+
+	inc = KEY_NONE;
+// 	rosh_console_raw();
+	while (inc == KEY_NONE){
+		inc = get_key(stdin, 6000);
+	}
+// 	rosh_console_std();
+	return inc;
+}	/* rosh_getkey */
+
+/* Template for command functions
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ *	ipwdstr	Initial PWD
+ */
+void rosh_1(const char *cmdstr, const char *pwdstr, const char *ipwdstr)
+{
+	ROSH_DEBUG("CMD: '%s'\npwd: '%s'\npwd: '%s'\n", cmdstr, pwdstr, \
+		ipwdstr);
+}	/* rosh_1 */
+
+/* Concatenate multiple files to stdout
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ */
+void rosh_cat(const char *cmdstr, const char *pwdstr)
+{
+	FILE *f;
+	char filestr[ROSH_PATH_SZ + 1];
+	char buf[ROSH_BUF_SZ];
+	int numrd;
+	int cmdpos;
+
+	ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+	/* 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");
+		if (f != NULL) {
+			numrd = fread(buf, 1, ROSH_BUF_SZ, f);
+			while (numrd > 0) {
+				fwrite(buf, 1, numrd, stdout);
+				numrd = fread(buf, 1, ROSH_BUF_SZ, f);
+			}
+			fclose(f);
+		} else {
+			rosh_error(errno, "cat", filestr);
+		}
+		cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+	}
+}	/* rosh_cat */
+
+/* Change PWD (Present Working Directory)
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ *	ipwdstr	Initial PWD
+ */
+void rosh_cd(const char *cmdstr, char *pwdstr, const char *ipwdstr)
+{
+	int rv;
+	char filestr[ROSH_PATH_SZ + 1];
+	int cmdpos;
+	ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+	/* 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);
+	ROSH_COM32(" -- cd (Change Directory) not implemented for use with
run and exit.\n");
+	if (strlen(filestr) != 0)
+		rv = chdir(filestr);
+	else
+		rv = chdir(ipwdstr);
+	if (rv != 0) {
+		rosh_error(errno, "cd", filestr);
+	} else {
+		getcwd(pwdstr, ROSH_PATH_SZ + 1);
+		printf("  %s\n", pwdstr);
+	}
+}	/* rosh_cd */
+
+/* Print the syslinux config file name
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ */
+void rosh_cfg(const char *cmdstr, const char *pwdstr)
+{
+	ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+	printf("CFG:     '%s'\n", syslinux_config_file());
+}	/* rosh_cfg */
+
+/* Simple directory listing for one argument (file/directory) based on
+ * filestr and pwdstr
+ *	ifilstr	input filename/directory name to list
+ *	pwdstr	Present Working Directory string
+ */
+void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
+{
+	struct stat fdstat;
+	int status;
+	int fd;
+	char filestr[ROSH_PATH_SZ + 1];
+	int filepos;
+	DIR *d;
+	struct dirent *de;
+#ifdef DO_DEBUG
+	char filestr2[ROSH_PATH_SZ + 1];
+	int fd2, file2pos;
+#ifdef __COM32__
+// 	int inchar;
+	char ty;
+#endif	/* __COM32__ */
+#endif	/* DO_DEBUG */
+
+	/* Initialization; make filestr based on leading character of ifilstr
+		and pwdstr */
+	if (ifilstr[0] == SEP) {
+		strcpy(filestr, ifilstr);
+	} else {
+		strcpy(filestr, pwdstr);
+		filepos = strlen(pwdstr);
+		if (filestr[filepos-1] != SEP)
+			filestr[filepos++] = SEP;
+		strcpy(filestr + filepos, ifilstr);
+ROSH_DEBUG("--'%s'\n", filestr);
+	}
+	fd = open(filestr, O_RDONLY);
+	if (fd != -1) {
+		status = fstat(fd, &fdstat);
+		if (S_ISDIR(fdstat.st_mode)) {
+			ROSH_DEBUG("PATH '%s' is a directory\n", ifilstr);
+			d = fdopendir(fd);
+			de = readdir(d);
+			while (de != NULL) {
+#ifdef DO_DEBUG
+				filestr2[0] = 0;
+				file2pos = strlen(filestr);
+				memcpy(filestr2, filestr, file2pos);
+				filestr2[file2pos] = '/';
+				strcpy(filestr2+file2pos+1, de->d_name);
+				fd2 = open(filestr2, O_RDONLY);
+				status = fstat(fd2, &fdstat);
+				printf("@%8d:%8d:", (int)de->d_ino, (int)fdstat.st_size);
+				fd2 = close(fd2);
+#endif	/* DO_DEBUG */
+				printf("%s\n", de->d_name);
+#ifdef DO_DEBUG
+// inchar = fgetc(stdin);
+#endif	/* DO_DEBUG */
+				de = readdir(d);
+			}
+			closedir(d);
+		} else if (S_ISREG(fdstat.st_mode)) {
+			ROSH_DEBUG("PATH '%s' is a regular file\n", ifilstr);
+			printf("%8d:%s\n", (int)fdstat.st_size, ifilstr);
+		} else {
+			ROSH_DEBUG("PATH '%s' is some other file\n", ifilstr);
+			printf("        :%s\n", ifilstr);
+		}
+	} else {
+#ifdef __COM32__
+		if (filestr[strlen(filestr)-1] == SEP) {
+			/* Directory */
+			filepos = 0;
+			d = opendir(filestr);
+			if (d != NULL) {
+printf("DIR:'%s'    %8d %8d\n", d->dd_name, d->dd_fd, d->dd_sect);
+				de = readdir(d);
+				while (de != NULL) {
+					filepos++;
+#ifdef DO_DEBUG
+// if (strlen(de->d_name) > 25) de->d_name[25] = 0;
+					switch (de->d_mode) {
+					case 16 : ty = 'D';	break;
+					case 32 : ty = 'F';	break;
+					default : ty = '*';
+					}
+					printf("@%8d:%8d:%4d ", (int)de->d_ino, (int)de->d_size, de->d_mode);
+#endif	/* DO_DEBUG */
+// 					printf("%s\n", de->d_name);
+printf("'%s'\n", de->d_name);
+#ifdef DO_DEBUG
+// inchar = fgetc(stdin);
+// fgets(instr, ROSH_CMD_SZ, stdin);
+#endif	/* DO_DEBUG */
+					free(de);
+					de = readdir(d);
+// if(filepos>15){	de = NULL;	printf("Force Break\n");}
+				}
+printf("Dir.dd_fd: '%8d'\n", d->dd_fd);
+				closedir(d);
+			} else {
+				rosh_error(0, "dir:NULL", filestr);
+			}
+		} else {
+			rosh_error(errno, "dir_c32", filestr);
+		}
+#else
+		rosh_error(errno, "dir", filestr);
+#endif	/* __COM32__ */
+	}
+}	/* rosh_dir_arg */
+
+/* Simple directory listing based on cmdstr and pwdstr
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ */
+void rosh_dir(const char *cmdstr, const char *pwdstr)
+{
+	char filestr[ROSH_PATH_SZ + 1];
+	int cmdpos;	/* Position within cmdstr */
+
+	ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+	/* 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);
+	/* If there are no real arguments, substitute PWD */
+	if (strlen(filestr) == 0)
+		strcpy(filestr, pwdstr);
+	while (strlen(filestr) > 0) {
+		rosh_dir_arg(filestr, pwdstr);
+		cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+	}
+}	/* rosh_dir */
+
+/* List Directory; Calls rosh_dir() for now.
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ */
+void rosh_ls(const char *cmdstr, const char *pwdstr)
+{
+	printf("  ls implemented as dir (for now)\n");
+	rosh_dir(cmdstr, pwdstr);
+}	/* rosh_ls */
+
+/* Page through a buffer string
+ *	buf	Buffer to page through
+ */
+void rosh_more_buf(char *buf, int buflen, int rows, int cols)
+{
+	char *bufp, *bufeol;	/* Pointer to current and next end-of-line
+		position in buffer */
+	int bufpos, bufcnt;	/* current position, count characters */
+	char scrbuf[ROSH_SBUF_SZ];
+	int inc;
+	int i, numln;	/* Index, Number of lines */
+
+	bufpos = 0;
+	bufp = buf + bufpos;
+	bufeol = bufp;
+	numln = rows - 1;
+printf("--(%d)\n", buflen);
+// printf("--termIOS CONSTS: ");
+// printf("ISIG=%08X ", ISIG);
+// printf("ICANON=%08X ", ICANON);
+// printf("ECHO=%08X ", ECHO);
+// printf("=%08X", );
+// printf("\n");
+	while (bufpos < buflen) {
+		for (i=0; i<numln; i++){
+			bufeol = strchr(bufeol, '\n');
+			if (bufeol == NULL) {
+				bufeol = buf + buflen;
+				i = numln;
+			} else {
+				bufeol++;
+			}
+// printf("--readln\n");
+		}
+		bufcnt = bufeol - bufp;
+printf("--(%d/%d @%d)\n", bufcnt, buflen, bufpos);
+		memcpy(scrbuf, bufp, bufcnt);
+		scrbuf[bufcnt] = 0;
+		printf("%s", scrbuf);
+		bufp = bufeol;
+		bufpos += bufcnt;
+		if (bufpos == buflen)	break;
+		inc = rosh_getkey();
+		numln = 1;
+		switch (inc){
+		case KEY_CTRL('c'): case 'q': case 'Q':
+			bufpos = buflen;	break;
+		case ' ':
+			numln = rows - 1;
+// 		default:
+		}
+	}
+/*tcgetattr(0, &tio);
+rosh_print_tc(&tio);
+printf("\n--END\n");*/
+}	/* rosh_more_buf */
+
+/* Page through a single file using the open file stream
+ *	fd	File Descriptor
+ */
+void rosh_more_fd(int fd, int rows, int cols)
+{
+	struct stat fdstat;
+	int status;
+	char *buf;
+	int bufpos;
+	int numrd;
+	FILE *f;
+
+	status = fstat(fd, &fdstat);
+	if (S_ISREG(fdstat.st_mode)) {
+		buf = malloc((int)fdstat.st_size);
+		if (buf != NULL) {
+			f = fdopen(fd, "r");
+			bufpos = 0;
+			numrd = fread(buf, 1, (int)fdstat.st_size, f);
+			while (numrd > 0) {
+				bufpos += numrd;
+				numrd = fread(buf+bufpos, 1, \
+					((int)fdstat.st_size - bufpos), f);
+			}
+			fclose(f);
+			rosh_more_buf(buf, bufpos, rows, cols);
+		}
+	} else {
+	}
+
+}	/* rosh_more_fd */
+
+/* Page through a file like the more command
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ *	ipwdstr	Initial PWD
+ */
+void rosh_more(const char *cmdstr, const char *pwdstr)
+	/*, const char *ipwdstr)*/
+{
+	int fd;
+	char filestr[ROSH_PATH_SZ + 1];
+	int cmdpos;
+	int rows, cols;
+
+	ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+	/* Initialization */
+	filestr[0] = 0;
+	cmdpos = 0;
+	if (getscreensize(1, &rows, &cols)) {
+		ROSH_DEBUG("getscreensize() fail; fall back\n");
+		ROSH_DEBUG("\tROWS='%d'\tCOLS='%d'\n", rows, cols);
+		/* If either fail, go under normal size, just in case */
+		if (!rows)
+			rows = 20;
+		if (!cols)
+			cols = 75;
+	}
+	ROSH_DEBUG("\tROWS='%d'\tCOLS='%d'\n", rows, cols);
+
+	/* skip the first word */
+	cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+	cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+	if (strlen(filestr) > 0) {
+		/* 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);
+			if (fd != -1) {
+				rosh_more_fd(fd, rows, cols);
+				close(fd);
+			} else {
+				rosh_error(errno, "more", filestr);
+			}
+			cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+		}
+		rosh_console_std();
+	}
+}	/* rosh_more */
+
+/* Page a file with rewind
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ *	ipwdstr	Initial PWD
+ */
+void rosh_less(const char *cmdstr, const char *pwdstr)
+{
+	printf("  less implemented as more (for now)\n");
+	rosh_more(cmdstr, pwdstr);
+}	/* rosh_less */
+
+/* Show PWD
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ */
+void rosh_pwd(const char *cmdstr, const char *pwdstr)
+{
+	int istr;
+	ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+	printf("%s\n", pwdstr);
+	istr = htonl(*(int*)pwdstr);
+	ROSH_DEBUG("  --%08X\n", istr);
+}	/* rosh_pwd */
+
+/* Run a boot string, calling syslinux_run_command
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ *	ipwdstr	Initial PWD
+ */
+void rosh_run(const char *cmdstr, const char *pwdstr, const char *ipwdstr)
+{
+	int cmdpos;
+	char *cmdptr;
+	char istr[ROSH_CMD_SZ];	/* input command string */
+
+	cmdpos = 0;
+	ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+	/* 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);
+	/* //HERE--Reparse if pwdstr != ipwdstr; seems a little daunting as
+		detecting params vs filenames is difficult/impossible */
+	if (strcmp(pwdstr, ipwdstr) != 0) {
+		/* For now, just prompt for verification */
+		printf("  from directory '%s'? (y/N):", pwdstr);
+		fgets(istr, ROSH_CMD_SZ, stdin);
+		if ((istr[0] != 'y') && (istr[0] != 'Y')) {
+			printf("Aborting run\n");
+			return;
+		}
+		printf("Run anyways\n");
+	}
+	syslinux_run_command(cmdptr);
+}	/* rosh_run */
+
+/* Process a single command string and call handling function
+ *	cmdstr	command string to process
+ *	pwdstr	Present Working Directory string
+ *	ipwdstr	Initial Present Working Directory string
+ *	returns	Whether to exit prompt
+ */
+char rosh_command(const char *cmdstr, char *pwdstr, const char *ipwdstr)
+{
+	char do_exit;
+	do_exit = false;
+	ROSH_DEBUG("--cmd:'%s'\n", cmdstr);
+	switch (cmdstr[0]) {
+	case 'e': case 'E': case 'q': case 'Q':
+		do_exit = true;		break;
+	case 'c': case 'C':	/* run 'cd' 'cat' 'cfg' */
+		switch (cmdstr[1]) {
+		case 'a': case 'A':
+			rosh_cat(cmdstr, pwdstr);	break;
+		case 'd': case 'D':
+			rosh_cd(cmdstr, pwdstr, ipwdstr);	break;
+		case 'f': case 'F':
+			rosh_cfg(cmdstr, pwdstr);	break;
+		default:	rosh_help(1);
+		}
+		break;
+	case 'd': case 'D':	/* run 'dir' */
+		rosh_dir(cmdstr, pwdstr);	break;
+	case 'h': case 'H': case '?': rosh_help(2);
+		break;
+	case 'l': case 'L':	/* run 'ls' 'less' */
+		switch (cmdstr[1]) {
+		case 0: case 's': case 'S':
+			rosh_ls(cmdstr, pwdstr);	break;
+		case 'e': case 'E':
+			rosh_less(cmdstr, pwdstr);	break;
+		default:	rosh_help(1);
+		}
+		break;
+	case 'm': case 'M':
+		switch (cmdstr[1]) {
+		case 'a': case 'A':
+			rosh_help(2);
+			break;
+		case 'o': case 'O':
+			rosh_more(cmdstr, pwdstr);
+			break;
+		default:	rosh_help(1);
+		}
+		break;
+	case 'p': case 'P':	/* run 'pwd' */
+		rosh_pwd(cmdstr, pwdstr);	break;
+	case 'r': case 'R':	/* run 'run' */
+		rosh_run(cmdstr, pwdstr, ipwdstr);	break;
+	case 'v': case 'V':
+		rosh_version();	break;
+	case 0: case '\n':	break;
+	default : rosh_help(1);
+	}	/* switch(cmdstr[0]) */
+	return do_exit;
+}	/* rosh_command */
+
+/* Process the prompt for commands as read from stdin and call rosh_command
+ * to process command line string
+ *	icmdstr	Initial command line string
+ *	returns	Exit status
+ */
+int rosh_prompt(const char *icmdstr)
+{
+	int rv;
+	char cmdstr[ROSH_CMD_SZ];
+	char pwdstr[ROSH_PATH_SZ + 1], ipwdstr[ROSH_PATH_SZ + 1];
+/* 	int numchar;
+*/	char do_exit;
+	char *c;
+
+	rv = 0;
+	do_exit = false;
+	strcpy(pwdstr, "/");
+	getcwd(pwdstr, ROSH_PATH_SZ + 1);
+	strcpy(ipwdstr, pwdstr);	/* Retain the original PWD */
+	if (icmdstr[0] != '\0')
+		do_exit = rosh_command(icmdstr, pwdstr, ipwdstr);
+	while (!(do_exit)) {
+		console_ansi_std();
+		printf("\nrosh: ");
+		/* Read a line from console */
+		fgets(cmdstr, ROSH_CMD_SZ, stdin);
+		/* remove newline from input string */
+		c = strchr(cmdstr, '\n');
+		*c = 0;
+		do_exit = rosh_command(cmdstr, pwdstr, ipwdstr);
+	}
+	if (strcmp(pwdstr, ipwdstr) != 0) {
+		/* Change directory to the original directory */
+		strcpy(cmdstr, "cd ");
+		strcpy(cmdstr + 3, ipwdstr);
+		rosh_cd(cmdstr, pwdstr, ipwdstr);
+	}
+	return rv;
+}
+
+int main(int argc, char *argv[])
+{
+	int rv;
+	char cmdstr[ROSH_CMD_SZ];
+
+	/* Initialization */
+	rv = 0;
+	console_ansi_std();
+// 	console_ansi_raw();
+	if (argc != 1) {
+		rv = rosh_argcat(cmdstr, argc, argv, 1);
+	} else {
+		rosh_version();
+		cmdstr[0] = '\0';
+	}
+	rv = rosh_prompt(cmdstr);
+	printf("--Exiting '%s'\n", APP_NAME);
+	console_ansi_std();
+	return rv;
+}
diff --git a/com32/rosh/rosh.h b/com32/rosh/rosh.h
new file mode 100644
index 0000000..d1930d9
--- /dev/null
+++ b/com32/rosh/rosh.h
@@ -0,0 +1,148 @@
+/* ----------------------------------------------------------------------- *
+ *
+ *   Copyright 2008 Gene Cumm - All Rights Reserved
+ *
+ *   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.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * rosh.h
+ *
+ * Read-Only shell; Header
+ */
+
+/*
+ * History
+ * b021	Move much PreProcessing stuff to rosh.h
+ * b018	Create rosh_debug() macro
+ * b012	Version of rosh.c at time of creating this file.
+ */
+
+#ifndef ROSH_H
+#define ROSH_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>	/* macro: true false */
+#include <string.h>	/* strcpy() strlen() memcpy() strchr() */
+#include <sys/types.h>
+#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 <errno.h>	/* errno; error macros */
+#include <netinet/in.h>	/* For htonl/ntohl/htons/ntohs */
+
+#include <getkey.h>
+#include <consoles.h>
+
+/* A GNUC extension to void out unused functions are used */
+/*	Plus, there seem to be other references for SYSLINUX to __GNUC__ */
+#ifndef __GNUC__
+#error SYSLINUX (I believe) requires __GNUC__
+#endif	/* __GNUC__ */
+
+#ifdef DO_DEBUG
+#define ROSH_DEBUG(f, ...)	printf (f, ## __VA_ARGS__)
+#ifdef DO_DEBUG2
+#define ROSH_DEBUG2(f, ...)	printf (f, ## __VA_ARGS__)
+#else	/* DO_DEBUG2 */
+#define ROSH_DEBUG2(f, ...)	((void)0)
+#endif	/* DO_DEBUG2 */
+#else	/* DO_DEBUG */
+#define ROSH_DEBUG(f, ...)	((void)0)
+#define ROSH_DEBUG2(f, ...)	((void)0)
+#endif	/* DO_DEBUG */
+
+#ifdef __COM32__
+#define ROSH_IS_COM32	1
+#include <console.h>		/* openconsole() */
+#include <syslinux/config.h>	/* Has info on the SYSLINUX variant */
+#include <syslinux/boot.h>	/* syslinux_run_command() */
+#define ROSH_COM32(f, ...)	printf (f, ## __VA_ARGS__)
+#else
+#include <termios.h>
+#define ROSH_IS_COM32	0
+static inline char *syslinux_config_file()
+{
+	return "";
+}
+static inline int getscreensize(int fd, int *rows, int *cols)
+{
+	char *str;
+	int rv;
+	*rows = 0;
+	*cols = 0;
+	if (rows) {
+		str = getenv("LINES");
+		if (str) {
+			*rows = atoi(str);
+		}
+	}
+	if (cols) {
+		str = getenv("COLUMNS");
+		if (str) {
+			*cols = atoi(str);
+		}
+	}
+	if (!rows || !cols)
+		rv = -1;
+	else if (!*rows || !*cols)
+		rv = -2;
+	else
+		rv = 0;
+	return rv;
+}
+#define ROSH_COM32(f, ...)	((void)0)
+#define syslinux_run_command(f)	((void)0)
+#endif	/* __COM32__ */
+
+#define SEP	'/'
+
+/* Size of buffer string */
+#define ROSH_BUF_SZ	16384
+/* Size of screen output buffer (80*40) */
+#define ROSH_SBUF_SZ	1200
+
+/* Size of command buffer string */
+#ifdef MAX_CMDLINE_LEN
+#define ROSH_CMD_SZ	MAX_CMDLINE_LEN
+#else
+#ifdef COMMAND_LINE_SIZE
+#define ROSH_CMD_SZ	COMMAND_LINE_SIZE
+#else
+#define ROSH_CMD_SZ	2048
+#endif	/* COMMAND_LINE_SIZE */
+#endif	/* MAX_CMDLINE_LEN */
+
+/* Size of path buffer string */
+#ifdef PATH_MAX
+#define ROSH_PATH_SZ	PATH_MAX
+#elif NAME_MAX
+#define ROSH_PATH_SZ	NAME_MAX
+#else
+#define ROSH_PATH_SZ	255
+#endif	/* NAME_MAX */
+
+const char rosh_help_str1[] =
+"Commands: ? cat cd cfg dir exit help less ls man more pwd run quit ver";
+
+const char rosh_help_str2[] =
+"Commands: (some 1-letter abreviations also allowed)\n\
+  h     HELP\n     ALSO ? help man\n\
+  cat   Concatenate file to console\n    cat <file>\n\
+  cd    Change to directory <dir>\n    cd <dir>\n\
+  less  Page a file with rewind\n\
+  ls    List contents of current directory\n    ls <dir>\n\
+    ALSO dir\n\
+  more  Page a file\n\
+  pwd   display Present Working Directory\n\
+  run   Run a program/kernel with options\n\
+  exit  Exit to previous environment\n    ALSO quit";
+
+#endif	/* Not ROSH_H */
diff --git a/com32/Makefile b/com32/Makefile
index bfb8e3a..a14c5b3 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS = lib libutil modules menu samples
+SUBDIRS = lib libutil modules menu samples rosh

 all tidy dist clean spotless install:
 	set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done




More information about the Syslinux mailing list