* process.c (rb_fork): propagete an error message from child to parent.

(rb_f_exec): show details of error in child process on
  exception.
  (save_redirect_fd): add error message arguments.
  (run_exec_dup2): ditto.
  (run_exec_close): ditto.
  (run_exec_open): ditto.
  (run_exec_dup2_child): ditto.
  (run_exec_pgroup): ditto.
  (run_exec_rlimit): ditto.
  (rb_run_exec_options): ditto.
  (rb_exec): ditto.
  (rb_exec_atfork): ditto.
  (rb_spawn_internal): ditto.
  (rb_spawn): ditto.
  (rb_f_system): follow arguments change.
  (proc_daemon): ditto.
  (rb_f_spawn): show details of error in child process on exception.

* io.c (popen_exec): add error message arguments.
  (pipe_open): show details of error in child process on exception.

* include/ruby/intern.h (rb_run_exec_options): add error message
  arguments.
  (rb_exec): ditto.
  (rb_fork): ditto.
  (rb_spawn): ditto.

* ext/pty/pty.c (chfunc): add error message arguments.



git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@20950 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
akr 2008-12-23 13:15:54 +00:00
Родитель 5677106ec9
Коммит 423bbf80d5
5 изменённых файлов: 170 добавлений и 68 удалений

Просмотреть файл

@ -1,3 +1,35 @@
Tue Dec 23 21:55:05 2008 Tanaka Akira <akr@fsij.org>
* process.c (rb_fork): propagete an error message from child to parent.
(rb_f_exec): show details of error in child process on
exception.
(save_redirect_fd): add error message arguments.
(run_exec_dup2): ditto.
(run_exec_close): ditto.
(run_exec_open): ditto.
(run_exec_dup2_child): ditto.
(run_exec_pgroup): ditto.
(run_exec_rlimit): ditto.
(rb_run_exec_options): ditto.
(rb_exec): ditto.
(rb_exec_atfork): ditto.
(rb_spawn_internal): ditto.
(rb_spawn): ditto.
(rb_f_system): follow arguments change.
(proc_daemon): ditto.
(rb_f_spawn): show details of error in child process on exception.
* io.c (popen_exec): add error message arguments.
(pipe_open): show details of error in child process on exception.
* include/ruby/intern.h (rb_run_exec_options): add error message
arguments.
(rb_exec): ditto.
(rb_fork): ditto.
(rb_spawn): ditto.
* ext/pty/pty.c (chfunc): add error message arguments.
Tue Dec 23 20:28:28 2008 Yuki Sonoda (Yugui) <yugui@yugui.jp>
* io.c: rdoc for File::open and 1.9 feature in file modes.

Просмотреть файл

@ -155,7 +155,7 @@ struct child_info {
};
static int
chfunc(void *data)
chfunc(void *data, char *errmsg, size_t errmsg_len)
{
struct child_info *carg = data;
int master = carg->master;
@ -258,7 +258,7 @@ establishShell(int argc, VALUE *argv, struct pty_info *info,
carg.slavename = SlaveName;
carg.argc = argc;
carg.argv = argv;
pid = rb_fork(0, chfunc, &carg, Qnil);
pid = rb_fork(0, chfunc, &carg, Qnil, NULL, 0);
if (pid < 0) {
close(master);

Просмотреть файл

@ -472,13 +472,13 @@ int rb_proc_exec(const char*);
VALUE rb_exec_arg_init(int argc, VALUE *argv, int accept_shell, struct rb_exec_arg *e);
int rb_exec_arg_addopt(struct rb_exec_arg *e, VALUE key, VALUE val);
void rb_exec_arg_fixup(struct rb_exec_arg *e);
int rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s);
int rb_exec(const struct rb_exec_arg*);
rb_pid_t rb_fork(int*, int (*)(void*), void*, VALUE);
int rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s, char*, size_t);
int rb_exec(const struct rb_exec_arg*, char*, size_t);
rb_pid_t rb_fork(int*, int (*)(void*, char*, size_t), void*, VALUE, char*, size_t);
VALUE rb_f_exec(int,VALUE*);
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags);
void rb_syswait(rb_pid_t pid);
rb_pid_t rb_spawn(int, VALUE*);
rb_pid_t rb_spawn(int, VALUE*, char*, size_t);
VALUE rb_proc_times(VALUE);
VALUE rb_detach_process(rb_pid_t pid);
/* range.c */

