Selaa lähdekoodia

add sash, simpleinit and a uclibc config for nonmmu case

Waldemar Brodkorb 9 vuotta sitten
vanhempi
commit
8e2707b81b

+ 8 - 0
mk/image.mk

@@ -6,6 +6,8 @@ ifeq (${ADK_BINSH_ASH},y)
 BINSH:=ash
 BINSH:=ash
 else ifeq (${ADK_BINSH_BASH},y)
 else ifeq (${ADK_BINSH_BASH},y)
 BINSH:=bash
 BINSH:=bash
+else ifeq (${ADK_BINSH_SASH},y)
+BINSH:=sash
 else ifeq (${ADK_BINSH_HUSH},y)
 else ifeq (${ADK_BINSH_HUSH},y)
 BINSH:=hush
 BINSH:=hush
 else ifeq (${ADK_BINSH_MKSH},y)
 else ifeq (${ADK_BINSH_MKSH},y)
@@ -21,6 +23,8 @@ ifeq (${ADK_ROOTSH_ASH},y)
 ROOTSH:=/bin/ash
 ROOTSH:=/bin/ash
 else ifeq (${ADK_ROOTSH_BASH},y)
 else ifeq (${ADK_ROOTSH_BASH},y)
 ROOTSH:=/bin/bash
 ROOTSH:=/bin/bash
+else ifeq (${ADK_ROOTSH_SASH},y)
+ROOTSH:=/bin/sash
 else ifeq (${ADK_ROOTSH_HUSH},y)
 else ifeq (${ADK_ROOTSH_HUSH},y)
 ROOTSH:=/bin/hush
 ROOTSH:=/bin/hush
 else ifeq (${ADK_ROOTSH_MKSH},y)
 else ifeq (${ADK_ROOTSH_MKSH},y)
@@ -54,9 +58,13 @@ image-prepare-post:
 			mkfontdir ${TARGET_DIR}/usr/share/fonts/X11/$${i}; \
 			mkfontdir ${TARGET_DIR}/usr/share/fonts/X11/$${i}; \
 		done; \
 		done; \
 	fi
 	fi
+ifeq (${ADK_ROOTSH_SASH},)
 	$(SED) '/^root:/s!:/bin/sh$$!:${ROOTSH}!' ${TARGET_DIR}/etc/passwd
 	$(SED) '/^root:/s!:/bin/sh$$!:${ROOTSH}!' ${TARGET_DIR}/etc/passwd
+endif
+ifeq (${ADK_BINSH_SASH},)
 	-rm -f ${TARGET_DIR}/bin/sh
 	-rm -f ${TARGET_DIR}/bin/sh
 	ln -sf ${BINSH} ${TARGET_DIR}/bin/sh
 	ln -sf ${BINSH} ${TARGET_DIR}/bin/sh
+endif
 	test -z $(GIT) || \
 	test -z $(GIT) || \
 	     $(GIT) log -1|head -1|sed -e 's#commit ##' \
 	     $(GIT) log -1|head -1|sed -e 's#commit ##' \
 		> $(TARGET_DIR)/etc/.adkversion
 		> $(TARGET_DIR)/etc/.adkversion

+ 3 - 0
package/busybox/config/init/Config.in

@@ -44,6 +44,7 @@ config BUSYBOX_FEATURE_BOOTCHARTD_CONFIG_FILE
 	help
 	help
 	  Enable reading and parsing of $PWD/bootchartd.conf
 	  Enable reading and parsing of $PWD/bootchartd.conf
 	  and /etc/bootchartd.conf files.
 	  and /etc/bootchartd.conf files.
+
 config BUSYBOX_HALT
 config BUSYBOX_HALT
 	bool "poweroff, halt, and reboot"
 	bool "poweroff, halt, and reboot"
 	default y
 	default y
@@ -69,9 +70,11 @@ config BUSYBOX_TELINIT_PATH
 	  When busybox halt and friends have to call external telinit
 	  When busybox halt and friends have to call external telinit
 	  to facilitate proper shutdown, this path is to be used when
 	  to facilitate proper shutdown, this path is to be used when
 	  locating telinit executable.
 	  locating telinit executable.
+
 config BUSYBOX_INIT
 config BUSYBOX_INIT
 	bool "init"
 	bool "init"
 	default y
 	default y
+	depends on !ADK_TARGET_UCLINUX
 	select BUSYBOX_FEATURE_SYSLOG
 	select BUSYBOX_FEATURE_SYSLOG
 	help
 	help
 	  init is the first program run when the system boots.
 	  init is the first program run when the system boots.

+ 1 - 1
package/busybox/config/shell/Config.in

@@ -299,7 +299,7 @@ config BUSYBOX_MSH
 
 
 choice
 choice
 	prompt "Choose which shell is aliased to 'sh' name"
 	prompt "Choose which shell is aliased to 'sh' name"
-	default FEATURE_SH_IS_ASH
+	default FEATURE_SH_IS_NONE
 	help
 	help
 	  Choose which shell you want to be executed by 'sh' alias.
 	  Choose which shell you want to be executed by 'sh' alias.
 	  The ash shell is the most bash compatible and full featured one.
 	  The ash shell is the most bash compatible and full featured one.

+ 25 - 0
package/sash/Makefile

@@ -0,0 +1,25 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include ${ADK_TOPDIR}/rules.mk
+
+PKG_NAME:=		sash
+PKG_VERSION:=		1.0
+PKG_RELEASE:=		1
+PKG_DESCR:=		standalone shell
+PKG_SECTION:=		base/shells
+
+NO_DISTFILES:=		1
+
+include ${ADK_TOPDIR}/mk/package.mk
+
+$(eval $(call PKG_template,SASH,sash,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+
+CONFIG_STYLE:=		manual
+INSTALL_STYLE:=		manual
+
+do-install:
+	${INSTALL_DIR} ${IDIR_SASH}/bin
+	${INSTALL_BIN} ${WRKBUILD}/sh ${IDIR_SASH}/bin/sh
+
+include ${ADK_TOPDIR}/mk/pkg-bottom.mk

+ 47 - 0
package/sash/files/rc

@@ -0,0 +1,47 @@
+#!/bin/sh
+set -x
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin
+ln -s /proc/self/fd/2 /dev/stderr
+: ${rcquiet=0}
+if [ $rcquiet -ne 1 ];then
+	echo "System initialization ..."
+fi
+
+# remount /dev with smaller size
+mount -o remount,nosuid,size=128k,mode=0755 -t tmpfs mdev /dev
+
+# start mdev dynamic device node management
+echo >/dev/mdev.seq
+if [ -f /proc/sys/kernel/hotplug ];then
+	echo "/sbin/mdev" >/proc/sys/kernel/hotplug
+fi
+# creates f.e. /dev/root
+mdev -s
+
+# seed some random
+cat /etc/.rnd >/dev/urandom 2>&1
+
+# setup cfgfs
+[ -x /sbin/cfgfs ] && {
+	cfgfs setup
+	mount -o remount,ro /
+}
+
+# remount /tmp with smaller size
+size=$(cat /etc/tmpfs 2>/dev/null)
+[ -z $size ] && size=2048
+mount -o remount,nosuid,nodev,mode=1777,size=${size}k -t tmpfs tmpfs /tmp
+
+# create some useful directories in tmpfs
+mkdir -p /var/log
+mkdir -p /var/run
+mkdir -p /var/tmp
+touch /var/log/lastlog
+touch /var/log/wtmp
+
+HOSTNAME=
+[[ -s /etc/hostname ]] && HOSTNAME=$(cat /etc/hostname)
+HOSTNAME=${HOSTNAME%%.*}
+echo ${HOSTNAME:=openadk} >/proc/sys/kernel/hostname
+
+chown 0:0 /tmp; chmod 1777 /tmp

+ 38 - 0
package/sash/src/Makefile

@@ -0,0 +1,38 @@
+
+SH = sh
+SHOBJS = sash.o cmds.o cmd_uclinux.o ls.o hexdump.o df.o free.o \
+	hostname.o date.o
+
+SHUTDOWN = shutdown
+SHUTDOWNOBJS = shutdown.o
+
+REBOOT = reboot
+REBOOTOBJS = reboot.o
+
+SHOBJS += ps.o
+CFLAGS += -DCONFIG_USER_SASH_PS
+
+LIBSASH = libsash/libsash.a
+
+CFLAGS += -DCOMMAND_HISTORY
+
+all: $(SH) $(SHUTDOWN) $(REBOOT)
+
+$(SH): $(SHOBJS) $(LIBSASH)
+	$(CC) $(LDFLAGS) -o $@ $(SHOBJS) $(LIBSASH) $(LDLIBS$(LDLIBS_$@))
+
+$(SHUTDOWN): $(SHUTDOWNOBJS) $(LIBSASH)
+	$(CC) $(LDFLAGS) -o $@ $(SHUTDOWNOBJS) $(LIBSASH) $(LDLIBS)
+
+$(REBOOT): $(REBOOTOBJS) $(LIBSASH)
+	$(CC) $(LDFLAGS) -o $@ $(REBOOTOBJS) $(LIBSASH) $(LDLIBS$(LDLIBS_$@))
+
+dummy_target:
+
+$(LIBSASH): dummy_target
+	$(MAKE) -C libsash
+
+clean:
+	-rm -f $(SH) $(SHUTDOWN) $(REBOOT) *.elf *.gdb *.o
+	$(MAKE) -C libsash clean
+

+ 6 - 0
package/sash/src/README

@@ -0,0 +1,6 @@
+
+
+  This shell is an adaption of David Bell's "sash", the stand-along shell,
+with some adaptions (and truncations) for our environment. It also includes
+a few utilities (like reboot and ps) that weren't part of the original sash.
+

+ 127 - 0
package/sash/src/cmd_uclinux.c

@@ -0,0 +1,127 @@
+
+#include "sash.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <unistd.h>
+
+#if 0
+char psbuf[256];
+char name[40];
+int pid, state;
+char statec;
+
+void
+do_ps(argc, argv)
+	char	**argv;
+{
+	int i;
+	int h;
+	int max;
+	FILE * f;
+	DIR * d;
+	struct dirent * de;
+	int l;
+	
+	printf("  PID TTY STAT  TIME COMMAND\n");
+	
+	
+	d = opendir("/proc");
+	if (!d)
+		return;
+	
+	while (de = readdir(d)) {
+		for(i=0;i<strlen(de->d_name);i++)
+			if (!isdigit(de->d_name[i]))
+				goto next;
+		
+		sprintf(psbuf, "/proc/%s/stat", de->d_name);
+		h = open(psbuf, O_RDONLY);
+		
+		if (h==-1)
+			continue;
+			
+		l = read(h, psbuf, 255);
+		if (l<=0) {
+			perror("Unable to read status");
+			close(h);
+			continue;
+		}
+		
+		psbuf[l] = '\0';
+		psbuf[255] = '\0';
+		
+		
+		if (sscanf(psbuf, 
+			"%d %s %c",
+			&pid, name, &statec)<3)
+			{
+			perror("Unable to parse status");
+			close(h);
+			continue;
+		}
+		
+		state = statec;
+		
+		close(h);
+		
+		sprintf(psbuf, "/proc/%s/cmdline", de->d_name);
+		h = open(psbuf, O_RDONLY);
+		
+		if (h == -1) {
+			perror("Unable to open cmdline");
+			continue;
+		}
+		
+		l = read(h, psbuf, 255);
+		if (l < 0) {
+			perror("Unable to read cmdline");
+			close(h);
+			continue;
+		}
+		
+		close(h);
+		
+		psbuf[255] = psbuf[l] = '\0';
+		
+		printf("%5d %3s %c     --:-- %s\n", pid, "", state, psbuf);
+	next:
+	}
+	
+	closedir(d);
+}
+#endif
+
+void
+do_cat(argc, argv)
+	char	**argv;
+{
+	int	fd;
+	char	*name;
+	size_t	l;
+	char	buf[256];
+
+	while (argc-- > 1) {
+		if (intflag) {
+			return;
+		}
+		name = *(++argv);
+
+		fd = open(name, O_RDONLY);
+		if (fd < 0) {
+			perror(name);
+			return;
+		}
+
+		while ((l = read(fd, buf, sizeof(buf))) > 0) {
+			fwrite(buf, 1, l, stdout);
+		}
+		close(fd);
+	}
+}

+ 899 - 0
package/sash/src/cmds.c

@@ -0,0 +1,899 @@
+/*
+ * Modifications for uClinux
+ * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>
+ *
+ * Original code
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * Most simple built-in commands are here.
+ */
+
+#include "sash.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <utime.h>
+#include <errno.h>
+#ifdef EMBED
+#include <config/autoconf.h>
+#endif
+
+void
+do_echo(argc, argv)
+	char	**argv;
+{
+	BOOL	first;
+
+	first = TRUE;
+	while (argc-- > 1) {
+		if (!first)
+			fputc(' ', stdout);
+		first = FALSE;
+		fputs(*++argv, stdout);
+	}
+	fputc('\n', stdout);
+}
+
+
+void
+do_pwd(argc, argv)
+	char	**argv;
+{
+	char	buf[PATHLEN];
+
+	if (getcwd(buf, PATHLEN) == NULL) {
+		fprintf(stderr, "Cannot get current directory\n");
+		return;
+	}
+
+	printf("%s\n", buf);
+}
+
+void
+do_time(argc, argv)
+	char ** argv;
+{
+	struct timeval tv;
+	gettimeofday(&tv, 0);
+	printf("Time of day = %d.%6.6d seconds\n", tv.tv_sec, tv.tv_usec);
+}
+
+void
+do_cd(argc, argv)
+	char	**argv;
+{
+	char	*path;
+
+	if (argc > 1)
+		path = argv[1];
+	else {
+		path = getenv("HOME");
+		if (path == NULL) {
+			fprintf(stderr, "No HOME environment variable\n");
+			return;
+		}
+	}
+
+	if (chdir(path) < 0)
+		perror(path);
+}
+
+
+void
+do_mkdir(argc, argv)
+	char	**argv;
+{
+	int state = 0, mode = -1;
+
+	while (argc-- > 1) {
+		if (state == 0) {
+			if (strcmp(argv[1], "-m") == 0)
+				state = 1;
+			else if (mkdir(argv[1], 0777) < 0)
+				perror(argv[1]);
+			else if (mode != -1 && chmod(argv[1], mode) < 0)
+				perror(argv[1]);
+		} else if (state == 1) {
+			mode = strtol(argv[1], NULL, 8);
+			state = 0;
+		}
+		argv++;
+	}
+}
+
+void
+do_sleep(argc, argv) 
+	char	**argv;
+{
+	if (argc > 1)
+		sleep(atoi(argv[1]));
+}
+
+void
+do_mknod(argc, argv)
+	char	**argv;
+{
+	char	*cp;
+	int	mode;
+	int	major;
+	int	minor;
+
+	mode = 0666;
+
+	if (strcmp(argv[2], "b") == 0)
+		mode |= S_IFBLK;
+	else if (strcmp(argv[2], "c") == 0)
+		mode |= S_IFCHR;
+	else {
+		fprintf(stderr, "Bad device type\n");
+		return;
+	}
+
+	major = 0;
+	cp = argv[3];
+	while (isdecimal(*cp))
+		major = major * 10 + *cp++ - '0';
+
+	if (*cp || (major < 0) || (major > 255)) {
+		fprintf(stderr, "Bad major number\n");
+		return;
+	}
+
+	minor = 0;
+	cp = argv[4];
+	while (isdecimal(*cp))
+		minor = minor * 10 + *cp++ - '0';
+
+	if (*cp || (minor < 0) || (minor > 255)) {
+		fprintf(stderr, "Bad minor number\n");
+		return;
+	}
+
+	if (mknod(argv[1], mode, major * 256 + minor) < 0)
+		perror(argv[1]);
+}
+
+
+void
+do_rmdir(argc, argv)
+	char	**argv;
+{
+	while (argc-- > 1) {
+		if (rmdir(argv[1]) < 0)
+			perror(argv[1]);
+		argv++;
+	}
+}
+
+
+void
+do_sync(argc, argv)
+	char	**argv;
+{
+#ifdef CONFIG_USER_FLATFSD_FLATFSD
+	system("exec flatfsd -s");
+#endif
+	sync();
+}
+
+
+void
+do_rm(argc, argv)
+	char	**argv;
+{
+	while (argc-- > 1) {
+		if (unlink(argv[1]) < 0)
+			perror(argv[1]);
+		argv++;
+	}
+}
+
+
+void
+do_chmod(argc, argv)
+	char	**argv;
+{
+	char	*cp;
+	int	mode;
+
+	mode = 0;
+	cp = argv[1];
+	while (isoctal(*cp))
+		mode = mode * 8 + (*cp++ - '0');
+
+	if (*cp) {
+		fprintf(stderr, "Mode must be octal\n");
+		return;
+	}
+	argc--;
+	argv++;
+
+	while (argc-- > 1) {
+		if (chmod(argv[1], mode) < 0)
+			perror(argv[1]);
+		argv++;
+	}
+}
+
+
+void
+do_chown(argc, argv)
+	char	**argv;
+{
+	char		*cp;
+	int		uid;
+	struct passwd	*pwd;
+	struct stat	statbuf;
+
+	cp = argv[1];
+	if (isdecimal(*cp)) {
+		uid = 0;
+		while (isdecimal(*cp))
+			uid = uid * 10 + (*cp++ - '0');
+
+		if (*cp) {
+			fprintf(stderr, "Bad uid value\n");
+			return;
+		}
+	} else {
+		pwd = getpwnam(cp);
+		if (pwd == NULL) {
+			fprintf(stderr, "Unknown user name\n");
+			return;
+		}
+
+		uid = pwd->pw_uid;
+	}
+
+	argc--;
+	argv++;
+
+	while (argc-- > 1) {
+		argv++;
+		if ((stat(*argv, &statbuf) < 0) ||
+			(chown(*argv, uid, statbuf.st_gid) < 0))
+				perror(*argv);
+	}
+}
+
+
+void
+do_chgrp(argc, argv)
+	char	**argv;
+{
+	char		*cp;
+	int		gid;
+	struct group	*grp;
+	struct stat	statbuf;
+
+	cp = argv[1];
+	if (isdecimal(*cp)) {
+		gid = 0;
+		while (isdecimal(*cp))
+			gid = gid * 10 + (*cp++ - '0');
+
+		if (*cp) {
+			fprintf(stderr, "Bad gid value\n");
+			return;
+		}
+	} else {
+		grp = getgrnam(cp);
+		if (grp == NULL) {
+			fprintf(stderr, "Unknown group name\n");
+			return;
+		}
+
+		gid = grp->gr_gid;
+	}
+
+	argc--;
+	argv++;
+
+	while (argc-- > 1) {
+		argv++;
+		if ((stat(*argv, &statbuf) < 0) ||
+			(chown(*argv, statbuf.st_uid, gid) < 0))
+				perror(*argv);
+	}
+}
+
+
+void
+do_touch(argc, argv)
+        char    **argv;
+{
+        char            *name;
+        int             fd;
+        struct  utimbuf now;
+
+        time(&now.actime);
+        now.modtime = now.actime;
+
+        while (argc-- > 1) {
+                name = *(++argv);
+
+                if (utime(name, &now) <0)
+                {
+                fd = open(name, O_CREAT | O_WRONLY | O_EXCL, 0666);
+                if (fd >= 0)
+                        {
+                        close(fd);
+                        continue;
+                        }
+                perror(name);
+                }
+        }
+}
+
+
+void
+do_mv(argc, argv)
+	char	**argv;
+{
+	int	dirflag;
+	char	*srcname;
+	char	*destname;
+	char	*lastarg;
+
+	lastarg = argv[argc - 1];
+
+	dirflag = isadir(lastarg);
+
+	if ((argc > 3) && !dirflag) {
+		fprintf(stderr, "%s: not a directory\n", lastarg);
+		return;
+	}
+
+	while (argc-- > 2) {
+		srcname = *(++argv);
+		if (access(srcname, 0) < 0) {
+			perror(srcname);
+			continue;
+		}
+
+		destname = lastarg;
+		if (dirflag)
+			destname = buildname(destname, srcname);
+
+		if (rename(srcname, destname) >= 0)
+			continue;
+
+		if (errno != EXDEV) {
+			perror(destname);
+			continue;
+		}
+
+		if (!copyfile(srcname, destname, TRUE))
+			continue;
+
+		if (unlink(srcname) < 0)
+			perror(srcname);
+	}
+}
+
+
+void
+do_ln(argc, argv)
+	char	**argv;
+{
+	int	dirflag;
+	char	*srcname;
+	char	*destname;
+	char	*lastarg;
+
+	if (argv[1][0] == '-') {
+		if (strcmp(argv[1], "-s")) {
+			fprintf(stderr, "Unknown option\n");
+			return;
+		}
+
+		if (argc != 4) {
+			fprintf(stderr, "Wrong number of arguments for symbolic link\n");
+			return;
+		}
+
+#ifdef	S_ISLNK
+		if (symlink(argv[2], argv[3]) < 0)
+			perror(argv[3]);
+#else
+		fprintf(stderr, "Symbolic links are not allowed\n");
+#endif
+		return;
+	}
+
+	/*
+	 * Here for normal hard links.
+	 */
+	lastarg = argv[argc - 1];
+	dirflag = isadir(lastarg);
+
+	if ((argc > 3) && !dirflag) {
+		fprintf(stderr, "%s: not a directory\n", lastarg);
+		return;
+	}
+
+	while (argc-- > 2) {
+		srcname = *(++argv);
+		if (access(srcname, 0) < 0) {
+			perror(srcname);
+			continue;
+		}
+
+		destname = lastarg;
+		if (dirflag)
+			destname = buildname(destname, srcname);
+
+		if (link(srcname, destname) < 0) {
+			perror(destname);
+			continue;
+		}
+	}
+}
+
+
+void
+do_cp(argc, argv)
+	char	**argv;
+{
+	BOOL	dirflag;
+	char	*srcname;
+	char	*destname;
+	char	*lastarg;
+
+	lastarg = argv[argc - 1];
+
+	dirflag = isadir(lastarg);
+
+	if ((argc > 3) && !dirflag) {
+		fprintf(stderr, "%s: not a directory\n", lastarg);
+		return;
+	}
+
+	while (argc-- > 2) {
+		destname = lastarg;
+		srcname = *++argv;
+		if (dirflag)
+			destname = buildname(destname, srcname);
+
+		(void) copyfile(srcname, destname, FALSE);
+	}
+}
+
+
+void
+do_mount(argc, argv)
+	char	**argv;
+{
+	char	*str;
+	char	*type;
+
+	argc--;
+	argv++;
+	type = "minix";
+
+	while ((argc > 0) && (**argv == '-')) {
+		argc--;
+		str = *argv++ ;
+
+		while (*++str) switch (*str) {
+			case 't':
+				if ((argc <= 0) || (**argv == '-')) {
+					fprintf(stderr, "Missing file system type\n");
+					return;
+				}
+
+				type = *argv++;
+				argc--;
+				break;
+
+			default:
+				fprintf(stderr, "Unknown option\n");
+				return;
+		}
+	}
+
+	if (argc != 2) {
+		fprintf(stderr, "Wrong number of arguments for mount\n");
+		return;
+	}
+
+	if (mount(argv[0], argv[1], type, 0, 0) < 0)
+		perror("mount failed");
+}
+
+
+void
+do_umount(argc, argv)
+	char	**argv;
+{
+	if (umount(argv[1]) < 0)
+		perror(argv[1]);
+}
+
+
+void
+do_cmp(argc, argv)
+	char	**argv;
+{
+	int		fd1;
+	int		fd2;
+	int		cc1;
+	int		cc2;
+	long		pos;
+	char		*srcname;
+	char		*destname;
+	char		*lastarg;
+	char		*bp1;
+	char		*bp2;
+	char		*buf1;
+	char		*buf2;
+	struct	stat	statbuf1;
+	struct	stat	statbuf2;
+	
+	if (stat(argv[1], &statbuf1) < 0) {
+		perror(argv[1]);
+		return;
+	}
+
+	if (stat(argv[2], &statbuf2) < 0) {
+		perror(argv[2]);
+		return;
+	}
+
+	if ((statbuf1.st_dev == statbuf2.st_dev) &&
+		(statbuf1.st_ino == statbuf2.st_ino))
+	{
+		printf("Files are links to each other\n");
+		return;
+	}
+
+	if (statbuf1.st_size != statbuf2.st_size) {
+		printf("Files are different sizes\n");
+		return;
+	}
+	
+	fd1 = open(argv[1], 0);
+	if (fd1 < 0) {
+		perror(argv[1]);
+		return;
+	}
+
+	fd2 = open(argv[2], 0);
+	if (fd2 < 0) {
+		perror(argv[2]);
+		close(fd1);
+		return;
+	}
+	
+	buf1 = malloc(8192-16);
+	buf2 = malloc(8192-16);
+
+	pos = 0;
+	while (TRUE) {
+		if (intflag)
+			goto closefiles;
+
+		cc1 = read(fd1, buf1, 8192-16);
+		if (cc1 < 0) {
+			perror(argv[1]);
+			goto closefiles;
+		}
+
+		cc2 = read(fd2, buf2, 8192-16);
+		if (cc2 < 0) {
+			perror(argv[2]);
+			goto closefiles;
+		}
+
+		if ((cc1 == 0) && (cc2 == 0)) {
+			printf("Files are identical\n");
+			goto closefiles;
+		}
+
+		if (cc1 < cc2) {
+			printf("First file is shorter than second\n");
+			goto closefiles;
+		}
+
+		if (cc1 > cc2) {
+			printf("Second file is shorter than first\n");
+			goto closefiles;
+		}
+
+		if (memcmp(buf1, buf2, cc1) == 0) {
+			pos += cc1;
+			continue;
+		}
+
+		bp1 = buf1;
+		bp2 = buf2;
+		while (*bp1++ == *bp2++)
+			pos++;
+
+		printf("Files differ at byte position %ld\n", pos);
+		goto closefiles;
+	}
+
+closefiles:
+	close(fd1);
+	close(fd2);
+	free(buf1);
+	free(buf2);
+}
+
+
+void
+do_more(argc, argv)
+	char	**argv;
+{
+	FILE	*fp;
+	char	*name;
+	int	ch;
+	int	line;
+	int	col;
+	char	buf[80];
+
+	while (argc-- > 1) {
+		name = *(++argv);
+
+		fp = fopen(name, "r");
+		if (fp == NULL) {
+			perror(name);
+			return;
+		}
+
+		printf("<< %s >>\n", name);
+		line = 1;
+		col = 0;
+
+		while (fp && ((ch = fgetc(fp)) != EOF)) {
+			switch (ch) {
+				case '\r':
+					col = 0;
+					break;
+
+				case '\n':
+					line++;
+					col = 0;
+					break;
+
+				case '\t':
+					col = ((col + 1) | 0x07) + 1;
+					break;
+
+				case '\b':
+					if (col > 0)
+						col--;
+					break;
+
+				default:
+					col++;
+			}
+
+			putchar(ch);
+			if (col >= 80) {
+				col -= 80;
+				line++;
+			}
+
+			if (line < 24)
+				continue;
+
+			if (col > 0)
+				putchar('\n');
+
+			printf("--More--");
+			fflush(stdout);
+
+			if (intflag || (read(0, buf, sizeof(buf)) < 0)) {
+				if (fp)
+					fclose(fp);
+				return;
+			}
+
+			ch = buf[0];
+			if (ch == ':')
+				ch = buf[1];
+
+			switch (ch) {
+				case 'N':
+				case 'n':
+					fclose(fp);
+					fp = NULL;
+					break;
+
+				case 'Q':
+				case 'q':
+					fclose(fp);
+					return;
+			}
+
+			col = 0;
+			line = 1;
+		}
+		if (fp)
+			fclose(fp);
+	}
+}
+
+
+void
+do_exit(argc, argv)
+	char	**argv;
+{
+	exit(0);
+}
+
+
+void
+do_setenv(argc, argv)
+	char	**argv;
+{
+	setenv(argv[1], argv[2], 1);
+}
+
+
+void
+do_printenv(argc, argv)
+	char	**argv;
+{
+	char		**env;
+	extern char	**environ;
+	int		len;
+
+	env = environ;
+
+	if (argc == 1) {
+		while (*env)
+			printf("%s\n", *env++);
+		return;
+	}
+
+	len = strlen(argv[1]);
+	while (*env) {
+		if ((strlen(*env) > len) && (env[0][len] == '=') &&
+			(memcmp(argv[1], *env, len) == 0))
+		{
+			printf("%s\n", &env[0][len+1]);
+			return;
+		}
+		env++;
+	}
+}
+
+
+void
+do_umask(argc, argv)
+	char	**argv;
+{
+	char	*cp;
+	int	mask;
+
+	if (argc <= 1) {
+		mask = umask(0);
+		umask(mask);
+		printf("%03o\n", mask);
+		return;
+	}
+
+	mask = 0;
+	cp = argv[1];
+	while (isoctal(*cp))
+		mask = mask * 8 + *cp++ - '0';
+
+	if (*cp || (mask & ~0777)) {
+		fprintf(stderr, "Bad umask value\n");
+		return;
+	}
+
+	umask(mask);
+}
+
+
+void
+do_kill(argc, argv)
+	char	**argv;
+{
+	char	*cp;
+	int	sig;
+	int	pid;
+
+	sig = SIGTERM;
+
+	if (argv[1][0] == '-') {
+		cp = &argv[1][1];
+		if (strcmp(cp, "HUP") == 0)
+			sig = SIGHUP;
+		else if (strcmp(cp, "INT") == 0)
+			sig = SIGINT;
+		else if (strcmp(cp, "QUIT") == 0)
+			sig = SIGQUIT;
+		else if (strcmp(cp, "ILL") == 0)
+			sig = SIGILL;
+		else if (strcmp(cp, "TRAP") == 0)
+			sig = SIGTRAP;
+		else if (strcmp(cp, "ABRT") == 0)
+			sig = SIGABRT;
+		else if (strcmp(cp, "IOT") == 0)
+			sig = SIGIOT;
+		else if (strcmp(cp, "BUS") == 0)
+			sig = SIGBUS;
+		else if (strcmp(cp, "FPE") == 0)
+			sig = SIGFPE;
+		else if (strcmp(cp, "KILL") == 0)
+			sig = SIGKILL;
+		else if (strcmp(cp, "USR1") == 0)
+			sig = SIGUSR1;
+		else if (strcmp(cp, "SEGV") == 0)
+			sig = SIGSEGV;
+		else if (strcmp(cp, "USR2") == 0)
+			sig = SIGUSR2;
+		else if (strcmp(cp, "PIPE") == 0)
+			sig = SIGPIPE;
+ 		else if (strcmp(cp, "ALRM") == 0)
+			sig = SIGALRM;
+ 		else if (strcmp(cp, "TERM") == 0)
+			sig = SIGTERM;
+#ifdef SIGSTKFLT
+ 		else if (strcmp(cp, "STKFLT") == 0)
+			sig = SIGSTKFLT;
+#endif
+ 		else if (strcmp(cp, "CHLD") == 0)
+			sig = SIGCHLD;
+		else if (strcmp(cp, "CONT") == 0)
+			sig = SIGCONT;
+		else if (strcmp(cp, "STOP") == 0)
+			sig = SIGSTOP;
+		else if (strcmp(cp, "TSTP") == 0)
+			sig = SIGTSTP;
+ 		else if (strcmp(cp, "TTIN") == 0)
+			sig = SIGTTIN;
+ 		else if (strcmp(cp, "TTOU") == 0)
+			sig = SIGTTOU;
+ 		else if (strcmp(cp, "URG") == 0)
+			sig = SIGURG;
+ 		else if (strcmp(cp, "PWR") == 0)
+			sig = SIGPWR;
+		else {
+			sig = 0;
+			while (isdecimal(*cp))
+				sig = sig * 10 + *cp++ - '0';
+
+			if (*cp) {
+				fprintf(stderr, "Unknown signal\n");
+				exit_code = 1;
+				return;
+			}
+		}
+		argc--;
+		argv++;
+	}
+
+	while (argc-- > 1) {
+		cp = *++argv;
+		pid = 0;
+		while (isdecimal(*cp))
+			pid = pid * 10 + *cp++ - '0';
+
+		if (*cp) {
+			fprintf(stderr, "Non-numeric pid\n");
+			exit_code = 1;
+			return;
+		}
+
+		if (kill(pid, sig) < 0) {
+			perror(*argv);
+			exit_code = 1;
+		}
+	}
+}
+
+/* END CODE */

+ 27 - 0
package/sash/src/cp.c

@@ -0,0 +1,27 @@
+
+void
+do_cp(argc, argv)
+	char	**argv;
+{
+	BOOL	dirflag;
+	char	*srcname;
+	char	*destname;
+	char	*lastarg;
+
+	lastarg = argv[argc - 1];
+
+	dirflag = isadir(lastarg);
+
+	if ((argc > 3) && !dirflag) {
+		fprintf(stderr, "%s: not a directory\n", lastarg);
+		return;
+	}
+
+	while (argc-- > 2) {
+		destname = lastarg;
+		if (dirflag)
+			destname = buildname(destname, srcname);
+
+		(void) copyfile(*++argv, destname, FALSE);
+	}
+}

+ 54 - 0
package/sash/src/date.c

@@ -0,0 +1,54 @@
+/* date.c bradkemp@indusriver.com */
+
+#include <time.h>
+#include <stdio.h>
+
+static const char invalid_date[] = "Invalid date %s\n";
+int do_date(int argc, char * argv[])
+{
+
+    time_t tm;
+    struct tm tm_time;
+    time(&tm);
+    memcpy(&tm_time, localtime(&tm), sizeof(tm_time));
+    
+    if (argc > 1) {
+	int nr;
+        
+	nr = sscanf(argv[1], "%2d%2d%2d%2d%d",
+                    &(tm_time.tm_mon),
+                    &(tm_time.tm_mday),
+                    &(tm_time.tm_hour),
+                    &(tm_time.tm_min), &(tm_time.tm_year));
+        
+	if (nr < 4 || nr > 5) {
+            fprintf(stderr, invalid_date, argv[1]);
+            return(0);
+	}
+        
+	/* correct for century  - minor Y2K problem here? */
+	if (tm_time.tm_year >= 1900)
+            tm_time.tm_year -= 1900;
+	/* adjust date */
+	tm_time.tm_mon -= 1;
+        
+        if((tm = mktime(&tm_time)) < 0) {
+            fprintf(stderr, invalid_date, argv[1]);
+            return(0);
+        }
+        
+        if(stime(&tm) < 0) {
+            fprintf(stderr, "Unable to set date\n");
+            return(0);
+        }
+            
+        return (0);
+        
+    }
+    printf("%s\n",asctime(&tm_time));
+
+    return(0);
+}
+
+
+

+ 55 - 0
package/sash/src/df.c

@@ -0,0 +1,55 @@
+/* df.c:
+ *
+ * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "sash.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/vfs.h>
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <linux/major.h>
+#ifdef __UC_LIBC__
+#include <linux/types.h>
+#endif
+#include <sys/time.h>
+#include <sys/param.h>
+#include <errno.h>
+
+void
+do_df(int argc, char * argv[])
+{
+	char * name;
+	struct statfs stbuf;
+
+#if 0
+	fclose(stdin);
+#endif
+
+	if (argc<2)
+		name = "/";
+	else
+		name = argv[1];
+	
+	if (statfs(name, &stbuf) == -1) {
+		printf("Unable to get disk space of %s: %s\n", name, strerror(errno));
+		return;
+	}
+	
+	printf("Total Kbytes: %ld\n", (stbuf.f_bsize / 256) * (stbuf.f_blocks / 4));
+	printf("Free  Kbytes: %ld\n", (stbuf.f_bsize / 256) * (stbuf.f_bfree / 4));
+	printf("Total  nodes: %ld\n", stbuf.f_files);
+	printf("Free   nodes: %ld\n", stbuf.f_ffree);
+}
+

+ 44 - 0
package/sash/src/free.c

@@ -0,0 +1,44 @@
+/* free.c:
+ *
+ * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "sash.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+
+void
+do_free(argc, argv)
+	char	**argv;
+{
+	int i;
+	FILE * f;
+	char buf[256];
+
+	f = fopen("/proc/meminfo", "r");
+	
+	if (!f) {
+		perror("Unable to open /proc/meminfo: ");
+		return;
+	}
+	
+	for(i=0;i<3;i++) {
+		fgets(buf, 250, f);
+		fputs(buf, stdout);
+	}
+	
+	fclose(f);
+}
+

+ 127 - 0
package/sash/src/hexdump.c

@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * Most simple built-in commands are here.
+ */
+
+#include "sash.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <pwd.h>
+#include <grp.h>
+#include <utime.h>
+#include <errno.h>
+
+void
+do_hexdump(argc, argv)
+	int	argc;
+	char	**argv;
+{
+	FILE	*fp;
+	int	count;
+	int	c;
+	char	text[17];
+	unsigned char	buf[130];
+
+	char	*name = 0;
+	unsigned long pos = 0;
+	char	*myname = argv[0];
+ 
+	if ( (argc > 2) && !strcmp(argv[1],"-s") ) {
+		pos = strtoul(argv[2], 0, 0);
+		argc -= 2;
+		argv += 2;
+	}
+	
+	if (argc <= 1) {
+		fprintf(stderr, "No filename provided\n");
+		return;
+	}
+
+	name = argv[1];
+	fp = fopen(name, "r");
+	if (!fp) {
+		fprintf(stderr, "Failed to open file '%s': %s\n",
+			name, strerror(errno));
+		return;
+	}
+
+	if (pos)
+		fseek(fp, pos, SEEK_SET);
+	
+	c = 0;
+	
+	text[16] = 0;
+	
+	while(!feof(fp)) {
+	
+	  strcmp(text, "                ");
+	
+	  while (c < (pos & 0xf)) {
+	    if (c == 0)
+	      printf("%4X:", pos & 0xfffffff0);
+	    printf( (c == 8) ? "-  " : "   ");
+	    text[c] = ' ';
+	    c++;
+	  }
+	
+	  {
+	    int p = 0;
+            count = fread(buf, 1, 128 - (pos % 16), fp);
+          
+            if (count <= 0)
+              break;
+
+            while (p < count) {
+              c = (pos & 0xf);
+            
+              if (c == 0)
+                printf("%4X:", pos & 0xfffffff0);
+              
+              if ((buf[p] < 32) || (buf[p]>126))
+                text[c] = '.';
+              else
+                text[c] = buf[p];
+            
+	      printf( (c==15) ? " %02.2X" : (c == 8) ? "-%02.2X" : " %02.2X", buf[p]);
+	      
+	      if (c == 15)
+	        printf(" %s\n", text);
+	    
+              pos++;
+              p++;
+            }
+	  }
+	  
+	  if (c = (pos & 0x0f)) {
+
+	    while (c < 16) {
+	      printf( (c == 8) ? "-  " : "   ");
+	      text[c] = ' ';
+	      c++;
+	    }
+	  
+	    printf(" %s\n", text);
+	  }
+	    
+	  if (feof(fp))
+	    break;
+	  
+	  printf("--more--");
+	  fflush(stdout);
+	  
+	  fgets(buf, 80, stdin);
+	  if (toupper(buf[0]) == 'Q')
+	    break;
+	}
+
+	if (fp != stdin)
+		fclose(fp);
+}
+

+ 24 - 0
package/sash/src/hostname.c

@@ -0,0 +1,24 @@
+/* hostname.c - poe@daimi.aau.dk */
+
+#include "sash.h"
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <stdio.h>
+#include <unistd.h>
+
+void do_hostname(int argc, char **argv)
+{
+	char hn[PATHLEN + 1];
+	
+	if(argc >= 2) {
+		if(strlen(argv[1]) > PATHLEN) {
+			printf("That name is too long.\n");
+		} else {
+			sethostname(argv[1], strlen(argv[1]));
+		}
+	} else {
+		gethostname(hn, PATHLEN);
+		printf("%s\n", hn);
+	}
+}

+ 20 - 0
package/sash/src/libsash/Makefile

@@ -0,0 +1,20 @@
+
+LIB = libsash.a
+CHOPSRC = utils.c
+LIBOBJS = intflag.o modestring.o timestring.o isadir.o copyfile.o \
+	buildname.o expandwildcards.o namesort.o match.o makeargs.o \
+	makestring.o chunks.o expandenvvar.o
+
+CFLAGS += -I../
+
+
+all: $(EXEC) $(LIB)
+
+$(LIBOBJS): $(CHOPSRC)
+	$(CC) $(CFLAGS) -DL_$(basename $*) -o $(basename $*).o -c $^
+
+$(LIB): $(LIB)($(LIBOBJS))
+	$(RANLIB) $(LIB)
+
+clean:
+	rm -f $(LIB) $(EXEC) *.o

+ 706 - 0
package/sash/src/libsash/utils.c

@@ -0,0 +1,706 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * Utility routines.
+ */
+
+#include "sash.h"
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <time.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <fnmatch.h>
+
+#ifdef L_intflag
+
+int intflag;
+
+#endif
+
+#ifdef L_modestring
+
+/*
+ * Return the standard ls-like mode string from a file mode.
+ * This is static and so is overwritten on each call.
+ */
+char *
+modestring(mode)
+{
+	static	char	buf[12];
+
+	strcpy(buf, "----------");
+
+	/*
+	 * Fill in the file type.
+	 */
+	if (S_ISDIR(mode))
+		buf[0] = 'd';
+	if (S_ISCHR(mode))
+		buf[0] = 'c';
+	if (S_ISBLK(mode))
+		buf[0] = 'b';
+	if (S_ISFIFO(mode))
+		buf[0] = 'p';
+#ifdef	S_ISLNK
+	if (S_ISLNK(mode))
+		buf[0] = 'l';
+#endif
+#ifdef	S_ISSOCK
+	if (S_ISSOCK(mode))
+		buf[0] = 's';
+#endif
+
+	/*
+	 * Now fill in the normal file permissions.
+	 */
+	if (mode & S_IRUSR)
+		buf[1] = 'r';
+	if (mode & S_IWUSR)
+		buf[2] = 'w';
+	if (mode & S_IXUSR)
+		buf[3] = 'x';
+	if (mode & S_IRGRP)
+		buf[4] = 'r';
+	if (mode & S_IWGRP)
+		buf[5] = 'w';
+	if (mode & S_IXGRP)
+		buf[6] = 'x';
+	if (mode & S_IROTH)
+		buf[7] = 'r';
+	if (mode & S_IWOTH)
+		buf[8] = 'w';
+	if (mode & S_IXOTH)
+		buf[9] = 'x';
+
+	/*
+	 * Finally fill in magic stuff like suid and sticky text.
+	 */
+	if (mode & S_ISUID)
+		buf[3] = ((mode & S_IXUSR) ? 's' : 'S');
+	if (mode & S_ISGID)
+		buf[6] = ((mode & S_IXGRP) ? 's' : 'S');
+	if (mode & S_ISVTX)
+		buf[9] = ((mode & S_IXOTH) ? 't' : 'T');
+
+	return buf;
+}
+
+#endif
+
+#ifdef L_timestring
+
+/*
+ * Get the time to be used for a file.
+ * This is down to the minute for new files, but only the date for old files.
+ * The string is returned from a static buffer, and so is overwritten for
+ * each call.
+ */
+char *
+timestring(t)
+	long	t;
+{
+	long		now;
+	char		*str;
+	static	char	buf[26];
+
+	time(&now);
+
+	str = ctime(&t);
+
+	strcpy(buf, &str[4]);
+	buf[12] = '\0';
+
+	if ((t > now) || (t < now - 365*24*60*60L)) {
+		strcpy(&buf[7], &str[20]);
+		buf[11] = '\0';
+	}
+
+	return buf;
+}
+
+#endif
+
+#ifdef L_isadir
+
+/*
+ * Return TRUE if a filename is a directory.
+ * Nonexistant files return FALSE.
+ */
+BOOL
+isadir(name)
+	char	*name;
+{
+	struct	stat	statbuf;
+
+	if (stat(name, &statbuf) < 0)
+		return FALSE;
+
+	return S_ISDIR(statbuf.st_mode);
+}
+
+#endif
+
+#ifdef L_copyfile
+
+/*
+ * Copy one file to another, while possibly preserving its modes, times,
+ * and modes.  Returns TRUE if successful, or FALSE on a failure with an
+ * error message output.  (Failure is not indicted if the attributes cannot
+ * be set.)
+ */
+BOOL
+copyfile(srcname, destname, setmodes)
+	char	*srcname;
+	char	*destname;
+	BOOL	setmodes;
+{
+	int		rfd;
+	int		wfd;
+	int		rcc;
+	int		wcc;
+	char		*bp;
+	struct	stat	statbuf1;
+	struct	stat	statbuf2;
+	struct	utimbuf	times;
+	int len = 8192-16;
+	char * buf = 0;
+	
+	if (stat(srcname, &statbuf1) < 0) {
+		perror(srcname);
+		return FALSE;
+	}
+
+	if (stat(destname, &statbuf2) < 0) {
+		statbuf2.st_ino = -1;
+		statbuf2.st_dev = -1;
+	}
+
+	if (S_ISREG(statbuf1.st_mode) &&
+			(statbuf1.st_dev == statbuf2.st_dev) &&
+		(statbuf1.st_ino == statbuf2.st_ino))
+	{
+		fprintf(stderr, "Copying file \"%s\" to itself\n", srcname);
+		return FALSE;
+	}
+
+	rfd = open(srcname, 0);
+	if (rfd < 0) {
+		perror(srcname);
+		return FALSE;
+	}
+
+	wfd = open(destname, O_WRONLY|O_CREAT|O_TRUNC, statbuf1.st_mode);
+	if (wfd < 0) {
+		perror(destname);
+		close(rfd);
+		return FALSE;
+	}
+
+	buf = malloc(len);
+	if (!buf) {
+		fprintf(stderr,"Unable to allocate buffer of %d bytes\n", len);
+		return FALSE;
+	}
+	
+	while ((rcc = read(rfd, buf, len)) > 0) {
+		if (intflag) {
+			close(rfd);
+			close(wfd);
+			free(buf);
+			return FALSE;
+		}
+
+		bp = buf;
+		while (rcc > 0) {
+			wcc = write(wfd, bp, rcc);
+			if (wcc < 0) {
+				perror(destname);
+				free(buf);
+				goto error_exit;
+			}
+			bp += wcc;
+			rcc -= wcc;
+		}
+	}
+	
+	free(buf);
+
+	if (rcc < 0) {
+		perror(srcname);
+		goto error_exit;
+	}
+
+	close(rfd);
+	if (close(wfd) < 0) {
+		perror(destname);
+		return FALSE;
+	}
+
+	if (setmodes) {
+		(void) chmod(destname, statbuf1.st_mode);
+
+		(void) chown(destname, statbuf1.st_uid, statbuf1.st_gid);
+
+		times.actime = statbuf1.st_atime;
+		times.modtime = statbuf1.st_mtime;
+
+		(void) utime(destname, &times);
+	}
+
+	return TRUE;
+
+
+error_exit:
+	close(rfd);
+	close(wfd);
+
+	return FALSE;
+}
+
+#endif
+
+#ifdef L_buildname
+
+/*
+ * Build a path name from the specified directory name and file name.
+ * If the directory name is NULL, then the original filename is returned.
+ * The built path is in a static area, and is overwritten for each call.
+ */
+char *
+buildname(dirname, filename)
+	char	*dirname;
+	char	*filename;
+{
+	char		*cp;
+	static	char	buf[PATHLEN];
+
+	if ((dirname == NULL) || (*dirname == '\0'))
+		return filename;
+
+	cp = strrchr(filename, '/');
+	if (cp)
+		filename = cp + 1;
+
+	strcpy(buf, dirname);
+	strcat(buf, "/");
+	strcat(buf, filename);
+
+	return buf;
+}
+
+#endif
+
+#ifdef L_expandwildcards
+
+/*
+ * Expand the wildcards in a filename, if any.
+ * Returns an argument list with matching filenames in sorted order.
+ * The expanded names are stored in memory chunks which can later all
+ * be freed at once.  Returns zero if the name is not a wildcard, or
+ * returns the count of matched files if the name is a wildcard and
+ * there was at least one match, or returns -1 if too many filenames
+ * matched (with an error output).
+ * If the name is a wildcard and no names match, returns 0 as
+ * if the name were not a wildcard.
+ */
+int
+expandwildcards(name, maxargc, retargv)
+	char	*name;
+	int	maxargc;
+	char	*retargv[];
+{
+	char	*last;
+	char	*cp1, *cp2, *cp3;
+	DIR	*dirp;
+	struct	dirent	*dp;
+	int	dirlen;
+	int	matches;
+	char	dirname[PATHLEN];
+
+	last = strrchr(name, '/');
+	if (last)
+		last++;
+	else
+		last = name;
+
+	cp1 = strchr(name, '*');
+	cp2 = strchr(name, '?');
+	cp3 = strchr(name, '[');
+
+	if ((cp1 == NULL) && (cp2 == NULL) && (cp3 == NULL))
+		return 0;
+
+	if ((cp1 && (cp1 < last)) || (cp2 && (cp2 < last)) ||
+		(cp3 && (cp3 < last)))
+	{
+		fprintf(stderr, "Wildcards only implemented for last filename component\n");
+		return -1;
+	}
+
+	dirname[0] = '.';
+	dirname[1] = '\0';
+
+	if (last != name) {
+		memcpy(dirname, name, last - name);
+		dirname[last - name - 1] = '\0';
+		if (dirname[0] == '\0') {
+			dirname[0] = '/';
+			dirname[1] = '\0';
+		}
+	}
+
+	dirp = opendir(dirname);
+	if (dirp == NULL) {
+		perror(dirname);
+		return -1;
+	}
+
+	dirlen = strlen(dirname);
+	if (last == name) {
+		dirlen = 0;
+		dirname[0] = '\0';
+	} else if (dirname[dirlen - 1] != '/') {
+		dirname[dirlen++] = '/';
+		dirname[dirlen] = '\0';
+	}
+
+	matches = 0;
+
+	while ((dp = readdir(dirp)) != NULL) {
+		if ((strcmp(dp->d_name, ".") == 0) ||
+			(strcmp(dp->d_name, "..") == 0))
+				continue;
+
+		if (!match(dp->d_name, last))
+			continue;
+
+		if (matches >= maxargc) {
+			fprintf(stderr, "Too many filename matches\n");
+			closedir(dirp);
+			return -1;
+		}
+
+		cp1 = getchunk(dirlen + strlen(dp->d_name) + 1);
+		if (cp1 == NULL) {
+			fprintf(stderr, "No memory for filename\n");
+			closedir(dirp);
+			return -1;
+		}
+
+		if (dirlen)
+			memcpy(cp1, dirname, dirlen);
+		strcpy(cp1 + dirlen, dp->d_name);
+
+		retargv[matches++] = cp1;
+	}
+
+	closedir(dirp);
+
+	if (matches == 0) {
+		return 0;
+	}
+
+	qsort((char *) retargv, matches, sizeof(char *), namesort);
+
+	return matches;
+}
+
+#endif
+
+#ifdef L_namesort
+
+/*
+ * Sort routine for list of filenames.
+ */
+int
+namesort(p1, p2)
+	char	**p1;
+	char	**p2;
+{
+	return strcmp(*p1, *p2);
+}
+
+#endif
+
+#ifdef L_match
+
+/*
+ * Routine to see if a text string is matched by a wildcard pattern.
+ * Returns TRUE if the text is matched, or FALSE if it is not matched
+ * or if the pattern is invalid.
+ *  *		matches zero or more characters
+ *  ?		matches a single character
+ *  [abc]	matches 'a', 'b' or 'c'
+ *  \c		quotes character c
+ *  Adapted from code written by Ingo Wilken.
+ */
+BOOL
+match(text, pattern)
+	char	*text;
+	char	*pattern;
+{
+	return fnmatch(pattern, text, 0) == 0;
+}
+#endif
+
+#ifdef L_makeargs
+
+/*
+ * Take a command string, and break it up into an argc, argv list.
+ * The returned argument list and strings are in static memory, and so
+ * are overwritten on each call.  The argument array is ended with an
+ * extra NULL pointer for convenience.  Returns TRUE if successful,
+ * or FALSE on an error with a message already output.
+ *
+ * Note that leading quotes are *not* removed at this point, but
+ * trailing quotes are.
+ */
+BOOL
+makeargs(cmd, argcptr, argvptr)
+	char	*cmd;
+	int	*argcptr;
+	char	***argvptr;
+{
+	char		*cp;
+	int		argc;
+	static char	strings[CMDLEN+1];
+	static char	*argtable[MAXARGS+1];
+	static char	quoted[MAXARGS+1];
+
+	/*
+	 * Copy the command string and then break it apart
+	 * into separate arguments.
+	 */
+	strcpy(strings, cmd);
+	argc = 0;
+	cp = strings;
+
+	while (*cp) {
+		if (argc >= MAXARGS) {
+			fprintf(stderr, "Too many arguments\n");
+			return FALSE;
+		}
+
+		quoted[argc] = 0;
+		argtable[argc++] = cp;
+
+		while (*cp && !isblank(*cp)) {
+			if (*cp == '"' || *cp == '\'') {
+				char *sp = cp++;
+
+				while (*cp && *cp != *sp)
+					cp++;
+
+				if (*cp == *sp) {
+					/* Chop off the trailing quote, but leave the leading quote
+					 * so that later processing will know the argument is quoted
+					 */
+					*cp++ = 0;
+				}
+			} else
+				cp++;
+		}
+
+		while (isblank(*cp))
+ 			*cp++ = '\0';
+	}
+
+	argtable[argc] = NULL;
+
+	*argcptr = argc;
+	*argvptr = argtable;
+
+ 	return TRUE;
+}
+
+#endif
+
+#ifdef L_makestring
+
+/*
+ * Make a NULL-terminated string out of an argc, argv pair.
+ * Returns TRUE if successful, or FALSE if the string is too long,
+ * with an error message given.  This does not handle spaces within
+ * arguments correctly.
+ */
+BOOL
+makestring(argc, argv, buf, buflen)
+	char	**argv;
+	char	*buf;
+{
+	int	len;
+
+	while (argc-- > 0) {
+		len = strlen(*argv);
+		if (len >= buflen) {
+			fprintf(stderr, "Argument string too long\n");
+			return FALSE;
+		}
+
+		strcpy(buf, *argv++);
+
+		buf += len;
+		buflen -= len;
+
+		if (argc)
+			*buf++ = ' ';
+		buflen--; 
+	}
+
+	*buf = '\0';
+
+	return TRUE;
+}
+
+#endif
+
+#ifdef L_chunks
+
+typedef	struct	chunk	CHUNK;
+#define	CHUNKINITSIZE	4
+struct	chunk	{
+	CHUNK	*next;
+	char	data[CHUNKINITSIZE];	/* actually of varying length */
+};
+
+
+static	CHUNK *	chunklist;
+
+
+/*
+ * Allocate a chunk of memory (like malloc).
+ * The difference, though, is that the memory allocated is put on a
+ * list of chunks which can be freed all at one time.  You CAN NOT free
+ * an individual chunk.
+ */
+char *
+getchunk(size)
+{
+	CHUNK	*chunk;
+
+	if (size < CHUNKINITSIZE)
+		size = CHUNKINITSIZE;
+
+	chunk = (CHUNK *) malloc(size + sizeof(CHUNK) - CHUNKINITSIZE);
+	if (chunk == NULL)
+		return NULL;
+
+	chunk->next = chunklist;
+	chunklist = chunk;
+
+	return chunk->data;
+}
+
+
+/*
+ * Free all chunks of memory that had been allocated since the last
+ * call to this routine.
+ */
+void
+freechunks()
+{
+	CHUNK	*chunk;
+
+	while (chunklist) {
+		chunk = chunklist;
+		chunklist = chunk->next;
+		free((char *) chunk);
+	}
+}
+
+#endif
+
+
+#ifdef L_expandenvvar
+
+/* Expand environment variables
+ * Variable names must use a-z, A-Z, 0-9, or _
+ * Backslashes are also interpreted to preserve the literal value of the
+ * next character.
+ * Returns NULL if there is an error, otherwise returns a pointer
+ * to a static buffer containing the expand command line.
+ *
+ * Makes a lame attempt to not expand inside single quotes.
+ */
+char *
+expandenvvar(cmd)
+	char	*cmd;
+{
+	static char newcmd[CMDLEN+1];
+	char* newp = newcmd;
+	int freelength = CMDLEN;	/* Don't include final terminator */
+	char varname[CMDLEN+1];
+	char* varp;
+	char* value;
+	int valuelength;
+	int quoted = 0;
+
+	if (cmd == NULL) {
+		return NULL;
+	}
+
+	if (strlen(cmd) > freelength) {
+		fprintf(stderr, "Variable expansion too long\n");
+		return NULL;
+	}
+
+	while (*cmd) {
+		int copy = 1;
+
+		switch (*cmd) {
+		case '$':
+			if (!quoted) {
+				copy = 0;
+				cmd++;
+				varp = varname;
+				while (isalnum(*cmd) || (*cmd == '_') || (*cmd == '?')) {
+					*varp++ = *cmd++;
+				}
+				*varp = '\0';
+				if ((*varname) && (value = getenv(varname))) {
+					valuelength = strlen(value);
+					if (valuelength > freelength) {
+						fprintf(stderr, "Variable expansion too long\n");
+						return NULL;
+					}
+					strncpy(newp, value, valuelength);
+					newp += valuelength;
+					freelength -= valuelength;
+				}
+			}
+			break;
+
+		case '\'':
+			quoted = !quoted;
+			break;
+
+		case '\\':
+			cmd++;
+			break;
+		}
+
+		if (copy) {
+			if (freelength < 1) {
+				fprintf(stderr, "Variable expansion too long\n");
+				return NULL;
+			}
+			*newp++ = *cmd++;
+			freelength--;
+		}
+	}
+
+	*newp = '\0';
+
+	return newcmd;
+}
+
+#endif
+
+
+/* END CODE */

+ 311 - 0
package/sash/src/ls.c

@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * The "ls" built-in command.
+ */
+
+#include "sash.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/sysmacros.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+
+#define	LISTSIZE	256
+
+#define	COLWIDTH	20
+
+#ifdef	S_ISLNK
+#define	LSTAT	lstat
+#else
+#define	LSTAT	stat
+#endif
+
+
+/*
+ * Flags for the LS command.
+ */
+#define	LSF_LONG	0x01
+#define	LSF_DIR		0x02
+#define	LSF_INODE	0x04
+#define	LSF_MULT	0x08
+#define LSF_ALL		0x10
+#define LSF_COMPACT	0x20
+
+
+static	char	**list;
+static	int	listsize;
+static	int	listused;
+static	int	linelen = 0;
+
+
+static	void	lsfile();
+
+
+void
+do_ls(argc, argv)
+	int argc;
+	char	**argv;
+{
+	char		*cp;
+	char		*name;
+	int		flags;
+	int		i;
+	DIR		*dirp;
+	BOOL		endslash;
+	char		**newlist;
+	struct	dirent	*dp;
+	char		fullname[PATHLEN];
+	struct	stat	statbuf;
+	static		char *def[2];
+
+	if (listsize == 0) {
+		list = (char **) malloc(LISTSIZE * sizeof(char *));
+		if (list == NULL) {
+			fprintf(stderr, "No memory for ls buffer\n");
+			return;
+		}
+		listsize = LISTSIZE;
+	}
+	listused = 0;
+	
+	flags = 0;
+	if ((argc > 1) && (argv[1][0] == '-'))
+	{
+		argc--;
+		cp = *(++argv) + 1;
+
+		while (*cp) switch (*cp++) {
+			case 'l':	flags |= LSF_LONG; break;
+			case 'd':	flags |= LSF_DIR; break;
+			case 'i':	flags |= LSF_INODE; break;
+			case 'a':	flags |= LSF_ALL; break;
+			case 'C':	flags |= LSF_COMPACT; break;
+			default:
+				fprintf(stderr, "Unknown option -%c\n", cp[-1]);
+				return;
+		}
+	}
+
+	if ((flags & LSF_COMPACT) && (flags & ~LSF_COMPACT)) {
+		fprintf(stderr, "Cannot do compact list with other options\n");
+		return;
+	}
+
+	if (argc <= 1) {
+		argc = 2;
+		argv = def;
+		argv[0] = "ls";
+		argv[1] = ".";
+	}
+
+	if (argc > 2)
+		flags |= LSF_MULT;
+
+	while (argc-- > 1) {
+		name = *(++argv);
+		endslash = (*name && (name[strlen(name) - 1] == '/'));
+
+		if (LSTAT(name, &statbuf) < 0) {
+			perror(name);
+			continue;
+		}
+
+		if ((flags & LSF_DIR) || (!S_ISDIR(statbuf.st_mode))) {
+			lsfile(name, &statbuf, flags);
+			continue;
+		}
+
+		/*
+		 * Do all the files in a directory.
+		 */
+		dirp = opendir(name);
+		if (dirp == NULL) {
+			perror(name);
+			continue;
+		}
+
+		if (flags & LSF_MULT)
+			printf("\n%s:\n", name);
+
+		while ((dp = readdir(dirp)) != NULL) {
+		
+			if ((dp->d_name[0] == '.') && !(flags & LSF_ALL))
+				continue;
+
+			fullname[0] = '\0';
+
+			if ((*name != '.') || (name[1] != '\0')) {
+				strcpy(fullname, name);
+				if (!endslash)
+					strcat(fullname, "/");
+			}
+
+			strcat(fullname, dp->d_name);
+
+			if (listused >= listsize) {
+				newlist = malloc((sizeof(char **)) * (listsize + LISTSIZE));
+				if (newlist == NULL) {
+					fprintf(stderr, "No memory for ls buffer\n");
+					break;
+				}
+				memcpy(newlist, list, sizeof(char**) * listsize);
+				free(list);
+				listsize += LISTSIZE;
+			}
+
+			list[listused] = strdup(fullname);
+			if (list[listused] == NULL) {
+				fprintf(stderr, "No memory for filenames\n");
+				break;
+			}
+			listused++;
+		}
+
+		closedir(dirp);
+
+		/*
+		 * Sort the files.
+		 */
+		qsort((char *) list, listused, sizeof(char *), namesort);
+
+		/*
+		 * Now finally list the filenames.
+		 */
+		for (i = 0; i < listused; i++) {
+			name = list[i];
+
+			if (LSTAT(name, &statbuf) < 0) {
+				perror(name);
+				free(name);
+				continue;
+			}
+
+			cp = strrchr(name, '/');
+			if (cp)
+				cp++;
+			else
+				cp = name;
+
+			lsfile(cp, &statbuf, flags);
+
+			free(name);
+		}
+
+		listused = 0;
+	}
+
+	if (linelen)
+		fputc('\n', stdout);
+}
+
+
+/*
+ * Do an LS of a particular file name according to the flags.
+ */
+static void
+lsfile(name, statbuf, flags)
+	char	*name;
+	struct	stat	*statbuf;
+{
+	char		*cp;
+	struct	passwd	*pwd;
+	struct	group	*grp;
+	int		len;
+	char		buf[PATHLEN];
+	static	char	username[12];
+	static	int	userid;
+	static	BOOL	useridknown;
+	static	char	groupname[12];
+	static	int	groupid;
+	static	BOOL	groupidknown;
+
+	cp = buf;
+	*cp = '\0';
+
+	if (flags & LSF_INODE) {
+		sprintf(cp, "%5d ", statbuf->st_ino);
+		cp += strlen(cp);
+	}
+
+	if (flags & LSF_LONG) {
+		strcpy(cp, modestring(statbuf->st_mode));
+		cp += strlen(cp);
+
+		sprintf(cp, "%3d ", statbuf->st_nlink);
+		cp += strlen(cp);
+
+		if (!useridknown || (statbuf->st_uid != userid)) {
+			/*pwd = getpwuid(statbuf->st_uid);
+			if (pwd)
+				strcpy(username, pwd->pw_name);
+			else*/
+				sprintf(username, "%d", statbuf->st_uid);
+			userid = statbuf->st_uid;
+			useridknown = TRUE;
+		}
+
+		sprintf(cp, "%-8s ", username);
+		cp += strlen(cp);
+
+		if (!groupidknown || (statbuf->st_gid != groupid)) {
+			/*grp = getgrgid(statbuf->st_gid);
+			if (grp)
+				strcpy(groupname, grp->gr_name);
+			else*/
+				sprintf(groupname, "%d", statbuf->st_gid);
+			groupid = statbuf->st_gid;
+			groupidknown = TRUE;
+		}
+
+		sprintf(cp, "%-8s ", groupname);
+		cp += strlen(cp);
+
+		if (S_ISBLK(statbuf->st_mode) || S_ISCHR(statbuf->st_mode))
+			sprintf(cp, "%3d, %3d ", major(statbuf->st_rdev),
+				minor(statbuf->st_rdev));
+		else
+			sprintf(cp, "%8d ", statbuf->st_size);
+		cp += strlen(cp);
+
+		sprintf(cp, " %-12s ", timestring(statbuf->st_mtime));
+	}
+
+	fputs(buf, stdout);
+	fputs(name, stdout);
+
+#ifdef	S_ISLNK
+	if ((flags & LSF_LONG) && S_ISLNK(statbuf->st_mode)) {
+		len = readlink(name, buf, PATHLEN - 1);
+		if (len >= 0) {
+			buf[len] = '\0';
+			printf(" -> %s", buf);
+		}
+	}
+#endif
+
+	if (flags & LSF_COMPACT) {
+		len = strlen(name);
+		if (len < COLWIDTH) {
+			for (; (len < COLWIDTH); len++)
+				fputc(' ', stdout);
+			linelen += COLWIDTH;
+		} else {
+			linelen = 80;
+		}
+
+		if (linelen >= 80) {
+			fputc('\n', stdout);
+			linelen = 0;
+		}
+	} else {
+		fputc('\n', stdout);
+	}
+}
+
+/* END CODE */

+ 317 - 0
package/sash/src/ps.c

@@ -0,0 +1,317 @@
+/* ps.c:
+ *
+ * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "sash.h"
+
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <linux/major.h>
+#ifdef __UC_LIBC_
+#include <linux/types.h>
+#endif
+#include <sys/time.h>
+#include <sys/param.h>
+#ifdef __UC_LIBC__
+#include <mathf.h>
+#endif
+
+char psbuf[256];
+char name[40];
+int pid, state;
+char statec;
+int ppid, pgrp, session;
+dev_t tty;
+char tty_name[10];
+
+char master[] = "pqrstuvwxyzabcde";
+
+#define MAJOR(x) ((x) >> 8)
+#define MINOR(x) ((x) & 0xff)
+
+int port_xlate[16] = {1, 3, 5, 7,9 ,11,13,15,
+                      2, 4, 6, 8,10,12,14,16};
+
+void dev_to_name(dev_t dev, char * ttyname)
+{
+	strcpy(ttyname, "");
+	if (MAJOR(dev) == 75)
+		sprintf(ttyname,"X%d", MINOR(dev));
+	else if (MAJOR(dev) == TTY_MAJOR)
+		sprintf(ttyname,"S%d", MINOR(dev)-64);
+	else if (MAJOR(dev) == PTY_SLAVE_MAJOR)
+		sprintf(ttyname,"%c%x", master[MINOR(dev) / 16], MINOR(dev) & 0xf);
+}
+
+void
+do_ps(argc, argv)
+	char	**argv;
+{
+	int i;
+	int h;
+	int max;
+	FILE * f;
+	DIR * d;
+	unsigned long bytes, sbytes;
+	struct dirent * de;
+	char *ext;
+	int l;
+	time_t time_now;
+	long uptime_secs;
+	float idle_secs;
+	float seconds, start, total_time;
+	int utime, stime, start_time;
+	int pcpu;
+	/*extern int _vfprintf_fp_ref, _vfscanf_fp_ref;*/
+
+#if 0
+	fclose(stdin);
+#endif 
+
+	printf("  PID PORT STAT  SIZE SHARED %%CPU COMMAND\n"/*, _vfprintf_fp_ref, _vfscanf_fp_ref*/);
+
+	h = open("/proc/uptime", O_RDONLY);
+		
+	if (h==-1) {
+		perror("Unable to open /proc/uptime\n");
+		return;
+	}
+	
+	l = read(h, psbuf, 255);
+
+	close(h);  
+
+
+	if (l<=0) {
+		perror("Unable to read uptime");
+		return;
+	}
+
+
+	psbuf[l] = '\0';
+	psbuf[255] = '\0';
+		
+	ext = psbuf;
+
+
+	uptime_secs = atol(ext);
+
+	
+	time_now = time(0);
+	
+	d = opendir("/proc");
+	if (!d)
+		return;
+	
+	while (de = readdir(d)) {
+	
+	
+		for(i=0;i<strlen(de->d_name);i++)
+			if (!isdigit(de->d_name[i]))
+				goto next;
+
+		sprintf(psbuf, "/proc/%s/stat", de->d_name);
+		
+		h = open(psbuf, O_RDONLY);
+		
+		if (h==-1)
+			continue;
+			
+		l = read(h, psbuf, 255);
+		if (l<=0) {
+			perror("Unable to read status");
+			close(h);
+			continue;
+		}
+		
+		psbuf[l] = '\0';
+		psbuf[255] = '\0';
+		
+		ext = strrchr(psbuf, ')');
+		ext[0] = '\0';
+
+		statec = ext[2];
+
+		ext += 4;
+		
+		ppid = atoi(ext);
+		ext = strchr(ext, ' ')+1;
+
+		pgrp = atoi(ext);
+		ext = strchr(ext, ' ')+1;
+		
+		session = atoi(ext);
+		ext = strchr(ext, ' ')+1;
+
+		tty = atoi(ext);
+		ext = strchr(ext, ' ')+1;
+
+		//printf("1|%s\n", ext);
+		//tpgid
+		ext = strchr(ext, ' ')+1;
+		
+		//printf("2|%s\n", ext);
+		//flags
+		ext = strchr(ext, ' ')+1;
+
+		//printf("3|%s\n", ext);
+		//min_flt
+		ext = strchr(ext, ' ')+1;
+
+		//printf("4|%s\n", ext);
+		//cmin_flt
+		ext = strchr(ext, ' ')+1;
+
+		//printf("5|%s\n", ext);
+		//maj_flt
+		ext = strchr(ext, ' ')+1;
+
+		//printf("6|%s\n", ext);
+		//cmaj_flt
+		ext = strchr(ext, ' ')+1;
+
+		//printf("7|%s\n", ext);
+		utime = atoi(ext);
+		ext = strchr(ext, ' ')+1;
+
+		//printf("8|%s\n", ext);
+		stime = atoi(ext);
+		ext = strchr(ext, ' ')+1;
+		
+		//printf("9|%s\n", ext);
+		//cutime
+		ext = strchr(ext, ' ')+1;
+
+		//printf("10|%s\n", ext);
+		//cstime
+		ext = strchr(ext, ' ')+1;
+		
+		//priority
+		ext = strchr(ext, ' ')+1;
+		
+		//nice
+		ext = strchr(ext, ' ')+1;
+		
+		//timeout
+		ext = strchr(ext, ' ')+1;
+
+		//it_real_value
+		ext = strchr(ext, ' ')+1;
+
+		start_time = atoi(ext);
+		
+		ext = strchr(psbuf, '(');
+		ext++;
+		strcpy(name, ext);
+		
+		pid = atoi(psbuf);
+		
+		
+		state = statec;
+		
+		close(h);
+		
+		dev_to_name(tty, tty_name);
+		
+		bytes = 0;
+		sbytes = 0;
+		sprintf(psbuf, "/proc/%s/status", de->d_name);
+
+		f = fopen(psbuf, "r");
+		
+		if (f) {
+			while (fgets(psbuf, 250, f)) {
+				if (strncmp(psbuf, "Mem:", 4) == 0) {
+					bytes = atol(psbuf+5);
+					bytes /= 1024;
+				} else if (strncmp(psbuf, "Shared:", 7) == 0) {
+					sbytes = atol(psbuf+8);
+					sbytes /= 1024;
+				} else if (strncmp(psbuf, "VmSize:", 7) == 0) {
+					bytes = atol(psbuf+8);
+				}
+			}
+			fclose(f);
+		}
+		
+
+		seconds = ((uptime_secs * (long)HZ) - start_time) / HZ;
+		
+		/*printf("seconds=%s\n", gcvt(seconds, 15, psbuf));*/
+		
+		start = time_now - seconds;
+		
+		/*
+		printf("1\n");
+
+		gcvt(start, 15, psbuf);
+
+		printf("2\n");
+		
+		printf("start=%s\n", psbuf);
+		
+		printf("utime=%d, stime=%d. start_time=%d\n", utime, stime, start_time);
+		*/
+		
+		total_time = (utime + stime);
+
+		/*printf("total_time=%s\n", gcvt(total_time, 15, psbuf));*/
+
+		pcpu = 	seconds ? 
+			(total_time * 10.0f * 100.0f / (float)HZ) / seconds :
+			0; 
+		if (pcpu > 999) pcpu = 999;
+
+
+		sprintf(psbuf, "/proc/%s/cmdline", de->d_name);
+		h = open(psbuf, O_RDONLY);
+		
+		if (h == -1) {
+			perror("Unable to open cmdline");
+			continue;
+		}
+		
+		l = read(h, psbuf, 255);
+		if (l < 0) {
+			perror("Unable to read cmdline");
+			close(h);
+			continue;
+		}
+		
+		close(h);
+		
+		/*
+		 * the args are NUL separated, substitute spaces instead
+		 */
+		psbuf[l] = '\0';
+		i=l;
+		while(psbuf[i] == '\0')
+			i--;		/* Don't bother with trailing NULs */
+		while(--i > 0)
+			if (psbuf[i] == '\0')
+				psbuf[i] = ' ';
+
+		printf("%5d %4s %c    %4ldK   %3ldK %2u.%u %s\n", pid, tty_name, state,
+			bytes, sbytes, 
+			 pcpu / 10, pcpu % 10, 
+			 /*(int)seconds / 60, (int)seconds % 60,*/
+			 l ? psbuf : name);
+	next:
+		;
+	}
+	
+	closedir(d);
+}
+

+ 93 - 0
package/sash/src/reboot.c

@@ -0,0 +1,93 @@
+/* shutdown.c:
+ *
+ * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * JUN/99 -- copied from shutdown.c to make new reboot command.
+ *           (gerg@snapgear.com)
+ * AUG/99 -- added delay option to reboot
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include <getopt.h>
+
+#if __GNU_LIBRARY__ > 5
+#include <sys/reboot.h>
+#endif
+
+int main(int argc, char *argv[])
+{
+	int delay = 0; /* delay in seconds before rebooting */
+	int rc;
+	int force = 0;
+  
+	while ((rc = getopt(argc, argv, "h?d:f")) > 0) {
+		switch (rc) {
+		case 'd':
+			delay = atoi(optarg);
+			break;
+		case 'f':
+			force = 1;
+			break;
+		case 'h':
+		case '?':
+		default:
+			printf("usage: reboot [-h] [-d <delay>] [-f]\n");
+			exit(0);
+			break;
+		}
+	}
+
+	if(delay > 0)
+		sleep(delay);
+#ifdef CONFIG_DISKtel
+	printf("unmounting /home\n");
+	if(umount("/home") != 0){
+		printf("unmounting failed!!!\n");
+	}
+#endif
+
+#ifdef CONFIG_USER_FLATFSD_FLATFSD
+	if (!force) {
+		/* Ask flatfsd to reboot us safely */
+		execlp("flatfsd", "flatfsd", "-b", NULL);
+		/* if this returns,  then force a reboot */
+	}
+#endif
+
+	kill(1, SIGTSTP);
+	sync();
+	signal(SIGTERM,SIG_IGN);
+	signal(SIGHUP,SIG_IGN);
+	setpgrp();
+	kill(-1, SIGTERM);
+	sleep(1);
+	kill(-1, SIGHUP);
+	sleep(1);
+	sync();
+	sleep(1);
+#if __GNU_LIBRARY__ > 5
+	reboot(0x01234567);
+#else
+	reboot(0xfee1dead, 672274793, 0x01234567);
+#endif
+	exit(0); /* Shrug */
+}
+

+ 1118 - 0
package/sash/src/sash.c

@@ -0,0 +1,1118 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * Stand-alone shell for system maintainance for Linux.
+ * This program should NOT be built using shared libraries.
+ *
+ * 1.1.1, 	hacked to re-allow cmd line invocation of script file
+ *		Pat Adamo, padamo@unix.asb.com
+ */
+
+#include "sash.h"
+
+#ifndef CMD_HELP
+#define	CMD_HELP
+#endif
+#undef INTERNAL_PATH_EXPANSION
+#define FAVOUR_EXTERNAL_COMMANDS
+
+#include <stdlib.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+
+static char version[] = "1.1.1";
+
+extern int intflag;
+
+extern void do_test();
+
+typedef struct {
+	char	name[10];
+	char	usage[30];
+	void	(*func)();
+	int	minargs;
+	int	maxargs;
+} CMDTAB;
+
+
+CMDTAB	cmdtab[] = {
+/*
+	"alias",	"[name [command]]", 	do_alias,
+	1,		MAXARGS,
+*/
+	"cd",		"[dirname]",		do_cd,
+	1,		2,
+			
+	"sleep",		"seconds",		do_sleep,
+	1,		2,
+
+	"chgrp",	"gid filename ...",	do_chgrp,
+	3,		MAXARGS,
+
+	"chmod",	"mode filename ...",	do_chmod,
+	3,		MAXARGS,
+
+	"chown",	"uid filename ...",	do_chown,
+	3,		MAXARGS,
+
+	"cmp",		"filename1 filename2",	do_cmp,
+	3,		3,
+
+	"cp",		"srcname ... destname",	do_cp,
+	3,		MAXARGS,
+
+/*
+	"dd",		"if=name of=name [bs=n] [count=n] [skip=n] [seek=n]", do_dd,
+	3,		MAXARGS,
+*/
+	"df",		"[file-system]",	do_df,
+	1,		2,
+
+	"echo",	"[args] ...",			do_echo,
+	1,		MAXARGS,
+
+/*
+	"ed",		"[filename]",		do_ed,
+	1,		2,
+*/
+
+	"exec",		"filename [args]",	do_exec,
+	2,		MAXARGS,
+
+	"exit",		"",			do_exit,
+	1,		1,
+
+	"free",		"",			do_free,
+	1,		1,
+
+/*
+	"-grep",	"[-in] word filename ...",	do_grep,
+	3,		MAXARGS,
+*/
+
+#ifdef CMD_HELP
+	"help",		"",			do_help,
+	1,		MAXARGS,
+#endif
+
+	"hexdump",	"[-s pos] filename",	do_hexdump,
+	1,		4,
+
+	"hostname",	"[hostname]",		do_hostname,
+	1,		2,
+
+	"kill",		"[-sig] pid ...",	do_kill,
+	2,		MAXARGS,
+
+	"ln",		"[-s] srcname ... destname",	do_ln,
+	3,		MAXARGS,
+
+	"ls",		"[-lidC] filename ...",	do_ls,
+	1,		MAXARGS,
+
+	"mkdir",	"dirname ...",		do_mkdir,
+	2,		MAXARGS,
+
+	"mknod",	"filename type major minor",	do_mknod,
+	5,		5,
+
+	"more",	"filename ...",		do_more,
+	2,		MAXARGS,
+
+	"mount",	"[-t type] devname dirname",	do_mount,
+	3,		MAXARGS,
+
+	"mv",		"srcname ... destname",	do_mv,
+	3,		MAXARGS,
+
+	"printenv",	"[name]",		do_printenv,
+	1,		2,
+
+	"pwd",		"",			do_pwd,
+	1,		1,
+
+	"pid",		"",			do_pid,
+	1,		1,
+
+	"quit",		"",			do_exit,
+	1,		1,
+
+	"rm",		"filename ...",		do_rm,
+	2,		MAXARGS,
+
+	"rmdir",	"dirname ...",		do_rmdir,
+	2,		MAXARGS,
+
+	"setenv",	"name value",		do_setenv,
+	3,		3,
+
+	"source",	"filename",		do_source,
+	2,		2,
+
+	"sync",	"",			do_sync,
+	1,		1,
+
+/*	"time",	"",			do_time,
+	1,		1,
+*/
+/*
+	"tar",		"[xtv]f devname filename ...",	do_tar,
+	2,		MAXARGS,
+*/
+	"touch",	"filename ...",		do_touch,
+	2,		MAXARGS,
+
+	"umask",	"[mask]",		do_umask,
+	1,		2,
+
+	"umount",	"filename",		do_umount,
+	2,		2,
+
+/*
+	"unalias",	"name",			do_unalias,
+	2,		2,
+*/
+#ifdef CONFIG_USER_SASH_PS
+	"ps",		"",			do_ps,
+	1,		MAXARGS,
+#endif
+
+/*	"reboot",	"",			do_reboot,
+	1,		MAXARGS,
+*/
+	"cat",		"filename ...",		do_cat,
+	2,		MAXARGS,
+
+	"date",		"date [MMDDhhmm[YYYY]]",	do_date,
+	1,		2,
+
+	0,		0,			0,
+	0,		0
+};
+
+
+typedef struct {
+	char	*name;
+	char	*value;
+} ALIAS;
+
+
+static	ALIAS	*aliastable;
+static	int	aliascount;
+
+static	FILE	*sourcefiles[MAXSOURCE];
+static	int	sourcecount;
+
+volatile static	BOOL	intcrlf = TRUE;
+
+
+static	void	catchint();
+static	void	catchquit();
+static	void	catchchild();
+static	void	readfile();
+static	void	command();
+#ifdef COMMAND_HISTORY
+#define do_command(c,h)	command(c,h)
+#else
+#define do_command(c,h)	command(c)
+#endif
+static	void	runcmd();
+static	void	showprompt();
+static	BOOL	trybuiltin();
+static	BOOL	command_in_path();
+static	ALIAS	*findalias();
+
+extern char ** environ;
+
+/* 
+char text1[] = "Text";
+char * text2 = text1;
+char ** text3 = &text2;
+*/
+
+char	buf[CMDLEN];
+int exit_code = 0;
+
+main(argc, argv, env)
+	char	**argv;
+	char	*env[];
+{
+	struct sigaction act;
+	char	*cp;
+/*	char	buf[PATHLEN];*/
+	int dofile = 0;
+	
+	if ((argc > 1) && !strcmp(argv[1], "-c")) {
+		/* We are that fancy a shell */
+		buf[0] = '\0';
+		for (dofile = 2; dofile < argc; dofile++) {
+			strncat(buf, argv[dofile], sizeof(buf));
+			if (dofile + 1 < argc)
+				strncat(buf, " ", sizeof(buf));
+		}
+		do_command(buf, FALSE);
+		exit(exit_code);
+	}
+
+	//;'pa990523 +
+	if ((argc > 1) && strcmp(argv[1], "-t"))
+		{
+		dofile++;
+		printf("Shell invoked to run file: %s\n",argv[1]);
+		}
+	else
+		printf("\nSash command shell (version %s)\n", version);
+	fflush(stdout);
+
+	signal(SIGINT, catchint);
+	signal(SIGQUIT, catchquit);
+
+	memset(&act, 0, sizeof(act));
+	act.sa_handler = catchchild;
+	act.sa_flags = SA_RESTART;
+	sigaction(SIGCHLD, &act, NULL);
+
+	if (getenv("PATH") == NULL)
+		putenv("PATH=/bin:/usr/bin:/etc:/sbin:/usr/sbin");
+
+/*	cp = getenv("HOME");
+	if (cp) {
+		strcpy(buf, cp);
+		strcat(buf, "/");
+		strcat(buf, ".aliasrc");
+
+		if ((access(buf, 0) == 0) || (errno != ENOENT))
+			readfile(buf);
+	}
+*/	
+	//;'pa990523 -1/+
+	//readfile(NULL);
+	if (dofile)
+		{
+		//open the file for reading!
+		readfile(argv[1]);
+		}
+	   else
+		{
+		readfile(NULL); //no arguments!
+		} //end if arguments supplied
+	exit(exit_code);
+}
+
+
+/*
+ * Read commands from the specified file.
+ * A null name pointer indicates to read from stdin.
+ */
+static void
+readfile(name)
+	char	*name;
+{
+	FILE	*fp;
+	int	cc;
+	BOOL	ttyflag;
+	char	*ptr;
+
+	if (sourcecount >= MAXSOURCE) {
+		fprintf(stderr, "Too many source files\n");
+		return;
+	}
+
+	fp = stdin;
+	if (name) {
+		fp = fopen(name, "r");
+		if (fp == NULL) {
+			perror(name);
+			return;
+		}
+	}
+	sourcefiles[sourcecount++] = fp;
+
+	ttyflag = isatty(fileno(fp));
+
+	while (TRUE) {
+		fflush(stdout);
+		//;'pa990523 -1/+1
+		//if (1)
+		if (fp == stdin) //using terminal, so show prompt
+			showprompt();
+
+		if (intflag && !ttyflag && (fp != stdin)) {
+			fclose(fp);
+			sourcecount--;
+			return;
+		}
+
+		if (fgets(buf, CMDLEN - 1, fp) == NULL) {
+			if (ferror(fp) && (errno == EINTR)) {
+				clearerr(fp);
+				continue;
+			}
+			break;
+		}
+
+		cc = strlen(buf);
+
+		while ((cc > 0) && isspace(buf[cc - 1]))
+			cc--;
+		buf[cc] = '\0';
+		/* remove leading spaces and look for a '#' */
+		ptr = &buf[0];
+		while (*ptr == ' ') {
+			ptr++;
+		}
+		if (*ptr != '#') {
+			//;'pa990523 +
+			if (fp != stdin) {
+				//taking commands from file - echo
+				printf("Command: %s\n",buf);
+			} //end if (fp != stdin)
+
+			do_command(buf, fp == stdin);
+		}
+	}
+
+
+
+	if (ferror(fp)) {
+		perror("Reading command line");
+		if (fp == stdin)
+			exit(1);
+	}
+
+	clearerr(fp);
+	if (fp != stdin)
+		{//;'pa990523 added braces and printf
+		fclose(fp);
+		printf("Execution Finished, Exiting\n");
+		} //end if (fp != stdin)
+
+	sourcecount--;
+}
+
+
+/*
+ * Parse and execute one null-terminated command line string.
+ * This breaks the command line up into words, checks to see if the
+ * command is an alias, and expands wildcards.
+ */
+static void
+#ifdef COMMAND_HISTORY
+command(cmd, do_history)
+	int do_history;
+#else
+command(cmd)
+#endif
+	char	*cmd;
+{
+	ALIAS	*alias;
+	char	**argv;
+	int	argc;
+	int 	bg;
+	char   *c;
+
+	char last_exit_code[10];
+
+	sprintf(last_exit_code, "%d", exit_code);
+
+	intflag = FALSE;
+	exit_code = 0;
+
+	freechunks();
+
+	while (isblank(*cmd))
+		cmd++;
+
+#ifdef COMMAND_HISTORY
+	if (do_history) {
+		int i;
+		static char *history[HISTORY_SIZE];
+
+		if (*cmd == '!') {
+			if (cmd[1] == '!')
+				i = 0;
+			else {
+				i = atoi(cmd+1) - 1;
+				if (i < 0 || i >= HISTORY_SIZE) {
+					printf("%s: Out of range\n", cmd);
+					return;
+				}
+			}
+			if (history[i] == NULL) {
+				printf("%s: Null entry\n", cmd);
+				return;
+			}
+			strcpy(cmd, history[i]);
+		} else if (*cmd == 'h' && cmd[1] == '\0') {
+			for (i=0; i<HISTORY_SIZE; i++) {
+				if (history[i] != NULL)
+					printf("%2d: %s\n", i+1, history[i]);
+			}
+			return;
+		} else if (*cmd != '\0') {
+			if (history[HISTORY_SIZE-1] != NULL)
+				free(history[HISTORY_SIZE-1]);
+			for (i=HISTORY_SIZE-1; i>0; i--)
+				history[i] = history[i-1];
+			history[0] = strdup(cmd);
+		}
+	}
+#endif
+	if (c = strchr(cmd, '&')) {
+		*c = '\0';
+		bg = 1;
+	} else
+		bg = 0;
+
+	/* Set the last exit code */
+	setenv("?", last_exit_code, 1);
+	
+	if ((cmd = expandenvvar(cmd)) == NULL)
+		return;
+
+	if ((*cmd == '\0') || !makeargs(cmd, &argc, &argv))
+		return;
+
+	/*
+	 * Search for the command in the alias table.
+	 * If it is found, then replace the command name with
+	 * the alias, and append any other arguments to it.
+	 */
+	alias = findalias(argv[0]);
+	if (alias) {
+		cmd = buf;
+		strcpy(cmd, alias->value);
+
+		while (--argc > 0) {
+			strcat(cmd, " ");
+			strcat(cmd, *++argv);
+		}
+
+		if (!makeargs(cmd, &argc, &argv))
+			return;
+	}
+
+	/*
+	 * BASH-style variable setting
+	 */
+	if (argc == 1) {
+		c = index(argv[0], '=');
+		if (c > argv[0]) {
+			*c++ = '\0';
+			setenv(argv[0], c, 1);
+			return;
+		}
+	}
+		
+	/*
+	 * Now look for the command in the builtin table, and execute
+	 * the command if found.
+	 */
+#ifdef FAVOUR_EXTERNAL_COMMANDS
+	if (!command_in_path(argv[0]))
+#endif
+	if (trybuiltin(argc, argv))
+		return;
+
+	/*
+	 * Not found, run the program along the PATH list.
+	 */
+	runcmd(cmd, bg, argc, argv);
+}
+
+
+#ifdef FAVOUR_EXTERNAL_COMMANDS
+/*
+ * return true if we find this command in our
+ * path.
+ */
+static BOOL
+command_in_path(char *cmd)
+{
+	struct stat	stat_buf;
+
+	if (strchr(cmd, '/') == 0) {
+		char	* path;
+		static char	path_copy[PATHLEN];
+		
+		/* Search path for binary */
+		for (path = getenv("PATH"); path && *path; ) {
+			char * p2;
+
+			strcpy(path_copy, path);
+			if (p2 = strchr(path_copy, ':')) {
+				*p2 = '\0';
+			}
+		
+			if (strlen(path_copy))
+				strcat(path_copy, "/");
+			strcat(path_copy, cmd);
+			
+			if (!stat(path_copy, &stat_buf) && (stat_buf.st_mode & 0111))
+				return(TRUE);
+			
+			p2 = strchr(path, ':');
+			if (p2)
+				path = p2 + 1;
+			else
+				path = 0;
+		}
+	} else if (!stat(cmd, &stat_buf) && (stat_buf.st_mode & 0111))
+		return(TRUE);
+	return(FALSE);
+}
+#endif /* FAVOUR_EXTERNAL_COMMANDS */
+
+
+/*
+ * Try to execute a built-in command.
+ * Returns TRUE if the command is a built in, whether or not the
+ * command succeeds.  Returns FALSE if this is not a built-in command.
+ */
+static BOOL
+trybuiltin(argc, argv)
+	char	**argv;
+{
+	CMDTAB	*cmdptr;
+	int	oac;
+	int	newargc;
+	int	matches;
+	int	i;
+	char	*newargv[MAXARGS];
+	char	*nametable[MAXARGS];
+
+	cmdptr = cmdtab - 1;
+	do {
+		cmdptr++;
+		if (cmdptr->name[0] == 0)
+			return FALSE;
+
+	} while (strcmp(argv[0], cmdptr->name));
+	
+	/*
+	 * Give a usage string if the number of arguments is too large
+	 * or too small.
+	 */
+	if ((argc < cmdptr->minargs) || (argc > cmdptr->maxargs)) {
+		fprintf(stderr, "usage: %s %s\n",
+			cmdptr->name, cmdptr->usage);
+		fflush(stderr);
+
+		return TRUE;
+	}
+
+	/*
+	 * Check here for several special commands which do not
+	 * have wildcarding done for them.
+	 */
+
+/*        if (cmdptr->func == do_prompt) {
+		(*cmdptr->func)(argc, argv);
+		return TRUE;
+	}
+*/
+
+	/*
+	 * Now for each command argument, see if it is a wildcard, and if
+	 * so, replace the argument with the list of matching filenames.
+	 */
+	newargv[0] = argv[0];
+	newargc = 1;
+	oac = 0;
+
+	while (++oac < argc) {
+		if (argv[oac][0] == '"' || argv[oac][0] == '\'') {
+			argv[oac]++;
+			matches = 0;
+		}
+		else {
+			matches = expandwildcards(argv[oac], MAXARGS, nametable);
+			if (matches < 0)
+				return TRUE;
+		}
+
+		if ((newargc + matches) >= MAXARGS) {
+			fprintf(stderr, "Too many arguments\n");
+			return TRUE;
+		}
+
+		if (matches == 0)
+			newargv[newargc++] = argv[oac];
+
+		for (i = 0; i < matches; i++)
+			newargv[newargc++] = nametable[i];
+	}
+
+	(*cmdptr->func)(newargc, newargv);
+
+	return TRUE;
+}
+
+
+/*
+ * Execute the specified command.
+ */
+static void
+runcmd(cmd, bg, argc, argv)
+	char	*cmd;
+	int	bg;
+	int	argc;
+	char	**argv;
+{
+	register char *	cp;
+	BOOL		magic;
+	int		pid;
+	int		status;
+	int oac;
+	int newargc;
+	int matches;
+	int i;
+	char	*newargv[MAXARGS];
+	char	*nametable[MAXARGS];
+	struct sigaction act;
+	
+	newargv[0] = argv[0];
+	
+#ifdef INTERNAL_PATH_EXPANSION
+	if (strchr(argv[0], '/') == 0) {
+		char	* path;
+		struct stat	stat_buf;
+		static char	path_copy[PATHLEN];
+		
+		/* Search path for binary */
+		for (path = getenv("PATH"); path && *path; ) {
+			char * p2;
+			strncpy(path_copy, path, sizeof(path_copy - 1));
+			if (p2 = strchr(path_copy, ':')) {
+				*p2 = '\0';
+			}
+		
+			if (strlen(path_copy))
+				strncat(path_copy, "/", sizeof(path_copy));
+			strncat(path_copy, argv[0], sizeof(path_copy));
+			
+			if (!stat(path_copy, &stat_buf) && (stat_buf.st_mode & 0111)) {
+				newargv[0] = path_copy;
+				break;
+			}
+			
+			p2 = strchr(path, ':');
+			if (p2)
+				path = p2 + 1;
+			else
+				path = 0;
+		}
+	}
+#endif
+
+	/*
+	 * Now for each command argument, see if it is a wildcard, and if
+	 * so, replace the argument with the list of matching filenames.
+	 */
+	newargc = 1;
+	oac = 0;
+
+	while (++oac < argc) {
+		if (argv[oac][0] == '"' || argv[oac][0] == '\'') {
+			argv[oac]++;
+			matches = 0;
+		}
+		else {
+			matches = expandwildcards(argv[oac], MAXARGS, nametable);
+			if (matches < 0)
+				return;
+		}
+
+		if ((newargc + matches) >= MAXARGS) {
+			fprintf(stderr, "Too many arguments\n");
+			return;
+		}
+
+		if (matches == 0)
+			newargv[newargc++] = argv[oac];
+
+		for (i = 0; i < matches; i++)
+			newargv[newargc++] = nametable[i];
+	}
+	
+	newargv[newargc] = 0;
+
+	magic = FALSE;
+	
+	/*
+	for (cp = cmd; *cp; cp++) {
+		if ((*cp >= 'a') && (*cp <= 'z'))
+			continue;
+		if ((*cp >= 'A') && (*cp <= 'Z'))
+			continue;	
+		if (isdecimal(*cp))
+			continue;
+		if (isblank(*cp))
+			continue;
+
+		if ((*cp == '.') || (*cp == '/') || (*cp == '-') ||
+			(*cp == '+') || (*cp == '=') || (*cp == '_') ||
+			(*cp == ':') || (*cp == ','))
+				continue;
+
+		magic = TRUE;
+	}
+	*/
+
+	if (magic) {
+		printf("%s: no such file or directory\n", cmd);
+		system(cmd);
+		return;
+	}
+	
+	if (!bg)
+		signal(SIGCHLD, SIG_DFL);
+
+	/*
+	 * No magic characters in the expanded command, so do the fork and
+	 * exec ourself.  If this fails with ENOEXEC, then run the
+	 * shell anyway since it might be a shell script.
+	 */
+	if (!(pid = vfork())) {
+		int	ci;
+
+		/*
+		 * We are the child, so run the program.
+		 * First close any extra file descriptors we have opened.
+		 * be sure not to modify any globals after the vfork !
+		 */	
+		
+		for (ci = 0; ci < sourcecount; ci++)
+			if (sourcefiles[ci] != stdin)
+				close(fileno(sourcefiles[ci]));
+		
+		signal(SIGINT, SIG_DFL);
+		signal(SIGQUIT, SIG_DFL);
+		signal(SIGCHLD, SIG_DFL);
+		
+		execvp(newargv[0], newargv);
+
+		printf("%s: %s\n", newargv[0], (errno == ENOENT) ? "Bad command or file name" : strerror(errno));
+		
+		_exit(0);
+	}
+	
+	if (pid < 0) {
+		memset(&act, 0, sizeof(act));
+		act.sa_handler = catchchild;
+		act.sa_flags = SA_RESTART;
+		sigaction(SIGCHLD, &act, NULL);
+
+		perror("vfork failed");
+		return;
+	}
+	
+	if (bg) {
+		printf("[%d]\n", pid);
+		return;
+	}
+
+	if (pid) {
+		int cpid;
+		status = 0;
+		intcrlf = FALSE;
+
+		for (;;) {
+			cpid = wait4(pid, &status, 0, 0);
+			if ((cpid < 0) && (errno == EINTR))
+				continue;
+			if (cpid < 0)
+				break;
+			if (cpid != pid) {
+				fprintf(stderr, "sh %d: child %d died\n", getpid(), cpid);
+				continue;
+			}
+		}
+
+		act.sa_handler = catchchild;
+		memset(&act.sa_mask, 0, sizeof(act.sa_mask));
+		act.sa_flags = SA_RESTART;
+		sigaction(SIGCHLD, &act, NULL);
+		
+		intcrlf = TRUE;
+
+		if (WIFEXITED(status)) {
+			if (WEXITSTATUS(status) == 0)
+				return;
+			exit_code = WEXITSTATUS(status);
+		} else
+			exit_code = 1;
+
+		return;
+	}
+	
+	perror(argv[0]);
+	exit(1);
+}
+
+#ifdef CMD_HELP
+void
+do_help(argc, argv)
+	char	**argv;
+{
+	CMDTAB	*cmdptr;
+
+	for (cmdptr = cmdtab; cmdptr->name && cmdptr->name[0]; cmdptr++)
+		printf("%-10s %s\n", cmdptr->name, cmdptr->usage);
+}
+#endif /* CMD_HELP */
+
+#ifdef CMD_ALIAS
+void
+do_alias(argc, argv)
+	char	**argv;
+{
+	char	*name;
+	char	*value;
+	ALIAS	*alias;
+	int	count;
+	char	buf[CMDLEN];
+
+	if (argc < 2) {
+		count = aliascount;
+		for (alias = aliastable; count-- > 0; alias++)
+			printf("%s\t%s\n", alias->name, alias->value);
+		return;
+	}
+
+	name = argv[1];
+	if (argc == 2) {
+		alias = findalias(name);
+		if (alias)
+			printf("%s\n", alias->value);
+		else
+			fprintf(stderr, "Alias \"%s\" is not defined\n", name);
+		return;	
+	}
+
+	if (strcmp(name, "alias") == 0) {
+		fprintf(stderr, "Cannot alias \"alias\"\n");
+		return;
+	}
+
+	if (!makestring(argc - 2, argv + 2, buf, CMDLEN))
+		return;
+
+	value = malloc(strlen(buf) + 1);
+
+	if (value == NULL) {
+		fprintf(stderr, "No memory for alias value\n");
+		return;
+	}
+
+	strcpy(value, buf);
+
+	alias = findalias(name);
+	if (alias) {
+		free(alias->value);
+		alias->value = value;
+		return;
+	}
+
+	if ((aliascount % ALIASALLOC) == 0) {
+		count = aliascount + ALIASALLOC;
+
+		if (aliastable)
+			alias = (ALIAS *) realloc(aliastable,
+				sizeof(ALIAS *) * count);
+		else
+			alias = (ALIAS *) malloc(sizeof(ALIAS *) * count);
+
+		if (alias == NULL) {
+			free(value);
+			fprintf(stderr, "No memory for alias table\n");
+			return;
+		}
+
+		aliastable = alias;
+	}
+
+	alias = &aliastable[aliascount];
+
+	alias->name = malloc(strlen(name) + 1);
+
+	if (alias->name == NULL) {
+		free(value);
+		fprintf(stderr, "No memory for alias name\n");
+		return;
+	}
+
+	strcpy(alias->name, name);
+	alias->value = value;
+	aliascount++;
+}
+#endif /* CMD_ALIAS */
+
+/*
+ * Look up an alias name, and return a pointer to it.
+ * Returns NULL if the name does not exist.
+ */
+static ALIAS *
+findalias(name)
+	char	*name;
+{
+	ALIAS	*alias;
+	int	count;
+
+	count = aliascount;
+	for (alias = aliastable; count-- > 0; alias++) {
+		if (strcmp(name, alias->name) == 0)
+			return alias;
+	}
+
+	return NULL;
+}
+
+
+void
+do_source(argc, argv)
+	char	**argv;
+{
+	readfile(argv[1]);
+}
+
+/*void
+do_cd(argc, argv)
+	char	**argv;
+{
+	char	*name;
+
+	name = argv[1];
+	
+	if (chdir(name))
+		perror("Unable to chdir to %s");
+	
+}*/
+
+void
+do_pid(argc, argv)
+{
+	printf("%d\n", getpid());
+}
+
+void
+do_exec(argc, argv)
+	char	**argv;
+{
+	while (--sourcecount >= 0) {
+		if (sourcefiles[sourcecount] != stdin)
+			fclose(sourcefiles[sourcecount]);
+	}
+
+	argv[argc] = NULL;
+	execvp(argv[1], &argv[1]);
+
+	perror(argv[1]);
+	exit(1);
+}
+
+/*void
+do_exit(argc, argv)
+	char	**argv;
+{
+	if (argc>1)
+		exit(atoi(argv[1]));
+	else
+		exit(0);
+}*/
+
+
+#ifdef CMD_ALIAS
+void
+do_unalias(argc, argv)
+	char	**argv;
+{
+	ALIAS	*alias;
+
+	while (--argc > 0) {
+		alias = findalias(*++argv);
+		if (alias == NULL)
+			continue;
+
+		free(alias->name);
+		free(alias->value);
+		aliascount--;
+		alias->name = aliastable[aliascount].name;
+		alias->value = aliastable[aliascount].value;	
+	}
+}
+#endif /* CMD_ALIAS */
+
+/*
+ * Display the prompt string.
+ */
+static void
+showprompt()
+{
+	char	*cp;
+	//;'pa990523 changed from 6...
+	char buf[60];
+	
+	if ((cp = getenv("PS1")) != NULL) {
+		printf("%s", cp);
+	}
+	else {
+		*buf = '\0';
+		getcwd(buf, sizeof(buf) - 1);
+		printf("%s> ", buf);
+	}
+	fflush(stdout);
+}	
+
+
+static void
+catchint()
+{
+	signal(SIGINT, catchint);
+
+	intflag = TRUE;
+
+	if (intcrlf)
+		write(STDOUT, "\n", 1);
+}
+
+
+static void
+catchquit()
+{
+	signal(SIGQUIT, catchquit);
+
+	intflag = TRUE;
+
+	if (intcrlf)
+		write(STDOUT, "\n", 1);
+}
+
+static void
+catchchild()
+{
+	char buf[40];
+	pid_t pid;
+	int status;
+	
+	/*signal(SIGCHLD, catchchild);*/ /* Unneeded */
+
+	pid = wait4(-1, &status, WUNTRACED, 0);
+	if (WIFSTOPPED(status))
+		sprintf(buf, "sh %d: Child %d stopped\n", getpid(), pid);
+	else
+		sprintf(buf, "sh %d: Child %d died\n", getpid(), pid);
+	
+	if (intcrlf)
+		write(STDOUT, "\n", 1);
+	
+	write(STDOUT, buf, strlen(buf));
+}
+
+/* END CODE */

+ 70 - 0
package/sash/src/sash.h

@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 1993 by David I. Bell
+ * Permission is granted to use, distribute, or modify this source,
+ * provided that this copyright notice remains intact.
+ *
+ * Definitions for stand-alone shell for system maintainance for Linux.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <malloc.h>
+#include <ctype.h>
+
+#define	PATHLEN		256	
+#define	CMDLEN		1024
+#define	MAXARGS		50	
+#define	ALIASALLOC	20
+#define	STDIN		0
+#define	STDOUT		1
+#define	MAXSOURCE	10
+#ifdef COMMAND_HISTORY
+#define HISTORY_SIZE	20	/* Number of entries in command history */
+#endif
+
+#ifndef	isblank
+#define	isblank(ch)	(((ch) == ' ') || ((ch) == '\t'))
+#endif
+
+#define	isquote(ch)	(((ch) == '"') || ((ch) == '\''))
+#define	isdecimal(ch)	(((ch) >= '0') && ((ch) <= '9'))
+#define	isoctal(ch)	(((ch) >= '0') && ((ch) <= '7'))
+
+
+typedef	int	BOOL;
+
+#define	FALSE	((BOOL) 0)
+#define	TRUE	((BOOL) 1)
+
+
+extern	void	do_alias(), do_cd(), do_exec(), do_exit(), do_prompt();
+extern	void	do_source(), do_umask(), do_unalias(), do_help(), do_ln();
+extern	void	do_cp(), do_mv(), do_rm(), do_chmod(), do_mkdir(), do_rmdir();
+extern	void	do_mknod(), do_chown(), do_chgrp(), do_sync(), do_printenv();
+extern	void	do_more(), do_cmp(), do_touch(), do_ls(), do_dd(), do_tar();
+extern	void	do_mount(), do_umount(), do_setenv(), do_pwd(), do_echo();
+extern	void	do_kill(), do_grep(), do_ed(), do_hexdump(), do_pid();
+extern	void	do_df(), do_ps(), do_reboot(), do_cat(), do_time(), do_free();
+extern	void	do_hostname(), do_sleep();
+extern	void	do_date();
+
+
+extern	char	*buildname();
+extern	char	*modestring();
+extern	char	*timestring();
+extern	BOOL	isadir();
+extern	BOOL	copyfile();
+extern	BOOL	match();
+extern	BOOL	makestring();
+extern	BOOL	makeargs();
+extern	int	expandwildcards();
+extern	int	namesort();
+extern	char	*getchunk();
+extern	void	freechunks();
+extern	char	*expandenvvar();
+
+extern	BOOL	intflag;
+extern	int	exit_code;
+
+/* END CODE */

+ 75 - 0
package/sash/src/shutdown.c

@@ -0,0 +1,75 @@
+/* shutdown.c:
+ *
+ * Copyright (C) 1998  Kenneth Albanowski <kjahds@kjahds.com>,
+ *
+ * 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; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include "sash.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+#include <sys/stat.h>
+#include <dirent.h>
+#include <pwd.h>
+#include <grp.h>
+#include <time.h>
+#include <signal.h>
+
+#if __GNU_LIBRARY__ > 5
+#include <sys/reboot.h>
+#endif
+
+int
+main(argc, argv)
+	int argc;
+	char	**argv;
+{
+	char *progname = argv[0];
+
+	if (argc > 2 && strcmp(argv[1], "-d") == 0) {
+		sleep(atoi(argv[2]));
+		argc -= 2;
+	}
+	if ((argc != 3) || (strcmp(argv[1], "-h") && strcmp(argv[1], "-r")) || strcmp(argv[2], "now")) {
+		printf("Usage: %s [-d delay] -h|-r now\n", progname);
+		exit(0);
+	}
+	
+	kill(1, SIGTSTP);
+	sync();
+	signal(SIGTERM,SIG_IGN);
+	setpgrp();
+	kill(-1, SIGTERM);
+	sleep(1);
+	kill(-1, SIGHUP); /* Force PPPD's down, too */
+	sleep(1);
+	kill(-1, SIGKILL);
+	sync();
+	sleep(1);
+	
+	if (strcmp(argv[1], "-h")==0) {
+#if __GNU_LIBRARY__ > 5
+		reboot(0xCDEF0123);
+#else
+		reboot(0xfee1dead, 672274793, 0xCDEF0123);
+#endif
+	} else {
+#if __GNU_LIBRARY__ > 5
+		reboot(0x01234567);
+#else
+		reboot(0xfee1dead, 672274793, 0x01234567);
+#endif
+	}
+	
+	exit(0); /* Shrug */
+}
+

