Changeset 1770 in MondoRescue for branches/stable/mindi-busybox/coreutils/ls.c


Ignore:
Timestamp:
Nov 6, 2007, 11:01:53 AM (16 years ago)
Author:
Bruno Cornec
Message:
  • Better output for mindi-busybox revision
  • Remove dummy file created on NFS - report from Arnaud Tiger <arnaud.tiger_at_hp.com>
  • strace useful for debug
  • fix new versions for pb (2.0.0 for mindi and 1.7.2 for mindi-busybox)
  • fix build process for mindi-busybox + options used in that version (dd for label-partitions-as-necessary)
  • fix typo in label-partitions-as-necessary which doesn't seem to work
  • Update to busybox 1.7.2
  • perl is now required at restore time to support uuid swap partitions (and will be used for many other thigs

in the future for sure)

  • next mindi version will be 2.0.0 due to all the changes made in it (udev may break working distros)
  • small optimization in mindi on keyboard handling (one single find instead of multiple)
  • better interaction for USB device when launching mindi manually
  • attempt to automatically guess block disk size for ramdisk
  • fix typos in bkphw
  • Fix the remaining problem with UUID support for swap partitions
  • Updates mondoarchive man page for USB support
  • Adds preliminary Hardware support to mindi (Proliant SSSTK)
  • Tries to add udev support also for rhel4
  • Fix UUID support which was still broken.
  • Be conservative in test for the start-nfs script
  • Update config file for mindi-busybox for 1.7.2 migration
  • Try to run around a busybox bug (1.2.2 pb on inexistant links)
  • Add build content for mindi-busybox in pb
  • Remove distributions content for mindi-busybox
  • Fix a warning on inexistant raidtab
  • Solve problem on tmpfs in restore init (Problem of inexistant symlink and busybox)
  • Create MONDO_CACHE and use it everywhere + creation at start
  • Really never try to eject a USB device
  • Fix a issue with &> usage (replaced with 1> and 2>)
  • Adds magic file to depllist in order to have file working + ldd which helps for debugging issues
  • tty modes correct to avoid sh error messages
  • Use ext3 normally and not ext2 instead
  • USB device should be corrected after reading (take 1st part)
  • Adds a mount_USB_here function derived from mount_CDROM_here
  • usb detection place before /dev detection in device name at restore time
  • Fix when restoring from USB: media is asked in interactive mode
  • Adds USB support for mondorestore
  • mount_cdrom => mount_media
  • elilo.efi is now searched throughout /boot/efi and not in a fixed place as there is no standard
  • untar-and-softlink => untar (+ interface change)
  • suppress useless softlinks creation/removal in boot process
  • avoids udevd messages on groups
  • Increase # of disks to 99 as in mindi at restore time (should be a conf file parameter)
  • skip existing big file creation
  • seems to work correctly for USB mindi boot
  • Adds group and tty link to udev conf
  • Always load usb-torage (even 2.6) to initiate USB bus discovery
  • Better printing of messages
  • Attempt to fix a bug in supporting OpenSusE 10.3 kernel for initramfs (mindi may now use multiple regex for kernel initrd detection)
  • Links were not correctly done as non relative for modules in mindi
  • exclusion of modules denied now works
  • Also create modules in their ordinary place, so that classical modprobe works + copy modules.dep
  • Fix bugs for DENY_MODS handling
  • Add device /dev/console for udev
  • ide-generic should now really be excluded
  • Fix a bug in major number for tty
  • If udev then adds modprobe/insmod to rootfs
  • tty0 is also cretaed with udev
  • ide-generic put rather in DENY_MODS
  • udevd remove from deplist s handled in mindi directly
  • better default for mindi when using --usb
  • Handles dynamically linked busybox (in case we want to use it soon ;-)
  • Adds fixed devices to create for udev
  • ide-generic should not be part of the initrd when using libata v2
  • support a dynamically linked udev (case on Ubuntu 7.10 and Mandriva 2008.0 so should be quite generic) This will give incitation to move to dyn. linked binaries in the initrd which will help for other tasks (ia6 4)
  • Improvement in udev support (do not use cl options not available in busybox)
  • Udev in mindi
    • auto creation of the right links at boot time with udev-links.conf(from Mandriva 2008.0)
    • rework startup of udev as current makes kernel crash (from Mandriva 2008.0)
    • add support for 64 bits udev
  • Try to render MyInsmod silent at boot time
  • Adds udev support (mandatory for newest distributions to avoid remapping of devices in a different way as on the original system)
  • We also need vaft format support for USB boot
  • Adds libusual support (Ubuntu 7.10 needs it for USB)
  • Improve Ubuntu/Debian keyboard detection and support
  • pbinit adapted to new pb (0.8.10). Filtering of docs done in it
  • Suppress some mondo warnings and errors on USB again
  • Tries to fix lack of files in deb mindi package
  • Verify should now work for USB devices
  • More log/mesages improvement for USB support
  • - Supress g_erase_tmpdir_and_scratchdir
  • Improve some log messages for USB support
  • Try to improve install in mindi to avoid issues with isolinux.cfg not installed vene if in the pkg :-(
  • Improve mindi-busybox build
  • In conformity with pb 0.8.9
  • Add support for Ubuntu 7.10 in build process
  • Add USB Key button to Menu UI (CD streamer removed)
  • Attempt to fix error messages on tmp/scratch files at the end by removing those dir at the latest possible.
  • Fix a bug linked to the size of the -E param which could be used (Arnaud Tiger/René Ribaud).
  • Integrate ~/.pbrc content into mondorescue.pb (required project-builder >= 0.8.7)
  • Put mondorescue in conformity with new pb filtering rules
  • Add USB support at restore time (no test done yet). New start-usb script PB varibale added where useful
  • Unmounting USB device before removal of temporary scratchdir
  • Stil refining USB copy back to mondo (one command was not executed)
  • No need to have the image subdor in the csratchdir when USB.
  • umount the USB partition before attempting to use it
  • Remove useless copy from mindi to mondo at end of USB handling

(risky merge, we are raising the limits of 2 diverging branches. The status of stable is not completely sure as such. Will need lots of tests, but it's not yet done :-()
(merge -r1692:1769 $SVN_M/branches/2.2.5)

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/stable/mindi-busybox/coreutils/ls.c

    r821 r1770  
    3030 */
    3131
     32#include <getopt.h>
     33#include "libbb.h"
     34
     35/* This is a NOEXEC applet. Be very careful! */
     36
     37
    3238enum {
    33     TERMINAL_WIDTH = 80,    /* use 79 if terminal has linefold bug */
    34     COLUMN_GAP = 2,     /* includes the file type char */
    35 };
    36 
    37 /************************************************************************/
    38 
    39 #include "busybox.h"
    40 #include <unistd.h>
    41 #include <errno.h>
    42 #include <string.h>
    43 #include <fcntl.h>
    44 #include <signal.h>
    45 #include <getopt.h> /* struct option */
    46 #include <sys/ioctl.h>
    47 #include <sys/sysmacros.h>     /* major() and minor() */
    48 #include <time.h>
     39
     40TERMINAL_WIDTH  = 80,           /* use 79 if terminal has linefold bug */
     41COLUMN_GAP      = 2,            /* includes the file type char */
    4942
    5043/* what is the overall style of the listing */
    51 #define STYLE_COLUMNS   (1U<<21)    /* fill columns */
    52 #define STYLE_LONG      (2U<<21)    /* one record per line, extended info */
    53 #define STYLE_SINGLE    (3U<<21)    /* one record per line */
    54 
    55 #define STYLE_MASK                 STYLE_SINGLE
    56 #define STYLE_ONE_RECORD_FLAG      STYLE_LONG
     44STYLE_COLUMNS   = 1 << 21,      /* fill columns */
     45STYLE_LONG      = 2 << 21,      /* one record per line, extended info */
     46STYLE_SINGLE    = 3 << 21,      /* one record per line */
     47STYLE_MASK      = STYLE_SINGLE,
    5748
    5849/* 51306 lrwxrwxrwx  1 root     root         2 May 11 01:43 /bin/view -> vi* */
    5950/* what file information will be listed */
    60 #define LIST_INO    (1U<<0)
    61 #define LIST_BLOCKS (1U<<1)
    62 #define LIST_MODEBITS   (1U<<2)
    63 #define LIST_NLINKS (1U<<3)
    64 #define LIST_ID_NAME    (1U<<4)
    65 #define LIST_ID_NUMERIC (1U<<5)
    66 #define LIST_CONTEXT    (1U<<6)
    67 #define LIST_SIZE   (1U<<7)
    68 #define LIST_DEV    (1U<<8)
    69 #define LIST_DATE_TIME  (1U<<9)
    70 #define LIST_FULLTIME   (1U<<10)
    71 #define LIST_FILENAME   (1U<<11)
    72 #define LIST_SYMLINK    (1U<<12)
    73 #define LIST_FILETYPE   (1U<<13)
    74 #define LIST_EXEC   (1U<<14)
    75 
    76 #define LIST_MASK       ((LIST_EXEC << 1) - 1)
     51LIST_INO        = 1 << 0,
     52LIST_BLOCKS     = 1 << 1,
     53LIST_MODEBITS   = 1 << 2,
     54LIST_NLINKS     = 1 << 3,
     55LIST_ID_NAME    = 1 << 4,
     56LIST_ID_NUMERIC = 1 << 5,
     57LIST_CONTEXT    = 1 << 6,
     58LIST_SIZE       = 1 << 7,
     59LIST_DEV        = 1 << 8,
     60LIST_DATE_TIME  = 1 << 9,
     61LIST_FULLTIME   = 1 << 10,
     62LIST_FILENAME   = 1 << 11,
     63LIST_SYMLINK    = 1 << 12,
     64LIST_FILETYPE   = 1 << 13,
     65LIST_EXEC       = 1 << 14,
     66LIST_MASK       = (LIST_EXEC << 1) - 1,
    7767
    7868/* what files will be displayed */
    79 #define DISP_DIRNAME    (1U<<15)    /* 2 or more items? label directories */
    80 #define DISP_HIDDEN (1U<<16)    /* show filenames starting with .  */
    81 #define DISP_DOT    (1U<<17)    /* show . and .. */
    82 #define DISP_NOLIST (1U<<18)    /* show directory as itself, not contents */
    83 #define DISP_RECURSIVE  (1U<<19)    /* show directory and everything below it */
    84 #define DISP_ROWS   (1U<<20)    /* print across rows */
    85 
    86 #define DISP_MASK       (((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1))
    87 
    88 // CONFIG_FEATURE_LS_SORTFILES
    89 /* how will the files be sorted */
    90 #define SORT_ORDER_FORWARD   0      /* sort in reverse order */
    91 #define SORT_ORDER_REVERSE   (1U<<27)   /* sort in reverse order */
    92 
    93 #define SORT_NAME      0        /* sort by file name */
    94 #define SORT_SIZE      (1U<<28)     /* sort by file size */
    95 #define SORT_ATIME     (2U<<28)     /* sort by last access time */
    96 #define SORT_CTIME     (3U<<28)     /* sort by last change time */
    97 #define SORT_MTIME     (4U<<28)     /* sort by last modification time */
    98 #define SORT_VERSION   (5U<<28)     /* sort by version */
    99 #define SORT_EXT       (6U<<28)     /* sort by file name extension */
    100 #define SORT_DIR       (7U<<28)     /* sort by file or directory */
    101 
    102 #define SORT_MASK      (7U<<28)
     69DISP_DIRNAME    = 1 << 15,      /* 2 or more items? label directories */
     70DISP_HIDDEN     = 1 << 16,      /* show filenames starting with . */
     71DISP_DOT        = 1 << 17,      /* show . and .. */
     72DISP_NOLIST     = 1 << 18,      /* show directory as itself, not contents */
     73DISP_RECURSIVE  = 1 << 19,      /* show directory and everything below it */
     74DISP_ROWS       = 1 << 20,      /* print across rows */
     75DISP_MASK       = ((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1),
     76
     77/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */
     78SORT_FORWARD    = 0,            /* sort in reverse order */
     79SORT_REVERSE    = 1 << 27,      /* sort in reverse order */
     80
     81SORT_NAME       = 0,            /* sort by file name */
     82SORT_SIZE       = 1 << 28,      /* sort by file size */
     83SORT_ATIME      = 2 << 28,      /* sort by last access time */
     84SORT_CTIME      = 3 << 28,      /* sort by last change time */
     85SORT_MTIME      = 4 << 28,      /* sort by last modification time */
     86SORT_VERSION    = 5 << 28,      /* sort by version */
     87SORT_EXT        = 6 << 28,      /* sort by file name extension */
     88SORT_DIR        = 7 << 28,      /* sort by file or directory */
     89SORT_MASK       = (7 << 28) * ENABLE_FEATURE_LS_SORTFILES,
    10390
    10491/* which of the three times will be used */
    105 #define TIME_CHANGE    ((1U<<23) * ENABLE_FEATURE_LS_TIMESTAMPS)
    106 #define TIME_ACCESS    ((1U<<24) * ENABLE_FEATURE_LS_TIMESTAMPS)
    107 #define TIME_MASK      ((3U<<23) * ENABLE_FEATURE_LS_TIMESTAMPS)
    108 
    109 #ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
    110 #define FOLLOW_LINKS   (1U<<25)
    111 #endif
    112 #ifdef CONFIG_FEATURE_HUMAN_READABLE
    113 #define LS_DISP_HR     (1U<<26)
    114 #endif
    115 
    116 #define LIST_SHORT  (LIST_FILENAME)
    117 #define LIST_ISHORT (LIST_INO | LIST_FILENAME)
    118 #define LIST_LONG   (LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \
    119                         LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK)
    120 #define LIST_ILONG  (LIST_INO | LIST_LONG)
    121 
    122 #define SPLIT_DIR      1
    123 #define SPLIT_FILE     0
    124 #define SPLIT_SUBDIR   2
     92TIME_CHANGE     = (1 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS,
     93TIME_ACCESS     = (1 << 24) * ENABLE_FEATURE_LS_TIMESTAMPS,
     94TIME_MASK       = (3 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS,
     95
     96FOLLOW_LINKS    = (1 << 25) * ENABLE_FEATURE_LS_FOLLOWLINKS,
     97
     98LS_DISP_HR      = (1 << 26) * ENABLE_FEATURE_HUMAN_READABLE,
     99
     100LIST_SHORT      = LIST_FILENAME,
     101LIST_LONG       = LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \
     102                  LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK,
     103
     104SPLIT_DIR       = 1,
     105SPLIT_FILE      = 0,
     106SPLIT_SUBDIR    = 2,
     107
     108};
    125109
    126110#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f)
    127111#define TYPECHAR(mode)  ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)])
    128 
    129 #if defined(CONFIG_FEATURE_LS_FILETYPES) || defined(CONFIG_FEATURE_LS_COLOR)
    130 # define APPCHAR(mode)   ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
    131 #endif
    132 
    133 /* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */
    134 #ifdef CONFIG_FEATURE_LS_COLOR
    135 
    136 static int show_color = 0;
    137 
    138 /* long option entry used only for --color, which has no short option
    139  * equivalent.  */
    140 static const struct option ls_color_opt[] =
    141 {
    142     {"color", optional_argument, NULL, 1},
    143     {NULL, 0, NULL, 0}
    144 };
    145 
     112#define APPCHAR(mode)   ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
    146113#define COLOR(mode) ("\000\043\043\043\042\000\043\043"\
    147114             "\000\000\044\000\043\000\000\040" [TYPEINDEX(mode)])
    148115#define ATTR(mode)  ("\00\00\01\00\01\00\01\00"\
    149116             "\00\00\01\00\01\00\00\01" [TYPEINDEX(mode)])
     117
     118/* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */
     119#if ENABLE_FEATURE_LS_COLOR
     120static smallint show_color;
     121/* long option entry used only for --color, which has no short option
     122 * equivalent */
     123static const char ls_color_opt[] ALIGN1 =
     124    "color\0" Optional_argument "\xff" /* no short equivalent */
     125    ;
     126#else
     127enum { show_color = 0 };
    150128#endif
    151129
     
    153131 * a directory entry and its stat info are stored here
    154132 */
    155 struct dnode {          /* the basic node */
    156     char *name;     /* the dir entry name */
    157     char *fullname;     /* the dir entry name */
     133struct dnode {                  /* the basic node */
     134    const char *name;             /* the dir entry name */
     135    const char *fullname;         /* the dir entry name */
    158136    int   allocated;
    159     struct stat dstat;  /* the file stat info */
    160 #ifdef CONFIG_SELINUX
    161     security_context_t sid;
    162 #endif
    163     struct dnode *next; /* point at the next node */
     137    struct stat dstat;      /* the file stat info */
     138    USE_SELINUX(security_context_t sid;)
     139    struct dnode *next;     /* point at the next node */
    164140};
    165141typedef struct dnode dnode_t;
     
    169145static int list_single(struct dnode *);
    170146
    171 static unsigned int all_fmt;
    172 
    173 #ifdef CONFIG_FEATURE_AUTOWIDTH
    174 static int terminal_width = TERMINAL_WIDTH;
    175 static unsigned short tabstops = COLUMN_GAP;
     147static unsigned all_fmt;
     148
     149#if ENABLE_FEATURE_AUTOWIDTH
     150static unsigned tabstops = COLUMN_GAP;
     151static unsigned terminal_width = TERMINAL_WIDTH;
    176152#else
    177 #define tabstops COLUMN_GAP
    178 #define terminal_width TERMINAL_WIDTH
     153enum {
     154    tabstops = COLUMN_GAP,
     155    terminal_width = TERMINAL_WIDTH,
     156};
    179157#endif
    180158
    181159static int status = EXIT_SUCCESS;
    182160
    183 static struct dnode *my_stat(char *fullname, char *name)
     161static struct dnode *my_stat(const char *fullname, const char *name, int force_follow)
    184162{
    185163    struct stat dstat;
    186164    struct dnode *cur;
    187 #ifdef CONFIG_SELINUX
    188     security_context_t sid=NULL;
    189 #endif
    190 
    191 #ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
    192     if (all_fmt & FOLLOW_LINKS) {
    193 #ifdef CONFIG_SELINUX
     165    USE_SELINUX(security_context_t sid = NULL;)
     166
     167    if ((all_fmt & FOLLOW_LINKS) || force_follow) {
     168#if ENABLE_SELINUX
    194169        if (is_selinux_enabled())  {
    195              getfilecon(fullname,&sid);
     170             getfilecon(fullname, &sid);
    196171        }
    197172#endif
     
    201176            return 0;
    202177        }
    203     } else
    204 #endif
    205     {
    206 #ifdef CONFIG_SELINUX
    207             if  (is_selinux_enabled())  {
    208           lgetfilecon(fullname,&sid);
     178    } else {
     179#if ENABLE_SELINUX
     180        if (is_selinux_enabled()) {
     181            lgetfilecon(fullname, &sid);
    209182        }
    210183#endif
     
    216189    }
    217190
    218     cur = (struct dnode *) xmalloc(sizeof(struct dnode));
     191    cur = xmalloc(sizeof(struct dnode));
    219192    cur->fullname = fullname;
    220193    cur->name = name;
    221194    cur->dstat = dstat;
    222 #ifdef CONFIG_SELINUX
    223     cur->sid = sid;
    224 #endif
     195    USE_SELINUX(cur->sid = sid;)
    225196    return cur;
    226197}
    227198
    228 /*----------------------------------------------------------------------*/
    229 #ifdef CONFIG_FEATURE_LS_COLOR
     199#if ENABLE_FEATURE_LS_COLOR
    230200static char fgcolor(mode_t mode)
    231201{
    232202    /* Check wheter the file is existing (if so, color it red!) */
    233     if (errno == ENOENT) {
     203    if (errno == ENOENT)
    234204        return '\037';
    235     }
    236205    if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
    237206        return COLOR(0xF000);   /* File is executable ... */
     
    239208}
    240209
    241 /*----------------------------------------------------------------------*/
    242210static char bgcolor(mode_t mode)
    243211{
     
    248216#endif
    249217
    250 /*----------------------------------------------------------------------*/
    251 #if defined(CONFIG_FEATURE_LS_FILETYPES) || defined(CONFIG_FEATURE_LS_COLOR)
     218#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
    252219static char append_char(mode_t mode)
    253220{
     
    264231#endif
    265232
    266 /*----------------------------------------------------------------------*/
    267 
    268 #define countdirs(A,B) count_dirs((A), (B), 1)
    269 #define countsubdirs(A,B) count_dirs((A), (B), 0)
    270 
     233#define countdirs(A, B) count_dirs((A), (B), 1)
     234#define countsubdirs(A, B) count_dirs((A), (B), 0)
    271235static int count_dirs(struct dnode **dn, int nfiles, int notsubdirs)
    272236{
    273237    int i, dirs;
    274238
    275     if (dn == NULL || nfiles < 1)
    276         return (0);
     239    if (!dn)
     240        return 0;
    277241    dirs = 0;
    278242    for (i = 0; i < nfiles; i++) {
    279         if (S_ISDIR(dn[i]->dstat.st_mode)
    280             && (notsubdirs ||
    281             ((dn[i]->name[0] != '.') || (dn[i]->name[1]
    282                         && ((dn[i]->name[1] != '.')
    283                         || dn[i]->name[2])))))
     243        const char *name;
     244        if (!S_ISDIR(dn[i]->dstat.st_mode))
     245            continue;
     246        name = dn[i]->name;
     247        if (notsubdirs
     248         || name[0]!='.' || (name[1] && (name[1]!='.' || name[2]))
     249        ) {
    284250            dirs++;
    285     }
    286     return (dirs);
     251        }
     252    }
     253    return dirs;
    287254}
    288255
     
    293260
    294261    if (dnp == NULL)
    295         return (0);
     262        return 0;
    296263    nfiles = 0;
    297     for (cur = dnp[0]; cur->next != NULL; cur = cur->next)
     264    for (cur = dnp[0]; cur->next; cur = cur->next)
    298265        nfiles++;
    299266    nfiles++;
    300     return (nfiles);
     267    return nfiles;
    301268}
    302269
     
    304271static struct dnode **dnalloc(int num)
    305272{
    306     struct dnode **p;
    307 
    308273    if (num < 1)
    309         return (NULL);
    310 
    311     p = (struct dnode **) xcalloc((size_t) num, (size_t) (sizeof(struct dnode *)));
    312     return (p);
    313 }
    314 
    315 #ifdef CONFIG_FEATURE_LS_RECURSIVE
     274        return NULL;
     275
     276    return xzalloc(num * sizeof(struct dnode *));
     277}
     278
     279#if ENABLE_FEATURE_LS_RECURSIVE
    316280static void dfree(struct dnode **dnp, int nfiles)
    317281{
     
    323287    for (i = 0; i < nfiles; i++) {
    324288        struct dnode *cur = dnp[i];
    325         if(cur->allocated)
    326             free(cur->fullname);    /* free the filename */
     289        if (cur->allocated)
     290            free((char*)cur->fullname); /* free the filename */
    327291        free(cur);      /* free the dnode */
    328292    }
     
    330294}
    331295#else
    332 #define dfree(...)
     296#define dfree(...) ((void)0)
    333297#endif
    334298
     
    339303
    340304    if (dn == NULL || nfiles < 1)
    341         return (NULL);
     305        return NULL;
    342306
    343307    /* count how many dirs and regular files there are */
     
    356320    for (d = i = 0; i < nfiles; i++) {
    357321        if (S_ISDIR(dn[i]->dstat.st_mode)) {
    358             if (which & (SPLIT_DIR|SPLIT_SUBDIR)) {
    359                 if ((which & SPLIT_DIR)
    360                     || ((dn[i]->name[0] != '.')
    361                         || (dn[i]->name[1]
    362                             && ((dn[i]->name[1] != '.')
    363                                 || dn[i]->name[2])))) {
    364                                     dnp[d++] = dn[i];
    365                                 }
     322            const char *name;
     323            if (!(which & (SPLIT_DIR|SPLIT_SUBDIR)))
     324                continue;
     325            name = dn[i]->name;
     326            if ((which & SPLIT_DIR)
     327             || name[0]!='.' || (name[1] && (name[1]!='.' || name[2]))
     328            ) {
     329                dnp[d++] = dn[i];
    366330            }
    367331        } else if (!(which & (SPLIT_DIR|SPLIT_SUBDIR))) {
     
    369333        }
    370334    }
    371     return (dnp);
    372 }
    373 
    374 /*----------------------------------------------------------------------*/
    375 #ifdef CONFIG_FEATURE_LS_SORTFILES
     335    return dnp;
     336}
     337
     338#if ENABLE_FEATURE_LS_SORTFILES
    376339static int sortcmp(const void *a, const void *b)
    377340{
    378341    struct dnode *d1 = *(struct dnode **)a;
    379342    struct dnode *d2 = *(struct dnode **)b;
    380     unsigned int sort_opts = all_fmt & SORT_MASK;
     343    unsigned sort_opts = all_fmt & SORT_MASK;
    381344    int dif;
    382345
    383     dif = 0;            /* assume SORT_NAME */
     346    dif = 0; /* assume SORT_NAME */
     347    // TODO: use pre-initialized function pointer
     348    // instead of branch forest
    384349    if (sort_opts == SORT_SIZE) {
    385350        dif = (int) (d2->dstat.st_size - d1->dstat.st_size);
     
    397362
    398363    if (dif == 0) {
    399         /* sort by name- may be a tie_breaker for time or size cmp */
     364        /* sort by name - may be a tie_breaker for time or size cmp */
    400365        if (ENABLE_LOCALE_SUPPORT) dif = strcoll(d1->name, d2->name);
    401366        else dif = strcmp(d1->name, d2->name);
    402367    }
    403368
    404     if (all_fmt & SORT_ORDER_REVERSE) {
     369    if (all_fmt & SORT_REVERSE) {
    405370        dif = -dif;
    406371    }
    407     return (dif);
    408 }
    409 
    410 /*----------------------------------------------------------------------*/
     372    return dif;
     373}
     374
    411375static void dnsort(struct dnode **dn, int size)
    412376{
    413     qsort(dn, size, sizeof *dn, sortcmp);
     377    qsort(dn, size, sizeof(*dn), sortcmp);
    414378}
    415379#else
    416 #define sortcmp(a, b) 0
    417 #define dnsort(dn, size)
    418 #endif
    419 
    420 
    421 /*----------------------------------------------------------------------*/
     380#define dnsort(dn, size) ((void)0)
     381#endif
     382
     383
    422384static void showfiles(struct dnode **dn, int nfiles)
    423385{
     
    430392        return;
    431393
    432     if (all_fmt & STYLE_ONE_RECORD_FLAG) {
     394    if (all_fmt & STYLE_LONG) {
    433395        ncols = 1;
    434396    } else {
    435         /* find the longest file name- use that as the column width */
     397        /* find the longest file name, use that as the column width */
    436398        for (i = 0; i < nfiles; i++) {
    437             int len = strlen(dn[i]->name) +
    438 #ifdef CONFIG_SELINUX
    439             ((all_fmt & LIST_CONTEXT) ? 33 : 0) +
    440 #endif
    441             ((all_fmt & LIST_INO) ? 8 : 0) +
    442             ((all_fmt & LIST_BLOCKS) ? 5 : 0);
     399            int len = strlen(dn[i]->name);
    443400            if (column_width < len)
    444401                column_width = len;
    445402        }
    446         column_width += tabstops;
     403        column_width += tabstops +
     404            USE_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + )
     405                         ((all_fmt & LIST_INO) ? 8 : 0) +
     406                         ((all_fmt & LIST_BLOCKS) ? 5 : 0);
    447407        ncols = (int) (terminal_width / column_width);
    448408    }
     
    450410    if (ncols > 1) {
    451411        nrows = nfiles / ncols;
    452         if ((nrows * ncols) < nfiles)
     412        if (nrows * ncols < nfiles)
    453413            nrows++;                /* round up fractionals */
    454414    } else {
     
    466426                if (column > 0) {
    467427                    nexttab -= column;
    468                     while (nexttab--) {
    469                         putchar(' ');
    470                         column++;
    471                     }
    472             }
     428                    printf("%*s", nexttab, "");
     429                    column += nexttab;
     430                }
    473431                nexttab = column + column_width;
    474432                column += list_single(dn[i]);
    475         }
     433            }
    476434        }
    477435        putchar('\n');
     
    480438}
    481439
    482 /*----------------------------------------------------------------------*/
     440
    483441static void showdirs(struct dnode **dn, int ndirs, int first)
    484442{
     
    494452        if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) {
    495453            if (!first)
    496                 printf("\n");
     454                puts("");
    497455            first = 0;
    498456            printf("%s:\n", dn[i]->fullname);
     
    502460        if (nfiles > 0) {
    503461            /* list all files at this level */
    504             if (ENABLE_FEATURE_LS_SORTFILES) dnsort(subdnp, nfiles);
     462            dnsort(subdnp, nfiles);
    505463            showfiles(subdnp, nfiles);
    506464            if (ENABLE_FEATURE_LS_RECURSIVE) {
     
    510468                    dndirs = countsubdirs(subdnp, nfiles);
    511469                    if (dndirs > 0) {
    512                         if (ENABLE_FEATURE_LS_SORTFILES) dnsort(dnd, dndirs);
     470                        dnsort(dnd, dndirs);
    513471                        showdirs(dnd, dndirs, 0);
    514472                        /* free the array of dnode pointers to the dirs */
     
    523481}
    524482
    525 /*----------------------------------------------------------------------*/
     483
    526484static struct dnode **list_dir(const char *path)
    527485{
     
    532490
    533491    if (path == NULL)
    534         return (NULL);
     492        return NULL;
    535493
    536494    dn = NULL;
    537495    nfiles = 0;
    538     dir = bb_opendir(path);
     496    dir = warn_opendir(path);
    539497    if (dir == NULL) {
    540498        status = EXIT_FAILURE;
    541         return (NULL);  /* could not open the dir */
     499        return NULL;    /* could not open the dir */
    542500    }
    543501    while ((entry = readdir(dir)) != NULL) {
     
    546504        /* are we going to list the file- it may be . or .. or a hidden file */
    547505        if (entry->d_name[0] == '.') {
    548             if ((entry->d_name[1] == 0 || (
    549                 entry->d_name[1] == '.'
    550                 && entry->d_name[2] == 0))
    551                     && !(all_fmt & DISP_DOT))
     506            if ((!entry->d_name[1] || (entry->d_name[1] == '.' && !entry->d_name[2]))
     507             && !(all_fmt & DISP_DOT)
     508            ) {
     509                continue;
     510            }
     511            if (!(all_fmt & DISP_HIDDEN))
     512                continue;
     513        }
     514        fullname = concat_path_file(path, entry->d_name);
     515        cur = my_stat(fullname, bb_basename(fullname), 0);
     516        if (!cur) {
     517            free(fullname);
    552518            continue;
    553             if (!(all_fmt & DISP_HIDDEN))
    554             continue;
    555         }
    556         fullname = concat_path_file(path, entry->d_name);
    557         cur = my_stat(fullname, strrchr(fullname, '/') + 1);
    558         if (!cur)
    559             continue;
     519        }
    560520        cur->allocated = 1;
    561521        cur->next = dn;
     
    566526
    567527    /* now that we know how many files there are
    568        ** allocate memory for an array to hold dnode pointers
     528     * allocate memory for an array to hold dnode pointers
    569529     */
    570530    if (dn == NULL)
    571         return (NULL);
     531        return NULL;
    572532    dnp = dnalloc(nfiles);
    573533    for (i = 0, cur = dn; i < nfiles; i++) {
     
    576536    }
    577537
    578     return (dnp);
    579 }
    580 
    581 /*----------------------------------------------------------------------*/
     538    return dnp;
     539}
     540
     541
     542#if ENABLE_FEATURE_LS_TIMESTAMPS
     543/* Do time() just once. Saves one syscall per file for "ls -l" */
     544/* Initialized in main() */
     545static time_t current_time_t;
     546#endif
     547
    582548static int list_single(struct dnode *dn)
    583549{
    584550    int i, column = 0;
    585551
    586 #ifdef CONFIG_FEATURE_LS_USERNAME
    587     char scratch[16];
    588 #endif
    589 #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
     552#if ENABLE_FEATURE_LS_TIMESTAMPS
    590553    char *filetime;
    591554    time_t ttime, age;
    592555#endif
    593 #if defined(CONFIG_FEATURE_LS_FILETYPES) || defined (CONFIG_FEATURE_LS_COLOR)
     556#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
    594557    struct stat info;
    595558    char append;
     
    597560
    598561    if (dn->fullname == NULL)
    599         return (0);
    600 
    601 #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
     562        return 0;
     563
     564#if ENABLE_FEATURE_LS_TIMESTAMPS
    602565    ttime = dn->dstat.st_mtime; /* the default time */
    603566    if (all_fmt & TIME_ACCESS)
     
    607570    filetime = ctime(&ttime);
    608571#endif
    609 #ifdef CONFIG_FEATURE_LS_FILETYPES
     572#if ENABLE_FEATURE_LS_FILETYPES
    610573    append = append_char(dn->dstat.st_mode);
    611574#endif
     
    614577        switch (all_fmt & (1 << i)) {
    615578        case LIST_INO:
    616             column += printf("%7ld ", (long int) dn->dstat.st_ino);
     579            column += printf("%7ld ", (long) dn->dstat.st_ino);
    617580            break;
    618581        case LIST_BLOCKS:
    619 #if _FILE_OFFSET_BITS == 64
    620             column += printf("%4lld ", (long long)dn->dstat.st_blocks >> 1);
    621 #else
    622             column += printf("%4ld ", dn->dstat.st_blocks >> 1);
    623 #endif
     582            column += printf("%4"OFF_FMT"d ", (off_t) dn->dstat.st_blocks >> 1);
    624583            break;
    625584        case LIST_MODEBITS:
     
    630589            break;
    631590        case LIST_ID_NAME:
    632 #ifdef CONFIG_FEATURE_LS_USERNAME
    633             bb_getpwuid(scratch, dn->dstat.st_uid, sizeof(scratch));
    634             printf("%-8.8s ", scratch);
    635             bb_getgrgid(scratch, dn->dstat.st_gid, sizeof(scratch));
    636             printf("%-8.8s", scratch);
     591#if ENABLE_FEATURE_LS_USERNAME
     592            printf("%-8.8s %-8.8s",
     593                get_cached_username(dn->dstat.st_uid),
     594                get_cached_groupname(dn->dstat.st_gid));
    637595            column += 17;
    638596            break;
     
    647605                       (int) minor(dn->dstat.st_rdev));
    648606            } else {
    649 #ifdef CONFIG_FEATURE_HUMAN_READABLE
    650607                if (all_fmt & LS_DISP_HR) {
    651608                    column += printf("%9s ",
    652                             make_human_readable_str(dn->dstat.st_size, 1, 0));
    653                 } else
    654 #endif
    655                 {
    656 #if _FILE_OFFSET_BITS == 64
    657                     column += printf("%9lld ", (long long) dn->dstat.st_size);
    658 #else
    659                     column += printf("%9ld ", dn->dstat.st_size);
    660 #endif
     609                        make_human_readable_str(dn->dstat.st_size, 1, 0));
     610                } else {
     611                    column += printf("%9"OFF_FMT"d ", (off_t) dn->dstat.st_size);
    661612                }
    662613            }
    663614            break;
    664 #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
     615#if ENABLE_FEATURE_LS_TIMESTAMPS
    665616        case LIST_FULLTIME:
    666617            printf("%24.24s ", filetime);
     
    669620        case LIST_DATE_TIME:
    670621            if ((all_fmt & LIST_FULLTIME) == 0) {
    671                 age = time(NULL) - ttime;
     622                /* current_time_t ~== time(NULL) */
     623                age = current_time_t - ttime;
    672624                printf("%6.6s ", filetime + 4);
    673625                if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) {
     
    681633            break;
    682634#endif
    683 #ifdef CONFIG_SELINUX
     635#if ENABLE_SELINUX
    684636        case LIST_CONTEXT:
    685637            {
     
    688640
    689641                if (dn->sid) {
    690                   /*  I assume sid initilized with NULL */
    691                   len = strlen(dn->sid)+1;
    692                   safe_strncpy(context, dn->sid, len);
    693                   freecon(dn->sid);
    694                 }else {
    695                   safe_strncpy(context, "unknown", 8);
     642                    /* I assume sid initilized with NULL */
     643                    len = strlen(dn->sid) + 1;
     644                    safe_strncpy(context, dn->sid, len);
     645                    freecon(dn->sid);
     646                } else {
     647                    safe_strncpy(context, "unknown", 8);
    696648                }
    697649                printf("%-32s ", context);
     
    701653#endif
    702654        case LIST_FILENAME:
    703 #ifdef CONFIG_FEATURE_LS_COLOR
    704655            errno = 0;
     656#if ENABLE_FEATURE_LS_COLOR
    705657            if (show_color && !lstat(dn->fullname, &info)) {
    706658                printf("\033[%d;%dm", bgcolor(info.st_mode),
    707                        fgcolor(info.st_mode));
     659                        fgcolor(info.st_mode));
    708660            }
    709661#endif
    710662            column += printf("%s", dn->name);
    711 #ifdef CONFIG_FEATURE_LS_COLOR
    712663            if (show_color) {
    713664                printf("\033[0m");
    714665            }
    715 #endif
    716666            break;
    717667        case LIST_SYMLINK:
    718668            if (S_ISLNK(dn->dstat.st_mode)) {
    719                 char *lpath = xreadlink(dn->fullname);
    720 
    721                 if (lpath) {
    722                     printf(" -> ");
    723 #if defined(CONFIG_FEATURE_LS_FILETYPES) || defined (CONFIG_FEATURE_LS_COLOR)
    724                     if (!stat(dn->fullname, &info)) {
    725                         append = append_char(info.st_mode);
    726                     }
    727 #endif
    728 #ifdef CONFIG_FEATURE_LS_COLOR
    729                     if (show_color) {
    730                         errno = 0;
    731                         printf("\033[%d;%dm", bgcolor(info.st_mode),
    732                                fgcolor(info.st_mode));
    733                     }
    734 #endif
    735                     column += printf("%s", lpath) + 4;
    736 #ifdef CONFIG_FEATURE_LS_COLOR
    737                     if (show_color) {
    738                         printf("\033[0m");
    739                     }
    740 #endif
    741                     free(lpath);
     669                char *lpath = xmalloc_readlink_or_warn(dn->fullname);
     670                if (!lpath) break;
     671                printf(" -> ");
     672#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR
     673                if (!stat(dn->fullname, &info)) {
     674                    append = append_char(info.st_mode);
    742675                }
    743             }
    744             break;
    745 #ifdef CONFIG_FEATURE_LS_FILETYPES
     676#endif
     677#if ENABLE_FEATURE_LS_COLOR
     678                if (show_color) {
     679                    errno = 0;
     680                    printf("\033[%d;%dm", bgcolor(info.st_mode),
     681                           fgcolor(info.st_mode));
     682                }
     683#endif
     684                column += printf("%s", lpath) + 4;
     685                if (show_color) {
     686                    printf("\033[0m");
     687                }
     688                free(lpath);
     689            }
     690            break;
     691#if ENABLE_FEATURE_LS_FILETYPES
    746692        case LIST_FILETYPE:
    747             if (append != '\0') {
    748                 printf("%1c", append);
     693            if (append) {
     694                putchar(append);
    749695                column++;
    750696            }
     
    756702    return column;
    757703}
    758 
    759 /*----------------------------------------------------------------------*/
    760704
    761705/* "[-]Cadil1", POSIX mandated options, busybox always supports */
     
    767711/* "[-]K", SELinux mandated options, busybox optionally supports */
    768712/* "[-]e", I think we made this one up */
    769 
    770 #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
    771 # define LS_STR_TIMESTAMPS  "cetu"
    772 #else
    773 # define LS_STR_TIMESTAMPS  ""
    774 #endif
    775 
    776 #ifdef CONFIG_FEATURE_LS_FILETYPES
    777 # define LS_STR_FILETYPES   "Fp"
    778 #else
    779 # define LS_STR_FILETYPES   ""
    780 #endif
    781 
    782 #ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
    783 # define LS_STR_FOLLOW_LINKS    "L"
    784 #else
    785 # define LS_STR_FOLLOW_LINKS    ""
    786 #endif
    787 
    788 #ifdef CONFIG_FEATURE_LS_RECURSIVE
    789 # define LS_STR_RECURSIVE   "R"
    790 #else
    791 # define LS_STR_RECURSIVE   ""
    792 #endif
    793 
    794 #ifdef CONFIG_FEATURE_HUMAN_READABLE
    795 # define LS_STR_HUMAN_READABLE  "h"
    796 #else
    797 # define LS_STR_HUMAN_READABLE  ""
    798 #endif
    799 
    800 #ifdef CONFIG_SELINUX
    801 # define LS_STR_SELINUX "K"
    802 #else
    803 # define LS_STR_SELINUX ""
    804 #endif
    805 
    806 #ifdef CONFIG_FEATURE_AUTOWIDTH
    807 # define LS_STR_AUTOWIDTH   "T:w:"
    808 #else
    809 # define LS_STR_AUTOWIDTH   ""
    810 #endif
    811 
    812 static const char ls_options[]="Cadil1gnsxAk" \
    813     LS_STR_TIMESTAMPS \
    814     USE_FEATURE_LS_SORTFILES("SXrv") \
    815     LS_STR_FILETYPES \
    816     LS_STR_FOLLOW_LINKS \
    817     LS_STR_RECURSIVE \
    818     LS_STR_HUMAN_READABLE \
    819     LS_STR_SELINUX \
    820     LS_STR_AUTOWIDTH;
    821 
    822 #define LIST_MASK_TRIGGER   0
    823 #define STYLE_MASK_TRIGGER  STYLE_MASK
    824 #define SORT_MASK_TRIGGER   SORT_MASK
    825 #define DISP_MASK_TRIGGER   DISP_ROWS
     713static const char ls_options[] ALIGN1 =
     714    "Cadil1gnsxAk"
     715    USE_FEATURE_LS_TIMESTAMPS("cetu")
     716    USE_FEATURE_LS_SORTFILES("SXrv")
     717    USE_FEATURE_LS_FILETYPES("Fp")
     718    USE_FEATURE_LS_FOLLOWLINKS("L")
     719    USE_FEATURE_LS_RECURSIVE("R")
     720    USE_FEATURE_HUMAN_READABLE("h")
     721    USE_SELINUX("K")
     722    USE_FEATURE_AUTOWIDTH("T:w:")
     723    USE_SELINUX("Z");
     724
     725enum {
     726    LIST_MASK_TRIGGER   = 0,
     727    STYLE_MASK_TRIGGER  = STYLE_MASK,
     728    DISP_MASK_TRIGGER   = DISP_ROWS,
     729    SORT_MASK_TRIGGER   = SORT_MASK,
     730};
    826731
    827732static const unsigned opt_flags[] = {
    828     LIST_SHORT | STYLE_COLUMNS, /* C */
    829     DISP_HIDDEN | DISP_DOT,     /* a */
    830     DISP_NOLIST,                /* d */
    831     LIST_INO,                   /* i */
    832     LIST_LONG | STYLE_LONG,     /* l - remember LS_DISP_HR in mask! */
    833     LIST_SHORT | STYLE_SINGLE,  /* 1 */
    834     0,                          /* g - ingored */
    835     LIST_ID_NUMERIC,            /* n */
    836     LIST_BLOCKS,                /* s */
    837     DISP_ROWS,                  /* x */
    838     DISP_HIDDEN,                /* A */
    839 #ifdef CONFIG_SELINUX
    840     LIST_CONTEXT,               /* k */
    841 #else
    842     0,                          /* k - ingored */
    843 #endif
    844 #ifdef CONFIG_FEATURE_LS_TIMESTAMPS
    845     TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME),   /* c */
    846     LIST_FULLTIME,              /* e */
    847     ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME,   /* t */
    848     TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME),   /* u */
    849 #endif
    850 #ifdef CONFIG_FEATURE_LS_SORTFILES
    851     SORT_SIZE,                  /* S */
    852     SORT_EXT,                   /* X */
    853     SORT_ORDER_REVERSE,         /* r */
    854     SORT_VERSION,               /* v */
    855 #endif
    856 #ifdef CONFIG_FEATURE_LS_FILETYPES
    857     LIST_FILETYPE | LIST_EXEC,  /* F */
    858     LIST_FILETYPE,              /* p */
    859 #endif
    860 #ifdef CONFIG_FEATURE_LS_FOLLOWLINKS
    861     FOLLOW_LINKS,               /* L */
    862 #endif
    863 #ifdef CONFIG_FEATURE_LS_RECURSIVE
    864     DISP_RECURSIVE,             /* R */
    865 #endif
    866 #ifdef CONFIG_FEATURE_HUMAN_READABLE
    867     LS_DISP_HR,                 /* h */
    868 #endif
    869 #ifdef CONFIG_SELINUX
     733    LIST_SHORT | STYLE_COLUMNS, /* C */
     734    DISP_HIDDEN | DISP_DOT,     /* a */
     735    DISP_NOLIST,                /* d */
     736    LIST_INO,                   /* i */
     737    LIST_LONG | STYLE_LONG,     /* l - remember LS_DISP_HR in mask! */
     738    LIST_SHORT | STYLE_SINGLE,  /* 1 */
     739    0,                          /* g - ingored */
     740    LIST_ID_NUMERIC,            /* n */
     741    LIST_BLOCKS,                /* s */
     742    DISP_ROWS,                  /* x */
     743    DISP_HIDDEN,                /* A */
     744    ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */
     745#if ENABLE_FEATURE_LS_TIMESTAMPS
     746    TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME),   /* c */
     747    LIST_FULLTIME,              /* e */
     748    ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME,   /* t */
     749    TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME),   /* u */
     750#endif
     751#if ENABLE_FEATURE_LS_SORTFILES
     752    SORT_SIZE,                  /* S */
     753    SORT_EXT,                   /* X */
     754    SORT_REVERSE,               /* r */
     755    SORT_VERSION,               /* v */
     756#endif
     757#if ENABLE_FEATURE_LS_FILETYPES
     758    LIST_FILETYPE | LIST_EXEC,  /* F */
     759    LIST_FILETYPE,              /* p */
     760#endif
     761#if ENABLE_FEATURE_LS_FOLLOWLINKS
     762    FOLLOW_LINKS,               /* L */
     763#endif
     764#if ENABLE_FEATURE_LS_RECURSIVE
     765    DISP_RECURSIVE,             /* R */
     766#endif
     767#if ENABLE_FEATURE_HUMAN_READABLE
     768    LS_DISP_HR,                 /* h */
     769#endif
     770#if ENABLE_SELINUX
    870771    LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */
    871772#endif
    872 #ifdef CONFIG_FEATURE_AUTOWIDTH
    873        0, 0,                    /* T, w - ignored */
     773#if ENABLE_FEATURE_AUTOWIDTH
     774    0, 0,                       /* T, w - ignored */
     775#endif
     776#if ENABLE_SELINUX
     777    LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */
    874778#endif
    875779    (1U<<31)
     
    877781
    878782
    879 /*----------------------------------------------------------------------*/
    880 
     783/* THIS IS A "SAFE" APPLET, main() MAY BE CALLED INTERNALLY FROM SHELL */
     784/* BE CAREFUL! */
     785
     786int ls_main(int argc, char **argv);
    881787int ls_main(int argc, char **argv)
    882788{
     
    886792    struct dnode *dn;
    887793    struct dnode *cur;
    888     long opt;
     794    unsigned opt;
    889795    int nfiles = 0;
    890796    int dnfiles;
     
    894800    int i;
    895801    char **av;
    896 #ifdef CONFIG_FEATURE_AUTOWIDTH
    897     char *tabstops_str = NULL;
    898     char *terminal_width_str = NULL;
    899 #endif
    900 #ifdef CONFIG_FEATURE_LS_COLOR
    901     char *color_opt;
     802    USE_FEATURE_AUTOWIDTH(char *tabstops_str = NULL;)
     803    USE_FEATURE_AUTOWIDTH(char *terminal_width_str = NULL;)
     804    USE_FEATURE_LS_COLOR(char *color_opt;)
     805
     806#if ENABLE_FEATURE_LS_TIMESTAMPS
     807    time(&current_time_t);
    902808#endif
    903809
    904810    all_fmt = LIST_SHORT |
    905         (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_ORDER_FORWARD));
    906 
    907 #ifdef CONFIG_FEATURE_AUTOWIDTH
    908     /* Obtain the terminal width. */
    909     get_terminal_width_height(STDOUT_FILENO, &terminal_width, NULL);
     811        (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD));
     812
     813#if ENABLE_FEATURE_AUTOWIDTH
     814    /* Obtain the terminal width */
     815    get_terminal_width_height(STDIN_FILENO, &terminal_width, NULL);
    910816    /* Go one less... */
    911817    terminal_width--;
    912818#endif
    913819
    914 #ifdef CONFIG_FEATURE_LS_COLOR
    915     bb_applet_long_options = ls_color_opt;
    916 #endif
    917 
    918820    /* process options */
    919 #ifdef CONFIG_FEATURE_AUTOWIDTH
    920     opt = bb_getopt_ulflags(argc, argv, ls_options, &tabstops_str, &terminal_width_str
    921 #ifdef CONFIG_FEATURE_LS_COLOR
    922         , &color_opt
    923 #endif
    924         );
    925     if (tabstops_str) {
    926         tabstops = atoi(tabstops_str);
    927     }
    928     if (terminal_width_str) {
    929         terminal_width = atoi(terminal_width_str);
    930     }
     821    USE_FEATURE_LS_COLOR(applet_long_options = ls_color_opt;)
     822#if ENABLE_FEATURE_AUTOWIDTH
     823    opt = getopt32(argv, ls_options, &tabstops_str, &terminal_width_str
     824                USE_FEATURE_LS_COLOR(, &color_opt));
     825    if (tabstops_str)
     826        tabstops = xatou(tabstops_str);
     827    if (terminal_width_str)
     828        terminal_width = xatou(terminal_width_str);
    931829#else
    932     opt = bb_getopt_ulflags(argc, argv, ls_options
    933 #ifdef CONFIG_FEATURE_LS_COLOR
    934         , &color_opt
    935 #endif
    936         );
     830    opt = getopt32(argv, ls_options USE_FEATURE_LS_COLOR(, &color_opt));
    937831#endif
    938832    for (i = 0; opt_flags[i] != (1U<<31); i++) {
    939833        if (opt & (1 << i)) {
    940             unsigned int flags = opt_flags[i];
    941 
    942             if (flags & LIST_MASK_TRIGGER) {
     834            unsigned flags = opt_flags[i];
     835
     836            if (flags & LIST_MASK_TRIGGER)
    943837                all_fmt &= ~LIST_MASK;
    944             }
    945             if (flags & STYLE_MASK_TRIGGER) {
     838            if (flags & STYLE_MASK_TRIGGER)
    946839                all_fmt &= ~STYLE_MASK;
    947             }
    948             if (ENABLE_FEATURE_LS_SORTFILES && (flags & SORT_MASK_TRIGGER)) {
     840            if (flags & SORT_MASK_TRIGGER)
    949841                all_fmt &= ~SORT_MASK;
    950             }
    951             if (flags & DISP_MASK_TRIGGER) {
     842            if (flags & DISP_MASK_TRIGGER)
    952843                all_fmt &= ~DISP_MASK;
    953             }
    954             if (flags & TIME_MASK) {
     844            if (flags & TIME_MASK)
    955845                all_fmt &= ~TIME_MASK;
    956             }
    957             if (flags & LIST_CONTEXT) {
     846            if (flags & LIST_CONTEXT)
    958847                all_fmt |= STYLE_SINGLE;
    959             }
    960 #ifdef CONFIG_FEATURE_HUMAN_READABLE
    961             if (opt == 'l') {
    962                 all_fmt &= ~LS_DISP_HR;
    963             }
    964 #endif
     848            /* huh?? opt cannot be 'l' */
     849            //if (LS_DISP_HR && opt == 'l')
     850            //  all_fmt &= ~LS_DISP_HR;
    965851            all_fmt |= flags;
    966852        }
    967853    }
    968854
    969 #ifdef CONFIG_FEATURE_LS_COLOR
    970     {
    971         /* find color bit value - last position for short getopt */
    972 
    973 #if CONFIG_FEATURE_LS_COLOR_IS_DEFAULT
    974         char *p;
    975 
    976         if ((p = getenv ("LS_COLORS")) != NULL &&
    977             (*p == '\0' || (strcmp(p, "none") == 0))) {
    978             ;
    979         } else if (isatty(STDOUT_FILENO)) {
     855#if ENABLE_FEATURE_LS_COLOR
     856    /* find color bit value - last position for short getopt */
     857    if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && isatty(STDOUT_FILENO)) {
     858        char *p = getenv("LS_COLORS");
     859        /* LS_COLORS is unset, or (not empty && not "none") ? */
     860        if (!p || (p[0] && strcmp(p, "none")))
    980861            show_color = 1;
    981         }
    982 #endif
    983 
    984         if((opt & (1 << i))) {  /* next flag after short options */
    985             if (color_opt == NULL || strcmp("always", color_opt) == 0)
    986                 show_color = 1;
    987             else if (color_opt != NULL && strcmp("never", color_opt) == 0)
    988                 show_color = 0;
    989             else if (color_opt != NULL && strcmp("auto", color_opt) == 0 && isatty(STDOUT_FILENO))
    990                 show_color = 1;
    991         }
     862    }
     863    if (opt & (1 << i)) {  /* next flag after short options */
     864        if (!color_opt || !strcmp("always", color_opt))
     865            show_color = 1;
     866        else if (color_opt && !strcmp("never", color_opt))
     867            show_color = 0;
     868        else if (color_opt && !strcmp("auto", color_opt) && isatty(STDOUT_FILENO))
     869            show_color = 1;
    992870    }
    993871#endif
    994872
    995873    /* sort out which command line options take precedence */
    996 #ifdef CONFIG_FEATURE_LS_RECURSIVE
    997     if (all_fmt & DISP_NOLIST)
     874    if (ENABLE_FEATURE_LS_RECURSIVE && (all_fmt & DISP_NOLIST))
    998875        all_fmt &= ~DISP_RECURSIVE; /* no recurse if listing only dir */
    999 #endif
    1000876    if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) {
    1001877        if (all_fmt & TIME_CHANGE)
     
    1006882    if ((all_fmt & STYLE_MASK) != STYLE_LONG) /* only for long list */
    1007883        all_fmt &= ~(LIST_ID_NUMERIC|LIST_FULLTIME|LIST_ID_NAME|LIST_ID_NUMERIC);
    1008 #ifdef CONFIG_FEATURE_LS_USERNAME
    1009     if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC))
    1010         all_fmt &= ~LIST_ID_NAME;   /* don't list names if numeric uid */
    1011 #endif
     884    if (ENABLE_FEATURE_LS_USERNAME)
     885        if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC))
     886            all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */
    1012887
    1013888    /* choose a display format */
     
    1024899    ac = argc - optind; /* how many cmd line args are left */
    1025900    if (ac < 1) {
    1026         static const char * const dotdir[] = { "." };
     901        static const char *const dotdir[] = { "." };
    1027902
    1028903        av = (char **) dotdir;
     
    1036911        all_fmt |= DISP_DIRNAME;    /* 2 or more items? label directories */
    1037912
    1038     /* stuff the command line file names into an dnode array */
     913    /* stuff the command line file names into a dnode array */
    1039914    dn = NULL;
    1040915    for (oi = 0; oi < ac; oi++) {
    1041         cur = my_stat(av[oi], av[oi]);
     916        /* ls w/o -l follows links on command line */
     917        cur = my_stat(av[oi], av[oi], !(all_fmt & STYLE_LONG));
    1042918        if (!cur)
    1043919            continue;
     
    1049925
    1050926    /* now that we know how many files there are
    1051        ** allocate memory for an array to hold dnode pointers
     927     * allocate memory for an array to hold dnode pointers
    1052928     */
    1053929    dnp = dnalloc(nfiles);
     
    1058934
    1059935    if (all_fmt & DISP_NOLIST) {
    1060         if (ENABLE_FEATURE_LS_SORTFILES) dnsort(dnp, nfiles);
     936        dnsort(dnp, nfiles);
    1061937        if (nfiles > 0)
    1062938            showfiles(dnp, nfiles);
     
    1067943        dnfiles = nfiles - dndirs;
    1068944        if (dnfiles > 0) {
    1069             if (ENABLE_FEATURE_LS_SORTFILES) dnsort(dnf, dnfiles);
     945            dnsort(dnf, dnfiles);
    1070946            showfiles(dnf, dnfiles);
    1071947            if (ENABLE_FEATURE_CLEAN_UP)
     
    1073949        }
    1074950        if (dndirs > 0) {
    1075             if (ENABLE_FEATURE_LS_SORTFILES) dnsort(dnd, dndirs);
     951            dnsort(dnd, dndirs);
    1076952            showdirs(dnd, dndirs, dnfiles == 0);
    1077953            if (ENABLE_FEATURE_CLEAN_UP)
     
    1081957    if (ENABLE_FEATURE_CLEAN_UP)
    1082958        dfree(dnp, nfiles);
    1083     return (status);
    1084 }
     959    return status;
     960}
Note: See TracChangeset for help on using the changeset viewer.