21
io.c
Просмотреть файл

@ -4440,12 +4440,12 @@ rb_close_before_exec(int lowfd, int maxhint, VALUE noclose_fds)
}
static int
popen_exec(void *pp)
popen_exec(void *pp, char *errmsg, size_t errmsg_len)
{
struct popen_arg *p = (struct popen_arg*)pp;
rb_thread_atfork_before_exec();
return rb_exec(p->execp);
return rb_exec(p->execp, errmsg, errmsg_len);
}
#endif
@ -4460,6 +4460,7 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
#if defined(HAVE_FORK)
int status;
struct popen_arg arg;
char errmsg[80] = { '\0' };
#elif defined(_WIN32)
volatile VALUE argbuf;
char **args = NULL;
@ -4530,11 +4531,11 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
}
if (eargp) {
rb_exec_arg_fixup(arg.execp);
pid = rb_fork(&status, popen_exec, &arg, arg.execp->redirect_fds);
pid = rb_fork(&status, popen_exec, &arg, arg.execp->redirect_fds, errmsg, sizeof(errmsg));
}
else {
fflush(stdin); /* is it really needed? */
pid = rb_fork(&status, 0, 0, Qnil);
pid = rb_fork(&status, 0, 0, Qnil, NULL, 0);
if (pid == 0) { /* child */
popen_redirect(&arg);
rb_io_synchronized(RFILE(orig_stdout)->fptr);
@ -4553,6 +4554,8 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
close(arg.write_pair[1]);
}
errno = e;
if (errmsg[0])
rb_sys_fail(errmsg);
rb_sys_fail(cmd);
}
if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
@ -4616,7 +4619,7 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
}
if (eargp) {
rb_exec_arg_fixup(eargp);
rb_run_exec_options(eargp, &sarg);
rb_run_exec_options(eargp, &sarg, NULL, 0);
}
while ((pid = (args ?
rb_w32_aspawn(P_NOWAIT, 0, args) :
@ -4631,13 +4634,13 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
break;
default:
if (eargp)
rb_run_exec_options(&sarg, NULL);
rb_run_exec_options(&sarg, NULL, NULL, 0);
rb_sys_fail(cmd);
break;
}
}
if (eargp)
rb_run_exec_options(&sarg, NULL);
rb_run_exec_options(&sarg, NULL, NULL, 0);
if ((fmode & FMODE_READABLE) && (fmode & FMODE_WRITABLE)) {
close(pair[1]);
fd = pair[0];
@ -4659,11 +4662,11 @@ pipe_open(struct rb_exec_arg *eargp, VALUE prog, const char *modestr, int fmode,
}
if (eargp) {
rb_exec_arg_fixup(eargp);
rb_run_exec_options(eargp, &sarg);
rb_run_exec_options(eargp, &sarg, NULL, 0);
}
fp = popen(cmd, modestr);
if (eargp)
rb_run_exec_options(&sarg, NULL);
rb_run_exec_options(&sarg, NULL, NULL, 0);
if (!fp) rb_sys_fail(RSTRING_PTR(prog));
fd = fileno(fp);
#endif

173
process.c
Просмотреть файл

@ -1756,17 +1756,23 @@ VALUE
rb_f_exec(int argc, VALUE *argv)
{
struct rb_exec_arg earg;
#define CHILD_ERRMSG_BUFLEN 80
char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
rb_exec_arg_init(argc, argv, Qtrue, &earg);
if (NIL_P(rb_ary_entry(earg.options, EXEC_OPTION_CLOSE_OTHERS)))
rb_exec_arg_addopt(&earg, ID2SYM(rb_intern("close_others")), Qfalse);
rb_exec_arg_fixup(&earg);
rb_exec(&earg);
rb_exec(&earg, errmsg, sizeof(errmsg));
if (errmsg[0])
rb_sys_fail(errmsg);
rb_sys_fail(earg.prog);
return Qnil; /* dummy */
}
#define ERRMSG(str) do { if (errmsg && 0 < errmsg_buflen) strlcpy(errmsg, (str), errmsg_buflen); } while (0)
/*#define DEBUG_REDIRECT*/
#if defined(DEBUG_REDIRECT)
@ -1837,12 +1843,15 @@ redirect_open(const char *pathname, int flags, mode_t perm)
#endif
static int
save_redirect_fd(int fd, VALUE save)
save_redirect_fd(int fd, VALUE save, char *errmsg, size_t errmsg_buflen)
{
if (!NIL_P(save)) {
VALUE newary;
int save_fd = redirect_dup(fd);
if (save_fd == -1) return -1;
if (save_fd == -1) {
ERRMSG("dup");
return -1;
}
newary = rb_ary_entry(save, EXEC_OPTION_DUP2);
if (NIL_P(newary)) {
newary = hide_obj(rb_ary_new());
@ -1897,7 +1906,7 @@ intrcmp(const void *a, const void *b)
}
static int
run_exec_dup2(VALUE ary, VALUE save)
run_exec_dup2(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
{
int n, i;
int ret;
@ -1910,7 +1919,11 @@ run_exec_dup2(VALUE ary, VALUE save)
} *pairs = 0;
n = RARRAY_LEN(ary);
pairs = ALLOC_N(struct fd_pair, n);
pairs = (struct fd_pair *)malloc(sizeof(struct fd_pair) * n);
if (pairs == NULL) {
ERRMSG("malloc");
return -1;
}
/* initialize oldfd and newfd: O(n) */
for (i = 0; i < n; i++) {
@ -1948,11 +1961,13 @@ run_exec_dup2(VALUE ary, VALUE save)
for (i = 0; i < n; i++) {
int j = i;
while (j != -1 && pairs[j].oldfd != -1 && pairs[j].num_newer == 0) {
if (save_redirect_fd(pairs[j].newfd, save) < 0)
if (save_redirect_fd(pairs[j].newfd, save, errmsg, errmsg_buflen) < 0)
goto fail;
ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
if (ret == -1)
if (ret == -1) {
ERRMSG("dup2");
goto fail;
}
pairs[j].oldfd = -1;
j = pairs[j].older_index;
if (j != -1)
@ -1969,13 +1984,17 @@ run_exec_dup2(VALUE ary, VALUE save)
#ifdef F_GETFD
int fd = pairs[i].oldfd;
ret = fcntl(fd, F_GETFD);
if (ret == -1)
if (ret == -1) {
ERRMSG("fcntl(F_GETFD)");
goto fail;
}
if (ret & FD_CLOEXEC) {
ret &= ~FD_CLOEXEC;
ret = fcntl(fd, F_SETFD, ret);
if (ret == -1)
if (ret == -1) {
ERRMSG("fcntl(F_SETFD)");
goto fail;
}
}
#endif
pairs[i].oldfd = -1;
@ -1983,29 +2002,37 @@ run_exec_dup2(VALUE ary, VALUE save)
}
if (extra_fd == -1) {
extra_fd = redirect_dup(pairs[i].oldfd);
if (extra_fd == -1)
if (extra_fd == -1) {
ERRMSG("dup");
goto fail;
}
}
else {
ret = redirect_dup2(pairs[i].oldfd, extra_fd);
if (ret == -1)
if (ret == -1) {
ERRMSG("dup2");
goto fail;
}
}
pairs[i].oldfd = extra_fd;
j = pairs[i].older_index;
pairs[i].older_index = -1;
while (j != -1) {
ret = redirect_dup2(pairs[j].oldfd, pairs[j].newfd);
if (ret == -1)
if (ret == -1) {
ERRMSG("dup2");
goto fail;
}
pairs[j].oldfd = -1;
j = pairs[j].older_index;
}
}
if (extra_fd != -1) {
ret = redirect_close(extra_fd);
if (ret == -1)
if (ret == -1) {
ERRMSG("close");
goto fail;
}
}
xfree(pairs);
@ -2017,7 +2044,7 @@ run_exec_dup2(VALUE ary, VALUE save)
}
static int
run_exec_close(VALUE ary)
run_exec_close(VALUE ary, char *errmsg, size_t errmsg_buflen)
{
int i, ret;
@ -2025,14 +2052,16 @@ run_exec_close(VALUE ary)
VALUE elt = RARRAY_PTR(ary)[i];
int fd = FIX2INT(RARRAY_PTR(elt)[0]);
ret = redirect_close(fd);
if (ret == -1)
if (ret == -1) {
ERRMSG("close");
return -1;
}
}
return 0;
}
static int
run_exec_open(VALUE ary, VALUE save)
run_exec_open(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
{
int i, ret;
@ -2045,7 +2074,10 @@ run_exec_open(VALUE ary, VALUE save)
int perm = NUM2INT(RARRAY_PTR(param)[2]);
int need_close = 1;
int fd2 = redirect_open(path, flags, perm);
if (fd2 == -1) return -1;
if (fd2 == -1) {
ERRMSG("open");
return -1;
}
while (i < RARRAY_LEN(ary) &&
(elt = RARRAY_PTR(ary)[i], RARRAY_PTR(elt)[1] == param)) {
fd = FIX2INT(RARRAY_PTR(elt)[0]);
@ -2053,23 +2085,29 @@ run_exec_open(VALUE ary, VALUE save)
need_close = 0;
}
else {
if (save_redirect_fd(fd, save) < 0)
if (save_redirect_fd(fd, save, errmsg, errmsg_buflen) < 0)
return -1;
ret = redirect_dup2(fd2, fd);
if (ret == -1) return -1;
if (ret == -1) {
ERRMSG("dup2");
return -1;
}
}
i++;
}
if (need_close) {
ret = redirect_close(fd2);
if (ret == -1) return -1;
if (ret == -1) {
ERRMSG("close");
return -1;
}
}
}
return 0;
}
static int
run_exec_dup2_child(VALUE ary, VALUE save)
run_exec_dup2_child(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
{
int i, ret;
for (i = 0; i < RARRAY_LEN(ary); i++) {
@ -2077,17 +2115,20 @@ run_exec_dup2_child(VALUE ary, VALUE save)
int newfd = FIX2INT(RARRAY_PTR(elt)[0]);
int oldfd = FIX2INT(RARRAY_PTR(elt)[1]);
if (save_redirect_fd(newfd, save) < 0)
if (save_redirect_fd(newfd, save, errmsg, errmsg_buflen) < 0)
return -1;
ret = redirect_dup2(oldfd, newfd);
if (ret == -1) return -1;
if (ret == -1) {
ERRMSG("dup2");
return -1;
}
}
return 0;
}
#ifdef HAVE_SETPGID
static int
run_exec_pgroup(VALUE obj, VALUE save)
run_exec_pgroup(VALUE obj, VALUE save, char *errmsg, size_t errmsg_buflen)
{
/*
* If FD_CLOEXEC is available, rb_fork waits the child's execve.
@ -2095,6 +2136,7 @@ run_exec_pgroup(VALUE obj, VALUE save)
* No race condition, even without setpgid from the parent.
* (Is there an environment which has setpgid but FD_CLOEXEC?)
*/
int ret;
pid_t pgroup;
if (!NIL_P(save)) {
/* maybe meaningless with no fork environment... */
@ -2104,13 +2146,15 @@ run_exec_pgroup(VALUE obj, VALUE save)
if (pgroup == 0) {
pgroup = getpid();
}
return setpgid(getpid(), pgroup);
ret = setpgid(getpid(), pgroup);
if (ret == -1) ERRMSG("setpgid");
return ret;
}
#endif
#ifdef RLIM2NUM
static int
run_exec_rlimit(VALUE ary, VALUE save)
run_exec_rlimit(VALUE ary, VALUE save, char *errmsg, size_t errmsg_buflen)
{
int i;
for (i = 0; i < RARRAY_LEN(ary); i++) {
@ -2119,8 +2163,10 @@ run_exec_rlimit(VALUE ary, VALUE save)
struct rlimit rlim;
if (!NIL_P(save)) {
VALUE tmp, newary;
if (getrlimit(rtype, &rlim) == -1)
if (getrlimit(rtype, &rlim) == -1) {
ERRMSG("getrlimit");
return -1;
}
tmp = hide_obj(rb_ary_new3(3, RARRAY_PTR(elt)[0],
RLIM2NUM(rlim.rlim_cur),
RLIM2NUM(rlim.rlim_max)));
@ -2133,15 +2179,17 @@ run_exec_rlimit(VALUE ary, VALUE save)
}
rlim.rlim_cur = NUM2RLIM(RARRAY_PTR(elt)[1]);
rlim.rlim_max = NUM2RLIM(RARRAY_PTR(elt)[2]);
if (setrlimit(rtype, &rlim) == -1)
if (setrlimit(rtype, &rlim) == -1) {
ERRMSG("setrlimit");
return -1;
}
}
return 0;
}
#endif
int
rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s, char *errmsg, size_t errmsg_buflen)
{
VALUE options = e->options;
VALUE soptions = Qnil;
@ -2161,7 +2209,7 @@ rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
#ifdef HAVE_SETPGID
obj = rb_ary_entry(options, EXEC_OPTION_PGROUP);
if (RTEST(obj)) {
if (run_exec_pgroup(obj, soptions) == -1)
if (run_exec_pgroup(obj, soptions, errmsg, errmsg_buflen) == -1)
return -1;
}
#endif
@ -2169,7 +2217,7 @@ rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
#ifdef RLIM2NUM
obj = rb_ary_entry(options, EXEC_OPTION_RLIMIT);
if (!NIL_P(obj)) {
if (run_exec_rlimit(obj, soptions) == -1)
if (run_exec_rlimit(obj, soptions, errmsg, errmsg_buflen) == -1)
return -1;
}
#endif
@ -2203,8 +2251,10 @@ rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
hide_obj(rb_str_new2(cwd)));
xfree(cwd);
}
if (chdir(RSTRING_PTR(obj)) == -1)
if (chdir(RSTRING_PTR(obj)) == -1) {
ERRMSG("chdir");
return -1;
}
}
obj = rb_ary_entry(options, EXEC_OPTION_UMASK);
@ -2217,7 +2267,7 @@ rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
obj = rb_ary_entry(options, EXEC_OPTION_DUP2);
if (!NIL_P(obj)) {
if (run_exec_dup2(obj, soptions) == -1)
if (run_exec_dup2(obj, soptions, errmsg, errmsg_buflen) == -1)
return -1;
}
@ -2226,7 +2276,7 @@ rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
if (!NIL_P(soptions))
rb_warn("cannot close fd before spawn");
else {
if (run_exec_close(obj) == -1)
if (run_exec_close(obj, errmsg, errmsg_buflen) == -1)
return -1;
}
}
@ -2240,13 +2290,13 @@ rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
obj = rb_ary_entry(options, EXEC_OPTION_OPEN);
if (!NIL_P(obj)) {
if (run_exec_open(obj, soptions) == -1)
if (run_exec_open(obj, soptions, errmsg, errmsg_buflen) == -1)
return -1;
}
obj = rb_ary_entry(options, EXEC_OPTION_DUP2_CHILD);
if (!NIL_P(obj)) {
if (run_exec_dup2_child(obj, soptions) == -1)
if (run_exec_dup2_child(obj, soptions, errmsg, errmsg_buflen) == -1)
return -1;
}
@ -2254,13 +2304,13 @@ rb_run_exec_options(const struct rb_exec_arg *e, struct rb_exec_arg *s)
}
int
rb_exec(const struct rb_exec_arg *e)
rb_exec(const struct rb_exec_arg *e, char *errmsg, size_t errmsg_buflen)
{
int argc = e->argc;
VALUE *argv = e->argv;
const char *prog = e->prog;
if (rb_run_exec_options(e, NULL) < 0) {
if (rb_run_exec_options(e, NULL, errmsg, errmsg_buflen) < 0) {
return -1;
}
@ -2281,10 +2331,10 @@ rb_exec(const struct rb_exec_arg *e)
#ifdef HAVE_FORK
static int
rb_exec_atfork(void* arg)
rb_exec_atfork(void* arg, char *errmsg, size_t errmsg_buflen)
{
rb_thread_atfork_before_exec();
return rb_exec(arg);
return rb_exec(arg, errmsg, errmsg_buflen);
}
#endif
@ -2367,7 +2417,8 @@ pipe_nocrash(int filedes[2], VALUE fds)
* +chfunc+ must not raise any exceptions.
*/
rb_pid_t
rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
rb_fork(int *status, int (*chfunc)(void*, char *, size_t), void *charg, VALUE fds,
char *errmsg, size_t errmsg_buflen)
{
rb_pid_t pid;
int err, state = 0;
@ -2422,10 +2473,12 @@ rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
#ifdef FD_CLOEXEC
close(ep[0]);
#endif
if (!(*chfunc)(charg)) _exit(EXIT_SUCCESS);
if (!(*chfunc)(charg, errmsg, errmsg_buflen)) _exit(EXIT_SUCCESS);
#ifdef FD_CLOEXEC
err = errno;
write(ep[1], &err, sizeof(err));
errmsg[errmsg_buflen-1] = '\0';
write(ep[1], errmsg, strlen(errmsg));
#endif
#if EXIT_SUCCESS == 127
_exit(EXIT_FAILURE);
@ -2441,6 +2494,14 @@ rb_fork(int *status, int (*chfunc)(void*), void *charg, VALUE fds)
if ((state = read(ep[0], &err, sizeof(err))) < 0) {
err = errno;
}
if (state == sizeof(err) &&
errmsg && 0 < errmsg_buflen) {
ssize_t ret;
ret = read(ep[0], errmsg, errmsg_buflen-1);
if (0 <= ret) {
errmsg[ret] = '\0';
}
}
close(ep[0]);
if (state) {
if (status) {
@ -2487,7 +2548,7 @@ rb_f_fork(VALUE obj)
rb_secure(2);
switch (pid = rb_fork(0, 0, 0, Qnil)) {
switch (pid = rb_fork(0, 0, 0, Qnil, NULL, 0)) {
case 0:
#ifdef linux
after_exec();
@ -2725,7 +2786,8 @@ rb_syswait(rb_pid_t pid)
}
static rb_pid_t
rb_spawn_internal(int argc, VALUE *argv, int default_close_others)
rb_spawn_internal(int argc, VALUE *argv, int default_close_others,
char *errmsg, size_t errmsg_buflen)
{
rb_pid_t status;
VALUE prog;
@ -2742,10 +2804,10 @@ rb_spawn_internal(int argc, VALUE *argv, int default_close_others)
rb_exec_arg_fixup(&earg);
#if defined HAVE_FORK
status = rb_fork(&status, rb_exec_atfork, &earg, earg.redirect_fds);
status = rb_fork(&status, rb_exec_atfork, &earg, earg.redirect_fds, errmsg, errmsg_buflen);
if (prog && earg.argc) earg.argv[0] = prog;
#else
if (rb_run_exec_options(&earg, &sarg) < 0) {
if (rb_run_exec_options(&earg, &sarg, errmsg, errmsg_buflen) < 0) {
return -1;
}
@ -2769,15 +2831,15 @@ rb_spawn_internal(int argc, VALUE *argv, int default_close_others)
rb_last_status_set((status & 0xff) << 8, 0);
# endif
rb_run_exec_options(&sarg, NULL);
rb_run_exec_options(&sarg, NULL, errmsg, errmsg_buflen);
#endif
return status;
}
rb_pid_t
rb_spawn(int argc, VALUE *argv)
rb_spawn(int argc, VALUE *argv, char *errmsg, size_t errmsg_buflen)
{
return rb_spawn_internal(argc, argv, Qtrue);
return rb_spawn_internal(argc, argv, Qtrue, errmsg, errmsg_buflen);
}
/*
@ -2825,7 +2887,7 @@ rb_f_system(int argc, VALUE *argv)
chfunc = signal(SIGCHLD, SIG_DFL);
#endif
status = rb_spawn_internal(argc, argv, Qfalse);
status = rb_spawn_internal(argc, argv, Qfalse, NULL, 0);
#if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
if (status > 0) {
rb_syswait(status);
@ -3068,9 +3130,14 @@ static VALUE
rb_f_spawn(int argc, VALUE *argv)
{
rb_pid_t pid;
char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
pid = rb_spawn(argc, argv);
if (pid == -1) rb_sys_fail(RSTRING_PTR(argv[0]));
pid = rb_spawn(argc, argv, errmsg, sizeof(errmsg));
if (pid == -1) {
if (errmsg[0] == '\0')
rb_sys_fail(RSTRING_PTR(argv[0]));
rb_sys_fail(errmsg);
}
#if defined(HAVE_FORK) || defined(HAVE_SPAWNV)
return PIDT2NUM(pid);
#else
@ -4406,7 +4473,7 @@ proc_daemon(int argc, VALUE *argv)
if (n < 0) rb_sys_fail("daemon");
return INT2FIX(n);
#elif defined(HAVE_FORK)
switch (rb_fork(0, 0, 0, Qnil)) {
switch (rb_fork(0, 0, 0, Qnil, NULL, 0)) {
case -1:
return (-1);
case 0: