Compatibility fixes:
authorDenis Vlasenko <vda.linux@googlemail.com>
Fri, 20 Mar 2009 22:17:13 +0000 (22:17 -0000)
committerDenis Vlasenko <vda.linux@googlemail.com>
Fri, 20 Mar 2009 22:17:13 +0000 (22:17 -0000)
grep: support -z
find: support --mindepth
  together +45 bytes
cpio: support -p (configurable, +230 bytes)
libbb: tweaks for cpio

TODO_config_nommu
archival/Config.in
archival/cpio.c
findutils/find.c
findutils/grep.c
include/libbb.h
include/usage.h
libbb/vfork_daemon_rexec.c
miscutils/setsid.c
scripts/defconfig

index 428d9b3000809de5846e18762e9c225c5cabff0b..2061bfd1cd6eeeaa4e630041ecf2167d3e5bf472 100644 (file)
@@ -110,6 +110,7 @@ CONFIG_BUNZIP2=y
 CONFIG_BZIP2=y
 CONFIG_CPIO=y
 CONFIG_FEATURE_CPIO_O=y
+CONFIG_FEATURE_CPIO_P=y
 CONFIG_DPKG=y
 CONFIG_DPKG_DEB=y
 CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY=y
index 0b5cf37507f622bfd2ea3249c9a1412608ea38c3..64b44c218c90f311614f8bb02de2089a29a35ea9 100644 (file)
@@ -110,6 +110,13 @@ config FEATURE_CPIO_O
          This implementation of cpio can create cpio archives in the "newc"
          format only.
 
+config FEATURE_CPIO_P
+       bool "Support for passthrough mode"
+       default n
+       depends on FEATURE_CPIO_O
+       help
+         Passthrough mode. Rarely used.
+
 config DPKG
        bool "dpkg"
        default n
index 1c30d89a8becda68a370a3d41e0586140366838b..929d544fffaa929ab2ef107cb0d023d9cc310c50 100644 (file)
@@ -259,8 +259,9 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
                CPIO_OPT_FILE               = (1 << 4),
                CPIO_OPT_CREATE_LEADING_DIR = (1 << 5),
                CPIO_OPT_PRESERVE_MTIME     = (1 << 6),
-               CPIO_OPT_CREATE             = (1 << 7),
-               CPIO_OPT_FORMAT             = (1 << 8),
+               CPIO_OPT_CREATE             = (1 << 7) * ENABLE_FEATURE_CPIO_O,
+               CPIO_OPT_FORMAT             = (1 << 8) * ENABLE_FEATURE_CPIO_O,
+               CPIO_OPT_PASSTHROUGH        = (1 << 9) * ENABLE_FEATURE_CPIO_P,
        };
 
 #if ENABLE_GETOPT_LONG
@@ -270,21 +271,66 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
 #if ENABLE_FEATURE_CPIO_O
                "create\0"       No_argument       "o"
                "format\0"       Required_argument "H"
+#if ENABLE_FEATURE_CPIO_P
+               "pass-through\0" No_argument       "p"
+#endif
 #endif
                ;
 #endif
 
