#ifdef HAVE_CONFIG_H # include "config.h" #endif #include "xwrap.h" #include <errno.h> #include <fcntl.h> #include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <time.h> #include <unistd.h> #ifdef OS_IS_FREEBSD # include <sys/sysctl.h> #endif #define RETRY_SEC 0 #define RETRY_NSEC 250000000 static const char fail_msg[] = "Fail to allocate memory. Retry ...\n"; static const size_t fail_len = STATIC_STRLEN (fail_msg); int xatol (const char* str, long* result) { int errno_save, rval; long lres; char* endptr; errno_save = errno; errno = 0, rval = 0; lres = strtol (str, &endptr, 10); if (str == endptr || errno != 0) { rval = -1; } else { *result = lres; } errno = errno_save; return rval; } void* xmalloc (size_t size) { void* memptr; while ((memptr = malloc (size)) == NULL) { nanosleep (&(struct timespec) { RETRY_SEC, RETRY_NSEC }, NULL); write (STDERR_FILENO, fail_msg, fail_len); } return memptr; } void* xrealloc (void* ptr, size_t size) { void* newptr; while ((newptr = realloc (ptr, size)) == NULL) { nanosleep (&(struct timespec) { RETRY_SEC, RETRY_NSEC }, NULL); write (STDERR_FILENO, fail_msg, fail_len); } return newptr; } bool xstrend (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* xstrcat (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 = xmalloc (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; } char* xstrdup (const char* str) { char* newstr; while ((newstr = strdup (str)) == NULL) { nanosleep (&(struct timespec) { RETRY_SEC, RETRY_NSEC }, NULL); write (STDERR_FILENO, fail_msg, fail_len); } return newstr; } char* xsprintf (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 = xmalloc (len); va_start (ap, format); vsnprintf (newstr, len, format, ap); va_end (ap); return newstr; } int xfaddfd (int fd, int fdflags) { int orgfd = fcntl (fd, F_GETFD); if (orgfd < 0) { return -1; } return fcntl (fd, F_SETFD, orgfd | fdflags); } int xfdelfd (int fd, int fdflags) { int orgfd = fcntl (fd, F_GETFD); if (orgfd < 0) { return -1; } return fcntl (fd, F_SETFD, orgfd & ~(fdflags)); } int xfaddfl (int fd, int flflags) { int orgfl = fcntl (fd, F_GETFL); if (orgfl < 0) { return -1; } return fcntl (fd, F_SETFL, orgfl | flflags); } int xfdelfl (int fd, int flflags) { int orgfl = fcntl (fd, F_GETFL); if (orgfl < 0) { return -1; } return fcntl (fd, F_SETFL, orgfl & ~(flflags)); } char* xreadlink (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* xgetcwd (void) { char *cwd, *result; size_t size = pathconf (".", _PC_PATH_MAX); size = size > 0 ? size : 256; cwd = xmalloc (sizeof (char) * size); while ((result = getcwd (cwd, size)) == NULL && errno == ERANGE) { size *= 2; cwd = xrealloc (cwd, size); } return cwd; } char* xgetexe (void) { char* myexec; #ifdef OS_IS_FREEBSD int fb_mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; int fb_rval; size_t fb_size = 256; myexec = xmalloc (fb_size); while ((fb_rval = sysctl (fb_mib, 4, myexec, &fb_size, NULL, 0)) < 0 && errno == ENOMEM) { fb_size *= 2; myexec = xrealloc (myexec, fb_size); } if (fb_rval >= 0) { return myexec; } else { free (myexec); } #endif if ((myexec = xreadlink ("/proc/self/exe")) != NULL) { return myexec; } if ((myexec = xreadlink ("/proc/curproc/exe")) != NULL) { return myexec; } if ((myexec = xreadlink ("/proc/curproc/file")) != NULL) { return myexec; } return NULL; } char* xgetres (const char* filename) { char *myexec, *myres; bool myexec_static = false; myexec = xgetexe (); if (myexec == NULL) { myexec = xgetcwd (); if (myexec == NULL) { myexec = "./"; myexec_static = true; } } else { char* dirsep = strrchr (myexec, '/'); if (dirsep != NULL && dirsep != myexec) { *dirsep = '\0'; } } if (xstrend (myexec, "/")) { myres = xstrcat (myexec, filename, (char*)NULL); } else { myres = xstrcat (myexec, "/", filename, (char*)NULL); } if (!myexec_static) { free (myexec); } return myres; } size_t xwrite (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 xbufinit (XBuf* 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; } char* xgetline (int fd, XBuf* buf, int delim) { if (buf->buf_error || buf->buf_eof) { return NULL; } if (buf->buf_len == 0) { int rval = read (fd, buf->buf, XBUFSIZ); 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 = xrealloc (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; }