Enable logging to syslog. v0.02
authorDavin McCall <davmac@davmac.org>
Sat, 11 Jun 2016 19:38:22 +0000 (20:38 +0100)
committerDavin McCall <davmac@davmac.org>
Sat, 11 Jun 2016 19:38:22 +0000 (20:38 +0100)
src/dinit-log.cc
src/dinit.cc
src/service.cc

index 64767d4ae6430fe75b2a918934e8fe1c8d3c05dd..1ad961c0261f915a004bab37af052af04eb3406c 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <unistd.h>
 #include <fcntl.h>
+#include <sys/syslog.h>
 
 #include "dasync.h"
 
@@ -115,7 +116,7 @@ void BufferedLogStream::flushForRelease()
 Rearm BufferedLogStream::gotEvent(EventLoop_t *loop, int fd, int flags) noexcept
 {
     auto &log_stream = *this;
-
+    
     if ((! partway) && log_stream.special) {
         char * start = log_stream.special_buf + log_stream.msg_index;
         char * end = std::find(log_stream.special_buf + log_stream.msg_index, (char *)nullptr, '\n');
@@ -137,9 +138,8 @@ Rearm BufferedLogStream::gotEvent(EventLoop_t *loop, int fd, int flags) noexcept
                 return Rearm::REARM;
             }
         }
-        else {
-            // spurious readiness, or EAGAIN/EWOULDBLOCK/EINTR
-            // There's not much we can do for other errors anyway.
+        else if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
+            return Rearm::REMOVE;
         }
         return Rearm::REARM;
     }
@@ -148,7 +148,7 @@ Rearm BufferedLogStream::gotEvent(EventLoop_t *loop, int fd, int flags) noexcept
         
         // TODO issue special message if we have discarded a log message
         
-        if (log_stream.current_index == 0) {
+        if (current_index == 0) {
             release_console();
             return Rearm::DISARM;
         }
@@ -181,6 +181,9 @@ Rearm BufferedLogStream::gotEvent(EventLoop_t *loop, int fd, int flags) noexcept
                 }
             }
         }
+        else if (errno != EAGAIN && errno != EINTR && errno != EWOULDBLOCK) {
+            return Rearm::REMOVE;
+        }
     }
     
     // We've written something by the time we get here. We could fall through to below, but
@@ -201,8 +204,8 @@ void init_log(ServiceSet *sset)
 // Potentially throws std::bad_alloc or std::system_error
 void setup_main_log(int fd)
 {
-    log_stream[DLOG_MAIN].init(STDERR_FILENO);
-    log_stream[DLOG_MAIN].registerWith(&eventLoop, STDERR_FILENO, out_events);
+    log_stream[DLOG_MAIN].init(fd);
+    log_stream[DLOG_MAIN].registerWith(&eventLoop, fd, out_events);
 }
 
 bool is_log_flushed() noexcept
@@ -237,7 +240,7 @@ static int sum_length(const char *arg) noexcept
     return std::strlen(arg);
 }
 
-template <typename U, typename ... T> static int sum_length(U first, T ... args) noexcept
+template <typename ... T> static int sum_length(const char * first, T ... args) noexcept
 {
     return sum_length(first) + sum_length(args...);
 }
@@ -248,7 +251,7 @@ static void append(BufferedLogStream &buf, const char *s)
     buf.append(s, std::strlen(s));
 }
 
-template <typename U, typename ... T> static void append(BufferedLogStream &buf, U u, T ... t)
+template <typename ... T> static void append(BufferedLogStream &buf, const char *u, T ... t)
 {
     append(buf, u);
     append(buf, t...);
@@ -289,7 +292,11 @@ template <typename ... T> static void do_log_main(T ... args) noexcept
 {
     log_current_line[DLOG_CONS] = false;
     log_current_line[DLOG_MAIN] = true;
-    push_to_log(args...);
+    
+    char svcbuf[10];
+    snprintf(svcbuf, 10, "<%d> ", LOG_DAEMON | LOG_NOTICE);
+    
+    push_to_log(svcbuf, args...);
 }
 
 // Log a message. A newline will be appended.
@@ -314,12 +321,6 @@ template <typename T> static void do_log_part(int idx, T arg) noexcept
     }
 }
 
