One more step toward a full-featured kinit; do lots of cleanups
diff --git a/kinit/Makefile b/kinit/Makefile
index 0771568..6ac41ea 100644
--- a/kinit/Makefile
+++ b/kinit/Makefile
@@ -13,7 +13,8 @@
$(SRCROOT)/ipconfig/libipconfig.a \
$(KLIBC) $(LIBGCC)
PROGS = kinit
-OBJS = kinit.o do_mounts.o nfsroot.o
+OBJS = kinit.o do_mounts.o nfsroot.o getintfile.o initrd.o \
+ open.o readfile.o
all: $(PROGS)
diff --git a/kinit/do_mounts.c b/kinit/do_mounts.c
index 5d5bf8e..150f0cd 100644
--- a/kinit/do_mounts.c
+++ b/kinit/do_mounts.c
@@ -14,7 +14,6 @@
#define BUF_SZ 4096
-static const char *progname = "VFS";
static const int do_devfs; // FIXME
/* Find dev_t for e.g. "hda,NULL" or "hdb,2" */
@@ -195,7 +194,7 @@
}
/* Create the device node "name" */
-static int
+int
create_dev(const char *name, dev_t dev, const char *devfs_name)
{
char path[BUF_SZ];
@@ -221,70 +220,82 @@
return symlink(path + 5, name);
}
-/* get a list of all filesystems to try to mount root with */
-static void
-get_fs_names(int argc, char *argv[], char *buf)
+/* mount a filesystem, possibly trying a set of different types */
+const char *
+mount_block(const char *source, const char *target,
+ const char *type, unsigned long flags,
+ const void *data)
{
- char *s, *p;
- char line[BUF_SZ];
- const char *root_fs_names;
- FILE *fp;
+ char *fslist, *p, *ep;
+ const char *rp;
+ ssize_t fsbytes;
- root_fs_names = get_arg(argc, argv, "rootfstype=");
- if (root_fs_names) {
- strcpy(buf, root_fs_names);
- for (s = buf; *s; s++) {
- if (*s == ',')
- *s = 0;
- }
- } else {
- buf[0] = 0;
- if ((fp = fopen("/proc/filesystems", "r")) == NULL)
- goto done;
-
- s = buf;
- while (fgets(line, BUF_SZ, fp)) {
- if (line[0] != '\t')
- continue;
- p = strchr(line, '\n');
- if (!p)
- continue;
-
- *p = 0;
- strcpy(s, line + 1);
- s += strlen(line + 1) + 1;
- }
+ if ( type ) {
+ int rv = mount(source, target, type, flags, data);
+ /* Mount readonly if necessary */
+ if ( rv == -1 && errno == EACCES && !(flags & MS_RDONLY) )
+ rv = mount(source, target, type, flags|MS_RDONLY, data);
+ return rv ? NULL : type;
}
- done:
- return;
+
+ fsbytes = readfile("/proc/filesystems", &fslist);
+
+ errno = EINVAL;
+ if ( fsbytes < 0 )
+ return NULL;
+
+ p = fslist;
+ ep = fslist+fsbytes;
+
+ rp = NULL;
+
+ while ( p < ep ) {
+ type = p;
+ p = strchr(p, '\n');
+ if (!p)
+ break;
+ *p++ = '\0';
+ if (*type != '\t')/* We can't mount a block device as a "nodev" fs */
+ continue;
+
+ type++;
+ rp = mount_block(source, target, type, flags, data);
+ if ( rp )
+ break;
+ if ( errno != EINVAL )
+ break;
+ }
+
+ free(fslist);
+ return rp;
}
/* mount the root filesystem from a block device */
static int
mount_block_root(int argc, char *argv[], dev_t root_dev,
- const char *root_dev_name, int flags)
+ const char *root_dev_name, unsigned long flags)
{
- char fs_names[BUF_SZ];
- const char *data;
- char *p;
+ const char *data, *type;
+ const char *rp;
data = get_arg(argc, argv, "rootflags=");
-
create_dev("/dev/root", root_dev, root_dev_name);
- get_fs_names(argc, argv, fs_names);
-retry:
- for (p = fs_names; *p; p += strlen(p)+1) {
- if (mount("/dev/root", "/root", p, flags, data) == 0)
- goto out;
+ errno = 0;
- switch (errno) {
- case -EACCES:
- flags |= MS_RDONLY;
- goto retry;
- case -EINVAL:
- continue;
- }
+ type = get_arg(argc, argv, "rootfstype=");
+ if ( type ) {
+ if ( (rp = mount_block("/dev/root", "/root", type, flags, data)) )
+ goto ok;
+ if ( errno != EINVAL )
+ goto bad;
+ }
+
+ if ( !errno && (rp = mount_block("/dev/root", "/root", NULL, flags, data)) )
+ goto ok;
+
+ bad:
+ if ( errno != EINVAL ) {
/*
* Allow the user to distinguish between failed open
* and bad superblock on root device.
@@ -292,32 +303,24 @@
fprintf(stderr, "%s: Cannot open root device \"%04x\"\n",
progname, root_dev);
return -errno;
+ } else {
+ fprintf(stderr, "%s: Unable to mount root fs on \"%04x\"\n",
+ progname, root_dev);
+ return -ESRCH;
}
- fprintf(stderr, "%s: Unable to mount root fs on \"%04x\"\n",
- progname, root_dev);
- return -ESRCH;
-out:
+ok:
printf("%s: Mounted root (%s filesystem)%s.\n",
- progname, p, (flags & MS_RDONLY) ? " readonly" : "");
+ progname, rp, (flags & MS_RDONLY) ? " readonly" : "");
return 0;
}
int
-do_mounts(int argc, char *argv[])
+mount_root(int argc, char *argv[], dev_t root_dev, const char *root_dev_name)
{
- const char *root_dev_name = get_arg(argc, argv, "root=");
- int flags = MS_RDONLY | MS_VERBOSE;
- dev_t root_dev = 0;
+ unsigned long flags = MS_RDONLY|MS_VERBOSE;
int ret;
- if (root_dev_name) {
- root_dev = name_to_dev_t(root_dev_name);
- if (strncmp(root_dev_name, "/dev/", 5) == 0) {
- root_dev_name += 5;
- }
- }
-
if (get_arg(argc, argv, "ro")) {
flags |= MS_RDONLY;
}
@@ -337,3 +340,39 @@
return ret;
}
+
+void
+md_run_setup(void)
+{
+ /* Muck around with md device(s) if necessary */
+}
+
+int do_mounts(int argc, char *argv[])
+{
+ const char *root_dev_name = get_arg(argc, argv, "root=");
+ const char *root_delay = get_arg(argc, argv, "rootdelay=");
+ dev_t root_dev = 0;
+
+ if (root_delay) {
+ int delay = atoi(root_delay);
+ fprintf(stderr, "Waiting %d s before mounting root device...\n", delay);
+ sleep(delay);
+ }
+
+ md_run_setup();
+
+ if (root_dev_name) {
+ root_dev = name_to_dev_t(root_dev_name);
+ if (strncmp(root_dev_name, "/dev/", 5) == 0) {
+ root_dev_name += 5;
+ }
+ }
+
+ if ( initrd_load(argc, argv, root_dev) )
+ return 0;
+
+ /* If it's a floppy(only?) and load_ramdisk is set, then load
+ a non-initrd ramdisk */
+
+ return mount_root(argc, argv, root_dev, root_dev_name);
+}
diff --git a/kinit/do_mounts.h b/kinit/do_mounts.h
index fb65aae..5717afd 100644
--- a/kinit/do_mounts.h
+++ b/kinit/do_mounts.h
@@ -11,4 +11,19 @@
#define Root_RAM0 makedev(1,0)
#define Root_NFS makedev(0,255)
+int
+create_dev(const char *name, dev_t dev, const char *devfs_name);
+
+const char *
+mount_block(const char *source, const char *target,
+ const char *type, unsigned long flags,
+ const void *data);
+
+int
+mount_root(int argc, char *argv[], dev_t root_dev, const char *root_dev_name);
+
+int do_mounts(int argc, char *argv[]);
+
+int initrd_load(int argc, char *argv[], dev_t root_dev);
+
#endif /* DO_MOUNTS_H */
diff --git a/kinit/getintfile.c b/kinit/getintfile.c
index 4a34a86..069870d 100644
--- a/kinit/getintfile.c
+++ b/kinit/getintfile.c
@@ -18,9 +18,9 @@
if ( !f )
return -1;
- memset(buffer, 0, sizeof buffer);
- fread(buffer, 1, sizeof buffer, f);
+ ep = buffer + fread(buffer, 1, sizeof buffer-1, f);
fclose(f);
+ *ep = '\0';
*val = strtol(buffer, &ep, 0);
if ( *ep && *ep != '\n' )
diff --git a/kinit/initrd.c b/kinit/initrd.c
index 31877cf..9aa5bd5 100644
--- a/kinit/initrd.c
+++ b/kinit/initrd.c
@@ -12,6 +12,7 @@
#include <sys/stat.h>
#include <sys/mount.h>
#include <sys/ioctl.h>
+#include <sys/wait.h>
#include "do_mounts.h"
#include "kinit.h"
@@ -21,13 +22,13 @@
* Copy the initrd to /dev/ram0, copy from the end to the beginning
* to avoid taking 2x the memory.
*/
-int rd_copy_image(const char *path)
+int rd_copy_image(int ffd)
{
- int ffd = open(path, O_RDONLY);
int dfd = open("/dev/ram0", O_RDWR);
char buffer[BUF_SIZE];
struct stat st;
off_t bytes;
+ int rv = -1;
if ( ffd < 0 || dfd < 0 )
goto barf;
@@ -47,27 +48,33 @@
ftruncate(ffd, offset); /* Free up memory */
bytes = offset;
}
-
- return 0; /* Success! */
+ rv = 0; /* Done! */
barf:
close(ffd);
close(dfd);
- return -1;
+ return rv;
}
/*
* Run /linuxrc, for emulation of old-style initrd
*/
-int run_linuxrc(const char *ramdisk)
+static int
+run_linuxrc(int argc, char *argv[], dev_t root_dev)
{
int root_fd, old_fd;
pid_t pid;
- int err;
long realroot = Root_RAM0;
+ const char *ramdisk_name = "/dev/ram0";
+ FILE *fp;
- if ( err = mount_block_root(ramdisk, root_mountflags & ~MS_RDONLY) )
- return err;
+ if ( !mount_block(ramdisk_name, "/", NULL, MS_VERBOSE, NULL) )
+ return -errno;
+
+ /* Write the current "real root device" out to procfs */
+ fp = fopen("/proc/sys/kernel/real-root-dev", "w");
+ fprintf(fp, "%lu", (unsigned long)root_dev);
+ fclose(fp);
mkdir("/old", 0700);
root_fd = open_cloexec("/", O_RDONLY|O_DIRECTORY, 0);
@@ -104,37 +111,44 @@
close(old_fd);
getintfile("/proc/sys/kernel/real-root-dev", &realroot);
- mount_root((dev_t)realroot);
+ mount_root(argc, argv, (dev_t)realroot, NULL);
/* If /root/initrd exists, move the initrd there, otherwise discard */
if ( !mount("/old", "/root/initrd", NULL, MS_MOVE, NULL) ) {
/* We're good */
} else {
- int olddev = open(ramdisk, O_RDWR);
+ int olddev = open(ramdisk_name, O_RDWR);
umount2("/old", MNT_DETACH);
if ( olddev < 0 ||
ioctl(olddev, BLKFLSBUF, (long)0) ||
close(olddev) ) {
- /* Print error message */
+ fprintf(stderr, "%s: Cannot flush initrd contents\n", progname);
}
}
+
+ return 0;
}
-int initrd_load(dev_t *root_dev)
+int initrd_load(int argc, char *argv[], dev_t root_dev)
{
- int mount_initrd = 1;
+ int initrd_fd;
- if ( mount_initrd ) {
- create_dev("/dev/ram0", Root_RAM0, NULL);
-
- if ( rd_copy_image("/initrd.image") == 0 && *root_dev != Root_RAM0 ) {
- run_linuxrc(root_dev)
- return 1;
- }
+ initrd_fd = open("/initrd.image", O_RDWR);
+ if ( initrd_fd < 0 )
+ return 0;
+
+ create_dev("/dev/ram0", Root_RAM0, NULL);
+
+ if ( rd_copy_image(initrd_fd) ||
+ unlink("/initrd.image") )
+ return 0;
+
+ if ( root_dev != Root_RAM0 ) {
+ run_linuxrc(argc, argv, root_dev);
+ return 1;
}
- unlink("/initrd.image");
return 0;
}
diff --git a/kinit/kinit.c b/kinit/kinit.c
index b3be538..738d40f 100644
--- a/kinit/kinit.c
+++ b/kinit/kinit.c
@@ -11,7 +11,7 @@
#include "kinit.h"
#include "ipconfig.h"
-static const char *progname = "kinit";
+const char *progname = "kinit";
int mnt_procfs;
int mnt_sysfs;
@@ -193,6 +193,8 @@
int init_argc;
char **init_argv;
+extern ssize_t readfile(const char *, char **);
+
int main(int argc, char *argv[])
{
char **cmdv;
@@ -202,6 +204,11 @@
int ret = 0;
int cmdc;
int fd;
+
+ ret = readfile("/proc/cmdline", &cmdline);
+ printf("Got: len = %d data = \"%s\"\n", ret, cmdline);
+
+ exit(0);
/* Default parameters for anything init-like we execute */
init_argc = argc;
diff --git a/kinit/kinit.h b/kinit/kinit.h
index 5cead89..ba19af4 100644
--- a/kinit/kinit.h
+++ b/kinit/kinit.h
@@ -2,6 +2,8 @@
* kinit/kinit.h
*/
+#include <stddef.h>
+
extern void dump_args(int argc, char *argv[]);
extern int do_mounts(int argc, char *argv[]);
extern int mount_nfs_root(int argc, char *argv[], int flags);
@@ -12,6 +14,12 @@
extern int init_argc;
extern char **init_argv;
+extern const char *progname;
+
+int open_cloexec(const char *path, int flags, mode_t mode);
+int getintfile(const char *path, long *val);
+ssize_t readfile(const char *path, char **pptr);
+ssize_t freadfile(FILE *f, char **pptr);
#undef INI_DEBUG
diff --git a/kinit/readfile.c b/kinit/readfile.c
new file mode 100644
index 0000000..98bb800
--- /dev/null
+++ b/kinit/readfile.c
@@ -0,0 +1,93 @@
+/*
+ * readfile.c
+ *
+ * Read the entire contents of a file into malloc'd storage. This
+ * is mostly useful for things like /proc files where we can't just
+ * fstat() to get the length and then mmap().
+ *
+ * Returns the number of bytes read, or -1 on error.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+
+ssize_t freadfile(FILE *f, char **pp)
+{
+ size_t bs; /* Decent starting point... */
+ size_t bf; /* Bytes free */
+ size_t bu = 0; /* Bytes used */
+ char *buffer, *nb;
+ size_t rv;
+ int old_errno = errno;
+#if 0
+ struct stat st;
+
+ if ( !fstat(fileno(f), &st) && S_ISREG(st.st_mode) && st.st_size )
+ bs = st.st_size+1;
+ else
+#endif
+ bs = BUFSIZ; /* A guess as good as any */
+
+ bf = bs;
+ buffer = malloc(bs);
+
+ if ( !buffer )
+ return -1;
+
+ for (;;) {
+ errno = 0;
+
+ while ( bf && (rv = _fread(buffer+bu, bf, f)) ) {
+ bu += rv;
+ bf -= rv;
+ }
+
+ if ( errno && errno != EINTR && errno != EAGAIN ) {
+ /* error */
+ free(buffer);
+ return -1;
+ }
+
+ if ( bf ) {
+ /* Hit EOF, no error */
+
+ /* Try to free superfluous memory */
+ if ( (nb = realloc(buffer, bu+1)) )
+ buffer = nb;
+
+ /* Null-terminate result for good measure */
+ buffer[bu] = '\0';
+
+ *pp = buffer;
+ errno = old_errno;
+ return bu;
+ }
+
+ /* Double the size of the buffer */
+ bf += bs;
+ bs += bs;
+ if ( !(nb = realloc(buffer, bs)) ) {
+ /* out of memory error */
+ free(buffer);
+ return -1;
+ }
+ buffer = nb;
+ }
+}
+
+ssize_t readfile(const char *filename, char **pp)
+{
+ FILE *f = fopen(filename, "r");
+ ssize_t rv;
+
+ if ( !f )
+ return -1;
+
+ rv = freadfile(f, pp);
+
+ fclose(f);
+
+ return rv;
+}