aboutsummaryrefslogtreecommitdiff
path: root/lib/mlibc/options/posix/generic/syslog-stubs.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/mlibc/options/posix/generic/syslog-stubs.cpp')
-rw-r--r--lib/mlibc/options/posix/generic/syslog-stubs.cpp152
1 files changed, 152 insertions, 0 deletions
diff --git a/lib/mlibc/options/posix/generic/syslog-stubs.cpp b/lib/mlibc/options/posix/generic/syslog-stubs.cpp
new file mode 100644
index 0000000..6a80ff9
--- /dev/null
+++ b/lib/mlibc/options/posix/generic/syslog-stubs.cpp
@@ -0,0 +1,152 @@
+
+#include <syslog.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <errno.h>
+#include <time.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <bits/ensure.h>
+
+#include <frg/mutex.hpp>
+#include <mlibc/lock.hpp>
+#include <mlibc/debug.hpp>
+
+// This syslog implementation is largely taken from musl
+
+static char log_ident[32];
+static int log_options;
+static int log_facility = LOG_USER;
+static int log_fd = -1;
+static int log_opt;
+static int log_mask = 0xff;
+
+static int use_mlibc_logger = 0;
+static FutexLock __syslog_lock;
+
+static const struct sockaddr_un log_addr {AF_UNIX, "/dev/log"};
+
+void closelog(void) {
+ frg::unique_lock<FutexLock> holder { __syslog_lock };
+ close(log_fd);
+ log_fd = -1;
+}
+
+static void __openlog() {
+ log_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+ if(log_fd >= 0) {
+ int ret = connect(log_fd, (const sockaddr *)&log_addr, sizeof log_addr);
+ if(ret) {
+ mlibc::infoLogger() << "\e[31mmlibc: syslog: connect returned an error, falling back to infoLogger\e[39m" << frg::endlog;
+ use_mlibc_logger = 1;
+ }
+ }
+}
+
+void openlog(const char *ident, int options, int facility) {
+ frg::unique_lock<FutexLock> holder { __syslog_lock };
+ if(ident) {
+ size_t n = strnlen(ident, sizeof log_ident - 1);
+ memcpy(log_ident, ident, n);
+ log_ident[n] = 0;
+ } else {
+ log_ident[0] = 0;
+ }
+ log_options = options;
+ log_facility = facility;
+
+ if((options & LOG_NDELAY) && log_fd < 0)
+ __openlog();
+}
+
+int setlogmask(int mask) {
+ int old_mask = log_mask;
+
+ log_mask = mask;
+
+ return old_mask;
+}
+
+static void _vsyslog(int priority, const char *message, va_list ap) {
+ auto is_lost_conn = [] (int e) {
+ return e == ECONNREFUSED || e == ECONNRESET || e == ENOTCONN || e == EPIPE;
+ };
+
+ if(!(priority & log_mask)) {
+ return;
+ }
+
+ char timebuf[16];
+ time_t now;
+ struct tm tm;
+ char buf[1024];
+ int errno_save = errno;
+ int pid;
+ int l, l2;
+ int hlen;
+ int fd;
+
+ if(log_fd < 0)
+ __openlog();
+
+ if(use_mlibc_logger) {
+ vsnprintf(buf, sizeof buf, message, ap);
+ mlibc::infoLogger() << "mlibc: syslog: " << buf << frg::endlog;
+ return;
+ }
+
+ if(!(priority & LOG_FACMASK))
+ priority |= log_facility;
+
+ now = time(NULL);
+ gmtime_r(&now, &tm);
+ strftime(timebuf, sizeof timebuf, "%b %e %T", &tm);
+
+ pid = (log_opt & LOG_PID) ? getpid() : 0;
+ l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ",
+ priority, timebuf, &hlen, log_ident, "[" + !pid, pid, "]" + !pid);
+ errno = errno_save;
+ l2 = vsnprintf(buf + l, sizeof buf - l, message, ap);
+ if(l2 >= 0) {
+ if(l2 >= (long int)(sizeof buf - l))
+ l = sizeof buf - 1;
+ else
+ l += l2;
+ if(buf[l - 1] != '\n')
+ buf[l++] = '\n';
+ if(send(log_fd, buf, l, 0) < 0 && (!is_lost_conn(errno)
+ || connect(log_fd, (const sockaddr *)&log_addr, sizeof log_addr) < 0
+ || send(log_fd, buf, l, 0) < 0)
+ && (log_opt & LOG_CONS)) {
+ fd = open("/dev/console", O_WRONLY|O_NOCTTY|O_CLOEXEC);
+ if(fd >= 0) {
+ dprintf(fd, "%.*s", l - hlen, buf + hlen);
+ close(fd);
+ }
+ }
+ if(log_opt & LOG_PERROR)
+ dprintf(STDERR_FILENO, "%.*s", l - hlen, buf + hlen);
+ }
+}
+
+void syslog(int priority, const char *format, ...) {
+ va_list ap;
+ va_start(ap, format);
+ vsyslog(priority, format, ap);
+ va_end(ap);
+}
+
+void vsyslog(int priority, const char *message, va_list ap) {
+ int cs;
+ if(!(log_mask & LOG_MASK(priority & 7)) || (priority & ~0x3ff)) {
+ mlibc::infoLogger() << "\e[31mmlibc: syslog: log_mask or priority out of range, not printing anything\e[39m" << frg::endlog;
+ return;
+ }
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+ frg::unique_lock<FutexLock> lock(__syslog_lock);
+ _vsyslog(priority, message, ap);
+ pthread_setcancelstate(cs, 0);
+}