diff options
Diffstat (limited to 'mdk-stage1/init.c')
| -rw-r--r-- | mdk-stage1/init.c | 410 | 
1 files changed, 285 insertions, 125 deletions
| diff --git a/mdk-stage1/init.c b/mdk-stage1/init.c index b5f5631f8..7c48f64ec 100644 --- a/mdk-stage1/init.c +++ b/mdk-stage1/init.c @@ -1,7 +1,7 @@  /* - * Guillaume Cottenceau (gc@mandrakesoft.com) + * Guillaume Cottenceau (gc)   * - * Copyright 2000 MandrakeSoft + * Copyright 2000 Mandriva   *   * This software may be freely redistributed under the terms of the GNU   * public license. @@ -19,21 +19,54 @@   *   */ -#ifndef INIT_HEADERS -#include "init-libc-headers.h" -#else -#include INIT_HEADERS -#endif +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <dirent.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <sys/mount.h> +#include <linux/un.h> +#include <errno.h> +#include <signal.h> +#include <sys/resource.h> +#include <sys/wait.h> +#include <linux/unistd.h> +#include <sys/select.h> +#include <sys/ioctl.h> +#include <linux/reboot.h> + +#include <sys/syscall.h> +#define syslog(...) syscall(__NR_syslog, __VA_ARGS__) + +static unsigned int reboot_magic = LINUX_REBOOT_CMD_RESTART; + +static inline long reboot(unsigned int command) +{ +	return (long) syscall(__NR_reboot, LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, command, 0); +}  #include "config-stage1.h" +#include <linux/cdrom.h> + + +#define BINARY_STAGE2 "/usr/bin/runinstall2"  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", +	"LD_LIBRARY_PATH=/lib:/usr/lib:/mnt/lib:/mnt/usr/lib" +#if defined(__x86_64__) +	":/lib64:/usr/lib64:/mnt/lib64:/mnt/usr/lib64" +#endif +	,  	"HOME=/",  	"TERM=linux",  	"TERMINFO=/etc/terminfo", +	"LC_CTYPE=UTF-8",  	NULL  }; @@ -48,14 +81,14 @@ char * env[] = {   *   */ -int testing; +int testing = 0;  int klog_pid;  void fatal_error(char *msg)  {  	printf("FATAL ERROR IN INIT: %s\n\nI can't recover from this, please reboot manually and send bugreport.\n", msg); -	while (1); +        select(0, NULL, NULL, NULL, NULL);  }  void print_error(char *msg) @@ -73,20 +106,20 @@ void print_int_init(int fd, 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(fd, chptr + 1, j);  } @@ -95,7 +128,6 @@ void print_str_init(int fd, char * string)  	write(fd, string, strlen(string));  } -  /* fork to:   *   (1) watch /proc/kmsg and copy the stuff to /dev/tty4   *   (2) listens to /dev/log and copy also this stuff (log from programs) @@ -105,7 +137,7 @@ void doklog()  	fd_set readset, unixs;  	int in, out, i;  	int log; -	int s; +	socklen_t s;  	int sock = -1;  	struct sockaddr_un sockaddr;  	char buf[1024]; @@ -118,7 +150,7 @@ void doklog()  		return;  	} -	if ((log = open("/tmp/syslog", O_WRONLY | O_CREAT, 0644)) < 0) { +	if ((log = open("/tmp/syslog", O_WRONLY | O_CREAT | O_APPEND, 0644)) < 0) {  		print_error("error opening /tmp/syslog");  		sleep(5);  		return; @@ -133,7 +165,7 @@ void doklog()  		close(1);  		close(2);  	} -	 +  	out = open("/dev/tty4", O_WRONLY, 0);  	if (out < 0)   		print_warning("couldn't open tty for syslog -- still using /tmp/syslog\n"); @@ -153,8 +185,7 @@ void doklog()  //		  print_str_init(log, "] bind error: ");  //		  print_int_init(log, errno);  //		  print_str_init(log, "\n"); -//		  sleep(5); -//	  } +//		  sleep(//	  }  //  //	  print_str_init(log, "] bound socket\n");  //	  chmod("/dev/log", 0666); @@ -176,7 +207,7 @@ void doklog()  		if (sock >= 0)  			FD_SET(sock, &readset);  		FD_SET(in, &readset); -		 +  		i = select(20, &readset, NULL, NULL, NULL);  		if (i <= 0)  			continue; @@ -191,25 +222,6 @@ void doklog()  			}  		}  -		/* examine some fd's in the hope to find some syslog outputs from programs */ -		for (readfd = 0; readfd < 20; ++readfd) { -			if (FD_ISSET(readfd, &readset) && FD_ISSET(readfd, &unixs)) { -				i = read(readfd, buf, sizeof(buf)); -				if (i > 0) { -					/* grep out the output of RPM telling that it installed/removed some packages */ -					if (!strstr(buf, "mdk installed") && !strstr(buf, "mdk removed")) { -						if (out >= 0) -							write(out, buf, i); -						write(log, buf, i); -					} -				} else if (i == 0) { -					/* socket closed */ -					close(readfd); -					FD_CLR(readfd, &unixs); -				} -			} -		} -  		/* the socket has moved, new stuff to do */  		if (sock >= 0 && FD_ISSET(sock, &readset)) {  			s = sizeof(sockaddr); @@ -231,20 +243,28 @@ void doklog()  #define LOOP_CLR_FD	0x4C01 -void del_loop(char *device)  +void del_loops(void)   { -	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); +        char loopdev[] = "/dev/loop0"; +        char chloopdev[] = "/dev/chloop0"; +        int i; +        for (i=0; i<8; i++) { +                int fd; +                loopdev[9] = '0' + i; +                fd = open(loopdev, O_RDONLY, 0); +                if (fd > 0) { +                        if (!ioctl(fd, LOOP_CLR_FD, 0)) +                                printf("\t%s\n", loopdev); +                        close(fd); +                } +                chloopdev[11] = '0' + i; +                fd = open(chloopdev, O_RDONLY, 0); +                if (fd > 0) { +                        if (!ioctl(fd, LOOP_CLR_FD, 0)) +                                printf("\t%s\n", chloopdev); +                        close(fd); +                } +        }  }  struct filesystem @@ -255,6 +275,18 @@ struct filesystem  	int mounted;  }; +char* strcat(register char* s,register const char* t) +{ +  char *dest=s; +  s+=strlen(s); +  for (;;) { +    if (!(*s = *t)) +	break; +    ++s; ++t; +  } +  return dest; +} +  /* attempt to unmount all filesystems in /proc/mounts */  void unmount_filesystems(void)  { @@ -264,9 +296,9 @@ void unmount_filesystems(void)  	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"); @@ -293,7 +325,12 @@ void unmount_filesystems(void)  		*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 */ +		if (strcmp(fs[numfs].name, "/") +                    && !strstr(fs[numfs].dev, "ram") +                    && strcmp(fs[numfs].name, "/dev") +                    && strcmp(fs[numfs].name, "/sys") +                    && strncmp(fs[numfs].name, "/proc", 5)) +                        numfs++;  	}  	/* Pixel's ultra-optimized sorting algorithm: @@ -303,31 +340,123 @@ void unmount_filesystems(void)  		nb = 0;  		for (i = 0; i < numfs; i++) {  			/*printf("trying with %s\n", fs[i].name);*/ +                        del_loops();  			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 */ +			printf("\tumount failed: %s\n", fs[i].name); +			if (strcmp(fs[i].fs, "ext3") == 0) nb++; /* don't count not-ext3 umount failed */  		} -	 + +  	if (nb) {  		printf("failed to umount some filesystems\n"); -		while (1); +                select(0, NULL, NULL, NULL, NULL);  	}  } -int exit_value_rescue = 66; +int in_reboot(void) +{ +        int fd; +        if ((fd = open("/var/run/rebootctl", O_RDONLY, 0)) > 0) { +                char buf[100]; +                int i = read(fd, buf, sizeof(buf)); +                close(fd); +                if (strstr(buf, "halt")) +                        reboot_magic = LINUX_REBOOT_CMD_POWER_OFF; +                return i > 0; +        } +        return 0; +} + +int recursive_remove(char *file); +int recursive_remove(char *file) +{ +	struct stat sb; + +	if (lstat(file, &sb) != 0) { +		printf("failed to stat %s: %d\n", file, errno); +		return -1; +	} + +	/* only descend into subdirectories if device is same as dir */ +	if (S_ISDIR(sb.st_mode)) { +		char * strBuf = alloca(strlen(file) + 1024); +		DIR * dir; +		struct dirent * d; + +		if (!(dir = opendir(file))) { +			printf("error opening %s: %d\n", file, errno); +			return -1; +		} +		while ((d = readdir(dir))) { +			if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) +				continue; + +			strcpy(strBuf, file); +			strcat(strBuf, "/"); +			strcat(strBuf, d->d_name); + +			if (recursive_remove(strBuf) != 0) { +				closedir(dir); +				return -1; +			} +		} +		closedir(dir); + +		if (rmdir(file)) { +			printf("failed to rmdir %s: %d\n", file, errno); +			return -1; +		} +	} else { +		if (unlink(file) != 0) { +			printf("failed to remove %s: %d\n", file, errno); +			return -1; +		} +	} +	return 0; +} + + +int create_initial_fs_symlinks(char* symlinks) +{ +        FILE *f; +        char buf[5000]; + +        if (!(f = fopen(symlinks, "rb"))) { +                printf("Error opening symlink definitions file '%s'\n", symlinks); +                return -1; +        } +        while (fgets(buf, sizeof(buf), f)) { +                char oldpath[500], newpath[500]; +                struct stat sb; + +                buf[strlen(buf)-1] = '\0';  // trim \n +                if (sscanf(buf, "%s %s", oldpath, newpath) != 2) { +                        snprintf(oldpath, sizeof(oldpath), "%s%s", STAGE2_LOCATION, buf); +                        snprintf(newpath, sizeof(newpath), "%s", buf); +                } +                if (lstat(newpath, &sb) == 0) +                        recursive_remove(newpath); +                printf("Creating symlink %s -> %s\n", oldpath, newpath); +                if (symlink(oldpath, newpath)) { +                        printf("Error creating symlink\n"); +                        return -1; +                } +        } +        fclose(f); +        return 0; +} + + +int exit_value_restart = 0x35;  int main(int argc, char **argv)  { @@ -335,10 +464,12 @@ int main(int argc, char **argv)  	int wait_status;  	int fd;  	int abnormal_termination = 0; -	int end_stage2 = 0; -	/* getpid() != 1 should work, by linuxrc tends to get a larger pid */ -	testing = (getpid() > 50); +        if (argc > 1 && argv[1][0] >= '0' && argv[1][0] <= '9') { +                printf("This is no normal init, sorry.\n" +                       "Call `reboot' or `halt' directly.\n"); +                return 0; +        }  	if (!testing) {  		/* turn off screen blanking */ @@ -346,46 +477,39 @@ int main(int argc, char **argv)  		printf("\033[8]");  	}  	else -		printf("*** TESTING MODE ***\n"); +		printf("*** TESTING MODE *** (pid is %d)\n", getpid()); -	printf("\n\t\t\t\033[1;40mWelcome to Linux-\033[1;36mMandrake\033[0;39m\n\n"); -	 -	if (!testing) { -		if (mount("/proc", "/proc", "proc", 0, NULL)) -			fatal_error("Unable to mount proc filesystem"); -	} -	 +	// needed for ldetect: +	if (!testing) +		if (mount("none", "/sys/kernel/debug", "debugfs", MS_NOSUID, "mode=0755")) +			fatal_error("Unable to mount debugfs filesystem"); +  	/* 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); -		 +		fd = open("/dev/console", O_RDWR, 0);  		if (fd < 0) -			fatal_error("failed to open /dev/tty1 and /dev/vc/1"); -		 +			fatal_error("failed to open /dev/console"); +  		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 (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)); +		char my_hostname[] = "localhost"; +		sethostname(my_hostname, sizeof(my_hostname));  		/* the default domainname (as of 2.0.35) is "(none)", which confuses   		   glibc */  		setdomainname("", 0); @@ -394,50 +518,78 @@ int main(int argc, char **argv)  	if (!testing)   		doklog(); -	/* Go into normal init mode - keep going, and then do a orderly shutdown -	   when: -	    -	   1) install exits -	   2) we receive a SIGHUP  -	*/ - -	printf("Traktopel says: drink an egg white each morning builds a man! (c) Warly\n"); -	printf("Running install...\n");  -	 -	if (!(installpid = fork())) { -		/* child */ -		char * child_argv[2]; -		child_argv[0] = "/sbin/stage1"; -		child_argv[1] = NULL; +	if (create_initial_fs_symlinks(STAGE2_LOCATION "/usr/share/symlinks") != 0) +		fatal_error("Fatal error finishing initialization (could not create symlinks)."); + +	/* kernel modules and firmware is needed by stage2, so move them to the root */ +	if (rename("/usr/lib/modules", "/modules")) +		fatal_error("Cannot rename modules folder"); +	if (rename("/usr/lib/firmware", "/firmware")) +		fatal_error("Cannot rename firmware folder"); + +	/* Add some symlinks so stage1 is still valid on it's own - not strictly needed */ +	if (symlink("/modules", "/usr/lib/modules")) +		fatal_error("Cannot symlink modules folder"); + +	if (symlink("/firmware", "/usr/lib/firmware")) +		fatal_error("Cannot symlink firmware folder"); + +	if (mount(STAGE2_LOCATION "/usr", "/usr", "none", MS_BIND|MS_RDONLY, NULL)) +		fatal_error("Unable to bind mount /usr filesystem from rescue or installer stage2"); + + +	if (access("/run/drakx/run-init", R_OK) == 0) { +		/* This is typically used in rescue mode */ +		char * child_argv[2] = { "/sbin/init", NULL }; + +		kill(klog_pid, 9); +		printf("proceeding, please wait...\n");  		execve(child_argv[0], child_argv, env); -		printf("error in exec of stage1 :-(\n"); -		return 0; +		fatal_error("failed to exec /sbin/init");  	} -	while (!end_stage2) { -		childpid = wait4(-1, &wait_status, 0, NULL); -		if (childpid == installpid) -			end_stage2 = 1; -	} +	/* This is installer mode */ +	do { +		printf("proceeding, please wait...\n"); + +		if (!(installpid = fork())) { +			/* child */ +			char * child_argv[2] = { BINARY_STAGE2, NULL }; +			execve(child_argv[0], child_argv, env); +			printf("error in exec of %s :-( [%d]\n", child_argv[0], errno); +			return 0; +		} -	if (!WIFEXITED(wait_status) || (WEXITSTATUS(wait_status) != 0 && WEXITSTATUS(wait_status) != exit_value_rescue)) { -		printf("install exited abnormally :-( "); +		do { +			childpid = wait4(-1, &wait_status, 0, NULL); +		} while (childpid != installpid); +	} while (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_restart); + +	/* allow Ctrl Alt Del to reboot */ +	reboot(LINUX_REBOOT_CMD_CAD_ON); + +	if (in_reboot()) { +		// any exitcode is valid if we're in_reboot +	} else if (!WIFEXITED(wait_status) || WEXITSTATUS(wait_status) != 0) { +		printf("exited abnormally :-( ");  		if (WIFSIGNALED(wait_status))  			printf("-- received signal %d", WTERMSIG(wait_status));  		printf("\n"); -		abnormal_termination = 1; -	} else if (WIFEXITED(wait_status) && WEXITSTATUS(wait_status) == exit_value_rescue) { -		kill(klog_pid, 9); -		printf("exiting init -- giving hand to rescue\n"); -		return 0; -        } else -		printf("install succeeded\n"); +	  	abnormal_termination = 1; +	} + +        if (!abnormal_termination) { +                int i; +                for (i=0; i<50; i++) +                        printf("\n");  /* cleanup startkde messages */ +        }  	if (testing)  		return 0;  	sync(); sync(); +	sleep(2);  	printf("sending termination signals...");  	kill(-1, 15); @@ -451,14 +603,22 @@ int main(int argc, char **argv)  	unmount_filesystems(); +	sync(); sync(); +  	if (!abnormal_termination) { -		printf("rebooting system\n"); -		sleep(2); -		reboot(0xfee1dead, 672274793, 0x01234567); +                if (reboot_magic == LINUX_REBOOT_CMD_RESTART) { +#ifdef DEBUG +                        printf("automatic reboot in 10 seconds\n"); +                        sleep(10); +#endif +                        reboot(reboot_magic); +                } else { +                        printf("you may safely poweroff your computer now\n"); +                }  	} else { -		printf("you may safely reboot your system\n"); -		while (1); +		printf("you may safely reboot or halt your system\n");  	} +        select(0, NULL, NULL, NULL, NULL);  	return 0;  } | 
