From 18c88d124481419a170ea692049fced4e4694619 Mon Sep 17 00:00:00 2001 From: Davin McCall Date: Tue, 20 Mar 2018 19:01:02 +0000 Subject: [PATCH] Add --log-file (-l) option to specify logging to file. The default is to log to the syslog facility. Also in this commit: start logging from the beginning if not system init, rather than waiting for logging service. --- src/dinit.cc | 103 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 68 insertions(+), 35 deletions(-) diff --git a/src/dinit.cc b/src/dinit.cc index b8232e5..06445dc 100644 --- a/src/dinit.cc +++ b/src/dinit.cc @@ -73,7 +73,8 @@ static std::string control_socket_str; static const char *env_file_path = "/etc/dinit/environment"; -static const char *log_socket_path = "/dev/log"; +static const char *log_path = "/dev/log"; +static bool log_is_syslog = true; // if false, log is a file static const char *user_home_path = nullptr; @@ -212,6 +213,16 @@ int dinit_main(int argc, char **argv) return 1; } } + else if (strcmp(argv[i], "--log-file") == 0 || strcmp(argv[i], "-l") == 0) { + if (++i < argc) { + log_path = argv[i]; + log_is_syslog = false; + } + else { + cerr << "dinit: '--log-file' (-l) requires an argument" << endl; + return 1; + } + } else if (strcmp(argv[i], "--help") == 0) { cout << "dinit, an init with dependency management" << endl; cout << " --help display help" << endl; @@ -334,6 +345,10 @@ int dinit_main(int argc, char **argv) // Try to open control socket (may fail due to readonly filesystem) open_control_socket(false); + // Only try to set up the external log now if we aren't the system init. (If we are the + // system init, wait until the log service starts). + if (! am_system_init) setup_external_log(); + #ifdef __linux__ if (am_system_init) { // Disable non-critical kernel output to console @@ -640,46 +655,64 @@ static void close_control_socket() noexcept void setup_external_log() noexcept { if (! external_log_open) { - - const char * saddrname = log_socket_path; - size_t saddrname_len = strlen(saddrname); - uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1; - - struct sockaddr_un * name = static_cast(malloc(sockaddr_size)); - if (name == nullptr) { - log(loglevel_t::ERROR, "Connecting to log socket: out of memory"); - return; - } - - name->sun_family = AF_UNIX; - memcpy(name->sun_path, saddrname, saddrname_len + 1); - - int sockfd = dinit_socket(AF_UNIX, SOCK_DGRAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC); - if (sockfd == -1) { - log(loglevel_t::ERROR, "Error creating log socket: ", strerror(errno)); - free(name); - return; - } - - if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) { - // For EINPROGRESS, connection is still being established; however, we can select on - // the file descriptor so we will be notified when it's ready. In other words we can - // basically use it anyway. - try { - setup_main_log(sockfd, true); + if (log_is_syslog) { + const char * saddrname = log_path; + size_t saddrname_len = strlen(saddrname); + uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + saddrname_len + 1; + + struct sockaddr_un * name = static_cast(malloc(sockaddr_size)); + if (name == nullptr) { + log(loglevel_t::ERROR, "Connecting to log socket: out of memory"); + return; + } + + name->sun_family = AF_UNIX; + memcpy(name->sun_path, saddrname, saddrname_len + 1); + + int sockfd = dinit_socket(AF_UNIX, SOCK_DGRAM, 0, SOCK_NONBLOCK | SOCK_CLOEXEC); + if (sockfd == -1) { + log(loglevel_t::ERROR, "Error creating log socket: ", strerror(errno)); + free(name); + return; } - catch (std::exception &e) { - log(loglevel_t::ERROR, "Setting up log failed: ", e.what()); + + if (connect(sockfd, (struct sockaddr *) name, sockaddr_size) == 0 || errno == EINPROGRESS) { + // For EINPROGRESS, connection is still being established; however, we can select on + // the file descriptor so we will be notified when it's ready. In other words we can + // basically use it anyway. + try { + setup_main_log(sockfd, true); + } + catch (std::exception &e) { + log(loglevel_t::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. close(sockfd); } + + free(name); } else { - // Note if connect fails, we haven't warned at all, because the syslog server might not - // have started yet. - close(sockfd); + // log to file: + int log_fd = open(log_path, O_WRONLY | O_CREAT | O_APPEND | O_NONBLOCK | O_CLOEXEC, 0644); + if (log_fd >= 0) { + try { + setup_main_log(log_fd, false); + } + catch (std::exception &e) { + log(loglevel_t::ERROR, "Setting up log failed: ", e.what()); + close(log_fd); + } + } + else { + // log failure to log? It makes more sense than first appears, because we also log to console: + log(loglevel_t::ERROR, "Setting up log failed: ", strerror(errno)); + } } - - free(name); } } -- 2.25.1