lkml.org 
[lkml]   [1997]   [Jan]   [7]   [last100]   RSS Feed
Views: [more markup]  [less markup]  [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From(David Hinds)
SubjectPatch for 2.1.20 to try: "kernel environment"
Date5 Jan 1997 18:26:34 GMT
Here's an update to the kernel environment patch I posted the other
day, that fixes a memory leak.  Also I was told the original patch
didn't go cleanly against 2.1.20.  It's possible I posted a patch
against 2.1.16 by mistake... in any case, this one is definitely for
2.1.20.  I've also put the patch on hyper.stanford.edu in
/pub/pcmcia/patches/kenv-2.1.20 just in case.

-- Dave Hinds

--- linux/init/main.c.orig	Thu Jan  2 22:32:15 1997
+++ linux/init/main.c	Sun Jan  5 10:29:47 1997
@@ -6,6 +6,7 @@
  *  GK 2/5/95  -  Changed to support mounting root fs via NFS
  *  Added initrd & change_root: Werner Almesberger & Hans Lermen, Feb '96
  *  Moan early if gcc is old, avoiding bogus kernels - Paul Gortmaker, May '96
+ *  Rewrite of boot parameter parsing - Dave Hinds, Dec '96
  */
 
 #define __KERNEL_SYSCALLS__
@@ -29,6 +30,7 @@
 #include <linux/mm.h>
 #include <linux/major.h>
 #include <linux/blk.h>
+#include <linux/malloc.h>
 #ifdef CONFIG_ROOT_NFS
 #include <linux/nfs_fs.h>
 #endif
@@ -205,7 +207,6 @@
  * Boot command-line arguments
  */
 #define MAX_INIT_ARGS 8
-#define MAX_INIT_ENVS 8
 
 extern void time_init(void);
 
@@ -235,11 +236,65 @@
 extern void dquot_init(void);
 
 static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
-static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, };
+char ** envp_init;
 
 static char * argv_rc[] = { "/bin/sh", NULL };
 static char * envp_rc[] = { "HOME=/", "TERM=linux", NULL };
 
+char *getkenv(const char *name)
+{
+	char **s, *t;
+	int i;
+	for (s = envp_init; (t = *s); s++) {
+		for (i = 0; (t[i] != '=') && name[i]; i++)
+			if (t[i] != name[i]) break;
+		if ((t[i] == '=') && (name[i] == '\0'))
+			return t+i+1;
+	}
+	return NULL;
+}
+
+int putkenv(const char *str)
+{
+	char **e, *s, *t;
+	int i, j;
+	unsigned long flags;
+	
+	if (strchr(str, '=') == NULL)
+		return -1;
+	/* See if the tag is already in the environment */
+	for (i = 0; (t = envp_init[i]); i++) {
+		for (j = 0; (t[j] != '=') && (str[j] != '='); j++)
+			if (t[j] != str[j]) break;
+		if ((t[j] == '=') && (str[j] == '='))
+			break;
+	}
+	if (!t) {
+		/* Extend the environment table if necessary */
+		e = kmalloc((i+2) * sizeof(char *), GFP_KERNEL);
+		if (e == NULL)
+			return -1;
+		memcpy(e, envp_init, (i+1) * sizeof(char *));
+		save_flags(flags);
+		cli();
+		if ((unsigned long)envp_init > memory_start)
+			kfree(envp_init);
+		envp_init = e;
+		restore_flags(flags);
+		e[i+1] = NULL;
+	}
+	/* Copy the string to a safe place and add to table */
+	s = kmalloc(strlen(str)+1, GFP_KERNEL);
+	if (s == NULL)
+		return -1;
+	strcpy(s, str);
+	envp_init[i] = s;
+	/* If the old string was kmalloc()ed, then free it */
+	if (t && ((unsigned long)t > memory_start))
+		kfree(t);
+	return 0;
+}
+
 char *get_options(char *str, int *ints)
 {
 	char *cur = str;
@@ -500,27 +555,25 @@
 
 #endif
 
-static int checksetup(char *line)
+static void checksetup(char *line)
 {
-	int i = 0;
+	int i;
 	int ints[11];
 
 #ifdef CONFIG_BLK_DEV_IDE
 	/* ide driver needs the basic string, rather than pre-processed values */
 	if (!strncmp(line,"ide",3) || (!strncmp(line,"hd",2) && line[2] != '=')) {
 		ide_setup(line);
-		return 1;
+		return;
 	}
 #endif
-	while (bootsetups[i].str) {
+	for (i = 0; bootsetups[i].str; i++) {
 		int n = strlen(bootsetups[i].str);
 		if (!strncmp(line,bootsetups[i].str,n)) {
 			bootsetups[i].setup_func(get_options(line+n,ints), ints);
-			return 1;
+			return;
 		}
-		i++;
 	}
-	return 0;
 }
 
 /* this should be approx 2 Bo*oMips to start (note initial shift), and will
@@ -636,88 +689,79 @@
  * as appropriate. Any cmd-line option is taken to be an environment
  * variable if it contains the character '='.
  *
- *
- * This routine also checks for options meant for the kernel.
- * These options are not given to init - they are for internal kernel use only.
+ * Options can be enclosed in quotation marks, and the backslash can
+ * be used to escape spaces and quotation marks.
  */
-static void parse_options(char *line)
+static unsigned long parse_options(char *line, unsigned long memory_start)
 {
-	char *next;
-	int args, envs;
+	char *last, *next, *s;
+	int quot = 0, args, envs;
 
-	if (!*line)
-		return;
-	args = 0;
-	envs = 1;	/* TERM is set to 'linux' by default */
-	next = line;
-	while ((line = next) != NULL) {
-		if ((next = strchr(line,' ')) != NULL)
-			*next++ = 0;
-		/*
-		 * check for kernel options first..
-		 */
-		if (!strncmp(line,"root=",5)) {
-			parse_root_dev(line+5);
-			continue;
-		}
-#ifdef CONFIG_ROOT_NFS
-		if (!strncmp(line, "nfsroot=", 8)) {
-			int n;
-			line += 8;
-			ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);
-			if (line[0] == '/' || line[0] == ',' || (line[0] >= '0' && line[0] <= '9')) {
-				strncpy(nfs_root_name, line, sizeof(nfs_root_name));
-				nfs_root_name[sizeof(nfs_root_name)-1] = '\0';
+	envp_init = (char **) memory_start;
+	envp_init[0] = "HOME=/";
+	envp_init[1] = "TERM=linux";
+	envs = 2;
+	args = 1;
+	for (;;) {
+		while (*line == ' ') line++;
+		if (*line == '\0') break;
+		/* Interpret quotes, backslashes */
+		for (last = next = line; *next != '\0'; next++) {
+			if (*next == '"') {
+				quot = !quot;
 				continue;
 			}
-			n = strlen(line) + strlen(NFS_ROOT);
-			if (n >= sizeof(nfs_root_name))
-				line[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0';
-			sprintf(nfs_root_name, NFS_ROOT, line);
-			continue;
-		}
-		if (!strncmp(line, "nfsaddrs=", 9)) {
-			line += 9;
-			strncpy(nfs_root_addrs, line, sizeof(nfs_root_addrs));
-			nfs_root_addrs[sizeof(nfs_root_addrs)-1] = '\0';
-			continue;
+			if (!quot && (*next == ' '))
+				break;
+			if (*next == '\\')
+				next++;
+			*(last++) = *next;
 		}
-#endif
-		if (!strcmp(line,"ro")) {
+		if (*next != '\0') next++;
+		*last = '\0';
+		if (strcmp(line, "ro") == 0)
 			root_mountflags |= MS_RDONLY;
-			continue;
-		}
-		if (!strcmp(line,"rw")) {
+		else if (strcmp(line, "rw") == 0)
 			root_mountflags &= ~MS_RDONLY;
-			continue;
-		}
-		if (!strcmp(line,"debug")) {
+		else if (strcmp(line, "debug") == 0)
 			console_loglevel = 10;
-			continue;
-		}
-		if (!strncmp(line,"init=",5)) {
-			line += 5;
-			execute_command = line;
-			continue;
-		}
-		if (checksetup(line))
-			continue;
-		/*
-		 * Then check if it's an environment variable or
-		 * an option.
-		 */
-		if (strchr(line,'=')) {
-			if (envs >= MAX_INIT_ENVS)
-				break;
-			envp_init[++envs] = line;
+		else if (strchr(line,'=')) {
+			envp_init[envs++] = line;
+			checksetup(line);
 		} else {
-			if (args >= MAX_INIT_ARGS)
+			if (args > MAX_INIT_ARGS)
 				break;
-			argv_init[++args] = line;
+			argv_init[args++] = line;
+		}
+		line = next;
+	}
+	argv_init[args] = NULL;
+	envp_init[envs] = NULL;
+
+	if ((s = getkenv("root")) != NULL)
+		parse_root_dev(s);
+#ifdef CONFIG_ROOT_NFS
+	if ((s = getkenv("nfsroot")) != NULL) {
+		int n;
+		ROOT_DEV = MKDEV(UNNAMED_MAJOR, 255);
+		if (s[0] == '/' || s[0] == ',' || (s[0] >= '0' && s[0] <= '9')) {
+		       	strncpy(nfs_root_name, s, sizeof(nfs_root_name));
+			nfs_root_name[sizeof(nfs_root_name)-1] = '\0';
+		} else {
+			n = strlen(s) + strlen(NFS_ROOT);
+			if (n >= sizeof(nfs_root_name))
+				s[sizeof(nfs_root_name) - strlen(NFS_ROOT) - 1] = '\0';
+			sprintf(nfs_root_name, NFS_ROOT, s);
 		}
 	}
-	argv_init[args+1] = NULL;
-	envp_init[envs+1] = NULL;
+	if ((s = getkenv("nfsaddrs")) != NULL) {
+		strncpy(nfs_root_addrs, line, sizeof(nfs_root_addrs));
+		nfs_root_addrs[sizeof(nfs_root_addrs)-1] = '\0';
+	}
+#endif
+	execute_command = getkenv("init");
+	
+	return (memory_start + (envs+1) * sizeof(char *));
 }
 
 
@@ -843,7 +887,7 @@
 	init_IRQ();
 	sched_init();
 	time_init();
-	parse_options(command_line);
+	memory_start = parse_options(command_line, memory_start);
 #ifdef CONFIG_MODULES
 	init_modules();
 #endif
--- linux/kernel/ksyms.c.orig	Wed Jan  1 22:09:13 1997
+++ linux/kernel/ksyms.c	Fri Jan  3 23:55:34 1997
@@ -70,7 +70,6 @@
 #include <linux/smp.h>
 #endif
 
-extern char *get_options(char *str, int *ints);
 extern void set_device_ro(int dev,int flag);
 extern struct file_operations * get_blkfops(unsigned int);
 extern void blkdev_release(struct inode * inode);
@@ -93,6 +92,8 @@
 #ifdef CONFIG_KERNELD
 EXPORT_SYMBOL(kerneld_send);
 #endif
+EXPORT_SYMBOL(getkenv);
+EXPORT_SYMBOL(putkenv);
 EXPORT_SYMBOL(get_options);
 
 #ifdef CONFIG_PCI
--- linux/include/linux/kernel.h.orig	Sun Dec  1 01:06:55 1996
+++ linux/include/linux/kernel.h	Fri Jan  3 23:54:36 1997
@@ -62,6 +62,10 @@
 #define pr_info(fmt,arg...) \
 	printk(KERN_INFO fmt,##arg)
 
+extern char *get_options(char *str, int *ints);
+extern char *getkenv(const char *name);
+extern int putkenv(const char *str);
+
 /*
  * "suser()" checks against the effective user id, while "fsuser()"
  * is used for file permission checking and checks against the fsuid..
--- linux/include/linux/proc_fs.h.orig	Wed Jan  1 22:08:27 1997
+++ linux/include/linux/proc_fs.h	Fri Jan  3 23:56:23 1997
@@ -46,7 +46,8 @@
 	PROC_MD,
 	PROC_RTC,
 	PROC_LOCKS,
-	PROC_ZORRO
+	PROC_ZORRO,
+	PROC_KENV
 };
 
 enum pid_directory_inos {
--- linux/fs/proc/array.c.orig	Wed Jan  1 22:08:20 1997
+++ linux/fs/proc/array.c	Fri Jan  3 23:54:36 1997
@@ -322,6 +322,16 @@
 	return sprintf(buffer, "%s\n", saved_command_line);
 }
 
+static int get_kenv(char * buffer)
+{
+	extern char **envp_init;
+	char **p;
+	int len = 0;
+	for (p = envp_init; *p; p++)
+		len += sprintf(buffer+len, "%s\n", *p);
+	return len;
+}
+
 static struct task_struct ** get_task(pid_t pid)
 {
 	struct task_struct ** p;
@@ -1081,6 +1091,9 @@
 #endif
 		case PROC_CMDLINE:
 			return get_cmdline(page);
+
+		case PROC_KENV:
+			return get_kenv(page);
 
                 case PROC_MTAB:
                        return get_filesystem_info( page );
--- linux/fs/proc/root.c.orig	Wed Jan  1 22:08:21 1997
+++ linux/fs/proc/root.c	Fri Jan  3 23:54:36 1997
@@ -496,6 +496,10 @@
 	PROC_CMDLINE, 7, "cmdline",
 	S_IFREG | S_IRUGO, 1, 0, 0,
 };
+static struct proc_dir_entry proc_root_kenv = {
+	PROC_KENV, 6, "kenv",
+	S_IFREG | S_IRUGO, 1, 0, 0,
+};
 #ifdef CONFIG_RTC
 static struct proc_dir_entry proc_root_rtc = {
 	PROC_RTC, 3, "rtc",
@@ -562,6 +566,7 @@
 	proc_register(&proc_root, &proc_root_dma);
 	proc_register(&proc_root, &proc_root_ioports);
 	proc_register(&proc_root, &proc_root_cmdline);
+	proc_register(&proc_root, &proc_root_kenv);
 #ifdef CONFIG_RTC
 	proc_register(&proc_root, &proc_root_rtc);
 #endif

\
 
 \ /
  Last update: 2005-03-22 13:38    [from the cache]
©2003-2008