Add ls from 4.4BSD-Lite Release 2
authorJason Self <j@jxself.org>
Mon, 10 Jun 2019 00:00:27 +0000 (17:00 -0700)
committerJason Self <j@jxself.org>
Mon, 10 Jun 2019 00:00:27 +0000 (17:00 -0700)
Signed-off-by: Jason Self <j@jxself.org>
usr/src/bin/ls/Makefile [new file with mode: 0644]
usr/src/bin/ls/cmp.c [new file with mode: 0644]
usr/src/bin/ls/extern.h [new file with mode: 0644]
usr/src/bin/ls/ls.1 [new file with mode: 0644]
usr/src/bin/ls/ls.c [new file with mode: 0644]
usr/src/bin/ls/ls.h [new file with mode: 0644]
usr/src/bin/ls/print.c [new file with mode: 0644]
usr/src/bin/ls/stat_flags.c [new file with mode: 0644]
usr/src/bin/ls/util.c [new file with mode: 0644]

diff --git a/usr/src/bin/ls/Makefile b/usr/src/bin/ls/Makefile
new file mode 100644 (file)
index 0000000..dd9036b
--- /dev/null
@@ -0,0 +1,6 @@
+#      @(#)Makefile    8.1 (Berkeley) 6/2/93
+
+PROG=  ls
+SRCS=  cmp.c stat_flags.c ls.c print.c util.c
+
+.include <bsd.prog.mk>
diff --git a/usr/src/bin/ls/cmp.c b/usr/src/bin/ls/cmp.c
new file mode 100644 (file)
index 0000000..42d2bcd
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)cmp.c      8.1 (Berkeley) 5/31/93";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <fts.h>
+#include <string.h>
+
+#include "ls.h"
+#include "extern.h"
+
+int
+namecmp(a, b)
+       const FTSENT *a, *b;
+{
+       return (strcmp(a->fts_name, b->fts_name));
+}
+
+int
+revnamecmp(a, b)
+       const FTSENT *a, *b;
+{
+       return (strcmp(b->fts_name, a->fts_name));
+}
+
+int
+modcmp(a, b)
+       const FTSENT *a, *b;
+{
+       return (b->fts_statp->st_mtime - a->fts_statp->st_mtime);
+}
+
+int
+revmodcmp(a, b)
+       const FTSENT *a, *b;
+{
+       return (a->fts_statp->st_mtime - b->fts_statp->st_mtime);
+}
+
+int
+acccmp(a, b)
+       const FTSENT *a, *b;
+{
+       return (b->fts_statp->st_atime - a->fts_statp->st_atime);
+}
+
+int
+revacccmp(a, b)
+       const FTSENT *a, *b;
+{
+       return (a->fts_statp->st_atime - b->fts_statp->st_atime);
+}
+
+int
+statcmp(a, b)
+       const FTSENT *a, *b;
+{
+       return (b->fts_statp->st_ctime - a->fts_statp->st_ctime);
+}
+
+int
+revstatcmp(a, b)
+       const FTSENT *a, *b;
+{
+       return (a->fts_statp->st_ctime - b->fts_statp->st_ctime);
+}
diff --git a/usr/src/bin/ls/extern.h b/usr/src/bin/ls/extern.h
new file mode 100644 (file)
index 0000000..b4e8a37
--- /dev/null
@@ -0,0 +1,46 @@
+/*-
+ * 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 __P((const FTSENT *, const FTSENT *));
+int     revacccmp __P((const FTSENT *, const FTSENT *));
+int     modcmp __P((const FTSENT *, const FTSENT *));
+int     revmodcmp __P((const FTSENT *, const FTSENT *));
+int     namecmp __P((const FTSENT *, const FTSENT *));
+int     revnamecmp __P((const FTSENT *, const FTSENT *));
+int     statcmp __P((const FTSENT *, const FTSENT *));
+int     revstatcmp __P((const FTSENT *, const FTSENT *));
+
+char   *flags_to_string __P((u_long, char *));
+void    prcopy __P((char *, char *, int));
+void    printcol __P((DISPLAY *));
+void    printlong __P((DISPLAY *));
+void    printscol __P((DISPLAY *));
+void    usage __P((void));
diff --git a/usr/src/bin/ls/ls.1 b/usr/src/bin/ls/ls.1
new file mode 100644 (file)
index 0000000..fd503ed
--- /dev/null
@@ -0,0 +1,334 @@
+.\" 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 July 29, 1994
+.Dt LS 1
+.Os
+.Sh NAME
+.Nm ls
+.Nd list directory contents
+.Sh SYNOPSIS
+.Nm ls
+.Op Fl ACFLRTWacdfiloqrstu1
+.Op Ar file ...
+.Sh DESCRIPTION
+For each operand that names a
+.Ar file
+of a type other than
+directory,
+.Nm ls
+displays its name as well as any requested,
+associated information.
+For each operand that names a
+.Ar file
+of type directory,
+.Nm ls
+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 C
+Force multi-column output; this is the default when output is to a terminal.
+.It Fl F
+Display a slash (/) immediately after each pathname
+that is a directory, an asterisk (*) after each that is
+executable,
+an at sign (@) after each symbolic link,
+and a percent sign (%) after each whiteout.
+.\" and a vertical bar (|) after each that is a
+.\" .Tn FIFO . 
+.It Fl L
+If argument is a symbolic link, list the file or directory the link references
+rather than the link itself.
+.It Fl R
+Recursively list subdirectories encountered.
+.It Fl T
+Display complete time information for the file, including
+month, day, hour, minute, second, and year.
+.It Fl W
+Display whiteouts when scanning directories.
+.It Fl a
+Include directory entries whose names begin with a
+dot (.).
+.It Fl c
+Use time when file status was last changed for sorting or printing.
+.It Fl d
+Directories are listed as plain files (not searched recursively) and
+symbolic links in the argument list are not indirected through.
+.It Fl f
+Output is not sorted.
+.It Fl i
+For each file, print the file's file serial number (inode number).
+.It Fl l
+(The lowercase letter ``ell.'')  List in long format. (See below.)
+If the output is to a terminal, a total sum for all the file
+sizes is output on a line before the long listing.
+.It Fl o
+Include the file flags in a long
+.Pq Fl l
+output
+.It Fl q
+Force printing of non-graphic characters in file names as
+the character `?'; this is the default when output is to a terminal.
+.It Fl r
+Reverse the order of the sort to get reverse
+lexicographical order or the oldest entries first.
+.It Fl s
+Display the number of file system blocks actually used by each file, in units
+of 512 bytes, 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
+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 \&1
+(The numeric digit ``one.'')  Force output to be
+one entry per line.
+This is the default when
+output is not to a terminal.
+.El
+.Pp
+The
+.Fl 1 ,
+.Fl C ,
+and
+.Fl l
+options all override each other; the last one specified determines
+the format used.
+.Pp
+The
+.Fl c ,
+and
+.Fl u
+options override each other; the last one specified determines
+the file time used.
+.Pp
+By default,
+.Nm ls
+lists one entry per line to standard
+output; the exceptions are to terminals or when the
+.Fl C
+option is specified.
+.Pp
+File information is displayed with one or more
+<blank>s 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:
+file mode,
+number of links, owner name, group name,
+number of bytes in the file, abbreviated
+month, day-of-month file was last modified,
+hour file last modified, minute file last
+modified, and the pathname.
+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 user or group name
+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 \-> .
+.Pp
+The file mode printed under the -l option consists of the
+entry type, owner permissions, and group permissions.
+The entry type character describes the type of file, as
+follows:
+.Pp
+.Bl -tag -width 4n -offset indent -compact
+.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
+.\" .Tn 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, writeable, 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 8 . )
+.It Sy t
+The sticky bit is set (mode
+.Li 1000 ) ,
+and is searchable or executable.
+(See
+.Xr chmod 1
+or
+.Xr sticky 8 . )
+.El
+.El
+.Pp
+The
+.Nm ls
+utility exits 0 on success, and >0 if an error occurs.
+.Sh ENVIRONMENTAL VARIABLES
+The following environment variables affect the execution of
+.Nm ls :
+.Bl -tag -width BLOCKSIZE
+.It Ev BLOCKSIZE
+If the environmental variable
+.Ev BLOCKSIZE
+is set, the block counts
+(see
+.Fl s )
+will be displayed in units of that size block.
+.It 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 ls
+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 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 chmod 1 ,
+.Xr symlink 7 ,
+.Xr sticky 8
+.Sh HISTORY
+An
+.Nm ls
+command appeared in
+.At v6 .
+.Sh STANDARDS
+The
+.Nm ls
+function is expected to be a superset of the
+.St -p1003.2
+specification.
diff --git a/usr/src/bin/ls/ls.c b/usr/src/bin/ls/ls.c
new file mode 100644 (file)
index 0000000..fc35f71
--- /dev/null
@@ -0,0 +1,514 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1993, 1994\n\
+       The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)ls.c       8.7 (Berkeley) 8/5/94";
+#endif /* not lint */
+
+#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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "ls.h"
+#include "extern.h"
+
+static void     display __P((FTSENT *, FTSENT *));
+static int      mastercmp __P((const FTSENT **, const FTSENT **));
+static void     traverse __P((int, char **, int));
+
+static void (*printfcn) __P((DISPLAY *));
+static int (*sortfcn) __P((const FTSENT *, const FTSENT *));
+
+long blocksize;                        /* block size units */
+int termwidth = 80;            /* default terminal width */
+
+/* flags */
+int f_accesstime;              /* use time of last access */
+int f_column;                  /* columnated format */
+int f_flags;                   /* show flags associated with a file */
+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_newline;                 /* if precede with newline */
+int f_nonprint;                        /* show unprintables as ? */
+int f_nosort;                  /* don't sort output */
+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_dirname;                 /* if precede with directory name */
+int f_timesort;                        /* sort by time vice name */
+int f_type;                    /* add type character for non-regular files */
+int f_whiteout;                        /* show whiteout entries */
+
+int
+main(argc, argv)
+       int argc;
+       char *argv[];
+{
+       static char dot[] = ".", *dotav[] = { dot, NULL };
+       struct winsize win;
+       int ch, fts_options, notused;
+       char *p;
+
+       /* Terminal defaults to -Cq, non-terminal defaults to -1. */
+       if (isatty(STDOUT_FILENO)) {
+               if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &win) == -1 ||
+                   !win.ws_col) {
+                       if ((p = getenv("COLUMNS")) != NULL)
+                               termwidth = atoi(p);
+               }
+               else
+                       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, "1ACFLRTWacdfgiloqrstu")) != EOF) {
+               switch (ch) {
+               /*
+                * The -1, -C and -l options all override each other so shell
+                * aliasing works right.
+                */
+               case '1':
+                       f_singlecol = 1;
+                       f_column = f_longform = 0;
+                       break;
+               case 'C':
+                       f_column = 1;
+                       f_longform = f_singlecol = 0;
+                       break;
+               case 'l':
+                       f_longform = 1;
+                       f_column = f_singlecol = 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 -d option turns off the -R option. */
+               case 'd':
+                       f_listdir = 1;
+                       f_recursive = 0;
+                       break;
+               case 'f':
+                       f_nosort = 1;
+                       break;
+               case 'g':               /* Compatibility with 4.3BSD. */
+                       break;
+               case 'i':
+                       f_inode = 1;
+                       break;
+               case 'o':
+                       f_flags = 1;
+                       break;
+               case 'q':
+                       f_nonprint = 1;
+                       break;
+               case 'r':
+                       f_reversesort = 1;
+                       break;
+               case 's':
+                       f_size = 1;
+                       break;
+               case 'T':
+                       f_sectime = 1;
+                       break;
+               case 't':
+                       f_timesort = 1;
+                       break;
+               case 'W':
+                       f_whiteout = 1;
+                       break;
+               default:
+               case '?':
+                       usage();
+               }
+       }
+       argc -= optind;
+       argv += optind;
+
+       /*
+        * If not -F, -i, -l, -s or -t options, don't require stat
+        * information.
+        */
+       if (!f_inode && !f_longform && !f_size && !f_timesort && !f_type)
+               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_longform || f_size) {
+               (void)getbsize(&notused, &blocksize);
+               blocksize /= 512;
+       }
+
+       /* Select a sort function. */
+       if (f_reversesort) {
+               if (!f_timesort)
+                       sortfcn = revnamecmp;
+               else if (f_accesstime)
+                       sortfcn = revacccmp;
+               else if (f_statustime)
+                       sortfcn = revstatcmp;
+               else /* Use modification time. */
+                       sortfcn = revmodcmp;
+       } else {
+               if (!f_timesort)
+                       sortfcn = namecmp;
+               else if (f_accesstime)
+                       sortfcn = acccmp;
+               else if (f_statustime)
+                       sortfcn = statcmp;
+               else /* Use modification time. */
+                       sortfcn = modcmp;
+       }
+
+       /* Select a print function. */
+       if (f_singlecol)
+               printfcn = printscol;
+       else if (f_longform)
+               printfcn = printlong;
+       else
+               printfcn = printcol;
+
+       if (argc)
+               traverse(argc, argv, fts_options);
+       else
+               traverse(1, dotav, fts_options);
+       exit(0);
+}
+
+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(argc, argv, options)
+       int argc, options;
+       char *argv[];
+{
+       FTS *ftsp;
+       FTSENT *p, *chp;
+       int ch_options;
+
+       if ((ftsp =
+           fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL)
+               err(1, NULL);
+
+       display(NULL, fts_children(ftsp, 0));
+       if (f_listdir)
+               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));
+                       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;
+               }
+       if (errno)
+               err(1, "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(p, list)
+       FTSENT *p, *list;
+{
+       struct stat *sp;
+       DISPLAY d;
+       FTSENT *cur;
+       NAMES *np;
+       u_quad_t maxsize;
+       u_long btotal, maxblock, maxinode, maxlen, maxnlink;
+       int bcfile, flen, glen, ulen, maxflags, maxgroup, maxuser;
+       int entries, needstats;
+       char *user, *group, *flags, buf[20];    /* 32 bits == 10 digits */
+
+       /*
+        * 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;
+       btotal = maxblock = maxinode = maxlen = maxnlink = 0;
+       bcfile = 0;
+       maxuser = maxgroup = maxflags = 0;
+       maxsize = 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;
+                       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 (f_nonprint)
+                       prcopy(cur->fts_name, cur->fts_name, cur->fts_namelen);
+               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;
+
+                       btotal += sp->st_blocks;
+                       if (f_longform) {
+                               user = user_from_uid(sp->st_uid, 0);
+                               if ((ulen = strlen(user)) > maxuser)
+                                       maxuser = ulen;
+                               group = group_from_gid(sp->st_gid, 0);
+                               if ((glen = strlen(group)) > maxgroup)
+                                       maxgroup = glen;
+                               if (f_flags) {
+                                       flags =
+                                           flags_to_string(sp->st_flags, "-");
+                                       if ((flen = strlen(flags)) > maxflags)
+                                               maxflags = flen;
+                               } else
+                                       flen = 0;
+
+                               if ((np = malloc(sizeof(NAMES) +
+                                   ulen + glen + flen + 3)) == NULL)
+                                       err(1, NULL);
+
+                               np->user = &np->data[0];
+                               (void)strcpy(np->user, user);
+                               np->group = &np->data[ulen + 1];
+                               (void)strcpy(np->group, group);
+
+                               if (S_ISCHR(sp->st_mode) ||
+                                   S_ISBLK(sp->st_mode))
+                                       bcfile = 1;
+
+                               if (f_flags) {
+                                       np->flags = &np->data[ulen + glen + 2];
+                                       (void)strcpy(np->flags, flags);
+                               }
+                               cur->fts_pointer = np;
+                       }
+               }
+               ++entries;
+       }
+
+       if (!entries)
+               return;
+
+       d.list = list;
+       d.entries = entries;
+       d.maxlen = maxlen;
+       if (needstats) {
+               d.bcfile = bcfile;
+               d.btotal = btotal;
+               (void)snprintf(buf, sizeof(buf), "%lu", maxblock);
+               d.s_block = strlen(buf);
+               d.s_flags = maxflags;
+               d.s_group = maxgroup;
+               (void)snprintf(buf, sizeof(buf), "%lu", maxinode);
+               d.s_inode = strlen(buf);
+               (void)snprintf(buf, sizeof(buf), "%lu", maxnlink);
+               d.s_nlink = strlen(buf);
+               (void)snprintf(buf, sizeof(buf), "%qu", maxsize);
+               d.s_size = strlen(buf);
+               d.s_user = maxuser;
+       }
+
+       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(a, b)
+       const FTSENT **a, **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)
+               return (namecmp(*a, *b));
+
+       if (a_info == b_info)
+               return (sortfcn(*a, *b));
+
+       if ((*a)->fts_level == FTS_ROOTLEVEL)
+               if (a_info == FTS_D)
+                       return (1);
+               else if (b_info == FTS_D)
+                       return (-1);
+               else
+                       return (sortfcn(*a, *b));
+       else
+               return (sortfcn(*a, *b));
+}
diff --git a/usr/src/bin/ls/ls.h b/usr/src/bin/ls/ls.h
new file mode 100644 (file)
index 0000000..f8c8d4a
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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_inode;            /* print inode */
+extern int f_longform;         /* long listing format */
+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 */
+
+typedef struct {
+       FTSENT *list;
+       u_long btotal;
+       int bcfile;
+       int entries;
+       int maxlen;
+       int s_block;
+       int s_flags;
+       int s_group;
+       int s_inode;
+       int s_nlink;
+       int s_size;
+       int s_user;
+} DISPLAY;
+
+typedef struct {
+       char *user;
+       char *group;
+       char *flags;
+       char data[1];
+} NAMES;
diff --git a/usr/src/bin/ls/print.c b/usr/src/bin/ls/print.c
new file mode 100644 (file)
index 0000000..82dc21c
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)print.c    8.5 (Berkeley) 7/28/94";
+#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 <utmp.h>
+
+#include "ls.h"
+#include "extern.h"
+
+static int     printaname __P((FTSENT *, u_long, u_long));
+static void    printlink __P((FTSENT *));
+static void    printtime __P((time_t));
+static int     printtype __P((u_int));
+
+#define        IS_NOPRINT(p)   ((p)->fts_number == NO_PRINT)
+
+void
+printscol(dp)
+       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(dp)
+       DISPLAY *dp;
+{
+       struct stat *sp;
+       FTSENT *p;
+       NAMES *np;
+       char buf[20];
+
+       if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
+               (void)printf("total %lu\n", howmany(dp->btotal, blocksize));
+
+       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, sp->st_ino);
+               if (f_size)
+                       (void)printf("%*qd ",
+                           dp->s_block, howmany(sp->st_blocks, blocksize));
+               (void)strmode(sp->st_mode, buf);
+               np = p->fts_pointer;
+               (void)printf("%s %*u %-*s  %-*s  ", buf, dp->s_nlink,
+                   sp->st_nlink, dp->s_user, np->user, 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("%3d, %3d ",
+                           major(sp->st_rdev), minor(sp->st_rdev));
+               else if (dp->bcfile)
+                       (void)printf("%*s%*qd ",
+                           8 - dp->s_size, "", dp->s_size, sp->st_size);
+               else
+                       (void)printf("%*qd ", dp->s_size, sp->st_size);
+               if (f_accesstime)
+                       printtime(sp->st_atime);
+               else if (f_statustime)
+                       printtime(sp->st_ctime);
+               else
+                       printtime(sp->st_mtime);
+               (void)printf("%s", p->fts_name);
+               if (f_type)
+                       (void)printtype(sp->st_mode);
+               if (S_ISLNK(sp->st_mode))
+                       printlink(p);
+               (void)putchar('\n');
+       }
+}
+
+#define        TAB     8
+
+void
+printcol(dp)
+       DISPLAY *dp;
+{
+       extern int termwidth;
+       static FTSENT **array;
+       static int lastentries = -1;
+       FTSENT *p;
+       int base, chcnt, cnt, col, colwidth, num;
+       int endcol, numcols, numrows, row;
+
+       /*
+        * Have to do random access in the linked list -- build a table
+        * of pointers.
+        */
+       if (dp->entries > lastentries) {
+               lastentries = dp->entries;
+               if ((array =
+                   realloc(array, dp->entries * sizeof(FTSENT *))) == NULL) {
+                       warn(NULL);
+                       printscol(dp);
+               }
+       }
+       for (p = dp->list, num = 0; p; p = p->fts_link)
+               if (p->fts_number != NO_PRINT)
+                       array[num++] = p;
+
+       colwidth = dp->maxlen;
+       if (f_inode)
+               colwidth += dp->s_inode + 1;
+       if (f_size)
+               colwidth += dp->s_block + 1;
+       if (f_type)
+               colwidth += 1;
+
+       colwidth = (colwidth + TAB) & ~(TAB - 1);
+       if (termwidth < 2 * colwidth) {
+               printscol(dp);
+               return;
+       }
+
+       numcols = termwidth / colwidth;
+       numrows = num / numcols;
+       if (num % numcols)
+               ++numrows;
+
+       if (dp->list->fts_level != FTS_ROOTLEVEL && (f_longform || f_size))
+               (void)printf("total %lu\n", howmany(dp->btotal, blocksize));
+       for (row = 0; row < numrows; ++row) {
+               endcol = colwidth;
+               for (base = row, chcnt = col = 0; col < numcols; ++col) {
+                       chcnt += printaname(array[base], dp->s_inode,
+                           dp->s_block);
+                       if ((base += numrows) >= num)
+                               break;
+                       while ((cnt = (chcnt + TAB & ~(TAB - 1))) <= endcol) {
+                               (void)putchar('\t');
+                               chcnt = cnt;
+                       }
+                       endcol += colwidth;
+               }
+               (void)putchar('\n');
+       }
+}
+
+/*
+ * print [inode] [size] name
+ * return # of characters printed, no trailing characters.
+ */
+static int
+printaname(p, inodefield, sizefield)
+       FTSENT *p;
+       u_long sizefield, inodefield;
+{
+       struct stat *sp;
+       int chcnt;
+
+       sp = p->fts_statp;
+       chcnt = 0;
+       if (f_inode)
+               chcnt += printf("%*lu ", (int)inodefield, sp->st_ino);
+       if (f_size)
+               chcnt += printf("%*qd ",
+                   (int)sizefield, howmany(sp->st_blocks, blocksize));
+       chcnt += printf("%s", p->fts_name);
+       if (f_type)
+               chcnt += printtype(sp->st_mode);
+       return (chcnt);
+}
+
+static void
+printtime(ftime)
+       time_t ftime;
+{
+       int i;
+       char *longstring;
+
+       longstring = ctime(&ftime);
+       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 > time(NULL))
+               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(' ');
+}
+
+static int
+printtype(mode)
+       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(p)
+       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(" -> %s", path);
+}
diff --git a/usr/src/bin/ls/stat_flags.c b/usr/src/bin/ls/stat_flags.c
new file mode 100644 (file)
index 0000000..6dc7503
--- /dev/null
@@ -0,0 +1,149 @@
+/*-
+ * Copyright (c) 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)stat_flags.c       8.2 (Berkeley) 7/28/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <stddef.h>
+#include <string.h>
+
+#define        SAPPEND(s) {                                                    \
+       if (prefix != NULL)                                             \
+               (void)strcat(string, prefix);                           \
+       (void)strcat(string, s);                                        \
+       prefix = ",";                                                   \
+}
+
+/*
+ * flags_to_string --
+ *     Convert stat flags to a comma-separated string.  If no flags
+ *     are set, return the default string.
+ */
+char *
+flags_to_string(flags, def)
+       u_long flags;
+       char *def;
+{
+       static char string[128];
+       char *prefix;
+
+       string[0] = '\0';
+       prefix = NULL;
+       if (flags & UF_APPEND)
+               SAPPEND("uappnd");
+       if (flags & UF_IMMUTABLE)
+               SAPPEND("uchg");
+       if (flags & UF_NODUMP)
+               SAPPEND("nodump");
+       if (flags & UF_OPAQUE)
+               SAPPEND("opaque");
+       if (flags & SF_APPEND)
+               SAPPEND("sappnd");
+       if (flags & SF_ARCHIVED)
+               SAPPEND("arch");
+       if (flags & SF_IMMUTABLE)
+               SAPPEND("schg");
+       return (prefix == NULL && def != NULL ? def : string);
+}
+
+#define        TEST(a, b, f) {                                                 \
+       if (!memcmp(a, b, sizeof(b))) {                                 \
+               if (clear) {                                            \
+                       if (clrp)                                       \
+                               *clrp |= (f);                           \
+               } else if (setp)                                        \
+                       *setp |= (f);                                   \
+               break;                                                  \
+       }                                                               \
+}
+
+/*
+ * string_to_flags --
+ *     Take string of arguments and return stat flags.  Return 0 on
+ *     success, 1 on failure.  On failure, stringp is set to point
+ *     to the offending token.
+ */
+int
+string_to_flags(stringp, setp, clrp)
+       char **stringp;
+       u_long *setp, *clrp;
+{
+       int clear;
+       char *string, *p;
+
+       clear = 0;
+       if (setp)
+               *setp = 0;
+       if (clrp)
+               *clrp = 0;
+       string = *stringp;
+       while ((p = strsep(&string, "\t ,")) != NULL) {
+               *stringp = p;
+               if (*p == '\0')
+                       continue;
+               if (p[0] == 'n' && p[1] == 'o') {
+                       clear = 1;
+                       p += 2;
+               }
+               switch (p[0]) {
+               case 'a':
+                       TEST(p, "arch", SF_ARCHIVED);
+                       TEST(p, "archived", SF_ARCHIVED);
+                       return (1);
+               case 'd':
+                       clear = !clear;
+                       TEST(p, "dump", UF_NODUMP);
+                       return (1);
+               case 'o':
+                       TEST(p, "opaque", UF_OPAQUE);
+                       return (1);
+               case 's':
+                       TEST(p, "sappnd", SF_APPEND);
+                       TEST(p, "sappend", SF_APPEND);
+                       TEST(p, "schg", SF_IMMUTABLE);
+                       TEST(p, "schange", SF_IMMUTABLE);
+                       TEST(p, "simmutable", SF_IMMUTABLE);
+                       return (1);
+               case 'u':
+                       TEST(p, "uappnd", UF_APPEND);
+                       TEST(p, "uappend", UF_APPEND);
+                       TEST(p, "uchg", UF_IMMUTABLE);
+                       TEST(p, "uchange", UF_IMMUTABLE);
+                       TEST(p, "uimmutable", UF_IMMUTABLE);
+                       /* FALLTHROUGH */
+               default:
+                       return (1);
+               }
+       }
+       return (0);
+}
diff --git a/usr/src/bin/ls/util.c b/usr/src/bin/ls/util.c
new file mode 100644 (file)
index 0000000..ae9a2a3
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)util.c     8.5 (Berkeley) 4/28/95";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "ls.h"
+#include "extern.h"
+
+void
+prcopy(src, dest, len)
+       char *src, *dest;
+       int len;
+{
+       int ch;
+
+       while (len--) {
+               ch = *src++;
+               *dest++ = isprint(ch) ? ch : '?';
+       }
+}
+
+void
+usage()
+{
+       (void)fprintf(stderr,
+           "usage: ls [-1ACFLRTWacdfikloqrstu] [file ...]\n");
+       exit(1);
+}