aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLAN-TW <lantw44@gmail.com>2014-01-11 22:41:59 +0800
committerLAN-TW <lantw44@gmail.com>2014-01-11 22:44:43 +0800
commit3e90963d4721aa18f7c8e65925de627f40a0de29 (patch)
treec1914c1a4219d9a1c6876b5fa3a2295741d158ea
parent600e2e611f426308bfb25601c62417f38198c1a6 (diff)
downloadl4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.tar
l4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.tar.gz
l4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.tar.bz2
l4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.tar.lz
l4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.tar.xz
l4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.tar.zst
l4basic-3e90963d4721aa18f7c8e65925de627f40a0de29.zip
Import utilities for POSIX system and other system-dependent functions
-rw-r--r--Makefile10
-rw-r--r--l4posix.c331
-rw-r--r--l4posix.h39
-rw-r--r--l4str.c42
-rw-r--r--l4str.h13
-rw-r--r--l4sysdep.c76
-rw-r--r--l4sysdep.h10
7 files changed, 519 insertions, 2 deletions
diff --git a/Makefile b/Makefile
index 9574451..339737a 100644
--- a/Makefile
+++ b/Makefile
@@ -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 */
diff --git a/l4str.c b/l4str.c
new file mode 100644
index 0000000..0d3577e
--- /dev/null
+++ b/l4str.c
@@ -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;
+}
+
diff --git a/l4str.h b/l4str.h
new file mode 100644
index 0000000..cda3c1d
--- /dev/null
+++ b/l4str.h
@@ -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 */