Prechádzať zdrojové kódy

LibC: syslog and lots of compat stuff for it

This is an implementation of syslog with some OpenBSD extensions.
There is no syslogd support (so it only logs to dbgprintf/stderr),
but otherwise is functional.

Many weird defines are always present, because some syslog users in
the wild check for their existence.
Calvin Buckley 5 rokov pred
rodič
commit
bbee1c5b98
3 zmenil súbory, kde vykonal 285 pridanie a 1 odobranie
  1. 2 1
      Libraries/LibC/Makefile
  2. 132 0
      Libraries/LibC/syslog.cpp
  3. 151 0
      Libraries/LibC/syslog.h

+ 2 - 1
Libraries/LibC/Makefile

@@ -53,7 +53,8 @@ LIBC_OBJS = \
        sched.o \
        dlfcn.o \
        libgen.o \
-       wchar.o
+       wchar.o \
+       syslog.o
 
 ASM_OBJS = setjmp.ao crti.ao crtn.ao
 

+ 132 - 0
Libraries/LibC/syslog.cpp

@@ -0,0 +1,132 @@
+// Has to be defined before including due to legacy Unices
+#define SYSLOG_NAMES 1
+
+#include <AK/StringBuilder.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+
+// This implementation doesn't talk to a syslog server. Any options related to
+// that are no-ops.
+
+extern "C" {
+
+// For implementation simplicity, we actually only use the re-entrant version
+// of each function, and the version that isn't just redirects with a static
+// struct to share.
+static struct syslog_data global_log_data = {
+    .ident = nullptr,
+    .logopt = 0,
+    .facility = LOG_USER,
+    .maskpri = LOG_UPTO(LOG_DEBUG)
+};
+
+// Used when ident is null, since syslog traditionally prints the program's
+// own name; the process name will always be the same unless we exec.
+static char program_name_buffer[256];
+static bool program_name_set = false;
+
+// Convenience function for initialization and checking what string to use
+// for the program name.
+static const char* get_syslog_ident(struct syslog_data* data)
+{
+    if (!program_name_set && data->ident == nullptr)
+        program_name_set = get_process_name(program_name_buffer, sizeof(program_name_buffer)) >= 0;
+
+    if (data->ident != nullptr)
+        return data->ident;
+    else if (program_name_set)
+        return program_name_buffer;
+
+    ASSERT_NOT_REACHED();
+}
+
+void openlog_r(const char* ident, int logopt, int facility, struct syslog_data* data)
+{
+    data->ident = ident;
+    data->logopt = logopt;
+    data->facility = facility;
+    // default value
+    data->maskpri = LOG_UPTO(LOG_DEBUG);
+    // would be where we connect to a daemon
+}
+
+void openlog(const char* ident, int logopt, int facility)
+{
+    openlog_r(ident, logopt, facility, &global_log_data);
+}
+
+void closelog_r(struct syslog_data* data)
+{
+    // would be where we disconnect from a daemon
+    // restore defaults
+    data->ident = nullptr;
+    data->logopt = 0;
+    data->facility = LOG_USER;
+    data->maskpri = LOG_UPTO(LOG_DEBUG);
+}
+
+void closelog(void)
+{
+    closelog_r(&global_log_data);
+}
+
+int setlogmask_r(int maskpri, struct syslog_data* data)
+{
+    // Remember, this takes the input of LOG_MASK/LOG_UPTO
+    int old_maskpri = data->maskpri;
+    data->maskpri = maskpri;
+    return old_maskpri;
+}
+
+int setlogmask(int maskpri)
+{
+    return setlogmask_r(maskpri, &global_log_data);
+}
+
+void syslog_r(int priority, struct syslog_data* data, const char* message, ...)
+{
+    va_list ap;
+    va_start(ap, message);
+    vsyslog_r(priority, data, message, ap);
+    va_end(ap);
+}
+
+void syslog(int priority, const char* message, ...)
+{
+    va_list ap;
+    va_start(ap, message);
+    vsyslog_r(priority, &global_log_data, message, ap);
+    va_end(ap);
+}
+
+void vsyslog_r(int priority, struct syslog_data* data, const char* message, va_list args)
+{
+    StringBuilder combined;
+
+    int real_priority = LOG_PRI(priority);
+    // Lots of parens, but it just extracts the priority from combo and masks.
+    if (!(data->maskpri & LOG_MASK(real_priority)))
+        return;
+
+    // Some metadata would be consumed by a syslog daemon, if we had one.
+    if (data->logopt & LOG_PID)
+        combined.appendf("%s[%d]: ", get_syslog_ident(data), getpid());
+    else
+        combined.appendf("%s: ", get_syslog_ident(data));
+
+    combined.appendvf(message, args);
+    String combined_string = combined.build();
+
+    if (data->logopt & LOG_CONS)
+        dbgputstr(combined_string.characters(), combined_string.length());
+    if (data->logopt & LOG_PERROR)
+        fputs(combined_string.characters(), stderr);
+}
+
+void vsyslog(int priority, const char* message, va_list args)
+{
+    vsyslog_r(priority, &global_log_data, message, args);
+}
+}

+ 151 - 0
Libraries/LibC/syslog.h

@@ -0,0 +1,151 @@
+#pragma once
+
+#include <stdarg.h>
+
+__BEGIN_DECLS
+
+struct syslog_data {
+    const char* ident;
+    int logopt;
+    int facility;
+    int maskpri;
+};
+
+/* The severity of the message. This is ordered. */
+#define LOG_EMERG   0
+#define LOG_ALERT   1
+#define LOG_CRIT    2
+#define LOG_ERR     3
+#define LOG_WARNING 4
+#define LOG_NOTICE  5
+#define LOG_INFO    6
+#define LOG_DEBUG   7
+
+/* Macros for masking out the priority of a combined priority */
+#define LOG_PRIMASK (7)
+#define LOG_PRI(priority) ((priority) & LOG_PRIMASK)
+
+/*
+ * Many of these facilities don't really make sense anymore, but we keep them
+ * for compatability purposes.
+ */
+#define LOG_KERN     ( 0 << 3)
+#define LOG_USER     ( 1 << 3)
+#define LOG_MAIL     ( 2 << 3)
+#define LOG_DAEMON   ( 3 << 3)
+#define LOG_AUTH     ( 4 << 3)
+#define LOG_SYSLOG   ( 5 << 3)
+#define LOG_LPR      ( 6 << 3) 
+#define LOG_NEWS     ( 7 << 3) 
+#define LOG_UUCP     ( 8 << 3)
+#define LOG_CRON     ( 9 << 3)
+#define LOG_AUTHPRIV (10 << 3)
+#define LOG_FTP      (11 << 3)
+/* glibc and OpenBSD reserve 12..15 for future system usage, we will too */
+#define LOG_LOCAL0   (16 << 3)
+#define LOG_LOCAL1   (17 << 3)
+#define LOG_LOCAL2   (18 << 3)
+#define LOG_LOCAL3   (19 << 3)
+#define LOG_LOCAL4   (20 << 3)
+#define LOG_LOCAL5   (21 << 3)
+#define LOG_LOCAL6   (22 << 3)
+#define LOG_LOCAL7   (23 << 3)
+
+#define LOG_NFACILITIES 24
+
+/* Macros to get the facility from a combined priority. */
+#define LOG_FACMASK (~7)
+#define LOG_FAC(priority) (((priority) & LOG_FACMASK) >> 3)
+
+/* For masking logs, we use these macros with just the priority. */
+#define LOG_MASK(priority) (1 << (priority))
+#define LOG_UPTO(priority) (LOG_MASK(priority) + (LOG_MASK(priority) - 1))
+
+/* Macro to make a combined priority. */
+#define LOG_MAKEPRI(facility, priority) ((facility) | (priority))
+
+/* Include a PID with the message. */
+#define LOG_PID    (1 << 0)
+/* Log on the console. */
+#define LOG_CONS   (1 << 1)
+/* Open the syslogd connection at the first call. (not implemented, default) */
+#define LOG_ODELAY (1 << 2)
+/* Open the syslogd connection immediately. (not implemented) */
+#define LOG_NDELAY (1 << 3)
+/* Log to stderr as well. */
+#define LOG_PERROR (1 << 4)
+
+/* This is useful to have, but has to be stored weirdly for compatibility. */
+#ifdef SYSLOG_NAMES
+/* Used for marking the fallback; some applications check for these defines. */
+#    define INTERNAL_NOPRI 0x10
+#    define INTERNAL_MARK LOG_MAKEPRI(LOG_NFACILITIES << 3, 0)
+
+typedef struct _code {
+    /*
+     * Most Unices define this as char*, but in C++, we have to define it as a
+     * const char* if we want to use string constants.
+     */
+    const char* c_name;
+    int c_val;
+} CODE;
+
+/*
+ * The names we use are the same as what glibc and OpenBSD use. We omit
+ * deprecated values in the hope that no one uses them. Sorted, as well.
+ */
+
+CODE prioritynames[] = {
+    { "alert",   LOG_ALERT },
+    { "crit",    LOG_CRIT },
+    { "debug",   LOG_DEBUG },
+    { "emerg",   LOG_EMERG },
+    { "err",     LOG_ERR },
+    { "info",    LOG_INFO },
+    /* Fallback */
+    { "none",    INTERNAL_NOPRI },
+    { "notice",  LOG_NOTICE },
+    { "warning", LOG_WARNING },
+    { NULL, -1 },
+};
+
+CODE facilitynames[] = {
+    { "auth",     LOG_AUTH },
+    { "authpriv", LOG_AUTHPRIV },
+    { "cron",     LOG_CRON },
+    { "daemon",   LOG_DAEMON },
+    { "ftp",      LOG_FTP },
+    { "kern",     LOG_KERN },
+    { "local0",   LOG_LOCAL0 },
+    { "local1",   LOG_LOCAL1 },
+    { "local2",   LOG_LOCAL2 },
+    { "local3",   LOG_LOCAL3 },
+    { "local4",   LOG_LOCAL4 },
+    { "local5",   LOG_LOCAL5 },
+    { "local6",   LOG_LOCAL6 },
+    { "local7",   LOG_LOCAL7 },
+    { "lpr",      LOG_LPR },
+    { "mail",     LOG_MAIL },
+    /* Fallback */
+    { "mark",     INTERNAL_MARK },
+    { "news",     LOG_NEWS },
+    { "syslog",   LOG_SYSLOG },
+    { "user",     LOG_USER },
+    { "uucp",     LOG_UUCP },
+    { NULL, -1 },
+};
+#endif
+
+/* The re-entrant versions are an OpenBSD extension we also implement. */
+void syslog(int, const char*, ...);
+void syslog_r(int, struct syslog_data*, const char*, ...);
+void vsyslog(int, const char* message, va_list);
+void vsyslog_r(int, struct syslog_data* data, const char* message, va_list);
+void openlog(const char*, int, int);
+void openlog_r(const char*, int, int, struct syslog_data*);
+void closelog(void);
+void closelog_r(struct syslog_data*);
+int setlogmask(int);
+int setlogmask_r(int, struct syslog_data*);
+
+__END_DECLS