From 07e8572d9d5280867732fe881b9e7bd030988207 Mon Sep 17 00:00:00 2001 From: Guillaume Cottenceau Date: Mon, 20 Nov 2000 22:36:40 +0000 Subject: first draft for init and minilibc --- mdk-stage1/Makefile | 118 +++++++++++ mdk-stage1/init.c | 540 ++++++++++++++++++++++++++++++++++++++++++++++++++ mdk-stage1/minilibc.c | 261 ++++++++++++++++++++++++ mdk-stage1/minilibc.h | 142 +++++++++++++ 4 files changed, 1061 insertions(+) create mode 100644 mdk-stage1/Makefile create mode 100644 mdk-stage1/init.c create mode 100644 mdk-stage1/minilibc.c create mode 100644 mdk-stage1/minilibc.h (limited to 'mdk-stage1') 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 + +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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, ...); -- cgit v1.2.1