-       /* Initialize */
-       archive_handle = init_handle();
-       archive_handle->src_fd = STDIN_FILENO;
-       archive_handle->seek = seek_by_read;
-       archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
-
-#if ENABLE_FEATURE_CPIO_O
-       opt = getopt32(argv, "ituvF:dmoH:", &cpio_filename, &cpio_fmt);
+       /* As of now we do not enforce this: */
+       /* -i,-t,-o,-p are mutually exclusive */
+       /* -u,-d,-m make sense only with -i or -p */
+       /* -F makes sense only with -o */
+#if !ENABLE_FEATURE_CPIO_O
+       opt = getopt32(argv, "ituvF:dm", &cpio_filename);
+#else
+       opt = getopt32(argv, "ituvF:dmoH:" USE_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
+       if (opt & CPIO_OPT_PASSTHROUGH) {
+               pid_t pid;
+               struct fd_pair pp;
 
+               if (argv[optind] == NULL)
+                       bb_show_usage();
+               if (opt & CPIO_OPT_CREATE_LEADING_DIR)
+                       mkdir(argv[optind], 0777);
+               /* Crude existence check:
+                * close(xopen(argv[optind], O_RDONLY | O_DIRECTORY));
+                * We can also xopen, fstat, IS_DIR, later fchdir.
+                * This would check for existence earlier and cleaner.
+                * As it stands now, if we fail xchdir later,
+                * child dies on EPIPE, unless it caught
+                * a diffrerent problem earlier.
+                * This is good enough for now.
+                */
+#if !BB_MMU
+               pp.rd = 3;
+               pp.wr = 4;
+               if (!re_execed) {
+                       close(3);
+                       close(4);
+                       xpiped_pair(pp);
+               }
+#else
+               xpiped_pair(pp);
+#endif
+               pid = fork_or_rexec(argv);
+               if (pid == 0) { /* child */
+                       close(pp.rd);
+                       xmove_fd(pp.wr, STDOUT_FILENO);
+                       goto dump;
+               }
+               /* parent */
+               xchdir(argv[optind++]);
+               close(pp.wr);
+               xmove_fd(pp.rd, STDIN_FILENO);
+               opt &= ~CPIO_OPT_PASSTHROUGH;
+               opt |= CPIO_OPT_EXTRACT;
+               goto skip;
+       }
+       /* -o */
        if (opt & CPIO_OPT_CREATE) {
-               if (*cpio_fmt != 'n')
+               if (*cpio_fmt != 'n') /* we _require_ "-H newc" */
                        bb_show_usage();
                if (opt & CPIO_OPT_FILE) {
                        fclose(stdout);
@@ -292,13 +338,18 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
                        /* Paranoia: I don't trust libc that much */
                        xdup2(fileno(stdout), STDOUT_FILENO);
                }
+ dump:
                return cpio_o();
        }
-#else
-       opt = getopt32(argv, "ituvF:dm", &cpio_filename);
+ skip:
 #endif
        argv += optind;
 
+       archive_handle = init_handle();
+       archive_handle->src_fd = STDIN_FILENO;
+       archive_handle->seek = seek_by_read;
+       archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER;
+
        /* One of either extract or test options must be given */
        if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) {
                bb_show_usage();
@@ -306,9 +357,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
 
        if (opt & CPIO_OPT_TEST) {
                /* if both extract and test options are given, ignore extract option */
-               if (opt & CPIO_OPT_EXTRACT) {
-                       opt &= ~CPIO_OPT_EXTRACT;
-               }
+               opt &= ~CPIO_OPT_EXTRACT;
                archive_handle->action_header = header_list;
        }
        if (opt & CPIO_OPT_EXTRACT) {
index f2b89746f515864a16a20564fe9798c5a0c11fa8..df632f21984050a7d2ce06d02db55f7e19a7a53c 100644 (file)
@@ -381,9 +381,11 @@ static int FAST_FUNC fileAction(const char *fileName,
 {
        int i;
 #if ENABLE_FEATURE_FIND_MAXDEPTH
-       int maxdepth = (int)(ptrdiff_t)userData;
+#define minmaxdepth ((int*)userData)
 
-       if (depth > maxdepth) return SKIP;
+       if (depth < minmaxdepth[0]) return TRUE;
+       if (depth > minmaxdepth[1]) return SKIP;
+#undef minmaxdepth
 #endif
 
 #if ENABLE_FEATURE_FIND_XDEV
@@ -812,19 +814,21 @@ int find_main(int argc, char **argv)
        static const char options[] ALIGN1 =
                          "-follow\0"
 USE_FEATURE_FIND_XDEV(    "-xdev\0"    )
-USE_FEATURE_FIND_MAXDEPTH("-maxdepth\0")
+USE_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0")
                          ;
        enum {
                          OPT_FOLLOW,
 USE_FEATURE_FIND_XDEV(    OPT_XDEV    ,)
-USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,)
+USE_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
        };
 
        char *arg;
        char **argp;
        int i, firstopt, status = EXIT_SUCCESS;
 #if ENABLE_FEATURE_FIND_MAXDEPTH
-       int maxdepth = INT_MAX;
+       int minmaxdepth[2] = { 0, INT_MAX };
+#else
+#define minmaxdepth NULL
 #endif
 
        for (firstopt = 1; firstopt < argc; firstopt++) {
@@ -875,10 +879,10 @@ USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,)
                }
 #endif
 #if ENABLE_FEATURE_FIND_MAXDEPTH
-               if (opt == OPT_MAXDEPTH) {
+               if (opt == OPT_MINDEPTH || opt == OPT_MINDEPTH + 1) {
                        if (!argp[1])
                                bb_show_usage();
-                       maxdepth = xatoi_u(argp[1]);
+                       minmaxdepth[opt - OPT_MINDEPTH] = xatoi_u(argp[1]);
                        argp[0] = (char*)"-a";
                        argp[1] = (char*)"-a";
                        argp++;
@@ -895,9 +899,7 @@ USE_FEATURE_FIND_MAXDEPTH(OPT_MAXDEPTH,)
                                fileAction,     /* file action */
                                fileAction,     /* dir action */
 #if ENABLE_FEATURE_FIND_MAXDEPTH
-                               /* double cast suppresses
-                                * "cast to ptr from int of different size" */
-                               (void*)(ptrdiff_t)maxdepth,/* user data */
+                               minmaxdepth,    /* user data */
 #else
                                NULL,           /* user data */
 #endif
index 6a6ddb67923a33c7bd4ff4d8d49f6eb922fd0064..723c3511a547b66727cdaa911a3d72fdb28abd71 100644 (file)
@@ -28,7 +28,9 @@
        USE_FEATURE_GREP_CONTEXT("A:B:C:") \
        USE_FEATURE_GREP_EGREP_ALIAS("E") \
        USE_DESKTOP("w") \
+       USE_EXTRA_COMPAT("z") \
        "aI"
+       
 /* ignored: -a "assume all files to be text" */
 /* ignored: -I "assume binary files have no matches" */
 
@@ -54,6 +56,7 @@ enum {
        USE_FEATURE_GREP_CONTEXT(    OPTBIT_C ,) /* -C NUM: -A and -B combined */
        USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */
        USE_DESKTOP(                 OPTBIT_w ,) /* whole word match */
+       USE_EXTRA_COMPAT(            OPTBIT_z ,) /* input is NUL terminated */
        OPT_l = 1 << OPTBIT_l,
        OPT_n = 1 << OPTBIT_n,
        OPT_q = 1 << OPTBIT_q,
@@ -75,6 +78,7 @@ enum {
        OPT_C = USE_FEATURE_GREP_CONTEXT(    (1 << OPTBIT_C)) + 0,
        OPT_E = USE_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0,
        OPT_w = USE_DESKTOP(                 (1 << OPTBIT_w)) + 0,
+       OPT_z = USE_EXTRA_COMPAT(            (1 << OPTBIT_z)) + 0,
 };
 
 #define PRINT_FILES_WITH_MATCHES    (option_mask32 & OPT_l)
@@ -84,6 +88,7 @@ enum {
 #define PRINT_MATCH_COUNTS          (option_mask32 & OPT_c)
 #define FGREP_FLAG                  (option_mask32 & OPT_F)
 #define PRINT_FILES_WITHOUT_MATCHES (option_mask32 & OPT_L)
+#define NUL_DELIMITED               (option_mask32 & OPT_z)
 
 struct globals {
        int max_matches;
@@ -186,7 +191,7 @@ static void print_line(const char *line, size_t line_len, int linenum, char deco
                puts(line);
 #else
                fwrite(line, 1, line_len, stdout);
-               putchar('\n');
+               putchar(NUL_DELIMITED ? '\0' : '\n');
 #endif
        }
 }
@@ -197,12 +202,13 @@ static ssize_t FAST_FUNC bb_getline(char **line_ptr, size_t *line_alloc_len, FIL
 {
        ssize_t res_sz;
        char *line;
+       int delim = (NUL_DELIMITED ? '\0' : '\n');
 
-       res_sz = getline(line_ptr, line_alloc_len, file);
+       res_sz = getdelim(line_ptr, line_alloc_len, delim, file);
        line = *line_ptr;
 
        if (res_sz > 0) {
-               if (line[res_sz - 1] == '\n')
+               if (line[res_sz - 1] == delim)
                        line[--res_sz] = '\0';
        } else {
                free(line); /* uclibc allocates a buffer even on EOF. WTF? */
@@ -407,8 +413,11 @@ static int grep_file(FILE *file)
 #endif
                /* Did we print all context after last requested match? */
                if ((option_mask32 & OPT_m)
-                && !print_n_lines_after && nmatches == max_matches)
+                && !print_n_lines_after
+                && nmatches == max_matches
+               ) {
                        break;
+               }
        } /* while (read line) */
 
        /* special-case file post-processing for options where we don't print line
index 8ea493b18fd7c75e5163661d12394bcd8bac5c86..a2042fe5c24e13575b5b639ff6f96ad1256034e7 100644 (file)
@@ -797,9 +797,9 @@ int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **
  * Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty
  * (will do setsid()).
  *
- * forkexit_or_rexec(argv) = bare-bones "fork + parent exits" on MMU,
+ * fork_or_rexec(argv) = bare-bones "fork" on MMU,
  *      "vfork + re-exec ourself" on NOMMU. No fd redirection, no setsid().
- *      Currently used for setsid only. On MMU ignores argv.
+ *      On MMU ignores argv.
  *
  * Helper for network daemons in foreground mode:
  *
@@ -813,14 +813,14 @@ enum {
        DAEMON_ONLY_SANITIZE = 8, /* internal use */
 };
 #if BB_MMU
-  void forkexit_or_rexec(void) FAST_FUNC;
+  pid_t fork_or_rexec(void) FAST_FUNC;
   enum { re_execed = 0 };
-# define forkexit_or_rexec(argv)            forkexit_or_rexec()
+# define fork_or_rexec(argv)                fork_or_rexec()
 # define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags)
 # define bb_daemonize(flags)                bb_daemonize_or_rexec(flags, bogus)
 #else
   void re_exec(char **argv) NORETURN FAST_FUNC;
-  void forkexit_or_rexec(char **argv) FAST_FUNC;
+  pid_t fork_or_rexec(char **argv) FAST_FUNC;
   extern bool re_execed;
   int  BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC;
   int  BUG_daemon_is_unavailable_on_nommu(void) FAST_FUNC;
index e787543159da5db401932763226dbc64763d2921..2b5d34ea65b2c9f51b1a0da3e7a9e69ce47fcf01 100644 (file)
      "\n       -l,-s   Create (sym)links" \
 
 #define cpio_trivial_usage \
-       "-[dim" USE_FEATURE_CPIO_O("o") "tuv][F cpiofile]" \
-       USE_FEATURE_CPIO_O( "[H newc]" )
+       "-[ti" USE_FEATURE_CPIO_O("o") USE_FEATURE_CPIO_P("p") "dmvu] [-F FILE]" \
+       USE_FEATURE_CPIO_O( " [-H newc]" )
 #define cpio_full_usage "\n\n" \
        "Extract or list files from a cpio archive" \
        USE_FEATURE_CPIO_O( ", or create a cpio archive" ) \
-     "\n" \
-       "Main operation mode:" \
-     "\n       d       Make leading directories" \
-     "\n       i       Extract" \
-     "\n       m       Preserve mtime" \
+     "\nMain operation mode:" \
+     "\n       -t      List" \
+     "\n       -i      Extract" \
        USE_FEATURE_CPIO_O( \
-     "\n       o       Create" \
-     "\n       H newc  Define format" \
+     "\n       -o      Create" \
+       ) \
+       USE_FEATURE_CPIO_P( \
+     "\n       -p      Passthrough" \
+       ) \
+     "\nOptions:" \
+     "\n       -d      Make leading directories" \
+     "\n       -m      Preserve mtime" \
+     "\n       -v      Verbose" \
+     "\n       -u      Overwrite" \
+     "\n       -F      Input file" \
+       USE_FEATURE_CPIO_O( \
+     "\n       -H      Define format" \
        ) \
-     "\n       t       List" \
-     "\n       v       Verbose" \
-     "\n       u       Unconditional overwrite" \
-     "\n       F       Input from file" \
 
 #define crond_trivial_usage \
        "-fbS -l N " USE_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR"
        USE_FEATURE_FIND_MAXDEPTH( \
      "\n       -maxdepth N     Descend at most N levels. -maxdepth 0 applies" \
      "\n                       tests/actions to command line arguments only") \
+     "\n       -mindepth N     Do not act on first N levels" \
      "\n       -name PATTERN   File name (w/o directory name) matches PATTERN" \
      "\n       -iname PATTERN  Case insensitive -name" \
        USE_FEATURE_FIND_PATH( \
        "eF" \
        USE_FEATURE_GREP_EGREP_ALIAS("E") \
        USE_FEATURE_GREP_CONTEXT("ABC") \
+       USE_EXTRA_COMPAT("z") \
        "] PATTERN [FILEs...]"
 #define grep_full_usage "\n\n" \
        "Search for PATTERN in each FILE or standard input\n" \
      "\n       -A      Print NUM lines of trailing context" \
      "\n       -B      Print NUM lines of leading context" \
      "\n       -C      Print NUM lines of output context") \
+       USE_EXTRA_COMPAT( \
+     "\n       -z      Input is NUL terminated") \
 
 #define grep_example_usage \
        "$ grep root /etc/passwd\n" \
index 50dc3affeef7877f77ed3c14046b46e5c972c776..f64239a96cd0ff9e86f2802a6bf718742de4ae8c 100644 (file)
@@ -251,35 +251,33 @@ void FAST_FUNC re_exec(char **argv)
        bb_perror_msg_and_die("exec %s", bb_busybox_exec_path);
 }
 
-void FAST_FUNC forkexit_or_rexec(char **argv)
+pid_t FAST_FUNC fork_or_rexec(char **argv)
 {
        pid_t pid;
        /* Maybe we are already re-execed and come here again? */
        if (re_execed)
-               return;
+               return 0; /* child */
 
        pid = vfork();
        if (pid < 0) /* wtf? */
                bb_perror_msg_and_die("vfork");
        if (pid) /* parent */
-               exit(EXIT_SUCCESS);
+               return pid;
        /* child - re-exec ourself */
        re_exec(argv);
 }
 #else
 /* Dance around (void)...*/
-#undef forkexit_or_rexec
-void FAST_FUNC forkexit_or_rexec(void)
+#undef fork_or_rexec
+pid_t FAST_FUNC fork_or_rexec(void)
 {
        pid_t pid;
        pid = fork();
        if (pid < 0) /* wtf? */
                bb_perror_msg_and_die("fork");
-       if (pid) /* parent */
-               exit(EXIT_SUCCESS);
-       /* child */
+       return pid;
 }
-#define forkexit_or_rexec(argv) forkexit_or_rexec()
+#define fork_or_rexec(argv) fork_or_rexec()
 #endif
 
 /* Due to a #define in libbb.h on MMU systems we actually have 1 argument -
@@ -310,7 +308,8 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv)
                fd = dup(fd); /* have 0,1,2 open at least to /dev/null */
 
        if (!(flags & DAEMON_ONLY_SANITIZE)) {
-               forkexit_or_rexec(argv);
+               if (fork_or_rexec(argv))
+                       exit(EXIT_SUCCESS); /* parent */
                /* if daemonizing, make sure we detach from stdio & ctty */
                setsid();
                dup2(fd, 0);
index 127adf6f2822cc1bedfd6d4f99e1b51e3742389c..d7de1f149726b179753f6cbf15595a9936a7baa0 100644 (file)
@@ -26,7 +26,8 @@ int setsid_main(int argc UNUSED_PARAM, char **argv)
         * Otherwise our PID serves as PGID of some existing process group
         * and cannot be used as PGID of a new process group. */
        if (getpgrp() == getpid())
-               forkexit_or_rexec(argv);
+               if (fork_or_rexec(argv))
+                       exit(EXIT_SUCCESS); /* parent */
 
        setsid();  /* no error possible */
 
index 6bf1a4a284bbc47bc8eed5d3facec8ad1c9dd159..166989bba6f6e45d86ffa48daa36b8b400cca51c 100644 (file)
@@ -112,6 +112,7 @@ CONFIG_BUNZIP2=y
 CONFIG_BZIP2=y
 CONFIG_CPIO=y
 CONFIG_FEATURE_CPIO_O=y
+CONFIG_FEATURE_CPIO_P=y
 # CONFIG_DPKG is not set
 # CONFIG_DPKG_DEB is not set
 # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set