/* vim:set sw=4 sts=4 et: */ /** * FILE: proc.c * AUTHOR: Yukihiro Nakadaira (original) * Nico Raffo (modified) */ #define _XOPEN_SOURCE 600 #include #include #include #include #include #include #include #include #include #include #if !defined __APPLE__ # include # include #endif #include #include /* for poll() */ #if defined __APPLE__ # include "fakepoll.h" #else # include #endif /* for forkpty() / login_tty() */ #if (defined __linux__ || defined __CYGWIN__) && !defined __ANDROID__ # include # include #elif defined __APPLE__ || defined __NetBSD__ || defined __OpenBSD__ # include #elif defined __sun__ || defined __ANDROID__ # include "ptytty.h" #else # include # include #endif /* for ioctl() */ #ifdef __APPLE__ # include #endif /* for tc* and ioctl */ #include #include #ifndef TIOCGWINSZ # include /* 4.3+BSD requires this too */ #endif /* for waitpid() */ #include #include #if defined __NetBSD__ # define WIFCONTINUED(x) (_WSTATUS(x) == _WSTOPPED && WSTOPSIG(x) == 0x13) #elif defined __ANDROID__ # define WIFCONTINUED(x) (WIFSTOPPED(x) && WSTOPSIG(x) == 0x13) #endif /* for socket */ #if defined __FreeBSD__ # define __BSD_VISIBLE 1 # include #endif #include #include #include #include /* for ctermid */ #if defined __ANDROID__ # define ctermid(x) "/dev/tty" #endif #include "vimstack.c" const int debug = 0; /* API */ const char *vp_dlopen(char *args); /* [handle] (path) */ const char *vp_dlclose(char *args); /* [] (handle) */ const char *vp_dlversion(char *args); /* [version] () */ const char *vp_file_open(char *args); /* [fd] (path, flags, mode) */ const char *vp_file_close(char *args); /* [] (fd) */ const char *vp_file_read(char *args); /* [eof, hd] (fd, cnt, timeout) */ const char *vp_file_write(char *args); /* [nleft] (fd, timeout, hd) */ const char *vp_pipe_open(char *args); /* [pid, [fd] * npipe] (npipe, hstdin, hstdout, hstderr, argc, [argv]) */ const char *vp_pipe_close(char *args); /* [] (fd) */ const char *vp_pipe_read(char *args); /* [eof, hd] (fd, cnt, timeout) */ const char *vp_pipe_write(char *args); /* [nleft] (fd, timeout, hd) */ const char *vp_pty_open(char *args); /* [pid, stdin, stdout, stderr] (npipe, width, height,hstdin, hstdout, hstderr, argc, [argv]) */ const char *vp_pty_close(char *args); /* [] (fd) */ const char *vp_pty_read(char *args); /* [eof, hd] (fd, cnt, timeout) */ const char *vp_pty_write(char *args); /* [nleft] (fd, timeout, hd) */ const char *vp_pty_get_winsize(char *args); /* [width, height] (fd) */ const char *vp_pty_set_winsize(char *args); /* [] (fd, width, height) */ const char *vp_kill(char *args); /* [] (pid, sig) */ const char *vp_waitpid(char *args); /* [cond, status] (pid) */ const char *vp_socket_open(char *args); /* [socket] (host, port) */ const char *vp_socket_close(char *args);/* [] (socket) */ const char *vp_socket_read(char *args); /* [eof, hd] (socket, cnt, timeout) */ const char *vp_socket_write(char *args);/* [nleft] (socket, hd, timeout) */ const char *vp_host_exists(char *args); /* [int] (host) */ const char *vp_decode(char *args); /* [decoded_str] (encode_str) */ const char *vp_get_signals(char *args); /* [signals] () */ /* --- */ #define VP_BUFSIZE (65536) #define VP_READ_BUFSIZE (VP_BUFSIZE - (VP_HEADER_SIZE + 1) * 2 - 1) static vp_stack_t _result = VP_STACK_NULL; const char * vp_dlopen(char *args) { vp_stack_t stack; char *path; void *handle; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &path)); VP_RETURN_IF_FAIL(vp_stack_reserve(&_result, VP_BUFSIZE)); handle = dlopen(path, RTLD_LAZY); if (handle == NULL) return dlerror(); vp_stack_push_num(&_result, "%p", handle); return vp_stack_return(&_result); } const char * vp_dlclose(char *args) { vp_stack_t stack; void *handle; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%p", &handle)); /* On FreeBSD6, to call dlclose() twice with same pointer causes SIGSEGV */ if (dlclose(handle) == -1) return dlerror(); vp_stack_free(&_result); return NULL; } const char * vp_dlversion(char *args) { vp_stack_push_num(&_result, "%2d%02d", 9, 2); return vp_stack_return(&_result); } static int str_to_oflag(const char *flags) { int oflag = 0; if (strchr("rwa", flags[0])) { if (strchr(flags, '+')) { oflag = O_RDWR; } else { oflag = flags[0] == 'r' ? O_RDONLY : O_WRONLY; } if (flags[0] == 'w' || flags[0] == 'a') { oflag |= O_CREAT | (flags[0] == 'w' ? O_TRUNC : O_APPEND); } #define VP_CHR_TO_OFLAG(_c, _f) do { \ if (strchr(flags, (_c))) { oflag |= (_f); } \ } while (0) #ifdef O_EXCL VP_CHR_TO_OFLAG('x', O_EXCL); #endif #ifdef O_CLOEXEC VP_CHR_TO_OFLAG('e', O_CLOEXEC); #endif #ifdef O_BINARY VP_CHR_TO_OFLAG('b', O_BINARY); #endif #ifdef O_TEXT VP_CHR_TO_OFLAG('t', O_TEXT); #endif #ifdef O_SEQUENTIAL VP_CHR_TO_OFLAG('S', O_SEQUENTIAL); #endif #ifdef O_RANDOM VP_CHR_TO_OFLAG('R', O_RANDOM); #endif #undef VP_CHR_TO_OFLAG } else { if (strstr(flags, "O_RDONLY")) { oflag = O_RDONLY; } else if (strstr(flags, "O_WRONLY")) { oflag = O_WRONLY; } else if (strstr(flags, "O_RDWR")) { oflag = O_RDWR; } else { return -1; } #define VP_STR_TO_OFLAG(_f) do { \ if (strstr(flags, #_f)) { oflag |= (_f); } \ } while (0) VP_STR_TO_OFLAG(O_APPEND); VP_STR_TO_OFLAG(O_CREAT); VP_STR_TO_OFLAG(O_TRUNC); #ifdef O_EXCL VP_STR_TO_OFLAG(O_EXCL); #endif #ifdef O_NONBLOCK VP_STR_TO_OFLAG(O_NONBLOCK); #endif #ifdef O_SHLOCK VP_STR_TO_OFLAG(O_SHLOCK); #endif #ifdef O_EXLOCK VP_STR_TO_OFLAG(O_EXLOCK); #endif #ifdef O_DIRECT VP_STR_TO_OFLAG(O_DIRECT); #endif #ifdef O_FSYNC VP_STR_TO_OFLAG(O_FSYNC); #endif #ifdef O_NOFOLLOW VP_STR_TO_OFLAG(O_NOFOLLOW); #endif #ifdef O_TEMPORARY VP_STR_TO_OFLAG(O_TEMPORARY); #endif #ifdef O_RANDOM VP_STR_TO_OFLAG(O_RANDOM); #endif #ifdef O_SEQUENTIAL VP_STR_TO_OFLAG(O_SEQUENTIAL); #endif #ifdef O_BINARY VP_STR_TO_OFLAG(O_BINARY); #endif #ifdef O_TEXT VP_STR_TO_OFLAG(O_TEXT); #endif #ifdef O_INHERIT VP_STR_TO_OFLAG(O_INHERIT); #endif #ifdef _O_SHORT_LIVED VP_STR_TO_OFLAG(O_SHORT_LIVED); #endif #undef VP_STR_TO_OFLAG } return oflag; } static int fd_set_nonblock(int fd) { #if defined(F_GETFL) && defined(F_SETFL) && defined(O_NONBLOCK) int flag; if ((flag = fcntl(fd, F_GETFL, 0)) == -1) return -1; if (!(flag & O_NONBLOCK)) return fcntl(fd, F_SETFL, flag | O_NONBLOCK); #endif return 0; } #ifdef __linux__ # define VP_SET_NONBLOCK_IF_NEEDED(_fd) (void)fd_set_nonblock(_fd) #else # define VP_SET_NONBLOCK_IF_NEEDED(_fd) do { /* nop */ } while (0) #endif const char * vp_fd_read(char *args, int is_pty_pipe) { #ifdef __linux__ # define VP_POLLIN (POLLIN | POLLHUP) #else # define VP_POLLIN (POLLIN) #endif vp_stack_t stack; int fd; int cnt; int timeout; int n; char *buf; char *eof; unsigned int size = 0; struct pollfd pfd = {0, POLLIN, 0}; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &cnt)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &timeout)); if (cnt < 0 || VP_READ_BUFSIZE < cnt) { cnt = VP_READ_BUFSIZE; } /* initialize buffer */ _result.top = _result.buf; vp_stack_push_num(&_result, "%d", 0); /* set eof to 0 */ eof = _result.top - 1; buf = _result.top; *(buf++) = VP_EOV; buf += VP_HEADER_SIZE; pfd.fd = fd; while (cnt > 0) { n = poll(&pfd, 1, timeout); if (n == -1) { /* eof or error */ *eof = '1'; break; } else if (n == 0) { /* timeout */ break; } if (pfd.revents & VP_POLLIN) { n = read(fd, buf, cnt); if (n == -1) { if (pfd.revents & POLLERR || pfd.revents & POLLNVAL || pfd.revents & POLLWRNORM /* Cygwin(after ver.2.0) fails pty read and returns * POLLIN. */ || (!is_pty_pipe && pfd.revents & POLLIN) ) { return vp_stack_return_error(&_result, "read() error: revents = %d, error = %s", pfd.revents, strerror(errno)); } /* eof */ *eof = '1'; break; } else if (n == 0) { /* eof */ *eof = '1'; break; } /* decrease stack top for concatenate. */ cnt -= n; buf += n; size += n; /* try read more bytes without waiting */ timeout = 0; continue; } else if (pfd.revents & (POLLERR | POLLHUP)) { /* eof or error */ *eof = '1'; break; } else if (pfd.revents & POLLNVAL) { return vp_stack_return_error(&_result, "poll() POLLNVAL: %d", pfd.revents); } /* DO NOT REACH HERE */ return vp_stack_return_error(&_result, "poll() unknown status: %d", pfd.revents); } vp_encode_size(size, _result.top + 1); _result.top = buf; return vp_stack_return(&_result); #undef VP_POLLIN } const char * vp_file_open(char *args) { vp_stack_t stack; char *path; char *flags; int mode; /* used when flags have O_CREAT */ int oflag = 0; int fd; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &path)); VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &flags)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &mode)); oflag = str_to_oflag(flags); if (oflag == -1) return vp_stack_return_error(&_result, "open flag error."); fd = open(path, oflag, mode); if (fd == -1) return vp_stack_return_error(&_result, "open() error: %s", strerror(errno)); vp_stack_push_num(&_result, "%d", fd); return vp_stack_return(&_result); } const char * vp_file_close(char *args) { vp_stack_t stack; int fd; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); if (close(fd) == -1) return vp_stack_return_error(&_result, "close() error: %s", strerror(errno)); return NULL; } const char * vp_file_read(char *args) { return vp_fd_read(args, 0); } const char * vp_file_write(char *args) { vp_stack_t stack; int fd; char *buf; size_t size; int timeout; size_t nleft; int n; struct pollfd pfd = {0, POLLOUT, 0}; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &timeout)); size = vp_decode_size(stack.top); buf = stack.top + VP_HEADER_SIZE; pfd.fd = fd; nleft = 0; while (nleft < size) { n = poll(&pfd, 1, timeout); if (n == -1) { return vp_stack_return_error(&_result, "poll() error: %s", strerror(errno)); } else if (n == 0) { /* timeout */ break; } if (pfd.revents & POLLOUT) { n = write(fd, buf + nleft, size - nleft); if (n == -1) { return vp_stack_return_error(&_result, "write() error: %s", strerror(errno)); } nleft += n; /* try write more bytes without waiting */ timeout = 0; continue; } else if (pfd.revents & (POLLERR | POLLHUP)) { /* eof or error */ break; } else if (pfd.revents & POLLNVAL) { return vp_stack_return_error(&_result, "poll() POLLNVAL: %d", pfd.revents); } /* DO NOT REACH HERE */ return vp_stack_return_error(&_result, "poll() unknown status: %s", pfd.revents); } vp_stack_push_num(&_result, "%zu", nleft); return vp_stack_return(&_result); } static void close_allfd(int fds[3][2]) { int i; for (i = 0; i < 6; ++i) { int fd = fds[i / 2][i % 2]; if (fd > 0) { (void)close(fd); } } } const char * vp_pipe_open(char *args) { #define VP_GOTO_ERROR(_fmt) do { errfmt = (_fmt); goto error; } while(0) vp_stack_t stack; int npipe, hstdin, hstderr, hstdout; int argc; int fd[3][2] = {{0}}; pid_t pid; int dummy; char *errfmt; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &npipe)); if (npipe != 2 && npipe != 3) return vp_stack_return_error(&_result, "npipe range error. wrong pipes."); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdin)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdout)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstderr)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &argc)); if (hstdin > 0) { fd[0][0] = hstdin; fd[0][1] = 0; } else { if (pipe(fd[0]) < 0) { VP_GOTO_ERROR("pipe() error: %s"); } } if (hstdout > 0) { fd[1][1] = hstdout; fd[1][0] = 0; } else { if (pipe(fd[1]) < 0) { VP_GOTO_ERROR("pipe() error: %s"); } } if (hstderr > 0) { fd[2][1] = hstderr; fd[2][0] = 0; } else if (npipe == 3 && hstderr == 0) { if (pipe(fd[2]) < 0) { VP_GOTO_ERROR("pipe() error: %s"); } } pid = fork(); if (pid < 0) { VP_GOTO_ERROR("fork() error: %s"); } else if (pid == 0) { /* child */ char **argv; int i; /* Set process group. */ setpgid(0, 0); if (fd[0][1] > 0) { close(fd[0][1]); } if (fd[1][0] > 0) { close(fd[1][0]); } if (fd[2][0] > 0) { close(fd[2][0]); } if (fd[0][0] > 0) { if (dup2(fd[0][0], STDIN_FILENO) != STDIN_FILENO) { goto child_error; } close(fd[0][0]); } if (fd[1][1] > 0) { if (dup2(fd[1][1], STDOUT_FILENO) != STDOUT_FILENO) { goto child_error; } close(fd[1][1]); } if (fd[2][1] > 0) { if (dup2(fd[2][1], STDERR_FILENO) != STDERR_FILENO) { goto child_error; } close(fd[2][1]); } else if (npipe == 2) { if (dup2(STDOUT_FILENO, STDERR_FILENO) != STDERR_FILENO) { goto child_error; } } { #ifndef TIOCNOTTY setsid(); #else /* Ignore tty. */ char name[L_ctermid]; if (ctermid(name)[0] != '\0') { int tfd; if ((tfd = open(name, O_RDONLY)) != -1) { ioctl(tfd, TIOCNOTTY, NULL); close(tfd); } } #endif } argv = malloc(sizeof(char *) * (argc+1)); if (argv == NULL) { goto child_error; } for (i = 0; i < argc; ++i) { if (vp_stack_pop_str(&stack, &(argv[i]))) { free(argv); goto child_error; } } argv[argc] = NULL; execv(argv[0], argv); /* error */ goto child_error; } else { /* parent */ if (fd[0][0] > 0) { close(fd[0][0]); } if (fd[1][1] > 0) { close(fd[1][1]); } if (fd[2][1] > 0) { close(fd[2][1]); } vp_stack_push_num(&_result, "%d", pid); vp_stack_push_num(&_result, "%d", fd[0][1]); vp_stack_push_num(&_result, "%d", fd[1][0]); if (npipe == 3) { vp_stack_push_num(&_result, "%d", fd[2][0]); } return vp_stack_return(&_result); } /* DO NOT REACH HERE */ return NULL; /* error */ error: close_allfd(fd); return vp_stack_return_error(&_result, errfmt, strerror(errno)); child_error: dummy = write(STDOUT_FILENO, strerror(errno), strlen(strerror(errno))); _exit(EXIT_FAILURE); #undef VP_GOTO_ERROR } const char * vp_pipe_close(char *args) { return vp_file_close(args); } const char * vp_pipe_read(char *args) { return vp_fd_read(args, 1); } const char * vp_pipe_write(char *args) { return vp_file_write(args); } const char * vp_pty_open(char *args) { #define VP_GOTO_ERROR(_fmt) do { errfmt = (_fmt); goto error; } while(0) vp_stack_t stack; int argc; int fd[3][2] = {{0}}; pid_t pid; struct winsize ws = {0, 0, 0, 0}; int dummy; int hstdin, hstderr, hstdout; int fdm; int npipe; char *errfmt; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &npipe)); if (npipe != 2 && npipe != 3) return vp_stack_return_error(&_result, "npipe range error. wrong pipes."); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%hu", &(ws.ws_col))); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%hu", &(ws.ws_row))); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdin)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstdout)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &hstderr)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &argc)); /* Set pipe */ if (hstdin > 0) { fd[0][0] = hstdin; fd[0][1] = 0; } if (hstdout > 1) { fd[1][1] = hstdout; fd[1][0] = 0; } else if (hstdout == 1) { if (pipe(fd[1]) < 0) { VP_GOTO_ERROR("pipe() error: %s"); } } if (hstderr > 1) { fd[2][1] = hstderr; fd[2][0] = 0; } else if (npipe == 3) { if (hstderr == 1){ if (pipe(fd[2]) < 0) { VP_GOTO_ERROR("pipe() error: %s"); } } else if (hstderr == 0) { if (openpty(&fd[2][0], &fd[2][1], NULL, NULL, &ws) < 0) { VP_GOTO_ERROR("openpty() error: %s"); } VP_SET_NONBLOCK_IF_NEEDED(fd[2][0]); } } pid = forkpty(&fdm, NULL, NULL, &ws); if (pid < 0) { VP_GOTO_ERROR("fork() error: %s"); } else if (pid == 0) { /* child */ char **argv; int i; /* Close pipe */ if (fd[1][0] > 0) { close(fd[1][0]); } if (fd[2][0] > 0) { close(fd[2][0]); } if (fd[0][0] > 0) { if (dup2(fd[0][0], STDIN_FILENO) != STDIN_FILENO) { goto child_error; } close(fd[0][0]); } if (fd[1][1] > 0) { if (dup2(fd[1][1], STDOUT_FILENO) != STDOUT_FILENO) { goto child_error; } close(fd[1][1]); } if (fd[2][1] > 0) { if (dup2(fd[2][1], STDERR_FILENO) != STDERR_FILENO) { goto child_error; } close(fd[2][1]); } argv = malloc(sizeof(char *) * (argc+1)); if (argv == NULL) { goto child_error; } for (i = 0; i < argc; ++i) { if (vp_stack_pop_str(&stack, &(argv[i]))) { free(argv); goto child_error; } } argv[argc] = NULL; execv(argv[0], argv); /* error */ goto child_error; } else { /* parent */ if (fd[1][1] > 0) { close(fd[1][1]); } if (fd[2][1] > 0) { close(fd[2][1]); } if (hstdin == 0) { fd[0][1] = fdm; } if (hstdout == 0) { fd[1][0] = hstdin == 0 ? dup(fdm) : fdm; VP_SET_NONBLOCK_IF_NEEDED(fd[1][0]); } vp_stack_push_num(&_result, "%d", pid); vp_stack_push_num(&_result, "%d", fd[0][1]); vp_stack_push_num(&_result, "%d", fd[1][0]); if (npipe == 3) { vp_stack_push_num(&_result, "%d", fd[2][0]); } return vp_stack_return(&_result); } /* DO NOT REACH HERE */ return NULL; /* error */ error: close_allfd(fd); return vp_stack_return_error(&_result, errfmt, strerror(errno)); child_error: dummy = write(STDOUT_FILENO, strerror(errno), strlen(strerror(errno))); _exit(EXIT_FAILURE); #undef VP_GOTO_ERROR } const char * vp_pty_close(char *args) { return vp_file_close(args); } const char * vp_pty_read(char *args) { return vp_fd_read(args, 1); } const char * vp_pty_write(char *args) { return vp_file_write(args); } const char * vp_pty_get_winsize(char *args) { vp_stack_t stack; int fd; struct winsize ws = {0, 0, 0, 0}; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); if (ioctl(fd, TIOCGWINSZ, &ws) < 0) return vp_stack_return_error(&_result, "ioctl() error: %s", strerror(errno)); vp_stack_push_num(&_result, "%hu", ws.ws_col); vp_stack_push_num(&_result, "%hu", ws.ws_row); return vp_stack_return(&_result); } const char * vp_pty_set_winsize(char *args) { vp_stack_t stack; int fd; struct winsize ws = {0, 0, 0, 0}; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &fd)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%hu", &(ws.ws_col))); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%hu", &(ws.ws_row))); if (ioctl(fd, TIOCSWINSZ, &ws) < 0) return vp_stack_return_error(&_result, "ioctl() error: %s", strerror(errno)); return NULL; } const char * vp_kill(char *args) { vp_stack_t stack; pid_t pid, pgid; int sig; int ret; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &pid)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &sig)); ret = kill(pid, sig); if (ret < 0) return vp_stack_return_error(&_result, "kill() error: %s", strerror(errno)); if (sig != 0) { /* Kill by the process group. */ pgid = getpgid(pid); if (pid == pgid) { kill(-pgid, sig); } } vp_stack_push_num(&_result, "%d", ret); return vp_stack_return(&_result); } const char * vp_waitpid(char *args) { vp_stack_t stack; pid_t pid, pgid; pid_t n; int status; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_num(&stack, "%d", &pid)); n = waitpid(pid, &status, WNOHANG | WUNTRACED); if (n == -1) return vp_stack_return_error(&_result, "waitpid() error: %s", strerror(errno)); if (n == 0 || WIFCONTINUED(status)) { vp_stack_push_str(&_result, "run"); vp_stack_push_num(&_result, "%d", 0); } else if (WIFEXITED(status)) { /* Kill by the process group. */ pgid = getpgid(pid); if (pgid > 0) { kill(-pgid, 15); } vp_stack_push_str(&_result, "exit"); vp_stack_push_num(&_result, "%d", WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { vp_stack_push_str(&_result, "signal"); vp_stack_push_num(&_result, "%d", WTERMSIG(status)); } else if (WIFSTOPPED(status)) { vp_stack_push_str(&_result, "stop"); vp_stack_push_num(&_result, "%d", WSTOPSIG(status)); } else { return vp_stack_return_error(&_result, "waitpid() unknown status: status=%d", status); } return vp_stack_return(&_result); } /* * This is based on socket.diff.gz written by Yasuhiro Matsumoto. * see: http://marc.theaimsgroup.com/?l=vim-dev&m=105289857008664&w=2 */ const char * vp_socket_open(char *args) { vp_stack_t stack; char *host; char *port; char *p; int n; unsigned short nport; int sock; struct sockaddr_in sockaddr; struct hostent *hostent; struct servent *servent; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &host)); VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &port)); n = strtol(port, &p, 10); if (p == port + strlen(port)) { nport = htons(n); } else { servent = getservbyname(port, NULL); if (servent == NULL) return vp_stack_return_error(&_result, "getservbyname() error: %s", port); nport = servent->s_port; } sock = socket(PF_INET, SOCK_STREAM, 0); hostent = gethostbyname(host); sockaddr.sin_family = AF_INET; sockaddr.sin_port = nport; sockaddr.sin_addr = *((struct in_addr*)*hostent->h_addr_list); if (connect(sock, (struct sockaddr*)&sockaddr, sizeof(struct sockaddr_in)) == -1) return vp_stack_return_error(&_result, "connect() error: %s", strerror(errno)); vp_stack_push_num(&_result, "%d", sock); return vp_stack_return(&_result); } const char * vp_socket_close(char *args) { return vp_file_close(args); } const char * vp_socket_read(char *args) { return vp_fd_read(args, 0); } const char * vp_socket_write(char *args) { return vp_file_write(args); } /* * Added by Richard Emberson * Check to see if a host exists. */ const char * vp_host_exists(char *args) { vp_stack_t stack; char *host; struct hostent *hostent; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &host)); hostent = gethostbyname(host); if (hostent) { vp_stack_push_num(&_result, "%d", 1); } else { vp_stack_push_num(&_result, "%d", 0); } return vp_stack_return(&_result); } const char * vp_readdir(char *args) { vp_stack_t stack; char *dirname; char buf[1024]; DIR *dir; struct dirent *dp; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &dirname)); if ((dir=opendir(dirname)) == NULL) { return vp_stack_return_error(&_result, "opendir() error: %s", strerror(errno)); } if (strcmp(dirname, "/") == 0) { dirname[0] = '\0'; } for (dp = readdir(dir); dp != NULL; dp = readdir(dir)) { if (strcmp(dp->d_name, ".") && strcmp(dp->d_name, "..")) { snprintf(buf, sizeof(buf), "%s/%s", dirname, dp->d_name); vp_stack_push_str(&_result, buf); } } closedir(dir); return vp_stack_return(&_result); } const char * vp_decode(char *args) { vp_stack_t stack; size_t len; char *str; char *p, *q; VP_RETURN_IF_FAIL(vp_stack_from_args(&stack, args)); VP_RETURN_IF_FAIL(vp_stack_pop_str(&stack, &str)); len = strlen(str); if (len % 2 != 0) { return "vp_decode: invalid data length"; } VP_RETURN_IF_FAIL(vp_stack_reserve(&_result, (_result.top - _result.buf) + (len / 2) + sizeof(VP_EOV_STR))); for (p = str, q = _result.top; p < str + len; ) { char hb, lb; hb = CHR2XD[(int)*(p++)]; lb = CHR2XD[(int)*(p++)]; if (hb != (char)-1 && lb != (char)-1) { *(q++) = (hb << 4) | lb; } } *(q++) = VP_EOV; *q = '\0'; _result.top = q; return vp_stack_return(&_result); } const char * vp_get_signals(char *args) { #define VP_STACK_PUSH_SIGNAME(_signame) \ vp_stack_push_num(&_result, #_signame ":%d", (_signame)) #define VP_STACK_PUSH_ALTSIGNAME(_signame, _altsig) \ vp_stack_push_num(&_result, #_signame ":%d", (_altsig)) #ifdef SIGABRT VP_STACK_PUSH_SIGNAME(SIGABRT); #else #error "SIGABRT is undefined, contrary to ISO C standard." #endif #ifdef SIGFPE VP_STACK_PUSH_SIGNAME(SIGFPE); #else #error "SIGFPE is undefined, contrary to ISO C standard." #endif #ifdef SIGILL VP_STACK_PUSH_SIGNAME(SIGILL); #else #error "SIGILL is undefined, contrary to ISO C standard." #endif #ifdef SIGINT VP_STACK_PUSH_SIGNAME(SIGINT); #else #error "SIGINT is undefined, contrary to ISO C standard." #endif #ifdef SIGSEGV VP_STACK_PUSH_SIGNAME(SIGSEGV); #else #error "SIGSEGV is undefined, contrary to ISO C standard." #endif #ifdef SIGTERM VP_STACK_PUSH_SIGNAME(SIGTERM); #else #error "SIGTERM is undefined, contrary to ISO C standard." #endif #ifdef SIGALRM VP_STACK_PUSH_SIGNAME(SIGALRM); #else VP_STACK_PUSH_ALTSIGNAME(SIGALRM, SIGTERM); #endif #ifdef SIGBUS VP_STACK_PUSH_SIGNAME(SIGBUS); #else VP_STACK_PUSH_ALTSIGNAME(SIGBUS, SIGABRT); #endif #ifdef SIGCHLD VP_STACK_PUSH_SIGNAME(SIGCHLD); #else VP_STACK_PUSH_ALTSIGNAME(SIGCHLD, 0); #endif #ifdef SIGCONT VP_STACK_PUSH_SIGNAME(SIGCONT); #else VP_STACK_PUSH_ALTSIGNAME(SIGCONT, 0); #endif #ifdef SIGHUP VP_STACK_PUSH_SIGNAME(SIGHUP); #else VP_STACK_PUSH_ALTSIGNAME(SIGHUP, SIGTERM); #endif #ifdef SIGKILL VP_STACK_PUSH_SIGNAME(SIGKILL); #else VP_STACK_PUSH_ALTSIGNAME(SIGKILL, SIGTERM); #endif #ifdef SIGPIPE VP_STACK_PUSH_SIGNAME(SIGPIPE); #else VP_STACK_PUSH_ALTSIGNAME(SIGPIPE, SIGTERM); #endif #ifdef SIGQUIT VP_STACK_PUSH_SIGNAME(SIGQUIT); #else VP_STACK_PUSH_ALTSIGNAME(SIGQUIT, SIGTERM); #endif #ifdef SIGSTOP VP_STACK_PUSH_SIGNAME(SIGSTOP); #else VP_STACK_PUSH_ALTSIGNAME(SIGSTOP, 0); #endif #ifdef SIGTSTP VP_STACK_PUSH_SIGNAME(SIGTSTP); #else VP_STACK_PUSH_ALTSIGNAME(SIGTSTP, 0); #endif #ifdef SIGTTIN VP_STACK_PUSH_SIGNAME(SIGTTIN); #else VP_STACK_PUSH_ALTSIGNAME(SIGTTIN, 0); #endif #ifdef SIGTTOU VP_STACK_PUSH_SIGNAME(SIGTTOU); #else VP_STACK_PUSH_ALTSIGNAME(SIGTTOU, 0); #endif #ifdef SIGUSR1 VP_STACK_PUSH_SIGNAME(SIGUSR1); #else VP_STACK_PUSH_ALTSIGNAME(SIGUSR1, SIGTERM); #endif #ifdef SIGUSR2 VP_STACK_PUSH_SIGNAME(SIGUSR2); #else VP_STACK_PUSH_ALTSIGNAME(SIGUSR2, SIGTERM); #endif #ifdef SIGPOLL VP_STACK_PUSH_SIGNAME(SIGPOLL); #else VP_STACK_PUSH_ALTSIGNAME(SIGPOLL, SIGTERM); #endif #ifdef SIGPROF VP_STACK_PUSH_SIGNAME(SIGPROF); #else VP_STACK_PUSH_ALTSIGNAME(SIGPROF, SIGTERM); #endif #ifdef SIGSYS VP_STACK_PUSH_SIGNAME(SIGSYS); #else VP_STACK_PUSH_ALTSIGNAME(SIGSYS, SIGABRT); #endif #ifdef SIGTRAP VP_STACK_PUSH_SIGNAME(SIGTRAP); #else VP_STACK_PUSH_ALTSIGNAME(SIGTRAP, SIGABRT); #endif #ifdef SIGURG VP_STACK_PUSH_SIGNAME(SIGURG); #else VP_STACK_PUSH_ALTSIGNAME(SIGURG, 0); #endif #ifdef SIGVTALRM VP_STACK_PUSH_SIGNAME(SIGVTALRM); #else VP_STACK_PUSH_ALTSIGNAME(SIGVTALRM, SIGTERM); #endif #ifdef SIGXCPU VP_STACK_PUSH_SIGNAME(SIGXCPU); #else VP_STACK_PUSH_ALTSIGNAME(SIGXCPU, SIGABRT); #endif #ifdef SIGXFSZ VP_STACK_PUSH_SIGNAME(SIGXFSZ); #else VP_STACK_PUSH_ALTSIGNAME(SIGXFSZ, SIGABRT); #endif #ifdef SIGEMT VP_STACK_PUSH_SIGNAME(SIGEMT); #else VP_STACK_PUSH_ALTSIGNAME(SIGEMT, SIGTERM); #endif #ifdef SIGWINCH VP_STACK_PUSH_SIGNAME(SIGWINCH); #else VP_STACK_PUSH_ALTSIGNAME(SIGWINCH, 0); #endif return vp_stack_return(&_result); #undef VP_STACK_PUSH_SIGNAME #undef VP_STACK_PUSH_ALTSIGNAME } /* * vim:set sw=4 sts=4 et: */