📄 sysutil.c
字号:
/* * Part of Very Secure FTPd * Licence: GPL v2 * Author: Chris Evans * * sysutil.c * * Routines to make the libc/syscall API more pleasant to use. Long term, * more libc/syscalls will go in here to reduce the number of .c files with * dependencies on libc or syscalls. */#define PRIVATE_HANDS_OFF_syscall_retval syscall_retval#define PRIVATE_HANDS_OFF_exit_status exit_status#include "sysutil.h"#include "utility.h"#include "tunables.h"/* Activate 64-bit file support on Linux/32bit plus others */#define _FILE_OFFSET_BITS 64#define _LARGEFILE_SOURCE 1#define _LARGEFILE64_SOURCE 1#define _LARGE_FILES 1/* For Linux, this adds nothing :-) */#include "port/porting_junk.h"#include <signal.h>#include <string.h>#include <stdlib.h>#include <unistd.h>#include <sys/types.h>#include <sys/socket.h>#include <sys/mman.h>#include <sys/stat.h>#include <fcntl.h>#include <netinet/in.h>#include <stdio.h>#include <dirent.h>#include <time.h>#include <arpa/inet.h>#include <errno.h>#include <pwd.h>#include <grp.h>#include <ctype.h>#include <sys/wait.h>#include <sys/time.h>/* Must be before netinet/ip.h. Found on FreeBSD, Solaris */#include <netinet/in_systm.h>#include <netinet/ip.h>#include <netinet/tcp.h>#include <limits.h>#include <syslog.h>#include <utime.h>#include <netdb.h>#include <sys/resource.h>/* Private variables to this file *//* Current umask() */static unsigned int s_current_umask;/* Cached time */static struct timeval s_current_time;/* Current pid */static int s_current_pid = -1;/* Exit function */static exitfunc_t s_exit_func;/* Difference in timezone from GMT in seconds */static long s_timezone;/* Our internal signal handling implementation details */static struct vsf_sysutil_sig_details{ vsf_sighandle_t sync_sig_handler; void* p_private; int pending; int running; int use_alarm;} s_sig_details[NSIG];static vsf_context_io_t s_io_handler;static void* s_p_io_handler_private;static int s_io_handler_running;struct vsf_sysutil_sockaddr{ union { struct sockaddr u_sockaddr; struct sockaddr_in u_sockaddr_in; struct sockaddr_in6 u_sockaddr_in6; } u;};/* File locals */static void vsf_sysutil_common_sighandler(int signum);static void vsf_sysutil_alrm_sighandler(int signum);static int vsf_sysutil_translate_sig(const enum EVSFSysUtilSignal sig);static void vsf_sysutil_set_sighandler(int sig, void (*p_handlefunc)(int));static int vsf_sysutil_translate_memprot( const enum EVSFSysUtilMapPermission perm);static int vsf_sysutil_translate_openmode( const enum EVSFSysUtilOpenMode mode);static void vsf_sysutil_alloc_statbuf(struct vsf_sysutil_statbuf** p_ptr);void vsf_sysutil_sockaddr_alloc(struct vsf_sysutil_sockaddr** p_sockptr);static int lock_internal(int fd, int lock_type);static voidvsf_sysutil_alrm_sighandler(int signum){ (void) signum; alarm(1);}static voidvsf_sysutil_common_sighandler(int signum){ if (signum < 0 || signum >= NSIG) { // bug() is not async safe but this check really is a "cannot happen" // debug aid. bug("signal out of range in vsf_sysutil_common_sighandler"); } if (s_sig_details[signum].sync_sig_handler) { s_sig_details[signum].pending = 1; /* Since this synchronous signal framework has a small race (signal coming * in just before we start a blocking call), there's the option to fire an * alarm repeatedly until the signal is handled. */ if (s_sig_details[signum].use_alarm) { alarm(1); } }}/* Notes. This signal check is evaluated after potentially blocking system * calls, i.e. at highly defined points in the code. Since we only interrupt * at these definite locations, the signal handlers can be non-trivial * without us having to worry about re-entrancy. * * We guarantee that a handler for a given signal is not re-entrant. This * is taken care of by the "running" flag. * * This call itself can only be re-entered once we dereference the actual * hander function pointer, so we are safe with respect to races modifying * the "running" flag. */voidvsf_sysutil_check_pending_actions( const enum EVSFSysUtilInterruptContext context, int retval, int fd){ unsigned int i; /* Check the i/o handler before the signal handlers */ if (s_io_handler && !s_io_handler_running && context == kVSFSysUtilIO) { s_io_handler_running = 1; (*s_io_handler)(retval, fd, s_p_io_handler_private); s_io_handler_running = 0; } for (i=0; i < NSIG; ++i) { if (s_sig_details[i].pending && !s_sig_details[i].running) { s_sig_details[i].running = 1; if (s_sig_details[i].use_alarm) { alarm(0); } if (s_sig_details[i].sync_sig_handler) { s_sig_details[i].pending = 0; (*(s_sig_details[i].sync_sig_handler))(s_sig_details[i].p_private); } s_sig_details[i].running = 0; } }}static intvsf_sysutil_translate_sig(const enum EVSFSysUtilSignal sig){ int realsig = 0; switch (sig) { case kVSFSysUtilSigALRM: realsig = SIGALRM; break; case kVSFSysUtilSigTERM: realsig = SIGTERM; break; case kVSFSysUtilSigCHLD: realsig = SIGCHLD; break; case kVSFSysUtilSigPIPE: realsig = SIGPIPE; break; case kVSFSysUtilSigURG: realsig = SIGURG; break; case kVSFSysUtilSigHUP: realsig = SIGHUP; break; default: bug("unknown signal in vsf_sysutil_translate_sig"); break; } if (realsig < 0 || realsig >= NSIG) { bug("signal out of range in vsf_sysutil_translate_sig"); } return realsig;}voidvsf_sysutil_install_sighandler(const enum EVSFSysUtilSignal sig, vsf_sighandle_t handler, void* p_private, int use_alarm){ int realsig = vsf_sysutil_translate_sig(sig); s_sig_details[realsig].p_private = p_private; s_sig_details[realsig].sync_sig_handler = handler; s_sig_details[realsig].use_alarm = use_alarm; vsf_sysutil_set_sighandler(realsig, vsf_sysutil_common_sighandler); if (use_alarm && realsig != SIGALRM) { vsf_sysutil_set_sighandler(SIGALRM, vsf_sysutil_alrm_sighandler); }}voidvsf_sysutil_default_sig(const enum EVSFSysUtilSignal sig){ int realsig = vsf_sysutil_translate_sig(sig); vsf_sysutil_set_sighandler(realsig, SIG_DFL); s_sig_details[realsig].p_private = NULL; s_sig_details[realsig].sync_sig_handler = NULL;}voidvsf_sysutil_install_null_sighandler(const enum EVSFSysUtilSignal sig){ int realsig = vsf_sysutil_translate_sig(sig); s_sig_details[realsig].p_private = NULL; s_sig_details[realsig].sync_sig_handler = NULL; vsf_sysutil_set_sighandler(realsig, vsf_sysutil_common_sighandler);}voidvsf_sysutil_install_async_sighandler(const enum EVSFSysUtilSignal sig, vsf_async_sighandle_t handler){ int realsig = vsf_sysutil_translate_sig(sig); s_sig_details[realsig].p_private = NULL; s_sig_details[realsig].sync_sig_handler = NULL; vsf_sysutil_block_sig(sig); vsf_sysutil_set_sighandler(realsig, handler);}static voidvsf_sysutil_set_sighandler(int sig, void (*p_handlefunc)(int)){ int retval; struct sigaction sigact; vsf_sysutil_memclr(&sigact, sizeof(sigact)); sigact.sa_handler = p_handlefunc; retval = sigfillset(&sigact.sa_mask); if (retval != 0) { die("sigfillset"); } retval = sigaction(sig, &sigact, NULL); if (retval != 0) { die("sigaction"); }}voidvsf_sysutil_block_sig(const enum EVSFSysUtilSignal sig){ sigset_t sset; int retval; int realsig = vsf_sysutil_translate_sig(sig); retval = sigemptyset(&sset); if (retval != 0) { die("sigemptyset"); } retval = sigaddset(&sset, realsig); if (retval != 0) { die("sigaddset"); } retval = sigprocmask(SIG_BLOCK, &sset, NULL); if (retval != 0) { die("sigprocmask"); }}voidvsf_sysutil_unblock_sig(const enum EVSFSysUtilSignal sig){ sigset_t sset; int retval; int realsig = vsf_sysutil_translate_sig(sig); retval = sigemptyset(&sset); if (retval != 0) { die("sigemptyset"); } retval = sigaddset(&sset, realsig); if (retval != 0) { die("sigaddset"); } retval = sigprocmask(SIG_UNBLOCK, &sset, NULL); if (retval != 0) { die("sigprocmask"); }}voidvsf_sysutil_install_io_handler(vsf_context_io_t handler, void* p_private){ if (s_io_handler != NULL) { bug("double register of i/o handler"); } s_io_handler = handler; s_p_io_handler_private = p_private;}voidvsf_sysutil_uninstall_io_handler(void){ if (s_io_handler == NULL) { bug("no i/o handler to unregister!"); } s_io_handler = NULL; s_p_io_handler_private = NULL;}voidvsf_sysutil_set_alarm(const unsigned int trigger_seconds){ (void) alarm(trigger_seconds);}voidvsf_sysutil_clear_alarm(void){ vsf_sysutil_set_alarm(0);}intvsf_sysutil_read(const int fd, void* p_buf, const unsigned int size){ while (1) { int retval = read(fd, p_buf, size); int saved_errno = errno; vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, fd); if (retval < 0 && saved_errno == EINTR) { continue; } return retval; }}intvsf_sysutil_write(const int fd, const void* p_buf, const unsigned int size){ while (1) { int retval = write(fd, p_buf, size); int saved_errno = errno; vsf_sysutil_check_pending_actions(kVSFSysUtilIO, retval, fd); if (retval < 0 && saved_errno == EINTR) { continue; } return retval; }}intvsf_sysutil_read_loop(const int fd, void* p_buf, unsigned int size){ int retval; int num_read = 0; if (size > INT_MAX) { die("size too big in vsf_sysutil_read_loop"); } while (1) { retval = vsf_sysutil_read(fd, (char*)p_buf + num_read, size); if (retval < 0) { return retval; } else if (retval == 0) { /* Read all we're going to read.. */ return num_read; } if ((unsigned int) retval > size) { die("retval too big in vsf_sysutil_read_loop"); } num_read += retval; size -= (unsigned int) retval; if (size == 0) { /* Hit the read target, cool. */ return num_read; } }}intvsf_sysutil_write_loop(const int fd, const void* p_buf, unsigned int size){ int retval; int num_written = 0; if (size > INT_MAX) { die("size too big in vsf_sysutil_write_loop"); } while (1) { retval = vsf_sysutil_write(fd, (const char*)p_buf + num_written, size); if (retval < 0) { /* Error */ return retval; } else if (retval == 0) { /* Written all we're going to write.. */ return num_written; } if ((unsigned int) retval > size) { die("retval too big in vsf_sysutil_read_loop"); } num_written += retval; size -= (unsigned int) retval; if (size == 0) { /* Hit the write target, cool. */ return num_written; } }}filesize_tvsf_sysutil_get_file_offset(const int file_fd){ filesize_t retval = lseek(file_fd, 0, SEEK_CUR); if (retval < 0) { die("lseek"); } return retval;}voidvsf_sysutil_lseek_to(const int fd, filesize_t seek_pos){ filesize_t retval; if (seek_pos < 0) { die("negative seek_pos in vsf_sysutil_lseek_to"); } retval = lseek(fd, seek_pos, SEEK_SET); if (retval < 0) { die("lseek"); }}void*vsf_sysutil_malloc(unsigned int size){ void* p_ret; /* Paranoia - what if we got an integer overflow/underflow? */ if (size == 0 || size > INT_MAX) { bug("zero or big size in vsf_sysutil_malloc"); } p_ret = malloc(size); if (p_ret == NULL) { die("malloc"); } return p_ret;}void*vsf_sysutil_realloc(void* p_ptr, unsigned int size){ void* p_ret; if (size == 0 || size > INT_MAX) { bug("zero or big size in vsf_sysutil_realloc"); } p_ret = realloc(p_ptr, size); if (p_ret == NULL) { die("realloc"); } return p_ret;}voidvsf_sysutil_free(void* p_ptr){ if (p_ptr == NULL) { bug("vsf_sysutil_free got a null pointer"); } free(p_ptr);}unsigned intvsf_sysutil_getpid(void){ if (s_current_pid == -1) { s_current_pid = getpid(); } return (unsigned int) s_current_pid;}intvsf_sysutil_fork(void){ /* Child does NOT inherit exit function */ exitfunc_t curr_func = s_exit_func; int retval; s_exit_func = 0; retval = vsf_sysutil_fork_failok(); if (retval != 0) { s_exit_func = curr_func; } if (retval < 0) { die("fork"); } return retval;}intvsf_sysutil_fork_failok(void){ int retval = fork(); if (retval == 0) { s_current_pid = -1; } return retval;}voidvsf_sysutil_set_exit_func(exitfunc_t exitfunc){ s_exit_func = exitfunc;}voidvsf_sysutil_exit(int exit_code){ if (s_exit_func) { exitfunc_t curr_func = s_exit_func; /* Prevent recursion */ s_exit_func = 0; (*curr_func)(); } _exit(exit_code);}struct vsf_sysutil_wait_retvalvsf_sysutil_wait(void){ struct vsf_sysutil_wait_retval retval; vsf_sysutil_memclr(&retval, sizeof(retval)); while (1) { int sys_ret = wait(&retval.exit_status); if (sys_ret < 0 && errno == EINTR) { vsf_sysutil_check_pending_actions(kVSFSysUtilUnknown, 0, 0); continue; } retval.syscall_retval = sys_ret; return retval; }}intvsf_sysutil_wait_reap_one(void){ int retval = waitpid(-1, NULL, WNOHANG); if (retval == 0 || (retval < 0 && errno == ECHILD)) { /* No more children */ return 0; } if (retval < 0) { die("waitpid"); } /* Got one */ return retval;}intvsf_sysutil_wait_get_retval(const struct vsf_sysutil_wait_retval* p_waitret){ return p_waitret->syscall_retval;}intvsf_sysutil_wait_exited_normally( const struct vsf_sysutil_wait_retval* p_waitret){ int status = ((struct vsf_sysutil_wait_retval*) p_waitret)->exit_status; return WIFEXITED(status);}intvsf_sysutil_wait_get_exitcode(const struct vsf_sysutil_wait_retval* p_waitret){ int status; if (!vsf_sysutil_wait_exited_normally(p_waitret)) { bug("not a normal exit in vsf_sysutil_wait_get_exitcode"); } status = ((struct vsf_sysutil_wait_retval*) p_waitret)->exit_status; return WEXITSTATUS(status);}voidvsf_sysutil_activate_keepalive(int fd){ int keepalive = 1; int retval = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keepalive, sizeof(keepalive)); if (retval != 0) { die("setsockopt: keepalive"); }}voidvsf_sysutil_activate_reuseaddr(int fd){ int reuseaddr = 1; int retval = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof(reuseaddr)); if (retval != 0) { die("setsockopt: reuseaddr"); }}voidvsf_sysutil_set_nodelay(int fd){ int nodelay = 1; int retval = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)); if (retval != 0) { die("setsockopt: nodelay"); }}voidvsf_sysutil_activate_sigurg(int fd){ int retval = fcntl(fd, F_SETOWN, getpid()); if (retval != 0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -