summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mk/image.mk8
-rw-r--r--package/busybox/config/init/Config.in3
-rw-r--r--package/busybox/config/shell/Config.in2
-rw-r--r--package/sash/Makefile25
-rwxr-xr-xpackage/sash/files/rc47
-rw-r--r--package/sash/src/Makefile38
-rw-r--r--package/sash/src/README6
-rw-r--r--package/sash/src/cmd_uclinux.c127
-rw-r--r--package/sash/src/cmds.c899
-rw-r--r--package/sash/src/cp.c27
-rw-r--r--package/sash/src/date.c54
-rw-r--r--package/sash/src/df.c55
-rw-r--r--package/sash/src/free.c44
-rw-r--r--package/sash/src/hexdump.c127
-rw-r--r--package/sash/src/hostname.c24
-rw-r--r--package/sash/src/libsash/Makefile20
-rw-r--r--package/sash/src/libsash/utils.c706
-rw-r--r--package/sash/src/ls.c311
-rw-r--r--package/sash/src/ps.c317
-rw-r--r--package/sash/src/reboot.c93
-rw-r--r--package/sash/src/sash.c1118
-rw-r--r--package/sash/src/sash.h70
-rw-r--r--package/sash/src/shutdown.c75
-rw-r--r--package/simpleinit/Makefile30
-rwxr-xr-xpackage/simpleinit/files/rc47
-rw-r--r--package/simpleinit/src/pathnames.h37
-rw-r--r--package/simpleinit/src/simpleinit.c1046
-rw-r--r--target/config/Config.in2
-rw-r--r--target/config/Config.in.runtime16
-rw-r--r--target/m68k/uclibc-ng.config5
-rw-r--r--target/m68k/uclibc.config81
31 files changed, 5416 insertions, 44 deletions
diff --git a/mk/image.mk b/mk/image.mk
index 321794f76..e47a82ac1 100644
--- a/mk/image.mk
+++ b/mk/image.mk
@@ -6,6 +6,8 @@ ifeq (${ADK_BINSH_ASH},y)
BINSH:=ash
else ifeq (${ADK_BINSH_BASH},y)
BINSH:=bash
+else ifeq (${ADK_BINSH_SASH},y)
+BINSH:=sash
else ifeq (${ADK_BINSH_HUSH},y)
BINSH:=hush
else ifeq (${ADK_BINSH_MKSH},y)
@@ -21,6 +23,8 @@ ifeq (${ADK_ROOTSH_ASH},y)
ROOTSH:=/bin/ash
else ifeq (${ADK_ROOTSH_BASH},y)
ROOTSH:=/bin/bash
+else ifeq (${ADK_ROOTSH_SASH},y)
+ROOTSH:=/bin/sash
else ifeq (${ADK_ROOTSH_HUSH},y)
ROOTSH:=/bin/hush
else ifeq (${ADK_ROOTSH_MKSH},y)
@@ -54,9 +58,13 @@ image-prepare-post:
mkfontdir ${TARGET_DIR}/usr/share/fonts/X11/$${i}; \
done; \
fi
+ifeq (${ADK_ROOTSH_SASH},)
$(SED) '/^root:/s!:/bin/sh$$!:${ROOTSH}!' ${TARGET_DIR}/etc/passwd
+endif
+ifeq (${ADK_BINSH_SASH},)
-rm -f ${TARGET_DIR}/bin/sh
ln -sf ${BINSH} ${TARGET_DIR}/bin/sh
+endif
test -z $(GIT) || \
$(GIT) log -1|head -1|sed -e 's#commit ##' \
> $(TARGET_DIR)/etc/.adkversion
diff --git a/package/busybox/config/init/Config.in b/package/busybox/config/init/Config.in
index d8b4a449e..58ab4bca4 100644
--- a/package/busybox/config/init/Config.in
+++ b/package/busybox/config/init/Config.in
@@ -44,6 +44,7 @@ config BUSYBOX_FEATURE_BOOTCHARTD_CONFIG_FILE
help
Enable reading and parsing of $PWD/bootchartd.conf
and /etc/bootchartd.conf files.
+
config BUSYBOX_HALT
bool "poweroff, halt, and reboot"
default y
@@ -69,9 +70,11 @@ config BUSYBOX_TELINIT_PATH
When busybox halt and friends have to call external telinit
to facilitate proper shutdown, this path is to be used when
locating telinit executable.
+
config BUSYBOX_INIT
bool "init"
default y
+ depends on !ADK_TARGET_UCLINUX
select BUSYBOX_FEATURE_SYSLOG
help
init is the first program run when the system boots.
diff --git a/package/busybox/config/shell/Config.in b/package/busybox/config/shell/Config.in
index b1b8ad4b2..dd396b015 100644
--- a/package/busybox/config/shell/Config.in
+++ b/package/busybox/config/shell/Config.in
@@ -299,7 +299,7 @@ config BUSYBOX_MSH
choice
prompt "Choose which shell is aliased to 'sh' name"
- default FEATURE_SH_IS_ASH
+ default FEATURE_SH_IS_NONE
help
Choose which shell you want to be executed by 'sh' alias.
The ash shell is the most bash compatible and full featured one.
diff --git a/package/sash/Makefile b/package/sash/Makefile
new file mode 100644
index 000000000..16a767a70
--- /dev/null
+++ b/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
diff --git a/package/sash/files/rc b/package/sash/files/rc
new file mode 100755
index 000000000..33d60a4b6
--- /dev/null
+++ b/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
diff --git a/package/sash/src/Makefile b/package/sash/src/Makefile
new file mode 100644
index 000000000..90d6adf99
--- /dev/null
+++ b/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
+
diff --git a/package/sash/src/README b/package/sash/src/README
new file mode 100644
index 000000000..191c7de63
--- /dev/null
+++ b/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.
+
diff --git a/package/sash/src/cmd_uclinux.c b/package/sash/src/cmd_uclinux.c
new file mode 100644
index 000000000..bf66c4529
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/package/sash/src/cmds.c b/package/sash/src/cmds.c
new file mode 100644
index 000000000..d822d9f6d
--- /dev/null
+++ b/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 */
diff --git a/package/sash/src/cp.c b/package/sash/src/cp.c
new file mode 100644
index 000000000..11d03f74c
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/package/sash/src/date.c b/package/sash/src/date.c
new file mode 100644
index 000000000..c7317998b
--- /dev/null
+++ b/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);
+}
+
+
+
diff --git a/package/sash/src/df.c b/package/sash/src/df.c
new file mode 100644
index 000000000..99ac2217e
--- /dev/null
+++ b/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);
+}
+
diff --git a/package/sash/src/free.c b/package/sash/src/free.c
new file mode 100644
index 000000000..281f10995
--- /dev/null
+++ b/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);
+}
+
diff --git a/package/sash/src/hexdump.c b/package/sash/src/hexdump.c
new file mode 100644
index 000000000..f12f62494
--- /dev/null
+++ b/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);
+}
+
diff --git a/package/sash/src/hostname.c b/package/sash/src/hostname.c
new file mode 100644
index 000000000..8841e7fa3
--- /dev/null
+++ b/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);
+ }
+}
diff --git a/package/sash/src/libsash/Makefile b/package/sash/src/libsash/Makefile
new file mode 100644
index 000000000..03a2fafae
--- /dev/null
+++ b/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
diff --git a/package/sash/src/libsash/utils.c b/package/sash/src/libsash/utils.c
new file mode 100644
index 000000000..a05b33aee
--- /dev/null
+++ b/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 */
diff --git a/package/sash/src/ls.c b/package/sash/src/ls.c
new file mode 100644
index 000000000..9b337aeaa
--- /dev/null
+++ b/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 */
diff --git a/package/sash/src/ps.c b/package/sash/src/ps.c
new file mode 100644
index 000000000..ed4226cc9
--- /dev/null
+++ b/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);
+}
+
diff --git a/package/sash/src/reboot.c b/package/sash/src/reboot.c
new file mode 100644
index 000000000..8342ec992
--- /dev/null
+++ b/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 */
+}
+
diff --git a/package/sash/src/sash.c b/package/sash/src/sash.c
new file mode 100644
index 000000000..24fbddbf7
--- /dev/null
+++ b/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 */
diff --git a/package/sash/src/sash.h b/package/sash/src/sash.h
new file mode 100644
index 000000000..eb2321fa0
--- /dev/null
+++ b/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 */
diff --git a/package/sash/src/shutdown.c b/package/sash/src/shutdown.c
new file mode 100644
index 000000000..444326483
--- /dev/null
+++ b/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 */
+}
+
diff --git a/package/simpleinit/Makefile b/package/simpleinit/Makefile
new file mode 100644
index 000000000..aeeedfc08
--- /dev/null
+++ b/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
diff --git a/package/simpleinit/files/rc b/package/simpleinit/files/rc
new file mode 100755
index 000000000..33d60a4b6
--- /dev/null
+++ b/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
diff --git a/package/simpleinit/src/pathnames.h b/package/simpleinit/src/pathnames.h
new file mode 100644
index 000000000..92b7d0302
--- /dev/null
+++ b/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"
diff --git a/package/simpleinit/src/simpleinit.c b/package/simpleinit/src/simpleinit.c
new file mode 100644
index 000000000..291f88f47
--- /dev/null
+++ b/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);
+}
diff --git a/target/config/Config.in b/target/config/Config.in
index 38f8090dd..3982b9cc9 100644
--- a/target/config/Config.in
+++ b/target/config/Config.in
@@ -16,6 +16,8 @@ config ADK_TARGET_TOOLCHAIN
config ADK_TARGET_UCLINUX
select ADK_TARGET_USE_STATIC_LIBS
+ select ADK_PACKAGE_SASH
+ select ADK_PACKAGE_SIMPLEINIT
boolean
config ADK_TARGET_QEMU
diff --git a/target/config/Config.in.runtime b/target/config/Config.in.runtime
index 845786a45..2caec15ec 100644
--- a/target/config/Config.in.runtime
+++ b/target/config/Config.in.runtime
@@ -150,7 +150,7 @@ config ADK_RUNTIME_KBD_LAYOUT
choice
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
config ADK_ROOTSH_MKSH
@@ -160,6 +160,12 @@ config ADK_ROOTSH_MKSH
Use mksh (a Korn Shell variant) as standard login shell
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
select ADK_PACKAGE_HUSH if !ADK_TOOLCHAIN_ONLY
bool "hush (Shell compatible with non-MMU systems)"
@@ -197,7 +203,7 @@ endchoice
choice
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
config ADK_BINSH_MKSH
@@ -207,6 +213,12 @@ config ADK_BINSH_MKSH
Use mksh (a Korn Shell variant) as system shell, which is
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
select ADK_PACKAGE_HUSH if !ADK_TOOLCHAIN_ONLY
bool "hush (busybox)"
diff --git a/target/m68k/uclibc-ng.config b/target/m68k/uclibc-ng.config
index c3225505d..2ca37cc90 100644
--- a/target/m68k/uclibc-ng.config
+++ b/target/m68k/uclibc-ng.config
@@ -54,9 +54,8 @@ UCLIBC_HAS_THREADS=y
# PTHREADS_DEBUG_SUPPORT is not set
UCLIBC_HAS_SYSLOG=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_DYNAMIC_ATEXIT=y
UCLIBC_SUSV2_LEGACY=y
diff --git a/target/m68k/uclibc.config b/target/m68k/uclibc.config
index 54e6f6322..2612dfe40 100644
--- a/target/m68k/uclibc.config
+++ b/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_arc is not set
# TARGET_arm is not set
+# TARGET_avr32 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_i960 is not set
+# TARGET_ia64 is not set
TARGET_m68k=y
-# TARGET_metag is not set
# TARGET_microblaze is not set
# TARGET_mips is not set
+# TARGET_nios is not set
+# TARGET_nios2 is not set
# TARGET_powerpc is not set
# TARGET_sh is not set
+# TARGET_sh64 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_xtensa is not set
@@ -23,58 +36,48 @@ TARGET_m68k=y
TARGET_ARCH="m68k"
FORCE_OPTIONS_FOR_ARCH=y
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
#
# Using Big Endian
#
-ARCH_HAS_MMU=y
-ARCH_USE_MMU=y
+# ARCH_HAS_MMU is not set
UCLIBC_HAS_FLOATS=y
-UCLIBC_HAS_FPU=y
+# UCLIBC_HAS_FPU is not set
+UCLIBC_HAS_SOFT_FLOAT=y
DO_C99_MATH=y
# DO_XSI_MATH is not set
UCLIBC_HAS_FENV=y
UCLIBC_HAS_LONG_DOUBLE_MATH=y
KERNEL_HEADERS=""
+UCLIBC_UCLINUX_BROKEN_MUNMAP=y
HAVE_DOT_CONFIG=y
#
# General Library Settings
#
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
+# LINUXTHREADS_OLD is not set
+# LINUXTHREADS_NEW is not set
# UCLIBC_HAS_THREADS_NATIVE is not set
UCLIBC_HAS_SYSLOG=y
UCLIBC_HAS_LFS=y
-# MALLOC is not set
+MALLOC=y
# MALLOC_SIMPLE is not set
-MALLOC_STANDARD=y
+# MALLOC_STANDARD is not set
MALLOC_GLIBC_COMPAT=y
-UCLIBC_HAS_OBSTACK=y
UCLIBC_DYNAMIC_ATEXIT=y
-UCLIBC_SUSV2_LEGACY=y
+# COMPAT_ATEXIT is not set
UCLIBC_SUSV3_LEGACY=y
# UCLIBC_SUSV3_LEGACY_MACROS is not set
UCLIBC_SUSV4_LEGACY=y
@@ -104,6 +107,8 @@ UCLIBC_GRP_BUFFER_SIZE=256
#
# Support various families of functions
#
+UCLIBC_LINUX_MODULE_26=y
+# UCLIBC_LINUX_MODULE_24 is not set
UCLIBC_LINUX_SPECIFIC=y
UCLIBC_HAS_GNU_ERROR=y
UCLIBC_BSD_SPECIFIC=y
@@ -125,6 +130,7 @@ UCLIBC_HAS_NETWORK_SUPPORT=y
UCLIBC_HAS_SOCKET=y
UCLIBC_HAS_IPV4=y
UCLIBC_HAS_IPV6=y
+# UCLIBC_HAS_RPC is not set
UCLIBC_USE_NETLINK=y
UCLIBC_SUPPORT_AI_ADDRCONFIG=y
UCLIBC_HAS_BSD_RES_CLOSE=y
@@ -149,6 +155,8 @@ UCLIBC_HAS_WCHAR=y
UCLIBC_HAS_HEXADECIMAL_FLOATS=y
UCLIBC_HAS_GLIBC_CUSTOM_PRINTF=y
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_512 is not set
# UCLIBC_HAS_STDIO_BUFSIZ_1024 is not set
@@ -178,7 +186,9 @@ UCLIBC_HAS_GNU_GETSUBOPT=y
# Big and Tall
#
UCLIBC_HAS_REGEX=y
+# UCLIBC_HAS_REGEX_OLD is not set
UCLIBC_HAS_FNMATCH=y
+# UCLIBC_HAS_FNMATCH_OLD is not set
UCLIBC_HAS_WORDEXP=y
UCLIBC_HAS_NFTW=y
UCLIBC_HAS_FTW=y
@@ -199,10 +209,7 @@ HARDWIRED_ABSPATH=y
# Security options
#
UCLIBC_HAS_ARC4RANDOM=y
-# ARC4RANDOM_USES_NODEV is not set
# UCLIBC_HAS_SSP is not set
-UCLIBC_BUILD_RELRO=y
-# UCLIBC_BUILD_NOW is not set
UCLIBC_BUILD_NOEXECSTACK=y
#
@@ -213,10 +220,8 @@ UCLIBC_EXTRA_CFLAGS=""
# DODEBUG is not set
# DOSTRIP 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_HAS_BACKTRACE is not set
WARNINGS="-Wall"
EXTRA_WARNINGS=y
# DOMULTI is not set
+# UCLIBC_MJN3_ONLY is not set