aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'src/main.c')
-rw-r--r--src/main.c186
1 files changed, 175 insertions, 11 deletions
diff --git a/src/main.c b/src/main.c
index 54eb407..8374218 100644
--- a/src/main.c
+++ b/src/main.c
@@ -16,12 +16,18 @@
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
+#include <syslog.h>
+
+#include <libdaemon/dfork.h>
#include <glib.h>
#include <gio/gio.h>
+#include <rc.h>
+
#include "hostnamed.h"
#include "localed.h"
#include "timedated.h"
@@ -32,26 +38,157 @@
#define DEFAULT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE)
static gboolean debug = FALSE;
+static gboolean foreground = FALSE;
+static gboolean use_syslog = FALSE;
static gboolean read_only = FALSE;
+static gboolean update_rc_status = FALSE;
static gchar *ntp_preferred_service = NULL;
+static guint components_started = 0;
+G_LOCK_DEFINE_STATIC (components_started);
+
+static gboolean started = FALSE;
+
static GOptionEntry option_entries[] =
{
{ "debug", 0, 0, G_OPTION_ARG_NONE, &debug, "Enable debugging messages", NULL },
+ { "foreground", 0, 0, G_OPTION_ARG_NONE, &foreground, "Do not daemonize", NULL },
{ "read-only", 0, 0, G_OPTION_ARG_NONE, &read_only, "Run in read-only mode", NULL },
{ "ntp-service", 0, 0, G_OPTION_ARG_STRING, &ntp_preferred_service, "Preferred rc NTP service for timedated", NULL },
+ { "update-rc-status", 0, 0, G_OPTION_ARG_NONE, &update_rc_status, "Force openrc-settingsd rc service to be marked as started", NULL },
{ NULL }
};
-/* Emulates the new behavior of g_log_default_handler introduced in glib-2.31.2 */
+static int
+log_level_to_syslog (GLogLevelFlags log_level)
+{
+ switch (log_level & G_LOG_LEVEL_MASK) {
+ case G_LOG_LEVEL_ERROR:
+ case G_LOG_LEVEL_CRITICAL:
+ return LOG_ERR;
+ case G_LOG_LEVEL_WARNING:
+ return LOG_WARNING;
+ case G_LOG_LEVEL_MESSAGE:
+ return LOG_NOTICE;
+ case G_LOG_LEVEL_INFO:
+ return LOG_INFO;
+ case G_LOG_LEVEL_DEBUG:
+ return LOG_DEBUG;
+ }
+ return LOG_NOTICE;
+}
+
static void
log_handler (const gchar *log_domain,
GLogLevelFlags log_level,
const gchar *message,
gpointer user_data)
{
- if (debug || log_level & DEFAULT_LEVELS)
- g_log_default_handler (log_domain, log_level, message, user_data);
+ const gchar *debug_domains = NULL;
+ GString *result = NULL;
+ gchar *result_data = NULL;
+
+ debug_domains = g_getenv ("G_MESSAGES_DEBUG");
+ if (!debug && !(log_level & DEFAULT_LEVELS) && g_strcmp0 (debug_domains, "all") && strstr0 (debug_domains, log_domain) == NULL)
+ return;
+
+ result = g_string_new (NULL);
+ if (!use_syslog)
+ g_string_append_printf (result, "openrc-settingsd[%lu]: ", (gulong)getpid ());
+ if (log_domain != NULL)
+ g_string_append_printf (result, "%s: ", log_domain);
+
+ if (!use_syslog)
+ switch (log_level & G_LOG_LEVEL_MASK) {
+ case G_LOG_LEVEL_ERROR:
+ case G_LOG_LEVEL_CRITICAL:
+ g_string_append (result, "ERROR: ");
+ break;
+ case G_LOG_LEVEL_WARNING:
+ g_string_append (result, "WARNING: ");
+ break;
+ case G_LOG_LEVEL_MESSAGE:
+ g_string_append (result, "Notice: ");
+ break;
+ case G_LOG_LEVEL_INFO:
+ g_string_append (result, "Info: ");
+ break;
+ case G_LOG_LEVEL_DEBUG:
+ g_string_append (result, "Debug: ");
+ break;
+ }
+
+ if (message != NULL)
+ g_string_append (result, message);
+ else
+ g_string_append (result, "(NULL)");
+
+ result_data = g_string_free (result, FALSE);
+
+ if (use_syslog) {
+ openlog ("openrc-settingsd", LOG_PID, LOG_DAEMON);
+ syslog (log_level_to_syslog (log_level), "%s", result_data);
+ } else
+ g_printerr ("%s\n", result_data);
+
+ g_free (result_data);
+}
+
+void
+openrc_settingsd_exit (int status)
+{
+ GFile *pidfile = NULL;
+
+ if (!foreground)
+ daemon_retval_send (status);
+
+ pidfile = g_file_new_for_path (PIDFILE);
+ g_file_delete (pidfile, NULL, NULL);
+
+ if (update_rc_status && started) {
+ if (status)
+ rc_service_mark ("openrc-settingsd", RC_SERVICE_FAILED);
+ else
+ rc_service_mark ("openrc-settingsd", RC_SERVICE_STOPPED);
+ }
+
+ g_clear_object (&pidfile);
+ exit (status);
+}
+
+/* This is called each time we successfully grab a bus name when starting up */
+void
+openrc_settingsd_component_started ()
+{
+ gchar *pidstring = NULL;
+ GError *err = NULL;
+ GFile *pidfile = NULL;
+
+ G_LOCK (components_started);
+
+ components_started++;
+ /* We want all 3 names (hostnamed, localed, timedated) to be grabbed */
+ if (components_started < 3)
+ goto out;
+
+ pidfile = g_file_new_for_path (PIDFILE);
+ pidstring = g_strdup_printf ("%lu", (gulong)getpid ());
+ if (!g_file_replace_contents (pidfile, pidstring, strlen(pidstring), NULL, FALSE, G_FILE_CREATE_NONE, NULL, NULL, &err)) {
+ g_critical ("Failed to write " PIDFILE ": %s", err->message);
+ openrc_settingsd_exit (1);
+ }
+
+ if (!foreground)
+ daemon_retval_send (0);
+
+ if (update_rc_status)
+ rc_service_mark ("openrc-settingsd", RC_SERVICE_STARTED);
+ started = TRUE;
+
+ out:
+ G_UNLOCK (components_started);
+ g_clear_object (&pidfile);
+ g_free (pidstring);
}
gint
@@ -60,21 +197,45 @@ main (gint argc, gchar *argv[])
GError *error = NULL;
GOptionContext *option_context;
GMainLoop *loop = NULL;
+ pid_t pid;
g_type_init ();
+ g_log_set_default_handler (log_handler, NULL);
option_context = g_option_context_new ("- system settings D-Bus service for OpenRC");
g_option_context_add_main_entries (option_context, option_entries, NULL);
if (!g_option_context_parse (option_context, &argc, &argv, &error)) {
- g_printerr ("Failed to parse options: %s\n", error->message);
- exit (1);
+ g_critical ("Failed to parse options: %s", error->message);
+ return 1;
}
- if (glib_check_version (2, 31, 2) == NULL) {
- if (debug)
- g_setenv("G_MESSAGES_DEBUG", "all", TRUE);
- } else
- g_log_set_default_handler (log_handler, NULL);
+ if (!foreground) {
+ if (daemon_retval_init () < 0) {
+ g_critical ("Failed to create pipe");
+ return 1;
+ }
+ if ((pid = daemon_fork ()) < 0) {
+ /* Fork failed */
+ daemon_retval_done ();
+ return 1;
+ } else if (pid) {
+ /* Parent */
+ int ret;
+
+ /* Wait 20 seconds for daemon_retval_send() in the daemon process */
+ if ((ret = daemon_retval_wait (20)) < 0) {
+ g_critical ("Timed out waiting for daemon process: %s", strerror(errno));
+ return 255;
+ } else if (ret > 0) {
+ g_critical ("Daemon process returned error code %d", ret);
+ return ret;
+ }
+ return 0;
+ }
+ /* Daemon */
+ use_syslog = TRUE;
+ daemon_close_all (-1);
+ }
utils_init ();
hostnamed_init (read_only);
@@ -84,10 +245,13 @@ main (gint argc, gchar *argv[])
g_main_loop_run (loop);
g_main_loop_unref (loop);
+
timedated_destroy ();
localed_destroy ();
hostnamed_destroy ();
utils_destroy ();
+
+ g_clear_error (&error);
g_free (ntp_preferred_service);
- return 0;
+ openrc_settingsd_exit (0);
}