From 8c8a1bc4c5158073c99159042d20bd859a79e72c Mon Sep 17 00:00:00 2001 From: jay Date: Sat, 15 Jan 2005 10:22:35 +0000 Subject: [PATCH] Implemented -execdir and -okdir --- find/defs.h | 1 + find/parser.c | 19 ++++++++++--- find/pred.c | 88 +++++++++++++++++++++++++++++++++++++++++----------------- lib/buildcmd.c | 47 ++++++++++++++++++++++++------- lib/buildcmd.h | 10 +++++-- 5 files changed, 122 insertions(+), 43 deletions(-) diff --git a/find/defs.h b/find/defs.h index ae77ba7..169d3e4 100644 --- a/find/defs.h +++ b/find/defs.h @@ -232,6 +232,7 @@ struct exec_val struct buildcmd_state state; char **replace_vec; /* Command arguments (for ";" style) */ int num_args; + boolean use_current_dir; /* If nonzero, don't chdir to start dir */ #else struct path_arg *paths; /* Array of args with path replacements. */ char **vec; /* Array of args to pass to program. */ diff --git a/find/parser.c b/find/parser.c index fbb1313..bd7faa6 100644 --- a/find/parser.c +++ b/find/parser.c @@ -1844,6 +1844,8 @@ new_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) int saw_braces; /* True if previous arg was '{}'. */ boolean allow_plus; /* True if + is a valid terminator */ int brace_count; /* Number of instances of {}. */ + const char *prefix; + size_t pfxlen; struct predicate *our_pred; struct exec_val *execp; /* Pointer for efficiency. */ @@ -1861,8 +1863,13 @@ new_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) else allow_plus = false; - our_pred->args.exec_vec.multiple = 0; + if ((func == pred_execdir) || (func == pred_okdir)) + execp->use_current_dir = true; + else + execp->use_current_dir = false; + our_pred->args.exec_vec.multiple = 0; + /* Count the number of args with path replacements, up until the ';'. * Also figure out if the command is terminated by ";" or by "+". */ @@ -1927,6 +1934,7 @@ new_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) /* execp->ctl = xmalloc(sizeof struct buildcmd_control); */ bc_init_controlinfo(&execp->ctl); + execp->ctl.exec_callback = launch; if (our_pred->args.exec_vec.multiple) { @@ -1943,13 +1951,15 @@ new_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) execp->ctl.initial_argc = (end-start) - 1; /* execp->state = xmalloc(sizeof struct buildcmd_state); */ - bc_init_state(&execp->ctl, &execp->state); + bc_init_state(&execp->ctl, &execp->state, execp); /* Gather the initial arguments. Skip the {}. */ for (i=start; ictl, &execp->state, - argv[i], strlen(argv[i])+1, 1); + argv[i], strlen(argv[i])+1, + NULL, 0, + 1); } } else @@ -1967,7 +1977,7 @@ new_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) /* execp->state = xmalloc(sizeof(*(execp->state))); */ - bc_init_state(&execp->ctl, &execp->state); + bc_init_state(&execp->ctl, &execp->state, execp); /* Remember the (pre-replacement) arguments for later. */ for (i=0; inum_args; ++i) @@ -2018,6 +2028,7 @@ old_insert_exec_ok (boolean (*func) (/* ??? */), char **argv, int *arg_ptr) our_pred->no_default_print = true; execp = &our_pred->args.exec_vec; execp->usercontext = our_pred; + execp->use_current_dir = false; execp->paths = (struct path_arg *) xmalloc (sizeof (struct path_arg) * (num_paths + 1)); execp->vec = (char **) xmalloc (sizeof (char *) * (end - start + 1)); diff --git a/find/pred.c b/find/pred.c index 4f00103..5f9242f 100644 --- a/find/pred.c +++ b/find/pred.c @@ -458,11 +458,12 @@ pred_empty (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) #if defined(NEW_EXEC) static boolean -new_impl_pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +new_impl_pred_exec (const char *pathname, struct stat *stat_buf, + struct predicate *pred_ptr, + const char *prefix, size_t pfxlen) { struct exec_val *execp = &pred_ptr->args.exec_vec; - - execp->ctl.exec_callback = launch; + size_t len = strlen(pathname); if (execp->multiple) { @@ -472,7 +473,9 @@ new_impl_pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pre */ bc_push_arg(&execp->ctl, &execp->state, - pathname, strlen(pathname)+1, 0); + prefix, pfxlen, + pathname, len+1, + 0); /* POSIX: If the primary expression is punctuated by a plus * sign, the primary shall always evaluate as true @@ -481,20 +484,21 @@ new_impl_pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pre } else { - int i, retval; + int i; for (i=0; inum_args; ++i) { bc_do_insert(&execp->ctl, &execp->state, execp->replace_vec[i], strlen(execp->replace_vec[i]), - pathname, strlen(pathname), 0); + prefix, pfxlen, + pathname, len, + 0); } /* Actually invoke the command. */ - retval = execp->ctl.exec_callback(&execp->ctl, + return execp->ctl.exec_callback(&execp->ctl, &execp->state); - return retval; } } #else @@ -544,7 +548,7 @@ boolean pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { #if defined(NEW_EXEC) - return new_impl_pred_exec(pathname, stat_buf, pred_ptr); + return new_impl_pred_exec(pathname, stat_buf, pred_ptr, NULL, 0); #else return old_impl_pred_exec(pathname, stat_buf, pred_ptr); #endif @@ -553,8 +557,8 @@ pred_exec (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) boolean pred_execdir (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { - error(1, 0, "-execdir is not yet implemented."); - /* return old_impl_pred_exec(pathname, stat_buf, pred_ptr); */ + const char *s = basename(pathname); + return new_impl_pred_exec(s, stat_buf, pred_ptr, "./", 2); } boolean @@ -1134,8 +1138,9 @@ pred_nouser (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) } #if defined(NEW_EXEC) -boolean -pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) + +static boolean +is_ok(const char *program, const char *arg) { fflush (stdout); /* The draft open standard requires that, in the POSIX locale, @@ -1143,14 +1148,33 @@ pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) The exact format is not specified. This standard does not have requirements for locales other than POSIX */ - fprintf (stderr, _("< %s ... %s > ? "), - pred_ptr->args.exec_vec.replace_vec[0], pathname); + fprintf (stderr, _("< %s ... %s > ? "), program, arg); fflush (stderr); - if (yesno ()) - return pred_exec (pathname, stat_buf, pred_ptr); + return yesno(); +} + +boolean +pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +{ + if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname)) + return new_impl_pred_exec (pathname, stat_buf, pred_ptr, NULL, 0); + else + return false; +} + +boolean +pred_okdir (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) +{ + const char *s = basename(pathname); + + if (is_ok(pred_ptr->args.exec_vec.replace_vec[0], pathname)) + return new_impl_pred_exec (s, stat_buf, pred_ptr, "./", 2); else return false; } + + + #else boolean pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) @@ -1169,8 +1193,6 @@ pred_ok (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) else return (false); } -#endif - boolean pred_okdir (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) @@ -1179,6 +1201,10 @@ pred_okdir (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) return false; } + +#endif + + boolean pred_open (char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { @@ -1511,9 +1537,10 @@ launch (const struct buildcmd_control *ctl, int wait_status; pid_t child_pid; static int first_time = 1; - + const struct exec_val *execp = buildstate->usercontext; + /* Null terminate the arg list. */ - bc_push_arg (ctl, buildstate, (char *) NULL, 0, false); + bc_push_arg (ctl, buildstate, (char *) NULL, 0, NULL, 0, false); /* Make sure output of command doesn't get mixed with find output. */ fflush (stdout); @@ -1533,13 +1560,22 @@ launch (const struct buildcmd_control *ctl, { /* We be the child. */ prep_child_for_exec(); - if (starting_desc < 0 - ? chdir (starting_dir) != 0 - : fchdir (starting_desc) != 0) + + /* For -exec and -ok, change directory back to the starting directory. + * for -execdir and -okdir, stay in the directory we are searching + * (the latter is more secure). + */ + if (!execp->use_current_dir) { - error (0, errno, "%s", starting_dir); - _exit (1); + if (starting_desc < 0 + ? chdir (starting_dir) != 0 + : fchdir (starting_desc) != 0) + { + error (0, errno, "%s", starting_dir); + _exit (1); + } } + execvp (buildstate->cmd_argv[0], buildstate->cmd_argv); error (0, errno, "%s", buildstate->cmd_argv[0]); _exit (1); diff --git a/lib/buildcmd.c b/lib/buildcmd.c index c71bcb0..eb26312 100644 --- a/lib/buildcmd.c +++ b/lib/buildcmd.c @@ -96,6 +96,8 @@ static char *mbstrstr PARAMS ((const char *haystack, const char *needle)); to execute. ARGLEN is the length of ARG, not including the null. LBLEN is the length of LINEBUF, not including the null. + PFXLEN is the length of PREFIX. Substitution is not performed on + the prefix. The prefix is used if the argument contains replace_pat. COMPAT: insertions on the SYSV version are limited to 255 chars per line, and a max of 5 occurrences of replace_pat in the initial-arguments. @@ -104,8 +106,8 @@ static char *mbstrstr PARAMS ((const char *haystack, const char *needle)); void bc_do_insert (const struct buildcmd_control *ctl, struct buildcmd_state *state, - char *arg, - size_t arglen, + char *arg, size_t arglen, + const char *prefix, size_t pfxlen, const char *linebuf, size_t lblen, int initial_args) @@ -115,19 +117,27 @@ bc_do_insert (const struct buildcmd_control *ctl, static char *insertbuf; char *p; int bytes_left = ctl->arg_max - 1; /* Bytes left on the command line. */ - + int need_prefix; + if (!insertbuf) insertbuf = (char *) xmalloc (ctl->arg_max + 1); p = insertbuf; + need_prefix = 0; do { size_t len; /* Length in ARG before `replace_pat'. */ char *s = mbstrstr (arg, ctl->replace_pat); if (s) - len = s - arg; + { + need_prefix = 1; + len = s - arg; + } else - len = arglen; + { + len = arglen; + } + bytes_left -= len; if (bytes_left <= 0) break; @@ -152,7 +162,17 @@ bc_do_insert (const struct buildcmd_control *ctl, if (*arg) error (1, 0, _("command too long")); *p++ = '\0'; - bc_push_arg (ctl, state, insertbuf, p - insertbuf, initial_args); + + if (!need_prefix) + { + prefix = NULL; + pfxlen = 0; + } + + bc_push_arg (ctl, state, + insertbuf, p - insertbuf, + prefix, pfxlen, + initial_args); } static @@ -171,8 +191,8 @@ void do_exec(const struct buildcmd_control *ctl, void bc_push_arg (const struct buildcmd_control *ctl, struct buildcmd_state *state, - char *arg, - size_t len, + const char *arg, size_t len, + const char *prefix, size_t pfxlen, int initial_args) { state->todo = 1; @@ -214,6 +234,12 @@ bc_push_arg (const struct buildcmd_control *ctl, else { state->cmd_argv[state->cmd_argc++] = state->argbuf + state->cmd_argv_chars; + if (prefix) + { + strcpy (state->argbuf + state->cmd_argv_chars, prefix); + state->cmd_argv_chars += pfxlen; + } + strcpy (state->argbuf + state->cmd_argv_chars, arg); state->cmd_argv_chars += len; @@ -326,7 +352,8 @@ bc_init_controlinfo(struct buildcmd_control *ctl) void bc_init_state(const struct buildcmd_control *ctl, - struct buildcmd_state *state) + struct buildcmd_state *state, + void *context) { state->cmd_argc = 0; state->cmd_argv_chars = 0; @@ -335,7 +362,7 @@ bc_init_state(const struct buildcmd_control *ctl, state->argbuf = (char *) xmalloc (ctl->arg_max + 1); state->cmd_argv_chars = 0; state->todo = 0; - state->usercontext = NULL; + state->usercontext = context; } void diff --git a/lib/buildcmd.h b/lib/buildcmd.h index d2a12b4..201035c 100644 --- a/lib/buildcmd.h +++ b/lib/buildcmd.h @@ -87,15 +87,19 @@ struct buildcmd_control extern void bc_do_insert (const struct buildcmd_control *ctl, struct buildcmd_state *state, char *arg, size_t arglen, + const char *prefix, size_t pfxlen, const char *linebuf, size_t lblen, int initial_args); extern void bc_push_arg (const struct buildcmd_control *ctl, - struct buildcmd_state *state, - char *arg, size_t len, int initial_args); + struct buildcmd_state *state, + const char *arg, size_t len, + const char *prefix, size_t pfxlen, + int initial_args); extern void bc_init_state(const struct buildcmd_control *ctl, - struct buildcmd_state *state); + struct buildcmd_state *state, + void *usercontext); extern void bc_init_controlinfo(struct buildcmd_control *ctl); extern long bc_get_arg_max(void); extern void bc_clear_args(const struct buildcmd_control *ctl, -- 2.11.4.GIT