Comment on kernel stuff
[oweals/busybox.git] / coreutils / ls.c
index f23c1e086d385b32e38c7a38ac726ee52fc7df05..0644cde877e7e4eb777a039a7a1afba61c5fcd6a 100644 (file)
  * it more portable.
  *
  * KNOWN BUGS:
- * 1. messy output if you mix files and directories on the command line
- * 2. ls -l of a directory doesn't give "total <blocks>" header
- * 3. ls of a symlink to a directory doesn't list directory contents
- * 4. hidden files can make column width too large
+ * 1. ls -l of a directory doesn't give "total <blocks>" header
+ * 2. ls of a symlink to a directory doesn't list directory contents
+ * 3. hidden files can make column width too large
+ *
  * NON-OPTIMAL BEHAVIOUR:
  * 1. autowidth reads directories twice
  * 2. if you do a short directory listing without filetype characters
 /************************************************************************/
 
 #include "internal.h"
-#if !defined(__GLIBC__) && (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
-# include <linux/types.h>
-#else
 # include <sys/types.h>
-#endif
 #include <sys/stat.h>
 #include <stdio.h>
 #include <unistd.h>
 #define APPCHAR(mode)  ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)])
 #endif
 
-#ifndef MAJOR
-#define MAJOR(dev) (((dev)>>8)&0xff)
-#define MINOR(dev) ((dev)&0xff)
-#endif
-
 #define FMT_AUTO       0
 #define FMT_LONG       1                       /* one record per line, extended info */
 #define FMT_SINGLE     2                       /* one record per line */
 #define DISP_DOT       8                       /* show . and .. */
 #define DISP_NUMERIC   16              /* numeric uid and gid */
 #define DISP_FULLTIME  32              /* show extended time display */
-#define DIR_NOLIST     64                      /* show directory as itself, not contents */
+#define DIR_NOLIST             64              /* show directory as itself, not contents */
 #define DISP_DIRNAME   128             /* show directory name (for internal use) */
-#define DIR_RECURSE    256                     /* -R (not yet implemented) */
+#define DISP_RECURSIVE 256             /* Do a recursive listing */
+
+#ifndef MAJOR
+#define MAJOR(dev) (((dev)>>8)&0xff)
+#define MINOR(dev) ((dev)&0xff)
+#endif
 
 static unsigned char display_fmt = FMT_AUTO;
 static unsigned short opts = 0;
 static unsigned short column = 0;
 
 #ifdef BB_FEATURE_AUTOWIDTH
-static unsigned short terminal_width = 0, column_width = 0;
+static unsigned short terminal_width = 0;
+static unsigned short column_width = 0;
+static unsigned short toplevel_column_width = 0;
 #else
 #define terminal_width TERMINAL_WIDTH
 #define column_width   COLUMN_WIDTH
@@ -182,7 +180,7 @@ static char append_char(mode_t mode)
 static void list_single(const char *name, struct stat *info,
                                                const char *fullname)
 {
-       char scratch[PATH_MAX + 1];
+       char scratch[BUFSIZ + 1];
        short len = strlen(name);
 
 #ifdef BB_FEATURE_LS_FILETYPES
@@ -343,12 +341,15 @@ static int list_item(const char *name)
        struct stat info;
        DIR *dir;
        struct dirent *entry;
-       char fullname[MAXNAMLEN + 1], *fnend;
+       char fullname[BUFSIZ + 1], *fnend;
 
        if (lstat(name, &info))
                goto listerr;
 
        if (!S_ISDIR(info.st_mode) || (opts & DIR_NOLIST)) {
+#ifdef BB_FEATURE_AUTOWIDTH
+               column_width = toplevel_column_width;
+#endif
                list_single(name, &info, name);
                return 0;
        }
@@ -407,6 +408,15 @@ static int list_item(const char *name)
                list_single(entry->d_name, &info, fullname);
        }
        closedir(dir);
+
+       if (opts & DISP_DIRNAME) {      /* separate the directory */
+               if (column) {
+                       wr("\n", 1);
+               }
+               wr("\n", 1);
+               column = 0;
+       }
+
        return 0;
 
   direrr:
@@ -436,10 +446,54 @@ static const char ls_usage[] = "ls [-1a"
 #ifdef BB_FEATURE_LS_FILETYPES
        "F"
 #endif
