summaryrefslogtreecommitdiffstats
path: root/lib/libstand
diff options
context:
space:
mode:
authorsobomax <sobomax@FreeBSD.org>2002-03-17 12:18:05 +0000
committersobomax <sobomax@FreeBSD.org>2002-03-17 12:18:05 +0000
commit9d703dcfedc6263b12ba725785b027e958c540f3 (patch)
treedd2d29323555872217afb04ebb572acebac59fcd /lib/libstand
parent006a375bc447bfc5b3db07294bf35dbe748b38a9 (diff)
downloadFreeBSD-src-9d703dcfedc6263b12ba725785b027e958c540f3.zip
FreeBSD-src-9d703dcfedc6263b12ba725785b027e958c540f3.tar.gz
Add splitfs vfs layer into libstand, which allows loading big kernels and
modules split across several physical medias. Following is how it works: The splitfs code, when asked to open "foo" looks for a file "foo.split" which is a text file containing a list of filenames and media names, e.g. foo.aa "Kernel floppy 1" foo.ab "Kernel floppy 2" foo.ac "Kernel and modules floppy" For each file segment, the process is: - try to open the file - prompt "Insert the disk labelled <whatever> and press any key..." - try to open the file - return error if file could not be located RE team is free to use this feature in the upcoming 5.0-DP1. Reviewed by: msmith, dcs
Diffstat (limited to 'lib/libstand')
-rw-r--r--lib/libstand/Makefile1
-rw-r--r--lib/libstand/bzipfs.c2
-rw-r--r--lib/libstand/gzipfs.c2
-rw-r--r--lib/libstand/splitfs.c287
-rw-r--r--lib/libstand/stand.h1
-rw-r--r--lib/libstand/zipfs.c2
6 files changed, 292 insertions, 3 deletions
diff --git a/lib/libstand/Makefile b/lib/libstand/Makefile
index 3349522..08f7319 100644
--- a/lib/libstand/Makefile
+++ b/lib/libstand/Makefile
@@ -153,6 +153,7 @@ SRCS+= bootp.c rarp.c bootparam.c
SRCS+= ufs.c nfs.c cd9660.c tftp.c zipfs.c bzipfs.c
SRCS+= netif.c nfs.c
SRCS+= dosfs.c ext2fs.c
+SRCS+= splitfs.c
beforeinstall:
${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/stand.h \
diff --git a/lib/libstand/bzipfs.c b/lib/libstand/bzipfs.c
index 5dd6fab..c0a8d9b 100644
--- a/lib/libstand/bzipfs.c
+++ b/lib/libstand/bzipfs.c
@@ -150,7 +150,7 @@ bzf_open(const char *fname, struct open_file *f)
/* If the name already ends in .gz or .bz2, ignore it */
if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
- || !strcmp(cp, ".bz2")))
+ || !strcmp(cp, ".bz2") || !strcmp(cp, ".split")))
return(ENOENT);
/* Construct new name */
diff --git a/lib/libstand/gzipfs.c b/lib/libstand/gzipfs.c
index 59034ff..00c8f8f 100644
--- a/lib/libstand/gzipfs.c
+++ b/lib/libstand/gzipfs.c
@@ -175,7 +175,7 @@ zf_open(const char *fname, struct open_file *f)
/* If the name already ends in .gz or .bz2, ignore it */
if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
- || !strcmp(cp, ".bz2")))
+ || !strcmp(cp, ".bz2") || !strcmp(cp, ".split")))
return(ENOENT);
/* Construct new name */
diff --git a/lib/libstand/splitfs.c b/lib/libstand/splitfs.c
new file mode 100644
index 0000000..26c7d1f
--- /dev/null
+++ b/lib/libstand/splitfs.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (c) 2002 Maxim Sobolev
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "stand.h"
+
+#define NTRIES (3)
+#define CONF_BUF (512)
+#define SEEK_BUF (512)
+
+struct split_file
+{
+ char **filesv; /* Filenames */
+ char **descsv; /* Descriptions */
+ int filesc; /* Number of parts */
+ int curfile; /* Current file number */
+ int curfd; /* Current file descriptor */
+ off_t tot_pos; /* Offset from the beginning of the sequence */
+ off_t file_pos; /* Offset from the beginning of the slice */
+};
+
+static int splitfs_open(const char *path, struct open_file *f);
+static int splitfs_close(struct open_file *f);
+static int splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid);
+static off_t splitfs_seek(struct open_file *f, off_t offset, int where);
+static int splitfs_stat(struct open_file *f, struct stat *sb);
+
+struct fs_ops splitfs_fsops = {
+ "split",
+ splitfs_open,
+ splitfs_close,
+ splitfs_read,
+ null_write,
+ splitfs_seek,
+ splitfs_stat,
+ null_readdir
+};
+
+static void
+split_file_destroy(struct split_file *sf)
+{
+ int i;
+
+ if (sf->filesc > 0) {
+ for (i = 0; i < sf->filesc; i++) {
+ free(sf->filesv[i]);
+ free(sf->descsv[i]);
+ }
+ free(sf->filesv);
+ free(sf->descsv);
+ }
+ free(sf);
+}
+
+static int
+splitfs_open(const char *fname, struct open_file *f)
+{
+ char *buf, *confname, *cp;
+ int conffd;
+ struct split_file *sf;
+ struct stat sb;
+
+ printf("%s\n", fname);
+ /* Have to be in "just read it" mode */
+ if (f->f_flags != F_READ)
+ return(EPERM);
+
+ /* If the name already ends in `.split', ignore it */
+ if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".split")))
+ return(ENOENT);
+
+ /* Construct new name */
+ confname = malloc(strlen(fname) + 7);
+ sprintf(confname, "%s.split", fname);
+
+ /* Try to open the configuration file */
+ conffd = open(confname, O_RDONLY);
+ free(confname);
+ if (conffd == -1)
+ return(ENOENT);
+
+ if (fstat(conffd, &sb) < 0) {
+ printf("splitfs_open: stat failed\n");
+ close(conffd);
+ return(ENOENT);
+ }
+ if (!S_ISREG(sb.st_mode)) {
+ printf("splitfs_open: not a file\n");
+ close(conffd);
+ return(EISDIR); /* best guess */
+ }
+
+ /* Allocate a split_file structure, populate it from the config file */
+ sf = malloc(sizeof(struct split_file));
+ bzero(sf, sizeof(struct split_file));
+ buf = malloc(CONF_BUF);
+ while (fgetstr(buf, CONF_BUF, conffd) > 0) {
+ cp = buf;
+ while ((*cp != '\0') && (isspace(*cp) == 0))
+ cp++;
+ if (*cp != '\0') {
+ *cp = '\0';
+ cp++;
+ }
+ while ((*cp != '\0') && (isspace(*cp) != 0))
+ cp++;
+ if (*cp == '\0')
+ cp = buf;
+ sf->filesc++;
+ sf->filesv = realloc(sf->filesv, sizeof(*(sf->filesv)) * sf->filesc);
+ sf->descsv = realloc(sf->descsv, sizeof(*(sf->descsv)) * sf->filesc);
+ sf->filesv[sf->filesc - 1] = strdup(buf);
+ sf->descsv[sf->filesc - 1] = strdup(cp);
+ }
+ free(buf);
+ close(conffd);
+
+ if ((sf->filesc == 0) || ((sf->curfd = open(sf->filesv[0], O_RDONLY)) == -1)) {
+ split_file_destroy(sf);
+ return(ENOENT);
+ }
+
+ /* Looks OK, we'll take it */
+ f->f_fsdata = sf;
+ return (0);
+}
+
+static int
+splitfs_close(struct open_file *f)
+{
+ int fd;
+ struct split_file *sf;
+
+ sf = (struct split_file *)f->f_fsdata;
+ fd = sf->curfd;
+ split_file_destroy(sf);
+ return(close(fd));
+}
+
+static int
+splitfs_read(struct open_file *f, void *buf, size_t size, size_t *resid)
+{
+ int i, nread, totread;
+ struct split_file *sf;
+
+ sf = (struct split_file *)f->f_fsdata;
+ totread = 0;
+ do {
+ nread = read(sf->curfd, buf, size - totread);
+
+ /* Error? */
+ if (nread == -1)
+ return (errno);
+
+ sf->tot_pos += nread;
+ sf->file_pos += nread;
+ totread += nread;
+ buf += nread;
+
+ if (totread < size) { /* EOF */
+ if (sf->curfile == (sf->filesc - 1)) /* Last slice */
+ break;
+
+ /* Close previous slice */
+ if (close(sf->curfd) != 0)
+ return (errno);
+
+ sf->curfile++;
+ for (i = 0;; i++) {
+ sf->curfd = open(sf->filesv[sf->curfile], O_RDONLY);
+ if (sf->curfd >= 0)
+ break;
+ if ((sf->curfd == -1) && (errno != ENOENT))
+ return (errno);
+ if (i == NTRIES)
+ return (EIO);
+ printf("\nInsert disk labelled %s and press any key...", sf->descsv[sf->curfile]);
+ getchar();putchar('\n');
+ }
+ sf->file_pos = 0;
+ }
+ } while (totread < size);
+
+ if (resid != NULL)
+ *resid = size - totread;
+
+ return (0);
+}
+
+static off_t
+splitfs_seek(struct open_file *f, off_t offset, int where)
+{
+ int nread;
+ size_t resid;
+ off_t new_pos, seek_by;
+ struct split_file *sf;
+
+ sf = (struct split_file *)f->f_fsdata;
+
+ seek_by = offset;
+ switch (where) {
+ case SEEK_SET:
+ seek_by -= sf->tot_pos;
+ break;
+ case SEEK_CUR:
+ break;
+ case SEEK_END:
+ panic("splitfs_seek: SEEK_END not supported");
+ break;
+ }
+
+ if (seek_by > 0) {
+ /*
+ * Seek forward - implemented using splitfs_read(), because otherwise we'll be
+ * unable to detect that we have crossed slice boundary and hence
+ * unable to do a long seek crossing that boundary.
+ */
+ void *tmp;
+
+ tmp = malloc(SEEK_BUF);
+ if (tmp == NULL)
+ return (-1);
+
+ nread = 0;
+ for (; seek_by > 0; seek_by -= nread) {
+ resid = 0;
+ errno = splitfs_read(f, tmp, min(seek_by, SEEK_BUF), &resid);
+ nread = min(seek_by, SEEK_BUF) - resid;
+ if ((errno != 0) || (nread == 0))
+ /* Error or EOF */
+ break;
+ }
+ free(tmp);
+ if (errno != 0)
+ return (-1);
+ }
+
+ if (seek_by != 0) {
+ /* Seek backward or seek past the boundary of the last slice */
+ if (sf->file_pos + seek_by < 0)
+ panic("splitfs_seek: can't seek past the beginning of the slice");
+ new_pos = lseek(sf->curfd, seek_by, SEEK_CUR);
+ if (new_pos < 0)
+ return (-1);
+ sf->tot_pos += new_pos - sf->file_pos;
+ sf->file_pos = new_pos;
+ }
+
+ return (sf->tot_pos);
+}
+
+static int
+splitfs_stat(struct open_file *f, struct stat *sb)
+{
+ int result;
+ struct split_file *sf = (struct split_file *)f->f_fsdata;
+
+ /* stat as normal, but indicate that size is unknown */
+ if ((result = fstat(sf->curfd, sb)) == 0)
+ sb->st_size = -1;
+ return (result);
+}
diff --git a/lib/libstand/stand.h b/lib/libstand/stand.h
index fcbb2e8..c4b1fae 100644
--- a/lib/libstand/stand.h
+++ b/lib/libstand/stand.h
@@ -125,6 +125,7 @@ extern struct fs_ops zipfs_fsops;
extern struct fs_ops bzipfs_fsops;
extern struct fs_ops dosfs_fsops;
extern struct fs_ops ext2fs_fsops;
+extern struct fs_ops splitfs_fsops;
/* where values for lseek(2) */
#define SEEK_SET 0 /* set file offset to offset */
diff --git a/lib/libstand/zipfs.c b/lib/libstand/zipfs.c
index 59034ff..00c8f8f 100644
--- a/lib/libstand/zipfs.c
+++ b/lib/libstand/zipfs.c
@@ -175,7 +175,7 @@ zf_open(const char *fname, struct open_file *f)
/* If the name already ends in .gz or .bz2, ignore it */
if ((cp = strrchr(fname, '.')) && (!strcmp(cp, ".gz")
- || !strcmp(cp, ".bz2")))
+ || !strcmp(cp, ".bz2") || !strcmp(cp, ".split")))
return(ENOENT);
/* Construct new name */
OpenPOWER on IntegriCloud