+ 30 - 0
package/simpleinit/Makefile

@@ -0,0 +1,30 @@
+# This file is part of the OpenADK project. OpenADK is copyrighted
+# material, please see the LICENCE file in the top-level directory.
+
+include ${ADK_TOPDIR}/rules.mk
+
+PKG_NAME:=		simpleinit
+PKG_VERSION:=		1.0
+PKG_RELEASE:=		1
+PKG_DESCR:=		simple init for systems without mmu
+PKG_SECTION:=		base/apps
+
+NO_DISTFILES:=		1
+
+include ${ADK_TOPDIR}/mk/package.mk
+
+$(eval $(call PKG_template,SIMPLEINIT,simpleinit,${PKG_VERSION}-${PKG_RELEASE},${PKG_DEPENDS},${PKG_DESCR},${PKG_SECTION}))
+
+CONFIG_STYLE:=		manual
+BUILD_STYLE:=		manual
+INSTALL_STYLE:=		manual
+
+do-build:
+	${TARGET_CC} ${TARGET_CPPFLAGS} ${TARGET_CFLAGS} ${TARGET_LDFLAGS} \
+		-o ${WRKBUILD}/simpleinit ${WRKBUILD}/simpleinit.c
+
+do-install:
+	${INSTALL_DIR} ${IDIR_SIMPLEINIT}/sbin
+	${INSTALL_BIN} ${WRKBUILD}/simpleinit ${IDIR_SIMPLEINIT}/sbin/init
+
+include ${ADK_TOPDIR}/mk/pkg-bottom.mk

+ 47 - 0
package/simpleinit/files/rc

@@ -0,0 +1,47 @@
+#!/bin/sh
+set -x
+export PATH=/bin:/sbin:/usr/bin:/usr/sbin
+ln -s /proc/self/fd/2 /dev/stderr
+: ${rcquiet=0}
+if [ $rcquiet -ne 1 ];then
+	echo "System initialization ..."
+fi
+
+# remount /dev with smaller size
+mount -o remount,nosuid,size=128k,mode=0755 -t tmpfs mdev /dev
+
+# start mdev dynamic device node management
+echo >/dev/mdev.seq
+if [ -f /proc/sys/kernel/hotplug ];then
+	echo "/sbin/mdev" >/proc/sys/kernel/hotplug
+fi
+# creates f.e. /dev/root
+mdev -s
+
+# seed some random
+cat /etc/.rnd >/dev/urandom 2>&1
+
+# setup cfgfs
+[ -x /sbin/cfgfs ] && {
+	cfgfs setup
+	mount -o remount,ro /
+}
+
+# remount /tmp with smaller size
+size=$(cat /etc/tmpfs 2>/dev/null)
+[ -z $size ] && size=2048
+mount -o remount,nosuid,nodev,mode=1777,size=${size}k -t tmpfs tmpfs /tmp
+
+# create some useful directories in tmpfs
+mkdir -p /var/log
+mkdir -p /var/run
+mkdir -p /var/tmp
+touch /var/log/lastlog
+touch /var/log/wtmp
+
+HOSTNAME=
+[[ -s /etc/hostname ]] && HOSTNAME=$(cat /etc/hostname)
+HOSTNAME=${HOSTNAME%%.*}
+echo ${HOSTNAME:=openadk} >/proc/sys/kernel/hostname
+
+chown 0:0 /tmp; chmod 1777 /tmp

+ 37 - 0
package/simpleinit/src/pathnames.h

@@ -0,0 +1,37 @@
+/*
+ *	@(#)pathnames.h	5.3 (Berkeley) 5/9/89
+ *
+ * Heavily modified by poe@daimi.aau.dk for Linux
+ */
+
+#include <paths.h>
+
+#ifndef __STDC__
+# error "we need an ANSI compiler"
+#endif
+
+#ifndef SBINDIR
+# define SBINDIR "/sbin"
+#endif
+
+#define _PATH_BSHELL    "/bin/sh"
+#define _PATH_CSHELL    "/bin/csh"
+#define _PATH_TTY       "/dev/tty"
+#define TTYTYPES        "/etc/ttytype"
+#define SECURETTY       "/etc/securetty"
+
+#define	_PATH_HUSHLOGIN	".hushlogin"
+#define	_PATH_MOTDFILE	"/etc/motd"
+#define	_PATH_NOLOGIN	"/etc/nologin"
+
+#define _PATH_LOGIN	"/bin/login"
+#define _PATH_INITTAB	"/etc/inittab"
+#define _PATH_RC	"/etc/rc"
+#define _PATH_REBOOT	"/bin/reboot"
+#define _PATH_SINGLE	"/etc/singleboot"
+#define _PATH_SECURE	"/etc/securesingle"
+#define _PATH_USERTTY   "/etc/usertty"
+
+#define _PATH_CONFIGRC	"/etc/config/start"
+#define _PATH_CONFIGTAB	"/etc/config/inittab"
+#define _PATH_FIREWALL  "/bin/firewall"

+ 1046 - 0
package/simpleinit/src/simpleinit.c

