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 <tsut...@ceres.dti.ne.jp> 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; }