Compatibility fixes:

grep: support -z
find: support --mindepth
  together +45 bytes
cpio: support -p (configurable, +230 bytes)
libbb: tweaks for cpio
This commit is contained in:
Denis Vlasenko 2009-03-20 22:17:13 +00:00
parent 0b28103cc7
commit 83518d18a3
10 changed files with 137 additions and 59 deletions

View 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

View 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

View 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;
}
archive_handle->action_header = header_list;
}
if (opt & CPIO_OPT_EXTRACT) {

View 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

View 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

View 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;

View File

@ -531,24 +531,29 @@
"\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"
@ -1167,6 +1172,7 @@
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( \
@ -1425,6 +1431,7 @@
"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" \
@ -1453,6 +1460,8 @@
"\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" \

View 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);

View 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 */

View 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