nls.c revision 20120a7c0174b82c10a30ab711e93ffd8619096b
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1987, 1988 Microsoft Corporation */
/* All Rights Reserved */
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* List files or directories
*/
#define _FILE_OFFSET_BITS 64
#include <wchar.h>
#include <stdio.h>
#include <ctype.h>
#include <dirent.h>
#include <string.h>
#include <locale.h>
#include <curses.h>
#include <termios.h>
#include <stdlib.h>
#include <widec.h>
#include <locale.h>
#include <wctype.h>
#include <pwd.h>
#include <grp.h>
#include <limits.h>
#include <unistd.h>
#include <libgen.h>
#ifndef STANDALONE
#define TERMINFO
#endif
/*
* -DNOTERMINFO can be defined on the cc command line to prevent
* the use of terminfo. This should be done on systems not having
* the terminfo feature(pre 6.0 sytems ?).
* As a result, columnar listings assume 80 columns for output,
* unless told otherwise via the COLUMNS environment variable.
*/
#ifdef NOTERMINFO
#endif
#include <term.h>
#define BFSIZE 16
/* this bit equals 1 in lflags of structure lbuf if *namep is to be used */
#define ISARG 0100000
/*
* Date and time formats
*
* b --- abbreviated month name
* e --- day number
* Y --- year in the form ccyy
* H --- hour(24-hour version)
* M --- minute
*/
#define FORMAT1 " %b %e %Y "
#define FORMAT2 " %b %e %H:%M "
#define FORMAT3 " %b %e %H:%M %Y "
#define BUFSIZ 4096
struct lbuf {
union {
char *namep; /* for name in ls-command; */
} ln;
char ltype; /* filetype */
char *flinkto; /* symbolic link contents */
char acl; /* indicate there are additional acl entries */
};
struct dchain {
char *dc_name; /* path name */
};
static char *curdir; /* the current directory */
static int nfiles = 0; /* number of flist entries in current use */
static int nargs = 0; /* number of flist entries used for arguments */
static int maxn = 0; /* number of flist entries with lbufs asigned */
static char *makename(char *, char *);
static void column(void);
static void selection(int *);
static void new_line(void);
static void rddir(char *);
static int strcol(unsigned char *);
static void pdirectory(char *, int, int);
static void csi_pprintf(unsigned char *);
static void pprintf(char *, char *);
static int Aflg;
static int err = 0; /* Contains return code */
static int statreq; /* is > 0 if any of sflg, (n)lflg, tflg are on */
static char *dotp = ".";
static int num_cols = 80;
static int colwidth;
static int filewidth;
static int fixedwidth;
static int nomocore;
static int curcol;
int
{
int c;
int i;
int width;
int amino = 0;
int opterr = 0;
#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
#endif
(void) textdomain(TEXT_DOMAIN);
#ifdef STANDALONE
if (argv[0][0] == '\0')
#endif
if (isatty(1)) {
Cflg = 1;
mflg = 0;
}
switch (c) {
case 'R':
Rflg++;
statreq++;
continue;
case 'A':
Aflg++;
continue;
case 'a':
aflg++;
continue;
case 'd':
dflg++;
continue;
case 'C':
Cflg = 1;
mflg = 0;
#ifdef XPG4
lflg = 0;
#endif
continue;
case '1':
Cflg = 0;
continue;
case 'x':
xflg = 1;
Cflg = 1;
mflg = 0;
#ifdef XPG4
lflg = 0;
#endif
continue;
case 'm':
Cflg = 0;
mflg = 1;
#ifdef XPG4
lflg = 0;
#endif
continue;
case 'n':
nflg++;
/* FALLTHROUGH */
case 'l':
lflg++;
statreq++;
Cflg = 0;
xflg = 0;
mflg = 0;
continue;
case 'o':
oflg++;
lflg++;
statreq++;
continue;
case 'g':
gflg++;
lflg++;
statreq++;
continue;
case 'r':
rflg = -1;
continue;
case 't':
tflg++;
statreq++;
continue;
case 'u':
cflg = 0;
uflg++;
continue;
case 'c':
uflg = 0;
cflg++;
continue;
case 'p':
pflg++;
statreq++;
continue;
case 'F':
Fflg++;
statreq++;
continue;
case 'b':
bflg = 1;
qflg = 0;
continue;
case 'q':
qflg = 1;
bflg = 0;
continue;
case 'i':
iflg++;
continue;
case 's':
sflg++;
statreq++;
continue;
case 'f':
fflg++;
continue;
case 'L':
Lflg++;
continue;
case '?':
opterr++;
continue;
}
if (opterr) {
"usage: ls -1RaAdCxmnlogrtucpFbqisfL [files]\n"));
return (2);
}
if (fflg) {
aflg++;
lflg = 0;
sflg = 0;
tflg = 0;
statreq = 0;
}
fixedwidth = 2;
fixedwidth++;
if (iflg)
fixedwidth += 11;
if (sflg)
fixedwidth += 5;
if (lflg) {
else
}
char *clptr;
#ifdef TERMINFO
else {
}
#endif
/* assume it is an error */
num_cols = 80;
}
/* allocate space for flist and the associated */
/* data structures (lbufs) */
perror("ls");
return (2);
}
/*
* case when no names are given
* in ls-command and current
* directory is to be used
*/
}
}
== NULL) {
if (nomocore)
return (2);
err = 2;
optind++;
continue;
}
optind++;
nargs++; /* count good arguments stored in flist */
}
(int (*)(const void *, const void *))compar);
for (i = 0; i < nargs; i++) {
break;
}
for (; i < nargs; i++) {
if (nomocore)
return (2);
/* -R: print subdirectories found */
/* Place direct subdirs on front in right order */
while (cdfirst) {
/* reverse cdfirst onto front of dfirst */
}
/* take off first dir on dfirst & print it */
if (nomocore)
return (2);
}
}
return (err);
}
/*
* pdirectory: print the directory name, labelling it if title is
* nonzero, using lp as the place to start reading in the dir.
*/
static void
{
char *pname;
int j;
filewidth = 0;
if (title) {
if (!first)
new_line();
}
if (nomocore)
return;
if (fflg == 0)
sizeof (struct lbuf *),
(int (*)(const void *, const void *))compar);
if (Rflg)
sizeof (struct dchain));
perror("ls");
exit(2);
}
perror("ls");
exit(2);
}
}
}
}
/*
* pem: print 'em. Print a list of files (e.g. a directory) bounded
* by slp and lp.
*/
static void
{
ncols = 1;
} else {
}
}
new_line();
return;
}
/* otherwise print -C columns */
if (tot_flag)
slp--;
}
new_line();
}
}
/*
* print one output entry;
*/
static void
{
struct lbuf *p;
char *cp;
p = ap;
column();
if (iflg)
else
: "%llu ", p->lnum);
if (sflg)
if (lflg) {
curcol++;
/* ACL: additional access mode flag */
curcol++;
if (oflg)
if (!nflg) {
} else
if (gflg)
if (!nflg) {
} else
} else {
}
}
/*
* prevent both "->" and trailing marks
* from appearing
*/
dmark = "/";
if (p->ltype == 'd')
dmark = "/";
else if (p->ltype == 'D')
dmark = ">";
else if (p->ltype == 'p')
dmark = "|";
else if (p->ltype == 'l')
dmark = "@";
else if (p->ltype == 's')
dmark = "=";
dmark = "*";
else
dmark = "";
}
}
else {
}
} else {
else {
}
}
}
/* print various r,w,x permissions */
static void
{
/* these arrays are declared static to allow initializations */
#ifdef XPG4
#else
#endif
int **mp;
}
static void
{
int n;
n = *pairp++;
while (n-->0) {
pairp++;
break;
} else {
pairp += 2;
}
}
curcol++;
}
/*
* column: get to the beginning of the next column.
*/
static void
column(void)
{
if (curcol == 0)
return;
if (mflg) {
curcol++;
curcol = 0;
return;
}
curcol++;
return;
}
if (Cflg == 0) {
curcol = 0;
return;
}
curcol = 0;
return;
}
do {
curcol++;
}
static void
new_line(void)
{
if (curcol) {
first = 0;
curcol = 0;
}
}
/*
* read each filename in directory dir and store its
* status in flist[nfiles]
*/
static void
{
int j;
int width;
err = 2;
return;
} else {
tblocks = 0;
(Aflg == 0 ||
/*
* check for directory items '.', '..',
* and items without valid inode-number;
*/
continue;
}
if (nomocore)
return;
continue;
} else {
}
}
}
}
/*
* get status of file and recomputes tblocks;
* argfl = 1 if file is a name in ls-command and = 0
* for filename in a directory whose name is an
* argument in the command;
* stores a pointer in flist[nfiles] and
* returns that pointer;
* returns NULL if failed;
*/
static struct lbuf *
{
int cc;
if (nomocore)
return (NULL);
/*
* more space
*/
perror("ls");
nomocore = 1;
return (NULL);
}
}
/*
* nfiles is reset to nargs for each directory
* that is given as an argument maxn is checked
* to prevent the assignment of an lbuf to a flist entry
* that already has one assigned.
*/
} else {
}
int doacl;
if (lflg)
doacl = 1;
else
doacl = 0;
nfiles--;
return (NULL);
}
case S_IFDIR:
break;
case S_IFBLK:
break;
case S_IFCHR:
break;
case S_IFIFO:
break;
case S_IFSOCK:
break;
case S_IFLNK:
/* symbolic links may not have ACLs, so elide acl() */
if (Lflg == 0)
doacl = 0;
if (lflg) {
if (cc >= 0) {
/*
* follow the symbolic link
* to generate the appropriate
* Fflg marker for the object
*/
S_IFMT) {
case S_IFDIR:
break;
case S_IFSOCK:
break;
default:
~S_IFMT) &
S_IXOTH))
break;
}
}
}
break;
}
/*
* ls /sym behaves differently from ls /sym/
* when /sym is a symbolic link. This is fixed
* when explicit arguments are specified.
*/
break;
}
break;
case S_IFDOOR:
break;
case S_IFREG:
break;
default:
break;
}
/* ACL: check acl entries count */
else
/* mask ISARG and other file-type bits */
if (uflg)
else if (cflg)
else
}
return (rep);
}
/*
* dir is a null-terminated string;
*/
static char *
{
/*
* dfile is static as this is returned by makename().
*/
while (*fp)
*dp++ = '/';
while (*fp)
*dp = '\0';
return (dfile);
}
#include <pwd.h>
#include <grp.h>
#include <utmpx.h>
struct cachenode { /* this struct must be zeroed before using */
long val; /* the uid or gid of this entry */
int initted; /* name has been filled in */
};
static struct cachenode *
{
while (c != NULL) {
/* found it */
return (c);
c = c->lesschild;
} else {
c = c->grtrchild;
}
}
/* not in the cache, make a new entry for it */
if (c == NULL) {
perror("ls");
exit(2);
}
*parent = c;
return (c);
}
/*
* get name from cache, or passwd file for a given uid;
* lastuid is set to uid.
*/
static char *
{
struct cachenode *c;
return (lastuname);
if (c->initted == 0) {
} else {
}
c->initted = 1;
}
return (lastuname);
}
/*
* get name from cache, or group file for a given gid;
* lastgid is set to gid.
*/
static char *
{
struct cachenode *c;
return (lastgname);
if (c->initted == 0) {
} else {
}
c->initted = 1;
}
return (lastgname);
}
/* return >0 if item pointed by pp2 should appear first */
static int
{
if (dflg == 0) {
/*
* compare two names in ls-command one of which is file
* and the other is a directory;
* this portion is not used for comparing files within
* a directory name of ls-command;
*/
return (1);
} else {
return (-1);
}
}
if (tflg) {
return (rflg);
return (-rflg);
/* if times are equal, fall through and sort by name */
}
}
static void
{
csi_pprintf((unsigned char *)s1);
csi_pprintf((unsigned char *)s2);
}
static void
csi_pprintf(unsigned char *s)
{
unsigned char *cp;
char c;
int i;
int c_len;
int p_col;
curcol++;
}
return;
}
if (!isprint(c)) {
if (qflg) {
c = '?';
} else {
curcol += 3;
}
}
curcol++;
cp++;
continue;
}
c_len = 1;
goto not_print;
}
continue;
}
for (i = 0; i < c_len; i++) {
if (qflg) {
c = '?';
} else {
curcol += 3;
}
curcol++;
cp++;
}
}
}
static int
{
int w;
int w_col;
int len;
w = 0;
while (*s1) {
w++;
s1++;
continue;
}
w++;
s1++;
continue;
}
w += w_col;
}
return (w);
}