aboutsummaryrefslogtreecommitdiff
path: root/coreutils
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils')
-rw-r--r--coreutils/ls.c149
1 files changed, 87 insertions, 62 deletions
diff --git a/coreutils/ls.c b/coreutils/ls.c
index 985086634..7d33eae8d 100644
--- a/coreutils/ls.c
+++ b/coreutils/ls.c
@@ -31,6 +31,10 @@
31 31
32#include "libbb.h" 32#include "libbb.h"
33 33
34#if ENABLE_FEATURE_ASSUME_UNICODE
35#include <wchar.h>
36#endif
37
34/* This is a NOEXEC applet. Be very careful! */ 38/* This is a NOEXEC applet. Be very careful! */
35 39
36 40
@@ -114,18 +118,6 @@ SPLIT_SUBDIR = 2,
114#define ATTR(mode) ("\00\00\01\00\01\00\01\00"\ 118#define ATTR(mode) ("\00\00\01\00\01\00\01\00"\
115 "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)]) 119 "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)])
116 120
117/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */
118#if ENABLE_FEATURE_LS_COLOR
119static smallint show_color;
120/* long option entry used only for --color, which has no short option
121 * equivalent */
122static const char ls_color_opt[] ALIGN1 =
123 "color\0" Optional_argument "\xff" /* no short equivalent */
124 ;
125#else
126enum { show_color = 0 };
127#endif
128
129/* 121/*
130 * a directory entry and its stat info are stored here 122 * a directory entry and its stat info are stored here
131 */ 123 */
@@ -137,25 +129,68 @@ struct dnode { /* the basic node */
137 USE_SELINUX(security_context_t sid;) 129 USE_SELINUX(security_context_t sid;)
138 struct dnode *next; /* point at the next node */ 130 struct dnode *next; /* point at the next node */
139}; 131};
140typedef struct dnode dnode_t;
141 132
142static struct dnode **list_dir(const char *); 133static struct dnode **list_dir(const char *);
143static struct dnode **dnalloc(int); 134static struct dnode **dnalloc(int);
144static int list_single(struct dnode *); 135static int list_single(const struct dnode *);
145 136
146static unsigned all_fmt;
147 137
138struct globals {
139#if ENABLE_FEATURE_LS_COLOR
140 smallint show_color;
141#endif
142 smallint exit_failure;
143 unsigned all_fmt;
144#if ENABLE_FEATURE_AUTOWIDTH
145 unsigned tabstops; // = COLUMN_GAP;
146 unsigned terminal_width; // = TERMINAL_WIDTH;
147#endif
148#if ENABLE_FEATURE_LS_TIMESTAMPS
149 /* Do time() just once. Saves one syscall per file for "ls -l" */
150 time_t current_time_t;
151#endif
152};
153#define G (*(struct globals*)&bb_common_bufsiz1)
154#if ENABLE_FEATURE_LS_COLOR
155#define show_color (G.show_color )
156#else
157enum { show_color = 0 };
158#endif
159#define exit_failure (G.exit_failure )
160#define all_fmt (G.all_fmt )
148#if ENABLE_FEATURE_AUTOWIDTH 161#if ENABLE_FEATURE_AUTOWIDTH
149static unsigned tabstops = COLUMN_GAP; 162#define tabstops (G.tabstops )
150static unsigned terminal_width = TERMINAL_WIDTH; 163#define terminal_width (G.terminal_width)
151#else 164#else
152enum { 165enum {
153 tabstops = COLUMN_GAP, 166 tabstops = COLUMN_GAP,
154 terminal_width = TERMINAL_WIDTH, 167 terminal_width = TERMINAL_WIDTH,
155}; 168};
156#endif 169#endif
170#define current_time_t (G.current_time_t)
171/* memset: we have to zero it out because of NOEXEC */
172#define INIT_G() { \
173 memset(&G, 0, sizeof(G)); \
174 tabstops = COLUMN_GAP; \
175 terminal_width = TERMINAL_WIDTH; \
176 USE_FEATURE_LS_TIMESTAMPS(time(&current_time_t);) \
177}
178
179
180#if ENABLE_FEATURE_ASSUME_UNICODE
181/* libbb candidate */
182static size_t mbstrlen(const char *string)
183{
184 size_t width = mbsrtowcs(NULL /*dest*/, &string,
185 MAXINT(size_t) /*len*/, NULL /*state*/);
186 if (width == (size_t)-1)
187 return strlen(string);
188 return width;
189}
190#else
191#define mbstrlen(string) strlen(string)
192#endif
157 193
158static int status = EXIT_SUCCESS;
159 194
160static struct dnode *my_stat(const char *fullname, const char *name, int force_follow) 195static struct dnode *my_stat(const char *fullname, const char *name, int force_follow)
161{ 196{
@@ -171,7 +206,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f
171#endif 206#endif
172 if (stat(fullname, &dstat)) { 207 if (stat(fullname, &dstat)) {
173 bb_simple_perror_msg(fullname); 208 bb_simple_perror_msg(fullname);
174 status = EXIT_FAILURE; 209 exit_failure = 1;
175 return 0; 210 return 0;
176 } 211 }
177 } else { 212 } else {
@@ -182,7 +217,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f
182#endif 217#endif
183 if (lstat(fullname, &dstat)) { 218 if (lstat(fullname, &dstat)) {
184 bb_simple_perror_msg(fullname); 219 bb_simple_perror_msg(fullname);
185 status = EXIT_FAILURE; 220 exit_failure = 1;
186 return 0; 221 return 0;
187 } 222 }
188 } 223 }
@@ -395,7 +430,7 @@ static void showfiles(struct dnode **dn, int nfiles)
395 } else { 430 } else {
396 /* find the longest file name, use that as the column width */ 431 /* find the longest file name, use that as the column width */
397 for (i = 0; i < nfiles; i++) { 432 for (i = 0; i < nfiles; i++) {
398 int len = strlen(dn[i]->name); 433 int len = mbstrlen(dn[i]->name);
399 if (column_width < len) 434 if (column_width < len)
400 column_width = len; 435 column_width = len;
401 } 436 }
@@ -494,7 +529,7 @@ static struct dnode **list_dir(const char *path)
494 nfiles = 0; 529 nfiles = 0;
495 dir = warn_opendir(path); 530 dir = warn_opendir(path);
496 if (dir == NULL) { 531 if (dir == NULL) {
497 status = EXIT_FAILURE; 532 exit_failure = 1;
498 return NULL; /* could not open the dir */ 533 return NULL; /* could not open the dir */
499 } 534 }
500 while ((entry = readdir(dir)) != NULL) { 535 while ((entry = readdir(dir)) != NULL) {
@@ -538,13 +573,7 @@ static struct dnode **list_dir(const char *path)
538} 573}
539 574
540 575
541#if ENABLE_FEATURE_LS_TIMESTAMPS 576static int list_single(const struct dnode *dn)
542/* Do time() just once. Saves one syscall per file for "ls -l" */
543/* Initialized in main() */
544static time_t current_time_t;
545#endif
546
547static int list_single(struct dnode *dn)
548{ 577{
549 int i, column = 0; 578 int i, column = 0;
550 579
@@ -658,7 +687,12 @@ static int list_single(struct dnode *dn)
658 fgcolor(info.st_mode)); 687 fgcolor(info.st_mode));
659 } 688 }
660#endif 689#endif
690#if ENABLE_FEATURE_ASSUME_UNICODE
691 printf("%s", dn->name);
692 column += mbstrlen(dn->name);
693#else
661 column += printf("%s", dn->name); 694 column += printf("%s", dn->name);
695#endif
662 if (show_color) { 696 if (show_color) {
663 printf("\033[0m"); 697 printf("\033[0m");
664 } 698 }
@@ -701,6 +735,7 @@ static int list_single(struct dnode *dn)
701 return column; 735 return column;
702} 736}
703 737
738
704/* "[-]Cadil1", POSIX mandated options, busybox always supports */ 739/* "[-]Cadil1", POSIX mandated options, busybox always supports */
705/* "[-]gnsx", POSIX non-mandated options, busybox always supports */ 740/* "[-]gnsx", POSIX non-mandated options, busybox always supports */
706/* "[-]Ak" GNU options, busybox always supports */ 741/* "[-]Ak" GNU options, busybox always supports */
@@ -779,11 +814,18 @@ static const unsigned opt_flags[] = {
779}; 814};
780 815
781 816
782/* THIS IS A "SAFE" APPLET, main() MAY BE CALLED INTERNALLY FROM SHELL */ 817/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */
783/* BE CAREFUL! */ 818#if ENABLE_FEATURE_LS_COLOR
819/* long option entry used only for --color, which has no short option
820 * equivalent */
821static const char ls_color_opt[] ALIGN1 =
822 "color\0" Optional_argument "\xff" /* no short equivalent */
823 ;
824#endif
825
784 826
785int ls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 827int ls_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
786int ls_main(int argc, char **argv) 828int ls_main(int argc ATTRIBUTE_UNUSED, char **argv)
787{ 829{
788 struct dnode **dnd; 830 struct dnode **dnd;
789 struct dnode **dnf; 831 struct dnode **dnf;
@@ -791,18 +833,13 @@ int ls_main(int argc, char **argv)
791 struct dnode *dn; 833 struct dnode *dn;
792 struct dnode *cur; 834 struct dnode *cur;
793 unsigned opt; 835 unsigned opt;
794 int nfiles = 0; 836 int nfiles;
795 int dnfiles; 837 int dnfiles;
796 int dndirs; 838 int dndirs;
797 int oi;
798 int ac;
799 int i; 839 int i;
800 char **av;
801 USE_FEATURE_LS_COLOR(char *color_opt;) 840 USE_FEATURE_LS_COLOR(char *color_opt;)
802 841
803#if ENABLE_FEATURE_LS_TIMESTAMPS 842 INIT_G();
804 time(&current_time_t);
805#endif
806 843
807 all_fmt = LIST_SHORT | 844 all_fmt = LIST_SHORT |
808 (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD)); 845 (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD));
@@ -883,39 +920,27 @@ int ls_main(int argc, char **argv)
883 if (!(all_fmt & STYLE_MASK)) 920 if (!(all_fmt & STYLE_MASK))
884 all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE); 921 all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE);
885 922
886 /* 923 argv += optind;
887 * when there are no cmd line args we have to supply a default "." arg. 924 if (!argv[0])
888 * we will create a second argv array, "av" that will hold either 925 *--argv = (char*)".";
889 * our created "." arg, or the real cmd line args. The av array
890 * just holds the pointers- we don't move the date the pointers
891 * point to.
892 */
893 ac = argc - optind; /* how many cmd line args are left */
894 if (ac < 1) {
895 static const char *const dotdir[] = { "." };
896
897 av = (char **) dotdir;
898 ac = 1;
899 } else {
900 av = argv + optind;
901 }
902 926
903 /* now, everything is in the av array */ 927 if (argv[1])
904 if (ac > 1) 928 all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */
905 all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */
906 929
907 /* stuff the command line file names into a dnode array */ 930 /* stuff the command line file names into a dnode array */
908 dn = NULL; 931 dn = NULL;
909 for (oi = 0; oi < ac; oi++) { 932 nfiles = 0;
933 do {
910 /* ls w/o -l follows links on command line */ 934 /* ls w/o -l follows links on command line */
911 cur = my_stat(av[oi], av[oi], !(all_fmt & STYLE_LONG)); 935 cur = my_stat(*argv, *argv, !(all_fmt & STYLE_LONG));
936 argv++;
912 if (!cur) 937 if (!cur)
913 continue; 938 continue;
914 cur->allocated = 0; 939 cur->allocated = 0;
915 cur->next = dn; 940 cur->next = dn;
916 dn = cur; 941 dn = cur;
917 nfiles++; 942 nfiles++;
918 } 943 } while (*argv);
919 944
920 /* now that we know how many files there are 945 /* now that we know how many files there are
921 * allocate memory for an array to hold dnode pointers 946 * allocate memory for an array to hold dnode pointers
@@ -950,5 +975,5 @@ int ls_main(int argc, char **argv)
950 } 975 }
951 if (ENABLE_FEATURE_CLEAN_UP) 976 if (ENABLE_FEATURE_CLEAN_UP)
952 dfree(dnp, nfiles); 977 dfree(dnp, nfiles);
953 return status; 978 return (exit_failure == 0);
954} 979}