summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mdk-stage1/Makefile118
-rw-r--r--mdk-stage1/init.c540
-rw-r--r--mdk-stage1/minilibc.c261
-rw-r--r--mdk-stage1/minilibc.h142
4 files changed, 1061 insertions, 0 deletions
diff --git a/mdk-stage1/Makefile b/mdk-stage1/Makefile
new file mode 100644
index 000000000..ca707070a
--- /dev/null
+++ b/mdk-stage1/Makefile
@@ -0,0 +1,118 @@
+ #******************************************************************************
+ #
+ # mdk-stage1 - the program that will load second-stage install
+ #
+ # $Id$
+ #
+ # Guillaume Cottenceau (gc@mandrakesoft.com)
+ #
+ # Copyright 2000 MandrakeSoft
+ #
+ # This software may be freely redistributed under the terms of the GNU
+ # public license.
+ #
+ # You should have received a copy of the GNU General Public License
+ # along with this program; if not, write to the Free Software
+ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ #
+ # Portions from Erik Troan (ewt@redhat.com) Copyright 1996 Red Hat Software
+ #
+ #*****************************************************************************
+
+VERSION = 7.2cooker
+
+
+ARCH := $(patsubst i%86,i386,$(shell uname -m))
+ARCH := $(patsubst sparc%,sparc,$(ARCH))
+
+
+ #- We can leave "-g" forever since stripping will remove everything
+CFLAGS = -Os -g -Wall -Werror -fomit-frame-pointer
+INCLUDES = -I.
+DEFS = -D_GNU_SOURCE=1 -DVERSION=\"$(VERSION)\" -DUSE_LOGDEV
+
+COMPILE = $(CC) $(DEFS) $(INCLUDES) $(CFLAGS)
+
+
+ #- stage1 "loader"
+INITSRC = minilibc.c init.c
+
+ #- stage1 itself
+STAGE1SRC = #stage1.c cdrom.c devices.c
+
+
+ALLSRC = $(INITSRC) $(STAGE1SRC)
+
+
+STATIC = -static
+
+ifeq (i386, $(ARCH))
+MINILIBC=minilibc.o
+LDFLAGS = -nostdlib /usr/lib/crt1.o
+STATIC=-static
+else
+ifeq (sparc, $(ARCH))
+MINILIBC=minilibc.o /usr/lib/libc.a
+LDFLAGS = -nostdlib /usr/lib/crt1.o
+STATIC=-static
+else
+STATIC=-static
+endif
+endif
+
+
+BINS = init
+
+
+#ifeq (i386, $(ARCH))
+#BINS += stage1-all stage1-cdrom stage1-network stage1-hd stage1-pcmcia
+#endif
+#
+#ifeq (ia64, $(ARCH))
+#BINS += stage1-all
+#endif
+#
+#ifeq (alpha, $(ARCH))
+#BINS += stage1-all
+#endif
+#
+#ifeq (sparc, $(ARCH))
+#BINS += stage1-all
+#endif
+
+DIRS = mar
+
+
+all: dirs $(BINS)
+
+dirs:
+ @echo -e "*** BUILDING in all directories\n"
+ @for n in . $(DIRS); do \
+ [ "$$n" = "." ] || make -C $$n ;\
+ done
+
+.c.o:
+ $(COMPILE) -c $<
+
+init: init.o $(MINILIBC)
+ $(CC) $(STATIC) $(LDFLAGS) -o $@ init.o $(MINILIBC)
+
+stage1-network: stage1-network.o $(OBJS) $(NETOBJS)
+ $(CC) -g $(STATIC) -o $@ $^ -lpopt \
+ -lkudzu_loader ../isys/libisys.a ../balkan/libbalkan.a \
+ $(MODULELINKAGE) \
+ -lpump -lbz2 -lz -lresolv -lnewt -lslang -lpci
+
+clean:
+ @echo -e "*** CLEANING in all directories\n"
+ @for n in $(DIRS); do \
+ (cd $$n; make clean) \
+ done
+ rm -f *.o .depend $(BINS)
+
+deps:
+ $(CPP) $(CFLAGS) -DHAVE_CONFIG_H -M $(ALLSRC) > .depend
+
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/mdk-stage1/init.c b/mdk-stage1/init.c
new file mode 100644
index 000000000..6fbaac8be
--- /dev/null
+++ b/mdk-stage1/init.c
@@ -0,0 +1,540 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 MandrakeSoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+#include "minilibc.h"
+
+
+#define KICK_FLOPPY 1
+#define KICK_BOOTP 2
+
+#define MS_REMOUNT 32
+
+#define ENV_PATH 0
+#define ENV_LD_LIBRARY_PATH 1
+#define ENV_HOME 2
+#define ENV_TERM 3
+#define ENV_DEBUG 4
+
+char * env[] = {
+ "PATH=/usr/bin:/bin:/sbin:/usr/sbin:/mnt/sbin:/mnt/usr/sbin:"
+ "/mnt/bin:/mnt/usr/bin",
+ "LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib",
+ "HOME=/",
+ "TERMINFO=/etc/linux-terminfo",
+ NULL
+};
+
+
+/*
+ * this needs to handle the following cases:
+ *
+ * 1) run from a CD root filesystem
+ * 2) run from a read only nfs rooted filesystem
+ * 3) run from a floppy
+ * 4) run from a floppy that's been loaded into a ramdisk
+ *
+ */
+
+int testing;
+
+
+void fatal_error(char *msg)
+{
+ printf("FATAL ERROR: %s\n\nI can't recover from this, please reboot manually and send bugreport.\n", msg);
+ while (1);
+}
+
+void print_error(char *msg)
+{
+ printf("E: %s\n", msg);
+}
+
+void print_warning(char *msg)
+{
+ printf("W: %s\n", msg);
+}
+
+
+void doklog(char * fn)
+{
+ fd_set readset, unixs;
+ int in, out, i;
+ int log;
+ int s;
+ int sock = -1;
+ struct sockaddr_un sockaddr;
+ char buf[1024];
+ int readfd;
+
+ /* open kernel message logger */
+ in = open("/proc/kmsg", O_RDONLY,0);
+ if (in < 0)
+ {
+ print_error("could not open /proc/kmsg");
+ return;
+ }
+
+ out = open(fn, O_WRONLY, 0);
+ if (out < 0)
+ print_warning("couldn't open tty for syslog -- still using /tmp/syslog\n");
+
+ log = open("/tmp/syslog", O_WRONLY | O_CREAT, 0644);
+
+ if (log < 0)
+ {
+ print_error("error opening /tmp/syslog");
+ sleep(5);
+ close(in);
+ return;
+ }
+
+ /* if we get this far, we should be in good shape */
+ if (fork())
+ {
+ /* parent */
+ close(in);
+ close(out);
+ close(log);
+ return;
+ }
+
+ close(0);
+ close(1);
+ close(2);
+
+ dup2(1, log);
+
+#if defined(USE_LOGDEV)
+ /* now open the syslog socket */
+ sockaddr.sun_family = AF_UNIX;
+ strcpy(sockaddr.sun_path, "/dev/log");
+ sock = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (sock < 0)
+ {
+ printf("error creating socket: %d\n", errno);
+ sleep(5);
+ }
+
+ printf("got socket\n");
+ if (bind(sock, (struct sockaddr *) &sockaddr, sizeof(sockaddr.sun_family) +
+ strlen(sockaddr.sun_path)))
+ {
+ printf("bind error: %d\n", errno);
+ sleep(5);
+ }
+
+ printf("bound socket\n");
+ chmod("/dev/log", 0666);
+ if (listen(sock, 5))
+ {
+ printf("listen error: %d\n", errno);
+ sleep(5);
+ }
+#endif
+
+ syslog(8, NULL, 1);
+
+ FD_ZERO(&unixs);
+ while (1)
+ {
+ memcpy(&readset, &unixs, sizeof(unixs));
+
+ if (sock >= 0) FD_SET(sock, &readset);
+ FD_SET(in, &readset);
+
+ i = select(20, &readset, NULL, NULL, NULL);
+ if (i <= 0) continue;
+
+ if (FD_ISSET(in, &readset))
+ {
+ i = read(in, buf, sizeof(buf));
+ if (i > 0)
+ {
+ if (out >= 0) write(out, buf, i);
+ write(log, buf, i);
+ }
+ }
+
+ for (readfd = 0; readfd < 20; ++readfd)
+ {
+ if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs))
+ {
+ i = read(readfd, buf, sizeof(buf));
+ if (i > 0)
+ {
+ if (out >= 0)
+ {
+ write(out, buf, i);
+ write(out, "\n", 1);
+ }
+
+ write(log, buf, i);
+ write(log, "\n", 1);
+ }
+ else
+ if (i == 0)
+ {
+ /* socket closed */
+ close(readfd);
+ FD_CLR(readfd, &unixs);
+ }
+ }
+ }
+
+ if (sock >= 0 && FD_ISSET(sock, &readset))
+ {
+ s = sizeof(sockaddr);
+ readfd = accept(sock, (struct sockaddr *) &sockaddr, &s);
+ if (readfd < 0)
+ {
+ if (out >= 0) write(out, "error in accept\n", 16);
+ write(log, "error in accept\n", 16);
+ close(sock);
+ sock = -1;
+ }
+ else
+ {
+ FD_SET(readfd, &unixs);
+ }
+ }
+ }
+}
+
+
+void del_loop(char *device)
+{
+ int fd;
+ if ((fd = open(device, O_RDONLY, 0)) < 0)
+ {
+ printf("del_loop open failed\n");
+ return;
+ }
+
+ if (ioctl(fd, LOOP_CLR_FD, 0) < 0)
+ {
+ printf("del_loop ioctl failed");
+ return;
+ }
+
+ close(fd);
+}
+
+struct filesystem
+{
+ char * dev;
+ char * name;
+ char * fs;
+ int mounted;
+};
+
+void unmount_filesystems(void)
+{
+ int fd, size;
+ char buf[65535]; /* this should be big enough */
+ char *p;
+ struct filesystem fs[500];
+ int numfs = 0;
+ int i, nb;
+
+ printf("unmounting filesystems...\n");
+
+ fd = open("/proc/mounts", O_RDONLY, 0);
+ if (fd < 1)
+ {
+ print_error("failed to open /proc/mounts");
+ sleep(2);
+ return;
+ }
+
+ size = read(fd, buf, sizeof(buf) - 1);
+ buf[size] = '\0';
+
+ close(fd);
+
+ p = buf;
+ while (*p)
+ {
+ fs[numfs].mounted = 1;
+ fs[numfs].dev = p;
+ while (*p != ' ') p++;
+ *p++ = '\0';
+ fs[numfs].name = p;
+ while (*p != ' ') p++;
+ *p++ = '\0';
+ fs[numfs].fs = p;
+ while (*p != ' ') p++;
+ *p++ = '\0';
+ while (*p != '\n') p++;
+ p++;
+ if (strcmp(fs[numfs].name, "/") != 0) numfs++; /* skip if root, no need to take initrd root in account */
+ }
+
+ /* Pixel's ultra-optimized sorting algorithm:
+ multiple passes trying to umount everything until nothing moves
+ anymore (a.k.a holy shotgun method) */
+ do
+ {
+ nb = 0;
+ for (i = 0; i < numfs; i++)
+ {
+ /*printf("trying with %s\n", fs[i].name);*/
+ if (fs[i].mounted && umount(fs[i].name) == 0)
+ {
+ if (strncmp(fs[i].dev + sizeof("/dev/") - 1, "loop",
+ sizeof("loop") - 1) == 0)
+ del_loop(fs[i].dev);
+
+ printf("\t%s\n", fs[i].name);
+ fs[i].mounted = 0;
+ nb++;
+ }
+ }
+ } while (nb);
+
+ for (i = nb = 0; i < numfs; i++)
+ if (fs[i].mounted)
+ {
+ printf("\t%s umount failed\n", fs[i].name);
+ if (strcmp(fs[i].fs, "ext2") == 0) nb++; /* don't count not-ext2 umount failed */
+ }
+
+ if (nb)
+ {
+ printf("failed to umount some filesystems\n");
+ while (1);
+ }
+}
+
+
+void disable_swap(void)
+{
+ int fd;
+ char buf[4096];
+ int i;
+ char * start;
+ char * chptr;
+
+ printf("disabling swap...\n");
+
+ fd = open("/proc/swaps", O_RDONLY, 0);
+ if (fd < 0)
+ {
+ print_warning("failed to open /proc/swaps");
+ return;
+ }
+
+ /* read all data at once */
+ i = read(fd, buf, sizeof(buf) - 1);
+ close(fd);
+ if (i < 0)
+ {
+ print_warning("failed to read /proc/swaps");
+ return;
+ }
+ buf[i] = '\0';
+
+ start = buf;
+ while (*start)
+ {
+ /* move to next line */
+ while (*start != '\n' && *start) start++;
+ if (!*start) return;
+
+ /* first char of new line */
+ start++;
+ if (*start != '/') return;
+
+ /* build up an ASCIIZ filename */
+ chptr = start;
+ while (*chptr && *chptr != ' ') chptr++;
+ if (!(*chptr)) return;
+ *chptr = '\0';
+
+ /* call swapoff */
+ printf("Swapoff %s ", start);
+ if (swapoff(start))
+ printf(" failed (%d)\n", errno);
+ else
+ printf(" succeeded\n");
+
+ start = chptr + 1;
+ }
+}
+
+
+int main(int argc, char **argv)
+{
+ pid_t installpid, childpid;
+ int wait_status;
+ int fd;
+ int abnormal_termination = 0;
+ int end_stage2 = 0;
+ char * child_argv[20];
+
+ /* getpid() != 1 should work, by linuxrc tends to get a larger pid */
+ testing = (getpid() > 50);
+
+ printf("*** TESTING MODE ***\n");
+
+ if (!testing)
+ {
+ /* turn off screen blanking */
+ printf("\033[9;0]");
+ printf("\033[8]");
+ }
+
+ printf("--- Hi. Linux-Mandrake install initializer starting. ---\n");
+ printf("VERSION: %s\n", VERSION);
+
+
+ if (!testing)
+ {
+ printf("mounting /proc filesystem... ");
+ if (mount("/proc", "/proc", "proc", 0, NULL))
+ fatal_error("Unable to mount proc filesystem");
+ printf("done\n");
+ }
+
+
+ /* ignore Control-C and keyboard stop signals */
+ signal(SIGINT, SIG_IGN);
+ signal(SIGTSTP, SIG_IGN);
+
+
+ if (!testing)
+ {
+ fd = open("/dev/tty1", O_RDWR, 0);
+ if (fd < 0)
+ /* try with devfs */
+ fd = open("/dev/vc/1", O_RDWR, 0);
+
+ if (fd < 0)
+ fatal_error("failed to open /dev/tty1 and /dev/vc/1");
+
+ dup2(fd, 0);
+ dup2(fd, 1);
+ dup2(fd, 2);
+ close(fd);
+ }
+
+
+ /* I set me up as session leader (probably not necessary?) */
+ setsid();
+ if (ioctl(0, TIOCSCTTY, NULL))
+ print_error("could not set new controlling tty");
+
+ if (!testing)
+ {
+ char * my_hostname = "localhost.localdomain";
+ sethostname(my_hostname, strlen(my_hostname));
+ /* the default domainname (as of 2.0.35) is "(none)", which confuses
+ glibc */
+ setdomainname("", 0);
+ }
+
+ if (!testing)
+ doklog("/dev/tty4");
+
+
+ /* Go into normal init mode - keep going, and then do a orderly shutdown
+ when:
+
+ 1) /bin/install exits
+ 2) we receive a SIGHUP
+ */
+
+ printf("running stage1...\n");
+
+ if (!(installpid = fork()))
+ {
+ /* child */
+ int index;
+ child_argv[0] = "/sbin/stage1";
+
+ index = 1;
+ while (argv[index])
+ {
+ /* should be strdup but I don't have malloc */
+ child_argv[index] = argv[index];
+ index++;
+ }
+ child_argv[index] = NULL;
+
+ printf("execing: %s\n", child_argv[0]);
+ execve(child_argv[0], child_argv, env);
+
+ exit(0);
+ }
+
+ while (!end_stage2)
+ {
+ childpid = wait4(-1, &wait_status, 0, NULL);
+ if (childpid == installpid)
+ end_stage2 = 1;
+ }
+
+ if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status))
+ {
+ printf("install exited abnormally :-( ");
+ if (WIFSIGNALED(wait_status))
+ {
+ printf("-- received signal %d", WTERMSIG(wait_status));
+ }
+ printf("\n");
+ abnormal_termination = 1;
+ }
+ else
+ printf("back to stage1-initializer control -- install exited normally\n");
+
+ if (testing)
+ exit(0);
+
+ sync(); sync();
+
+ printf("sending termination signals...");
+ kill(-1, 15);
+ sleep(2);
+ printf("done\n");
+
+ printf("sending kill signals...");
+ kill(-1, 9);
+ sleep(2);
+ printf("done\n");
+
+ disable_swap();
+ unmount_filesystems();
+
+ if (!abnormal_termination)
+ {
+ printf("rebooting system\n");
+ sleep(2);
+
+ reboot(0xfee1dead, 672274793, 0x1234567);
+ }
+ else
+ {
+ printf("you may safely reboot your system\n");
+ while (1);
+ }
+
+ exit(0);
+ return 0;
+}
diff --git a/mdk-stage1/minilibc.c b/mdk-stage1/minilibc.c
new file mode 100644
index 000000000..e7c374105
--- /dev/null
+++ b/mdk-stage1/minilibc.c
@@ -0,0 +1,261 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 MandrakeSoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+
+#define MINILIBC_INTERNAL
+
+#include "minilibc.h"
+
+int atexit (void (*__func) (void))
+{
+ return 0;
+}
+
+void exit()
+{
+ _do_exit(0);
+ for (;;); /* Shut up gcc */
+}
+
+
+char ** _environ = NULL;
+int errno = 0;
+
+void _init (int __status)
+{
+}
+
+void __libc_init_first (int __status)
+{
+}
+
+int __libc_start_main (int (*main) (int, char **, char **), int argc,
+ char **argv, void (*init) (void), void (*fini) (void),
+ void (*rtld_fini) (void), void *stack_end)
+{
+ exit ((*main) (argc, argv, NULL));
+ /* never get here */
+ return 0;
+}
+
+void _fini (int __status)
+{
+}
+
+inline int socket(int a, int b, int c)
+{
+ unsigned long args[] = { a, b, c };
+
+ return socketcall(SYS_SOCKET, args);
+}
+
+inline int bind(int a, void * b, int c)
+{
+ unsigned long args[] = { a, (long) b, c };
+
+ return socketcall(SYS_BIND, args);
+}
+
+inline int listen(int a, int b)
+{
+ unsigned long args[] = { a, b, 0 };
+
+ return socketcall(SYS_LISTEN, args);
+}
+
+inline int accept(int a, void * addr, void * addr2)
+{
+ unsigned long args[] = { a, (long) addr, (long) addr2 };
+
+ return socketcall(SYS_ACCEPT, args);
+}
+
+
+void sleep(int secs)
+{
+ struct timeval tv;
+
+ tv.tv_sec = secs;
+ tv.tv_usec = 0;
+
+ select(0, NULL, NULL, NULL, &tv);
+}
+
+
+int strlen(const char * string)
+{
+ int i = 0;
+
+ while (*string++) i++;
+
+ return i;
+}
+
+char * strncpy(char * dst, const char * src, int len)
+{
+ char * chptr = dst;
+ int i = 0;
+
+ while (*src && i < len) *dst++ = *src++, i++;
+ if (i < len) *dst = '\0';
+
+ return chptr;
+}
+
+char * strcpy(char * dst, const char * src)
+{
+ char * chptr = dst;
+
+ while (*src) *dst++ = *src++;
+ *dst = '\0';
+
+ return chptr;
+}
+
+void * memcpy(void * dst, const void * src, size_t count)
+{
+ char * a = dst;
+ const char * b = src;
+
+ while (count--)
+ *a++ = *b++;
+
+ return dst;
+}
+
+
+int strcmp(const char * a, const char * b)
+{
+ int i, j;
+
+ i = strlen(a); j = strlen(b);
+ if (i < j)
+ return -1;
+ else if (j < i)
+ return 1;
+
+ while (*a && (*a == *b)) a++, b++;
+
+ if (!*a) return 0;
+
+ if (*a < *b)
+ return -1;
+ else
+ return 1;
+}
+
+int strncmp(const char * a, const char * b, int len)
+{
+ char buf1[1000], buf2[1000];
+
+ strncpy(buf1, a, len);
+ strncpy(buf2, b, len);
+ buf1[len] = '\0';
+ buf2[len] = '\0';
+
+ return strcmp(buf1, buf2);
+}
+
+char * strchr(char * str, int ch)
+{
+ char * chptr;
+
+ chptr = str;
+ while (*chptr)
+ {
+ if (*chptr == ch) return chptr;
+ chptr++;
+ }
+
+ return NULL;
+}
+
+void print_int(int i)
+{
+ char buf[10];
+ char * chptr = buf + 9;
+ int j = 0;
+
+ if (i < 0)
+ {
+ write(1, "-", 1);
+ i = -1 * i;
+ }
+
+ while (i)
+ {
+ *chptr-- = '0' + (i % 10);
+ j++;
+ i = i / 10;
+ }
+
+ write(1, chptr + 1, j);
+}
+
+void print_str(char * string)
+{
+ write(1, string, strlen(string));
+}
+
+/* Minimum printf which handles only characters, %d's and %s's */
+void printf(char * fmt, ...)
+{
+ char buf[2048];
+ char * start = buf;
+ char * chptr = buf;
+ va_list args;
+ char * strarg;
+ int numarg;
+
+ strncpy(buf, fmt, sizeof(buf));
+ va_start(args, fmt);
+
+ while (start)
+ {
+ while (*chptr != '%' && *chptr) chptr++;
+
+ if (*chptr == '%')
+ {
+ *chptr++ = '\0';
+ print_str(start);
+
+ switch (*chptr++)
+ {
+ case 's':
+ strarg = va_arg(args, char *);
+ print_str(strarg);
+ break;
+
+ case 'd':
+ numarg = va_arg(args, int);
+ print_int(numarg);
+ break;
+ }
+
+ start = chptr;
+ }
+ else
+ {
+ print_str(start);
+ start = NULL;
+ }
+ }
+}
diff --git a/mdk-stage1/minilibc.h b/mdk-stage1/minilibc.h
new file mode 100644
index 000000000..824ac5d6e
--- /dev/null
+++ b/mdk-stage1/minilibc.h
@@ -0,0 +1,142 @@
+/*
+ * Guillaume Cottenceau (gc@mandrakesoft.com)
+ *
+ * Copyright 2000 MandrakeSoft
+ *
+ * This software may be freely redistributed under the terms of the GNU
+ * public license.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+/*
+ * Portions from Erik Troan (ewt@redhat.com)
+ *
+ * Copyright 1996 Red Hat Software
+ *
+ */
+
+
+#include <stdarg.h>
+
+#define _LOOSE_KERNEL_NAMES 1
+
+#define NULL ((void *) 0)
+
+#define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
+#define WIFSIGNALED(status) (!WIFSTOPPED(status) && !WIFEXITED(status))
+#define WEXITSTATUS(status) (((status) & 0xff00) >> 8)
+#define WTERMSIG(status) ((status) & 0x7f)
+#define WSTOPSIG(status) WEXITSTATUS(status)
+#define WIFEXITED(status) (WTERMSIG(status) == 0)
+
+#define MS_MGC_VAL 0xc0ed0000
+
+#define isspace(a) (a == ' ' || a == '\t')
+
+extern char ** _environ;
+
+extern int errno;
+
+/* Aieee, gcc 2.95+ creates a stub for posix_types.h on i386 which brings
+ glibc headers in and thus makes __FD_SET etc. not defined with 2.3+ kernels. */
+#define _FEATURES_H 1
+#include <linux/socket.h>
+#include <linux/types.h>
+#include <linux/time.h>
+#include <linux/if.h>
+#include <linux/un.h>
+#include <linux/loop.h>
+#include <linux/net.h>
+#include <asm/posix_types.h>
+#include <asm/termios.h>
+#include <asm/ioctls.h>
+#include <asm/unistd.h>
+#include <asm/fcntl.h>
+#include <asm/signal.h>
+
+
+#ifndef MINILIBC_INTERNAL
+static inline _syscall5(int,mount,const char *,spec,const char *,dir,const char *,type,unsigned long,rwflag,const void *,data);
+static inline _syscall5(int,_newselect,int,n,fd_set *,rd,fd_set *,wr,fd_set *,ex,struct timeval *,timeval);
+static inline _syscall4(int,wait4,pid_t,pid,int *,status,int,opts,void *,rusage)
+static inline _syscall3(int,write,int,fd,const char *,buf,unsigned long,count)
+static inline _syscall3(int,reboot,int,magic,int,magic_too,int,flag)
+static inline _syscall3(int,execve,const char *,fn,void *,argv,void *,envp)
+static inline _syscall3(int,read,int,fd,const char *,buf,unsigned long,count)
+static inline _syscall3(int,open,const char *,fn,int,flags,mode_t,mode)
+static inline _syscall3(int,ioctl,int,fd,int,request,void *,argp)
+static inline _syscall2(int,dup2,int,one,int,two)
+static inline _syscall2(int,kill,pid_t,pid,int,sig)
+static inline _syscall2(int,symlink,const char *,a,const char *,b)
+static inline _syscall2(int,chmod,const char * ,path,mode_t,mode)
+static inline _syscall2(int,sethostname,const char *,name,int,len)
+static inline _syscall2(int,setdomainname,const char *,name,int,len)
+static inline _syscall2(int,setpgid,int,name,int,len)
+static inline _syscall2(int,signal,int,num,void *,len)
+static inline _syscall1(int,umount,const char *,dir)
+static inline _syscall1(int,unlink,const char *,fn)
+static inline _syscall1(int,close,int,fd)
+static inline _syscall1(int,swapoff,const char *,fn)
+static inline _syscall0(int,getpid)
+static inline _syscall0(int,sync)
+#ifdef __sparc__
+/* Nonstandard fork calling convention :( */
+static inline int fork(void) {
+ int __res;
+ __asm__ __volatile__ (
+ "mov %0, %%g1\n\t"
+ "t 0x10\n\t"
+ "bcc 1f\n\t"
+ "dec %%o1\n\t"
+ "sethi %%hi(%2), %%g1\n\t"
+ "st %%o0, [%%g1 + %%lo(%2)]\n\t"
+ "b 2f\n\t"
+ "mov -1, %0\n\t"
+ "1:\n\t"
+ "and %%o0, %%o1, %0\n\t"
+ "2:\n\t"
+ : "=r" (__res)
+ : "0" (__NR_fork), "i" (&errno)
+ : "g1", "o0", "cc");
+ return __res;
+}
+#else
+static inline _syscall0(int,fork)
+#endif
+static inline _syscall0(pid_t,setsid)
+static inline _syscall3(int,syslog,int, type, char *, buf, int, len);
+#else
+static inline _syscall5(int,_newselect,int,n,fd_set *,rd,fd_set *,wr,fd_set *,ex,struct timeval *,timeval);
+static inline _syscall3(int,write,int,fd,const char *,buf,unsigned long,count)
+static inline _syscall2(int,socketcall,int,code,unsigned long *, args)
+#define __NR__do_exit __NR_exit
+extern inline _syscall1(int,_do_exit,int,exitcode)
+#endif
+
+#define select _newselect
+
+extern int errno;
+
+inline int socket(int a, int b, int c);
+inline int bind(int a, void * b, int c);
+inline int listen(int a, int b);
+inline int accept(int a, void * addr, void * addr2);
+
+void sleep(int secs);
+
+int strlen(const char * string);
+char * strcpy(char * dst, const char * src);
+void * memcpy(void * dst, const void * src, size_t count);
+int strcmp(const char * a, const char * b);
+int strncmp(const char * a, const char * b, int len);
+char * strchr(char * str, int ch);
+char * strncpy(char * dst, const char * src, int len);
+
+void print_str(char * string);
+void print_int(int i);
+/* Minimum printf which handles only characters, %d's and %s's */
+void printf(char * fmt, ...);