diff --git a/src/signal_handler.c b/src/signal_handler.c index c6eb6b79821a21b9eecf2fadabd7089c3f901282..60e4ea1866b4a927fc0cffd5a0aa44f5259a3d3e 100644 --- a/src/signal_handler.c +++ b/src/signal_handler.c @@ -3,6 +3,7 @@ ||| Pike is distributed as GPL (General Public License) ||| See the files COPYING and DISCLAIMER for more information. \*/ +/**/ #include "global.h" #include "fdlib.h" #include "fd_control.h" @@ -22,7 +23,7 @@ #include "builtin_functions.h" #include <signal.h> -RCSID("$Id: signal_handler.c,v 1.90 1998/11/23 00:06:15 marcus Exp $"); +RCSID("$Id: signal_handler.c,v 1.91 1998/11/29 21:28:17 grubba Exp $"); #ifdef HAVE_PASSWD_H # include <passwd.h> @@ -809,6 +810,37 @@ static void free_perishables(struct perishables *storage) #endif +#if !defined(__NT__) && !defined(__amigaos__) + +extern int pike_make_pipe(int *); + +/* + * Errors that can be generated by the child process + */ + +#define PROCE_CHDIR 1 +#define PROCE_DUP2 2 +#define PROCE_SETGID 3 +#define PROCE_SETGROUPS 4 +#define PROCE_GETPWUID 5 +#define PROCE_INITGROUPS 6 +#define PROCE_SETUID 7 +#define PROCE_EXEC 8 + +#define PROCERROR(err, id) do { int _l, _i; \ + buf[0] = err; buf[1] = errno; buf[2] = id; \ + for(_i = 0; _i < 3; _i += _l) { \ + while (((_l = write(control_pipe[1], buf + _i, 3 - _i)) < 0) && \ + (errno == EINTR)) \ + ; \ + if (_l < 0) break; \ + } \ + exit(99); \ + } while(0) + +#endif /* !__NT__ && !__amigaos__ */ + + /* * create_process(string *arguments, mapping optional_data); @@ -1101,6 +1133,8 @@ void f_create_process(INT32 args) int gid_request=0; int keep_signals = 0; pid_t pid; + int control_pipe[2]; /* Used for communication with the child. */ + char buf[4]; storage.env=0; storage.argv=0; @@ -1365,6 +1399,10 @@ void f_create_process(INT32 args) fprintf(stderr, "%s:%d: init_threads_disable()...\n", __FILE__, __LINE__); #endif /* PROC_DEBUG */ + if (pike_make_pipe(control_pipe) < 0) { + error("Failed to create child communication pipe.\n"); + } + #if 1 init_threads_disable(NULL); storage.disabled = 1; @@ -1383,6 +1421,9 @@ void f_create_process(INT32 args) UNSET_ONERROR(err); if(pid==-1) { + close(control_pipe[0]); + close(control_pipe[1]); + free_perishables(&storage); #ifdef PROC_DEBUG @@ -1393,6 +1434,9 @@ void f_create_process(INT32 args) error("Failed to start process.\n" "errno:%d\n", errno); } else if(pid) { + /* Close our childs end of the pipe. */ + close(control_pipe[1]); + free_perishables(&storage); pop_n_elems(sp - stack_save); @@ -1402,6 +1446,7 @@ void f_create_process(INT32 args) __FILE__, __LINE__, (int)pid); #endif /* PROC_DEBUG */ + /* FIXME: Can anything of the following throw an error? */ if(!signal_evaluator_callback) { signal_evaluator_callback=add_to_callback(&evaluator_callbacks, @@ -1414,7 +1459,24 @@ void f_create_process(INT32 args) push_int(pid); mapping_insert(pid_mapping,sp-1, sp-2); pop_n_elems(2); - push_int(0); + + /* Wake up the child. */ + buf[0] = 0; + while (((e = write(control_pipe[0], buf, 1)) < 0) && (errno == EINTR)) + ; + + /* Wait for exec. */ + while(((e = read(control_pipe[0], buf, 3)) < 0) && (errno == EINTR)) + ; + close(control_pipe[0]); + if (!e) { + /* OK! */ + push_int(0); + } else { + /* Something went wrong. */ + error("Process.create_process(): Child failed: %d, %d, %d!\n", + buf[0], buf[1], buf[2]); + } }else{ ONERROR oe; @@ -1424,12 +1486,24 @@ void f_create_process(INT32 args) extern void my_set_close_on_exec(int,int); extern void do_set_close_on_exec(void); + /* Close our parents end of the pipe. */ + close(control_pipe[0]); + /* Ensure that the pipe will be closed when the child starts. */ + set_close_on_exec(control_pipe[1], 1); + SET_ONERROR(oe, exit_on_error, "Error in create_process() child."); #ifdef _REENTRANT /* forked copy. there is now only one thread running, this one. */ num_threads=1; #endif + + /* Wait for parent to get ready... */ + while ((( e = read(control_pipe[1], buf, 1)) < 0) && (errno == EINTR)) + ; + + /* FIXME: What to do if e < 0 ? */ + call_callback(&fork_child_callback, 0); for(e=0;e<cmd->size;e++) storage.argv[e]=ITEM(cmd)[e].u.string->str; @@ -1462,7 +1536,7 @@ void f_create_process(INT32 args) __FILE__, __LINE__, tmp->u.string->str, errno); #endif /* PROC_DEBUG */ - exit(69); + PROCERROR(PROCE_CHDIR, 0); } #ifdef HAVE_NICE @@ -1499,7 +1573,7 @@ void f_create_process(INT32 args) __FILE__, __LINE__, f, fd, errno); #endif /* PROC_DEBUG */ - exit(67); + PROCERROR(PROCE_DUP2, f); } } } @@ -1544,7 +1618,7 @@ void f_create_process(INT32 args) __FILE__, __LINE__, (int)wanted_gid, errno); #endif /* PROC_DEBUG */ - exit(77); + PROCERROR(PROCE_SETGID, (int)wanted_gid); } } #endif @@ -1560,7 +1634,8 @@ void f_create_process(INT32 args) #ifdef PROC_DEBUG fprintf(stderr, "setgroups() failed.\n"); #endif /* PROC_DEBUG */ - exit(77); + + PROCERROR(PROCE_SETGROUPS,0); } } #endif @@ -1580,7 +1655,8 @@ void f_create_process(INT32 args) #ifdef PROC_DEBUG fprintf(stderr, "getpwuid() failed.\n"); #endif /* PROC_DEBUG */ - exit(77); + + PROCERROR(PROCE_GETPWUID, wanted_uid); } initgroupgid=pw->pw_gid; /* printf("uid=%d euid=%d initgroups(%s,%d)\n",getuid(),geteuid(),pw->pw_name, initgroupgid); */ @@ -1604,7 +1680,8 @@ void f_create_process(INT32 args) #ifdef PROC_DEBUG fprintf(stderr, "initgroups() failed.\n"); #endif /* PROC_DEBUG */ - exit(77); + + PROCERROR(PROCE_INITGROUPS, 0); } } } @@ -1613,7 +1690,8 @@ void f_create_process(INT32 args) if(setuid(wanted_uid)) { perror("setuid"); - exit(77); + + PROCERROR(PROCE_SETUID, (int)wanted_uid); } } #endif /* SETUID */ @@ -1642,7 +1720,11 @@ void f_create_process(INT32 args) "errno = %d\n", storage.argv[0], errno); #endif /* PROC_DEBUG */ - exit(69); +#ifndef HAVE_BROKEN_F_SETFD + /* No way to tell about this on broken OS's :-( */ + PROCERROR(PROCE_EXEC, 0); +#endif /* HAVE_BROKEN_F_SETFD */ + exit(99); } } #endif /* __amigaos__ */