__dead void shell_exec(const char *shell, const char *shellcmd) { const char *shellname, *ptr; char *argv0; ptr = strrchr(shell, '/'); if (ptr != NULL && *(ptr + 1) != '\0') shellname = ptr + 1; else shellname = shell; if (login_shell) xasprintf(&argv0, "-%s", shellname); else xasprintf(&argv0, "%s", shellname); setenv("SHELL", shell, 1); setblocking(STDIN_FILENO, 1); setblocking(STDOUT_FILENO, 1); setblocking(STDERR_FILENO, 1); closefrom(STDERR_FILENO + 1); execl(shell, argv0, "-c", shellcmd, (char *) NULL); fatal("execl failed"); }
static int on_ssh_channel_read(__unused ssh_session _session, __unused ssh_channel channel, void *_data, uint32_t total_len, __unused int is_stderr, void *userdata) { struct tmate_session *session = userdata; char *data = _data; size_t written = 0; ssize_t len; if (session->readonly) return total_len; setblocking(session->pty, 1); while (total_len) { len = write(session->pty, data, total_len); if (len < 0) tmate_fatal("Error writing to pty"); total_len -= len; written += len; data += len; } setblocking(session->pty, 0); return written; }
TCPSocket::TCPSocket( TCPSocket& (connreq)(), void (*disconnected)(), void (*received)(void *, size_t), void (*error)(), int bs ): fd(socket(DOMAIN, TYPE, PROTOCOL)), addr(), lerr(NULL), buffer(new char[bs]), buffersize(bs), connrequestf(connreq), disconnectedf(disconnected), receivedf(received), errorf(error), state(IDLE) { if(fd == -1 || !setblocking(false)) throw ERR_INIT; // FIXME FIXME FIXME no throw in constructor #if defined(SO_NOSIGPIPE) { int val = 1; // ignore sigpipe - FreeBSD setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &val, sizeof(val)); } #endif memset(&addr, '\0', sizeof addr); }
int SocketUDP::openAsReceiver(const string& ip, int port, bool blocking) { int r; _leaveGroup = false; r = _ip.setString(ip); if (r != E_OK) return r; r = open(_family, _type, _protocol); if (r != E_OK) return r; r = bind(port); if (r != E_OK) return r; if (_ip.getType() == IPv4::TYPE_MULTICAST) { r = joinGroup(_ip); if (r != E_OK) return r; _igmpSender.start(_ip); _leaveGroup = true; } r = setblocking(blocking); if (r != E_OK) return r; return E_OK; }
int SocketUDP::openAsSender(const string& ip, int port, bool blocking) { int r; _leaveGroup = false; r = _ip.setString(ip); if (r != E_OK) return r; r = open(_family, _type, _protocol); if (r != E_OK) return r; memset(&_addr.sin_zero, '\0', 8); _addr.sin_family = AF_INET; _addr.sin_addr.s_addr = inet_addr(ip.c_str()); _addr.sin_port = htons(port); if (_ip.getType() == IPv4::TYPE_MULTICAST) { r = setTtl(DEFAULT_MULTICAST_TTL); if (r != E_OK) return r; r = setLoop(DEFAULT_LOOPBACK); if (r != E_OK) return r; /* // seta valores default para TTL e LOOP if (setsockopt(IPPROTO_IP, IP_MULTICAST_TTL, (char *)&ttl, sizeof(ttl)) < 0) { throw 1; } if (setsockopt(IPPROTO_IP, IP_MULTICAST_LOOP, (char *)&loop, sizeof(loop)) < 0) { throw 1; } // permite envio dos pacotes de qualquer interface _mreq.imr_interface.s_addr = htonl(INADDR_ANY); if (setsockopt(IPPROTO_IP, IP_MULTICAST_IF, (char *)&_mreq.imr_interface, sizeof(struct ip_mreq)) < 0) { throw 1; } */ } else { r = setTtl(DEFAULT_UNICAST_TTL); if (r != E_OK) return r; } r = setblocking(blocking); if (r != E_OK) return r; return E_OK; }
void TCPSocket::newsocket(int newfd) { if(newfd == -1 || !setblocking(false)) throw ERR_INIT; if(state == CONNECTED) shutdown(fd, SHUT_RDWR); close(fd); fd = newfd; }
//------------------------------------------------------------------------------------ Connection::Connection(SOCKET fd) { this->fd = fd; this->recv_bytes = 0; this->send_bytes = 0; this->active = true; if (fd > 0) { setblocking(fd, false); } }
void tty_start_tty(struct tty *tty) { struct termios tio; if (tty->fd == -1 || tcgetattr(tty->fd, &tty->tio) != 0) return; setblocking(tty->fd, 0); bufferevent_enable(tty->event, EV_READ|EV_WRITE); memcpy(&tio, &tty->tio, sizeof tio); tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP); tio.c_iflag |= IGNBRK; tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET); tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL| ECHOPRT|ECHOKE|ECHOCTL|ISIG); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; if (tcsetattr(tty->fd, TCSANOW, &tio) == 0) tcflush(tty->fd, TCIOFLUSH); tty_putcode(tty, TTYC_SMCUP); tty_putcode(tty, TTYC_SGR0); memcpy(&tty->cell, &grid_default_cell, sizeof tty->cell); tty_putcode(tty, TTYC_RMKX); if (tty_use_acs(tty)) tty_putcode(tty, TTYC_ENACS); tty_putcode(tty, TTYC_CLEAR); tty_putcode(tty, TTYC_CNORM); if (tty_term_has(tty->term, TTYC_KMOUS)) tty_puts(tty, "\033[?1000l"); tty->cx = UINT_MAX; tty->cy = UINT_MAX; tty->rlower = UINT_MAX; tty->rupper = UINT_MAX; tty->mode = MODE_CURSOR; tty->flags |= TTY_STARTED; tty_force_cursor_colour(tty, ""); }
void tty_stop_tty(struct tty *tty) { struct winsize ws; if (!(tty->flags & TTY_STARTED)) return; tty->flags &= ~TTY_STARTED; bufferevent_disable(tty->event, EV_READ|EV_WRITE); /* * Be flexible about error handling and try not kill the server just * because the fd is invalid. Things like ssh -t can easily leave us * with a dead tty. */ if (ioctl(tty->fd, TIOCGWINSZ, &ws) == -1) return; if (tcsetattr(tty->fd, TCSANOW, &tty->tio) == -1) return; setblocking(tty->fd, 1); tty_raw(tty, tty_term_string2(tty->term, TTYC_CSR, 0, ws.ws_row - 1)); if (tty_use_acs(tty)) tty_raw(tty, tty_term_string(tty->term, TTYC_RMACS)); tty_raw(tty, tty_term_string(tty->term, TTYC_SGR0)); tty_raw(tty, tty_term_string(tty->term, TTYC_RMKX)); tty_raw(tty, tty_term_string(tty->term, TTYC_CLEAR)); if (tty_term_has(tty->term, TTYC_CS1) && tty->cstyle != 0) { if (tty_term_has(tty->term, TTYC_CSR1)) tty_raw(tty, tty_term_string(tty->term, TTYC_CSR1)); else tty_raw(tty, tty_term_string1(tty->term, TTYC_CS1, 0)); } tty_raw(tty, tty_term_string(tty->term, TTYC_CR)); tty_raw(tty, tty_term_string(tty->term, TTYC_CNORM)); if (tty_term_has(tty->term, TTYC_KMOUS)) tty_raw(tty, "\033[?1000l"); tty_raw(tty, tty_term_string(tty->term, TTYC_RMCUP)); if (tty->xterm_version > 270) tty_raw(tty, "\033[61;1\"p"); }
void control_error_callback( unused struct bufferevent *bufev, unused short what, unused void *data) { struct client *c = data; c->references--; if (c->flags & CLIENT_DEAD) return; bufferevent_disable(c->stdin_event, EV_READ|EV_WRITE); setblocking(c->stdin_fd, 1); close(c->stdin_fd); c->stdin_fd = -1; if (c->stdin_callback != NULL) c->stdin_callback(c, c->stdin_data); }
int write_response(pConnInfo conn_info, struct response* header_body) {/*{{{*/ int res; setblocking(conn_info->clientfd); char *accept_encoding; //compress--start-- if((header_body->content_len > 0) && uws_config.http.gzip && in_str_array(uws_config.http.gzip_types, get_header_param("Content-Type", header_body->header)) >= 0 && (accept_encoding = get_header_param("Accept-Encoding", conn_info->request_header)) && strstr(accept_encoding, "gzip") != NULL ) { size_t src_len = header_body->content_len; size_t dst_len; char *dst_buff; gzcompress(&dst_buff, &dst_len, header_body->content, src_len); char *content_len = itoa(dst_len); add_header_param("Content-Length", content_len, header_body->header); uws_free(content_len); add_header_param("Content-Encoding", "gzip", header_body->header); uws_free(header_body->content); header_body->content = dst_buff; header_body->content_len = dst_len; } char* header_str = str_response_header(header_body->header); size_t header_len = strlen(header_str); res = write(conn_info->clientfd, header_str, header_len); uws_free(header_str); if(res == -1) return -1; res = write(conn_info->clientfd, HEADER_SEP, strlen(HEADER_SEP)); if(res == -1) return -1; res = writen(conn_info->clientfd, header_body->content, header_body->content_len); if(res == -1) {return -1;} return 0; }/*}}}*/
void tmate_client_pty_init(struct tmate_session *session) { struct tmate_ssh_client *client = &session->ssh_client; ioctl(session->pty, TIOCSWINSZ, &session->ssh_client.winsize_pty); memset(&client->channel_cb, 0, sizeof(client->channel_cb)); ssh_callbacks_init(&client->channel_cb); client->channel_cb.userdata = session; client->channel_cb.channel_data_function = on_ssh_channel_read, ssh_set_channel_callbacks(client->channel, &client->channel_cb); ssh_set_message_callback(session->ssh_client.session, on_ssh_message_callback, session); setblocking(session->pty, 0); event_set(&session->ev_pty, session->pty, EV_READ | EV_PERSIST, __on_pty_event, session); event_add(&session->ev_pty, NULL); tmate_add_ssh_latency_callback(client, on_latency_callback, session); }
static selene_error_t *want_pull(selene_t *s, selene_event_e event, void *baton) { int rv = 0; char buf[8096]; size_t blen = 0; size_t remaining = 0; server_t *srv = (server_t *)baton; do { SELENE_ERR( selene_io_out_enc_bytes(s, &buf[0], sizeof(buf), &blen, &remaining)); if (blen > 0) { setblocking(srv->sock); rv = write(srv->sock, buf, blen); if (rv < 0) { srv->write_err = errno; break; } } } while (remaining > 0); return SELENE_SUCCESS; }
void tty_init_termios(int fd, struct termios *orig_tio, struct bufferevent *bufev) { struct termios tio; if (fd == -1 || tcgetattr(fd, orig_tio) != 0) return; setblocking(fd, 0); if (bufev != NULL) bufferevent_enable(bufev, EV_READ|EV_WRITE); memcpy(&tio, orig_tio, sizeof tio); tio.c_iflag &= ~(IXON|IXOFF|ICRNL|INLCR|IGNCR|IMAXBEL|ISTRIP); tio.c_iflag |= IGNBRK; tio.c_oflag &= ~(OPOST|ONLCR|OCRNL|ONLRET); tio.c_lflag &= ~(IEXTEN|ICANON|ECHO|ECHOE|ECHONL|ECHOCTL| ECHOPRT|ECHOKE|ECHOCTL|ISIG); tio.c_cc[VMIN] = 1; tio.c_cc[VTIME] = 0; if (tcsetattr(fd, TCSANOW, &tio) == 0) tcflush(fd, TCIOFLUSH); }
int SocketUDP::openAsReceiver(int port, bool blocking) { int r; _leaveGroup = false; r = _ip.setString("127.0.0.1"); if (r != E_OK) return r; r = open(_family, _type, _protocol); if (r != E_OK) return r; r = bind(port); if (r != E_OK) return r; r = setblocking(blocking); if (r != E_OK) return r; return E_OK; }
/* Start a job running, if it isn't already. */ struct job * job_run(const char *cmd, void (*callbackfn)(struct job *), void (*freefn)(void *), void *data) { struct job *job; struct environ env; pid_t pid; int nullfd, out[2]; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) return (NULL); environ_init(&env); environ_copy(&global_environ, &env); server_fill_environ(NULL, &env); switch (pid = fork()) { case -1: environ_free(&env); return (NULL); case 0: /* child */ clear_signals(1); environ_push(&env); environ_free(&env); if (dup2(out[1], STDOUT_FILENO) == -1) fatal("dup2 failed"); if (out[1] != STDOUT_FILENO) close(out[1]); close(out[0]); nullfd = open(_PATH_DEVNULL, O_RDWR, 0); if (nullfd < 0) fatal("open failed"); if (dup2(nullfd, STDIN_FILENO) == -1) fatal("dup2 failed"); if (dup2(nullfd, STDERR_FILENO) == -1) fatal("dup2 failed"); if (nullfd != STDIN_FILENO && nullfd != STDERR_FILENO) close(nullfd); closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); fatal("execl failed"); } /* parent */ environ_free(&env); close(out[1]); job = xmalloc(sizeof *job); job->cmd = xstrdup(cmd); job->pid = pid; job->status = 0; LIST_INSERT_HEAD(&all_jobs, job, lentry); job->callbackfn = callbackfn; job->freefn = freefn; job->data = data; job->fd = out[0]; setblocking(job->fd, 0); job->event = bufferevent_new(job->fd, NULL, NULL, job_callback, job); bufferevent_enable(job->event, EV_READ); log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); return (job); }
static enum cmd_retval cmd_pipe_pane_exec(struct cmd *self, struct cmdq_item *item) { struct args *args = self->args; struct client *c = cmd_find_client(item, NULL, 1); struct window_pane *wp = item->target.wp; struct session *s = item->target.s; struct winlink *wl = item->target.wl; char *cmd; int old_fd, pipe_fd[2], null_fd, in, out; struct format_tree *ft; sigset_t set, oldset; /* Destroy the old pipe. */ old_fd = wp->pipe_fd; if (wp->pipe_fd != -1) { bufferevent_free(wp->pipe_event); close(wp->pipe_fd); wp->pipe_fd = -1; if (window_pane_destroy_ready(wp)) { server_destroy_pane(wp, 1); return (CMD_RETURN_NORMAL); } } /* If no pipe command, that is enough. */ if (args->argc == 0 || *args->argv[0] == '\0') return (CMD_RETURN_NORMAL); /* * With -o, only open the new pipe if there was no previous one. This * allows a pipe to be toggled with a single key, for example: * * bind ^p pipep -o 'cat >>~/output' */ if (args_has(self->args, 'o') && old_fd != -1) return (CMD_RETURN_NORMAL); /* What do we want to do? Neither -I or -O is -O. */ if (args_has(self->args, 'I')) { in = 1; out = args_has(self->args, 'O'); } else { in = 0; out = 1; } /* Open the new pipe. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { cmdq_error(item, "socketpair error: %s", strerror(errno)); return (CMD_RETURN_ERROR); } /* Expand the command. */ ft = format_create(item->client, item, FORMAT_NONE, 0); format_defaults(ft, c, s, wl, wp); cmd = format_expand_time(ft, args->argv[0]); format_free(ft); /* Fork the child. */ sigfillset(&set); sigprocmask(SIG_BLOCK, &set, &oldset); switch (fork()) { case -1: sigprocmask(SIG_SETMASK, &oldset, NULL); cmdq_error(item, "fork error: %s", strerror(errno)); free(cmd); return (CMD_RETURN_ERROR); case 0: /* Child process. */ proc_clear_signals(server_proc, 1); sigprocmask(SIG_SETMASK, &oldset, NULL); close(pipe_fd[0]); null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); if (out) { if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); } else { if (dup2(null_fd, STDIN_FILENO) == -1) _exit(1); } if (in) { if (dup2(pipe_fd[1], STDOUT_FILENO) == -1) _exit(1); if (pipe_fd[1] != STDOUT_FILENO) close(pipe_fd[1]); } else { if (dup2(null_fd, STDOUT_FILENO) == -1) _exit(1); } if (dup2(null_fd, STDERR_FILENO) == -1) _exit(1); closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); _exit(1); default: /* Parent process. */ sigprocmask(SIG_SETMASK, &oldset, NULL); close(pipe_fd[1]); wp->pipe_fd = pipe_fd[0]; if (wp->fd != -1) wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); else wp->pipe_off = 0; setblocking(wp->pipe_fd, 0); wp->pipe_event = bufferevent_new(wp->pipe_fd, cmd_pipe_pane_read_callback, cmd_pipe_pane_write_callback, cmd_pipe_pane_error_callback, wp); if (wp->pipe_event == NULL) fatalx("out of memory"); if (out) bufferevent_enable(wp->pipe_event, EV_WRITE); if (in) bufferevent_enable(wp->pipe_event, EV_READ); free(cmd); return (CMD_RETURN_NORMAL); } }
/* Functions */ void imt_plugin(int pipe_fd, struct configuration *cfgptr, void *ptr) { int maxqsize = (MAX_QUERIES*sizeof(struct pkt_primitives))+sizeof(struct query_header)+2; struct sockaddr cAddr; struct pkt_data *data; struct ports_table pt; unsigned char srvbuf[maxqsize]; unsigned char *srvbufptr; struct query_header *qh; unsigned char *pipebuf; char path[] = "/tmp/collect.pipe"; short int go_to_clear = FALSE; u_int32_t request, sz; struct ch_status *status = ((struct channels_list_entry *)ptr)->status; int datasize = ((struct channels_list_entry *)ptr)->datasize; struct extra_primitives extras; unsigned char *rgptr; int pollagain = 0; u_int32_t seq = 0; int rg_err_count = 0; int ret; struct pkt_bgp_primitives *pbgp, empty_pbgp; struct pkt_nat_primitives *pnat, empty_pnat; struct pkt_mpls_primitives *pmpls, empty_pmpls; char *pcust, empty_pcust[] = ""; struct pkt_vlen_hdr_primitives *pvlen, empty_pvlen; struct networks_file_data nfd; struct timeval select_timeout; struct primitives_ptrs prim_ptrs; fd_set read_descs, bkp_read_descs; /* select() stuff */ int select_fd, lock = FALSE; int cLen, num, sd, sd2; char *dataptr; memcpy(&config, cfgptr, sizeof(struct configuration)); memcpy(&extras, &((struct channels_list_entry *)ptr)->extras, sizeof(struct extra_primitives)); recollect_pipe_memory(ptr); pm_setproctitle("%s [%s]", "IMT Plugin", config.name); if (config.pidfile) write_pid_file_plugin(config.pidfile, config.type, config.name); if (config.logfile) { fclose(config.logfile_fd); config.logfile_fd = open_logfile(config.logfile, "a"); } if (extras.off_pkt_vlen_hdr_primitives) { Log(LOG_ERR, "ERROR ( %s/%s ): variable-length primitives, ie. label, are not supported in IMT plugin. Exiting ..\n", config.name, config.type); exit_plugin(1); } reload_map = FALSE; status->wakeup = TRUE; /* a bunch of default definitions and post-checks */ pipebuf = (unsigned char *) malloc(config.buffer_size); if (!pipebuf) { Log(LOG_ERR, "ERROR ( %s/%s ): malloc() failed (pipebuf). Exiting ..\n", config.name, config.type); exit_plugin(1); } setnonblocking(pipe_fd); memset(pipebuf, 0, config.buffer_size); no_more_space = FALSE; if (config.what_to_count & (COUNT_SUM_HOST|COUNT_SUM_NET)) insert_func = sum_host_insert; else if (config.what_to_count & COUNT_SUM_PORT) insert_func = sum_port_insert; else if (config.what_to_count & COUNT_SUM_AS) insert_func = sum_as_insert; #if defined (HAVE_L2) else if (config.what_to_count & COUNT_SUM_MAC) insert_func = sum_mac_insert; #endif else insert_func = insert_accounting_structure; memset(&nt, 0, sizeof(nt)); memset(&nc, 0, sizeof(nc)); memset(&pt, 0, sizeof(pt)); load_networks(config.networks_file, &nt, &nc); set_net_funcs(&nt); if (config.ports_file) load_ports(config.ports_file, &pt); if (config.pkt_len_distrib_bins_str) load_pkt_len_distrib_bins(); else { if (config.what_to_count_2 & COUNT_PKT_LEN_DISTRIB) { Log(LOG_ERR, "ERROR ( %s/%s ): 'aggregate' contains pkt_len_distrib but no 'pkt_len_distrib_bins' defined. Exiting.\n", config.name, config.type); exit_plugin(1); } } if ((!config.num_memory_pools) && (!have_num_memory_pools)) config.num_memory_pools = NUM_MEMORY_POOLS; if (!config.memory_pool_size) config.memory_pool_size = MEMORY_POOL_SIZE; else { if (config.memory_pool_size < sizeof(struct acc)) { Log(LOG_WARNING, "WARN ( %s/%s ): enforcing memory pool's minimum size, %d bytes.\n", config.name, config.type, sizeof(struct acc)); config.memory_pool_size = MEMORY_POOL_SIZE; } } if (!config.imt_plugin_path) config.imt_plugin_path = path; if (!config.buckets) config.buckets = MAX_HOSTS; init_memory_pool_table(config); if (mpd == NULL) { Log(LOG_ERR, "ERROR ( %s/%s ): unable to allocate memory pools table\n", config.name, config.type); exit_plugin(1); } current_pool = request_memory_pool(config.buckets*sizeof(struct acc)); if (current_pool == NULL) { Log(LOG_ERR, "ERROR ( %s/%s ): unable to allocate first memory pool, try with larger value.\n", config.name, config.type); exit_plugin(1); } a = current_pool->base_ptr; lru_elem_ptr = malloc(config.buckets*sizeof(struct acc *)); if (lru_elem_ptr == NULL) { Log(LOG_ERR, "ERROR ( %s/%s ): unable to allocate LRU element pointers.\n", config.name, config.type); exit_plugin(1); } else memset(lru_elem_ptr, 0, config.buckets*sizeof(struct acc *)); current_pool = request_memory_pool(config.memory_pool_size); if (current_pool == NULL) { Log(LOG_ERR, "ERROR ( %s/%s ): unable to allocate more memory pools, try with larger value.\n", config.name, config.type); exit_plugin(1); } signal(SIGHUP, reload); /* handles reopening of syslog channel */ signal(SIGINT, exit_now); /* exit lane */ signal(SIGUSR1, SIG_IGN); signal(SIGUSR2, reload_maps); signal(SIGPIPE, SIG_IGN); signal(SIGCHLD, SIG_IGN); memset(&empty_pbgp, 0, sizeof(empty_pbgp)); memset(&empty_pnat, 0, sizeof(empty_pnat)); memset(&empty_pmpls, 0, sizeof(empty_pmpls)); memset(&empty_pvlen, 0, sizeof(empty_pvlen)); /* building a server for interrogations by clients */ sd = build_query_server(config.imt_plugin_path); cLen = sizeof(cAddr); /* preparing for synchronous I/O multiplexing */ select_fd = 0; FD_ZERO(&read_descs); FD_SET(sd, &read_descs); if (sd > select_fd) select_fd = sd; FD_SET(pipe_fd, &read_descs); if (pipe_fd > select_fd) select_fd = pipe_fd; select_fd++; memcpy(&bkp_read_descs, &read_descs, sizeof(read_descs)); qh = (struct query_header *) srvbuf; /* plugin main loop */ for(;;) { select_again: select_timeout.tv_sec = DEFAULT_IMT_PLUGIN_SELECT_TIMEOUT; select_timeout.tv_usec = 0; memcpy(&read_descs, &bkp_read_descs, sizeof(bkp_read_descs)); num = select(select_fd, &read_descs, NULL, NULL, &select_timeout); if (num <= 0) { if (getppid() == 1) { Log(LOG_ERR, "ERROR ( %s/%s ): Core process *seems* gone. Exiting.\n", config.name, config.type); exit_plugin(1); } goto select_again; } gettimeofday(&cycle_stamp, NULL); /* doing server tasks */ if (FD_ISSET(sd, &read_descs)) { struct pollfd pfd; int ret; sd2 = accept(sd, &cAddr, &cLen); setblocking(sd2); srvbufptr = srvbuf; sz = maxqsize; pfd.fd = sd2; pfd.events = POLLIN; recv_again: ret = poll(&pfd, 1, 1000); if (ret == 0) { Log(LOG_WARNING, "WARN ( %s/%s ): Timed out while processing fragmented query.\n", config.name, config.type); close(sd2); goto select_again; } else { num = recv(sd2, srvbufptr, sz, 0); if (srvbufptr[num-1] != '\x4') { srvbufptr += num; sz -= num; goto recv_again; /* fragmented query */ } } num = num+(maxqsize-sz); if (qh->num > MAX_QUERIES) { Log(LOG_DEBUG, "DEBUG ( %s/%s ): request discarded. Too much queries.\n", config.name, config.type); close(sd2); continue; } request = qh->type; if (request & WANT_RESET) request ^= WANT_RESET; if (request & WANT_LOCK_OP) { lock = TRUE; request ^= WANT_LOCK_OP; } /* - if explicitely required, we do not fork: query obtains exclusive control - lock - over the memory table; - operations that may cause inconsistencies (full erasure, counter reset for individual entries, etc.) are entitled of an exclusive lock. - if query is matter of just a single short-lived walk through the table, we avoid fork(): the plugin will serve the request; - in all other cases, we fork; the newly created child will serve queries asyncronously. */ if (request & WANT_ERASE) { request ^= WANT_ERASE; if (request) { if (num > 0) process_query_data(sd2, srvbuf, num, &extras, datasize, FALSE); else Log(LOG_DEBUG, "DEBUG ( %s/%s ): %d incoming bytes. Errno: %d\n", config.name, config.type, num, errno); } Log(LOG_DEBUG, "DEBUG ( %s/%s ): Closing connection with client ...\n", config.name, config.type); go_to_clear = TRUE; } else if (((request == WANT_COUNTER) || (request == WANT_MATCH)) && (qh->num == 1) && (qh->what_to_count == config.what_to_count)) { if (num > 0) process_query_data(sd2, srvbuf, num, &extras, datasize, FALSE); else Log(LOG_DEBUG, "DEBUG ( %s/%s ): %d incoming bytes. ERRNO: %d\n", config.name, config.type, num, errno); Log(LOG_DEBUG, "DEBUG ( %s/%s ): Closing connection with client ...\n", config.name, config.type); } else if (request == WANT_CLASS_TABLE) { if (num > 0) process_query_data(sd2, srvbuf, num, &extras, datasize, FALSE); else Log(LOG_DEBUG, "DEBUG ( %s/%s ): %d incoming bytes. ERRNO: %d\n", config.name, config.type, num, errno); Log(LOG_DEBUG, "DEBUG ( %s/%s ): Closing connection with client ...\n", config.name, config.type); } else if (request == WANT_PKT_LEN_DISTRIB_TABLE) { if (num > 0) process_query_data(sd2, srvbuf, num, &extras, datasize, FALSE); else Log(LOG_DEBUG, "DEBUG ( %s/%s ): %d incoming bytes. ERRNO: %d\n", config.name, config.type, num, errno); Log(LOG_DEBUG, "DEBUG ( %s/%s ): Closing connection with client ...\n", config.name, config.type); } else { if (lock) { if (num > 0) process_query_data(sd2, srvbuf, num, &extras, datasize, FALSE); else Log(LOG_DEBUG, "DEBUG ( %s/%s ): %d incoming bytes. Errno: %d\n", config.name, config.type, num, errno); Log(LOG_DEBUG, "DEBUG ( %s/%s ): Closing connection with client ...\n", config.name, config.type); } else { switch (fork()) { case -1: /* Something went wrong */ Log(LOG_WARNING, "WARN ( %s/%s ): Unable to serve client query: %s\n", config.name, config.type, strerror(errno)); break; case 0: /* Child */ close(sd); pm_setproctitle("%s [%s]", "IMT Plugin -- serving client", config.name); if (num > 0) process_query_data(sd2, srvbuf, num, &extras, datasize, TRUE); else Log(LOG_DEBUG, "DEBUG ( %s/%s ): %d incoming bytes. Errno: %d\n", config.name, config.type, num, errno); Log(LOG_DEBUG, "DEBUG ( %s/%s ): Closing connection with client ...\n", config.name, config.type); close(sd2); exit(0); default: /* Parent */ break; } } } close(sd2); } /* clearing stats if requested */ if (go_to_clear) { /* When using extended BGP features we need to free() up memory allocations before erasing */ /* XXX: given the current use of empty_* vars we have always to free_extra_allocs() in order to prevent memory leaks */ /* if (extras.off_pkt_bgp_primitives || extras.off_pkt_nat_primitives || extras.off_pkt_mpls_primitives || extras.off_custom_primitives) */ free_extra_allocs(); clear_memory_pool_table(); current_pool = request_memory_pool(config.buckets*sizeof(struct acc)); if (current_pool == NULL) { Log(LOG_ERR, "ERROR ( %s/%s ): Cannot allocate my first memory pool, try with larger value.\n", config.name, config.type); exit_plugin(1); } a = current_pool->base_ptr; current_pool = request_memory_pool(config.memory_pool_size); if (current_pool == NULL) { Log(LOG_ERR, "ERROR ( %s/%s ): Cannot allocate more memory pools, try with larger value.\n", config.name, config.type); exit_plugin(1); } go_to_clear = FALSE; no_more_space = FALSE; memcpy(&table_reset_stamp, &cycle_stamp, sizeof(struct timeval)); } if (FD_ISSET(pipe_fd, &read_descs)) { if (!pollagain) { seq++; seq %= MAX_SEQNUM; } pollagain = FALSE; if ((num = read(pipe_fd, &rgptr, sizeof(rgptr))) == 0) exit_plugin(1); /* we exit silently; something happened at the write end */ if (num < 0) { pollagain = TRUE; goto select_again; } memcpy(pipebuf, rgptr, config.buffer_size); if (((struct ch_buf_hdr *)pipebuf)->seq != seq) { rg_err_count++; if (config.debug || (rg_err_count > MAX_RG_COUNT_ERR)) { Log(LOG_ERR, "ERROR ( %s/%s ): We are missing data.\n", config.name, config.type); Log(LOG_ERR, "If you see this message once in a while, discard it. Otherwise some solutions follow:\n"); Log(LOG_ERR, "- increase shared memory size, 'plugin_pipe_size'; now: '%d'.\n", config.pipe_size); Log(LOG_ERR, "- increase buffer size, 'plugin_buffer_size'; now: '%d'.\n", config.buffer_size); Log(LOG_ERR, "- increase system maximum socket size.\n\n"); seq = ((struct ch_buf_hdr *)pipebuf)->seq; } } if (num > 0) { data = (struct pkt_data *) (pipebuf+sizeof(struct ch_buf_hdr)); while (((struct ch_buf_hdr *)pipebuf)->num > 0) { // XXX: to be optimized: remove empty_* vars if (extras.off_pkt_bgp_primitives) pbgp = (struct pkt_bgp_primitives *) ((u_char *)data + extras.off_pkt_bgp_primitives); else pbgp = &empty_pbgp; if (extras.off_pkt_nat_primitives) pnat = (struct pkt_nat_primitives *) ((u_char *)data + extras.off_pkt_nat_primitives); else pnat = &empty_pnat; if (extras.off_pkt_mpls_primitives) pmpls = (struct pkt_mpls_primitives *) ((u_char *)data + extras.off_pkt_mpls_primitives); else pmpls = &empty_pmpls; if (extras.off_custom_primitives) pcust = ((u_char *)data + extras.off_custom_primitives); else pcust = empty_pcust; if (extras.off_pkt_vlen_hdr_primitives) pvlen = (struct pkt_vlen_hdr_primitives *) ((u_char *)data + extras.off_pkt_vlen_hdr_primitives); else pvlen = &empty_pvlen; for (num = 0; net_funcs[num]; num++) (*net_funcs[num])(&nt, &nc, &data->primitives, pbgp, &nfd); if (config.ports_file) { if (!pt.table[data->primitives.src_port]) data->primitives.src_port = 0; if (!pt.table[data->primitives.dst_port]) data->primitives.dst_port = 0; } if (config.pkt_len_distrib_bins_str && config.what_to_count_2 & COUNT_PKT_LEN_DISTRIB) evaluate_pkt_len_distrib(data); prim_ptrs.data = data; prim_ptrs.pbgp = pbgp; prim_ptrs.pnat = pnat; prim_ptrs.pmpls = pmpls; prim_ptrs.pcust = pcust; prim_ptrs.pvlen = pvlen; (*insert_func)(&prim_ptrs); ((struct ch_buf_hdr *)pipebuf)->num--; if (((struct ch_buf_hdr *)pipebuf)->num) { dataptr = (unsigned char *) data; dataptr += datasize; data = (struct pkt_data *) dataptr; } } } } if (reload_map) { load_networks(config.networks_file, &nt, &nc); load_ports(config.ports_file, &pt); reload_map = FALSE; } } }
int addr_mksocket(const char *host, const char *service, int socktype, int aflags, conbind_t func, struct sockaddr *sockaddr, size_t *addrlen, int64_t softto_us, int64_t hardto_us) { D("invoked: host='%s', serv='%s', scktype: %d, aflags: %d, func: %s, sto=%lu, hto=%lu", host, service, socktype, aflags, !func ? "(none)" : func == connect ? "connect" : func == bind ? "bind" : "(unkonwn)", softto_us, hardto_us); struct addrinfo *ai_list = NULL; struct addrinfo hints; int64_t hardtsend = hardto_us ? tstamp_us() + hardto_us : 0; memset(&hints, 0, sizeof hints); hints.ai_family = AF_UNSPEC; hints.ai_socktype = socktype; hints.ai_protocol = 0; hints.ai_flags = aflags; if (isdigitstr(service)) hints.ai_flags |= AI_NUMERICSERV; D("calling getaddrinfo on '%s:%s'", host, service); int r = getaddrinfo(host, service, &hints, &ai_list); if (r != 0) { W("getaddrinfo() failed: %s", gai_strerror(r)); return -1; } if (!ai_list) { W("getaddrinfo() result address list empty"); return -1; } bool success = false; int sck = -1; D("iterating over result list..."); for (struct addrinfo *ai = ai_list; ai; ai = ai->ai_next) { sck = -1; if (hardtsend && hardtsend - tstamp_us() <= 0) { W("hard timeout"); return 0; } D("next result, creating socket (fam=%d, styp=%d, prot=%d)", ai->ai_family, ai->ai_socktype, ai->ai_protocol); sck = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol); if (sck < 0) { WE("cannot create socket"); continue; } char peeraddr[64] = "(non-INET/INET6)"; unsigned short peerport = 0; if (ai->ai_family == AF_INET) { struct sockaddr_in *sin = (struct sockaddr_in*)ai->ai_addr; inet_ntop(AF_INET, &sin->sin_addr, peeraddr, sizeof peeraddr); peerport = ntohs(sin->sin_port); } else if (ai->ai_family == AF_INET6) { struct sockaddr_in6 *sin = (struct sockaddr_in6*)ai->ai_addr; inet_ntop(AF_INET6, &sin->sin6_addr, peeraddr, sizeof peeraddr); peerport = ntohs(sin->sin6_port); } char portstr[7]; snprintf(portstr, sizeof portstr, ":%hu", peerport); strNcat(peeraddr, portstr, sizeof peeraddr); int opt = 1; socklen_t optlen = sizeof opt; D("peer addr is '%s'", peeraddr); if (sockaddr) *sockaddr = *(ai->ai_addr); if (addrlen) *addrlen = ai->ai_addrlen; if (func) { D("going non-blocking"); if (setblocking(sck, false) == -1) { WE("failed to enable nonblocking mode"); close(sck); continue; } D("set to nonblocking mode, calling the backend function..."); errno = 0; bool doselect = false; int r = func(sck, ai->ai_addr, ai->ai_addrlen); if (r == -1 && (errno != EINPROGRESS)) { WE("backend failed"); close(sck); continue; } else if (r == -1) doselect = true; int64_t trem = 0; D("backend returned with %d", r); if (doselect) { if (hardtsend) { trem = hardtsend - tstamp_us(); if (trem <= 0) { D("hard timeout detected"); close(sck); continue; } } int64_t softtsend = softto_us ? tstamp_us() + softto_us : 0; if (softtsend) { int64_t trem_tmp = softtsend - tstamp_us(); if (trem_tmp <= 0) { W("soft timeout"); close(sck); continue; } if (trem_tmp < trem) trem = trem_tmp; } D("calling io_select1w (timeout: %lld us)", trem); r = io_select1w(sck, trem, true); if (r < 0) { WE("select() failed"); close(sck); continue; } else if (!r) { W("select() timeout"); close(sck); continue; } else D("selected!"); D("calling getsockopt to query error state"); if (getsockopt(sck, SOL_SOCKET, SO_ERROR, &opt, &optlen) != 0) { W("getsockopt failed"); close(sck); continue; } if (opt == 0) { I("socket in good shape! ('%s')", peeraddr); if (setblocking(sck, true) == -1) { WE("failed to disable nonblocking mode"); close(sck); continue; } success = true; break; } else { char errstr[256]; strerror_r(opt, errstr, sizeof errstr); W("backend function failed (%d: %s)", opt, errstr); close(sck); continue; } } else { I("There we go... ('%s')", peeraddr); if (setblocking(sck, true) == -1) { WE("failed to disable nonblocking mode"); close(sck); continue; } success = true; break; } } else { success = true; break; } } D("after loop; alling freeaddrinfo then returning %d", sck); freeaddrinfo(ai_list); return success ? sck : -1; }
enum cmd_retval cmd_pipe_pane_exec(struct cmd *self, struct cmd_q *cmdq) { struct args *args = self->args; struct client *c = cmdq->state.c; struct window_pane *wp = cmdq->state.tflag.wp; struct session *s = cmdq->state.tflag.s; struct winlink *wl = cmdq->state.tflag.wl; char *cmd; int old_fd, pipe_fd[2], null_fd; struct format_tree *ft; /* Destroy the old pipe. */ old_fd = wp->pipe_fd; if (wp->pipe_fd != -1) { bufferevent_free(wp->pipe_event); close(wp->pipe_fd); wp->pipe_fd = -1; } /* If no pipe command, that is enough. */ if (args->argc == 0 || *args->argv[0] == '\0') return (CMD_RETURN_NORMAL); /* * With -o, only open the new pipe if there was no previous one. This * allows a pipe to be toggled with a single key, for example: * * bind ^p pipep -o 'cat >>~/output' */ if (args_has(self->args, 'o') && old_fd != -1) return (CMD_RETURN_NORMAL); /* Open the new pipe. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { cmdq_error(cmdq, "socketpair error: %s", strerror(errno)); return (CMD_RETURN_ERROR); } /* Expand the command. */ ft = format_create(cmdq, 0); format_defaults(ft, c, s, wl, wp); cmd = format_expand_time(ft, args->argv[0], time(NULL)); format_free(ft); /* Fork the child. */ switch (fork()) { case -1: cmdq_error(cmdq, "fork error: %s", strerror(errno)); free(cmd); return (CMD_RETURN_ERROR); case 0: /* Child process. */ close(pipe_fd[0]); clear_signals(1); if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); if (pipe_fd[1] != STDIN_FILENO) close(pipe_fd[1]); null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); if (dup2(null_fd, STDOUT_FILENO) == -1) _exit(1); if (dup2(null_fd, STDERR_FILENO) == -1) _exit(1); if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) close(null_fd); closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); _exit(1); default: /* Parent process. */ close(pipe_fd[1]); wp->pipe_fd = pipe_fd[0]; wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); wp->pipe_event = bufferevent_new(wp->pipe_fd, NULL, NULL, cmd_pipe_pane_error_callback, wp); bufferevent_enable(wp->pipe_event, EV_WRITE); setblocking(wp->pipe_fd, 0); free(cmd); return (CMD_RETURN_NORMAL); } }
int cmd_pipe_pane_exec(struct cmd *self, struct cmd_ctx *ctx) { struct args *args = self->args; struct client *c; struct window_pane *wp; char *command; int old_fd, pipe_fd[2], null_fd; if ((c = cmd_find_client(ctx, NULL)) == NULL) return (-1); if (cmd_find_pane(ctx, args_get(args, 't'), NULL, &wp) == NULL) return (-1); /* Destroy the old pipe. */ old_fd = wp->pipe_fd; if (wp->pipe_fd != -1) { bufferevent_free(wp->pipe_event); close(wp->pipe_fd); wp->pipe_fd = -1; } /* If no pipe command, that is enough. */ if (args->argc == 0 || *args->argv[0] == '\0') return (0); /* * With -o, only open the new pipe if there was no previous one. This * allows a pipe to be toggled with a single key, for example: * * bind ^p pipep -o 'cat >>~/output' */ if (args_has(self->args, 'o') && old_fd != -1) return (0); /* Open the new pipe. */ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pipe_fd) != 0) { ctx->error(ctx, "socketpair error: %s", strerror(errno)); return (-1); } /* Fork the child. */ switch (fork()) { case -1: ctx->error(ctx, "fork error: %s", strerror(errno)); return (-1); case 0: /* Child process. */ close(pipe_fd[0]); clear_signals(1); if (dup2(pipe_fd[1], STDIN_FILENO) == -1) _exit(1); if (pipe_fd[1] != STDIN_FILENO) close(pipe_fd[1]); null_fd = open(_PATH_DEVNULL, O_WRONLY, 0); if (dup2(null_fd, STDOUT_FILENO) == -1) _exit(1); if (dup2(null_fd, STDERR_FILENO) == -1) _exit(1); if (null_fd != STDOUT_FILENO && null_fd != STDERR_FILENO) close(null_fd); closefrom(STDERR_FILENO + 1); command = status_replace( c, NULL, NULL, NULL, args->argv[0], time(NULL), 0); execl(_PATH_BSHELL, "sh", "-c", command, (char *) NULL); _exit(1); default: /* Parent process. */ close(pipe_fd[1]); wp->pipe_fd = pipe_fd[0]; wp->pipe_off = EVBUFFER_LENGTH(wp->event->input); wp->pipe_event = bufferevent_new(wp->pipe_fd, NULL, NULL, cmd_pipe_pane_error_callback, wp); bufferevent_enable(wp->pipe_event, EV_WRITE); setblocking(wp->pipe_fd, 0); return (0); } }
int main(int argc, char **argv) { char responseBuf[MAXLEN]; int i; int retval; ser_t serport; char EDFPacket[MAXHEADERLEN]; int EDFLen = MAXHEADERLEN; /// buffer for reading from serial port char smallbuf[PROTOWINDOW]; char *hostname = NULL; char *deviceName = NULL; /// DEFAULTHOST; unsigned short portno = 0; /// DEFAULTPORT; struct timeval when; rprintf("ModEEG Driver v. %s-%s\n", VERSION, OSTYPESTR); rinitNetworking(); /// process command line inputs for (i = 1; argv[i]; ++i) { if (argv[i][0] == '-' && argv[i][1] == 'h') { printHelp(); exit(0); } if (argv[i][0] == '-' && argv[i][1] == 'd') { if (argv[i+1] == NULL) { rprintf("Bad devicename option: %s\nExpected device name as next argument.\n", argv[i]); exit(1); } deviceName = argv[i+1]; i += 1; continue; } if (hostname == NULL) { hostname = argv[i]; continue; } if (portno == 0) { portno = atoi(argv[i]); continue; } } if (deviceName == NULL) deviceName = DEFAULTDEVICE; if (portno == 0) portno = DEFAULTPORT; if (hostname == NULL) hostname = DEFAULTHOST; makeREDFConfig(¤t, &modEEGCfg); writeEDFString(¤t, EDFPacket, &EDFLen); sock_fd = rsocket(); if (sock_fd < 0) { perror("socket"); rexit(1); } setblocking(sock_fd); rprintf("Attempting to connect to nsd at %s:%d\n", hostname, portno); retval = rconnectName(sock_fd, hostname, portno); if (retval != 0) { rprintf("connect error\n"); rexit(1); } rprintf("Socket connected.\n"); fflush(stdout); serport = openSerialPort(deviceName,57600); rprintf("Serial port %s opened.\n", deviceName); writeString(sock_fd, "eeg\n", &ob); mGetOK(sock_fd, &ib); writeString(sock_fd, "setheader ", &ob); writeBytes(sock_fd, EDFPacket, EDFLen, &ob); writeString(sock_fd, "\n", &ob); mGetOK(sock_fd, &ib); updateMaxFd(sock_fd); #ifndef __MINGW32__ updateMaxFd(serport); #endif when.tv_usec = (1000000L / modEEGCfg.chan[0].sampleCount); rprintf("Polling at %d Hertz or %d usec\n", modEEGCfg.chan[0].sampleCount, when.tv_usec); for (;;) { int i, readSerBytes; int retval; fd_set toread; when.tv_sec = 0; when.tv_usec = (1000000L / modEEGCfg.chan[0].sampleCount); FD_ZERO(&toread); FD_SET(sock_fd, &toread); #ifndef __MINGW32__ FD_SET(serport, &toread); #endif retval = rselect_timed(max_fd, &toread, NULL, NULL, &when); readSerBytes = readSerial(serport, smallbuf, PROTOWINDOW); if (readSerBytes < 0) { rprintf("Serial error.\n"); } if (readSerBytes > 0) { for (i = 0; i < readSerBytes; ++i) eatCharacter(smallbuf[i]); } if (FD_ISSET(sock_fd, &toread)) { my_read(sock_fd, responseBuf, MAXLEN, &ib); } if (isEOF(sock_fd, &ib)) { rprintf("Server died, exitting.\n"); exit(0); } } return 0; }
/* Start a job running, if it isn't already. */ struct job * job_run(const char *cmd, struct session *s, const char *cwd, job_update_cb updatecb, job_complete_cb completecb, job_free_cb freecb, void *data) { struct job *job; struct environ *env; pid_t pid; int nullfd, out[2]; const char *home; if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, out) != 0) return (NULL); /* * Do not set TERM during .tmux.conf, it is nice to be able to use * if-shell to decide on default-terminal based on outside TERM. */ env = environ_for_session(s, !cfg_finished); switch (pid = fork()) { case -1: environ_free(env); close(out[0]); close(out[1]); return (NULL); case 0: /* child */ clear_signals(1); if (cwd == NULL || chdir(cwd) != 0) { if ((home = find_home()) == NULL || chdir(home) != 0) chdir("/"); } environ_push(env); environ_free(env); if (dup2(out[1], STDIN_FILENO) == -1) fatal("dup2 failed"); if (dup2(out[1], STDOUT_FILENO) == -1) fatal("dup2 failed"); if (out[1] != STDIN_FILENO && out[1] != STDOUT_FILENO) close(out[1]); close(out[0]); nullfd = open(_PATH_DEVNULL, O_RDWR, 0); if (nullfd < 0) fatal("open failed"); if (dup2(nullfd, STDERR_FILENO) == -1) fatal("dup2 failed"); if (nullfd != STDERR_FILENO) close(nullfd); closefrom(STDERR_FILENO + 1); execl(_PATH_BSHELL, "sh", "-c", cmd, (char *) NULL); fatal("execl failed"); } /* parent */ environ_free(env); close(out[1]); job = xmalloc(sizeof *job); job->state = JOB_RUNNING; job->cmd = xstrdup(cmd); job->pid = pid; job->status = 0; LIST_INSERT_HEAD(&all_jobs, job, entry); job->updatecb = updatecb; job->completecb = completecb; job->freecb = freecb; job->data = data; job->fd = out[0]; setblocking(job->fd, 0); job->event = bufferevent_new(job->fd, job_read_callback, job_write_callback, job_error_callback, job); bufferevent_enable(job->event, EV_READ|EV_WRITE); log_debug("run job %p: %s, pid %ld", job, job->cmd, (long) job->pid); return (job); }