Changeset View
Changeset View
Standalone View
Standalone View
head/bin/ls/ls.c
Show First 20 Lines • Show All 62 Lines • ▼ Show 20 Lines | |||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include <string.h> | #include <string.h> | ||||
#include <unistd.h> | #include <unistd.h> | ||||
#ifdef COLORLS | #ifdef COLORLS | ||||
#include <termcap.h> | #include <termcap.h> | ||||
#include <signal.h> | #include <signal.h> | ||||
#endif | #endif | ||||
#include <libxo/xo.h> | |||||
#include "ls.h" | #include "ls.h" | ||||
#include "extern.h" | #include "extern.h" | ||||
/* | /* | ||||
* Upward approximation of the maximum number of characters needed to | * Upward approximation of the maximum number of characters needed to | ||||
* represent a value of integral type t as a string, excluding the | * represent a value of integral type t as a string, excluding the | ||||
* NUL terminator, with provision for a sign. | * NUL terminator, with provision for a sign. | ||||
Show All 36 Lines | |||||
static int f_listdir; /* list actual directory, not contents */ | static int f_listdir; /* list actual directory, not contents */ | ||||
static int f_listdot; /* list files beginning with . */ | static int f_listdot; /* list files beginning with . */ | ||||
int f_longform; /* long listing format */ | int f_longform; /* long listing format */ | ||||
static int f_noautodot; /* do not automatically enable -A for root */ | static int f_noautodot; /* do not automatically enable -A for root */ | ||||
static int f_nofollow; /* don't follow symbolic link arguments */ | static int f_nofollow; /* don't follow symbolic link arguments */ | ||||
int f_nonprint; /* show unprintables as ? */ | int f_nonprint; /* show unprintables as ? */ | ||||
static int f_nosort; /* don't sort output */ | static int f_nosort; /* don't sort output */ | ||||
int f_notabs; /* don't use tab-separated multi-col output */ | int f_notabs; /* don't use tab-separated multi-col output */ | ||||
int f_numericonly; /* don't convert uid/gid to name */ | static int f_numericonly; /* don't convert uid/gid to name */ | ||||
int f_octal; /* show unprintables as \xxx */ | int f_octal; /* show unprintables as \xxx */ | ||||
int f_octal_escape; /* like f_octal but use C escapes if possible */ | int f_octal_escape; /* like f_octal but use C escapes if possible */ | ||||
static int f_recursive; /* ls subdirectories also */ | static int f_recursive; /* ls subdirectories also */ | ||||
static int f_reversesort; /* reverse whatever sort is used */ | static int f_reversesort; /* reverse whatever sort is used */ | ||||
int f_samesort; /* sort time and name in same direction */ | int f_samesort; /* sort time and name in same direction */ | ||||
int f_sectime; /* print full time information */ | int f_sectime; /* print full time information */ | ||||
static int f_singlecol; /* use single column output */ | static int f_singlecol; /* use single column output */ | ||||
int f_size; /* list size in short listing */ | int f_size; /* list size in short listing */ | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
if (errstr) | if (errstr) | ||||
termwidth = 80; | termwidth = 80; | ||||
fts_options = FTS_PHYSICAL; | fts_options = FTS_PHYSICAL; | ||||
if (getenv("LS_SAMESORT")) | if (getenv("LS_SAMESORT")) | ||||
f_samesort = 1; | f_samesort = 1; | ||||
argc = xo_parse_args(argc, argv); | |||||
if (argc < 0) | |||||
return (1); | |||||
xo_set_flags(NULL, XOF_COLUMNS); | |||||
xo_set_version(LS_XO_VERSION); | |||||
while ((ch = getopt(argc, argv, | while ((ch = getopt(argc, argv, | ||||
"1ABCD:FGHILPRSTUWXZabcdfghiklmnopqrstuwxy,")) != -1) { | "1ABCD:FGHILPRSTUWXZabcdfghiklmnopqrstuwxy,")) != -1) { | ||||
switch (ch) { | switch (ch) { | ||||
/* | /* | ||||
* The -1, -C, -x and -l options all override each other so | * The -1, -C, -x and -l options all override each other so | ||||
* shell aliasing works right. | * shell aliasing works right. | ||||
*/ | */ | ||||
case '1': | case '1': | ||||
▲ Show 20 Lines • Show All 180 Lines • ▼ Show 20 Lines | if (tgetent(termcapbuf, getenv("TERM")) == 1) { | ||||
* don't do colours at all. */ | * don't do colours at all. */ | ||||
ansi_coloff = tgetstr("op", &bp); | ansi_coloff = tgetstr("op", &bp); | ||||
if (!ansi_coloff) | if (!ansi_coloff) | ||||
ansi_coloff = tgetstr("oc", &bp); | ansi_coloff = tgetstr("oc", &bp); | ||||
if (ansi_fgcol && ansi_bgcol && ansi_coloff) | if (ansi_fgcol && ansi_bgcol && ansi_coloff) | ||||
f_color = 1; | f_color = 1; | ||||
} | } | ||||
#else | #else | ||||
xo_warnx("color support not compiled in"); | warnx("color support not compiled in"); | ||||
#endif /*COLORLS*/ | #endif /*COLORLS*/ | ||||
#ifdef COLORLS | #ifdef COLORLS | ||||
if (f_color) { | if (f_color) { | ||||
/* | /* | ||||
* We can't put tabs and color sequences together: | * We can't put tabs and color sequences together: | ||||
* column number will be incremented incorrectly | * column number will be incremented incorrectly | ||||
* for "stty oxtabs" mode. | * for "stty oxtabs" mode. | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | if (f_singlecol) | ||||
printfcn = printscol; | printfcn = printscol; | ||||
else if (f_longform) | else if (f_longform) | ||||
printfcn = printlong; | printfcn = printlong; | ||||
else if (f_stream) | else if (f_stream) | ||||
printfcn = printstream; | printfcn = printstream; | ||||
else | else | ||||
printfcn = printcol; | printfcn = printcol; | ||||
xo_open_container("file-information"); | |||||
if (argc) | if (argc) | ||||
traverse(argc, argv, fts_options); | traverse(argc, argv, fts_options); | ||||
else | else | ||||
traverse(1, dotav, fts_options); | traverse(1, dotav, fts_options); | ||||
xo_close_container("file-information"); | |||||
xo_finish(); | |||||
exit(rval); | exit(rval); | ||||
} | } | ||||
static int output; /* If anything output. */ | static int output; /* If anything output. */ | ||||
/* | /* | ||||
* Traverse() walks the logical directory structure specified by the argv list | * Traverse() walks the logical directory structure specified by the argv list | ||||
* in the order specified by the mastercmp() comparison function. During the | * in the order specified by the mastercmp() comparison function. During the | ||||
* traversal it passes linked lists of structures to display() which represent | * traversal it passes linked lists of structures to display() which represent | ||||
* a superset (may be exact set) of the files to be displayed. | * a superset (may be exact set) of the files to be displayed. | ||||
*/ | */ | ||||
static void | static void | ||||
traverse(int argc, char *argv[], int options) | traverse(int argc, char *argv[], int options) | ||||
{ | { | ||||
FTS *ftsp; | FTS *ftsp; | ||||
FTSENT *p, *chp; | FTSENT *p, *chp; | ||||
int ch_options; | int ch_options; | ||||
int first = 1; | |||||
if ((ftsp = | if ((ftsp = | ||||
fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) | fts_open(argv, options, f_nosort ? NULL : mastercmp)) == NULL) | ||||
xo_err(1, "fts_open"); | err(1, "fts_open"); | ||||
/* | /* | ||||
* We ignore errors from fts_children here since they will be | * We ignore errors from fts_children here since they will be | ||||
* replicated and signalled on the next call to fts_read() below. | * replicated and signalled on the next call to fts_read() below. | ||||
*/ | */ | ||||
chp = fts_children(ftsp, 0); | chp = fts_children(ftsp, 0); | ||||
if (chp != NULL) | if (chp != NULL) | ||||
display(NULL, chp, options); | display(NULL, chp, options); | ||||
if (f_listdir) | if (f_listdir) | ||||
return; | return; | ||||
/* | /* | ||||
* If not recursing down this tree and don't need stat info, just get | * If not recursing down this tree and don't need stat info, just get | ||||
* the names. | * the names. | ||||
*/ | */ | ||||
ch_options = !f_recursive && !f_label && | ch_options = !f_recursive && !f_label && | ||||
options & FTS_NOSTAT ? FTS_NAMEONLY : 0; | options & FTS_NOSTAT ? FTS_NAMEONLY : 0; | ||||
while ((p = fts_read(ftsp)) != NULL) | while ((p = fts_read(ftsp)) != NULL) | ||||
switch (p->fts_info) { | switch (p->fts_info) { | ||||
case FTS_DC: | case FTS_DC: | ||||
xo_warnx("%s: directory causes a cycle", p->fts_name); | warnx("%s: directory causes a cycle", p->fts_name); | ||||
break; | break; | ||||
case FTS_DNR: | case FTS_DNR: | ||||
case FTS_ERR: | case FTS_ERR: | ||||
xo_warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); | warnx("%s: %s", p->fts_path, strerror(p->fts_errno)); | ||||
rval = 1; | rval = 1; | ||||
break; | break; | ||||
case FTS_D: | case FTS_D: | ||||
if (p->fts_level != FTS_ROOTLEVEL && | if (p->fts_level != FTS_ROOTLEVEL && | ||||
p->fts_name[0] == '.' && !f_listdot) | p->fts_name[0] == '.' && !f_listdot) | ||||
break; | break; | ||||
if (first) { | |||||
first = 0; | |||||
xo_open_list("directory"); | |||||
} | |||||
xo_open_instance("directory"); | |||||
/* | /* | ||||
* If already output something, put out a newline as | * If already output something, put out a newline as | ||||
* a separator. If multiple arguments, precede each | * a separator. If multiple arguments, precede each | ||||
* directory with its name. | * directory with its name. | ||||
*/ | */ | ||||
if (output) { | if (output) { | ||||
xo_emit("\n"); | putchar('\n'); | ||||
(void)printname("path", p->fts_path); | (void)printname(p->fts_path); | ||||
xo_emit(":\n"); | puts(":"); | ||||
} else if (argc > 1) { | } else if (argc > 1) { | ||||
(void)printname("path", p->fts_path); | (void)printname(p->fts_path); | ||||
xo_emit(":\n"); | puts(":"); | ||||
output = 1; | output = 1; | ||||
} | } | ||||
chp = fts_children(ftsp, ch_options); | chp = fts_children(ftsp, ch_options); | ||||
display(p, chp, options); | display(p, chp, options); | ||||
xo_close_instance("directory"); | |||||
if (!f_recursive && chp != NULL) | if (!f_recursive && chp != NULL) | ||||
(void)fts_set(ftsp, p, FTS_SKIP); | (void)fts_set(ftsp, p, FTS_SKIP); | ||||
break; | break; | ||||
default: | default: | ||||
break; | break; | ||||
} | } | ||||
if (!first) | |||||
xo_close_list("directory"); | |||||
if (errno) | if (errno) | ||||
xo_err(1, "fts_read"); | err(1, "fts_read"); | ||||
} | } | ||||
/* | /* | ||||
* Display() takes a linked list of FTSENT structures and passes the list | * Display() takes a linked list of FTSENT structures and passes the list | ||||
* along with any other necessary information to the print function. P | * along with any other necessary information to the print function. P | ||||
* points to the parent directory of the display list. | * points to the parent directory of the display list. | ||||
*/ | */ | ||||
static void | static void | ||||
Show All 30 Lines | display(const FTSENT *p, FTSENT *list, int options) | ||||
maxinode = 0; | maxinode = 0; | ||||
if (initmax != NULL && *initmax != '\0') { | if (initmax != NULL && *initmax != '\0') { | ||||
char *initmax2, *jinitmax; | char *initmax2, *jinitmax; | ||||
int ninitmax; | int ninitmax; | ||||
/* Fill-in "::" as "0:0:0" for the sake of scanf. */ | /* Fill-in "::" as "0:0:0" for the sake of scanf. */ | ||||
jinitmax = malloc(strlen(initmax) * 2 + 2); | jinitmax = malloc(strlen(initmax) * 2 + 2); | ||||
if (jinitmax == NULL) | if (jinitmax == NULL) | ||||
xo_err(1, "malloc"); | err(1, "malloc"); | ||||
initmax2 = jinitmax; | initmax2 = jinitmax; | ||||
if (*initmax == ':') | if (*initmax == ':') | ||||
strcpy(initmax2, "0:"), initmax2 += 2; | strcpy(initmax2, "0:"), initmax2 += 2; | ||||
else | else | ||||
*initmax2++ = *initmax, *initmax2 = '\0'; | *initmax2++ = *initmax, *initmax2 = '\0'; | ||||
for (initmax++; *initmax != '\0'; initmax++) { | for (initmax++; *initmax != '\0'; initmax++) { | ||||
if (initmax[-1] == ':' && initmax[0] == ':') { | if (initmax[-1] == ':' && initmax[0] == ':') { | ||||
*initmax2++ = '0'; | *initmax2++ = '0'; | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | #endif | ||||
MAKENINES(maxsize); | MAKENINES(maxsize); | ||||
free(jinitmax); | free(jinitmax); | ||||
} | } | ||||
d.s_size = 0; | d.s_size = 0; | ||||
sizelen = 0; | sizelen = 0; | ||||
flags = NULL; | flags = NULL; | ||||
for (cur = list, entries = 0; cur; cur = cur->fts_link) { | for (cur = list, entries = 0; cur; cur = cur->fts_link) { | ||||
if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { | if (cur->fts_info == FTS_ERR || cur->fts_info == FTS_NS) { | ||||
xo_warnx("%s: %s", | warnx("%s: %s", | ||||
cur->fts_name, strerror(cur->fts_errno)); | cur->fts_name, strerror(cur->fts_errno)); | ||||
cur->fts_number = NO_PRINT; | cur->fts_number = NO_PRINT; | ||||
rval = 1; | rval = 1; | ||||
continue; | continue; | ||||
} | } | ||||
/* | /* | ||||
* P is NULL if list is the argv list, to which different rules | * P is NULL if list is the argv list, to which different rules | ||||
* apply. | * apply. | ||||
▲ Show 20 Lines • Show All 49 Lines • ▼ Show 20 Lines | if (needstats) { | ||||
maxgroup = glen; | maxgroup = glen; | ||||
if (f_flags) { | if (f_flags) { | ||||
flags = fflagstostr(sp->st_flags); | flags = fflagstostr(sp->st_flags); | ||||
if (flags != NULL && *flags == '\0') { | if (flags != NULL && *flags == '\0') { | ||||
free(flags); | free(flags); | ||||
flags = strdup("-"); | flags = strdup("-"); | ||||
} | } | ||||
if (flags == NULL) | if (flags == NULL) | ||||
xo_err(1, "fflagstostr"); | err(1, "fflagstostr"); | ||||
flen = strlen(flags); | flen = strlen(flags); | ||||
if (flen > (size_t)maxflags) | if (flen > (size_t)maxflags) | ||||
maxflags = flen; | maxflags = flen; | ||||
} else | } else | ||||
flen = 0; | flen = 0; | ||||
labelstr = NULL; | labelstr = NULL; | ||||
if (f_label) { | if (f_label) { | ||||
char name[PATH_MAX + 1]; | char name[PATH_MAX + 1]; | ||||
mac_t label; | mac_t label; | ||||
int error; | int error; | ||||
error = mac_prepare_file_label(&label); | error = mac_prepare_file_label(&label); | ||||
if (error == -1) { | if (error == -1) { | ||||
xo_warn("MAC label for %s/%s", | warn("MAC label for %s/%s", | ||||
cur->fts_parent->fts_path, | cur->fts_parent->fts_path, | ||||
cur->fts_name); | cur->fts_name); | ||||
goto label_out; | goto label_out; | ||||
} | } | ||||
if (cur->fts_level == FTS_ROOTLEVEL) | if (cur->fts_level == FTS_ROOTLEVEL) | ||||
snprintf(name, sizeof(name), | snprintf(name, sizeof(name), | ||||
"%s", cur->fts_name); | "%s", cur->fts_name); | ||||
else | else | ||||
snprintf(name, sizeof(name), | snprintf(name, sizeof(name), | ||||
"%s/%s", cur->fts_parent-> | "%s/%s", cur->fts_parent-> | ||||
fts_accpath, cur->fts_name); | fts_accpath, cur->fts_name); | ||||
if (options & FTS_LOGICAL) | if (options & FTS_LOGICAL) | ||||
error = mac_get_file(name, | error = mac_get_file(name, | ||||
label); | label); | ||||
else | else | ||||
error = mac_get_link(name, | error = mac_get_link(name, | ||||
label); | label); | ||||
if (error == -1) { | if (error == -1) { | ||||
xo_warn("MAC label for %s/%s", | warn("MAC label for %s/%s", | ||||
cur->fts_parent->fts_path, | cur->fts_parent->fts_path, | ||||
cur->fts_name); | cur->fts_name); | ||||
mac_free(label); | mac_free(label); | ||||
goto label_out; | goto label_out; | ||||
} | } | ||||
error = mac_to_text(label, | error = mac_to_text(label, | ||||
&labelstr); | &labelstr); | ||||
if (error == -1) { | if (error == -1) { | ||||
xo_warn("MAC label for %s/%s", | warn("MAC label for %s/%s", | ||||
cur->fts_parent->fts_path, | cur->fts_parent->fts_path, | ||||
cur->fts_name); | cur->fts_name); | ||||
mac_free(label); | mac_free(label); | ||||
goto label_out; | goto label_out; | ||||
} | } | ||||
mac_free(label); | mac_free(label); | ||||
label_out: | label_out: | ||||
if (labelstr == NULL) | if (labelstr == NULL) | ||||
labelstr = strdup("-"); | labelstr = strdup("-"); | ||||
labelstrlen = strlen(labelstr); | labelstrlen = strlen(labelstr); | ||||
if (labelstrlen > maxlabelstr) | if (labelstrlen > maxlabelstr) | ||||
maxlabelstr = labelstrlen; | maxlabelstr = labelstrlen; | ||||
} else | } else | ||||
labelstrlen = 0; | labelstrlen = 0; | ||||
if ((np = malloc(sizeof(NAMES) + labelstrlen + | if ((np = malloc(sizeof(NAMES) + labelstrlen + | ||||
ulen + glen + flen + 4)) == NULL) | ulen + glen + flen + 4)) == NULL) | ||||
xo_err(1, "malloc"); | err(1, "malloc"); | ||||
np->user = &np->data[0]; | np->user = &np->data[0]; | ||||
(void)strcpy(np->user, user); | (void)strcpy(np->user, user); | ||||
np->group = &np->data[ulen + 1]; | np->group = &np->data[ulen + 1]; | ||||
(void)strcpy(np->group, group); | (void)strcpy(np->group, group); | ||||
if (S_ISCHR(sp->st_mode) || | if (S_ISCHR(sp->st_mode) || | ||||
S_ISBLK(sp->st_mode)) { | S_ISBLK(sp->st_mode)) { | ||||
▲ Show 20 Lines • Show All 89 Lines • Show Last 20 Lines |