@@ -0,0 +1,1046 @@
+/* simpleinit.c - poe@daimi.aau.dk */
+/* Version 1.21 */
+
+/* gerg@snapgear.com -- modified for direct console support DEC/1999 */
+/* davidm@snapgear.com -- modified for init.conf SEP/2004 */
+/* toby@snapgear.com -- allow the array of commands to grow as needed OCT/2004 */
+/* davidm@snapgear.com -- use dynamically allocated tables APR/2005 */
+
+#define _GNU_SOURCE	/* For crypt() and termios defines */
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <limits.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <signal.h>
+#include <pwd.h>
+#include <sys/file.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/termios.h>
+#include <sys/ioctl.h>
+#include <sys/uio.h>
+#include <linux/version.h>
+#include <utmp.h>
+#include <errno.h>
+#include <time.h>
+#include <termios.h>
+#ifdef SHADOW_PWD
+#include <shadow.h>
+#endif
+
+#if __GNU_LIBRARY__ > 5
+#include <sys/reboot.h>
+#endif
+
+#include "pathnames.h"
+
+#define BUF_SIZ 100	/* max size of a line in inittab */
+#define NUMCMD 30	/* step size when realloc more space for the commands */
+#define NUMTOK 20	/* max number of tokens in inittab command */
+
+/* Threshold time for detecting "fast" spawning processes */
+static int testtime  = 90;
+/* Number of rapid respawns that counts as too fast */
+static int maxspawn  = 5;
+/* Maximum delay between runs */
+static int maxdelay  = 595;
+/* Time between successive runs of a process */
+static int delaytime = 5;
+
+#define MAXTRIES 3	/* number of tries allowed when giving the password */
+
+#define RUN_RC		/* Use a console if possible */
+
+#ifndef CTRL
+#define CTRL(X) ((X)&037)
+#endif
+
+#ifdef INCLUDE_TIMEZONE
+char tzone[BUF_SIZ];
+#endif
+/* #define DEBUGGING */
+
+/* Define this if you want init to ignore the termcap field in inittab for
+   console ttys. */
+/* #define SPECIAL_CONSOLE_TERM */
+
+struct initline {
+	pid_t	pid;
+	time_t	lastrun;
+	time_t	nextrun;
+	char	**toks;
+	short	delay;
+	char	tty[10];
+	char	termcap[30];
+	char	*line;
+	char	*fullline;
+	unsigned char xcnt;
+};
+
+struct initline *inittab;
+/* How many struct initline's will fit in the memory pointed to by inittab */
+int inittab_size = 0; 
+int numcmd;
+int stopped = 0;	/* are we stopped */
+int reload = 0;	/* are we stopped */
+int run_sigint_processing = 0;
+
+extern void spawn(int);
+extern void hup_handler();
+extern void reload_inittab();
+extern void read_inittab(void);
+static int  read_initfile(const char *);
+extern void tstp_handler();
+extern void int_handler();
+extern void sigint_processing();
+extern void cont_handler();
+extern void set_tz(void);
+extern void write_wtmp(void);
+extern void make_ascii_tty(void);
+extern void make_console(const char *);
+extern int boot_single(int singlearg, int argc, char *argv[]);
+#ifdef CONFIG_USER_INIT_CONF
+extern void load_init_conf(void);
+#endif
+
+/* Keep track of console device, if any... */
+#if LINUX_VERSION_CODE < 0x020100
+char	*console_device = NULL;
+int	console_baud = -1;
+#else
+int have_console = 0;
+#endif
+
+
+static void err(const char *s)
+{
+	struct iovec output[2];
+#if LINUX_VERSION_CODE < 0x020100
+	int fd;
+#endif
+	output[0].iov_base = "init: ";
+	output[0].iov_len = 6;
+	output[1].iov_base = (void *)s;
+	output[1].iov_len = strlen(s);
+#if LINUX_VERSION_CODE < 0x020100	
+	if (console_device == NULL) return;
+	if((fd = open(console_device, O_WRONLY)) < 0) return;
+	writev(fd, output, 2);
+	close(fd);
+#else
+	if (have_console)
+		writev(1, output, 2);
+#endif
+}
+
+void
+add_tok(struct initline *p, char *tok)
+{
+	int i;
+	for (i = 0; p->toks && p->toks[i]; i++)
+		;
+
+	/* allocate space for new entry and terminating NULL */
+	p->toks = (char **) realloc(p->toks, (i + 2) * sizeof(char *));
+	if (!p->toks) {
+		err("malloc failed\n");
+		_exit(1);
+	}
+	p->toks[i++] = tok;
+	p->toks[i] = NULL;
+}
+
+static void enter_single(void)
+{
+	pid_t pid;
+	char *av[2];
+
+    err("Booting to single user mode\n");
+    av[0] = _PATH_BSHELL;
+    av[1] = NULL;
+    if((pid = vfork()) == 0) {
+    extern char **environ;
+	/* the child */
+	execve(_PATH_BSHELL, av, environ);
+	err("exec of single user shell failed\n");
+	_exit(0);
+    } else if(pid > 0) {
+    int i;
+	while(wait(&i) != pid) /* nothing */;
+    } else if(pid < 0) {
+	err("fork of single user shell failed\n");
+    }
+    unlink(_PATH_SINGLE);
+}
+
+
+#if LINUX_VERSION_CODE < 0x020100
+static void
+set_console_baud(int baud)
+{
+	switch (baud) {
+	case 50:     console_baud = B50; break;
+	case 75:     console_baud = B75; break;
+	case 110:    console_baud = B110; break;
+	case 134:    console_baud = B134; break;
+	case 150:    console_baud = B150; break;
+	case 200:    console_baud = B200; break;
+	case 300:    console_baud = B300; break;
+	case 600:    console_baud = B600; break;
+	case 1200:   console_baud = B1200; break;
+	case 1800:   console_baud = B1800; break;
+	case 2400:   console_baud = B2400; break;
+	case 4800:   console_baud = B4800; break;
+	default:
+	case 9600:   console_baud = B9600; break;
+	case 19200:  console_baud = B19200; break;
+	case 38400:  console_baud = B38400; break;
+	case 57600:  console_baud = B57600; break;
+	case 115200: console_baud = B115200; break;
+	case 230400: console_baud = B230400; break;
+	case 460800: console_baud = B460800; break;
+	}
+}
+#endif
+
+static int do_command(const char *path, const char *filename, int dowait)
+{
+	pid_t pid, wpid;
+	int stat, st;
+	
+	if((pid = vfork()) == 0) {
+		/* the child */
+		char *argv[3];
+#ifdef INCLUDE_TIMEZONE
+		char tz[BUF_SIZ];
+#endif
+		char *env[3];
+
+		/* Use /dev/null for stdin */
+		close(0);
+		open("/dev/null", O_RDONLY);
+
+		argv[0] = (char *)path;
+		argv[1] = (char *)filename;
+		argv[2] = NULL;
+
+		env[0] = "PATH=/bin:/usr/bin:/etc:/sbin:/usr/sbin";
+#ifdef INCLUDE_TIMEZONE
+		strcpy(tz, "TZ=");
+		strcat(tz, tzone);
+		env[1] = tz;
+		env[2] = NULL;
+#else
+		env[1] = NULL;
+#endif
+
+		execve(path, argv, env);
+
+		err("exec rc failed\n");
+		_exit(2);
+	} else if(pid > 0) {
+		if (!dowait)
+			stat = 0;
+		else {
+			/* parent, wait till rc process dies before spawning */
+			while ((wpid = wait(&stat)) != pid)
+				if (wpid == -1 && errno == ECHILD) { /* see wait(2) manpage */
+					stat = 0;
+					break;
+				}
+		}
+	} else if(pid < 0) {
+		err("fork of rc shell failed\n");
+		stat = -1;
+	}
+	st = WEXITSTATUS(stat);
+	return st;
+}
+
+/*
+ * run /etc/rc. The environment is passed to the script, so the RC environment
+ * variable can be used to decide what to do. RC may be set from LILO.
+ */
+static int do_rc(void)
+{
+	int rc;
+
+	rc = do_command(_PATH_BSHELL, _PATH_RC, 1);
+	if (rc)
+		return(rc);
+#ifdef CONFIG_USER_INIT_RUN_FIREWALL
+	rc = do_command(_PATH_FIREWALL, "-i", 1);
+	if (rc)
+		err(_PATH_FIREWALL " failed!");
+#endif
+#ifdef CONFIG_USER_FLATFSD_FLATFSD
+	rc = do_command(_PATH_BSHELL, _PATH_CONFIGRC, 1);
+	if (rc)
+		err(_PATH_CONFIGRC " failed!");
+#endif
+#ifdef CONFIG_USER_INIT_RUN_FIREWALL
+	rc = do_command(_PATH_FIREWALL, NULL, 0);
+	if (rc)
+		err(_PATH_FIREWALL " failed!");
+#endif
+#ifdef INCLUDE_TIMEZONE
+	/* We read the timezone file here, because the flat file system
+	 * has probably been created by now.
+	 */
+	set_tz();
+#endif
+	return(0);
+}
+
+void respawn_children(int signo) {
+	int i, delta = -1;
+	time_t now;
+	alarm(0);
+	if ((now = time(NULL)) == 0) now = 1;
+	for(i = 0; i < numcmd; i++) {
+		if(inittab[i].pid < 0) {	/* Start jobs */
+			if(stopped)
+				inittab[i].pid = -1;
+			/*
+			** Do not spawn child from signal handler !
+			** SIGALRM would be blocked for the child
+			*/
+			else if (signo == 0)
+				spawn(i);
+		}
+		/* Check for naughty jobs */
+		if (inittab[i].nextrun > now) {
+		int d;
+			d = inittab[i].nextrun - now;
+			if (delta < 0 || d < delta)
+				delta = d;
+		}
+	}
+	if (delta > 0) {
+		alarm(delta);
+	}
+}
+
+int main(int argc, char *argv[])
+{
+	int 	i;
+	struct sigaction sa;
+
+	/*
+	 * setup all the signal handlers here
+	 */
+
+	memset(&sa, 0, sizeof(sa));
+	/* sa.sa_flags = SA_RESETHAND we want to keep the handlers armed */
+
+	sa.sa_handler = tstp_handler;
+	sigaction(SIGTSTP, &sa, NULL);
+
+	sa.sa_handler = cont_handler;
+	sigaction(SIGCONT, &sa, NULL);
+
+	sa.sa_handler = int_handler;
+	sigaction(SIGINT, &sa, NULL);
+
+	sa.sa_handler = respawn_children;
+	sigaction(SIGALRM, &sa, NULL);
+
+	sa.sa_handler = hup_handler;
+	sigaction(SIGHUP, &sa, NULL);
+
+#if defined(CONSOLE_BAUD_RATE) && LINUX_VERSION_CODE < 0x020100
+	set_console_baud(CONSOLE_BAUD_RATE);
+#endif
+
+	/* 
+	 * start up in single user mode if /etc/singleboot exists or if
+	 * argv[1] is "single".
+	 */
+	if(boot_single(0, argc, argv)) enter_single();
+
+#ifdef RUN_RC
+	/* Register console if defined by boot */
+#if LINUX_VERSION_CODE < 0x020100
+	if ((console_device = getenv("CONSOLE"))) {
+	char	*sp;
+		unsetenv("CONSOLE");
+		if ((sp = strchr(console_device, ','))) {
+			*sp++ = 0;
+			set_console_baud(atoi(sp));
+		}
+	}
+
+	make_ascii_tty();
+#else
+{
+	struct stat st;
+
+	if (isatty(1)) {
+		have_console = 1;
+		make_ascii_tty();
+	} else if (fstat(1, &st) == -1 && errno == EBADF) {
+		/* No stdout, so send everything to /dev/null */
+		close(0); close(1); close(2);
+		open("/dev/null", O_RDWR);
+		dup(0);
+		dup(0);
+	}
+}
+#endif
+
+	/*If we get a SIGTSTP before multi-user mode, do nothing*/
+	while(stopped)	
+		pause();
+	if(do_rc() != 0 && boot_single(1, argc, argv) && !stopped)
+		enter_single();
+	while(stopped)	/*Also if /etc/rc fails & we get SIGTSTP*/
+		pause();
+#endif
+
+	/* initialize the array of commands */
+	inittab = (struct initline *)malloc(NUMCMD * sizeof(struct initline));
+	inittab_size = NUMCMD;
+
+	if (!inittab) {
+		/* failure case - what do you do if init fails? */
+		err("malloc failed");
+		_exit(1);
+	}
+
+	write_wtmp();	/* write boottime record */
+	read_inittab();
+
+#ifdef DEBUGGING
+	for(i = 0; i < numcmd; i++) {
+		char **p = inittab[i].toks;
+		printf("toks= %s %s %s %s\n",p[0], p[1], p[2], p[3]);
+		printf("tty= %s\n", inittab[i].tty);
+		printf("termcap= %s\n", inittab[i].termcap);
+	}
+	/*exit(0);*/
+#endif
+
+#if LINUX_VERSION_CODE < 0x020100
+	for(i = 0; i < getdtablesize(); i++) close(i);
+#else
+	/* Always leave 0, 1, and 2 connected (to /dev/null) for the child process */
+	for(i = 3; i < getdtablesize(); i++) close(i);
+#endif
+
+	for (;;) {
+		pid_t	pid;
+		int	vec;
+
+		if (run_sigint_processing) {
+			run_sigint_processing = 0;
+			sigint_processing();
+		}
+
+		respawn_children(0);
+
+		if (reload) {
+			reload = 0;
+			reload_inittab();
+			continue; /* process all reloads before waiting */
+		}
+
+		pid = wait(&vec);
+		alarm(0);
+
+		/* clear utmp entry, and append to wtmp if possible */
+#if 0		/* DAVIDM */
+		{
+		    struct utmp *ut;
+		    int ut_fd;
+
+		    utmpname(_PATH_UTMP);
+		    setutent();
+		    while((ut = getutent())) {
+			if(ut->ut_pid == pid) {
+			    time(&ut->ut_time);
+			    bzero(&ut->ut_user, UT_NAMESIZE);
+			    bzero(&ut->ut_host, sizeof(ut->ut_host));
+			    ut->ut_type = DEAD_PROCESS;
+			    ut->ut_pid = 0;
+			    ut->ut_addr = 0;
+			    endutent();
+			    pututline(ut);
+			    if((ut_fd = open(_PATH_WTMP, O_APPEND|O_WRONLY)) >= 0) {
+				flock(ut_fd, LOCK_EX|LOCK_NB);
+				write(ut_fd, (const void *)ut, sizeof(struct utmp));
+				flock(ut_fd, LOCK_UN|LOCK_NB);
+				close(ut_fd);
+			    }
+			    break;
+			}
+		    }
+		    endutent();
+		}
+#endif
+
+		for(i = 0; i < numcmd; i++) {
+			if(pid == inittab[i].pid) {
+				inittab[i].pid = -1;
+			}
+		}
+	}
+}	
+
+
+/*
+ * return true if we should boot up in singleuser mode. If argv[i] is 
+ * "single" or the file /etc/singleboot exists, then singleuser mode should
+ * be entered. If /etc/securesingle exists ask for root password first.
+ */
+int boot_single(int singlearg, int argc, char *argv[])
+{
+	char *pass, *rootpass = NULL;
+	struct passwd *pwd;
+	int i;
+
+	for(i = 1; i < argc; i++) {
+	    if(argv[i] && !strcmp(argv[i], "single")) singlearg = 1;
+	}
+	return 0;
+}
+
+void spawn(int i)
+{
+	pid_t pid;
+	int j;
+	time_t t;
+	struct initline *it;
+	char buf[150];
+	
+	it = inittab + i;
+
+	t = time(NULL);
+	/* Check for held process */
+	if ((unsigned long)(it->nextrun - t - 1) < maxdelay)
+		return;
+	if (it->lastrun + testtime > t) {	/* Respawning quickly */
+		if (it->xcnt < 0xff)
+			it->xcnt++;
+	} else {				/* Normal respawning */
+		it->xcnt = 0;
+		it->lastrun = t;
+		it->delay = delaytime;
+	}
+	if (it->xcnt >= maxspawn) {		/* Too many too quickly */
+		strcpy(buf, it->toks[0]);
+		strcat(buf, " respawning too fast\n");
+		err(buf);
+		it->pid = -1;
+		if (it->delay >= maxdelay)
+			it->delay = maxdelay;
+		else if (it->delay < delaytime)
+			it->delay = delaytime;
+		else if((it->delay *= 2) > maxdelay)
+			it->delay = maxdelay;
+		it->nextrun = t + it->delay;
+		/* Fiddle with the tracking vars to ensure that only
+		 * one attempt is made to run this next time around.
+		 */
+		it->lastrun = it->nextrun;
+		it->xcnt -= 2;
+		return;
+	}
+	it->nextrun = t + delaytime;
+	
+	if((pid = vfork()) < 0) {
+		it->pid = -1;
+		err("fork failed\n");
+		return;
+	}
+	if(pid) {
+		/* this is the parent */
+		it->pid = pid;
+		return;
+	} else {
+		/* this is the child */
+		char term[40];
+		char *prog;
+#ifdef INCLUDE_TIMEZONE
+		char tz[BUF_SIZ];
+#endif
+		char *env[4];
+		
+		setsid();
+
+		/* Close everything other than 0, 1 and 2 */
+		for(j = 3; j < getdtablesize(); j++) {
+			close(j);
+		}
+		/* Now set up 0, 1 and 2 */
+		make_console(it->tty);
+
+		strcpy(term, "TERM=");
+		strcat(term, it->termcap);
+		env[0] = term;
+		env[1] = "PATH=/bin:/usr/bin:/etc:/sbin:/usr/sbin";
+#ifdef INCLUDE_TIMEZONE
+		strcpy(tz, "TZ=");
+		strcat(tz, tzone);
+		env[2] = tz;
+		env[3] = NULL;
+#else
+		env[2] = NULL;
+#endif
+
+		prog = it->toks[0];
+		if (*prog == '-' && *(prog+1))
+			prog++;
+		execve(prog, it->toks, env);
+		strcpy(buf, it->toks[0]);
+		strcat(buf, " exec failed\n");
+		err(buf);
+		_exit(1);
+	}
+}
+
+static void init_itab(struct initline *p) {
+	bzero(p, sizeof(struct initline));
+	p->pid = -1;
+	p->nextrun = time(NULL);
+}
+
+static void clear_itab(struct initline *p) {
+	if (p->line)
+		free(p->line);
+	if (p->fullline)
+		free(p->fullline);
+	if (p->toks)
+		free(p->toks);
+	init_itab(p);
+}
+
+void read_inittab(void)
+{
+	int i;
+
+	/*
+	 * free any old data and start again
+	 */
+	for (i = 0; i < numcmd; i++)
+		clear_itab(&inittab[i]);
+	numcmd = 0;
+
+	/* Fake an inittab entry if boot console defined */
+#ifdef CONFIG_USER_INIT_CONSOLE_SH
+#if LINUX_VERSION_CODE < 0x020100
+	if (console_device && strcmp(console_device, "/dev/null"))
+#else
+	if (have_console)
+#endif
+	{
+	struct initline *p;
+		p = inittab + numcmd++;
+		init_itab(p);
+		p->fullline = strdup("console");
+		strcpy(p->tty, "console");
+		strcpy(p->termcap, "linux");
+		add_tok(p, "-/bin/sh");
+	}
+#endif
+
+	i = 0;
+	if (read_initfile(_PATH_INITTAB) == 0)
+		i++;
+
+#ifdef CONFIG_USER_FLATFSD_FLATFSD
+	if (read_initfile(_PATH_CONFIGTAB) == 0)
+		i++;
+#endif
+
+	if (i == 0) {
+		err("Failed to open " _PATH_INITTAB
+#ifdef CONFIG_USER_FLATFSD_FLATFSD
+				" or " _PATH_CONFIGTAB
+#endif
+				"."
+				);
+	}
+
+#ifdef CONFIG_USER_INIT_CONF
+	load_init_conf();
+#endif
+
+	/* if needed, shrink the array using realloc -
+	 * must be done here so that we include the results of all init files
+	 * when calculating number of commands */
+	if ((numcmd + 2) < (inittab_size - NUMCMD)) {
+		/* round up from numcmd to the nearest multiple of NUMCMD */
+		inittab_size = ((numcmd + 2) / NUMCMD + 1) * NUMCMD;
+		inittab = realloc(inittab, inittab_size * sizeof(struct initline));
+		if (!inittab) {
+			/* failure case - what do you do if init fails? */
+			err("malloc failed");
+			_exit(1);
+		}
+	}
+
+	if (numcmd == 0)
+		_exit(1);
+}
+
+static int
+read_initfile(const char *initfile)
+{
+	struct initline *p;
+	FILE *f;
+	char *buf = NULL;
+	size_t buf_len = 0;
+	int i,j,k;
+	char *ptr, *getty;
+#ifdef SPECIAL_CONSOLE_TERM
+	char tty[50];
+	struct stat stb;
+	char *termenv;
+
+	termenv = getenv("TERM");	/* set by kernel */
+#endif
+
+	i = numcmd;
+
+	if (!(f = fopen(initfile, "r")))
+		return 1;
+
+	while(!feof(f)) {
+		if (i+2 == inittab_size) {
+			/* need to realloc inittab */
+			inittab_size += NUMCMD;
+			inittab = realloc(inittab, inittab_size * sizeof(struct initline));
+			if (!inittab) {
+				/* failure case - what do you do if init fails? */
+				err("malloc failed");
+				_exit(1);
+			}
+		}
+		if (getline(&buf, &buf_len, f) == -1) break;
+
+		for(k = 0; k < buf_len && buf[k]; k++) {
+			if(buf[k] == '#') { 
+				buf[k] = '\0'; break; 
+			}
+		}
+
+		if(buf[0] == '\0' || buf[0] == '\n') continue;
+
+		p = inittab + i;
+		init_itab(p);
+		p->line = strdup(buf);
+		p->fullline = strdup(buf);
+		if (!p->line || !p->fullline) {
+			err("Not memory to allocate inittab entry");
+			clear_itab(p);
+			continue;
+		}
+		ptr = strtok(p->line, ":");
+		if (!ptr) {
+			err("Missing TTY/ID field in inittab");
+			clear_itab(p);
+			continue;
+		}
+		strncpy(p->tty, ptr, 9);
+		//p->tty[9] = '\0';
+		ptr = strtok(NULL, ":");
+		if (!ptr) {
+			err("Missing TERMTYPE field in inittab");
+			clear_itab(p);
+			continue;
+		}
+		strncpy(p->termcap, ptr, 29);
+		//p->termcap[29] = '\0';
+
+		getty = strtok(NULL, " \t\n");
+		if (!getty) {
+			err("Missing PROCESS field in inittab");
+			clear_itab(p);
+			continue;
+		}
+		add_tok(p, getty);
+		j = 1;
+		while((ptr = strtok(NULL, " \t\n")))
+			add_tok(p, ptr);
+
+#ifdef SPECIAL_CONSOLE_TERM
+		/* special-case termcap for the console ttys */
+		strcpy(tty, "/dev/");
+		strcat(tty, p->tty);
+		if(!termenv || stat(tty, &stb) < 0) {
+			err("no TERM or cannot stat tty\n");
+		} else {
+			/* is it a console tty? */
+			if(major(stb.st_rdev) == 4 && minor(stb.st_rdev) < 64) {
+				strncpy(p->termcap, termenv, 30);
+				p->termcap[29] = 0;
+			}
+		}
+#endif
+
+		i++;
+	}
+
+	if (buf)
+		free(buf);
+	
+	fclose(f);
+
+	numcmd = i;
+	return 0;
+}
+
+void hup_handler()
+{
+	reload = 1;
+}
+
+void reload_inittab()
+{
+	int i;
+	int oldnum;
+	char ** saveline = (char **) malloc(inittab_size * sizeof(char *));
+	pid_t * savepid = (pid_t*) malloc(inittab_size * sizeof(pid_t));
+
+	if (!saveline || !savepid) {
+		/* another failure case - what DO you do if init fails */
+		err("malloc failed");
+		_exit(1);
+	}
+
+	for (i=0; i<numcmd; i++) {
+		savepid[i] = inittab[i].pid;
+		saveline[i] = strdup(inittab[i].fullline);
+		if (!saveline[i]) {
+			err("malloc failed");
+			_exit(1);
+		}
+	}
+
+	oldnum = numcmd;		
+	read_inittab();
+
+	/* See which ones still exist */
+	for(i = 0; i < numcmd; i++) {
+		int j;
+		for(j = 0; j < oldnum; j++) {
+			if(strcmp(saveline[j], inittab[i].fullline) == 0) {
+				inittab[i].pid = savepid[j];
+				savepid[j] = -1;
+				break;
+			}
+		}
+	}
+
+	/* Kill off processes no longer needed and free memory */
+	for(i = 0; i < oldnum; i++) {
+		if (savepid[i] > 1)
+			kill(savepid[i], SIGTERM);
+		free(saveline[i]);
+	}
+
+	free(saveline);
+	free(savepid);
+}
+
+void tstp_handler()
+{
+	stopped++;
+}
+
+void cont_handler()
+{
+	stopped = 0;
+}
+
+void int_handler()
+{
+	run_sigint_processing = 1;
+}
+
+void sigint_processing()
+{
+	/*
+	 * After Linux 0.96b PL1, we get a SIGINT when
+	 * the user presses Ctrl-Alt-Del...
+	 */
+
+	int pid;
+	
+	sync();
+	sync();
+	if((pid = vfork()) == 0) {
+	char *av[2];
+	extern char **environ;
+		/* reboot properly... */
+		av[0] = _PATH_REBOOT;
+		av[1] = NULL;
+		
+		execve(_PATH_REBOOT, av, environ);
+#if __GNU_LIBRARY__ > 5
+		reboot(0x1234567);
+#else
+		reboot(0xfee1dead, 672274793, 0x1234567);
+#endif
+		_exit(2);
+	} else if(pid < 0) {
+		/* fork failed, try the hard way... */
+#if __GNU_LIBRARY__ > 5
+		reboot(0x1234567);
+#else
+		reboot(0xfee1dead, 672274793, 0x1234567);
+#endif
+	}
+}
+
+#ifdef INCLUDE_TIMEZONE
+void set_tz(void)
+{
+	FILE *f;
+	int len;
+
+	if((f = fopen("/etc/config/TZ", "r")) == NULL &&
+	   (f = fopen("/etc/TZ", "r")) == NULL)
+		return;
+	fgets(tzone, BUF_SIZ-2, f);
+	fclose(f);
+	if((len=strlen(tzone)) < 2)
+		return;
+	tzone[len-1] = 0; /* get rid of the '\n' */
+	setenv("TZ", tzone, 0);
+}
+#endif
+
+#ifdef CONFIG_USER_INIT_CONF
+void load_init_conf(void)
+{
+	char line[BUF_SIZ];
+	FILE *f;
+
+	if ((f = fopen("/etc/config/init.conf", "r")) == NULL &&
+			(f = fopen("/etc/init.conf", "r")) == NULL)
+		return;
+	while (fgets(line, sizeof(line) - 2, f)) {
+		if (strncasecmp(line, "delaytime=", 10) == 0)
+			delaytime = atoi(line + 10);
+		if (strncasecmp(line, "maxdelay=", 9) == 0)
+			maxdelay = atoi(line + 9);
+		if (strncasecmp(line, "maxspawn=", 9) == 0)
+			maxspawn = atoi(line + 9);
+		if (strncasecmp(line, "testtime=", 9) == 0)
+			testtime = atoi(line + 9);
+	}
+	fclose(f);
+}
+#endif
+
+void write_wtmp(void)
+{
+#if 0
+    int fd;
+    struct utmp ut;
+    
+    bzero((char *)&ut, sizeof(ut));
+    strcpy(ut.ut_line, "~");
+    bzero(ut.ut_name, sizeof(ut.ut_name));
+    time(&ut.ut_time);
+    ut.ut_type = BOOT_TIME;
+    
+    if((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND)) >= 0) {
+	flock(fd, LOCK_EX|LOCK_NB); /* make sure init won't hang */
+	write(fd, (char *)&ut, sizeof(ut));
+	flock(fd, LOCK_UN|LOCK_NB);
+	close(fd);
+    }
+#endif
+}     
+
+void make_ascii_tty(void)
+{
+	struct termios tty;
+	const char *pt;
+
+	if (tcgetattr(0, &tty) < 0)
+		return;
+
+	tty.c_iflag &= ~(INLCR|IGNCR|IUCLC);
+	tty.c_iflag |= ICRNL;
+	tty.c_oflag &= ~(OCRNL|OLCUC|ONOCR|ONLRET|OFILL);
+	tty.c_oflag |= OPOST|ONLCR;
+	tty.c_cflag |= CLOCAL;
+	tty.c_lflag  = ISIG|ICANON|ECHO|ECHOE|ECHOK|ECHOCTL|ECHOKE;
+#ifdef IEXTEN
+	tty.c_lflag  |= IEXTEN;
+#endif
+
+#if LINUX_VERSION_CODE < 0x020100
+	if (console_baud != -1)
+		cfsetospeed(&tty, console_baud);
+#endif
+
+	tty.c_cc[VINTR]  = CTRL('C');
+	tty.c_cc[VQUIT]  = CTRL('\\');
+	tty.c_cc[VERASE] = CTRL('H'); /*127*/
+	tty.c_cc[VKILL]  = CTRL('U'); /*Changed from non-standard ^X*/
+	tty.c_cc[VEOF]   = CTRL('D');
+	tty.c_cc[VTIME]  = 0;
+	tty.c_cc[VMIN]   = 1;
+	tty.c_cc[VSTART] = CTRL('Q');
+	tty.c_cc[VSTOP]  = CTRL('S');
+	tty.c_cc[VSUSP]  = CTRL('Z');
+#ifdef VWERASE
+	tty.c_cc[VWERASE]  = CTRL('W');
+#endif
+	/* Pick up simple environment setting of VERASE.
+	 * Useful for setting on kernel command line.
+	 * e.g. TTYERASE=^?
+	 */
+	pt = getenv("TTYERASE");
+	if (pt && pt[0] == '^' && pt[1]) {
+		tty.c_cc[VERASE] = (pt[1] == '?') ? 127 : CTRL(pt[1]);
+	}
+
+	tcsetattr(0, TCSANOW, &tty);
+}
+
+void make_console(const char *tty)
+{
+	char devname[32];
+
+	close(0); close(1); close(2);
+
+	if (tty && *tty) {
+#if LINUX_VERSION_CODE < 0x020100
+	    /*
+	     *	until we get proper console support under 2.0
+	     */
+	    if (strcmp(tty, "console") == 0) {
+		    strcpy(devname, console_device);
+	    }
+	    else
+#endif
+	    {
+		    strcpy(devname, "/dev/");
+		    strcat(devname, tty);
+	    }
+
+	    /* Try to open the specified console */
+	    if (open(devname, O_RDWR|O_NONBLOCK) >= 0) {
+		fcntl(0, F_SETFL, 0);
+		dup(0); 
+		dup(0);
+		make_ascii_tty();
+		ioctl(0, TIOCSCTTY, (char*)0);
+		return;
+	    }
+	}
+
+	/* No go, so send to /dev/null */
+	open("/dev/null", O_RDWR|O_NONBLOCK);
+	dup(0);
+	dup(0);
+}

