Upgrading ls

Change-Id: Ie0bacf04e727fac5c6df7b2bcf5039e9ce800616
This commit is contained in:
Lionel Sambuc 2013-01-30 19:06:57 +01:00
parent b7ea9f3fd1
commit b7ef8cfb52
16 changed files with 2241 additions and 1330 deletions

10
bin/ls/Makefile Normal file
View file

@ -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>

199
bin/ls/cmp.c Normal file
View file

@ -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));
}

53
bin/ls/extern.h Normal file
View file

@ -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 *);

510
bin/ls/ls.1 Normal file
View file

@ -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 .

701
bin/ls/ls.c Normal file
View file

@ -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));
}

79
bin/ls/ls.h Normal file
View file

@ -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;

52
bin/ls/main.c Normal file
View file

@ -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 */
}

464
bin/ls/print.c Normal file
View file

@ -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);
}

168
bin/ls/util.c Normal file
View file

@ -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;
}

View 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 \

View file

@ -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>

File diff suppressed because it is too large Load diff

View 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"

View 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 \

View file

@ -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>

View 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