bool impl_pred_exec (const char *pathname, struct stat *stat_buf, struct predicate *pred_ptr) { struct exec_val *execp = &pred_ptr->args.exec_vec; char *buf = NULL; const char *target; bool result; const bool local = is_exec_in_local_dir (pred_ptr->pred_func); char *prefix; size_t pfxlen; (void) stat_buf; if (local) { /* For -execdir/-okdir predicates, the parser did not fill in the wd_for_exec member of sturct exec_val. So for those predicates, we do so now. */ if (!record_exec_dir (execp)) { error (EXIT_FAILURE, errno, _("Failed to save working directory in order to " "run a command on %s"), safely_quote_err_filename (0, pathname)); /*NOTREACHED*/ } target = buf = base_name (state.rel_pathname); if ('/' == target[0]) { /* find / execdir ls -d {} \; */ prefix = NULL; pfxlen = 0; } else { prefix = "./"; pfxlen = 2u; } } else { /* For the others (-exec, -ok), the parser should have set wd_for_exec to initial_wd, indicating that the exec should take place from find's initial working directory. */ assert (execp->wd_for_exec == initial_wd); target = pathname; prefix = NULL; pfxlen = 0u; } if (execp->multiple) { /* Push the argument onto the current list. * The command may or may not be run at this point, * depending on the command line length limits. */ bc_push_arg (&execp->ctl, &execp->state, target, strlen (target)+1, prefix, pfxlen, 0); /* remember that there are pending execdirs. */ if (execp->state.todo) state.execdirs_outstanding = true; /* POSIX: If the primary expression is punctuated by a plus * sign, the primary shall always evaluate as true */ result = true; } else { int i; for (i=0; i<execp->num_args; ++i) { bc_do_insert (&execp->ctl, &execp->state, execp->replace_vec[i], strlen (execp->replace_vec[i]), prefix, pfxlen, target, strlen (target), 0); } /* Actually invoke the command. */ bc_do_exec (&execp->ctl, &execp->state); if (WIFEXITED(execp->last_child_status)) { if (0 == WEXITSTATUS(execp->last_child_status)) result = true; /* The child succeeded. */ else result = false; } else { result = false; } } if (buf) { assert (local); free (buf); } return result; }
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) { /* Temporary copy of each arg with the replace pattern replaced by the real arg. */ static char *insertbuf; char *p; size_t bytes_left = ctl->arg_max - 1; /* Bytes left on the command line. */ /* XXX: on systems lacking an upper limit for exec args, ctl->arg_max * may have been set to LONG_MAX (see bc_get_arg_max()). Hence * this xmalloc call may be a bad idea, especially since we are * adding 1 to it... */ if (!insertbuf) insertbuf = xmalloc (ctl->arg_max + 1); p = insertbuf; do { size_t len; /* Length in ARG before `replace_pat'. */ char *s = mbsstr (arg, ctl->replace_pat); if (s) { len = s - arg; } else { len = arglen; } if (bytes_left <= len) break; else bytes_left -= len; strncpy (p, arg, len); p += len; arg += len; arglen -= len; if (s) { if (bytes_left <= (lblen + pfxlen)) break; else bytes_left -= (lblen + pfxlen); if (prefix) { strcpy (p, prefix); p += pfxlen; } strcpy (p, linebuf); p += lblen; arg += ctl->rplen; arglen -= ctl->rplen; } } while (*arg); if (*arg) error (1, 0, _("command too long")); *p++ = '\0'; bc_push_arg (ctl, state, insertbuf, p - insertbuf, NULL, 0, initial_args); }