1#define _ALL_SOURCE
2#include "libc.h"
3#include <errno.h>
4#include <fcntl.h>
5#include <signal.h>
6#include <stdarg.h>
7#include <stdio.h>
8#include <string.h>
9#include <sys/socket.h>
10#include <syslog.h>
11#include <threads.h>
12#include <time.h>
13#include <unistd.h>
14
15static mtx_t lock = MTX_INIT;
16static char log_ident[32];
17static int log_opt;
18static int log_facility = LOG_USER;
19static int log_mask = 0xff;
20static int log_fd = -1;
21
22int setlogmask(int maskpri) {
23    mtx_lock(&lock);
24    int ret = log_mask;
25    if (maskpri)
26        log_mask = maskpri;
27    mtx_unlock(&lock);
28    return ret;
29}
30
31static const struct {
32    short sun_family;
33    char sun_path[9];
34} log_addr = {AF_UNIX, "/dev/log"};
35
36void closelog(void) {
37    mtx_lock(&lock);
38    close(log_fd);
39    log_fd = -1;
40    mtx_unlock(&lock);
41}
42
43static void __openlog(void) {
44    log_fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
45    if (log_fd >= 0)
46        connect(log_fd, (void*)&log_addr, sizeof log_addr);
47}
48
49void openlog(const char* ident, int opt, int facility) {
50    mtx_lock(&lock);
51
52    if (ident) {
53        size_t n = strnlen(ident, sizeof log_ident - 1);
54        memcpy(log_ident, ident, n);
55        log_ident[n] = 0;
56    } else {
57        log_ident[0] = 0;
58    }
59    log_opt = opt;
60    log_facility = facility;
61
62    if ((opt & LOG_NDELAY) && log_fd < 0)
63        __openlog();
64
65    mtx_unlock(&lock);
66}
67
68static int is_lost_conn(int e) {
69    return e == ECONNREFUSED || e == ECONNRESET || e == ENOTCONN || e == EPIPE;
70}
71
72static void _vsyslog(int priority, const char* message, va_list ap) {
73    char timebuf[16];
74    time_t now;
75    struct tm tm;
76    char buf[1024];
77    int errno_save = errno;
78    int pid;
79    int l, l2;
80    int hlen;
81    int fd;
82
83    if (log_fd < 0)
84        __openlog();
85
86    if (!(priority & LOG_FACMASK))
87        priority |= log_facility;
88
89    now = time(NULL);
90    gmtime_r(&now, &tm);
91    strftime(timebuf, sizeof timebuf, "%b %e %T", &tm);
92
93    pid = (log_opt & LOG_PID) ? getpid() : 0;
94    l = snprintf(buf, sizeof buf, "<%d>%s %n%s%s%.0d%s: ", priority, timebuf, &hlen, log_ident,
95                 pid ? "[" : "", pid, pid ? "]" : "");
96    errno = errno_save;
97    l2 = vsnprintf(buf + l, sizeof buf - l, message, ap);
98    if (l2 >= 0) {
99        if ((size_t)l2 >= sizeof(buf) - l)
100            l = sizeof(buf) - 1;
101        else
102            l += l2;
103        if (buf[l - 1] != '\n')
104            buf[l++] = '\n';
105        if (send(log_fd, buf, l, 0) < 0 &&
106            (!is_lost_conn(errno) || connect(log_fd, (void*)&log_addr, sizeof log_addr) < 0 ||
107             send(log_fd, buf, l, 0) < 0) &&
108            (log_opt & LOG_CONS)) {
109            fd = open("/dev/console", O_WRONLY | O_NOCTTY | O_CLOEXEC);
110            if (fd >= 0) {
111                dprintf(fd, "%.*s", l - hlen, buf + hlen);
112                close(fd);
113            }
114        }
115        if (log_opt & LOG_PERROR)
116            dprintf(2, "%.*s", l - hlen, buf + hlen);
117    }
118}
119
120void __vsyslog(int priority, const char* message, va_list ap) {
121    if (!(log_mask & LOG_MASK(priority & 7)) || (priority & ~0x3ff))
122        return;
123    mtx_lock(&lock);
124    _vsyslog(priority, message, ap);
125    mtx_unlock(&lock);
126}
127
128void syslog(int priority, const char* message, ...) {
129    va_list ap;
130    va_start(ap, message);
131    __vsyslog(priority, message, ap);
132    va_end(ap);
133}
134
135weak_alias(__vsyslog, vsyslog);
136