tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: Second stage bootloader (i386) hangs on ls command for ext2
Hello,
Here is a fix for the issue. Independent on what fs partition
contains, ufs_ls() was called. Because of ext2 and ufs similarity it
worked successfully in some cases.
netbsd_boot2_ls_fix.diff
Fix ls command used in second stage bootloader.
Currently only ufs_ls is supported. But if ls is called on ext2
partition, it hangs bootloader, because ufs_ls() is called.
ls command should always call fs-dependent XXX_ls().
netbsd_boot2_ext2_ls
Add ls support to libsa/ext2fs (used by boot2).
Could someone please review and commit it?
On Thu, Dec 8, 2011 at 7:35 PM, Izumi Tsutsui
<tsutsui%ceres.dti.ne.jp@localhost> wrote:
>> If my ext2 partition is hd2e then when I do
>> dev hd2e:
>> ls
>> Boot loader hangs.
>>
>> >From man page it's not clear if it should support ext2 (as any other
>> FS, because there are dosboot, cdboot, etc), but there is some code
>> and SUPPORT_EXT2FS for boot2.
>
> The bootloader can load files from ext2fs, but
> currently ls command supports only ufs.
> /boot calls src/sys/lib/libsa/ufs_ls.c for ls command:
> http://nxr.NetBSD.org/xref/src/sys/arch/i386/stand/boot/boot2.c#406
>
>> But it shouldn't hang anyway.
>
> Yes, please file a PR.
>
> ---
> Izumi Tsutsui
--
Evgeniy Ivanov
diff --git a/sys/arch/i386/stand/boot/boot2.c b/sys/arch/i386/stand/boot/boot2.c
index 587990e..dc50808 100644
--- a/sys/arch/i386/stand/boot/boot2.c
+++ b/sys/arch/i386/stand/boot/boot2.c
@@ -409,7 +409,7 @@ command_ls(char *arg)
const char *save = default_filename;
default_filename = "/";
- ufs_ls(arg);
+ ls(arg);
default_filename = save;
}
diff --git a/sys/arch/i386/stand/bootxx/Makefile.bootxx
b/sys/arch/i386/stand/bootxx/Makefile.bootxx
index ab80745..fd8508c 100644
--- a/sys/arch/i386/stand/bootxx/Makefile.bootxx
+++ b/sys/arch/i386/stand/bootxx/Makefile.bootxx
@@ -87,7 +87,8 @@ CPPFLAGS+= -DLIBSA_SINGLE_FILESYSTEM=xxfs \
-D"blkdevioctl(x,y,z)=EINVAL" \
-D"blkdevclose(f)=0" \
-D"devopen(f,n,fl)=(*(fl)=(void *)n,0)" \
- -DLIBSA_NO_DISKLABEL_MSGS
+ -DLIBSA_NO_DISKLABEL_MSGS \
+ -DLIBSA_NO_LS_OP
# -DLIBSA_FS_SINGLECOMPONENT
diff --git a/sys/arch/i386/stand/dosboot/main.c
b/sys/arch/i386/stand/dosboot/main.c
index 87054b0..9aa3d2a 100644
--- a/sys/arch/i386/stand/dosboot/main.c
+++ b/sys/arch/i386/stand/dosboot/main.c
@@ -328,7 +328,7 @@ command_ls(char *arg)
return;
}
default_filename = "/";
- ufs_ls(arg);
+ ls(arg);
default_filename = help;
}
diff --git a/sys/arch/i386/stand/libsa/nfs.c b/sys/arch/i386/stand/libsa/nfs.c
index 18d1bd1..03244d6 100644
--- a/sys/arch/i386/stand/libsa/nfs.c
+++ b/sys/arch/i386/stand/libsa/nfs.c
@@ -630,3 +630,12 @@ nfs_stat(struct open_file *f, struct stat *sb)
return (0);
}
+
+__compactcall void
+nfs_ls(struct open_file *f, const char *pattern)
+{
+#if !defined(LIBSA_NO_LS_OP)
+ printf("Currently ls command is unsupported by nfs\n");
+#endif
+ return;
+}
diff --git a/sys/lib/libsa/Makefile b/sys/lib/libsa/Makefile
index da59909..557887f 100644
--- a/sys/lib/libsa/Makefile
+++ b/sys/lib/libsa/Makefile
@@ -40,7 +40,7 @@ SRCS+= bcopy.c bzero.c # Remove me eventually.
# io routines
SRCS+= closeall.c dev.c disklabel.c dkcksum.c ioctl.c nullfs.c stat.c fstat.c
-SRCS+= close.c lseek.c open.c read.c write.c
+SRCS+= close.c ls.c lseek.c open.c read.c write.c
.if (${SA_USE_CREAD} == "yes")
CPPFLAGS+= -D__INTERNAL_LIBSA_CREAD
SRCS+= cread.c
@@ -65,7 +65,7 @@ SRCS+= bootp.c rarp.c bootparam.c
SRCS+= nfs.c tftp.c
.endif
-SRCS+= ffsv1.c ffsv2.c ufs_ls.c
+SRCS+= ffsv1.c ffsv2.c
SRCS+= lfsv1.c lfsv2.c
SRCS+= cd9660.c
SRCS+= ustarfs.c
diff --git a/sys/lib/libsa/cd9660.c b/sys/lib/libsa/cd9660.c
index 4ebb91a..aab3411 100644
--- a/sys/lib/libsa/cd9660.c
+++ b/sys/lib/libsa/cd9660.c
@@ -396,3 +396,12 @@ cd9660_stat(struct open_file *f, struct stat *sb)
sb->st_size = fp->size;
return 0;
}
+
+__compactcall void
+cd9660_ls(struct open_file *f, const char *pattern)
+{
+#if !defined(LIBSA_NO_LS_OP)
+ printf("Currently ls command is unsupported by cd9660\n");
+#endif
+ return;
+}
diff --git a/sys/lib/libsa/dosfs.c b/sys/lib/libsa/dosfs.c
index 2dab9be..86b4635 100644
--- a/sys/lib/libsa/dosfs.c
+++ b/sys/lib/libsa/dosfs.c
@@ -405,6 +405,15 @@ dosfs_stat(struct open_file *fd, struct stat *sb)
return 0;
}
+__compactcall void
+dosfs_ls(struct open_file *f, const char *pattern)
+{
+#if !defined(LIBSA_NO_LS_OP)
+ printf("Currently ls command is unsupported by dosfs\n");
+#endif
+ return;
+}
+
/*
* Parse DOS boot sector
*/
diff --git a/sys/lib/libsa/ext2fs.c b/sys/lib/libsa/ext2fs.c
index 3f08190..1e06f31 100644
--- a/sys/lib/libsa/ext2fs.c
+++ b/sys/lib/libsa/ext2fs.c
@@ -146,6 +146,59 @@ struct file {
daddr_t f_buf_blkno; /* block number of data block */
};
+#if !defined(LIBSA_NO_LS_OP)
+
+#define NELEM(x) (sizeof (x) / sizeof(*x))
+
+typedef struct entry_t entry_t;
+struct entry_t {
+ entry_t *e_next;
+ ino32_t e_ino;
+ uint8_t e_type;
+ char e_name[1];
+};
+
+static const char *const typestr[] = {
+ "unknown",
+ "REG",
+ "DIR",
+ "CHR",
+ "BLK",
+ "FIFO",
+ "SOCK",
+ "LNK"
+};
+
+static int
+fn_match(const char *fname, const char *pattern)
+{
+ char fc, pc;
+
+ do {
+ fc = *fname++;
+ pc = *pattern++;
+ if (!fc && !pc)
+ return 1;
+ if (pc == '?' && fc)
+ pc = fc;
+ } while (fc == pc);
+
+ if (pc != '*')
+ return 0;
+ /*
+ * Too hard (and unnecessary really) too check for "*?name" etc....
+ * "**" will look for a '*' and "*?" a '?'
+ */
+ pc = *pattern++;
+ if (!pc)
+ return 1;
+ while ((fname = strchr(fname, pc)))
+ if (fn_match(++fname, pattern))
+ return 1;
+ return 0;
+}
+#endif /* LIBSA_NO_LS_OP */
+
static int read_inode(ino32_t, struct open_file *);
static int block_map(struct open_file *, indp_t, indp_t *);
static int buf_read_file(struct open_file *, char **, size_t *);
@@ -803,6 +856,97 @@ ext2fs_stat(struct open_file *f, struct stat *sb)
return 0;
}
+__compactcall void
+ext2fs_ls(struct open_file *f, const char *pattern)
+{
+#if !defined(LIBSA_NO_LS_OP)
+ struct file *fp = (struct file *)f->f_fsdata;
+ size_t block_size = fp->f_fs->e2fs_bsize;
+ char *buf;
+ size_t buf_size;
+ entry_t *names = 0, *n, **np;
+
+ fp->f_seekp = 0;
+ while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
+ struct ext2fs_direct *dp, *edp;
+ int rc = buf_read_file(f, &buf, &buf_size);
+ if (rc)
+ goto out;
+ if (buf_size != block_size || buf_size == 0)
+ goto out;
+
+ dp = (struct ext2fs_direct *)buf;
+ edp = (struct ext2fs_direct *)(buf + buf_size);
+
+ for (; dp < edp;
+ dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
+ const char *t;
+
+ if (fs2h16(dp->e2d_reclen) <= 0)
+ goto out;
+
+ if (fs2h32(dp->e2d_ino) == 0)
+ continue;
+
+ if (dp->e2d_type >= NELEM(typestr) ||
+ !(t = typestr[dp->e2d_type])) {
+ /*
+ * This does not handle "old"
+ * filesystems properly. On little
+ * endian machines, we get a bogus
+ * type name if the namlen matches a
+ * valid type identifier. We could
+ * check if we read namlen "0" and
+ * handle this case specially, if
+ * there were a pressing need...
+ */
+ printf("bad dir entry\n");
+ goto out;
+ }
+ if (pattern && !fn_match(dp->e2d_name, pattern))
+ continue;
+ n = alloc(sizeof *n + strlen(dp->e2d_name));
+ if (!n) {
+ printf("%d: %s (%s)\n",
+ fs2h32(dp->e2d_ino), dp->e2d_name, t);
+ continue;
+ }
+ n->e_ino = fs2h32(dp->e2d_ino);
+ n->e_type = dp->e2d_type;
+ strcpy(n->e_name, dp->e2d_name);
+ for (np = &names; *np; np = &(*np)->e_next) {
+ if (strcmp(n->e_name, (*np)->e_name) < 0)
+ break;
+ }
+ n->e_next = *np;
+ *np = n;
+ }
+ fp->f_seekp += buf_size;
+ }
+
+ if (names) {
+ entry_t *p_names = names;
+ do {
+ n = p_names;
+ printf("%d: %s (%s)\n",
+ n->e_ino, n->e_name, typestr[n->e_type]);
+ p_names = n->e_next;
+ } while (p_names);
+ } else {
+ printf("not found\n");
+ }
+out:
+ if (names) {
+ do {
+ n = names;
+ names = n->e_next;
+ dealloc(n, 0);
+ } while (names);
+ }
+#endif
+ return;
+}
+
/*
* byte swap functions for big endian machines
* (ext2fs is always little endian)
diff --git a/sys/lib/libsa/ffsv1.c b/sys/lib/libsa/ffsv1.c
index 182c997..ea4300f 100644
--- a/sys/lib/libsa/ffsv1.c
+++ b/sys/lib/libsa/ffsv1.c
@@ -8,6 +8,7 @@
#define ufs_write ffsv1_write
#define ufs_seek ffsv1_seek
#define ufs_stat ffsv1_stat
+#define ufs_ls ffsv1_ls
#define ufs_dinode ufs1_dinode
#define indp_t int32_t
diff --git a/sys/lib/libsa/ffsv2.c b/sys/lib/libsa/ffsv2.c
index 2f712f5..589ecf3 100644
--- a/sys/lib/libsa/ffsv2.c
+++ b/sys/lib/libsa/ffsv2.c
@@ -8,6 +8,7 @@
#define ufs_write ffsv2_write
#define ufs_seek ffsv2_seek
#define ufs_stat ffsv2_stat
+#define ufs_ls ffsv2_ls
#define ufs_dinode ufs2_dinode
#define indp_t int64_t
diff --git a/sys/lib/libsa/lfsv1.c b/sys/lib/libsa/lfsv1.c
index 69ed855..e6f811e 100644
--- a/sys/lib/libsa/lfsv1.c
+++ b/sys/lib/libsa/lfsv1.c
@@ -9,6 +9,7 @@
#define ufs_write lfsv1_write
#define ufs_seek lfsv1_seek
#define ufs_stat lfsv1_stat
+#define ufs_ls lfsv1_ls
#define fs_bsize lfs_ibsize
#define IFILE_Vx IFILE_V1
diff --git a/sys/lib/libsa/lfsv2.c b/sys/lib/libsa/lfsv2.c
index fe28990..dfbbd0b 100644
--- a/sys/lib/libsa/lfsv2.c
+++ b/sys/lib/libsa/lfsv2.c
@@ -9,6 +9,7 @@
#define ufs_write lfsv2_write
#define ufs_seek lfsv2_seek
#define ufs_stat lfsv2_stat
+#define ufs_ls lfsv2_ls
#define fs_bsize lfs_bsize
#define IFILE_Vx IFILE
diff --git a/sys/lib/libsa/ls.c b/sys/lib/libsa/ls.c
new file mode 100644
index 0000000..542848f
--- /dev/null
+++ b/sys/lib/libsa/ls.c
@@ -0,0 +1,157 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2011
+ * The NetBSD Foundation, Inc. All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Martin Husemann.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * Copyright (c) 1993
+ * The Regents of the University of California. 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.
+ * 3. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ */
+
+/*
+ * Copyright (c) 1996
+ * Matthias Drochner. 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 ``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 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 "stand.h"
+#include <sys/stat.h>
+#include <lib/libkern/libkern.h>
+
+void
+ls(const char *path)
+{
+ int fd;
+ struct stat sb;
+ size_t size;
+ const char *fname = 0;
+ char *p;
+ struct open_file *f;
+
+ if ((fd = open(path, 0)) < 0
+ || fstat(fd, &sb) < 0
+ || (sb.st_mode & S_IFMT) != S_IFDIR) {
+ /* Path supplied isn't a directory, open parent
+ directory and list matching files. */
+ if (fd >= 0)
+ close(fd);
+ fname = strrchr(path, '/');
+ if (fname) {
+ size = fname - path;
+ p = alloc(size + 1);
+ if (!p)
+ goto out;
+ memcpy(p, path, size);
+ p[size] = 0;
+ fd = open(p, 0);
+ dealloc(p, size + 1);
+ } else {
+ fd = open("", 0);
+ fname = path;
+ }
+
+ if (fd < 0) {
+ printf("ls: %s\n", strerror(errno));
+ return;
+ }
+ if (fstat(fd, &sb) < 0) {
+ printf("stat: %s\n", strerror(errno));
+ goto out;
+ }
+ if ((sb.st_mode & S_IFMT) != S_IFDIR) {
+ printf("%s: %s\n", path, strerror(ENOTDIR));
+ goto out;
+ }
+ }
+
+ f = &files[fd];
+
+#if !defined(LIBSA_NO_FD_CHECKING)
+ if ((unsigned int)fd >= SOPEN_MAX || f->f_flags == 0) {
+ errno = EBADF;
+ goto out;
+ }
+#endif
+
+#if !defined(LIBSA_NO_RAW_ACCESS)
+ /* operation not defined on raw devices */
+ if (f->f_flags & F_RAW) {
+ errno = EOPNOTSUPP;
+ goto out;
+ }
+#endif
+
+ FS_LS(f->f_ops)(f, fname);
+
+out:
+ close(fd);
+}
diff --git a/sys/lib/libsa/nfs.c b/sys/lib/libsa/nfs.c
index a3935ff..7964bfd 100644
--- a/sys/lib/libsa/nfs.c
+++ b/sys/lib/libsa/nfs.c
@@ -655,3 +655,12 @@ nfs_stat(struct open_file *f, struct stat *sb)
return 0;
}
+
+__compactcall void
+nfs_ls(struct open_file *f, const char *pattern)
+{
+#if !defined(LIBSA_NO_LS_OP)
+ printf("Currently ls command is unsupported by nfs\n");
+#endif
+ return;
+}
diff --git a/sys/lib/libsa/nullfs.c b/sys/lib/libsa/nullfs.c
index bc23260..c29a79f 100644
--- a/sys/lib/libsa/nullfs.c
+++ b/sys/lib/libsa/nullfs.c
@@ -113,3 +113,12 @@ null_stat(struct open_file *f, struct stat *sb)
return EIO;
}
+
+__compactcall void
+null_ls(struct open_file *f, const char *pattern)
+{
+#if !defined(LIBSA_NO_LS_OP)
+ printf("Currently ls command is unsupported by nullfs\n");
+#endif
+ return;
+}
diff --git a/sys/lib/libsa/stand.h b/sys/lib/libsa/stand.h
index f1af4ce..7d218c6 100644
--- a/sys/lib/libsa/stand.h
+++ b/sys/lib/libsa/stand.h
@@ -95,7 +95,8 @@ struct open_file;
extern __compactcall int __CONCAT(fs,_write)(struct open_file *,
void *, \
size_t, size_t *); \
extern __compactcall off_t __CONCAT(fs,_seek)(struct open_file *,
off_t, int); \
- extern __compactcall int __CONCAT(fs,_stat)(struct open_file *,
struct stat *)
+ extern __compactcall int __CONCAT(fs,_stat)(struct open_file *,
struct stat *); \
+ extern __compactcall void __CONCAT(fs,_ls)(struct open_file *,
const char *);
/*
* This structure is used to define file system operations in a file system
@@ -112,6 +113,7 @@ struct fs_ops {
__compactcall int (*write)(struct open_file *, void *, size_t
size, size_t *);
__compactcall off_t (*seek)(struct open_file *, off_t, int);
__compactcall int (*stat)(struct open_file *, struct stat *);
+ __compactcall void (*ls)(struct open_file *, const char *);
};
extern struct fs_ops file_system[];
@@ -123,7 +125,8 @@ extern int nfsys;
__CONCAT(fs,_read), \
__CONCAT(fs,_write), \
__CONCAT(fs,_seek), \
- __CONCAT(fs,_stat) }
+ __CONCAT(fs,_stat), \
+ __CONCAT(fs,_ls) }
#define FS_OPEN(fs) ((fs)->open)
#define FS_CLOSE(fs) ((fs)->close)
@@ -131,6 +134,7 @@ extern int nfsys;
#define FS_WRITE(fs) ((fs)->write)
#define FS_SEEK(fs) ((fs)->seek)
#define FS_STAT(fs) ((fs)->stat)
+#define FS_LS(fs) ((fs)->ls)
#else
@@ -140,6 +144,7 @@ extern int nfsys;
#define FS_WRITE(fs)
___CONCAT(LIBSA_SINGLE_FILESYSTEM,_write)
#define FS_SEEK(fs) ___CONCAT(LIBSA_SINGLE_FILESYSTEM,_seek)
#define FS_STAT(fs) ___CONCAT(LIBSA_SINGLE_FILESYSTEM,_stat)
+#define FS_LS(fs) ___CONCAT(LIBSA_SINGLE_FILESYSTEM,_ls)
FS_DEF(LIBSA_SINGLE_FILESYSTEM);
@@ -256,6 +261,7 @@ off_t lseek(int, off_t, int);
int ioctl(int, u_long, char *);
int stat(const char *, struct stat *);
int fstat(int, struct stat *);
+void ls(const char *);
typedef int cmp_t(const void *, const void *);
void qsort(void *, size_t, size_t, cmp_t *);
diff --git a/sys/lib/libsa/tftp.c b/sys/lib/libsa/tftp.c
index 17bad29..7902647 100644
--- a/sys/lib/libsa/tftp.c
+++ b/sys/lib/libsa/tftp.c
@@ -429,6 +429,15 @@ tftp_stat(struct open_file *f, struct stat *sb)
return 0;
}
+__compactcall void
+tftp_ls(struct open_file *f, const char *pattern)
+{
+#if !defined(LIBSA_NO_LS_OP)
+ printf("Currently ls command is unsupported by tftp\n");
+#endif
+ return;
+}
+
__compactcall off_t
tftp_seek(struct open_file *f, off_t offset, int where)
{
diff --git a/sys/lib/libsa/ufs.c b/sys/lib/libsa/ufs.c
index 473100d..22c1493 100644
--- a/sys/lib/libsa/ufs.c
+++ b/sys/lib/libsa/ufs.c
@@ -179,6 +179,66 @@ static void ffs_oldfscompat(struct fs *);
static int ffs_find_superblock(struct open_file *, struct fs *);
#endif
+#if !defined(LIBSA_NO_LS_OP)
+
+#define NELEM(x) (sizeof (x) / sizeof(*x))
+
+typedef struct entry_t entry_t;
+struct entry_t {
+ entry_t *e_next;
+ ino32_t e_ino;
+ uint8_t e_type;
+ char e_name[1];
+};
+
+static const char *const typestr[] = {
+ "unknown",
+ "FIFO",
+ "CHR",
+ 0,
+ "DIR",
+ 0,
+ "BLK",
+ 0,
+ "REG",
+ 0,
+ "LNK",
+ 0,
+ "SOCK",
+ 0,
+ "WHT"
+};
+
+static int
+fn_match(const char *fname, const char *pattern)
+{
+ char fc, pc;
+
+ do {
+ fc = *fname++;
+ pc = *pattern++;
+ if (!fc && !pc)
+ return 1;
+ if (pc == '?' && fc)
+ pc = fc;
+ } while (fc == pc);
+
+ if (pc != '*')
+ return 0;
+ /*
+ * Too hard (and unnecessary really) too check for "*?name" etc....
+ * "**" will look for a '*' and "*?" a '?'
+ */
+ pc = *pattern++;
+ if (!pc)
+ return 1;
+ while ((fname = strchr(fname, pc)))
+ if (fn_match(++fname, pattern))
+ return 1;
+ return 0;
+}
+#endif /* LIBSA_NO_LS_OP */
+
#ifdef LIBSA_LFS
/*
* Find an inode's block. Look it up in the ifile. Whee!
@@ -852,6 +912,90 @@ ufs_stat(struct open_file *f, struct stat *sb)
return 0;
}
+__compactcall void
+ufs_ls(struct open_file *f, const char *pattern)
+{
+#if !defined(LIBSA_NO_LS_OP)
+ struct file *fp = (struct file *)f->f_fsdata;
+ char *buf;
+ size_t buf_size;
+ entry_t *names = 0, *n, **np;
+
+ fp->f_seekp = 0;
+ while (fp->f_seekp < (off_t)fp->f_di.di_size) {
+ struct direct *dp, *edp;
+ int rc = buf_read_file(f, &buf, &buf_size);
+ if (rc)
+ goto out;
+ if (buf_size != DIRBLKSIZ || buf_size == 0)
+ goto out;
+
+ dp = (struct direct *)buf;
+ edp = (struct direct *)(buf + buf_size);
+
+ for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
+ const char *t;
+ if (dp->d_ino == 0)
+ continue;
+
+ if (dp->d_type >= NELEM(typestr) ||
+ !(t = typestr[dp->d_type])) {
+ /*
+ * This does not handle "old"
+ * filesystems properly. On little
+ * endian machines, we get a bogus
+ * type name if the namlen matches a
+ * valid type identifier. We could
+ * check if we read namlen "0" and
+ * handle this case specially, if
+ * there were a pressing need...
+ */
+ printf("bad dir entry\n");
+ goto out;
+ }
+ if (pattern && !fn_match(dp->d_name, pattern))
+ continue;
+ n = alloc(sizeof *n + strlen(dp->d_name));
+ if (!n) {
+ printf("%d: %s (%s)\n",
+ dp->d_ino, dp->d_name, t);
+ continue;
+ }
+ n->e_ino = dp->d_ino;
+ n->e_type = dp->d_type;
+ strcpy(n->e_name, dp->d_name);
+ for (np = &names; *np; np = &(*np)->e_next) {
+ if (strcmp(n->e_name, (*np)->e_name) < 0)
+ break;
+ }
+ n->e_next = *np;
+ *np = n;
+ }
+ fp->f_seekp += buf_size;
+ }
+
+ if (names) {
+ entry_t *p_names = names;
+ do {
+ n = p_names;
+ printf("%d: %s (%s)\n",
+ n->e_ino, n->e_name, typestr[n->e_type]);
+ p_names = n->e_next;
+ } while (p_names);
+ } else {
+ printf("not found\n");
+ }
+out:
+ if (names) {
+ do {
+ n = names;
+ names = n->e_next;
+ dealloc(n, 0);
+ } while (names);
+ }
+#endif /* LIBSA_NO_LS_OP */
+}
+
#ifdef LIBSA_FFSv1
/*
* Sanity checks for old file systems.
diff --git a/sys/lib/libsa/ufs.h b/sys/lib/libsa/ufs.h
index aa458bf..4340f08 100644
--- a/sys/lib/libsa/ufs.h
+++ b/sys/lib/libsa/ufs.h
@@ -34,5 +34,3 @@
FS_DEF(ufs);
FS_DEF(ffsv1);
FS_DEF(ffsv2);
-
-void ufs_ls(const char *);
diff --git a/sys/lib/libsa/ufs_ls.c b/sys/lib/libsa/ufs_ls.c
deleted file mode 100644
index 55e5b78..0000000
--- a/sys/lib/libsa/ufs_ls.c
+++ /dev/null
@@ -1,231 +0,0 @@
-/* $NetBSD: ufs_ls.c,v 1.14 2007/11/24 13:20:58 isaki Exp $ */
-
-/*
- * Copyright (c) 1993
- * The Regents of the University of California. 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.
- * 3. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- */
-
-/*
- * Copyright (c) 1996
- * Matthias Drochner. 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 ``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 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/param.h>
-#include <lib/libkern/libkern.h>
-#include <ufs/ufs/dinode.h>
-#include <ufs/ufs/dir.h>
-
-#include "stand.h"
-#include "ufs.h"
-
-#define NELEM(x) (sizeof (x) / sizeof(*x))
-
-
-typedef uint32_t ino32_t;
-typedef struct entry_t entry_t;
-struct entry_t {
- entry_t *e_next;
- ino32_t e_ino;
- uint8_t e_type;
- char e_name[1];
-};
-
-static const char *const typestr[] = {
- "unknown",
- "FIFO",
- "CHR",
- 0,
- "DIR",
- 0,
- "BLK",
- 0,
- "REG",
- 0,
- "LNK",
- 0,
- "SOCK",
- 0,
- "WHT"
-};
-
-static int
-fn_match(const char *fname, const char *pattern)
-{
- char fc, pc;
-
- do {
- fc = *fname++;
- pc = *pattern++;
- if (!fc && !pc)
- return 1;
- if (pc == '?' && fc)
- pc = fc;
- } while (fc == pc);
-
- if (pc != '*')
- return 0;
- /*
- * Too hard (and unnecessary really) too check for "*?name" etc....
- * "**" will look for a '*' and "*?" a '?'
- */
- pc = *pattern++;
- if (!pc)
- return 1;
- while ((fname = strchr(fname, pc)))
- if (fn_match(++fname, pattern))
- return 1;
- return 0;
-}
-
-void
-ufs_ls(const char *path)
-{
- int fd;
- struct stat sb;
- size_t size;
- char dirbuf[DIRBLKSIZ];
- const char *fname = 0;
- char *p;
- entry_t *names = 0, *n, **np;
-
- if ((fd = open(path, 0)) < 0
- || fstat(fd, &sb) < 0
- || (sb.st_mode & IFMT) != IFDIR) {
- /* Path supplied isn't a directory, open parent
- directory and list matching files. */
- if (fd >= 0)
- close(fd);
- fname = strrchr(path, '/');
- if (fname) {
- size = fname - path;
- p = alloc(size + 1);
- if (!p)
- goto out;
- memcpy(p, path, size);
- p[size] = 0;
- fd = open(p, 0);
- dealloc(p, size + 1);
- } else {
- fd = open("", 0);
- fname = path;
- }
-
- if (fd < 0) {
- printf("ls: %s\n", strerror(errno));
- return;
- }
- if (fstat(fd, &sb) < 0) {
- printf("stat: %s\n", strerror(errno));
- goto out;
- }
- if ((sb.st_mode & IFMT) != IFDIR) {
- printf("%s: %s\n", path, strerror(ENOTDIR));
- goto out;
- }
- }
-
- while ((size = read(fd, dirbuf, DIRBLKSIZ)) == DIRBLKSIZ) {
- struct direct *dp, *edp;
-
- dp = (struct direct *)dirbuf;
- edp = (struct direct *)(dirbuf + size);
-
- for (; dp < edp; dp = (void *)((char *)dp + dp->d_reclen)) {
- const char *t;
- if (dp->d_ino == 0)
- continue;
-
- if (dp->d_type >= NELEM(typestr) ||
- !(t = typestr[dp->d_type])) {
- /*
- * This does not handle "old"
- * filesystems properly. On little
- * endian machines, we get a bogus
- * type name if the namlen matches a
- * valid type identifier. We could
- * check if we read namlen "0" and
- * handle this case specially, if
- * there were a pressing need...
- */
- printf("bad dir entry\n");
- goto out;
- }
- if (fname && !fn_match(dp->d_name, fname))
- continue;
- n = alloc(sizeof *n + strlen(dp->d_name));
- if (!n) {
- printf("%d: %s (%s)\n",
- dp->d_ino, dp->d_name, t);
- continue;
- }
- n->e_ino = dp->d_ino;
- n->e_type = dp->d_type;
- strcpy(n->e_name, dp->d_name);
- for (np = &names; *np; np = &(*np)->e_next) {
- if (strcmp(n->e_name, (*np)->e_name) < 0)
- break;
- }
- n->e_next = *np;
- *np = n;
- }
- }
-
- if (names) {
- do {
- n = names;
- printf("%d: %s (%s)\n",
- n->e_ino, n->e_name, typestr[n->e_type]);
- names = n->e_next;
- dealloc(n, 0);
- } while (names);
- } else {
- printf( "%s not found\n", path );
- }
-out:
- close(fd);
-}
diff --git a/sys/lib/libsa/ustarfs.c b/sys/lib/libsa/ustarfs.c
index cd41bd2..c066ad1 100644
--- a/sys/lib/libsa/ustarfs.c
+++ b/sys/lib/libsa/ustarfs.c
@@ -537,6 +537,16 @@ ustarfs_stat(struct open_file *f, struct stat *sb)
return 0;
}
+
+__compactcall void
+ustarfs_ls(struct open_file *f, const char *pattern)
+{
+#if !defined(LIBSA_NO_LS_OP)
+ printf("Currently ls command is unsupported by ustarfs\n");
+#endif
+ return;
+}
+
#ifndef LIBSA_NO_FS_CLOSE
__compactcall int
ustarfs_close(struct open_file *f)
diff --git a/sys/lib/libsa/ext2fs.c b/sys/lib/libsa/ext2fs.c
index e267d2b..1e06f31 100644
--- a/sys/lib/libsa/ext2fs.c
+++ b/sys/lib/libsa/ext2fs.c
@@ -146,6 +146,59 @@ struct file {
daddr_t f_buf_blkno; /* block number of data block */
};
+#if !defined(LIBSA_NO_LS_OP)
+
+#define NELEM(x) (sizeof (x) / sizeof(*x))
+
+typedef struct entry_t entry_t;
+struct entry_t {
+ entry_t *e_next;
+ ino32_t e_ino;
+ uint8_t e_type;
+ char e_name[1];
+};
+
+static const char *const typestr[] = {
+ "unknown",
+ "REG",
+ "DIR",
+ "CHR",
+ "BLK",
+ "FIFO",
+ "SOCK",
+ "LNK"
+};
+
+static int
+fn_match(const char *fname, const char *pattern)
+{
+ char fc, pc;
+
+ do {
+ fc = *fname++;
+ pc = *pattern++;
+ if (!fc && !pc)
+ return 1;
+ if (pc == '?' && fc)
+ pc = fc;
+ } while (fc == pc);
+
+ if (pc != '*')
+ return 0;
+ /*
+ * Too hard (and unnecessary really) too check for "*?name" etc....
+ * "**" will look for a '*' and "*?" a '?'
+ */
+ pc = *pattern++;
+ if (!pc)
+ return 1;
+ while ((fname = strchr(fname, pc)))
+ if (fn_match(++fname, pattern))
+ return 1;
+ return 0;
+}
+#endif /* LIBSA_NO_LS_OP */
+
static int read_inode(ino32_t, struct open_file *);
static int block_map(struct open_file *, indp_t, indp_t *);
static int buf_read_file(struct open_file *, char **, size_t *);
@@ -807,7 +860,89 @@ __compactcall void
ext2fs_ls(struct open_file *f, const char *pattern)
{
#if !defined(LIBSA_NO_LS_OP)
- printf("Currently ls command is unsupported by ext2fs\n");
+ struct file *fp = (struct file *)f->f_fsdata;
+ size_t block_size = fp->f_fs->e2fs_bsize;
+ char *buf;
+ size_t buf_size;
+ entry_t *names = 0, *n, **np;
+
+ fp->f_seekp = 0;
+ while (fp->f_seekp < (off_t)fp->f_di.e2di_size) {
+ struct ext2fs_direct *dp, *edp;
+ int rc = buf_read_file(f, &buf, &buf_size);
+ if (rc)
+ goto out;
+ if (buf_size != block_size || buf_size == 0)
+ goto out;
+
+ dp = (struct ext2fs_direct *)buf;
+ edp = (struct ext2fs_direct *)(buf + buf_size);
+
+ for (; dp < edp;
+ dp = (void *)((char *)dp + fs2h16(dp->e2d_reclen))) {
+ const char *t;
+
+ if (fs2h16(dp->e2d_reclen) <= 0)
+ goto out;
+
+ if (fs2h32(dp->e2d_ino) == 0)
+ continue;
+
+ if (dp->e2d_type >= NELEM(typestr) ||
+ !(t = typestr[dp->e2d_type])) {
+ /*
+ * This does not handle "old"
+ * filesystems properly. On little
+ * endian machines, we get a bogus
+ * type name if the namlen matches a
+ * valid type identifier. We could
+ * check if we read namlen "0" and
+ * handle this case specially, if
+ * there were a pressing need...
+ */
+ printf("bad dir entry\n");
+ goto out;
+ }
+ if (pattern && !fn_match(dp->e2d_name, pattern))
+ continue;
+ n = alloc(sizeof *n + strlen(dp->e2d_name));
+ if (!n) {
+ printf("%d: %s (%s)\n",
+ fs2h32(dp->e2d_ino), dp->e2d_name, t);
+ continue;
+ }
+ n->e_ino = fs2h32(dp->e2d_ino);
+ n->e_type = dp->e2d_type;
+ strcpy(n->e_name, dp->e2d_name);
+ for (np = &names; *np; np = &(*np)->e_next) {
+ if (strcmp(n->e_name, (*np)->e_name) < 0)
+ break;
+ }
+ n->e_next = *np;
+ *np = n;
+ }
+ fp->f_seekp += buf_size;
+ }
+
+ if (names) {
+ entry_t *p_names = names;
+ do {
+ n = p_names;
+ printf("%d: %s (%s)\n",
+ n->e_ino, n->e_name, typestr[n->e_type]);
+ p_names = n->e_next;
+ } while (p_names);
+ } else {
+ printf("not found\n");
+ }
+out:
+ if (names) {
+ do {
+ n = names;
+ names = n->e_next;
+ dealloc(n, 0);
+ } while (names);
+ }
#endif
return;
}
Home |
Main Index |
Thread Index |
Old Index