]> Zhao Yanbai Git Server - minix.git/commitdiff
Upgrading ls 81/281/3
authorLionel Sambuc <lionel@minix3.org>
Wed, 30 Jan 2013 18:06:57 +0000 (19:06 +0100)
committerLionel Sambuc <lionel@minix3.org>
Sat, 2 Feb 2013 00:20:09 +0000 (01:20 +0100)
Change-Id: Ie0bacf04e727fac5c6df7b2bcf5039e9ce800616

16 files changed:
bin/ls/Makefile [new file with mode: 0644]
bin/ls/cmp.c [new file with mode: 0644]
bin/ls/extern.h [new file with mode: 0644]
bin/ls/ls.1 [new file with mode: 0644]
bin/ls/ls.c [new file with mode: 0644]
bin/ls/ls.h [new file with mode: 0644]
bin/ls/main.c [new file with mode: 0644]
bin/ls/print.c [new file with mode: 0644]
bin/ls/util.c [new file with mode: 0644]
commands/Makefile
commands/ls/Makefile [deleted file]
commands/ls/ls.c [deleted file]
drivers/ramdisk/Makefile
man/man1/Makefile
man/man1/ls.1 [deleted file]
releasetools/nbsd_ports

diff --git a/bin/ls/Makefile b/bin/ls/Makefile
new file mode 100644 (file)
index 0000000..55497f6
--- /dev/null
@@ -0,0 +1,10 @@
+#      $NetBSD: Makefile,v 1.14 2006/12/14 20:09:36 he Exp $
+#      @(#)Makefile    8.1 (Berkeley) 6/2/93
+
+PROG=  ls
+SRCS=  cmp.c ls.c main.c print.c util.c
+
+LDADD+=        -lutil
+DPADD+=        ${LIBUTIL}
+
+.include <bsd.prog.mk>
diff --git a/bin/ls/cmp.c b/bin/ls/cmp.c
new file mode 100644 (file)
index 0000000..21d50e1
--- /dev/null
@@ -0,0 +1,199 @@
+/*     $NetBSD: cmp.c,v 1.17 2003/08/07 09:05:14 agc Exp $     */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)cmp.c      8.1 (Berkeley) 5/31/93";
+#else
+__RCSID("$NetBSD: cmp.c,v 1.17 2003/08/07 09:05:14 agc Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fts.h>
+#include <string.h>
+
+#include "ls.h"
+#include "extern.h"
+
+#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) || \
+    defined(_XOPEN_SOURCE) || defined(__NetBSD__)
+#define ATIMENSEC_CMP(x, op, y) ((x)->st_atimensec op (y)->st_atimensec)
+#define CTIMENSEC_CMP(x, op, y) ((x)->st_ctimensec op (y)->st_ctimensec)
+#define MTIMENSEC_CMP(x, op, y) ((x)->st_mtimensec op (y)->st_mtimensec)
+#else
+#define ATIMENSEC_CMP(x, op, y) \
+       ((x)->st_atimespec.tv_nsec op (y)->st_atimespec.tv_nsec)
+#define CTIMENSEC_CMP(x, op, y) \
+       ((x)->st_ctimespec.tv_nsec op (y)->st_ctimespec.tv_nsec)
+#define MTIMENSEC_CMP(x, op, y) \
+       ((x)->st_mtimespec.tv_nsec op (y)->st_mtimespec.tv_nsec)
+#endif
+
+int
+namecmp(const FTSENT *a, const FTSENT *b)
+{
+
+       return (strcmp(a->fts_name, b->fts_name));
+}
+
+int
+revnamecmp(const FTSENT *a, const FTSENT *b)
+{
+
+       return (strcmp(b->fts_name, a->fts_name));
+}
+
+int
+modcmp(const FTSENT *a, const FTSENT *b)
+{
+
+       if (b->fts_statp->st_mtime > a->fts_statp->st_mtime)
+               return (1);
+       else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime)
+               return (-1);
+       else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+               return (1);
+       else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+               return (-1);
+       else
+               return (namecmp(a, b));
+}
+
+int
+revmodcmp(const FTSENT *a, const FTSENT *b)
+{
+
+       if (b->fts_statp->st_mtime > a->fts_statp->st_mtime)
+               return (-1);
+       else if (b->fts_statp->st_mtime < a->fts_statp->st_mtime)
+               return (1);
+       else if (MTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+               return (-1);
+       else if (MTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+               return (1);
+       else
+               return (revnamecmp(a, b));
+}
+
+int
+acccmp(const FTSENT *a, const FTSENT *b)
+{
+
+       if (b->fts_statp->st_atime > a->fts_statp->st_atime)
+               return (1);
+       else if (b->fts_statp->st_atime < a->fts_statp->st_atime)
+               return (-1);
+       else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+               return (1);
+       else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+               return (-1);
+       else
+               return (namecmp(a, b));
+}
+
+int
+revacccmp(const FTSENT *a, const FTSENT *b)
+{
+
+       if (b->fts_statp->st_atime > a->fts_statp->st_atime)
+               return (-1);
+       else if (b->fts_statp->st_atime < a->fts_statp->st_atime)
+               return (1);
+       else if (ATIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+               return (-1);
+       else if (ATIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+               return (1);
+       else
+               return (revnamecmp(a, b));
+}
+
+int
+statcmp(const FTSENT *a, const FTSENT *b)
+{
+
+       if (b->fts_statp->st_ctime > a->fts_statp->st_ctime)
+               return (1);
+       else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime)
+               return (-1);
+       else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+               return (1);
+       else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+               return (-1);
+       else
+               return (namecmp(a, b));
+}
+
+int
+revstatcmp(const FTSENT *a, const FTSENT *b)
+{
+
+       if (b->fts_statp->st_ctime > a->fts_statp->st_ctime)
+               return (-1);
+       else if (b->fts_statp->st_ctime < a->fts_statp->st_ctime)
+               return (1);
+       else if (CTIMENSEC_CMP(b->fts_statp, >, a->fts_statp))
+               return (-1);
+       else if (CTIMENSEC_CMP(b->fts_statp, <, a->fts_statp))
+               return (1);
+       else
+               return (revnamecmp(a, b));
+}
+
+int
+sizecmp(const FTSENT *a, const FTSENT *b)
+{
+
+       if (b->fts_statp->st_size > a->fts_statp->st_size)
+               return (1);
+       if (b->fts_statp->st_size < a->fts_statp->st_size)
+               return (-1);
+       else
+               return (namecmp(a, b));
+}
+
+int
+revsizecmp(const FTSENT *a, const FTSENT *b)
+{
+
+       if (b->fts_statp->st_size > a->fts_statp->st_size)
+               return (-1);
+       if (b->fts_statp->st_size < a->fts_statp->st_size)
+               return (1);
+       else
+               return (revnamecmp(a, b));
+}
diff --git a/bin/ls/extern.h b/bin/ls/extern.h
new file mode 100644 (file)
index 0000000..0a9eea0
--- /dev/null
@@ -0,0 +1,53 @@
+/*     $NetBSD: extern.h,v 1.17 2011/08/29 14:44:21 joerg Exp $        */
+
+/*-
+ * Copyright (c) 1991, 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.
+ *
+ *     @(#)extern.h    8.1 (Berkeley) 5/31/93
+ */
+
+int     acccmp(const FTSENT *, const FTSENT *);
+int     revacccmp(const FTSENT *, const FTSENT *);
+int     modcmp(const FTSENT *, const FTSENT *);
+int     revmodcmp(const FTSENT *, const FTSENT *);
+int     namecmp(const FTSENT *, const FTSENT *);
+int     revnamecmp(const FTSENT *, const FTSENT *);
+int     statcmp(const FTSENT *, const FTSENT *);
+int     revstatcmp(const FTSENT *, const FTSENT *);
+int     sizecmp(const FTSENT *, const FTSENT *);
+int     revsizecmp(const FTSENT *, const FTSENT *);
+
+int     ls_main(int, char *[]);
+
+int     printescaped(const char *);
+void    printacol(DISPLAY *);
+void    printcol(DISPLAY *);
+void    printlong(DISPLAY *);
+void    printscol(DISPLAY *);
+void    printstream(DISPLAY *);
+int     safe_print(const char *);
diff --git a/bin/ls/ls.1 b/bin/ls/ls.1
new file mode 100644 (file)
index 0000000..1d10b17
--- /dev/null
@@ -0,0 +1,510 @@
+.\"    $NetBSD: ls.1,v 1.69 2011/04/02 08:38:56 mbalmer Exp $
+.\"
+.\" Copyright (c) 1980, 1990, 1991, 1993, 1994
+.\"    The Regents of the University of California.  All rights reserved.
+.\"
+.\" This code is derived from software contributed to Berkeley by
+.\" the Institute of Electrical and Electronics Engineers, Inc.
+.\"
+.\" 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.
+.\"
+.\"     @(#)ls.1       8.7 (Berkeley) 7/29/94
+.\"
+.Dd April 2, 2011
+.Dt LS 1
+.Os
+.Sh NAME
+.Nm ls
+.Nd list directory contents
+.Sh SYNOPSIS
+.Nm
+.Op Fl AaBbCcdFfghikLlMmnopqRrSsTtuWwx1
+.Op Ar
+.Sh DESCRIPTION
+For each operand that names a
+.Ar file
+of a type other than
+directory,
+.Nm
+displays its name as well as any requested,
+associated information.
+For each operand that names a
+.Ar file
+of type directory,
+.Nm
+displays the names of files contained
+within that directory, as well as any requested, associated
+information.
+.Pp
+If no operands are given, the contents of the current
+directory are displayed.
+If more than one operand is given,
+non-directory operands are displayed first; directory
+and non-directory operands are sorted separately and in
+lexicographical order.
+.Pp
+The following options are available:
+.Bl -tag -width indent
+.It Fl A
+List all entries except for
+.Ql \&.
+and
+.Ql \&.. .
+Always set for the super-user.
+.It Fl a
+Include directory entries whose names begin with a
+dot
+.Pq Sq \&. .
+.It Fl B
+Force printing of non-graphic characters in file names as \exxx, where xxx
+is the numeric value of the character in octal.
+.It Fl b
+As
+.Fl B ,
+but use C escape codes whenever possible.
+.It Fl C
+Force multi-column output; this is the default when output is to a terminal.
+.It Fl c
+Use time when file status was last changed,
+instead of time of last modification of the file for sorting
+.Pq Fl t
+or printing
+.Pq Fl l .
+.It Fl d
+Directories are listed as plain files (not searched recursively) and
+symbolic links in the argument list are not followed.
+.It Fl F
+Display a slash
+.Pq Sq \&/
+immediately after each pathname that is a directory,
+an asterisk
+.Pq Sq \&*
+after each that is executable,
+an at sign
+.Pq Sq \&@
+after each symbolic link,
+a percent sign
+.Pq Sq \&%
+after each whiteout,
+an equal sign
+.Pq Sq \&=
+after each socket,
+and a vertical bar
+.Pq Sq \&|
+after each that is a
+.Tn FIFO .
+.It Fl f
+Output is not sorted.
+.It Fl g
+The same as
+.Fl l ,
+except that the owner is not printed.
+.It Fl h
+Modifies the
+.Fl s
+and
+.Fl l
+options, causing the sizes to be reported in bytes displayed in a human
+readable format.
+Overrides
+.Fl k
+and
+.Fl M .
+.It Fl i
+For each file, print the file's file serial number (inode number).
+.It Fl k
+Modifies the
+.Fl s
+option, causing the sizes to be reported in kilobytes.
+The rightmost of the
+.Fl k
+and
+.Fl h
+flags overrides the previous flag.
+See also
+.Fl h
+and
+.Fl M .
+.It Fl L
+For each file, if it's a link, evaluate file information and file type
+of the referenced file and not the link itself; however still print
+the link name, unless used with
+.Fl l ,
+for example.
+.It Fl l
+(The lowercase letter
+.Dq ell ) .
+List in long format.
+(See below.)
+A total sum for all the file sizes is output on a line before the long
+listing.
+.It Fl M
+Modifies the
+.Fl l
+and
+.Fl s
+options, causing the sizes or block counts reported to be separated with
+commas (or a locale appropriate separator) resulting in a more readable
+output.
+Overrides
+.Fl h .
+Does not override
+.Fl k .
+.It Fl m
+Stream output format; list files across the page, separated by commas.
+.It Fl n
+The same as
+.Fl l ,
+except that
+the owner and group IDs are displayed numerically rather than converting
+to a owner or group name.
+.It Fl o
+Include the file flags in a long
+.Pq Fl l
+output.
+If no file flags are set,
+.Dq -
+is displayed.
+(See
+.Xr chflags 1
+for a list of possible flags and their meanings.)
+.It Fl p
+Display a slash
+.Pq Sq \&/
+immediately after each pathname that is a directory.
+.It Fl q
+Force printing of non-printable characters in file names as
+the character
+.Sq \&? ;
+this is the default when output is to a terminal.
+.It Fl R
+Recursively list subdirectories encountered.
+.It Fl r
+Reverse the order of the sort to get reverse
+lexicographical order or the smallest or oldest entries first.
+.It Fl S
+Sort by size, largest file first.
+.It Fl s
+Display the number of file system blocks actually used by each file, in units
+of 512 bytes or
+.Ev BLOCKSIZE
+(see
+.Sx ENVIRONMENT )
+where partial units are rounded up to the
+next integer value.
+If the output is to a terminal, a total sum for all the file
+sizes is output on a line before the listing.
+.It Fl T
+When used with the
+.Fl l
+(the lowercase letter
+.Dq ell )
+option, display complete time information for the file, including
+month, day, hour, minute, second, and year.
+.It Fl t
+Sort by time modified (most recently modified
+first) before sorting the operands by lexicographical
+order.
+.It Fl u
+Use time of last access,
+instead of last modification
+of the file for sorting
+.Pq Fl t
+or printing
+.Pq Fl l .
+.It Fl W
+Display whiteouts when scanning directories.
+.It Fl w
+Force raw printing of non-printable characters.
+This is the default when output is not to a terminal.
+.It Fl x
+Multi-column output sorted across the page rather than down the page.
+.It Fl \&1
+(The numeric digit
+.Dq one ) .
+Force output to be one entry per line.
+This is the default when output is not to a terminal.
+.El
+.Pp
+The
+.Fl B ,
+.Fl b ,
+.Fl w ,
+and
+.Fl q
+options all override each other; the last one specified determines
+the format used for non-printable characters.
+.Pp
+The
+.Fl 1 ,
+.Fl C ,
+.Fl g ,
+.Fl l ,
+.Fl m ,
+and
+.Fl x
+options all override each other; the last one specified determines
+the format used with the exception that if both
+.Fl l
+and
+.Fl g
+are specified,
+.Fl l
+will always override
+.Fl g ,
+even if
+.Fl g
+was specified last.
+.Pp
+The
+.Fl c
+and
+.Fl u
+options override each other; the last one specified determines
+the file time used.
+.Pp
+By default,
+.Nm
+lists one entry per line to standard
+output; the exceptions are to terminals or when the
+.Fl C
+or
+.Fl m
+options are specified.
+.Pp
+File information is displayed with one or more
+.Aq blank
+separating the information associated with the
+.Fl i ,
+.Fl s ,
+and
+.Fl l
+options.
+.Ss The Long Format
+If the
+.Fl l
+option is given, the following information
+is displayed for each file:
+.Bl -item -offset indent -compact
+.It
+file mode
+.It
+number of links
+.It
+owner name
+.It
+group name
+.It
+file flags (if
+.Fl o
+given)
+.It
+number of bytes in the file
+.It
+abbreviated month file was last modified
+.It
+day-of-month file was last modified
+.It
+hour and minute file was last modified
+.It
+pathname
+.El
+.Pp
+In addition, for each directory whose contents are displayed, the total
+number of 512-byte blocks used by the files in the directory is displayed
+on a line by itself immediately before the information for the files in the
+directory.
+.Pp
+If the owner or group names are not a known owner or group name,
+or the
+.Fl n
+option is given,
+the numeric ID's are displayed.
+.Pp
+If the file is a character special or block special file,
+the major and minor device numbers for the file are displayed
+in the size field.
+If the file is a symbolic link the pathname of the
+linked-to file is preceded by
+.Dq \-\*[Gt] .
+.Pp
+The file mode printed under the
+.Fl l
+option consists of the entry type, owner permissions, group
+permissions, and other permissions.
+The entry type character describes the type of file, as
+follows:
+.Pp
+.Bl -tag -width 4n -offset indent -compact
+.It Sy a
+Archive state 1.
+.It Sy A
+Archive state 2.
+.It Sy b
+Block special file.
+.It Sy c
+Character special file.
+.It Sy d
+Directory.
+.It Sy l
+Symbolic link.
+.It Sy s
+Socket link.
+.It Sy p
+FIFO.
+.It Sy w
+Whiteout.
+.It Sy \-
+Regular file.
+.El
+.Pp
+The next three fields
+are three characters each:
+owner permissions,
+group permissions, and
+other permissions.
+Each field has three character positions:
+.Bl -enum -offset indent
+.It
+If
+.Sy r ,
+the file is readable; if
+.Sy \- ,
+it is not readable.
+.It
+If
+.Sy w ,
+the file is writable; if
+.Sy \- ,
+it is not writable.
+.It
+The first of the following that applies:
+.Bl -tag -width 4n -offset indent
+.It Sy S
+If in the owner permissions, the file is not executable and
+set-user-ID mode is set.
+If in the group permissions, the file is not executable
+and set-group-ID mode is set.
+.It Sy s
+If in the owner permissions, the file is executable
+and set-user-ID mode is set.
+If in the group permissions, the file is executable
+and setgroup-ID mode is set.
+.It Sy x
+The file is executable or the directory is
+searchable.
+.It Sy \-
+The file is neither readable, writable, executable,
+nor set-user-ID nor set-group-ID mode, nor sticky.
+(See below.)
+.El
+.Pp
+These next two apply only to the third character in the last group
+(other permissions).
+.Bl -tag -width 4n -offset indent
+.It Sy T
+The sticky bit is set
+(mode
+.Li 1000 ) ,
+but not execute or search permission.
+(See
+.Xr chmod 1
+or
+.Xr sticky 7 . )
+.It Sy t
+The sticky bit is set (mode
+.Li 1000 ) ,
+and is searchable or executable.
+(See
+.Xr chmod 1
+or
+.Xr sticky 7 . )
+.El
+.El
+.Pp
+The number of bytes displayed for a directory is a function of the
+number of
+.Xr dirent 3
+structures in the directory, not all of which may be allocated to
+any existing file.
+.Sh ENVIRONMENT
+The following environment variables affect the execution of
+.Nm :
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environment variable
+.Ev BLOCKSIZE
+is set, and the
+.Fl h
+and
+.Fl k
+options are not specified, the block counts
+(see
+.Fl s )
+will be displayed in units of that size block.
+.It Ev COLUMNS
+If this variable contains a string representing a
+decimal integer, it is used as the
+column position width for displaying
+multiple-text-column output.
+The
+.Nm
+utility calculates how
+many pathname text columns to display
+based on the width provided.
+(See
+.Fl C . )
+.It Ev TZ
+The timezone to use when displaying dates.
+See
+.Xr environ 7
+for more information.
+.El
+.Sh EXIT STATUS
+.Ex -std
+.Sh COMPATIBILITY
+The group field is now automatically included in the long listing for
+files in order to be compatible with the
+.St -p1003.2
+specification.
+.Sh SEE ALSO
+.Xr chflags 1 ,
+.Xr chmod 1 ,
+.Xr stat 2 ,
+.Xr dirent 3 ,
+.Xr getbsize 3 ,
+.Xr sticky 7 ,
+.Xr symlink 7
+.Sh STANDARDS
+The
+.Nm
+utility is expected to be a superset of the
+.St -p1003.2
+specification.
+.Sh HISTORY
+An
+.Nm
+utility appeared in
+.At v5 .
diff --git a/bin/ls/ls.c b/bin/ls/ls.c
new file mode 100644 (file)
index 0000000..aceaa8d
--- /dev/null
@@ -0,0 +1,701 @@
+/*     $NetBSD: ls.c,v 1.69 2011/08/29 14:44:21 joerg Exp $    */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)ls.c       8.7 (Berkeley) 8/5/94";
+#else
+__RCSID("$NetBSD: ls.c,v 1.69 2011/08/29 14:44:21 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+
+#include <dirent.h>
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <termios.h>
+#include <pwd.h>
+#include <grp.h>
+#include <util.h>
+
+#include "ls.h"
+#include "extern.h"
+
+static void     display(FTSENT *, FTSENT *);
+static int      mastercmp(const FTSENT **, const FTSENT **);
+static void     traverse(int, char **, int);
+
+static void (*printfcn)(DISPLAY *);
+static int (*sortfcn)(const FTSENT *, const FTSENT *);
+
+#define        BY_NAME 0
+#define        BY_SIZE 1
+#define        BY_TIME 2
+
+long blocksize;                        /* block size units */
+int termwidth = 80;            /* default terminal width */
+int sortkey = BY_NAME;
+int rval = EXIT_SUCCESS;       /* exit value - set if error encountered */
+
+/* flags */
+int f_accesstime;              /* use time of last access */
+int f_column;                  /* columnated format */
+int f_columnacross;            /* columnated format, sorted across */
+int f_flags;                   /* show flags associated with a file */
+int f_grouponly;               /* long listing without owner */
+int f_humanize;                        /* humanize the size field */
+int f_commas;           /* separate size field with comma */
+int f_inode;                   /* print inode */
+int f_listdir;                 /* list actual directory, not contents */
+int f_listdot;                 /* list files beginning with . */
+int f_longform;                        /* long listing format */
+int f_nonprint;                        /* show unprintables as ? */
+int f_nosort;                  /* don't sort output */
+int f_numericonly;             /* don't convert uid/gid to name */
+int f_octal;                   /* print octal escapes for nongraphic characters */
+int f_octal_escape;            /* like f_octal but use C escapes if possible */
+int f_recursive;               /* ls subdirectories also */
+int f_reversesort;             /* reverse whatever sort is used */
+int f_sectime;                 /* print the real time for all files */
+int f_singlecol;               /* use single column output */
+int f_size;                    /* list size in short listing */
+int f_statustime;              /* use time of last mode change */
+int f_stream;                  /* stream format */
+int f_type;                    /* add type character for non-regular files */
+int f_typedir;                 /* add type character for directories */
+int f_whiteout;                        /* show whiteout entries */
+
+__dead static void
+usage(void)
+{
+
+       (void)fprintf(stderr,
+           "usage: %s [-AaBbCcdFfghikLlMmnopqRrSsTtuWwx1] [file ...]\n",
+           getprogname());
+       exit(EXIT_FAILURE);
+       /* NOTREACHED */
+}
+
+int
+ls_main(int argc, char *argv[])
+{
+       static char dot[] = ".", *dotav[] = { dot, NULL };
+       struct winsize win;
+       int ch, fts_options;
+       int kflag = 0;
+       const char *p;
+
+       setprogname(argv[0]);
+       (void)setlocale(LC_ALL, "");
+
+       /* Terminal defaults to -Cq, non-terminal defaults to -1. */
+       if (isatty(STDOUT_FILENO)) {
+               if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == 0 &&
+                   win.ws_col > 0)
+                       termwidth = win.ws_col;
+               f_column = f_nonprint = 1;
+       } else
+               f_singlecol = 1;
+
+       /* Root is -A automatically. */
+       if (!getuid())
+               f_listdot = 1;
+
+       fts_options = FTS_PHYSICAL;
+       while ((ch = getopt(argc, argv, "1ABCFLMRSTWabcdfghiklmnopqrstuwx")) != -1) {
+               switch (ch) {
+               /*
+                * The -1, -C, -l, -m and -x options all override each other so
+                * shell aliasing works correctly.
+                */
+               case '1':
+                       f_singlecol = 1;
+                       f_column = f_columnacross = f_longform = f_stream = 0;
+                       break;
+               case 'C':
+                       f_column = 1;
+                       f_columnacross = f_longform = f_singlecol = f_stream =
+                           0;
+                       break;
+               case 'g':
+                       if (f_grouponly != -1)
+                               f_grouponly = 1;
+                       f_longform = 1;
+                       f_column = f_columnacross = f_singlecol = f_stream = 0;
+                       break;
+               case 'l':
+                       f_longform = 1;
+                       f_column = f_columnacross = f_singlecol = f_stream = 0;
+                       /* Never let -g take precedence over -l. */
+                       f_grouponly = -1;
+                       break;
+               case 'm':
+                       f_stream = 1;
+                       f_column = f_columnacross = f_longform = f_singlecol =
+                           0;
+                       break;
+               case 'x':
+                       f_columnacross = 1;
+                       f_column = f_longform = f_singlecol = f_stream = 0;
+                       break;
+               /* The -c and -u options override each other. */
+               case 'c':
+                       f_statustime = 1;
+                       f_accesstime = 0;
+                       break;
+               case 'u':
+                       f_accesstime = 1;
+                       f_statustime = 0;
+                       break;
+               case 'F':
+                       f_type = 1;
+                       break;
+               case 'L':
+                       fts_options &= ~FTS_PHYSICAL;
+                       fts_options |= FTS_LOGICAL;
+                       break;
+               case 'R':
+                       f_recursive = 1;
+                       break;
+               case 'a':
+                       fts_options |= FTS_SEEDOT;
+                       /* FALLTHROUGH */
+               case 'A':
+                       f_listdot = 1;
+                       break;
+               /* The -B option turns off the -b, -q and -w options. */
+               case 'B':
+                       f_nonprint = 0;
+                       f_octal = 1;
+                       f_octal_escape = 0;
+                       break;
+               /* The -b option turns off the -B, -q and -w options. */
+               case 'b':
+                       f_nonprint = 0;
+                       f_octal = 0;
+                       f_octal_escape = 1;
+                       break;
+               /* The -d option turns off the -R option. */
+               case 'd':
+                       f_listdir = 1;
+                       f_recursive = 0;
+                       break;
+               case 'f':
+                       f_nosort = 1;
+                       break;
+               case 'i':
+                       f_inode = 1;
+                       break;
+               case 'k':
+                       blocksize = 1024;
+                       kflag = 1;
+                       f_humanize = 0;
+                       break;
+               /* The -h option forces all sizes to be measured in bytes. */
+               case 'h':
+                       f_humanize = 1;
+                       kflag = 0;
+                       f_commas = 0;
+                       break;
+               case 'M':
+                       f_humanize = 0;
+                       f_commas = 1;
+                       break;
+               case 'n':
+                       f_numericonly = 1;
+                       f_longform = 1;
+                       f_column = f_columnacross = f_singlecol = f_stream = 0;
+                       break;
+               case 'o':
+                       f_flags = 1;
+                       break;
+               case 'p':
+                       f_typedir = 1;
+                       break;
+               /* The -q option turns off the -B, -b and -w options. */
+               case 'q':
+                       f_nonprint = 1;
+                       f_octal = 0;
+                       f_octal_escape = 0;
+                       break;
+               case 'r':
+                       f_reversesort = 1;
+                       break;
+               case 'S':
+                       sortkey = BY_SIZE;
+                       break;
+               case 's':
+                       f_size = 1;
+                       break;
+               case 'T':
+                       f_sectime = 1;
+                       break;
+               case 't':
+                       sortkey = BY_TIME;
+                       break;
+               case 'W':
+                       f_whiteout = 1;
+                       break;
+               /* The -w option turns off the -B, -b and -q options. */
+               case 'w':
+                       f_nonprint = 0;
+                       f_octal = 0;
+                       f_octal_escape = 0;
+                       break;
+               default:
+               case '?':
+                       usage();
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       if (f_column || f_columnacross || f_stream) {
+               if ((p = getenv("COLUMNS")) != NULL)
+                       termwidth = atoi(p);
+       }
+
+       /*
+        * If both -g and -l options, let -l take precedence.
+        */
+       if (f_grouponly == -1)
+               f_grouponly = 0;
+
+       /*
+        * If not -F, -i, -l, -p, -S, -s or -t options, don't require stat
+        * information.
+        */
+       if (!f_inode && !f_longform && !f_size && !f_type && !f_typedir &&
+           sortkey == BY_NAME)
+               fts_options |= FTS_NOSTAT;
+
+       /*
+        * If not -F, -d or -l options, follow any symbolic links listed on
+        * the command line.
+        */
+       if (!f_longform && !f_listdir && !f_type)
+               fts_options |= FTS_COMFOLLOW;
+
+       /*
+        * If -W, show whiteout entries
+        */
+#ifdef FTS_WHITEOUT
+       if (f_whiteout)
+               fts_options |= FTS_WHITEOUT;
+#endif
+
+       /* If -l or -s, figure out block size. */
+       if (f_inode || f_longform || f_size) {
+               if (!kflag)
+                       (void)getbsize(NULL, &blocksize);
+               blocksize /= 512;
+       }
+
+       /* Select a sort function. */
+       if (f_reversesort) {
+               switch (sortkey) {
+               case BY_NAME:
+                       sortfcn = revnamecmp;
+                       break;
+               case BY_SIZE:
+                       sortfcn = revsizecmp;
+                       break;
+               case BY_TIME:
+                       if (f_accesstime)
+                               sortfcn = revacccmp;
+                       else if (f_statustime)
+                               sortfcn = revstatcmp;
+                       else /* Use modification time. */
+                               sortfcn = revmodcmp;
+                       break;
+               }
+       } else {
+               switch (sortkey) {
+               case BY_NAME:
+                       sortfcn = namecmp;
+                       break;
+               case BY_SIZE:
+                       sortfcn = sizecmp;
+                       break;
+               case BY_TIME:
+                       if (f_accesstime)
+                               sortfcn = acccmp;
+                       else if (f_statustime)
+                               sortfcn = statcmp;
+                       else /* Use modification time. */
+                               sortfcn = modcmp;
+                       break;
+               }
+       }
+
+       /* Select a print function. */
+       if (f_singlecol)
+               printfcn = printscol;
+       else if (f_columnacross)
+               printfcn = printacol;
+       else if (f_longform)
+               printfcn = printlong;
+       else if (f_stream)
+               printfcn = printstream;
+       else
+               printfcn = printcol;
+
+       if (argc)
+               traverse(argc, argv, fts_options);
+       else
+               traverse(1, dotav, fts_options);
+       return rval;
+       /* NOTREACHED */
+}
+
+static int output;                     /* If anything output. */
+
+/*
+ * Traverse() walks the logical directory structure specified by the argv list
+ * in the order specified by the mastercmp() comparison function.  During the
+ * traversal it passes linked lists of structures to display() which represent
+ * a superset (may be exact set) of the files to be displayed.
+ */
+static void
+traverse(int argc, char *argv[], int options)
+{
+       FTS *ftsp;
+       FTSENT *p, *chp;
+       int ch_options, error;
+
+       if ((ftsp =
+           fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL)
+               err(EXIT_FAILURE, NULL);
+
+       display(NULL, fts_children(ftsp, 0));
+       if (f_listdir) {
+               (void)fts_close(ftsp);
+               return;
+       }
+
+       /*
+        * If not recursing down this tree and don't need stat info, just get
+        * the names.
+        */
+       ch_options = !f_recursive && options & FTS_NOSTAT ? FTS_NAMEONLY : 0;
+
+       while ((p = fts_read(ftsp)) != NULL)
+               switch (p->fts_info) {
+               case FTS_DC:
+                       warnx("%s: directory causes a cycle", p->fts_name);
+                       break;
+               case FTS_DNR:
+               case FTS_ERR:
+                       warnx("%s: %s", p->fts_name, strerror(p->fts_errno));
+                       rval = EXIT_FAILURE;
+                       break;
+               case FTS_D:
+                       if (p->fts_level != FTS_ROOTLEVEL &&
+                           p->fts_name[0] == '.' && !f_listdot)
+                               break;
+
+                       /*
+                        * If already output something, put out a newline as
+                        * a separator.  If multiple arguments, precede each
+                        * directory with its name.
+                        */
+                       if (output)
+                               (void)printf("\n%s:\n", p->fts_path);
+                       else if (argc > 1) {
+                               (void)printf("%s:\n", p->fts_path);
+                               output = 1;
+                       }
+
+                       chp = fts_children(ftsp, ch_options);
+                       display(p, chp);
+
+                       if (!f_recursive && chp != NULL)
+                               (void)fts_set(ftsp, p, FTS_SKIP);
+                       break;
+               }
+       error = errno;
+       (void)fts_close(ftsp);
+       errno = error;
+       if (errno)
+               err(EXIT_FAILURE, "fts_read");
+}
+
+/*
+ * Display() takes a linked list of FTSENT structures and passes the list
+ * along with any other necessary information to the print function.  P
+ * points to the parent directory of the display list.
+ */
+static void
+display(FTSENT *p, FTSENT *list)
+{
+       struct stat *sp;
+       DISPLAY d;
+       FTSENT *cur;
+       NAMES *np;
+       u_int64_t btotal, stotal;
+       off_t maxsize;
+       blkcnt_t maxblock;
+       ino_t maxinode;
+       int maxmajor, maxminor;
+       uint32_t maxnlink;
+       int bcfile, entries, flen, glen, ulen, maxflags, maxgroup;
+       unsigned int maxlen;
+       int maxuser, needstats;
+       const char *user, *group;
+       char buf[21];           /* 64 bits == 20 digits, +1 for NUL */
+       char nuser[12], ngroup[12];
+       char *flags = NULL;
+
+       /*
+        * If list is NULL there are two possibilities: that the parent
+        * directory p has no children, or that fts_children() returned an
+        * error.  We ignore the error case since it will be replicated
+        * on the next call to fts_read() on the post-order visit to the
+        * directory p, and will be signalled in traverse().
+        */
+       if (list == NULL)
+               return;
+
+       needstats = f_inode || f_longform || f_size;
+       flen = 0;
+       maxinode = maxnlink = 0;
+       bcfile = 0;
+       maxuser = maxgroup = maxflags = maxlen = 0;
+       btotal = stotal = maxblock = maxsize = 0;
+       maxmajor = maxminor = 0;
+       for (cur = list, entries = 0; cur; cur = cur->fts_link) {
+               if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) {
+                       warnx("%s: %s",
+                           cur->fts_name, strerror(cur->fts_errno));
+                       cur->fts_number = NO_PRINT;
+                       rval = EXIT_FAILURE;
+                       continue;
+               }
+
+               /*
+                * P is NULL if list is the argv list, to which different rules
+                * apply.
+                */
+               if (p == NULL) {
+                       /* Directories will be displayed later. */
+                       if (cur->fts_info == FTS_D && !f_listdir) {
+                               cur->fts_number = NO_PRINT;
+                               continue;
+                       }
+               } else {
+                       /* Only display dot file if -a/-A set. */
+                       if (cur->fts_name[0] == '.' && !f_listdot) {
+                               cur->fts_number = NO_PRINT;
+                               continue;
+                       }
+               }
+               if (cur->fts_namelen > maxlen)
+                       maxlen = cur->fts_namelen;
+               if (needstats) {
+                       sp = cur->fts_statp;
+                       if (sp->st_blocks > maxblock)
+                               maxblock = sp->st_blocks;
+                       if (sp->st_ino > maxinode)
+                               maxinode = sp->st_ino;
+                       if (sp->st_nlink > maxnlink)
+                               maxnlink = sp->st_nlink;
+                       if (sp->st_size > maxsize)
+                               maxsize = sp->st_size;
+                       if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode)) {
+                               bcfile = 1;
+                               if (major(sp->st_rdev) > maxmajor)
+                                       maxmajor = major(sp->st_rdev);
+                               if (minor(sp->st_rdev) > maxminor)
+                                       maxminor = minor(sp->st_rdev);
+                       }
+
+                       btotal += sp->st_blocks;
+                       stotal += sp->st_size;
+                       if (f_longform) {
+                               if (f_numericonly ||
+                                   (user = user_from_uid(sp->st_uid, 0)) ==
+                                   NULL) {
+                                       (void)snprintf(nuser, sizeof(nuser),
+                                           "%u", sp->st_uid);
+                                       user = nuser;
+                               }
+                               if (f_numericonly ||
+                                   (group = group_from_gid(sp->st_gid, 0)) ==
+                                   NULL) {
+                                       (void)snprintf(ngroup, sizeof(ngroup),
+                                           "%u", sp->st_gid);
+                                       group = ngroup;
+                               }
+                               if ((ulen = strlen(user)) > maxuser)
+                                       maxuser = ulen;
+                               if ((glen = strlen(group)) > maxgroup)
+                                       maxgroup = glen;
+                               if (f_flags) {
+                                       flags =
+                                           flags_to_string((u_long)sp->st_flags, "-");
+                                       if ((flen = strlen(flags)) > maxflags)
+                                               maxflags = flen;
+                               } else
+                                       flen = 0;
+
+                               if ((np = malloc(sizeof(NAMES) +
+                                   ulen + glen + flen + 2)) == NULL)
+                                       err(EXIT_FAILURE, NULL);
+
+                               np->user = &np->data[0];
+                               (void)strcpy(np->user, user);
+                               np->group = &np->data[ulen + 1];
+                               (void)strcpy(np->group, group);
+
+                               if (f_flags) {
+                                       np->flags = &np->data[ulen + glen + 2];
+                                       (void)strcpy(np->flags, flags);
+                                       free(flags);
+                               }
+                               cur->fts_pointer = np;
+                       }
+               }
+               ++entries;
+       }
+
+       if (!entries)
+               return;
+
+       d.list = list;
+       d.entries = entries;
+       d.maxlen = maxlen;
+       if (needstats) {
+               d.btotal = btotal;
+               d.stotal = stotal;
+               if (f_humanize) {
+                       d.s_block = 4; /* min buf length for humanize_number */
+               } else {
+                       (void)snprintf(buf, sizeof(buf), "%llu",
+                           (long long)howmany(maxblock, blocksize));
+                       d.s_block = strlen(buf);
+                       if (f_commas) /* allow for commas before every third digit */
+                               d.s_block += (d.s_block - 1) / 3;
+               }
+               d.s_flags = maxflags;
+               d.s_group = maxgroup;
+               (void)snprintf(buf, sizeof(buf), "%llu",
+                   (unsigned long long)maxinode);
+               d.s_inode = strlen(buf);
+               (void)snprintf(buf, sizeof(buf), "%u", maxnlink);
+               d.s_nlink = strlen(buf);
+               if (f_humanize) {
+                       d.s_size = 4; /* min buf length for humanize_number */
+               } else {
+                       (void)snprintf(buf, sizeof(buf), "%llu",
+                           (long long)maxsize);
+                       d.s_size = strlen(buf);
+                       if (f_commas) /* allow for commas before every third digit */
+                               d.s_size += (d.s_size - 1) / 3;
+               }
+               d.s_user = maxuser;
+               if (bcfile) {
+                       (void)snprintf(buf, sizeof(buf), "%u", maxmajor);
+                       d.s_major = strlen(buf);
+                       (void)snprintf(buf, sizeof(buf), "%u", maxminor);
+                       d.s_minor = strlen(buf);
+                       if (d.s_major + d.s_minor + 2 > d.s_size)
+                               d.s_size = d.s_major + d.s_minor + 2;
+                       else if (d.s_size - d.s_minor - 2 > d.s_major)
+                               d.s_major = d.s_size - d.s_minor - 2;
+               } else {
+                       d.s_major = 0;
+                       d.s_minor = 0;
+               }
+       }
+
+       printfcn(&d);
+       output = 1;
+
+       if (f_longform)
+               for (cur = list; cur; cur = cur->fts_link)
+                       free(cur->fts_pointer);
+}
+
+/*
+ * Ordering for mastercmp:
+ * If ordering the argv (fts_level = FTS_ROOTLEVEL) return non-directories
+ * as larger than directories.  Within either group, use the sort function.
+ * All other levels use the sort function.  Error entries remain unsorted.
+ */
+static int
+mastercmp(const FTSENT **a, const FTSENT **b)
+{
+       int a_info, b_info;
+
+       a_info = (*a)->fts_info;
+       if (a_info == FTS_ERR)
+               return (0);
+       b_info = (*b)->fts_info;
+       if (b_info == FTS_ERR)
+               return (0);
+
+       if (a_info == FTS_NS || b_info == FTS_NS) {
+               if (b_info != FTS_NS)
+                       return (1);
+               else if (a_info != FTS_NS)
+                       return (-1);
+               else
+                       return (namecmp(*a, *b));
+       }
+
+       if (a_info != b_info && !f_listdir &&
+           (*a)->fts_level == FTS_ROOTLEVEL) {
+               if (a_info == FTS_D)
+                       return (1);
+               else if (b_info == FTS_D)
+                       return (-1);
+       }
+       return (sortfcn(*a, *b));
+}
diff --git a/bin/ls/ls.h b/bin/ls/ls.h
new file mode 100644 (file)
index 0000000..46aad2a
--- /dev/null
@@ -0,0 +1,79 @@
+/*     $NetBSD: ls.h,v 1.18 2011/03/15 03:52:38 erh Exp $      */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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.
+ *
+ *     @(#)ls.h        8.1 (Berkeley) 5/31/93
+ */
+
+#define NO_PRINT       1
+
+extern long blocksize;         /* block size units */
+
+extern int f_accesstime;       /* use time of last access */
+extern int f_flags;            /* show flags associated with a file */
+extern int f_grouponly;                /* long listing without owner */
+extern int f_humanize;         /* humanize size field */
+extern int f_commas;        /* separate size field with commas */
+extern int f_inode;            /* print inode */
+extern int f_longform;         /* long listing format */
+extern int f_octal;            /* print octal escapes for nongraphic characters */
+extern int f_octal_escape;     /* like f_octal but use C escapes if possible */
+extern int f_sectime;          /* print the real time for all files */
+extern int f_size;             /* list size in short listing */
+extern int f_statustime;       /* use time of last mode change */
+extern int f_type;             /* add type character for non-regular files */
+extern int f_typedir;          /* add type character for directories */
+extern int f_nonprint;         /* show unprintables as ? */
+
+typedef struct {
+       FTSENT *list;
+       u_int64_t btotal;
+       u_int64_t stotal;
+       int entries;
+       unsigned int maxlen;
+       int s_block;
+       int s_flags;
+       int s_group;
+       int s_inode;
+       int s_nlink;
+       int s_size;
+       int s_user;
+       int s_major;
+       int s_minor;
+} DISPLAY;
+
+typedef struct {
+       char *user;
+       char *group;
+       char *flags;
+       char data[1];
+} NAMES;
diff --git a/bin/ls/main.c b/bin/ls/main.c
new file mode 100644 (file)
index 0000000..3b9e81c
--- /dev/null
@@ -0,0 +1,52 @@
+/*     $NetBSD: main.c,v 1.4 2008/04/28 20:22:51 martin Exp $  */
+
+/*-
+ * Copyright (c) 1999 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Luke Mewburn.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+
+#ifndef lint
+__RCSID("$NetBSD: main.c,v 1.4 2008/04/28 20:22:51 martin Exp $");
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <fts.h>
+
+#include "ls.h"
+#include "extern.h"
+
+int    main(int, char *[]);
+
+int
+main(int argc, char *argv[])
+{
+
+       return ls_main(argc, argv);
+       /* NOTREACHED */
+}
diff --git a/bin/ls/print.c b/bin/ls/print.c
new file mode 100644 (file)
index 0000000..17a8063
--- /dev/null
@@ -0,0 +1,464 @@
+/*     $NetBSD: print.c,v 1.51 2012/06/29 12:51:38 yamt Exp $  */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)print.c    8.5 (Berkeley) 7/28/94";
+#else
+__RCSID("$NetBSD: print.c,v 1.51 2012/06/29 12:51:38 yamt Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fts.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <tzfile.h>
+#include <unistd.h>
+#include <util.h>
+
+#include "ls.h"
+#include "extern.h"
+
+extern int termwidth;
+
+static int     printaname(FTSENT *, int, int);
+static void    printlink(FTSENT *);
+static void    printtime(time_t);
+static void    printtotal(DISPLAY *dp);
+static int     printtype(u_int);
+
+static time_t  now;
+
+#define        IS_NOPRINT(p)   ((p)->fts_number == NO_PRINT)
+
+void
+printscol(DISPLAY *dp)
+{
+       FTSENT *p;
+
+       for (p = dp->list; p; p = p->fts_link) {
+               if (IS_NOPRINT(p))
+                       continue;
+               (void)printaname(p, dp->s_inode, dp->s_block);
+               (void)putchar('\n');
+       }
+}
+
+void
+printlong(DISPLAY *dp)
+{
+       struct stat *sp;
+       FTSENT *p;
+       NAMES *np;
+       char buf[20], szbuf[5];
+
+       now = time(NULL);
+
+       printtotal(dp);         /* "total: %u\n" */
+       
+       for (p = dp->list; p; p = p->fts_link) {
+               if (IS_NOPRINT(p))
+                       continue;
+               sp = p->fts_statp;
+               if (f_inode)
+                       (void)printf("%*lu ", dp->s_inode,
+                           (unsigned long)sp->st_ino);
+               if (f_size) {
+                       if (f_humanize) {
+                               if ((humanize_number(szbuf, sizeof(szbuf),
+                                   sp->st_blocks * S_BLKSIZE,
+                                   "", HN_AUTOSCALE,
+                                   (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
+                                       err(1, "humanize_number");
+                               (void)printf("%*s ", dp->s_block, szbuf);
+                       } else {
+                               (void)printf(f_commas ? "%'*llu " : "%*llu ",
+                                   dp->s_block,
+                                   (unsigned long long)howmany(sp->st_blocks,
+                                   blocksize));
+                       }
+               }
+               (void)strmode(sp->st_mode, buf);
+               np = p->fts_pointer;
+               (void)printf("%s %*lu ", buf, dp->s_nlink,
+                   (unsigned long)sp->st_nlink);
+               if (!f_grouponly)
+                       (void)printf("%-*s  ", dp->s_user, np->user);
+               (void)printf("%-*s  ", dp->s_group, np->group);
+               if (f_flags)
+                       (void)printf("%-*s ", dp->s_flags, np->flags);
+               if (S_ISCHR(sp->st_mode) || S_ISBLK(sp->st_mode))
+                       (void)printf("%*lld, %*lld ",
+                           dp->s_major, (long long)major(sp->st_rdev),
+                           dp->s_minor, (long long)minor(sp->st_rdev));
+               else
+                       if (f_humanize) {
+                               if ((humanize_number(szbuf, sizeof(szbuf),
+                                   sp->st_size, "", HN_AUTOSCALE,
+                                   (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
+                                       err(1, "humanize_number");
+                               (void)printf("%*s ", dp->s_size, szbuf);
+                       } else {
+                               (void)printf(f_commas ? "%'*llu " : "%*llu ", 
+                                   dp->s_size, (unsigned long long)
+                                   sp->st_size);
+                       }
+               if (f_accesstime)
+                       printtime(sp->st_atime);
+               else if (f_statustime)
+                       printtime(sp->st_ctime);
+               else
+                       printtime(sp->st_mtime);
+               if (f_octal || f_octal_escape)
+                       (void)safe_print(p->fts_name);
+               else if (f_nonprint)
+                       (void)printescaped(p->fts_name);
+               else
+                       (void)printf("%s", p->fts_name);
+
+               if (f_type || (f_typedir && S_ISDIR(sp->st_mode)))
+                       (void)printtype(sp->st_mode);
+               if (S_ISLNK(sp->st_mode))
+                       printlink(p);
+               (void)putchar('\n');
+       }
+}
+
+void
+printcol(DISPLAY *dp)
+{
+       static FTSENT **array;
+       static int lastentries = -1;
+       FTSENT *p;
+       int base, chcnt, col, colwidth, num;
+       int numcols, numrows, row;
+
+       colwidth = dp->maxlen;
+       if (f_inode)
+               colwidth += dp->s_inode + 1;
+       if (f_size) {
+               if (f_humanize)
+                       colwidth += dp->s_size + 1;
+               else
+                       colwidth += dp->s_block + 1;
+       }
+       if (f_type || f_typedir)
+               colwidth += 1;
+
+       colwidth += 1;
+
+       if (termwidth < 2 * colwidth) {
+               printscol(dp);
+               return;
+       }
+
+       /*
+        * Have to do random access in the linked list -- build a table
+        * of pointers.
+        */
+       if (dp->entries > lastentries) {
+               FTSENT **newarray;
+
+               newarray = realloc(array, dp->entries * sizeof(FTSENT *));
+               if (newarray == NULL) {
+                       warn(NULL);
+                       printscol(dp);
+                       return;
+               }
+               lastentries = dp->entries;
+               array = newarray;
+       }
+       for (p = dp->list, num = 0; p; p = p->fts_link)
+               if (p->fts_number != NO_PRINT)
+                       array[num++] = p;
+
+       numcols = termwidth / colwidth;
+       colwidth = termwidth / numcols;         /* spread out if possible */
+       numrows = num / numcols;
+       if (num % numcols)
+               ++numrows;
+
+       printtotal(dp);                         /* "total: %u\n" */
+
+       for (row = 0; row < numrows; ++row) {
+               for (base = row, chcnt = col = 0; col < numcols; ++col) {
+                       chcnt = printaname(array[base], dp->s_inode,
+                           f_humanize ? dp->s_size : dp->s_block);
+                       if ((base += numrows) >= num)
+                               break;
+                       while (chcnt++ < colwidth)
+                               (void)putchar(' ');
+               }
+               (void)putchar('\n');
+       }
+}
+
+void
+printacol(DISPLAY *dp)
+{
+       FTSENT *p;
+       int chcnt, col, colwidth;
+       int numcols;
+
+       colwidth = dp->maxlen;
+       if (f_inode)
+               colwidth += dp->s_inode + 1;
+       if (f_size) {
+               if (f_humanize)
+                       colwidth += dp->s_size + 1;
+               else
+                       colwidth += dp->s_block + 1;
+       }
+       if (f_type || f_typedir)
+               colwidth += 1;
+
+       colwidth += 1;
+
+       if (termwidth < 2 * colwidth) {
+               printscol(dp);
+               return;
+       }
+
+       numcols = termwidth / colwidth;
+       colwidth = termwidth / numcols;         /* spread out if possible */
+
+       printtotal(dp);                         /* "total: %u\n" */
+
+       chcnt = col = 0;
+       for (p = dp->list; p; p = p->fts_link) {
+               if (IS_NOPRINT(p))
+                       continue;
+               if (col >= numcols) {
+                       chcnt = col = 0;
+                       (void)putchar('\n');
+               }
+               chcnt = printaname(p, dp->s_inode,
+                   f_humanize ? dp->s_size : dp->s_block);
+               while (chcnt++ < colwidth)
+                       (void)putchar(' ');
+               col++;
+       }
+       (void)putchar('\n');
+}
+
+void
+printstream(DISPLAY *dp)
+{
+       FTSENT *p;
+       int col;
+       int extwidth;
+
+       extwidth = 0;
+       if (f_inode)
+               extwidth += dp->s_inode + 1;
+       if (f_size) {
+               if (f_humanize)
+                       extwidth += dp->s_size + 1;
+               else 
+                       extwidth += dp->s_block + 1;
+       }
+       if (f_type)
+               extwidth += 1;
+
+       for (col = 0, p = dp->list; p != NULL; p = p->fts_link) {
+               if (IS_NOPRINT(p))
+                       continue;
+               if (col > 0) {
+                       (void)putchar(','), col++;
+                       if (col + 1 + extwidth + (int)p->fts_namelen >= termwidth)
+                               (void)putchar('\n'), col = 0;
+                       else
+                               (void)putchar(' '), col++;
+               }
+               col += printaname(p, dp->s_inode,
+                   f_humanize ? dp->s_size : dp->s_block);
+       }
+       (void)putchar('\n');
+}
+
+/*
+ * print [inode] [size] name
+ * return # of characters printed, no trailing characters.
+ */
+static int
+printaname(FTSENT *p, int inodefield, int sizefield)
+{
+       struct stat *sp;
+       int chcnt;
+       char szbuf[5];
+
+       sp = p->fts_statp;
+       chcnt = 0;
+       if (f_inode)
+               chcnt += printf("%*lu ", inodefield, (unsigned long)sp->st_ino);
+       if (f_size) {
+               if (f_humanize) {
+                       if ((humanize_number(szbuf, sizeof(szbuf), sp->st_size,
+                           "", HN_AUTOSCALE,
+                           (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
+                               err(1, "humanize_number");
+                       chcnt += printf("%*s ", sizefield, szbuf);
+               } else {
+                       chcnt += printf(f_commas ? "%'*llu " : "%*llu ",
+                           sizefield, (unsigned long long)
+                           howmany(sp->st_blocks, blocksize));
+               }
+       }
+       if (f_octal || f_octal_escape)
+               chcnt += safe_print(p->fts_name);
+       else if (f_nonprint)
+               chcnt += printescaped(p->fts_name);
+       else
+               chcnt += printf("%s", p->fts_name);
+       if (f_type || (f_typedir && S_ISDIR(sp->st_mode)))
+               chcnt += printtype(sp->st_mode);
+       return (chcnt);
+}
+
+static void
+printtime(time_t ftime)
+{
+       int i;
+       const char *longstring;
+
+       if ((longstring = ctime(&ftime)) == NULL) {
+                          /* 012345678901234567890123 */
+               longstring = "????????????????????????";
+       }
+       for (i = 4; i < 11; ++i)
+               (void)putchar(longstring[i]);
+
+#define        SIXMONTHS       ((DAYSPERNYEAR / 2) * SECSPERDAY)
+       if (f_sectime)
+               for (i = 11; i < 24; i++)
+                       (void)putchar(longstring[i]);
+       else if (ftime + SIXMONTHS > now && ftime - SIXMONTHS < now)
+               for (i = 11; i < 16; ++i)
+                       (void)putchar(longstring[i]);
+       else {
+               (void)putchar(' ');
+               for (i = 20; i < 24; ++i)
+                       (void)putchar(longstring[i]);
+       }
+       (void)putchar(' ');
+}
+
+/*
+ * Display total used disk space in the form "total: %u\n".
+ * Note: POSIX (IEEE Std 1003.1-2001) says this should be always in 512 blocks,
+ * but we humanise it with -h, or separate it with commas with -M, and use 1024
+ * with -k.
+ */
+static void
+printtotal(DISPLAY *dp)
+{
+       char szbuf[5];
+       
+       if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size)) {
+               if (f_humanize) {
+                       if ((humanize_number(szbuf, sizeof(szbuf), (int64_t)dp->stotal,
+                           "", HN_AUTOSCALE,
+                           (HN_DECIMAL | HN_B | HN_NOSPACE))) == -1)
+                               err(1, "humanize_number");
+                       (void)printf("total %s\n", szbuf);
+               } else {
+                       (void)printf(f_commas ? "total %'llu\n" :
+                           "total %llu\n", (unsigned long long)
+                           howmany(dp->btotal, blocksize));
+               }
+       }
+}
+
+static int
+printtype(u_int mode)
+{
+       switch (mode & S_IFMT) {
+       case S_IFDIR:
+               (void)putchar('/');
+               return (1);
+       case S_IFIFO:
+               (void)putchar('|');
+               return (1);
+       case S_IFLNK:
+               (void)putchar('@');
+               return (1);
+       case S_IFSOCK:
+               (void)putchar('=');
+               return (1);
+       case S_IFWHT:
+               (void)putchar('%');
+               return (1);
+       }
+       if (mode & (S_IXUSR | S_IXGRP | S_IXOTH)) {
+               (void)putchar('*');
+               return (1);
+       }
+       return (0);
+}
+
+static void
+printlink(FTSENT *p)
+{
+       int lnklen;
+       char name[MAXPATHLEN + 1], path[MAXPATHLEN + 1];
+
+       if (p->fts_level == FTS_ROOTLEVEL)
+               (void)snprintf(name, sizeof(name), "%s", p->fts_name);
+       else
+               (void)snprintf(name, sizeof(name),
+                   "%s/%s", p->fts_parent->fts_accpath, p->fts_name);
+       if ((lnklen = readlink(name, path, sizeof(path) - 1)) == -1) {
+               (void)fprintf(stderr, "\nls: %s: %s\n", name, strerror(errno));
+               return;
+       }
+       path[lnklen] = '\0';
+       (void)printf(" -> ");
+       if (f_octal || f_octal_escape)
+               (void)safe_print(path);
+       else if (f_nonprint)
+               (void)printescaped(path);
+       else
+               (void)printf("%s", path);
+}
+
diff --git a/bin/ls/util.c b/bin/ls/util.c
new file mode 100644 (file)
index 0000000..61b0fda
--- /dev/null
@@ -0,0 +1,168 @@
+/*     $NetBSD: util.c,v 1.34 2011/08/29 14:44:21 joerg Exp $  */
+
+/*
+ * Copyright (c) 1989, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
+ *
+ * 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.
+ */
+
+#include <sys/cdefs.h>
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)util.c     8.5 (Berkeley) 4/28/95";
+#else
+__RCSID("$NetBSD: util.c,v 1.34 2011/08/29 14:44:21 joerg Exp $");
+#endif
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <err.h>
+#include <fts.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <vis.h>
+#include <wchar.h>
+#include <wctype.h>
+
+#include "ls.h"
+#include "extern.h"
+
+int
+safe_print(const char *src)
+{
+       size_t len;
+       char *name;
+       int flags;
+
+       flags = VIS_NL | VIS_OCTAL | VIS_WHITE;
+       if (f_octal_escape)
+               flags |= VIS_CSTYLE;
+
+       len = strlen(src);
+       if (len != 0 && SIZE_T_MAX/len <= 4) {
+               errx(EXIT_FAILURE, "%s: name too long", src);
+               /* NOTREACHED */
+       }
+
+       name = (char *)malloc(4*len+1);
+       if (name != NULL) {
+               len = strvis(name, src, flags);
+               (void)printf("%s", name);
+               free(name);
+               return len;
+       } else
+               errx(EXIT_FAILURE, "out of memory!");
+               /* NOTREACHED */
+}
+
+/*
+ * The reasons why we don't use putwchar(wc) here are:
+ * - If wc == L'\0', we need to restore the initial shift state, but
+ *   the C language standard doesn't say that putwchar(L'\0') does.
+ * - It isn't portable to mix a wide-oriented function (i.e. getwchar)
+ *   with byte-oriented functions (printf et al.) in same FILE.
+ */
+static int
+printwc(wchar_t wc, mbstate_t *pst)
+{
+       size_t size;
+       char buf[MB_LEN_MAX];
+
+       size = wcrtomb(buf, wc, pst);
+       if (size == (size_t)-1) /* This shouldn't happen, but for sure */
+               return 0;
+       if (wc == L'\0') {
+               /* The following condition must be always true, but for sure */
+               if (size > 0 && buf[size - 1] == '\0')
+                       --size;
+       }
+       if (size > 0)
+               fwrite(buf, 1, size, stdout);
+       return wc == L'\0' ? 0 : wcwidth(wc);
+}
+
+int
+printescaped(const char *src)
+{
+       int n = 0;
+       mbstate_t src_state, stdout_state;
+       /* The following +1 is to pass '\0' at the end of src to mbrtowc(). */
+       const char *endptr = src + strlen(src) + 1;
+
+       /*
+        * We have to reset src_state each time in this function, because
+        * the codeset of src pathname may not match with current locale.
+        * Note that if we pass NULL instead of src_state to mbrtowc(),
+        * there is no way to reset the state.
+        */
+       memset(&src_state, 0, sizeof(src_state));
+       memset(&stdout_state, 0, sizeof(stdout_state));
+       while (src < endptr) {
+               wchar_t wc;
+               size_t rv, span = endptr - src;
+
+#if 0
+               /*
+                * XXX - we should fix libc instead.
+                * Theoretically this should work, but our current
+                * implementation of iso2022 module doesn't actually work
+                * as expected, if there are redundant escape sequences
+                * which exceed 32 bytes.
+                */
+               if (span > MB_CUR_MAX)
+                       span = MB_CUR_MAX;
+#endif
+               rv = mbrtowc(&wc, src, span, &src_state);
+               if (rv == 0) { /* assert(wc == L'\0'); */
+                       /* The following may output a shift sequence. */
+                       n += printwc(wc, &stdout_state);
+                       break;
+               }
+               if (rv == (size_t)-1) { /* probably errno == EILSEQ */
+                       n += printwc(L'?', &stdout_state);
+                       /* try to skip 1byte, because there is no better way */
+                       src++;
+                       memset(&src_state, 0, sizeof(src_state));
+               } else if (rv == (size_t)-2) {
+                       if (span < MB_CUR_MAX) { /* incomplete char */
+                               n += printwc(L'?', &stdout_state);
+                               break;
+                       }
+                       src += span; /* a redundant shift sequence? */
+               } else {
+                       n += printwc(iswprint(wc) ? wc : L'?', &stdout_state);
+                       src += rv;
+               }
+       }
+       return n;
+}
index 0921cf12e540ef07923be23a60379e6130758dce..2a7849217180a7eb745f53b3d9d1842142ffd275 100644 (file)
@@ -14,7 +14,7 @@ SUBDIR=       add_route arp ash at backup banner basename btrace cal \
        hostaddr id ifconfig ifdef \
        intr ipcrm ipcs irdpd isoread last \
        less loadkeys loadramdisk logger look lp \
-       lpd ls lspci mail MAKEDEV \
+       lpd lspci mail MAKEDEV \
        mesg mined mkfifo \
        mount mt netconf nice acknm nohup \
        nonamed od paste patch \
diff --git a/commands/ls/Makefile b/commands/ls/Makefile
deleted file mode 100644 (file)
index b7d1004..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-PROG=  ls
-BINDIR=        /bin
-MAN=
-
-# LSC Force usage of local mergesort
-CPPFLAGS.ls.c+= -D__NBSD_LIBC
-
-.include <bsd.prog.mk>
diff --git a/commands/ls/ls.c b/commands/ls/ls.c
deleted file mode 100644 (file)
index dd404eb..0000000
+++ /dev/null
@@ -1,1154 +0,0 @@
-/*     ls 5.4 - List files.                            Author: Kees J. Bot
- *                                                             25 Apr 1989
- *
- * About the amount of bytes for heap + stack under Minix:
- * Ls needs a average amount of 42 bytes per unserviced directory entry, so
- * scanning 10 directory levels deep in an ls -R with 100 entries per directory
- * takes 42000 bytes of heap.  So giving ls 10000 bytes is tight, 20000 is
- * usually enough, 40000 is pessimistic.
- */
-
-/* The array l_ifmt[] is used in an 'ls -l' to map the type of a file to a
- * letter.  This is done so that ls can list any future file or device type
- * other than symlinks, without recompilation.  (Yes it's dirty.)
- */
-char l_ifmt[] = "0pcCd?bB-?l?s???";
-
-#define ifmt(mode)     l_ifmt[((mode) >> 12) & 0xF]
-
-#define nil 0
-#include <stdio.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <dirent.h>
-#include <time.h>
-#include <pwd.h>
-#include <grp.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <limits.h>
-#include <termios.h>
-#include <sys/ioctl.h>
-
-#ifndef major
-#define major(dev)     ((int) (((dev) >> 8) & 0xFF))
-#define minor(dev)     ((int) (((dev) >> 0) & 0xFF))
-#endif
-
-#if !__minix
-#define SUPER_ID       uid     /* Let -A flag be default for SUPER_ID == 0. */
-#else
-#define SUPER_ID       gid
-#endif
-
-#ifdef S_IFLNK
-int (*status)(const char *file, struct stat *stp);
-#else
-#define status stat
-#endif
-
-/* Basic disk block size is 512 except for one niche O.S. */
-#if __minix
-#define BLOCK  1024
-#else
-#define BLOCK   512
-#endif
-
-/* Assume other systems have st_blocks. */
-#if !__minix
-#define ST_BLOCKS 1
-#endif
-
-/* Some terminals ignore more than 80 characters on a line.  Dumb ones wrap
- * when the cursor hits the side.  Nice terminals don't wrap until they have
- * to print the 81st character.  Whether we like it or not, no column 80.
- */
-int ncols= 79;
-
-#define NSEP   3       /* # spaces between columns. */
-
-#define MAXCOLS        128     /* Max # of files per line. */
-
-char *arg0;    /* Last component of argv[0]. */
-int uid, gid;  /* callers id. */
-int ex= 0;     /* Exit status to be. */
-int istty;     /* Output is on a terminal. */
-
-/* Safer versions of malloc and realloc: */
-
-void heaperr(void)
-{
-       fprintf(stderr, "%s: Out of memory\n", arg0);
-       exit(-1);
-}
-
-void *allocate(size_t n)
-/* Deliver or die. */
-{
-       void *a;
-
-       if ((a= malloc(n)) == nil) heaperr();
-       return a;
-}
-
-void *reallocate(void *a, size_t n)
-{
-       if ((a= realloc(a, n)) == nil) heaperr();
-       return a;
-}
-
-char allowed[] = "acdfghilnpqrstu1ACDFLMRTX";
-char flags[sizeof(allowed)];
-
-char arg0flag[] = "cdfmrtx";   /* These in argv[0] go to upper case. */
-
-void setflags(char *flgs)
-{
-       int c;
-
-       while ((c= *flgs++) != 0) {
-               if (strchr(allowed, c) == nil) {
-                       fprintf(stderr, "Usage: %s [-%s] [file ...]\n",
-                               arg0, allowed);
-                       exit(1);
-               } else
-               if (strchr(flags, c) == nil) {
-                       flags[strlen(flags)] = c;
-               }
-       }
-}
-
-int present(int f)
-{
-       return f == 0 || strchr(flags, f) != nil;
-}
-
-void report(char *f)
-/* Like perror(3), but in the style: "ls: junk: No such file or directory. */
-{
-       fprintf(stderr, "%s: %s: %s\n", arg0, f, strerror(errno));
-       ex= 1;
-}
-
-/* Two functions, uidname and gidname, translate id's to readable names.
- * All names are remembered to avoid searching the password file.
- */
-#define NNAMES (1 << (sizeof(int) + sizeof(char *)))
-enum whatmap { PASSWD, GROUP };
-
-struct idname {                /* Hash list of names. */
-       struct idname   *next;
-       char            *name;
-       uid_t           id;
-} *uids[NNAMES], *gids[NNAMES];
-
-char *idname(unsigned id, enum whatmap map)
-/* Return name for a given user/group id. */
-{
-       struct idname *i;
-       struct idname **ids= &(map == PASSWD ? uids : gids)[id % NNAMES];
-
-       while ((i= *ids) != nil && id < i->id) ids= &i->next;
-
-       if (i == nil || id != i->id) {
-               /* Not found, go look in the password or group map. */
-               char *name= nil;
-               char noname[3 * sizeof(uid_t)];
-
-               if (!present('n')) {
-                       if (map == PASSWD) {
-                               struct passwd *pw= getpwuid(id);
-
-                               if (pw != nil) name= pw->pw_name;
-                       } else {
-                               struct group *gr= getgrgid(id);
-
-                               if (gr != nil) name= gr->gr_name;
-                       }
-               }
-               if (name == nil) {
-                       /* Can't find it, weird.  Use numerical "name." */
-                       sprintf(noname, "%u", id);
-                       name= noname;
-               }
-
-               /* Add a new id-to-name cell. */
-               i= allocate(sizeof(*i));
-               i->id= id;
-               i->name= allocate(strlen(name) + 1);
-               strcpy(i->name, name);
-               i->next= *ids;
-               *ids= i;
-       }
-       return i->name;
-}
-
-#define uidname(uid)   idname((uid), PASSWD)
-#define gidname(gid)   idname((gid), GROUP)
-
-/* Path name construction, addpath adds a component, delpath removes it.
- * The string path is used throughout the program as the file under examination.
- */
-
-char *path;    /* Path name constructed in path[]. */
-int plen= 0, pidx= 0;  /* Lenght/index for path[]. */
-
-void addpath(int *didx, char *name)
-/* Add a component to path. (name may also be a full path at the first call)
- * The index where the current path ends is stored in *pdi.
- */
-{
-       if (plen == 0) path= (char *) allocate((plen= 32) * sizeof(path[0]));
-
-       if (pidx == 1 && path[0] == '.') pidx= 0;       /* Remove "." */
-
-       *didx= pidx;    /* Record point to go back to for delpath. */
-
-       if (pidx > 0 && path[pidx-1] != '/') path[pidx++]= '/';
-
-       do {
-               if (*name != '/' || pidx == 0 || path[pidx-1] != '/') {
-                       if (pidx == plen) {
-                               path= (char *) reallocate((void *) path,
-                                               (plen*= 2) * sizeof(path[0]));
-                       }
-                       path[pidx++]= *name;
-               }
-       } while (*name++ != 0);
-
-       --pidx;         /* Put pidx back at the null.  The path[pidx++]= '/'
-                        * statement will overwrite it at the next call.
-                        */
-}
-
-#define delpath(didx)  (path[pidx= didx]= 0)   /* Remove component. */
-
-int field = 0; /* (used to be) Fields that must be printed. */
-               /* (now) Effects triggered by certain flags. */
-
-#define L_INODE                0x0001  /* -i */
-#define L_BLOCKS       0x0002  /* -s */
-#define L_EXTRA                0x0004  /* -X */
-#define L_MODE         0x0008  /* -lMX */
-#define L_LONG         0x0010  /* -l */
-#define L_GROUP                0x0020  /* -g */
-#define L_BYTIME       0x0040  /* -tuc */
-#define L_ATIME                0x0080  /* -u */
-#define L_CTIME                0x0100  /* -c */
-#define L_MARK         0x0200  /* -F */
-#define L_MARKDIR      0x0400  /* -p */
-#define L_TYPE         0x0800  /* -D */
-#define L_LONGTIME     0x1000  /* -T */
-#define L_DIR          0x2000  /* -d */
-#define L_KMG          0x4000  /* -h */
-
-struct file {          /* A file plus stat(2) information. */
-       struct file     *next;  /* Lists are made of them. */
-       char            *name;  /* Null terminated name. */
-       ino_t           ino;
-       mode_t          mode;
-       uid_t           uid;
-       gid_t           gid;
-       nlink_t         nlink;
-       dev_t           rdev;
-       off_t           size;
-       time_t          mtime;
-       time_t          atime;
-       time_t          ctime;
-#if ST_BLOCKS
-       long            blocks;
-#endif
-};
-
-void setstat(struct file *f, struct stat *stp)
-{
-       f->ino=         stp->st_ino;
-       f->mode=        stp->st_mode;
-       f->nlink=       stp->st_nlink;
-       f->uid=         stp->st_uid;
-       f->gid=         stp->st_gid;
-       f->rdev=        stp->st_rdev;
-       f->size=        stp->st_size;
-       f->mtime=       stp->st_mtime;
-       f->atime=       stp->st_atime;
-       f->ctime=       stp->st_ctime;
-#if ST_BLOCKS
-       f->blocks=      stp->st_blocks;
-#endif
-}
-
-#define        PAST    (26*7*24*3600L) /* Half a year ago. */
-/* Between PAST and FUTURE from now a time is printed, otherwise a year. */
-#define FUTURE ( 1*7*24*3600L) /* One week. */
-
-static char *timestamp(struct file *f)
-/* Transform the right time field into something readable. */
-{
-       struct tm *tm;
-       time_t t;
-       static time_t now;
-       static int drift= 0;
-       static char date[] = "Jan 19 03:14:07 2038";
-       static char month[] = "JanFebMarAprMayJunJulAugSepOctNovDec";
-
-       t= f->mtime;
-       if (field & L_ATIME) t= f->atime;
-       if (field & L_CTIME) t= f->ctime;
-
-       tm= localtime(&t);
-       if (--drift < 0) { time(&now); drift= 50; }     /* limit time() calls */
-
-       if (field & L_LONGTIME) {
-               sprintf(date, "%.3s %2d %02d:%02d:%02d %d",
-                       month + 3*tm->tm_mon,
-                       tm->tm_mday,
-                       tm->tm_hour, tm->tm_min, tm->tm_sec,
-                       1900 + tm->tm_year);
-       } else
-       if (t < now - PAST || t > now + FUTURE) {
-               sprintf(date, "%.3s %2d  %d",
-                       month + 3*tm->tm_mon,
-                       tm->tm_mday,
-                       1900 + tm->tm_year);
-       } else {
-               sprintf(date, "%.3s %2d %02d:%02d",
-                       month + 3*tm->tm_mon,
-                       tm->tm_mday,
-                       tm->tm_hour, tm->tm_min);
-       }
-       return date;
-}
-
-char *permissions(struct file *f)
-/* Compute long or short rwx bits. */
-{
-       static char rwx[] = "drwxr-x--x";
-
-       rwx[0] = ifmt(f->mode);
-       /* Note that rwx[0] is a guess for the more alien file types.  It is
-        * correct for BSD4.3 and derived systems.  I just don't know how
-        * "standardized" these numbers are.
-        */
-
-       if (field & L_EXTRA) {          /* Short style */
-               int mode = f->mode, ucase= 0;
-
-               if (uid == f->uid) {    /* What group of bits to use. */
-                       /* mode<<= 0, */
-                       ucase= (mode<<3) | (mode<<6);
-                       /* Remember if group or others have permissions. */
-               } else
-               if (gid == f->gid) {
-                       mode<<= 3;
-               } else {
-                       mode<<= 6;
-               }
-               rwx[1]= mode&S_IRUSR ? (ucase&S_IRUSR ? 'R' : 'r') : '-';
-               rwx[2]= mode&S_IWUSR ? (ucase&S_IWUSR ? 'W' : 'w') : '-';
-
-               if (mode&S_IXUSR) {
-                       static char sbit[]= { 'x', 'g', 'u', 's' };
-
-                       rwx[3]= sbit[(f->mode&(S_ISUID|S_ISGID))>>10];
-                       if (ucase&S_IXUSR) rwx[3] += 'A'-'a';
-               } else {
-                       rwx[3]= f->mode&(S_ISUID|S_ISGID) ? '=' : '-';
-               }
-               rwx[4]= 0;
-       } else {                /* Long form. */
-               char *p= rwx+1;
-               int mode= f->mode;
-
-               do {
-                       p[0] = (mode & S_IRUSR) ? 'r' : '-';
-                       p[1] = (mode & S_IWUSR) ? 'w' : '-';
-                       p[2] = (mode & S_IXUSR) ? 'x' : '-';
-                       mode<<= 3;
-               } while ((p+=3) <= rwx+7);
-
-               if (f->mode&S_ISUID) rwx[3]= f->mode&(S_IXUSR>>0) ? 's' : '=';
-               if (f->mode&S_ISGID) rwx[6]= f->mode&(S_IXUSR>>3) ? 's' : '=';
-               if (f->mode&S_ISVTX) rwx[9]= f->mode&(S_IXUSR>>6) ? 't' : '=';
-       }
-       return rwx;
-}
-
-void numeral(int i, char **pp)
-{
-       char itoa[3*sizeof(int)], *a=itoa;
-
-       do *a++ = i%10 + '0'; while ((i/=10) > 0);
-
-       do *(*pp)++ = *--a; while (a>itoa);
-}
-
-#define K      1024L           /* A kilobyte counts in multiples of K */
-#define T      1000L           /* A megabyte in T*K, a gigabyte in T*T*K */
-
-char *cxsize(struct file *f)
-/* Try and fail to turn a 32 bit size into 4 readable characters. */
-{
-       static char siz[] = "1.2m";
-       char *p= siz;
-       off_t z;
-
-       siz[1]= siz[2]= siz[3]= 0;
-
-       if (f->size <= 5*K) {   /* <= 5K prints as is. */
-               numeral((int) f->size, &p);
-               return siz;
-       }
-       z= (f->size + K-1) / K;
-
-       if (z <= 999) {         /* Print as 123k. */
-               numeral((int) z, &p);
-               *p = 'k';       /* Can't use 'K', looks bad */
-       } else
-       if (z*10 <= 99*T) {     /* 1.2m (Try ls -X /dev/at0) */
-               z= (z*10 + T-1) / T;    /* Force roundup */
-               numeral((int) z / 10, &p);
-               *p++ = '.';
-               numeral((int) z % 10, &p);
-               *p = 'm';
-       } else
-       if (z <= 999*T) {       /* 123m */
-               numeral((int) ((z + T-1) / T), &p);
-               *p = 'm';
-       } else {                /* 1.2g */
-               z= (z*10 + T*T-1) / (T*T);
-               numeral((int) z / 10, &p);
-               *p++ = '.';
-               numeral((int) z % 10, &p);
-               *p = 'g';
-       }
-       return siz;
-}
-
-/* Transform size of file to number of blocks.  This was once a function that
- * guessed the number of indirect blocks, but that nonsense has been removed.
- */
-#if ST_BLOCKS
-#define nblocks(f)     ((f)->blocks)
-#else
-#define nblocks(f)     (((f)->size + BLOCK-1) / BLOCK)
-#endif
-
-/* From number of blocks to kilobytes. */
-#if BLOCK < 1024
-#define nblk2k(nb)     (((nb) + (1024 / BLOCK - 1)) / (1024 / BLOCK))
-#else
-#define nblk2k(nb)     ((nb) * (BLOCK / 1024))
-#endif
-
-static int (*CMP)(struct file *f1, struct file *f2);
-static int (*rCMP)(struct file *f1, struct file *f2);
-
-#ifdef __NBSD_LIBC
-#define mergesort _ls_mergesort
-#endif
-
-static void mergesort(struct file **al)
-/* This is either a stable mergesort, or thermal noise, I'm no longer sure.
- * It must be called like this: if (L != nil && L->next != nil) mergesort(&L);
- */
-{
-       /* static */ struct file *l1, **mid;  /* Need not be local */
-       struct file *l2;
-
-       l1= *(mid= &(*al)->next);
-       do {
-               if ((l1= l1->next) == nil) break;
-               mid= &(*mid)->next;
-       } while ((l1= l1->next) != nil);
-
-       l2= *mid;
-       *mid= nil;
-
-       if ((*al)->next != nil) mergesort(al);
-       if (l2->next != nil) mergesort(&l2);
-
-       l1= *al;
-       for (;;) {
-               if ((*CMP)(l1, l2) <= 0) {
-                       if ((l1= *(al= &l1->next)) == nil) {
-                               *al= l2;
-                               break;
-                       }
-               } else {
-                       *al= l2;
-                       l2= *(al= &l2->next);
-                       *al= l1;
-                       if (l2 == nil) break;
-               }
-       }
-}
-
-int namecmp(struct file *f1, struct file *f2)
-{
-       return strcmp(f1->name, f2->name);
-}
-
-int mtimecmp(struct file *f1, struct file *f2)
-{
-       return f1->mtime == f2->mtime ? 0 : f1->mtime > f2->mtime ? -1 : 1;
-}
-
-int atimecmp(struct file *f1, struct file *f2)
-{
-       return f1->atime == f2->atime ? 0 : f1->atime > f2->atime ? -1 : 1;
-}
-
-int ctimecmp(struct file *f1, struct file *f2)
-{
-       return f1->ctime == f2->ctime ? 0 : f1->ctime > f2->ctime ? -1 : 1;
-}
-
-int typecmp(struct file *f1, struct file *f2)
-{
-       return ifmt(f1->mode) - ifmt(f2->mode);
-}
-
-int revcmp(struct file *f1, struct file *f2) { return (*rCMP)(f2, f1); }
-
-static void sort(struct file **al)
-/* Sort the files according to the flags. */
-{
-       if (!present('f') && *al != nil && (*al)->next != nil) {
-               CMP= namecmp;
-
-               if (!(field & L_BYTIME)) {
-                       /* Sort on name */
-
-                       if (present('r')) { rCMP= CMP; CMP= revcmp; }
-                       mergesort(al);
-               } else {
-                       /* Sort on name first, then sort on time. */
-
-                       mergesort(al);
-                       if (field & L_CTIME) {
-                               CMP= ctimecmp;
-                       } else
-                       if (field & L_ATIME) {
-                               CMP= atimecmp;
-                       } else {
-                               CMP= mtimecmp;
-                       }
-
-                       if (present('r')) { rCMP= CMP; CMP= revcmp; }
-                       mergesort(al);
-               }
-               /* Separate by file type if so desired. */
-
-               if (field & L_TYPE) {
-                       CMP= typecmp;
-                       mergesort(al);
-               }
-       }
-}
-
-struct file *newfile(char *name)
-/* Create file structure for given name. */
-{
-       struct file *new;
-
-       new= (struct file *) allocate(sizeof(*new));
-       new->name= strcpy((char *) allocate(strlen(name)+1), name);
-       return new;
-}
-
-void pushfile(struct file **flist, struct file *new)
-/* Add file to the head of a list. */
-{
-       new->next= *flist;
-       *flist= new;
-}
-
-void delfile(struct file *old)
-/* Release old file structure. */
-{
-       free((void *) old->name);
-       free((void *) old);
-}
-
-struct file *popfile(struct file **flist)
-/* Pop file off top of file list. */
-{
-       struct file *f;
-
-       f= *flist;
-       *flist= f->next;
-       return f;
-}
-
-int dotflag(char *name)
-/* Return flag that would make ls list this name: -a or -A. */
-{
-       if (*name++ != '.') return 0;
-
-       switch (*name++) {
-       case 0:         return 'a';                     /* "." */
-       case '.':       if (*name == 0) return 'a';     /* ".." */
-       default:        return 'A';                     /* ".*" */
-       }
-}
-
-int adddir(struct file **aflist, char *name)
-/* Add directory entries of directory name to a file list. */
-{
-       DIR *d;
-       struct dirent *e;
-
-       if (access(name, 0) < 0) {
-               report(name);
-               return 0;
-       }
-
-       if ((d= opendir(name)) == nil) {
-               report(name);
-               return 0;
-       }
-       while ((e= readdir(d)) != nil) {
-               if (e->d_ino != 0 && present(dotflag(e->d_name))) {
-                       pushfile(aflist, newfile(e->d_name));
-                       aflist= &(*aflist)->next;
-               }
-       }
-       closedir(d);
-       return 1;
-}
-
-off_t countblocks(struct file *flist)
-/* Compute total block count for a list of files. */
-{
-       off_t cb = 0;
-
-       while (flist != nil) {
-               switch (flist->mode & S_IFMT) {
-               case S_IFDIR:
-               case S_IFREG:
-#ifdef S_IFLNK
-               case S_IFLNK:
-#endif
-                       cb += nblocks(flist);
-               }
-               flist= flist->next;
-       }
-       return cb;
-}
-
-void printname(char *name)
-/* Print a name with control characters as '?' (unless -q).  The terminal is
- * assumed to be eight bit clean.
- */
-{
-       int c, q= present('q');
-
-       while ((c= (unsigned char) *name++) != 0) {
-               if (q && (c < ' ' || c == 0177)) c= '?';
-               putchar(c);
-       }
-}
-
-int mark(struct file *f, int doit)
-{
-       int c;
-
-       c= 0;
-
-       if (field & L_MARK) {
-               switch (f->mode & S_IFMT) {
-               case S_IFDIR:   c= '/'; break;
-#ifdef S_IFIFO
-               case S_IFIFO:   c= '|'; break;
-#endif
-#ifdef S_IFLNK
-               case S_IFLNK:   c= '@'; break;
-#endif
-#ifdef S_IFSOCK
-               case S_IFSOCK:  c= '='; break;
-#endif
-               case S_IFREG:
-                       if (f->mode & (S_IXUSR | S_IXGRP | S_IXOTH)) c= '*';
-                       break;
-               }
-       } else
-       if (field & L_MARKDIR) {
-               if (S_ISDIR(f->mode)) c= '/';
-       }
-
-       if (doit && c != 0) putchar(c);
-       return c;
-}
-
-/* Width of entire column, and of several fields. */
-enum { W_COL, W_INO, W_BLK, W_NLINK, W_UID, W_GID, W_SIZE, W_NAME, MAXFLDS };
-
-unsigned char fieldwidth[MAXCOLS][MAXFLDS];
-
-void maxise(unsigned char *aw, int w)
-/* Set *aw to the larger of it and w. */
-{
-       if (w > *aw) {
-               if (w > UCHAR_MAX) w= UCHAR_MAX;
-               *aw= w;
-       }
-}
-
-int numwidth(unsigned long n)
-/* Compute width of 'n' when printed. */
-{
-       int width= 0;
-
-       do { width++; } while ((n /= 10) > 0);
-       return width;
-}
-
-#if !__minix
-int numxwidth(unsigned long n)
-/* Compute width of 'n' when printed in hex. */
-{
-       int width= 0;
-
-       do { width++; } while ((n /= 16) > 0);
-       return width;
-}
-#endif
-
-static int nsp= 0;     /* This many spaces have not been printed yet. */
-#define spaces(n)      (nsp= (n))
-#define terpri()       (nsp= 0, putchar('\n'))         /* No trailing spaces */
-
-void print1(struct file *f, int col, int doit)
-/* Either compute the number of spaces needed to print file f (doit == 0) or
- * really print it (doit == 1).
- */
-{
-       int width= 0, n;
-       char *p;
-       unsigned char *f1width = fieldwidth[col];
-
-       while (nsp>0) { putchar(' '); nsp--; }/* Fill gap between two columns */
-
-       if (field & L_INODE) {
-               if (doit) {
-                       printf("%*d ", f1width[W_INO], f->ino);
-               } else {
-                       maxise(&f1width[W_INO], numwidth(f->ino));
-                       width++;
-               }
-       }
-       if (field & L_BLOCKS) {
-               unsigned long nb= nblk2k(nblocks(f));
-               if (doit) {
-                       printf("%*lu ", f1width[W_BLK], nb);
-               } else {
-                       maxise(&f1width[W_BLK], numwidth(nb));
-                       width++;
-               }
-       }
-       if (field & L_MODE) {
-               if (doit) {
-                       printf("%s ", permissions(f));
-               } else {
-                       width+= (field & L_EXTRA) ? 5 : 11;
-               }
-       }
-       if (field & L_EXTRA) {
-               p= cxsize(f);
-               n= strlen(p)+1;
-
-               if (doit) {
-                       n= f1width[W_SIZE] - n;
-                       while (n > 0) { putchar(' '); --n; }
-                       printf("%s ", p);
-               } else {
-                       maxise(&f1width[W_SIZE], n);
-               }
-       }
-       if (field & L_LONG) {
-               if (doit) {
-                       printf("%*u ", f1width[W_NLINK], (unsigned) f->nlink);
-               } else {
-                       maxise(&f1width[W_NLINK], numwidth(f->nlink));
-                       width++;
-               }
-               if (!(field & L_GROUP)) {
-                       if (doit) {
-                               printf("%-*s  ", f1width[W_UID],
-                                                       uidname(f->uid));
-                       } else {
-                               maxise(&f1width[W_UID],
-                                               strlen(uidname(f->uid)));
-                               width+= 2;
-                       }
-               }
-               if (doit) {
-                       printf("%-*s  ", f1width[W_GID], gidname(f->gid));
-               } else {
-                       maxise(&f1width[W_GID], strlen(gidname(f->gid)));
-                       width+= 2;
-               }
-
-               switch (f->mode & S_IFMT) {
-               case S_IFBLK:
-               case S_IFCHR:
-#ifdef S_IFMPB
-               case S_IFMPB:
-#endif
-#ifdef S_IFMPC
-               case S_IFMPC:
-#endif
-#if __minix
-                       if (doit) {
-                               printf("%*d, %3d ", f1width[W_SIZE] - 5,
-                                       major(f->rdev), minor(f->rdev));
-                       } else {
-                               maxise(&f1width[W_SIZE],
-                                               numwidth(major(f->rdev)) + 5);
-                               width++;
-                       }
-#else /* !__minix */
-                       if (doit) {
-                               printf("%*lX ", f1width[W_SIZE],
-                                       (unsigned long) f->rdev);
-                       } else {
-                               maxise(&f1width[W_SIZE], numwidth(f->rdev));
-                               width++;
-                       }
-#endif /* !__minix */
-                       break;
-               default:
-                       if (field & L_KMG) {
-                               p= cxsize(f);
-                               n= strlen(p)+1;
-
-                               if (doit) {
-                                       n= f1width[W_SIZE] - n;
-                                       while (n > 0) { putchar(' '); --n; }
-                                       printf("%s ", p);
-                               } else {
-                                       maxise(&f1width[W_SIZE], n);
-                               }
-                       } else {
-                               if (doit) {
-                                       printf("%*lu ", f1width[W_SIZE],
-                                               (unsigned long) f->size);
-                               } else {
-                                       maxise(&f1width[W_SIZE],
-                                               numwidth(f->size));
-                                       width++;
-                               }
-                       }
-               }
-
-               if (doit) {
-                       printf("%s ", timestamp(f));
-               } else {
-                       width+= (field & L_LONGTIME) ? 21 : 13;
-               }
-       }
-
-       n= strlen(f->name);
-       if (doit) {
-               printname(f->name);
-               if (mark(f, 1) != 0) n++;
-#ifdef S_IFLNK
-               if ((field & L_LONG) && (f->mode & S_IFMT) == S_IFLNK) {
-                       char *buf;
-                       int r, didx;
-
-                       buf= (char *) allocate(((size_t) f->size + 1)
-                                                       * sizeof(buf[0]));
-                       addpath(&didx, f->name);
-                       r= readlink(path, buf, (int) f->size);
-                       delpath(didx);
-                       if (r > 0) buf[r] = 0; else r=1, strcpy(buf, "?");
-                       printf(" -> ");
-                       printname(buf);
-                       free((void *) buf);
-                       n+= 4 + r;
-               }
-#endif
-               spaces(f1width[W_NAME] - n);
-       } else {
-               if (mark(f, 0) != 0) n++;
-#ifdef S_IFLNK
-               if ((field & L_LONG) && (f->mode & S_IFMT) == S_IFLNK) {
-                       n+= 4 + (int) f->size;
-               }
-#endif
-               maxise(&f1width[W_NAME], n + NSEP);
-
-               for (n= 1; n < MAXFLDS; n++) width+= f1width[n];
-               maxise(&f1width[W_COL], width);
-       }
-}
-
-int countfiles(struct file *flist)
-/* Return number of files in the list. */
-{
-       int n= 0;
-
-       while (flist != nil) { n++; flist= flist->next; }
-
-       return n;
-}
-
-struct file *filecol[MAXCOLS]; /* filecol[i] is list of files for column i. */
-int nfiles, nlines;    /* # files to print, # of lines needed. */
-
-void columnise(struct file *flist, int nplin)
-/* Chop list of files up in columns.  Note that 3 columns are used for 5 files
- * even though nplin may be 4, filecol[3] will simply be nil.
- */
-{
-       int i, j;
-
-       nlines= (nfiles + nplin - 1) / nplin;   /* nlines needed for nfiles */
-
-       filecol[0]= flist;
-
-       for (i=1; i<nplin; i++) {       /* Give nlines files to each column. */
-               for (j=0; j<nlines && flist != nil; j++) flist= flist->next;
-
-               filecol[i]= flist;
-       }
-}
-
-int print(struct file *flist, int nplin, int doit)
-/* Try (doit == 0), or really print the list of files over nplin columns.
- * Return true if it can be done in nplin columns or if nplin == 1.
- */
-{
-       register struct file *f;
-       register int col, fld, totlen;
-
-       columnise(flist, nplin);
-
-       if (!doit) {
-               for (col= 0; col < nplin; col++) {
-                       for (fld= 0; fld < MAXFLDS; fld++) {
-                               fieldwidth[col][fld]= 0;
-                       }
-               }
-       }
-
-       while (--nlines >= 0) {
-               totlen= 0;
-
-               for (col= 0; col < nplin; col++) {
-                       if ((f= filecol[col]) != nil) {
-                               filecol[col]= f->next;
-                               print1(f, col, doit);
-                       }
-                       if (!doit && nplin > 1) {
-                               /* See if this line is not too long. */
-                               if (fieldwidth[col][W_COL] == UCHAR_MAX) {
-                                       return 0;
-                               }
-                               totlen+= fieldwidth[col][W_COL];
-                               if (totlen > ncols+NSEP) return 0;
-                       }
-               }
-               if (doit) terpri();
-       }
-       return 1;
-}
-
-enum depth { SURFACE, SURFACE1, SUBMERGED };
-enum state { BOTTOM, SINKING, FLOATING };
-
-void listfiles(struct file *flist, enum depth depth, enum state state)
-/* Main workhorse of ls, it sorts and prints the list of files.  Flags:
- * depth: working with the command line / just one file / listing dir.
- * state: How "recursive" do we have to be.
- */
-{
-       struct file *dlist= nil, **afl= &flist, **adl= &dlist;
-       int nplin;
-       static int white = 1;   /* Nothing printed yet. */
-
-       /* Flush everything previously printed, so new error output will
-        * not intermix with files listed earlier.
-        */
-       fflush(stdout);
-
-       if (field != 0 || state != BOTTOM) {    /* Need stat(2) info. */
-               while (*afl != nil) {
-                       static struct stat st;
-                       int r, didx;
-
-                       addpath(&didx, (*afl)->name);
-
-                       if ((r= status(path, &st)) < 0
-#ifdef S_IFLNK
-                               && (status == lstat || lstat(path, &st) < 0)
-#endif
-                       ) {
-                               if (depth != SUBMERGED || errno != ENOENT)
-                                       report((*afl)->name);
-                               delfile(popfile(afl));
-                       } else {
-                               setstat(*afl, &st);
-                               afl= &(*afl)->next;
-                       }
-                       delpath(didx);
-               }
-       }
-       sort(&flist);
-
-       if (depth == SUBMERGED && (field & (L_BLOCKS | L_LONG))) {
-               printf("total %d\n", nblk2k(countblocks(flist)));
-       }
-
-       if (state == SINKING || depth == SURFACE1) {
-       /* Don't list directories themselves, list their contents later. */
-               afl= &flist;
-               while (*afl != nil) {
-                       if (((*afl)->mode & S_IFMT) == S_IFDIR) {
-                               pushfile(adl, popfile(afl));
-                               adl= &(*adl)->next;
-                       } else {
-                               afl= &(*afl)->next;
-                       }
-               }
-       }
-
-       if ((nfiles= countfiles(flist)) > 0) {
-               /* Print files in how many columns? */
-               nplin= !present('C') ? 1 : nfiles < MAXCOLS ? nfiles : MAXCOLS;
-
-               while (!print(flist, nplin, 0)) nplin--;        /* Try first */
-
-               print(flist, nplin, 1);         /* Then do it! */
-               white = 0;
-       }
-
-       while (flist != nil) {  /* Destroy file list */
-               if (state == FLOATING && (flist->mode & S_IFMT) == S_IFDIR) {
-                       /* But keep these directories for ls -R. */
-                       pushfile(adl, popfile(&flist));
-                       adl= &(*adl)->next;
-               } else {
-                       delfile(popfile(&flist));
-               }
-       }
-
-       while (dlist != nil) {  /* List directories */
-               if (dotflag(dlist->name) != 'a' || depth != SUBMERGED) {
-                       int didx;
-
-                       addpath(&didx, dlist->name);
-
-                       flist= nil;
-                       if (adddir(&flist, path)) {
-                               if (depth != SURFACE1) {
-                                       if (!white) putchar('\n');
-                                       printf("%s:\n", path);
-                                       white = 0;
-                               }
-                               listfiles(flist, SUBMERGED,
-                                       state == FLOATING ? FLOATING : BOTTOM);
-                       }
-                       delpath(didx);
-               }
-               delfile(popfile(&dlist));
-       }
-}
-
-int main(int argc, char **argv)
-{
-       struct file *flist= nil, **aflist= &flist;
-       enum depth depth;
-       char *lsflags;
-       struct winsize ws;
-
-       uid= geteuid();
-       gid= getegid();
-
-       if ((arg0= strrchr(argv[0], '/')) == nil) arg0= argv[0]; else arg0++;
-       argv++;
-
-       if (strcmp(arg0, "ls") != 0) {
-               char *p= arg0+1;
-
-               while (*p != 0) {
-                       if (strchr(arg0flag, *p) != nil) *p += 'A' - 'a';
-                       p++;
-               }
-               setflags(arg0+1);
-       }
-       while (*argv != nil && (*argv)[0] == '-') {
-               if ((*argv)[1] == '-' && (*argv)[2] == 0) {
-                       argv++;
-                       break;
-               }
-               setflags(*argv++ + 1);
-       }
-
-       istty= isatty(1);
-
-       if (istty && (lsflags= getenv("LSOPTS")) != nil) {
-               if (*lsflags == '-') lsflags++;
-               setflags(lsflags);
-       }
-
-       if (!present('1') && !present('C') && !present('l')
-               && (istty || present('M') || present('X') || present('F'))
-       ) setflags("C");
-
-       if (istty) setflags("q");
-
-       if (SUPER_ID == 0 || present('a')) setflags("A");
-
-       if (present('i')) field|= L_INODE;
-       if (present('s')) field|= L_BLOCKS;
-       if (present('M')) field|= L_MODE;
-       if (present('X')) field|= L_EXTRA | L_MODE;
-       if (present('t')) field|= L_BYTIME;
-       if (present('u')) field|= L_ATIME;
-       if (present('c')) field|= L_CTIME;
-       if (present('l')) field|= L_MODE | L_LONG;
-       if (present('g')) field|= L_MODE | L_LONG | L_GROUP;
-       if (present('F')) field|= L_MARK;
-       if (present('p')) field|= L_MARKDIR;
-       if (present('D')) field|= L_TYPE;
-       if (present('T')) field|= L_MODE | L_LONG | L_LONGTIME;
-       if (present('d')) field|= L_DIR;
-       if (present('h')) field|= L_KMG;
-       if (field & L_LONG) field&= ~L_EXTRA;
-
-#ifdef S_IFLNK
-       status= present('L') ? stat : lstat;
-#endif
-
-       if (present('C')) {
-               int t= istty ? 1 : open("/dev/tty", O_WRONLY);
-
-               if (t >= 0 && ioctl(t, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0)
-                       ncols= ws.ws_col - 1;
-
-               if (t != 1 && t != -1) close(t);
-       }
-
-       depth= SURFACE;
-
-       if (*argv == nil) {
-               if (!(field & L_DIR)) depth= SURFACE1;
-               pushfile(aflist, newfile("."));
-       } else {
-               if (argv[1] == nil && !(field & L_DIR)) depth= SURFACE1;
-
-               do {
-                       pushfile(aflist, newfile(*argv++));
-                       aflist= &(*aflist)->next;
-               } while (*argv!=nil);
-       }
-       listfiles(flist, depth,
-               (field & L_DIR) ? BOTTOM : present('R') ? FLOATING : SINKING);
-       return ex;
-}
index 5d81eccf561a57ac2dc072bd65c6234f6883dda0..b3f8d382e5725f10630af51cd2b2abea5967363b 100644 (file)
@@ -58,8 +58,8 @@ PROG_DRIVERS+=        acpi
 .if ${MACHINE_ARCH} == "earm"
 EXTRA+=                rc.arm mylogin.sh ttys
 PROG_DRIVERS+= mmc tty gpio
-PROG_COMMANDS+=        cp dd getty ls time sync sleep stty umount
-PROG_BIN+=     cat rm
+PROG_COMMANDS+=        cp dd getty time sync sleep stty umount
+PROG_BIN+=     cat ls rm
 PROTO=         proto.arm.small
 .endif # ${MACHINE_ARCH} == "earm"
 
index effbb4861ff2b692e41f74c8a932048e879c97f0..aa405d5e974b794fb21c2c474ae79cd19655bef4 100644 (file)
@@ -9,7 +9,7 @@ MAN=    ash.1 at.1 banner.1 basename.1 \
        fsck.mfs.1 head.1 host.1 hostaddr.1 ifdef.1 \
        isodir.1 isoinfo.1 isoread.1 \
        last.1 loadfont.1 loadkeys.1 logger.1 \
-       look.1 lp.1 ls.1 lspci.1 mail.1  \
+       look.1 lp.1 lspci.1 mail.1  \
        mesg.1 mixer.1 mkfs.mfs.1 \
        mkproto.1 mount.1 mt.1 nice.1 nm.1 nohup.1 od.1 \
        paste.1 ping.1 playwave.1 pr.1 prep.1 \
diff --git a/man/man1/ls.1 b/man/man1/ls.1
deleted file mode 100644 (file)
index d1cc54c..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-.TH LS 1
-.SH NAME
-ls \- list the contents of a directory
-.SH SYNOPSIS
-\fBls\fP [\fB\-acdfghilnpqrstu1ACDFLMRTX\fP] [\fIname\fP...]
-.SH DESCRIPTION
-For each file argument, list it.  For each directory argument, list its
-contents.  The current working directory is listed when no files are named.
-Information is printed multicolumn on terminals, single column if the output
-is redirected.  The options control what information is shown and how.
-.PP
-.B Ls
-has two sources other then the command line to draw options from, one is
-the environment variable
-.B LSOPTS
-that is scanned for option letters when the output of
-.B ls
-is displayed on a terminal.  The other is the name of
-.B ls
-itself.  If
-.B ls
-is linked to another name, then all the characters after the l are used as
-flags too, except that d, f, r, t and x are translated to D, F, R, T and X.
-Useful links are
-.BR ll ,
-.BR lf ,
-.B lm
-and
-.BR lx .
-.PP
-Files whose names start with a dot are by default not listed.
-.PP
-Note that standard MINIX 3 doesn't have sockets, and
-.B \-u
-and
-.B \-c
-are no-ops on a V1 file system, since only modified times are stored in V1
-inodes.
-.SH OPTIONS
-.TP
-.B \-a
-All entries are listed, even
-.B .
-and
-.B ..
-.TP
-.B \-c
-Use inode changed time for sorting, listing or searching.
-.TP
-.B \-d
-Do not list contents of directories, but list the directory itself.
-.TP
-.B \-f
-Do not sort (should also be: treat a file as a directory, but that
-can't be implemented portably).
-.TP
-.B \-g
-Suppress the owner name on a long listing (implies
-.BR \-l ).
-.TP
-.B \-h
-Show file sizes in kilo, mega or gigabytes.
-.TP
-.B \-i
-I-node number printed in the first column.
-.TP
-.B \-l
-Long listing: mode, links, owner, group, size and time.
-.RB ( "ls \-lC"
-uses columns in a wide enough window!)
-.TP
-.B \-n
-Print numerical user and group id's.
-.TP
-.B \-p
-Mark directories with a '\fB/\fP'.
-.TP
-.B \-q
-Print nongraphic characters as '\fB?\fP' (default on terminals).
-.TP
-.B \-r
-Reverse the sort order.
-.TP
-.B \-s
-Give the size in kilobytes in the first
-.RB ( \-s )
-or second column
-.RB ( \-is ).
-.TP
-.B \-t
-Sort by time (modified time default), latest first.
-.TP
-.B \-u
-Use last accessed time for sorting, listing or searching.
-.TP
-.B \-1
-Print in one column.
-.TP
-.B \-A
-List all entries, but not
-.B .
-and
-.B ..
-(This is the default for privileged users.)
-.TP
-.B \-C
-Print multicolumn (default on terminals).
-.TP
-.B \-D
-Distinguish files by type, i.e. regular files together, directories
-together, etc.
-.TP
-.B \-F
-Mark directories with a '\fB/\fP', executables with a '\fB*\fP', \s-2UNIX\s+2
-domain sockets with a '\fB=\fP', named pipes with a '\fB|\fP' and symbolic
-links with a '\fB@\fP' behind the name.
-.TP
-.B \-L
-Print the file referenced by a symbolic link instead of the link.
-.TP
-.B \-M
-List mode before name (implies
-.BR \-C ).
-.TP
-.B \-R
-List directory trees recursively.
-.TP
-.B \-T
-Print file times in a long format, e.g. "Oct 24 21:37:41 1996".
-.TP
-.B \-X
-Print crunched mode and size before name (implies
-.BR \-C ).
-Only the rwx permissions that its caller has on the file are shown, but they
-are in upper case if the caller owns the file and has given the permission
-to the callers group or other users.  The size is listed in bytes (<= 5K),
-or rounded up kilo, mega or gigabytes.
-.SH "SEE ALSO"
-.BR du (1),
-.BR stat (1),
-.BR stat (2).
-.SH BUGS
-Having to type
-.B ls \-C
-when viewing files through
-.BR more (1).
-.PP
-Is only portable to systems with the same
-.B st_mode
-(see
-.BR stat (2)).
-.PP
-The
-.B LSOPTS
-variable and the
-.BR -D ,
-.B -M
-and
-.B -X
-flags are not found on other
-.B ls
-implementations.  (They have their own nonstandard flags.)
-.SH AUTHOR
-Kees J. Bot <kjb@cs.vu.nl>
index c08df40d54d849e0f7421760e0277f834654931f..416d22364416fc8fe2a09e604d69abe9a55cea31 100644 (file)
@@ -13,6 +13,7 @@
 2012/10/17 12:00:00,bin/expr
 2012/10/17 12:00:00,bin/kill
 2012/10/17 12:00:00,bin/ln
+2012/10/17 12:00:00,bin/ls
 2012/10/17 12:00:00,bin/Makefile
 2012/10/17 12:00:00,bin/Makefile.inc
 2008/07/20 00:52:40,bin/mkdir