diff options
-rw-r--r-- | src/CMakeLists.txt | 3 | ||||
-rw-r--r-- | src/Makefile | 4 | ||||
-rw-r--r-- | src/cow.c | 5 | ||||
-rw-r--r-- | src/cow_utils.c | 39 | ||||
-rw-r--r-- | src/debug.h | 14 | ||||
-rw-r--r-- | src/findbranch.c | 3 | ||||
-rw-r--r-- | src/general.c | 4 | ||||
-rw-r--r-- | src/general.h | 1 | ||||
-rw-r--r-- | src/rmdir.c | 3 | ||||
-rw-r--r-- | src/string.c | 8 | ||||
-rw-r--r-- | src/unionfs.c | 16 | ||||
-rw-r--r-- | src/usyslog.c | 296 | ||||
-rw-r--r-- | src/usyslog.h | 31 |
13 files changed, 374 insertions, 53 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 970d882..d58d4f4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,6 @@ set(HASHTABLE_SRCS hashtable.c hashtable_itr.c) -set(UNIONFS_SRCS unionfs.c stats.c opts.c debug.c findbranch.c readdir.c general.c unlink.c cow.c cow_utils.c string.c rmdir.c) +set(UNIONFS_SRCS unionfs.c stats.c opts.c debug.c findbranch.c readdir.c + general.c unlink.c cow.c cow_utils.c string.c rmdir.c usyslog.c) add_executable(unionfs ${UNIONFS_SRCS} ${HASHTABLE_SRCS}) target_link_libraries(unionfs fuse pthread rt) diff --git a/src/Makefile b/src/Makefile index 2f51bf5..1e4e55c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -8,7 +8,9 @@ LDFLAGS += LIB = $(shell pkg-config --libs fuse) HASHTABLE_OBJ = hashtable.o hashtable_itr.o -UNIONFS_OBJ = unionfs.o stats.o opts.o debug.o findbranch.o readdir.o general.o unlink.o rmdir.o cow.o cow_utils.o string.o +UNIONFS_OBJ = unionfs.o stats.o opts.o debug.o findbranch.o readdir.o \ + general.o unlink.o rmdir.o cow.o cow_utils.o string.o \ + usyslog.o unionfs: $(UNIONFS_OBJ) $(HASHTABLE_OBJ) version.h @@ -24,6 +24,7 @@ #include "cow_utils.h" #include "string.h" #include "debug.h" +#include "usyslog.h" /** @@ -53,7 +54,7 @@ static int do_create(const char *path, int nbranch_ro, int nbranch_rw) { res = mkdir(dirp, buf.st_mode); if (res == -1) { - usyslog(LOG_DAEMON, "Creating %s failed: \n", dirp); + USYSLOG(LOG_DAEMON, "Creating %s failed: \n", dirp); RETURN(1); } @@ -169,7 +170,7 @@ int cow_cp(const char *path, int branch_ro, int branch_rw) { res = copy_fifo(&cow); break; case S_IFSOCK: - usyslog(LOG_WARNING, "COW of sockets not supported: %s\n", cow.from_path); + USYSLOG(LOG_WARNING, "COW of sockets not supported: %s\n", cow.from_path); RETURN(1); default: res = copy_file(&cow); diff --git a/src/cow_utils.c b/src/cow_utils.c index 49126c6..31c8bae 100644 --- a/src/cow_utils.c +++ b/src/cow_utils.c @@ -46,6 +46,7 @@ #include "cow_utils.h" #include "debug.h" #include "general.h" +#include "usyslog.h" // BSD seems to know S_ISTXT itself #ifndef S_ISTXT @@ -68,7 +69,7 @@ int setfile(const char *path, struct stat *fs) ut.actime = fs->st_atime; ut.modtime = fs->st_mtime; if (utime(path, &ut)) { - usyslog(LOG_WARNING, "utimes: %s", path); + USYSLOG(LOG_WARNING, "utimes: %s", path); rval = 1; } /* @@ -79,14 +80,14 @@ int setfile(const char *path, struct stat *fs) */ if (chown(path, fs->st_uid, fs->st_gid)) { if (errno != EPERM) { - usyslog(LOG_WARNING, "chown: %s", path); + USYSLOG(LOG_WARNING, "chown: %s", path); rval = 1; } fs->st_mode &= ~(S_ISTXT | S_ISUID | S_ISGID); } if (chmod(path, fs->st_mode)) { - usyslog(LOG_WARNING, "chown: %s", path); + USYSLOG(LOG_WARNING, "chown: %s", path); rval = 1; } @@ -101,7 +102,7 @@ int setfile(const char *path, struct stat *fs) errno = 0; if (chflags(path, fs->st_flags)) { if (errno != EOPNOTSUPP || fs->st_flags != 0) { - usyslog(LOG_WARNING, "chflags: %s", path); + USYSLOG(LOG_WARNING, "chflags: %s", path); rval = 1; } RETURN(rval); @@ -119,7 +120,7 @@ static int setlink(const char *path, struct stat *fs) if (lchown(path, fs->st_uid, fs->st_gid)) { if (errno != EPERM) { - usyslog(LOG_WARNING, "lchown: %s", path); + USYSLOG(LOG_WARNING, "lchown: %s", path); RETURN(1); } } @@ -143,7 +144,7 @@ int copy_file(struct cow *cow) #endif if ((from_fd = open(cow->from_path, O_RDONLY, 0)) == -1) { - usyslog(LOG_WARNING, "%s", cow->from_path); + USYSLOG(LOG_WARNING, "%s", cow->from_path); RETURN(1); } @@ -153,7 +154,7 @@ int copy_file(struct cow *cow) fs->st_mode & ~(S_ISTXT | S_ISUID | S_ISGID)); if (to_fd == -1) { - usyslog(LOG_WARNING, "%s", cow->to_path); + USYSLOG(LOG_WARNING, "%s", cow->to_path); (void)close(from_fd); RETURN(1); } @@ -167,17 +168,17 @@ int copy_file(struct cow *cow) if (fs->st_size > 0 && fs->st_size <= 8 * 1048576) { if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ, MAP_FILE|MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) { - usyslog(LOG_WARNING, "mmap: %s", cow->from_path); + USYSLOG(LOG_WARNING, "mmap: %s", cow->from_path); rval = 1; } else { madvise(p, fs->st_size, MADV_SEQUENTIAL); if (write(to_fd, p, fs->st_size) != fs->st_size) { - usyslog(LOG_WARNING, "%s", cow->to_path); + USYSLOG(LOG_WARNING, "%s", cow->to_path); rval = 1; } /* Some systems don't unmap on close(2). */ if (munmap(p, fs->st_size) < 0) { - usyslog(LOG_WARNING, "%s", cow->from_path); + USYSLOG(LOG_WARNING, "%s", cow->from_path); rval = 1; } } @@ -187,13 +188,13 @@ int copy_file(struct cow *cow) while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { wcount = write(to_fd, buf, rcount); if (rcount != wcount || wcount == -1) { - usyslog(LOG_WARNING, "%s", cow->to_path); + USYSLOG(LOG_WARNING, "%s", cow->to_path); rval = 1; break; } } if (rcount < 0) { - usyslog(LOG_WARNING, "copy failed: %s", cow->from_path); + USYSLOG(LOG_WARNING, "copy failed: %s", cow->from_path); RETURN(1); } } @@ -214,17 +215,17 @@ int copy_file(struct cow *cow) (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) else if (fs->st_mode & (S_ISUID | S_ISGID) && fs->st_uid == cow->uid) { if (fstat(to_fd, &to_stat)) { - usyslog(LOG_WARNING, "%s", cow->to_path); + USYSLOG(LOG_WARNING, "%s", cow->to_path); rval = 1; } else if (fs->st_gid == to_stat.st_gid && fchmod(to_fd, fs->st_mode & RETAINBITS & ~cow->umask)) { - usyslog(LOG_WARNING, "%s", cow->to_path); + USYSLOG(LOG_WARNING, "%s", cow->to_path); rval = 1; } } (void)close(from_fd); if (close(to_fd)) { - usyslog(LOG_WARNING, "%s", cow->to_path); + USYSLOG(LOG_WARNING, "%s", cow->to_path); rval = 1; } @@ -242,14 +243,14 @@ int copy_link(struct cow *cow) char link[PATHLEN_MAX]; if ((len = readlink(cow->from_path, link, sizeof(link)-1)) == -1) { - usyslog(LOG_WARNING, "readlink: %s", cow->from_path); + USYSLOG(LOG_WARNING, "readlink: %s", cow->from_path); RETURN(1); } link[len] = '\0'; if (symlink(link, cow->to_path)) { - usyslog(LOG_WARNING, "symlink: %s", link); + USYSLOG(LOG_WARNING, "symlink: %s", link); RETURN(1); } @@ -265,7 +266,7 @@ int copy_fifo(struct cow *cow) DBG("from %s to %s\n", cow->from_path, cow->to_path); if (mkfifo(cow->to_path, cow->stat->st_mode)) { - usyslog(LOG_WARNING, "mkfifo: %s", cow->to_path); + USYSLOG(LOG_WARNING, "mkfifo: %s", cow->to_path); RETURN(1); } RETURN(setfile(cow->to_path, cow->stat)); @@ -280,7 +281,7 @@ int copy_special(struct cow *cow) DBG("from %s to %s\n", cow->from_path, cow->to_path); if (mknod(cow->to_path, cow->stat->st_mode, cow->stat->st_rdev)) { - usyslog(LOG_WARNING, "mknod: %s", cow->to_path); + USYSLOG(LOG_WARNING, "mknod: %s", cow->to_path); RETURN(1); } RETURN(setfile(cow->to_path, cow->stat)); diff --git a/src/debug.h b/src/debug.h index 103d47b..64626eb 100644 --- a/src/debug.h +++ b/src/debug.h @@ -24,20 +24,6 @@ extern FILE* dbgfile; fflush(stdout); \ } while (0) -/** - * Calling syslog() will deadlock if the filesystem is for /etc or /var. - * This is a bit unexpected, since I thought it would just write into a buffer - * and then the syslog-daemon would then independetely of the unionfs thread - * write it's log entry. However, it seems the syslog() call waits for until - * the log entry is written, which will cause a deadlock, of course. - * Until we find a solution for that, we simply disable syslogs. - * The only sane solution comming presently into my mind is to write into - * a buffer and then to have an independent thread which will flush this buffer - * to syslog. Other suggestions are welcome, of course! - */ -#define usyslog(priority, format, ...) DBG(format, ##__VA_ARGS__) - - #define RETURN(returncode) \ do { \ if (uopt.debug) DBG("return %d\n", returncode); \ diff --git a/src/findbranch.c b/src/findbranch.c index 7e9e0ff..8c8d703 100644 --- a/src/findbranch.c +++ b/src/findbranch.c @@ -49,6 +49,7 @@ #include "findbranch.h" #include "string.h" #include "debug.h" +#include "usyslog.h" /** * Find a branch that has "path". Return the branch number. @@ -76,7 +77,7 @@ static int find_branch(const char *path, searchflag_t flag) { if (uopt.branches[i].rw) RETURN(i); break; default: - usyslog(LOG_ERR, "%s: Unknown flag %d\n", __func__, flag); + USYSLOG(LOG_ERR, "%s: Unknown flag %d\n", __func__, flag); } } diff --git a/src/general.c b/src/general.c index e0bb374..fcec693 100644 --- a/src/general.c +++ b/src/general.c @@ -30,7 +30,7 @@ #include "findbranch.h" #include "general.h" #include "debug.h" - +#include "usyslog.h" /** * Check if a file or directory with the hidden flag exists. @@ -200,7 +200,7 @@ int set_owner(const char *path) { if (ctx->uid != 0 && ctx->gid != 0) { int res = lchown(path, ctx->uid, ctx->gid); if (res) { - usyslog(LOG_WARNING, + USYSLOG(LOG_WARNING, ":%s: Setting the correct file owner failed: %s !\n", __func__, strerror(errno)); RETURN(-errno); diff --git a/src/general.h b/src/general.h index 5a51e32..33a67c6 100644 --- a/src/general.h +++ b/src/general.h @@ -8,7 +8,6 @@ #define GENERAL_H #include <stdbool.h> -#include <syslog.h> enum whiteout { WHITEOUT_FILE, diff --git a/src/rmdir.c b/src/rmdir.c index b9190a8..5170425 100644 --- a/src/rmdir.c +++ b/src/rmdir.c @@ -32,6 +32,7 @@ #include "findbranch.h" #include "string.h" #include "readdir.h" +#include "usyslog.h" /** * If the branch that has the directory to be removed is in read-write mode, @@ -69,7 +70,7 @@ static int rmdir_ro(const char *path, int branch_ro) { case (ENOTDIR): case (ENOTEMPTY): // catch errors not allowed for rmdir() - usyslog (LOG_ERR, "%s: Creating the whiteout failed: %s\n", + USYSLOG (LOG_ERR, "%s: Creating the whiteout failed: %s\n", __func__, strerror(errno)); errno = EFAULT; } diff --git a/src/string.c b/src/string.c index 36d3e54..71deef7 100644 --- a/src/string.c +++ b/src/string.c @@ -23,7 +23,7 @@ #include "opts.h" #include "debug.h" #include "general.h" - +#include "usyslog.h" /** * Check if the given fname suffixes the hide tag @@ -113,7 +113,7 @@ int build_path(char *path, int max_len, const char *callfunc, int line, ...) { // +1 for final \0 not counted by strlen if (len + 1 > max_len) { - usyslog (LOG_WARNING, "%s():%d Path too long \n", callfunc, line); + USYSLOG (LOG_WARNING, "%s():%d Path too long \n", callfunc, line); errno = ENAMETOOLONG; RETURN(-errno); } @@ -122,7 +122,7 @@ int build_path(char *path, int max_len, const char *callfunc, int line, ...) { } if (len == 0) { - usyslog(LOG_ERR, "from: %s():%d : No argument given?\n", callfunc, line); + USYSLOG(LOG_ERR, "from: %s():%d : No argument given?\n", callfunc, line); errno = EIO; RETURN(-errno); } @@ -141,7 +141,7 @@ char *u_dirname(const char *path) { char *ret = strdup(path); if (ret == NULL) { - usyslog(LOG_WARNING, "strdup failed, probably out of memory!\n"); + USYSLOG(LOG_WARNING, "strdup failed, probably out of memory!\n"); return ret; } diff --git a/src/unionfs.c b/src/unionfs.c index 726062b..184a714 100644 --- a/src/unionfs.c +++ b/src/unionfs.c @@ -50,6 +50,7 @@ #include "readdir.h" #include "cow.h" #include "string.h" +#include "usyslog.h" static struct fuse_opt unionfs_opts[] = { @@ -194,7 +195,7 @@ static int unionfs_getattr(const char *path, struct stat *stbuf) { stbuf->st_size = STATS_SIZE; RETURN(0); } - + int i = find_rorw_branch(path); if (i == -1) RETURN(-errno); @@ -229,7 +230,7 @@ static void * unionfs_init(struct fuse_conn_info *conn) { if (uopt.chroot) { int res = chroot(uopt.chroot); if (res) { - usyslog("Chdir to %s failed: %s ! Aborting!\n", + USYSLOG(LOG_WARNING, "Chdir to %s failed: %s ! Aborting!\n", uopt.chroot, strerror(errno)); exit(1); } @@ -306,10 +307,10 @@ static int unionfs_mknod(const char *path, mode_t mode, dev_t rdev) { // since we now have the unionfs_create() method // So can we remove it? - usyslog (LOG_INFO, "deprecated mknod workaround, tell the unionfs-fuse authors if you see this!\n"); + USYSLOG (LOG_INFO, "deprecated mknod workaround, tell the unionfs-fuse authors if you see this!\n"); res = creat(p, 0); - if (res > 0 && close(res) == -1) usyslog(LOG_WARNING, "Warning, cannot close file\n"); + if (res > 0 && close(res) == -1) USYSLOG(LOG_WARNING, "Warning, cannot close file\n"); } else { res = mknod(p, file_type, rdev); } @@ -444,7 +445,7 @@ static int unionfs_rename(const char *from, const char *to) { } if (i != j) { - usyslog(LOG_ERR, "%s: from and to are on different writable branches %d vs %d, which" + USYSLOG(LOG_ERR, "%s: from and to are on different writable branches %d vs %d, which" "is not supported yet.\n", __func__, i, j); RETURN(-EXDEV); } @@ -477,11 +478,11 @@ static int unionfs_rename(const char *from, const char *to) { // if from was on a read-only branch we copied it, but now rename failed so we need to delete it if (!uopt.branches[i].rw) { if (unlink(f)) - usyslog(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now " + USYSLOG(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now " "also unlink() failed\n", __func__, from); if (remove_hidden(from, i)) - usyslog(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now " + USYSLOG(LOG_ERR, "%s: cow of %s succeeded, but rename() failed and now " "also removing the whiteout failed\n", __func__, from); } RETURN(-err); @@ -807,6 +808,7 @@ static struct fuse_operations unionfs_oper = { int main(int argc, char *argv[]) { struct fuse_args args = FUSE_ARGS_INIT(argc, argv); + init_syslog(); uopt_init(); if (fuse_opt_parse(&args, NULL, unionfs_opts, unionfs_opt_proc) == -1) RETURN(1); diff --git a/src/usyslog.c b/src/usyslog.c new file mode 100644 index 0000000..75becac --- /dev/null +++ b/src/usyslog.c @@ -0,0 +1,296 @@ +/* + * License: BSD-style license + * Copyright: Bernd Schubert <bernd.schubert@fastmail.fm> + * + * Details: + * Log files might be located on our own filesystem. If we then want to log + * a message to syslog, we would need to log to ourself, which easily ends up + * in a deadlock. Initializing openlog() using the flags + * LOG_NDELAY | LOG_NOWAIT should prevent that, but real live has shown that + * this does not work reliable and systems 'crashed' just because we + * tried to log a harmless message. + * So this file introduces a syslog thread and a syslog buffer. usyslog() + * calls write without a risk to deadlock into the syslog buffer (chained + * list) and then the seperate syslog_thread call syslog(). That way our + * our filesystem thread(s) cannot stall from syslog() calls. + */ + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <malloc.h> +#include <pthread.h> +#include <stdarg.h> + +#include "usyslog.h" +#include "debug.h" + +static ulogs_t *free_head, *free_bottom; // free chained list log entries +static ulogs_t *used_head = NULL, *used_bottom = NULL; //used chained list pointers + +static pthread_mutex_t list_lock; // locks the entire chained list +static pthread_cond_t cond_message; // used to wake up the syslog thread + +// Only used for debugging, protected by list_lock +static int free_entries; +static int used_entries = 0; + +//#define USYSLOG_DEBUG + +#ifdef USYSLOG_DEBUG +static void verify_lists() +{ + pthread_mutex_lock(&list_lock); + + ulogs_t *entry = free_head; + int free_count = -1; + bool first_free = true; + while (entry) { + if (first_free) { + first_free = false; + free_count = 1; + } else + free_count++; + entry = entry->next; + } + if (free_count != free_entries && free_entries != 0) + DBG("usyslog list error detected: number of free entries inconsistent!" + " %d vs. %d", free_count, free_entries); + + entry = used_head; + int used_count = -1; + bool first_used = true; + while (entry) { + if (first_used) { + first_used = false; + used_count = 1; + } else + used_count++; + entry = entry->next; + } + if (used_count != used_entries && used_entries != 0) + DBG("usyslog list error detected: number of used entries inconsistent!" + " (used: %d vs. %d) (free: %d vs. %d) \n", + used_count, used_entries, free_count, free_entries); + + pthread_mutex_unlock(&list_lock); +} +#else +#define verify_lists() +#endif + + +/** + * Walks the chained used-list and calls syslog() + */ +static void do_syslog(void) +{ + pthread_mutex_lock(&list_lock); // we MUST ensure not to keep that forever + + ulogs_t *log_entry = used_head; + + while (log_entry) { + pthread_mutex_t *entry_lock = &log_entry->lock; + int res = pthread_mutex_trylock(entry_lock); + if (res) { + if (res != EBUSY) + DBG("Entirely unexpected locking error %s\n", + strerror(res)); + // If something goes wrong with the log_entry we do not + // block the critical list_lock forever! + // EBUSY might come up rarely, if we race with usyslog() + pthread_mutex_unlock(&list_lock); + sleep(1); + pthread_mutex_lock(&list_lock); + log_entry = used_head; + continue; + } + pthread_mutex_unlock(&list_lock); + + // This syslog call and so this lock might block, so be + // carefull on using locks! The filesystem IO thread + // *MUST* only try to lock it using pthread_mutex_trylock() + syslog(log_entry->priority, "%s", log_entry->message); + log_entry->used = false; + + // NOTE: The list is only locked now, after syslog() succeeded! + pthread_mutex_lock(&list_lock); + ulogs_t *next_entry = log_entry->next; // just to save the pointer + + used_head = log_entry->next; + if (!used_head) + used_bottom = NULL; // no used entries left + + if (free_bottom) + free_bottom->next = log_entry; + free_bottom = log_entry; + free_bottom->next = NULL; + + if (!free_head) + free_head = log_entry; + + free_entries++; + used_entries--; + + pthread_mutex_unlock(&list_lock); // unlock ist ASAP + + log_entry = next_entry; + pthread_mutex_unlock(entry_lock); + } + + verify_lists(); +} + +/** + * syslog backgroung thread that tries to to empty the syslog buffer + */ +static void * syslog_thread(void *arg) +{ + // FIXME: What is a better way to prevent a compiler warning about + // unused variable 'arg' + int tinfo = *((int *) arg); + if (1 == 0) + printf("Starting thread %d", tinfo); + + pthread_mutex_t sleep_mutex; + + pthread_mutex_init(&sleep_mutex, NULL); + pthread_mutex_lock(&sleep_mutex); + while (1) { + pthread_cond_wait(&cond_message, &sleep_mutex); + do_syslog(); + } + + return NULL; +} + +/** + * usyslog - function to be called if something shall be logged to syslog + */ +void usyslog(int priority, const char *format, ...) +{ + int res; + ulogs_t *log; + + // Lock the entire list first, which means the syslog thread MUST NOT + // lock it if there is any chance it might be locked forever. + pthread_mutex_lock(&list_lock); + + // Some sanity checks. If we fail here, we will leak a log entry, + // but will not lock up. + + if (free_head == NULL) { + DBG("All syslog entries already busy\n"); + pthread_mutex_unlock(&list_lock); + return; + } + + log = free_head; + free_head = log->next; + + res = pthread_mutex_trylock(&log->lock); + if (res == EBUSY) { + // huh, that never should happen! + DBG("Critical log error, log entry is BUSY, but should not\n"); + pthread_mutex_unlock(&list_lock); + return; + } else if (res) { + // huh, that never should happen either! + DBG("Never should happen, can get lock: %s\n", strerror(res)); + pthread_mutex_unlock(&list_lock); + return; + } + + if (log->used) { + // huh, that never should happen either! + DBG("Never should happen, entry is busy, but should not!\n"); + pthread_mutex_unlock(&log->lock); + pthread_mutex_unlock(&list_lock); + return; + } + + if (!used_head) + used_head = used_bottom = log; + else { + used_bottom->next = log; + used_bottom = log; + } + + if (log->next) { + // from free_list to end of used_list, so next is NULL now + log->next = NULL; + } else { + // so the last entry in free_list + free_bottom = NULL; + } + + + free_entries--; + used_entries++; + + // Everything below is log entry related, so we can free the list_lock + pthread_mutex_unlock(&list_lock); + + va_list ap; + va_start(ap, format); + vsnprintf(log->message, MAX_MSG_SIZE, format, ap); + log->priority = priority; + log->used = 1; + + pthread_mutex_unlock(&log->lock); + + pthread_cond_signal(&cond_message); // wake up the syslog thread +} + +/** + * Initialize syslogs + */ +void init_syslog(void) +{ + openlog("unionfs-fuse: ", LOG_CONS | LOG_NDELAY | LOG_NOWAIT | LOG_PID, LOG_DAEMON); + + pthread_mutex_init(&list_lock, NULL); + pthread_cond_init(&cond_message, NULL); + pthread_t thread; + pthread_attr_t attr; + int t_arg = 0; // thread argument, not required for us + + int i; + ulogs_t *log, *last = NULL; + for (i = 0; i < MAX_SYSLOG_MESSAGES; i++) { + log = malloc(sizeof(ulogs_t)); + if (log == NULL) { + fprintf(stderr, "\nLog initialization failed: %s\n", strerror(errno)); + fprintf(stderr, "Aborting!\n"); + // Still initialazation phase, we can abort. + exit (1); + } + + log->used = false; + pthread_mutex_init(&log->lock, NULL); + + if (last) { + last->next = log; + } else { + // so the very first entry + free_head = log; + } + last = log; + } + last->next = NULL; + free_bottom = last; + + free_entries = MAX_SYSLOG_MESSAGES; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + int res = pthread_create(&thread, &attr, syslog_thread, (void *) &t_arg); + if (res != 0) { + fprintf(stderr, "Failed to initialize the syslog threads: %s\n", + strerror(res)); + exit(1); + } +} + diff --git a/src/usyslog.h b/src/usyslog.h new file mode 100644 index 0000000..5b127a9 --- /dev/null +++ b/src/usyslog.h @@ -0,0 +1,31 @@ +/* + * License: BSD-style license + * Copyright: Bernd Schubert <bernd.schubert@fastmail.fm> + */ + +#include <syslog.h> +#include <stdbool.h> + +#define MAX_SYSLOG_MESSAGES 32 // max number of buffered syslog messages +#define MAX_MSG_SIZE 256 // max string length for syslog messages + +/* chained buffer list of syslog entries */ +typedef struct ulogs { + int priority; // first argument for syslog() + char message[MAX_MSG_SIZE]; // 2nd argument for syslog() + bool used; // is this entry used? + pthread_mutex_t lock; // lock a single entry + struct ulogs *next; // pointer to the next entry +} ulogs_t; + + +void init_syslog(void); +void usyslog(int priority, const char *format, ...); + + +#define USYSLOG(priority, format, ...) \ + do { \ + DBG(format, ##__VA_ARGS__); \ + usyslog(priority, format, ##__VA_ARGS__); \ + } while (0); + |