* 1. requires lstat (BSD) - how do you do it without?
*/
-#include "busybox.h"
#include <getopt.h>
+#include "libbb.h"
+
+/* This is a NOEXEC applet. Be very careful! */
+
enum {
/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */
#if ENABLE_FEATURE_LS_COLOR
-static int show_color;
+static smallint show_color;
/* long option entry used only for --color, which has no short option
* equivalent */
-static const struct option ls_color_opt[] = {
- { "color", optional_argument, NULL, 1 },
- { NULL, 0, NULL, 0 }
-};
+static const char ls_color_opt[] ALIGN1 =
+ "color\0" Optional_argument "\xff" /* no short equivalent */
+ ;
#else
enum { show_color = 0 };
#endif
* a directory entry and its stat info are stored here
*/
struct dnode { /* the basic node */
- char *name; /* the dir entry name */
- char *fullname; /* the dir entry name */
+ const char *name; /* the dir entry name */
+ const char *fullname; /* the dir entry name */
int allocated;
struct stat dstat; /* the file stat info */
USE_SELINUX(security_context_t sid;)
static int status = EXIT_SUCCESS;
-static struct dnode *my_stat(char *fullname, char *name)
+static struct dnode *my_stat(const char *fullname, const char *name, int force_follow)
{
struct stat dstat;
struct dnode *cur;
USE_SELINUX(security_context_t sid = NULL;)
- if (all_fmt & FOLLOW_LINKS) {
+ if ((all_fmt & FOLLOW_LINKS) || force_follow) {
#if ENABLE_SELINUX
if (is_selinux_enabled()) {
getfilecon(fullname, &sid);
}
#endif
if (stat(fullname, &dstat)) {
- bb_perror_msg("%s", fullname);
+ bb_simple_perror_msg(fullname);
status = EXIT_FAILURE;
return 0;
}
} else {
#if ENABLE_SELINUX
if (is_selinux_enabled()) {
- lgetfilecon(fullname,&sid);
+ lgetfilecon(fullname, &sid);
}
#endif
if (lstat(fullname, &dstat)) {
- bb_perror_msg("%s", fullname);
+ bb_simple_perror_msg(fullname);
status = EXIT_FAILURE;
return 0;
}
return 0;
dirs = 0;
for (i = 0; i < nfiles; i++) {
- char *name;
+ const char *name;
if (!S_ISDIR(dn[i]->dstat.st_mode))
continue;
name = dn[i]->name;
for (i = 0; i < nfiles; i++) {
struct dnode *cur = dnp[i];
if (cur->allocated)
- free(cur->fullname); /* free the filename */
+ free((char*)cur->fullname); /* free the filename */
free(cur); /* free the dnode */
}
free(dnp); /* free the array holding the dnode pointers */
}
#else
-#define dfree(...) do {} while(0)
+#define dfree(...) ((void)0)
#endif
static struct dnode **splitdnarray(struct dnode **dn, int nfiles, int which)
/* copy the entrys into the file or dir array */
for (d = i = 0; i < nfiles; i++) {
if (S_ISDIR(dn[i]->dstat.st_mode)) {
- char *name;
+ const char *name;
if (!(which & (SPLIT_DIR|SPLIT_SUBDIR)))
continue;
name = dn[i]->name;
qsort(dn, size, sizeof(*dn), sortcmp);
}
#else
-#define dnsort(dn, size) do {} while(0)
+#define dnsort(dn, size) ((void)0)
#endif
for (i = 0; i < ndirs; i++) {
if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) {
if (!first)
- puts("");
+ bb_putchar('\n');
first = 0;
printf("%s:\n", dn[i]->fullname);
}
/* are we going to list the file- it may be . or .. or a hidden file */
if (entry->d_name[0] == '.') {
- if ((entry->d_name[1] == 0 || (
- entry->d_name[1] == '.'
- && entry->d_name[2] == 0))
- && !(all_fmt & DISP_DOT))
+ if ((!entry->d_name[1] || (entry->d_name[1] == '.' && !entry->d_name[2]))
+ && !(all_fmt & DISP_DOT)
+ ) {
continue;
+ }
if (!(all_fmt & DISP_HIDDEN))
continue;
}
fullname = concat_path_file(path, entry->d_name);
- cur = my_stat(fullname, strrchr(fullname, '/') + 1);
+ cur = my_stat(fullname, bb_basename(fullname), 0);
if (!cur) {
free(fullname);
continue;
}
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+/* Do time() just once. Saves one syscall per file for "ls -l" */
+/* Initialized in main() */
+static time_t current_time_t;
+#endif
+
static int list_single(struct dnode *dn)
{
int i, column = 0;
-#if ENABLE_FEATURE_LS_USERNAME
- char scratch[16];
-#endif
#if ENABLE_FEATURE_LS_TIMESTAMPS
char *filetime;
time_t ttime, age;
break;
case LIST_ID_NAME:
#if ENABLE_FEATURE_LS_USERNAME
- bb_getpwuid(scratch, dn->dstat.st_uid, sizeof(scratch));
- printf("%-8.8s ", scratch);
- bb_getgrgid(scratch, dn->dstat.st_gid, sizeof(scratch));
- printf("%-8.8s", scratch);
+ printf("%-8.8s %-8.8s",
+ get_cached_username(dn->dstat.st_uid),
+ get_cached_groupname(dn->dstat.st_gid));
column += 17;
break;
#endif
break;
case LIST_DATE_TIME:
if ((all_fmt & LIST_FULLTIME) == 0) {
- age = time(NULL) - ttime;
+ /* current_time_t ~== time(NULL) */
+ age = current_time_t - ttime;
printf("%6.6s ", filetime + 4);
if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
/* hh:mm if less than 6 months old */
#endif
case LIST_FILENAME:
errno = 0;
+#if ENABLE_FEATURE_LS_COLOR
if (show_color && !lstat(dn->fullname, &info)) {
printf("\033[%d;%dm", bgcolor(info.st_mode),
fgcolor(info.st_mode));
}
+#endif
column += printf("%s", dn->name);
if (show_color) {
printf("\033[0m");
break;
case LIST_SYMLINK:
if (S_ISLNK(dn->dstat.st_mode)) {
- char *lpath = xreadlink(dn->fullname);
+ char *lpath = xmalloc_readlink_or_warn(dn->fullname);
if (!lpath) break;
printf(" -> ");
#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
append = append_char(info.st_mode);
}
#endif
+#if ENABLE_FEATURE_LS_COLOR
if (show_color) {
errno = 0;
printf("\033[%d;%dm", bgcolor(info.st_mode),
fgcolor(info.st_mode));
}
+#endif
column += printf("%s", lpath) + 4;
if (show_color) {
printf("\033[0m");
/* "[-]SXvThw", GNU options, busybox optionally supports */
/* "[-]K", SELinux mandated options, busybox optionally supports */
/* "[-]e", I think we made this one up */
-static const char ls_options[] = "Cadil1gnsxAk"
+static const char ls_options[] ALIGN1 =
+ "Cadil1gnsxAk"
USE_FEATURE_LS_TIMESTAMPS("cetu")
USE_FEATURE_LS_SORTFILES("SXrv")
USE_FEATURE_LS_FILETYPES("Fp")
USE_FEATURE_LS_RECURSIVE("R")
USE_FEATURE_HUMAN_READABLE("h")
USE_SELINUX("K")
- USE_FEATURE_AUTOWIDTH("T:w:");
+ USE_FEATURE_AUTOWIDTH("T:w:")
+ USE_SELINUX("Z");
enum {
LIST_MASK_TRIGGER = 0,
#endif
#if ENABLE_FEATURE_AUTOWIDTH
0, 0, /* T, w - ignored */
+#endif
+#if ENABLE_SELINUX
+ LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */
#endif
(1U<<31)
};
+/* THIS IS A "SAFE" APPLET, main() MAY BE CALLED INTERNALLY FROM SHELL */
+/* BE CAREFUL! */
+
+int ls_main(int argc, char **argv);
int ls_main(int argc, char **argv)
{
struct dnode **dnd;
USE_FEATURE_AUTOWIDTH(char *terminal_width_str = NULL;)
USE_FEATURE_LS_COLOR(char *color_opt;)
+#if ENABLE_FEATURE_LS_TIMESTAMPS
+ time(¤t_time_t);
+#endif
+
all_fmt = LIST_SHORT |
(ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD));
#if ENABLE_FEATURE_AUTOWIDTH
/* Obtain the terminal width */
- get_terminal_width_height(STDOUT_FILENO, &terminal_width, NULL);
+ get_terminal_width_height(STDIN_FILENO, &terminal_width, NULL);
/* Go one less... */
terminal_width--;
#endif
/* process options */
USE_FEATURE_LS_COLOR(applet_long_options = ls_color_opt;)
#if ENABLE_FEATURE_AUTOWIDTH
- opt = getopt32(argc, argv, ls_options, &tabstops_str, &terminal_width_str
+ opt = getopt32(argv, ls_options, &tabstops_str, &terminal_width_str
USE_FEATURE_LS_COLOR(, &color_opt));
if (tabstops_str)
tabstops = xatou(tabstops_str);
if (terminal_width_str)
terminal_width = xatou(terminal_width_str);
#else
- opt = getopt32(argc, argv, ls_options USE_FEATURE_LS_COLOR(, &color_opt));
+ opt = getopt32(argv, ls_options USE_FEATURE_LS_COLOR(, &color_opt));
#endif
for (i = 0; opt_flags[i] != (1U<<31); i++) {
if (opt & (1 << i)) {
all_fmt &= ~TIME_MASK;
if (flags & LIST_CONTEXT)
all_fmt |= STYLE_SINGLE;
- if (LS_DISP_HR && opt == 'l')
- all_fmt &= ~LS_DISP_HR;
+ /* huh?? opt cannot be 'l' */
+ //if (LS_DISP_HR && opt == 'l')
+ // all_fmt &= ~LS_DISP_HR;
all_fmt |= flags;
}
}
/* stuff the command line file names into a dnode array */
dn = NULL;
for (oi = 0; oi < ac; oi++) {
- cur = my_stat(av[oi], av[oi]);
+ /* ls w/o -l follows links on command line */
+ cur = my_stat(av[oi], av[oi], !(all_fmt & STYLE_LONG));
if (!cur)
continue;
cur->allocated = 0;