int start_thread(void (*fn)(void *, int), void *ptr, int l) { int p[2]; pid_t pid; if (c_pipe(p) < 0) return -1; if (set_nonblocking_fd(p[0]) < 0) return -1; if (set_nonblocking_fd(p[1]) < 0) return -1; pid = fork(); if (!pid) { struct terminal *term; /* Close input in this thread; otherwise, if it will live * longer than its parent, it'll block the terminal until it'll * quit as well; this way it will hopefully just die unseen and * in background, causing no trouble. */ /* Particularly, when async dns resolving was in progress and * someone quitted ELinks, it could make a delay before the * terminal would be really freed and returned to shell. */ foreach (term, terminals) if (term->fdin > 0) close(term->fdin); close(p[0]); fn(ptr, p[1]); write(p[1], "x", 1); close(p[1]); /* We use _exit() here instead of exit(), see * http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC6 for * reasons. Fixed by Sven Neumann <*****@*****.**>. */ _exit(0); } if (pid == -1) { close(p[0]); close(p[1]); return -1; } close(p[1]); return p[0]; }
int start_thread(void (*fn)(void *, int), void *ptr, int l) { int p[2]; struct tdata *t; if (c_pipe(p) < 0) return -1; t = malloc(sizeof(*t) + l); if (!t) return -1; t->fn = fn; t->h = p[1]; memcpy(t->data, ptr, l); if (start_thr((void (*)(void *)) bgt, t, "elinks_thread") < 0) { close(p[0]); close(p[1]); mem_free(t); return -1; } return p[0]; }
void mailcap_protocol_handler(struct connection *conn) { #ifdef HAVE_FORK unsigned char *script, *ref; pid_t pid; struct connection_state state = connection_state(S_OK); int pipe_read[2], check; /* security checks */ if (!conn->referrer || conn->referrer->protocol != PROTOCOL_MAILCAP) { goto bad; } ref = get_uri_string(conn->referrer, URI_DATA); if (!ref) { goto bad; } check = strcmp(ref, "elmailcap"); mem_free(ref); if (check) goto bad; script = get_uri_string(conn->uri, URI_DATA); if (!script) { state = connection_state(S_OUT_OF_MEM); goto end2; } if (c_pipe(pipe_read)) { state = connection_state_for_errno(errno); goto end1; } pid = fork(); if (pid < 0) { state = connection_state_for_errno(errno); goto end0; } if (!pid) { if (dup2(pipe_read[1], STDOUT_FILENO) < 0) { _exit(2); } /* We implicitly chain stderr to ELinks' stderr. */ close_all_non_term_fd(); if (execl("/bin/sh", "/bin/sh", "-c", script, (char *) NULL)) { _exit(3); } } else { /* ELinks */ mem_free(script); if (!init_http_connection_info(conn, 1, 0, 1)) { close(pipe_read[0]); close(pipe_read[1]); return; } close(pipe_read[1]); conn->socket->fd = pipe_read[0]; conn->data_socket->fd = -1; conn->cgi = 1; set_nonblocking_fd(conn->socket->fd); get_request(conn); return; } end0: close(pipe_read[0]); close(pipe_read[1]); end1: mem_free(script); end2: abort_connection(conn, state); return; #endif bad: abort_connection(conn, connection_state(S_BAD_URL)); }
void smb_protocol_handler(struct connection *conn) { int smb_pipe[2] = { -1, -1 }; int header_pipe[2] = { -1, -1 }; pid_t cpid; if (c_pipe(smb_pipe) || c_pipe(header_pipe)) { int s_errno = errno; if (smb_pipe[0] >= 0) close(smb_pipe[0]); if (smb_pipe[1] >= 0) close(smb_pipe[1]); if (header_pipe[0] >= 0) close(header_pipe[0]); if (header_pipe[1] >= 0) close(header_pipe[1]); abort_connection(conn, connection_state_for_errno(s_errno)); return; } conn->from = 0; conn->unrestartable = 1; find_auth(conn->uri); /* remember username and password */ cpid = fork(); if (cpid == -1) { int s_errno = errno; close(smb_pipe[0]); close(smb_pipe[1]); close(header_pipe[0]); close(header_pipe[1]); retry_connection(conn, connection_state_for_errno(s_errno)); return; } if (!cpid) { dup2(open("/dev/null", O_RDONLY), 0); close(1); close(2); data_out = fdopen(smb_pipe[1], "w"); header_out = fdopen(header_pipe[1], "w"); if (!data_out || !header_out) exit(1); close(smb_pipe[0]); close(header_pipe[0]); /* There may be outgoing data in stdio buffers * inherited from the parent process. The parent * process is going to write this data, so the child * process must not do that. Closing the file * descriptors ensures this. * * FIXME: If something opens more files and gets the * same file descriptors and does not close them * before exit(), then stdio may attempt to write the * buffers to the wrong files. This might happen for * example if libsmbclient calls syslog(). */ close_all_fds_but_two(smb_pipe[1], header_pipe[1]); do_smb(conn); } else { struct read_buffer *buf2; conn->data_socket->fd = smb_pipe[0]; conn->socket->fd = header_pipe[0]; set_nonblocking_fd(conn->data_socket->fd); set_nonblocking_fd(conn->socket->fd); close(smb_pipe[1]); close(header_pipe[1]); buf2 = alloc_read_buffer(conn->socket); if (!buf2) { close_socket(conn->data_socket); close_socket(conn->socket); abort_connection(conn, connection_state(S_OUT_OF_MEM)); return; } read_from_socket(conn->socket, buf2, connection_state(S_CONN), smb_got_header); } }
void daemon_t::_parent( ) { // http://www.freedesktop.org/software/systemd/man/daemon.html pipe_t c_pipe( "child" ); pipe_t g_pipe( "grandchild" ); // TODO: Reset signal handlers? // TODO: Reset signal mask? // TODO: Sanitize environment? pid_t pid = 0; ESYSCALL( "forking child", "fork", pid = fork(), pid >= 0, "child forked " << ( pid == 0 ? "(i am child)" : "(i am parent)" ) ); if ( pid == 0 ) { _child( c_pipe, g_pipe ); return; // TODO: Or exit? }; c_pipe.writer().close(); g_pipe.writer().close(); int error = 0; ESYSCALL( "anti-zombying child", "waitpid", error = waitpid( pid, NULL, WNOHANG ), error != -1, "child anti-zombied" ); // Wait until child finishes initialization. string_t c_reply = c_pipe.reader().read(); string_t g_reply = g_pipe.reader().read(); // Report errors, if any. if ( c_reply != ok || g_reply != ok ) { osstream_t errors; if ( c_reply != ok ) { errors << "Child: "; if ( c_reply.empty() ) { errors << "Died silently"; } else { errors << split( "\n", c_reply ); }; }; // if if ( g_reply != ok ) { if ( ! errors.str().empty() ) { errors << "; "; }; errors << "Grandchild: "; if ( g_reply.empty() ) { errors << "Died silently"; } else { errors << split( "\n", g_reply ); }; }; // if ERR( 1, "Daemon initialization failed: " << errors.str() ); }; // if c_pipe.reader().close(); g_pipe.reader().close(); }; // _parent