diff options
author | LAN-TW <lantw44@gmail.com> | 2014-01-11 22:41:59 +0800 |
---|---|---|
committer | LAN-TW <lantw44@gmail.com> | 2014-01-11 22:44:43 +0800 |
commit | 3e90963d4721aa18f7c8e65925de627f40a0de29 (patch) | |
tree | c1914c1a4219d9a1c6876b5fa3a2295741d158ea | |
parent | 600e2e611f426308bfb25601c62417f38198c1a6 (diff) | |
download | l4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.tar.gz l4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.tar.zst l4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.zip |
Import utilities for POSIX system and other system-dependent functions
-rw-r--r-- | Makefile | 10 | ||||
-rw-r--r-- | l4posix.c | 331 | ||||
-rw-r--r-- | l4posix.h | 39 | ||||
-rw-r--r-- | l4str.c | 42 | ||||
-rw-r--r-- | l4str.h | 13 | ||||
-rw-r--r-- | l4sysdep.c | 76 | ||||
-rw-r--r-- | l4sysdep.h | 10 |
7 files changed, 519 insertions, 2 deletions
@@ -29,7 +29,7 @@ INCLUDEDIR= $(DESTDIR)$(PREFIX)/include # Tasks definition lib_LIBRARIES= libl4basic.a libl4basic_a_OBJECTS= l4array.o l4array2.o l4file.o l4strv.o l4arg.o \ - l4list.o + l4list.o l4str.o l4posix.o l4sysdep.o libl4basic_a_HEADERS= $(libl4basic_a_OBJECTS:.o=.h) l4common.h check_PROGRAMS= test-array test-array2 test-file test-strv test-arg \ @@ -43,6 +43,9 @@ l4file_o_DEPENDS= l4common.h l4array.o l4strv_o_DEPENDS= l4common.h l4array.o l4arg_o_DEPENDS= l4common.h l4array.o l4list_o_DEPENDS= l4common.h +l4str_o_DEPENDS= l4common.h +l4posix_o_DEPENDS= l4common.h +l4sysdep_o_DEPENDS= l4common.h l4posix.o l4str.o test_array_o_DEPENDS= l4array.o test_array2_o_DEPENDS= l4array2.o @@ -79,6 +82,9 @@ l4file.o: l4file.c l4file.h $(l4file_o_DEPENDS) l4strv.o: l4strv.c l4strv.h $(l4strv_o_DEPENDS) l4arg.o: l4arg.c l4arg.h $(l4arg_o_DEPENDS) l4list.o: l4list.c l4list.h $(l4list_o_DEPENDS) +l4str.o: l4str.c l4str.h $(l4list_o_DEPENDS) +l4posix.o: l4posix.c l4posix.h $(l4list_o_DEPENDS) +l4sysdep.o: l4sysdep.c l4sysdep.h $(l4list_o_DEPENDS) test-array: test-array.o $(test_array_o_DEPENDS) $(CC) $(M_CFLAGS) test-array.o $(test_array_o_DEPENDS) -o $@ $(M_LDFLAGS) @@ -125,7 +131,7 @@ distcheck: dist cd $(NAME)-`cat VERSION` && $(MAKE) \ CC="$(CC)" AR="$(AR)" RANLIB="$(RANLIB)" RM="$(RM)" \ MKDIR="$(MKDIR)" MKDIR_P="$(MKDIR_P)" INSTALL="$(INSTALL)" \ - CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" + CFLAGS="$(CFLAGS)" LDFLAGS="$(LDFLAGS)" all check $(RM_R) $(NAME)-`cat VERSION` @echo "--------------------" @echo "$(NAME)-`cat VERSION`$(TARBALL_EXTENSION) is ready for distribution!" diff --git a/l4posix.c b/l4posix.c new file mode 100644 index 0000000..91ade6f --- /dev/null +++ b/l4posix.c @@ -0,0 +1,331 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#define _POSIX_C_SOURCE 200809L +#define _XOPEN_SOURCE +#include "l4posix.h" + +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> +#include <sys/select.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> + +char* lbs_posix_strcat (const char* str, ...) { + va_list ap; + char* strp; + char* strnow; + char* newstr; + int len = strlen (str); + + va_start (ap, str); + while ((strp = va_arg (ap, char*)) != NULL) { + len += strlen (strp); + } + va_end (ap); + + newstr = malloc (len + 1); + + va_start (ap, str); + strnow = stpcpy (newstr, str); + while ((strp = va_arg (ap, char*)) != NULL) { + strnow = stpcpy (strnow, strp); + } + newstr[len] = '\0'; + va_end (ap); + + return newstr; +} + +int lbs_posix_add_fd (int fd, int fdflags) { + int orgfd = fcntl (fd, F_GETFD); + if (orgfd < 0) { + return -1; + } + return fcntl (fd, F_SETFD, orgfd | fdflags); +} + +int lbs_posix_del_fd (int fd, int fdflags) { + int orgfd = fcntl (fd, F_GETFD); + if (orgfd < 0) { + return -1; + } + return fcntl (fd, F_SETFD, orgfd & ~(fdflags)); +} + +int lbs_posix_add_fl (int fd, int flflags) { + int orgfl = fcntl (fd, F_GETFL); + if (orgfl < 0) { + return -1; + } + return fcntl (fd, F_SETFL, orgfl | flflags); +} + +int lbs_posix_del_fl (int fd, int flflags) { + int orgfl = fcntl (fd, F_GETFL); + if (orgfl < 0) { + return -1; + } + return fcntl (fd, F_SETFL, orgfl & ~(flflags)); +} + +char* lbs_posix_readlink (const char* filename) { + struct stat st; + if (lstat (filename, &st) < 0) { + return NULL; + } + size_t bufsize = st.st_size ? st.st_size : 8192; + char* buf = malloc (bufsize + 1); + if (buf == NULL) { + return NULL; + } + ssize_t written = readlink (filename, buf, bufsize); + if (written < 0) { + free (buf); + return NULL; + } + buf[written] = '\0'; + return buf; +} + +char* lbs_posix_getcwd (void) { + char *cwd, *result; + size_t size = pathconf (".", _PC_PATH_MAX); + + size = size > 0 ? size : 256; + size = size > 8192 ? 8192 : size; + cwd = malloc (sizeof (char) * size); + + while ((result = getcwd (cwd, size)) == NULL && errno == ERANGE) { + size *= 2; + cwd = realloc (cwd, size); + } + + return cwd; +} + +size_t lbs_posix_write_all (int fd, const char* str, size_t size) { + ssize_t wtn = 0; + if (size <= 0) { + size = strlen (str); + } + size_t rem = size; + while (rem > 0) { + wtn = write (fd, str, rem); + if (wtn < 0) { + if (errno != EINTR && errno != EAGAIN) { + break; + } + continue; + } + str += wtn; + rem -= wtn; + } + + rem = rem > 0 ? rem : 0; + return size - rem; +} + +void lbs_posix_buffer_init (LbsPosixBuffer* buf) { + buf->buf_start = 0; + buf->buf_len = 0; + buf->buf_line = NULL; + buf->buf_line_len = 0; + buf->buf_error = false; + buf->buf_eof = false; +} + +void lbs_posix_buffer_clear (LbsPosixBuffer* buf, bool initial) { + buf->buf_start = 0; + buf->buf_len = 0; + + if (!initial) { + free (buf->buf_line); + } + buf->buf_line = NULL; + buf->buf_line_len = 0; + buf->buf_error = false; + buf->buf_eof = false; +} + +char* lbs_posix_buffer_getline (int fd, LbsPosixBuffer* buf, int delim) { + if (buf->buf_error || buf->buf_eof) { + return NULL; + } + + if (buf->buf_len == 0) { + int rval = read (fd, buf->buf, LBS_POSIX_BUFFER_SIZE); + if (rval < 0) { + if (errno != EAGAIN && errno != EINTR) { + buf->buf_error = true; + } + return NULL; + } + if (rval == 0) { + buf->buf_eof = true; + return NULL; + } + buf->buf_start = 0; + buf->buf_len = rval; + } + + int i; + for (i = 0; i < buf->buf_len; i++) { + if (buf->buf[buf->buf_start + i] == delim) { + break; + } + } + + int buf_line_start = buf->buf_line_len; + buf->buf_line_len += i; + buf->buf_line = realloc (buf->buf_line, buf->buf_line_len + 1); + memcpy (buf->buf_line + buf_line_start, buf->buf + buf->buf_start, i); + buf->buf_line[buf->buf_line_len] = '\0'; + + /* remove CR if delim is LF and delim is found */ + if (i < buf->buf_len && delim == '\n' && buf->buf_line_len - 1 >= 0 && + buf->buf_line[buf->buf_line_len - 1] == '\r') { + buf->buf_line[buf->buf_line_len - 1] = '\0'; + buf->buf_line_len--; + } + + int buf_len_saved = buf->buf_len; + buf->buf_start += i + 1; + buf->buf_len -= i + 1; + if (buf->buf_len <= 0) { + buf->buf_start = 0; + buf->buf_len = 0; + } + + if (i < buf_len_saved) { + /* delim is found */ + char* newstr = buf->buf_line; + buf->buf_line = NULL; + buf->buf_line_len = 0; + memmove (buf->buf, buf->buf + buf->buf_start, buf->buf_len); + buf->buf_start = 0; + return newstr; + } + + return NULL; +} + +#define SOCKADDR(x) ((struct sockaddr*)(x)) +#define SOCKADDR_UN(x) ((struct sockaddr_un*)(x)) +#define SOCKADDR_IN(x) ((struct sockaddr_in*)(x)) +#define SOCKADDR_IN6(x) ((struct sockaddr_in6*)(x)) + +static char* lbs_posix_socket_name ( + int sockfd, int (*getter) (int, struct sockaddr*, socklen_t*)) { + + struct sockaddr_storage sock; + socklen_t socklen = sizeof (sock); + + memset (&sock, 0, socklen); + if ((*getter)(sockfd, SOCKADDR (&sock), &socklen) < 0) { + return strdup ("invalid socket"); + } + + int domain = sock.ss_family; + if (domain == AF_UNIX) { + return strdup ("local process"); + } + + socklen_t ipstrlen; + void* ipnet; + char* ipstr; + if (domain == AF_INET) { + ipstrlen = INET_ADDRSTRLEN; + ipnet = &(SOCKADDR_IN (&sock)->sin_addr); + } else { + ipstrlen = INET6_ADDRSTRLEN; + ipnet = &(SOCKADDR_IN6 (&sock)->sin6_addr); + } + + ipstr = malloc (ipstrlen); + if (inet_ntop (domain, ipnet, ipstr, ipstrlen) == NULL) { + free (ipstr); + return strdup ("unknown address"); + } + + return ipstr; +} + +char* lbs_posix_socket_sockname (int sockfd) { + return lbs_posix_socket_name (sockfd, getsockname); +} + +char* lbs_posix_socket_peername (int sockfd) { + return lbs_posix_socket_name (sockfd, getpeername); +} + +void lbs_posix_exchange_data (int fd[2], LbsPosixProgress prog_cb) { + int nfds, active; + fd_set rset, wset; + fd_set rres, wres; + LbsPosixBuffer buf[2]; + + FD_ZERO (&rset); + FD_SET (fd[0], &rset); + FD_SET (fd[1], &rset); + FD_ZERO (&wset); + + active = 2; + nfds = (fd[0] > fd[1] ? fd[0] : fd[1]) + 1; + lbs_posix_buffer_clear (&buf[0], true); + lbs_posix_buffer_clear (&buf[1], true); + + while (active && (*prog_cb) (fd, buf)) { + rres = rset; + wres = wset; + if (select (nfds, &rres, &wres, NULL, NULL) >= 0) { + for (int i = 0; i < 2; i++) { + if (buf[i].buf_len) { + /* read buffer full */ + if (FD_ISSET (fd[!i], &wres)) { + int wb = write (fd[!i], + buf[i].buf + buf[i].buf_start, buf[i].buf_len); + if (wb > 0) { + buf[i].buf_start += wb; + buf[i].buf_len -= wb; + if (!buf[i].buf_len) { + FD_CLR (fd[!i], &wset); + FD_SET (fd[i], &rset); + } + } else { + if (wb < 0 && (errno == EAGAIN || errno == EINTR)) { + continue; + } else { + FD_CLR (fd[!i], &wset); + active = 0; + } + } + } + } else { + /* read buffer empty */ + if (FD_ISSET (fd[i], &rres)) { + int rb = read (fd[i], buf[i].buf, LBS_POSIX_BUFFER_SIZE); + if (rb > 0) { + buf[i].buf_start = 0; + buf[i].buf_len = rb; + FD_CLR (fd[i], &rset); + FD_SET (fd[!i], &wset); + } else { + if (rb < 0 && (errno == EAGAIN || errno == EINTR)) { + continue; + } else{ + FD_CLR (fd[i], &rset); + active = 0; + } + } + } + } + } + } + } +} diff --git a/l4posix.h b/l4posix.h new file mode 100644 index 0000000..8b15ce0 --- /dev/null +++ b/l4posix.h @@ -0,0 +1,39 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#ifndef LBS_POSIX_H +#define LBS_POSIX_H + +#include <l4common.h> +#include <sys/types.h> + +char* lbs_posix_strcat (const char* str, ...); +int lbs_posix_add_fd (int fd, int fdflags); +int lbs_posix_del_fd (int fd, int fdflags); +int lbs_posix_add_fl (int fd, int flflags); +int lbs_posix_del_fl (int fd, int flflags); +char* lbs_posix_readlink (const char* filename); +char* lbs_posix_getcwd (void); +size_t lbs_posix_write_all (int fd, const char* str, size_t size); +char* lbs_posix_socket_sockname (int sockfd); +char* lbs_posix_socket_peername (int sockfd); + + +#define LBS_POSIX_BUFFER_SIZE 4096 + +typedef struct { + char buf[LBS_POSIX_BUFFER_SIZE]; + off_t buf_start; + off_t buf_len; + char* buf_line; + ssize_t buf_line_len; + int buf_error : 1; + int buf_eof : 1; +} LbsPosixBuffer; + +void lbs_posix_buffer_init (LbsPosixBuffer* buf); +void lbs_posix_buffer_clear (LbsPosixBuffer* buf, bool initial); +char* lbs_posix_buffer_getline (int fd, LbsPosixBuffer* buf, int delim); + +typedef int (*LbsPosixProgress) (int fd[2], LbsPosixBuffer buf[2]); +void lbs_posix_exchange_data (int fd[2], LbsPosixProgress prog_cb); + +#endif /* LBS_POSIX_H */ @@ -0,0 +1,42 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ + +#include "l4str.h" + +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +bool lbs_str_has_suffix (const char* str, const char* suffix) { + size_t len = strlen (str); + size_t suflen = strlen (suffix); + int i, j; + for (i = len - 1, j = suflen - 1; i >= 0 && j >= 0; i--, j--) { + if (str[i] != suffix[j]) { + return false; + } + } + if (i < 0 && j >= 0) { + return false; + } + return true; +} + +char* lbs_str_printf (const char* format, ...) { + va_list ap; + char* newstr; + int len; + + va_start (ap, format); + len = vsnprintf (NULL, 0, format, ap) + 1; + va_end (ap); + + newstr = malloc (len); + + va_start (ap, format); + vsnprintf (newstr, len, format, ap); + va_end (ap); + + return newstr; +} + @@ -0,0 +1,13 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#ifndef LBS_STR_H +#define LBS_STR_H + +#include <l4common.h> + +#define LBS_STR_STATIC_STRLEN(x) (sizeof(x)/sizeof(char) - 1) +#define LBS_STR_ARRAY_LEN(x,t) (sizeof(x)/sizeof(t)) + +bool lbs_str_has_suffix (const char* str, const char* suffix); +char* lbs_str_printf (const char* format, ...); + +#endif /* LBS_STR_H */ diff --git a/l4sysdep.c b/l4sysdep.c new file mode 100644 index 0000000..0806f15 --- /dev/null +++ b/l4sysdep.c @@ -0,0 +1,76 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ + +#include "l4sysdep.h" +#include "l4posix.h" +#include "l4str.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#ifdef __FreeBSD__ +# include <sys/sysctl.h> +#endif + +char* lbs_sysdep_get_executable (void) { + char* myexec; + +#ifdef __FreeBSD__ + int fb_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + int fb_rval; + size_t fb_size = 256; + myexec = malloc (fb_size); + while ((fb_rval = sysctl (fb_mib, 4, myexec, &fb_size, NULL, 0)) < 0 && + errno == ENOMEM) { + + fb_size *= 2; + myexec = realloc (myexec, fb_size); + } + if (fb_rval >= 0) { + return myexec; + } else { + free (myexec); + } +#endif + + if ((myexec = lbs_posix_readlink ("/proc/self/exe")) != NULL) { + return myexec; + } + if ((myexec = lbs_posix_readlink ("/proc/curproc/exe")) != NULL) { + return myexec; + } + if ((myexec = lbs_posix_readlink ("/proc/curproc/file")) != NULL) { + return myexec; + } + + return NULL; +} + +char* lbs_sysdep_get_resource (const char* filename) { + char *myexec, *myres; + bool myexec_static = false; + + myexec = lbs_sysdep_get_executable (); + if (myexec == NULL) { + myexec = lbs_posix_getcwd (); + if (myexec == NULL) { + myexec = "./"; + myexec_static = true; + } + } else { + char* dirsep = strrchr (myexec, '/'); + if (dirsep != NULL && dirsep != myexec) { + *dirsep = '\0'; + } + } + + if (lbs_str_has_suffix (myexec, "/")) { + myres = lbs_posix_strcat (myexec, filename, (char*)NULL); + } else { + myres = lbs_posix_strcat (myexec, "/", filename, (char*)NULL); + } + if (!myexec_static) { + free (myexec); + } + + return myres; +} diff --git a/l4sysdep.h b/l4sysdep.h new file mode 100644 index 0000000..79e0c35 --- /dev/null +++ b/l4sysdep.h @@ -0,0 +1,10 @@ +/* vim: set sw=4 ts=4 sts=4 et: */ +#ifndef LBS_SYSDEP_H +#define LBS_SYSDEP_H + +#include <l4common.h> + +char* lbs_sysdep_get_executable (void); +char* lbs_sysdep_get_resource (const char* filename); + +#endif /* LBS_SYSDEP_H */ |