+ 2 - 0
target/config/Config.in

@@ -16,6 +16,8 @@ config ADK_TARGET_TOOLCHAIN
 
 
 config ADK_TARGET_UCLINUX
 config ADK_TARGET_UCLINUX
 	select ADK_TARGET_USE_STATIC_LIBS
 	select ADK_TARGET_USE_STATIC_LIBS
+	select ADK_PACKAGE_SASH
+	select ADK_PACKAGE_SIMPLEINIT
 	boolean
 	boolean
 
 
 config ADK_TARGET_QEMU
 config ADK_TARGET_QEMU

+ 14 - 2
target/config/Config.in.runtime

@@ -150,7 +150,7 @@ config ADK_RUNTIME_KBD_LAYOUT
 
 
 choice
 choice
 prompt "initial login shell for the root user"
 prompt "initial login shell for the root user"
-default ADK_ROOTSH_HUSH if ADK_TARGET_UCLINUX
+default ADK_ROOTSH_SASH if ADK_TARGET_UCLINUX
 default ADK_ROOTSH_MKSH
 default ADK_ROOTSH_MKSH
 
 
 config ADK_ROOTSH_MKSH
 config ADK_ROOTSH_MKSH
@@ -160,6 +160,12 @@ config ADK_ROOTSH_MKSH
 	  Use mksh (a Korn Shell variant) as standard login shell
 	  Use mksh (a Korn Shell variant) as standard login shell
 	  for the superuser.
 	  for the superuser.
 
 
+config ADK_ROOTSH_SASH
+	select ADK_PACKAGE_SASH if !ADK_TOOLCHAIN_ONLY
+	bool "sash (Shell compatible with non-MMU systems)"
+	help
+	  standalone shell.
+
 config ADK_ROOTSH_HUSH
 config ADK_ROOTSH_HUSH
 	select ADK_PACKAGE_HUSH if !ADK_TOOLCHAIN_ONLY
 	select ADK_PACKAGE_HUSH if !ADK_TOOLCHAIN_ONLY
 	bool "hush (Shell compatible with non-MMU systems)"
 	bool "hush (Shell compatible with non-MMU systems)"
@@ -197,7 +203,7 @@ endchoice
 
 
 choice
 choice
 prompt "system /bin/sh (POSIX script shell)"
 prompt "system /bin/sh (POSIX script shell)"
-default ADK_BINSH_HUSH if ADK_TARGET_UCLINUX
+default ADK_BINSH_SASH if ADK_TARGET_UCLINUX
 default ADK_BINSH_MKSH
 default ADK_BINSH_MKSH
 
 
 config ADK_BINSH_MKSH
 config ADK_BINSH_MKSH
@@ -207,6 +213,12 @@ config ADK_BINSH_MKSH
 	  Use mksh (a Korn Shell variant) as system shell, which is
 	  Use mksh (a Korn Shell variant) as system shell, which is
 	  both small and powerful, so quite suited for this task.
 	  both small and powerful, so quite suited for this task.
 
 
+config ADK_BINSH_SASH
+	select ADK_PACKAGE_SASH if !ADK_TOOLCHAIN_ONLY
+	bool "sash (Standalone Shell)"
+	help
+	  hush shell.
+
 config ADK_BINSH_HUSH
 config ADK_BINSH_HUSH
 	select ADK_PACKAGE_HUSH if !ADK_TOOLCHAIN_ONLY
 	select ADK_PACKAGE_HUSH if !ADK_TOOLCHAIN_ONLY
 	bool "hush (busybox)"
 	bool "hush (busybox)"

+ 2 - 3
target/m68k/uclibc-ng.config

@@ -54,9 +54,8 @@ UCLIBC_HAS_THREADS=y
 # PTHREADS_DEBUG_SUPPORT is not set
 # PTHREADS_DEBUG_SUPPORT is not set
 UCLIBC_HAS_SYSLOG=y
 UCLIBC_HAS_SYSLOG=y
 UCLIBC_HAS_LFS=y
 UCLIBC_HAS_LFS=y
-MALLOC=y
-# MALLOC_SIMPLE is not set
-MALLOC_GLIBC_COMPAT=y
+MALLOC_SIMPLE=y
+# MALLOC_GLIBC_COMPAT is not set
 UCLIBC_HAS_OBSTACK=y
 UCLIBC_HAS_OBSTACK=y
 UCLIBC_DYNAMIC_ATEXIT=y
 UCLIBC_DYNAMIC_ATEXIT=y
 UCLIBC_SUSV2_LEGACY=y
 UCLIBC_SUSV2_LEGACY=y

+ 43 - 38
target/m68k/uclibc.config

@@ -1,19 +1,32 @@
 #
 #
-# Automatically generated file; DO NOT EDIT.
-# uClibc-ng 1.0.0 C Library Configuration
+# Automatically generated make config: don't edit
+# Version: 0.9.33.2
+# Mon Aug 18 18:48:15 2014
 #
 #
 # TARGET_alpha is not set
 # TARGET_alpha is not set
-# TARGET_arc is not set
 # TARGET_arm is not set
 # TARGET_arm is not set
+# TARGET_avr32 is not set
 # TARGET_bfin is not set
 # TARGET_bfin is not set
+# TARGET_c6x is not set
+# TARGET_cris is not set
+# TARGET_e1 is not set
+# TARGET_frv is not set
+# TARGET_h8300 is not set
+# TARGET_hppa is not set
 # TARGET_i386 is not set
 # TARGET_i386 is not set
+# TARGET_i960 is not set
+# TARGET_ia64 is not set
 TARGET_m68k=y
 TARGET_m68k=y
-# TARGET_metag is not set
 # TARGET_microblaze is not set
 # TARGET_microblaze is not set
 # TARGET_mips is not set
 # TARGET_mips is not set
+# TARGET_nios is not set
+# TARGET_nios2 is not set
 # TARGET_powerpc is not set
 # TARGET_powerpc is not set
 # TARGET_sh is not set
 # TARGET_sh is not set
+# TARGET_sh64 is not set
 # TARGET_sparc is not set
 # TARGET_sparc is not set
+# TARGET_v850 is not set
+# TARGET_vax is not set
 # TARGET_x86_64 is not set
 # TARGET_x86_64 is not set
 # TARGET_xtensa is not set
 # TARGET_xtensa is not set
 
 
@@ -23,58 +36,48 @@ TARGET_m68k=y
 TARGET_ARCH="m68k"
 TARGET_ARCH="m68k"
 FORCE_OPTIONS_FOR_ARCH=y
 FORCE_OPTIONS_FOR_ARCH=y
 TARGET_SUBARCH=""
 TARGET_SUBARCH=""
-
-#
-# Using ELF file format
-#
-ARCH_HAS_DEPRECATED_SYSCALLS=y
+# UCLIBC_FORMAT_ELF is not set
+# UCLIBC_FORMAT_FDPIC_ELF is not set
+# UCLIBC_FORMAT_DSBT_ELF is not set
+# UCLIBC_FORMAT_FLAT is not set
+UCLIBC_FORMAT_FLAT_SEP_DATA=y
+# UCLIBC_FORMAT_SHARED_FLAT is not set
 ARCH_BIG_ENDIAN=y
 ARCH_BIG_ENDIAN=y
 
 
 #
 #
 # Using Big Endian
 # Using Big Endian
 #
 #
-ARCH_HAS_MMU=y
-ARCH_USE_MMU=y
+# ARCH_HAS_MMU is not set
 UCLIBC_HAS_FLOATS=y
 UCLIBC_HAS_FLOATS=y
-UCLIBC_HAS_FPU=y
+# UCLIBC_HAS_FPU is not set
+UCLIBC_HAS_SOFT_FLOAT=y
 DO_C99_MATH=y
 DO_C99_MATH=y
 # DO_XSI_MATH is not set
 # DO_XSI_MATH is not set
 UCLIBC_HAS_FENV=y
 UCLIBC_HAS_FENV=y
 UCLIBC_HAS_LONG_DOUBLE_MATH=y
 UCLIBC_HAS_LONG_DOUBLE_MATH=y
 KERNEL_HEADERS=""
 KERNEL_HEADERS=""
+UCLIBC_UCLINUX_BROKEN_MUNMAP=y
 HAVE_DOT_CONFIG=y
 HAVE_DOT_CONFIG=y
 
 
 #
 #
 # General Library Settings
 # General Library Settings
 #
 #
 DOPIC=y
 DOPIC=y
-HAVE_SHARED=y
-# FORCE_SHAREABLE_TEXT_SEGMENTS is not set
-LDSO_LDD_SUPPORT=y
-LDSO_CACHE_SUPPORT=y
-LDSO_PRELOAD_ENV_SUPPORT=y
-# LDSO_PRELOAD_FILE_SUPPORT is not set
-LDSO_BASE_FILENAME="ld.so"
-# LDSO_STANDALONE_SUPPORT is not set
-# LDSO_PRELINK_SUPPORT is not set
-UCLIBC_STATIC_LDCONFIG=y
-LDSO_RUNPATH=y
-LDSO_SAFE_RUNPATH=y
-LDSO_SEARCH_INTERP_PATH=y
-LDSO_LD_LIBRARY_PATH=y
-# LDSO_NO_CLEANUP is not set
-# LDSO_GNU_HASH_SUPPORT is not set
+ARCH_HAS_NO_SHARED=y
+ARCH_HAS_NO_LDSO=y
+UCLIBC_CTOR_DTOR=y
 HAS_NO_THREADS=y
 HAS_NO_THREADS=y
+# LINUXTHREADS_OLD is not set
+# LINUXTHREADS_NEW is not set
 # UCLIBC_HAS_THREADS_NATIVE is not set
 # UCLIBC_HAS_THREADS_NATIVE is not set
 UCLIBC_HAS_SYSLOG=y
 UCLIBC_HAS_SYSLOG=y
 UCLIBC_HAS_LFS=y
 UCLIBC_HAS_LFS=y
-# MALLOC is not set
+MALLOC=y
 # MALLOC_SIMPLE is not set
 # MALLOC_SIMPLE is not set
-MALLOC_STANDARD=y
+# MALLOC_STANDARD is not set
 MALLOC_GLIBC_COMPAT=y
 MALLOC_GLIBC_COMPAT=y
-UCLIBC_HAS_OBSTACK=y
 UCLIBC_DYNAMIC_ATEXIT=y
 UCLIBC_DYNAMIC_ATEXIT=y
-UCLIBC_SUSV2_LEGACY=y
+# COMPAT_ATEXIT is not set
 UCLIBC_SUSV3_LEGACY=y
 UCLIBC_SUSV3_LEGACY=y
 # UCLIBC_SUSV3_LEGACY_MACROS is not set
 # UCLIBC_SUSV3_LEGACY_MACROS is not set
 UCLIBC_SUSV4_LEGACY=y
 UCLIBC_SUSV4_LEGACY=y
@@ -104,6 +107,8 @@ UCLIBC_GRP_BUFFER_SIZE=256
 #
 #
 # Support various families of functions
 # Support various families of functions
 #
 #
+UCLIBC_LINUX_MODULE_26=y
+# UCLIBC_LINUX_MODULE_24 is not set
 UCLIBC_LINUX_SPECIFIC=y
 UCLIBC_LINUX_SPECIFIC=y
 UCLIBC_HAS_GNU_ERROR=y
 UCLIBC_HAS_GNU_ERROR=y
 UCLIBC_BSD_SPECIFIC=y
 UCLIBC_BSD_SPECIFIC=y
@@ -125,6 +130,7 @@ UCLIBC_HAS_NETWORK_SUPPORT=y
 UCLIBC_HAS_SOCKET=y
 UCLIBC_HAS_SOCKET=y
 UCLIBC_HAS_IPV4=y
 UCLIBC_HAS_IPV4=y
 UCLIBC_HAS_IPV6=y
 UCLIBC_HAS_IPV6=y
+# UCLIBC_HAS_RPC is not set
 UCLIBC_USE_NETLINK=y
 UCLIBC_USE_NETLINK=y
 UCLIBC_SUPPORT_AI_ADDRCONFIG=y
 UCLIBC_SUPPORT_AI_ADDRCONFIG=y
 UCLIBC_HAS_BSD_RES_CLOSE=y
 UCLIBC_HAS_BSD_RES_CLOSE=y
@@ -149,6 +155,8 @@ UCLIBC_HAS_WCHAR=y
 UCLIBC_HAS_HEXADECIMAL_FLOATS=y
 UCLIBC_HAS_HEXADECIMAL_FLOATS=y
 UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
 UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
 UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9
 UCLIBC_PRINTF_SCANF_POSITIONAL_ARGS=9
+# UCLIBC_HAS_SCANF_GLIBC_A_FLAG is not set
+# UCLIBC_HAS_STDIO_BUFSIZ_NONE is not set
 # UCLIBC_HAS_STDIO_BUFSIZ_256 is not set
 # UCLIBC_HAS_STDIO_BUFSIZ_256 is not set
 # UCLIBC_HAS_STDIO_BUFSIZ_512 is not set
 # UCLIBC_HAS_STDIO_BUFSIZ_512 is not set
 # UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set
 # UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set
@@ -178,7 +186,9 @@ UCLIBC_HAS_GNU_GETSUBOPT=y
 # Big and Tall
 # Big and Tall
 #
 #
 UCLIBC_HAS_REGEX=y
 UCLIBC_HAS_REGEX=y
+# UCLIBC_HAS_REGEX_OLD is not set
 UCLIBC_HAS_FNMATCH=y
 UCLIBC_HAS_FNMATCH=y
+# UCLIBC_HAS_FNMATCH_OLD is not set
 UCLIBC_HAS_WORDEXP=y
 UCLIBC_HAS_WORDEXP=y
 UCLIBC_HAS_NFTW=y
 UCLIBC_HAS_NFTW=y
 UCLIBC_HAS_FTW=y
 UCLIBC_HAS_FTW=y
@@ -199,10 +209,7 @@ HARDWIRED_ABSPATH=y
 # Security options
 # Security options
 #
 #
 UCLIBC_HAS_ARC4RANDOM=y
 UCLIBC_HAS_ARC4RANDOM=y
-# ARC4RANDOM_USES_NODEV is not set
 # UCLIBC_HAS_SSP is not set
 # UCLIBC_HAS_SSP is not set
-UCLIBC_BUILD_RELRO=y
-# UCLIBC_BUILD_NOW is not set
 UCLIBC_BUILD_NOEXECSTACK=y
 UCLIBC_BUILD_NOEXECSTACK=y
 
 
 #
 #
@@ -213,10 +220,8 @@ UCLIBC_EXTRA_CFLAGS=""
 # DODEBUG is not set
 # DODEBUG is not set
 # DOSTRIP is not set
 # DOSTRIP is not set
 # DOASSERTS is not set
 # DOASSERTS is not set
-# SUPPORT_LD_DEBUG is not set
-# SUPPORT_LD_DEBUG_EARLY is not set
 # UCLIBC_MALLOC_DEBUGGING is not set
 # UCLIBC_MALLOC_DEBUGGING is not set
-# UCLIBC_HAS_BACKTRACE is not set
 WARNINGS="-Wall"
 WARNINGS="-Wall"
 EXTRA_WARNINGS=y
 EXTRA_WARNINGS=y
 # DOMULTI is not set
 # DOMULTI is not set
+# UCLIBC_MJN3_ONLY is not set