-#ifdef FEATURE_RECURSIVE
+#ifdef BB_FEATURE_LS_RECURSIVE
        "R"
 #endif
-       "] [filenames...]\n";
+       "] [filenames...]\n"
+#ifndef BB_FEATURE_TRIVIAL_HELP
+       "\nList directory contents\n\n"
+       "Options:\n"
+       "\t-a\tdo not hide entries starting with .\n"
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+       "\t-c\twith -l: show ctime (the time of last\n"
+    "\t\tmodification of file status information)\n"
+#endif
+       "\t-d\tlist directory entries instead of contents\n"
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+       "\t-e\tlist both full date and full time\n"
+#endif
+       "\t-l\tuse a long listing format\n"
+       "\t-n\tlist numeric UIDs and GIDs instead of names\n"
+#ifdef BB_FEATURE_LS_FILETYPES
+       "\t-p\tappend indicator (one of /=@|) to entries\n"
+#endif
+#ifdef BB_FEATURE_LS_TIMESTAMPS
+       "\t-u\twith -l: show access time (the time of last\n"
+       "\t\taccess of the file)\n"
+#endif
+       "\t-x\tlist entries by lines instead of by columns\n"
+       "\t-A\tdo not list implied . and ..\n"
+       "\t-C\tlist entries by columns\n"
+#ifdef BB_FEATURE_LS_FILETYPES
+       "\t-F\tappend indicator (one of */=@|) to entries\n"
+#endif
+#ifdef BB_FEATURE_LS_RECURSIVE
+       "\t-R\tlist subdirectories recursively\n"
+#endif
+#endif
+       ;
+
+
+#ifdef BB_FEATURE_LS_RECURSIVE
+static int dirAction(const char *fileName, struct stat *statbuf, void* junk)
+{
+       int i;
+       fprintf(stdout, "\n%s:\n", fileName);
+       i = list_item(fileName);
+       newline();
+       return (i);
+}
+#endif
 
 extern int ls_main(int argc, char **argv)
 {
@@ -494,11 +548,6 @@ extern int ls_main(int argc, char **argv)
                        case 'd':
                                opts |= DIR_NOLIST;
                                break;
-#ifdef FEATURE_RECURSIVE
-                       case 'R':
-                               opts |= DIR_RECURSE;
-                               break;
-#endif
 #ifdef BB_FEATURE_LS_TIMESTAMPS
                        case 'u':
                                time_fmt = TIME_ACCESS;
@@ -510,6 +559,13 @@ extern int ls_main(int argc, char **argv)
                                opts |= DISP_FULLTIME;
                                break;
 #endif
+#ifdef BB_FEATURE_LS_RECURSIVE
+                       case 'R':
+                               opts |= DISP_RECURSIVE;
+                               break;
+#endif
+                       case 'g': /* ignore -- for ftp servers */
+                               break;
                        default:
                                goto print_usage_message;
                        }
@@ -530,18 +586,31 @@ extern int ls_main(int argc, char **argv)
        for (i = argi; i < argc; i++) {
                int len = strlen(argv[i]);
 
-               if (column_width < len)
-                       column_width = len;
+               if (toplevel_column_width < len)
+                       toplevel_column_width = len;
        }
 #endif
 
        /* process files specified, or current directory if none */
-       i = 0;
-       if (argi == argc)
-               i = list_item(".");
-       while (argi < argc)
-               i |= list_item(argv[argi++]);
-       newline();
+#ifdef BB_FEATURE_LS_RECURSIVE
+       if (opts & DISP_RECURSIVE) {
+               i = 0;
+               if (argi == argc) {
+                       i = recursiveAction(".", TRUE, FALSE, FALSE, NULL, dirAction, NULL);
+               }
+               while (argi < argc) {
+                       i |= recursiveAction(argv[argi++], TRUE, FALSE, FALSE, NULL, dirAction, NULL);
+               }
+       } else 
+#endif
+       {
+               i = 0;
+               if (argi == argc)
+                       i = list_item(".");
+               while (argi < argc)
+                       i |= list_item(argv[argi++]);
+               newline();
+       }
        exit(i);
 
   print_usage_message: