#include <unistd.h>
#include <fcntl.h>
+#include <sys/syslog.h>
#include "dasync.h"
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');
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;
}
// 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;
}
}
}
}
+ 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
// 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
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...);
}
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...);
{
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.
}
}
-// 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
{
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);
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
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;
}
// Set up signal handlers
- //ev_signal sigint_ev_signal;
CallbackSignalHandler sigint_watcher;
if (am_system_init) {
sigint_watcher.setCbFunc(sigint_reboot_cb);
// PID 1 must not actually exit, although we should never reach this point:
while (true) {
- // ev_loop(loop, EVLOOP_ONESHOT);
eventLoop.run();
}
}
}
}
-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;
}
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);
}
}
+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
{