/* * close_out: When we are done sending to a process sometimes we have to * close our stdout before they will do their thing and send us data back * to stdin. */ static void exec_close_out (int idx) { Process *proc; if (valid_process_index(idx) == 0) return; proc = process_list[idx]; if (proc->p_stdout != -1) proc->p_stdout = new_close(proc->p_stdout); if (proc->p_stderr != -1) proc->p_stderr = new_close(proc->p_stderr); proc->dumb = 1; }
/* * exec_close: silly, eh? Well, it makes the code look nicer. Or does it * really? No. But what the hell */ static int exec_close(int des) { if (des == -1) return (-1); new_close(des); return (-1); }
/* * close_in: When we are finished with the process but still want the * rest of its output, we close its input, and hopefully it will get the * message and close up shop. */ static void exec_close_in (int idx) { Process *proc; if (valid_process_index(idx) == 0) return; proc = process_list[idx]; if (proc->p_stdin != -1) proc->p_stdin = new_close(proc->p_stdin); }
/* * This is the back end to do_processes, saves some repeated code */ static void handle_filedesc (Process *proc, int *fd, int hook_nonl, int hook_nl) { char exec_buffer[IO_BUFFER_SIZE + 1]; ssize_t len; int ofs; const char *callback = NULL; int hook = -1; int l; char logical_name[1024]; const char *utf8_text; char *extra = NULL; /* No buffering! */ switch ((len = dgets(*fd, exec_buffer, IO_BUFFER_SIZE, 0))) { case -1: /* Something died */ { *fd = new_close(*fd); if (proc->p_stdout == -1 && proc->p_stderr == -1) proc->dumb = 1; return; /* PUNT! */ } case 0: /* We didnt get a full line */ { /* * XXX This is a hack. dgets() can return 0 for a line * containing solely a newline, as well as a line that didn't * have a newline. So we have to check to see if the line * contains only a newline! */ if (exec_buffer[0] != '\n') { if (hook_nl == EXEC_LIST) { if (proc->stdoutpc && *proc->stdoutpc) callback = proc->stdoutpc; } else if (hook_nl == EXEC_ERRORS_LIST) { if (proc->stderrpc && *proc->stderrpc) callback = proc->stderrpc; } hook = hook_nonl; break; } /* XXX HACK -- Line contains only a newline. */ *exec_buffer = 0; /* FALLTHROUGH */ } default: /* We got a full line */ { if (hook_nl == EXEC_LIST) { if (proc->stdoutc && *proc->stdoutc) callback = proc->stdoutc; } else if (hook_nl == EXEC_ERRORS_LIST) { if (proc->stderrc && *proc->stderrc) callback = proc->stderrc; } hook = hook_nl; break; } } ofs = from_server; from_server = proc->server; if (proc->refnum) l = message_setall(proc->refnum, NULL, LEVEL_OTHER); else l = message_from(NULL, LEVEL_OTHER); proc->counter++; while (len > 0 && (exec_buffer[len - 1] == '\n' || exec_buffer[len - 1] == '\r')) exec_buffer[--len] = 0; index_to_target(proc->index, logical_name, sizeof(logical_name)); utf8_text = inbound_recode(logical_name, proc->server, empty_string, exec_buffer, &extra); if (proc->redirect) redirect_text(proc->server, proc->who, utf8_text, proc->redirect, 1); if (callback) call_lambda_command("EXEC", callback, utf8_text); else if (proc->logical) { if ((do_hook(hook, "%s %s", proc->logical, utf8_text))) if (!proc->redirect) put_it("%s", utf8_text); } else { if ((do_hook(hook, "%d %s", proc->index, utf8_text))) if (!proc->redirect) put_it("%s", utf8_text); } new_free(&extra); pop_message_from(l); from_server = ofs; }
/* * This function is called by the three places that can effect a change * on the state of a running process: * 1) get_child_exit, which can mark a process as exited * 2) do_processes, which can mark a child as being done with I/O * 3) execcmd, which can mark a child as being done with I/O * * Any processes that are found to have both exited and having completed * their I/O will be summarily destroyed. */ static void cleanup_dead_processes (void) { int i; List *cmd, *next; Process *deadproc, *proc; char *exit_info; int old_from_server, l; if (!process_list) return; /* Nothing to do */ old_from_server = from_server; for (i = 0; i < process_list_size; i++) { if (!(proc = process_list[i])) continue; /* * We do not parse the process if it has not * both exited and finished its io, UNLESS * it has been disowned. */ if ((!proc->exited || !proc->dumb) && !proc->disowned) continue; /* Not really dead yet */ deadproc = process_list[i]; process_list[i] = NULL; /* * First thing to do is fill out the exit information */ if (deadproc->logical) { size_t len = strlen(deadproc->logical) + 25; exit_info = alloca(len); snprintf(exit_info, len, "%s %d %d", deadproc->logical, deadproc->termsig, deadproc->retcode); } else { exit_info = alloca(40); snprintf(exit_info, 32, "%d %d %d", deadproc->index, deadproc->termsig, deadproc->retcode); } from_server = deadproc->server; l = message_from(NULL, LEVEL_OTHER); /* * First thing we do is run any /wait %proc -cmd commands */ next = deadproc->waitcmds; deadproc->waitcmds = NULL; while ((cmd = next)) { next = cmd->next; call_lambda_command("WAITPROC", cmd->name, exit_info); new_free(&cmd->name); new_free((char **)&cmd); } /* * Throw /on exec_exit */ if (do_hook(EXEC_EXIT_LIST, "%s", exit_info)) { if (get_int_var(NOTIFY_ON_TERMINATION_VAR)) { if (deadproc->termsig > 0 && deadproc->termsig < NSIG) { say("Process %d (%s) terminated " "with signal %s (%d)", deadproc->index, deadproc->name, sys_siglist[deadproc->termsig], deadproc->termsig); } else if (deadproc->disowned) { say("Process %d (%s) disowned", deadproc->index, deadproc->name); } else { say("Process %d (%s) terminated " "with return code %d", deadproc->index, deadproc->name, deadproc->retcode); } } } pop_message_from(l); deadproc->p_stdin = new_close(deadproc->p_stdin); deadproc->p_stdout = new_close(deadproc->p_stdout); deadproc->p_stderr = new_close(deadproc->p_stderr); new_free(&deadproc->name); new_free(&deadproc->logical); new_free(&deadproc->who); new_free(&deadproc->redirect); new_free(&deadproc->stdoutc); new_free(&deadproc->stdoutpc); new_free(&deadproc->stderrc); new_free(&deadproc->stderrpc); new_free((char **)&deadproc); } /* * Resize away any dead processes at the end */ for (i = process_list_size - 1; i >= 0; i--) { if (process_list[i]) break; } if (process_list_size != i + 1) { process_list_size = i + 1; RESIZE(process_list, Process, process_list_size); } from_server = old_from_server; }
/* * This is the back end to do_processes, saves some repeated code */ static void handle_filedesc (Process *proc, int *fd, int hook_nonl, int hook_nl) { char exec_buffer[IO_BUFFER_SIZE + 1]; ssize_t len; switch ((len = dgets(*fd, exec_buffer, IO_BUFFER_SIZE, 0, NULL))) /* No buffering! */ { case -1: /* Something died */ { *fd = new_close(*fd); if (proc->p_stdout == -1 && proc->p_stderr == -1) proc->dumb = 1; break; } case 0: /* We didnt get a full line */ { /* * XXX XXX Major, world class hack here XXX XXX * Since this problem has been addressed already * by newio2.c, it doesn't matter if we just fix the * symptom here since this code is all obsolete. */ if (exec_buffer[0] == '\n') { exec_buffer[0] = 0; goto this_sucks; } if (hook_nl == EXEC_LIST && proc->stdoutpc && *proc->stdoutpc) parse_line("EXEC", proc->stdoutpc, exec_buffer, 0, 0); else if (hook_nl == EXEC_ERRORS_LIST && proc->stderrpc && *proc->stderrpc) parse_line("EXEC", proc->stderrpc, exec_buffer, 0, 0); else if (proc->logical) do_hook(hook_nonl, "%s %s", proc->logical, exec_buffer); else do_hook(hook_nonl, "%d %s", proc->index, exec_buffer); set_prompt_by_refnum(proc->refnum, exec_buffer); break; } default: /* We got a full line */ this_sucks: { int ofs; ofs = from_server; from_server = proc->server; if (proc->refnum) message_to(proc->refnum); proc->counter++; while (len > 0 && (exec_buffer[len] == '\n' || exec_buffer[len] == '\r')) { exec_buffer[len--] = 0; } if (proc->redirect) redirect_text(proc->server, proc->who, exec_buffer, proc->redirect, 1); if (hook_nl == EXEC_LIST && proc->stdoutc && *proc->stdoutc) parse_line("EXEC", proc->stdoutc, exec_buffer, 0, 0); else if (hook_nl == EXEC_ERRORS_LIST && proc->stderrc && *proc->stderrc) parse_line("EXEC", proc->stderrc, exec_buffer, 0, 0); else if (proc->logical) { if ((do_hook(hook_nl, "%s %s", proc->logical, exec_buffer))) if (!proc->redirect) put_it("%s", exec_buffer); } else { if ((do_hook(hook_nl, "%d %s", proc->index, exec_buffer))) if (!proc->redirect) put_it("%s", exec_buffer); } message_to(-1); from_server = ofs; } } }