summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--coreutils/ls.c141
1 files changed, 64 insertions, 77 deletions
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 75d7b1f33..ac2557a55 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -83,15 +83,15 @@ enum {
/* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */
/* what file information will be listed */
-#define LIST_INO (1U<<0)
-#define LIST_BLOCKS (1U<<1)
+#define LIST_INO (1U<<0)
+#define LIST_BLOCKS (1U<<1)
#define LIST_MODEBITS (1U<<2)
-#define LIST_NLINKS (1U<<3)
+#define LIST_NLINKS (1U<<3)
#define LIST_ID_NAME (1U<<4)
#define LIST_ID_NUMERIC (1U<<5)
#define LIST_CONTEXT (1U<<6)
-#define LIST_SIZE (1U<<7)
-#define LIST_DEV (1U<<8)
+#define LIST_SIZE (1U<<7)
+#define LIST_DEV (1U<<8)
#define LIST_DATE_TIME (1U<<9)
#define LIST_FULLTIME (1U<<10)
#define LIST_FILENAME (1U<<11)
@@ -103,22 +103,22 @@ enum {
/* what files will be displayed */
/* TODO -- We may be able to make DISP_NORMAL 0 to save a bit slot. */
-#define DISP_NORMAL (1U<<14) /* show normal filenames */
+#define DISP_NORMAL (1U<<14) /* show normal filenames */
#define DISP_DIRNAME (1U<<15) /* 2 or more items? label directories */
-#define DISP_HIDDEN (1U<<16) /* show filenames starting with . */
-#define DISP_DOT (1U<<17) /* show . and .. */
-#define DISP_NOLIST (1U<<18) /* show directory as itself, not contents */
+#define DISP_HIDDEN (1U<<16) /* show filenames starting with . */
+#define DISP_DOT (1U<<17) /* show . and .. */
+#define DISP_NOLIST (1U<<18) /* show directory as itself, not contents */
#define DISP_RECURSIVE (1U<<19) /* show directory and everything below it */
-#define DISP_ROWS (1U<<20) /* print across rows */
+#define DISP_ROWS (1U<<20) /* print across rows */
#define DISP_MASK (((DISP_ROWS << 1) - 1) & ~(DISP_NORMAL - 1))
#ifdef CONFIG_FEATURE_LS_SORTFILES
/* how will the files be sorted */
-#define SORT_ORDER_FORWARD 0 /* sort in reverse order */
+#define SORT_ORDER_FORWARD 0 /* sort in reverse order */
#define SORT_ORDER_REVERSE (1U<<27) /* sort in reverse order */
-#define SORT_NAME 0 /* sort by file name */
+#define SORT_NAME 0 /* sort by file name */
#define SORT_SIZE (1U<<28) /* sort by file size */
#define SORT_ATIME (2U<<28) /* sort by last access time */
#define SORT_CTIME (3U<<28) /* sort by last change time */
@@ -170,25 +170,25 @@ static int show_color = 0;
/* long option entry used only for --color, which has no short option
* equivalent. */
-static int got_color_opt;
static struct option ls_color_opt[] =
{
- {"color", optional_argument, &got_color_opt, 1},
+ {"color", optional_argument, NULL, 1},
{NULL, 0, NULL, 0}
};
#define COLOR(mode) ("\000\043\043\043\042\000\043\043"\
- "\000\000\044\000\043\000\000\040" [TYPEINDEX(mode)])
+ "\000\000\044\000\043\000\000\040" [TYPEINDEX(mode)])
#define ATTR(mode) ("\00\00\01\00\01\00\01\00"\
- "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)])
+ "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)])
#endif
/*
* a directory entry and its stat info are stored here
*/
struct dnode { /* the basic node */
- char *name; /* the dir entry name */
+ char *name; /* the dir entry name */
char *fullname; /* the dir entry name */
+ int allocated;
struct stat dstat; /* the file stat info */
#ifdef CONFIG_SELINUX
security_context_t sid;
@@ -235,8 +235,7 @@ static struct dnode *my_stat(char *fullname, char *name)
}
#endif
rc = stat(fullname, &dstat);
- if(rc)
- {
+ if(rc) {
bb_perror_msg("%s", fullname);
status = EXIT_FAILURE;
return 0;
@@ -251,8 +250,7 @@ static struct dnode *my_stat(char *fullname, char *name)
}
#endif
rc = lstat(fullname, &dstat);
- if(rc)
- {
+ if(rc) {
bb_perror_msg("%s", fullname);
status = EXIT_FAILURE;
return 0;
@@ -320,11 +318,10 @@ static int count_dirs(struct dnode **dn, int nfiles, int notsubdirs)
dirs = 0;
for (i = 0; i < nfiles; i++) {
if (S_ISDIR(dn[i]->dstat.st_mode)
- && (notsubdirs
- || ((dn[i]->name[0] != '.')
- || (dn[i]->name[1]
+ && (notsubdirs ||
+ ((dn[i]->name[0] != '.') || (dn[i]->name[1]
&& ((dn[i]->name[1] != '.')
- || dn[i]->name[2])))))
+ || dn[i]->name[2])))))
dirs++;
}
return (dirs);
@@ -352,8 +349,7 @@ static struct dnode **dnalloc(int num)
if (num < 1)
return (NULL);
- p = (struct dnode **) xcalloc((size_t) num,
- (size_t) (sizeof(struct dnode *)));
+ p = (struct dnode **) xcalloc((size_t) num, (size_t) (sizeof(struct dnode *)));
return (p);
}
@@ -367,7 +363,8 @@ static void dfree(struct dnode **dnp)
cur = dnp[0];
while (cur != NULL) {
- free(cur->fullname); /* free the filename */
+ if(cur->allocated)
+ free(cur->fullname); /* free the filename */
next = cur->next;
free(cur); /* free the dnode */
cur = next;
@@ -622,6 +619,7 @@ static struct dnode **list_dir(const char *path)
cur = my_stat(fullname, strrchr(fullname, '/') + 1);
if (!cur)
continue;
+ cur->allocated = 1;
cur->next = dn;
dn = cur;
nfiles++;
@@ -756,7 +754,7 @@ static int list_single(struct dnode *dn)
safe_strncpy(context, dn->sid, len);
freecon(dn->sid);
}else {
- safe_strncpy(context, "unknown",8);
+ safe_strncpy(context, "unknown", 8);
}
printf("%-32s ", context);
column += MAX(33, len);
@@ -952,6 +950,9 @@ static const unsigned opt_flags[] = {
#ifdef CONFIG_SELINUX
LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */
#endif
+#ifdef CONFIG_FEATURE_AUTOWIDTH
+ 0, 0, /* T, w - ignored */
+#endif
(1U<<31)
};
@@ -977,6 +978,9 @@ extern int ls_main(int argc, char **argv)
char *tabstops_str = NULL;
char *terminal_width_str = NULL;
#endif
+#ifdef CONFIG_FEATURE_LS_COLOR
+ char *color_opt;
+#endif
all_fmt = LIST_SHORT | DISP_NORMAL | STYLE_AUTO
#ifdef CONFIG_FEATURE_LS_TIMESTAMPS
@@ -1000,7 +1004,11 @@ extern int ls_main(int argc, char **argv)
/* process options */
#ifdef CONFIG_FEATURE_AUTOWIDTH
- opt = bb_getopt_ulflags(argc, argv, ls_options, &tabstops_str, &terminal_width_str);
+ opt = bb_getopt_ulflags(argc, argv, ls_options, &tabstops_str, &terminal_width_str
+#ifdef CONFIG_FEATURE_LS_COLOR
+ , &color_opt
+#endif
+ );
if (tabstops_str) {
tabstops = atoi(tabstops_str);
}
@@ -1008,11 +1016,16 @@ extern int ls_main(int argc, char **argv)
terminal_width = atoi(terminal_width_str);
}
#else
- opt = bb_getopt_ulflags(argc, argv, ls_options);
+ opt = bb_getopt_ulflags(argc, argv, ls_options
+#ifdef CONFIG_FEATURE_LS_COLOR
+ , &color_opt
+#endif
+ );
#endif
for (i = 0; opt_flags[i] != (1U<<31); i++) {
if (opt & (1 << i)) {
unsigned int flags = opt_flags[i];
+
if (flags & LIST_MASK_TRIGGER) {
all_fmt &= ~LIST_MASK;
}
@@ -1045,51 +1058,28 @@ extern int ls_main(int argc, char **argv)
}
#ifdef CONFIG_FEATURE_LS_COLOR
- if (got_color_opt) {
- /* there is no way for bb_getopt_ulflags() to
- * return us the argument string for long options
- * which don't have a short option equivalent.
- * all we can find out is that the option was
- * present, and we have to rescan to find the
- * argument string.
- */
- got_color_opt=0;
- optind = 1;
- while ((i = getopt_long (argc, argv, ls_options,
- ls_color_opt, NULL)) >= 0) {
- if (i != 0) continue;
- if (got_color_opt) {
- if (!optarg || strcmp("always", optarg) == 0)
- show_color = 1;
- else if (strcmp("never", optarg) == 0)
- show_color = 0;
- else if (strcmp("auto", optarg) == 0 &&
- isatty(STDOUT_FILENO))
- show_color = 1;
-
- /* don't break; want to a) pick up repeated
- * --color options, and b) leave optind
- * set correctly when we're done.
- */
- got_color_opt = 0;
- }
- }
+ {
+ /* find color bit value - last position for short getopt */
+
#if CONFIG_FEATURE_LS_COLOR_IS_DEFAULT
- } else {
- /* if no option set by user, then this config option
- * forces "auto", which is what busybox 1.00 and previous
- * did. however, provide one more "out" for users that
- * don't want color: if LS_COLOR is set, and is null or
- * "none" -- then default coloring to "off".
- */
char *p;
+
if ((p = getenv ("LS_COLORS")) != NULL &&
(*p == '\0' || (strcmp(p, "none") == 0))) {
- show_color = 0;
+ ;
} else if (isatty(STDOUT_FILENO)) {
show_color = 1;
}
#endif
+
+ if((opt & (1 << i))) { /* next flag after short options */
+ if (color_opt == NULL || strcmp("always", color_opt) == 0)
+ show_color = 1;
+ else if (color_opt != NULL && strcmp("never", color_opt) == 0)
+ show_color = 0;
+ else if (color_opt != NULL && strcmp("auto", color_opt) == 0 && isatty(STDOUT_FILENO))
+ show_color = 1;
+ }
}
#endif
@@ -1129,14 +1119,12 @@ extern int ls_main(int argc, char **argv)
*/
ac = argc - optind; /* how many cmd line args are left */
if (ac < 1) {
- av = (char **) xcalloc((size_t) 1, (size_t) (sizeof(char *)));
- av[0] = bb_xstrdup(".");
+ static const char * const dotdir[] = { "." };
+
+ av = (char **) dotdir;
ac = 1;
} else {
- av = (char **) xcalloc((size_t) ac, (size_t) (sizeof(char *)));
- for (oi = 0; oi < ac; oi++) {
- av[oi] = argv[optind++]; /* copy pointer to real cmd line arg */
- }
+ av = argv + optind;
}
/* now, everything is in the av array */
@@ -1146,11 +1134,10 @@ extern int ls_main(int argc, char **argv)
/* stuff the command line file names into an dnode array */
dn = NULL;
for (oi = 0; oi < ac; oi++) {
- char *fullname = bb_xstrdup(av[oi]);
-
- cur = my_stat(fullname, fullname);
+ cur = my_stat(av[oi], av[oi]);
if (!cur)
continue;
+ cur->allocated = 0;
cur->next = dn;
dn = cur;
nfiles++;