-// Log part of a message. A series of calls to do_log_part must be followed by a call to do_log_commit.
-template <typename T> static void do_log_part(T arg) noexcept
-{
-    do_log_part(DLOG_CONS, arg);
-}
-
 // Commit a message that was issued as a series of parts (via do_log_part).
 static void do_log_commit(int idx) noexcept
 {
index 8315af1a8e9c13bdf4db97752687b545159c2fb3..a82f502c69d3f583e4cc75e9cdb91321d31a9384 100644 (file)
@@ -65,15 +65,11 @@ using EventLoop_t = EventLoop<NullMutex>;
 
 EventLoop_t eventLoop = EventLoop_t();
 
-// TODO remove:
-//static void sigint_reboot_cb(struct ev_loop *loop, ev_signal *w, int revents);
-//static void sigquit_cb(struct ev_loop *loop, ev_signal *w, int revents);
-//static void sigterm_cb(struct ev_loop *loop, ev_signal *w, int revents);
 static void sigint_reboot_cb(EventLoop_t *eloop) noexcept;
 static void sigquit_cb(EventLoop_t *eloop) noexcept;
 static void sigterm_cb(EventLoop_t *eloop) noexcept;
-void open_control_socket(EventLoop_t *loop) noexcept;
-void close_control_socket(EventLoop_t *loop) noexcept;
+static void open_control_socket(EventLoop_t *loop) noexcept;
+static void close_control_socket(EventLoop_t *loop) noexcept;
 
 static void control_socket_cb(EventLoop_t *loop, int fd);
 
@@ -106,6 +102,7 @@ static ServiceSet *service_set;
 static bool am_system_init = false; // true if we are the system init process
 
 static bool control_socket_open = false;
+static bool external_log_open = false;
 int active_control_conns = 0;
 
 // Control socket path. We maintain a string (control_socket_str) in case we need
@@ -113,6 +110,8 @@ int active_control_conns = 0;
 static const char *control_socket_path = "/dev/dinitctl";
 static std::string control_socket_str;
 
+static const char *log_socket_path = "/dev/log";
+
 static const char *user_home_path = nullptr;
 
 
@@ -300,7 +299,6 @@ int main(int argc, char **argv)
     }
 
     // Set up signal handlers
-    //ev_signal sigint_ev_signal;
     CallbackSignalHandler sigint_watcher;
     if (am_system_init) {
       sigint_watcher.setCbFunc(sigint_reboot_cb);
@@ -425,7 +423,6 @@ int main(int argc, char **argv)
         
         // PID 1 must not actually exit, although we should never reach this point:
         while (true) {
-            // ev_loop(loop, EVLOOP_ONESHOT);
             eventLoop.run();
         }
     }
@@ -454,7 +451,7 @@ static void control_socket_cb(EventLoop_t *loop, int sockfd)
     }
 }
 
-void open_control_socket(EventLoop_t *loop) noexcept
+static void open_control_socket(EventLoop_t *loop) noexcept
 {
     if (! control_socket_open) {
         const char * saddrname = control_socket_path;
@@ -508,17 +505,14 @@ void open_control_socket(EventLoop_t *loop) noexcept
         }
 
         control_socket_open = true;
-        //ev_io_init(&control_socket_io, control_socket_cb, sockfd, EV_READ);
-        //ev_io_start(loop, &control_socket_io);
         control_socket_io.registerWith(&eventLoop, sockfd, in_events);
     }
 }
 
-void close_control_socket(EventLoop_t *loop) noexcept
+static void close_control_socket(EventLoop_t *loop) noexcept
 {
     if (control_socket_open) {
         int fd = control_socket_io.fd;
-        //ev_io_stop(loop, &control_socket_io);
         control_socket_io.deregisterWatch(&eventLoop);
         close(fd);
         
@@ -527,6 +521,59 @@ void close_control_socket(EventLoop_t *loop) noexcept
     }
 }
 
+static void setup_external_log() noexcept
+{
+    if (! external_log_open) {
+    
+        const char * saddrname = log_socket_path;
+        uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(saddrname) + 1;
+        
+        struct sockaddr_un * name = static_cast<sockaddr_un *>(malloc(sockaddr_size));
+        if (name == nullptr) {
+            log(LogLevel::ERROR, "Connecting to log socket: out of memory");
+            return;
+        }
+        
+        name->sun_family = AF_UNIX;
+        strcpy(name->sun_path, saddrname);
+        
+        int sockfd = socket(AF_UNIX, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0);
+        if (sockfd == -1) {
+            log(LogLevel::ERROR, "Error creating log socket: ", strerror(errno));
+            free(name);
+            return;
+        }
+        
+        if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) {
+            // TODO for EINPROGRESS, set up a watcher so we can properly wait until
+            // connection is established (or fails) before we pass it to the logging subsystem.
+            try {
+                setup_main_log(sockfd);
+            }
+            catch (std::exception &e) {
+                log(LogLevel::ERROR, "Setting up log failed: ", e.what());
+                close(sockfd);
+            }
+        }
+        else {
+            // Note if connect fails, we haven't warned at all, because the syslog server might not
+            // have started yet. TODO, have a special startup flag to indicate when syslog should
+            // be available.
+            close(sockfd);
+        }
+        
+        free(name);
+    }
+}
+
+// Called from service when the system is "rw ready" (filesystem mounted r/w etc).
+// May be called more than once.
+void system_rw_ready() noexcept
+{
+    open_control_socket(&eventLoop);
+    setup_external_log();
+}
+
 /* handle SIGINT signal (generated by kernel when ctrl+alt+del pressed) */
 static void sigint_reboot_cb(EventLoop_t *eloop) noexcept
 {
index 47ba9de25848e436d309278b5597ca9a23887a1b..b3bbf16e5bba5f22c70e37a2e3576d9c8d400305 100644 (file)
@@ -23,7 +23,7 @@
  */
 
 // from dinit.cc:
-void open_control_socket(EventLoop_t *loop) noexcept;
+void system_rw_ready() noexcept;
 extern EventLoop_t eventLoop;
 
 // Find the requested service by name
@@ -558,7 +558,7 @@ void ServiceRecord::started() noexcept
     notifyListeners(ServiceEvent::STARTED);
 
     if (onstart_flags.rw_ready) {
-        open_control_socket(&eventLoop);
+        system_rw_ready();
     }
 
     if (force_stop || desired_state == ServiceState::STOPPED) {