bool socket_close(int fd) { char unused[64]; int sys_res; sys_res = shutdown(fd, SHUT_WR); if (sys_res < 0) { close_noerr(fd); return false; } for (;;) { do { sys_res = read(fd, unused, sizeof(unused)); } while (sys_res < 0 && errno == EINTR); if (sys_res < 0) { close_noerr(fd); return false; } if (sys_res == 0) break; } if (close(fd) < 0) return false; else return true; }
static int start_connect(const struct addrinfo *addr, bool *immediate) { int fd; *immediate = false; fd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol); if (fd == -1) return fd; if (!set_nonblock(fd, true)) goto close; if (connect(fd, addr->ai_addr, addr->ai_addrlen) == 0) { /* Immediate connect. */ *immediate = true; return fd; } if (errno == EINPROGRESS) return fd; close: close_noerr(fd); return -1; }
void net_connect_abort(struct pollfd pfds[2]) { unsigned int i; for (i = 0; i < 2; i++) { if (pfds[i].fd != -1) close_noerr(pfds[i].fd); pfds[i].fd = -1; } }
static bool create_child(struct ptr_valid_batch *batch) { int outpipe[2], inpipe[2]; if (pipe(outpipe) != 0) return false; if (pipe(inpipe) != 0) goto close_outpipe; fflush(stdout); batch->child_pid = fork(); if (batch->child_pid == 0) { close(outpipe[1]); close(inpipe[0]); run_child(outpipe[0], inpipe[1]); } if (batch->child_pid == -1) goto cleanup_pid; close(outpipe[0]); close(inpipe[1]); batch->to_child = outpipe[1]; batch->from_child = inpipe[0]; return true; cleanup_pid: batch->child_pid = 0; close_noerr(inpipe[0]); close_noerr(inpipe[1]); close_outpipe: close_noerr(outpipe[0]); close_noerr(outpipe[1]); return false; }
int net_connect_async(const struct addrinfo *addrinfo, struct pollfd pfds[2]) { const struct addrinfo *addr[2] = { NULL, NULL }; unsigned int i; pfds[0].fd = pfds[1].fd = -1; pfds[0].events = pfds[1].events = POLLOUT; /* Give IPv6 a slight advantage, by trying it first. */ for (; addrinfo; addrinfo = addrinfo->ai_next) { switch (addrinfo->ai_family) { case AF_INET: addr[1] = addrinfo; break; case AF_INET6: addr[0] = addrinfo; break; default: continue; } } /* In case we found nothing. */ errno = ENOENT; for (i = 0; i < 2; i++) { bool immediate; if (!addr[i]) continue; pfds[i].fd = start_connect(addr[i], &immediate); if (immediate) { if (pfds[!i].fd != -1) close(pfds[!i].fd); if (!set_nonblock(pfds[i].fd, false)) { close_noerr(pfds[i].fd); return -1; } return pfds[i].fd; } } if (pfds[0].fd != -1 || pfds[1].fd != -1) errno = EINPROGRESS; return -1; }
static int make_listen_fd(const struct addrinfo *addrinfo) { int fd, on = 1; fd = socket(addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol); if (fd < 0) return -1; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)); if (bind(fd, addrinfo->ai_addr, addrinfo->ai_addrlen) != 0) goto fail; if (should_listen(addrinfo) && listen(fd, 5) != 0) goto fail; return fd; fail: close_noerr(fd); return -1; }
/* arg* may be null */ static char *ask_process(const tal_t *ctx, const char *name, const char *arg1, const char *arg2, const char *arg3, const char *arg4, const char *arg5) { char *output; int fds[2], status; if (pipe(fds) != 0) return NULL; switch (fork()) { case -1: return NULL; case 0: close(fds[0]); dup2(fds[1], STDOUT_FILENO); execlp(name, name, arg1, arg2, arg3, arg4, arg5, NULL); exit(errno); } close(fds[1]); output = grab_fd(ctx, fds[0]); close_noerr(fds[0]); wait(&status); if (!WIFEXITED(status)) { output = tal_free(output); errno = EINTR; } else if (WEXITSTATUS(status)) { output = tal_free(output); errno = WEXITSTATUS(status); } return output; }
static char *grab(const char *filename) { int ret, fd; size_t max = 16384, s = 0; char *buffer; fd = open(filename, O_RDONLY); if (fd < 0) return NULL; buffer = malloc(max+1); if (!buffer) goto close; while ((ret = read(fd, buffer + s, max - s)) > 0) { s += ret; if (s == max) { buffer = realloc(buffer, max*2+1); if (!buffer) goto close; max *= 2; } } if (ret < 0) goto free; close(fd); buffer[s] = '\0'; return buffer; free: free(buffer); close: close_noerr(fd); return NULL; }
char *run_with_timeout(const void *ctx, const char *cmd, bool *ok, unsigned *timeout_ms) { pid_t pid; int p[2]; char *ret; int status, ms; struct timeval start, end; *ok = false; if (pipe(p) != 0) return talloc_asprintf(ctx, "Failed to create pipe: %s", strerror(errno)); if (tools_verbose) printf("Running: %s\n", cmd); gettimeofday(&start, NULL); pid = fork(); if (pid == -1) { close_noerr(p[0]); close_noerr(p[1]); return talloc_asprintf(ctx, "Failed to fork: %s", strerror(errno)); return NULL; } if (pid == 0) { struct itimerval itim; if (dup2(p[1], STDOUT_FILENO) != STDOUT_FILENO || dup2(p[1], STDERR_FILENO) != STDERR_FILENO || close(p[0]) != 0 || close(STDIN_FILENO) != 0 || open("/dev/null", O_RDONLY) != STDIN_FILENO) exit(128); signal(SIGALRM, killme); itim.it_interval.tv_sec = itim.it_interval.tv_usec = 0; itim.it_value.tv_sec = *timeout_ms / 1000; itim.it_value.tv_usec = (*timeout_ms % 1000) * 1000; setitimer(ITIMER_REAL, &itim, NULL); status = system(cmd); if (WIFEXITED(status)) exit(WEXITSTATUS(status)); /* Here's a hint... */ exit(128 + WTERMSIG(status)); } close(p[1]); ret = grab_fd(ctx, p[0], NULL); /* This shouldn't fail... */ if (waitpid(pid, &status, 0) != pid) err(1, "Failed to wait for child"); gettimeofday(&end, NULL); if (end.tv_usec < start.tv_usec) { end.tv_usec += 1000000; end.tv_sec--; } ms = (end.tv_sec - start.tv_sec) * 1000 + (end.tv_usec - start.tv_usec) / 1000; if (ms > *timeout_ms) *timeout_ms = 0; else *timeout_ms -= ms; close(p[0]); if (tools_verbose) { printf("%s", ret); printf("Finished: %u ms, %s %u\n", ms, WIFEXITED(status) ? "exit status" : "killed by signal", WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status)); } *ok = (WIFEXITED(status) && WEXITSTATUS(status) == 0); return ret; }
pid_t pipecmdarr(int *fd_fromchild, int *fd_tochild, int *fd_errfromchild, char *const *arr) { int tochild[2], fromchild[2], errfromchild[2], execfail[2]; pid_t childpid; int err; if (fd_tochild) { if (pipe(tochild) != 0) goto fail; } else { tochild[0] = open("/dev/null", O_RDONLY); if (tochild[0] < 0) goto fail; } if (fd_fromchild) { if (pipe(fromchild) != 0) goto close_tochild_fail; } else { fromchild[1] = open("/dev/null", O_WRONLY); if (fromchild[1] < 0) goto close_tochild_fail; } if (fd_errfromchild) { if (fd_errfromchild == fd_fromchild) { errfromchild[0] = fromchild[0]; errfromchild[1] = fromchild[1]; } else { if (pipe(errfromchild) != 0) goto close_fromchild_fail; } } else { errfromchild[1] = open("/dev/null", O_WRONLY); if (errfromchild[1] < 0) goto close_fromchild_fail; } if (pipe(execfail) != 0) goto close_errfromchild_fail; if (fcntl(execfail[1], F_SETFD, fcntl(execfail[1], F_GETFD) | FD_CLOEXEC) < 0) goto close_execfail_fail; childpid = fork(); if (childpid < 0) goto close_execfail_fail; if (childpid == 0) { if (fd_tochild) close(tochild[1]); if (fd_fromchild) close(fromchild[0]); if (fd_errfromchild && fd_errfromchild != fd_fromchild) close(errfromchild[0]); close(execfail[0]); // Child runs command. if (tochild[0] != STDIN_FILENO) { if (dup2(tochild[0], STDIN_FILENO) == -1) goto child_errno_fail; close(tochild[0]); } if (fromchild[1] != STDOUT_FILENO) { if (dup2(fromchild[1], STDOUT_FILENO) == -1) goto child_errno_fail; close(fromchild[1]); } if (fd_errfromchild && fd_errfromchild == fd_fromchild) { if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) goto child_errno_fail; } else if (errfromchild[1] != STDERR_FILENO) { if (dup2(errfromchild[1], STDERR_FILENO) == -1) goto child_errno_fail; close(errfromchild[1]); } execvp(arr[0], arr); child_errno_fail: err = errno; write(execfail[1], &err, sizeof(err)); exit(127); } close(tochild[0]); close(fromchild[1]); close(errfromchild[1]); close(execfail[1]); /* Child will close this without writing on successful exec. */ if (read(execfail[0], &err, sizeof(err)) == sizeof(err)) { close(execfail[0]); waitpid(childpid, NULL, 0); errno = err; return -1; } close(execfail[0]); if (fd_tochild) *fd_tochild = tochild[1]; if (fd_fromchild) *fd_fromchild = fromchild[0]; if (fd_errfromchild) *fd_errfromchild = errfromchild[0]; return childpid; close_execfail_fail: close_noerr(execfail[0]); close_noerr(execfail[1]); close_errfromchild_fail: if (fd_errfromchild) close_noerr(errfromchild[0]); close_noerr(errfromchild[1]); close_fromchild_fail: if (fd_fromchild) close_noerr(fromchild[0]); close_noerr(fromchild[1]); close_tochild_fail: close_noerr(tochild[0]); if (fd_tochild) close_noerr(tochild[1]); fail: return -1; }