From 7951278841a9ee7f2a7092a33d32ed9c81b3e753 Mon Sep 17 00:00:00 2001 From: Alexandre Rostovtsev Date: Fri, 7 Sep 2012 06:20:10 -0400 Subject: Add daemonized mode with syslog logging, pid file, and ability to set rc status The ability to set openrc-settingsd's rc status is useful mainly for dbus activation, so a dbus-activated process can be easily stopped via "/etc/init.d/openrc-settingsd stop". --- Makefile.am | 8 +- autogen.sh | 3 +- configure.ac | 7 +- data/init.d/openrc-settingsd.in | 7 +- data/org.freedesktop.hostname1.service.in | 2 +- data/org.freedesktop.locale1.service.in | 2 +- data/org.freedesktop.timedate1.service.in | 2 +- src/hostnamed.c | 12 +- src/localed.c | 12 +- src/main.c | 186 ++++++++++++++++++++++++++++-- src/main.h | 33 ++++++ src/timedated.c | 12 +- src/utils.c | 26 +++-- src/utils.h | 3 + 14 files changed, 266 insertions(+), 49 deletions(-) create mode 100644 src/main.h diff --git a/Makefile.am b/Makefile.am index dde27ad..5b7b0c2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -44,11 +44,9 @@ initd_SCRIPTS = data/init.d/openrc-settingsd confddir = $(sysconfdir)/conf.d dist_confd_DATA = data/conf.d/openrc-settingsd -rootsbindir = @rootsbindir@ - +pidfile = @pidfile@ do_subst = sed -e 's,[@]libexecdir[@],$(libexecdir),g' \ - -e 's,[@]localstatedir[@],$(localstatedir),g' \ - -e 's,[@]rootsbindir[@],$(rootsbindir),g' \ + -e 's,[@]pidfile[@],$(pidfile),g' \ $(NULL) data/init.d/openrc-settingsd : data/init.d/openrc-settingsd.in @@ -63,6 +61,7 @@ AM_CPPFLAGS = \ -DDATADIR=\""$(datadir)"\" \ -DLIBEXECDIR=\""$(libexecdir)"\" \ -DPKGDATADIR=\""$(pkgdatadir)"\" \ + -DPIDFILE=\""$(pidfile)"\" \ $(OPENRC_SETTINGSD_CFLAGS) \ -I$(top_srcdir)/src \ -I$(top_builddir)/src \ @@ -105,6 +104,7 @@ openrc_settingsd_SOURCES = \ src/timedated.h \ src/utils.c \ src/utils.h \ + src/main.h \ src/main.c \ $(NULL) diff --git a/autogen.sh b/autogen.sh index 6383ac1..4f9c076 100755 --- a/autogen.sh +++ b/autogen.sh @@ -3,8 +3,7 @@ autoreconf --install --symlink args="--prefix=/usr \ ---sysconfdir=/etc \ ---localstatedir=/var" +--sysconfdir=/etc" echo echo "----------------------------------------------------------------" diff --git a/configure.ac b/configure.ac index a162912..a7ccb04 100644 --- a/configure.ac +++ b/configure.ac @@ -17,6 +17,7 @@ PKG_CHECK_MODULES(OPENRC_SETTINGSD, glib-2.0 >= 2.30 dbus-1 polkit-gobject-1 + libdaemon openrc]) AC_SUBST(OPENRC_SETTINGSD_CFLAGS) AC_SUBST(OPENRC_SETTINGSD_LIBS) @@ -26,8 +27,8 @@ if test "x$GDBUS_CODEGEN" = x; then AC_MSG_ERROR([Failed to find gdbus-codegen]) fi -AC_ARG_WITH([rootsbindir], AS_HELP_STRING([--with-rootsbindir=DIR], [root /sbin directory @<:@default=/sbin@:>@]), [], [with_rootsbindir=/sbin]) -AC_SUBST([rootsbindir], [$with_rootsbindir]) +AC_ARG_WITH([pidfile], AS_HELP_STRING([--with-pidfile=FILENAME], [pid filename @<:@default=/var/run/openrc-settingsd.pid@:>@]), [], [with_pidfile=/var/run/openrc-settingsd.pid]) +AC_SUBST([pidfile], [$with_pidfile]) AC_MSG_CHECKING([dbus interfaces directory]) dbusinterfacesdir=`$PKG_CONFIG --variable=interfaces_dir dbus-1` @@ -68,7 +69,7 @@ AC_MSG_RESULT([ prefix: ${prefix} sysconfdir: ${sysconfdir} - rootsbindir: ${with_rootsbindir} + pid file: ${with_pidfile} compiler: ${CC} cflags: ${CFLAGS} diff --git a/data/init.d/openrc-settingsd.in b/data/init.d/openrc-settingsd.in index dfdcda8..8db56c5 100755 --- a/data/init.d/openrc-settingsd.in +++ b/data/init.d/openrc-settingsd.in @@ -12,15 +12,14 @@ start() { [ -n "${NTP_SERVICE}" ] && OPENRC_SETTINGSD_OPTS="--ntp-service=${NTP_SERVICE} ${OPENRC_SETTINGSD_OPTS}" ebegin "Starting openrc-settingsd" - start-stop-daemon --start --quiet --pidfile "@localstatedir@/run/openrc-settingsd.pid" \ - --make-pidfile --background "@libexecdir@/openrc-settingsd" -- \ - ${OPENRC_SETTINGSD_OPTS} + start-stop-daemon --start --quiet --pidfile "@pidfile@" \ + "@libexecdir@/openrc-settingsd" -- ${OPENRC_SETTINGSD_OPTS} eend $? } stop() { ebegin "Stopping openrc-settingsd" - start-stop-daemon --stop --quiet --pidfile "@localstatedir@/run/openrc-settingsd.pid" + start-stop-daemon --stop --quiet --pidfile "@pidfile@" eend $? } diff --git a/data/org.freedesktop.hostname1.service.in b/data/org.freedesktop.hostname1.service.in index 0d850f5..56f4a80 100644 --- a/data/org.freedesktop.hostname1.service.in +++ b/data/org.freedesktop.hostname1.service.in @@ -1,4 +1,4 @@ [D-BUS Service] Name=org.freedesktop.hostname1 -Exec=@rootsbindir@/rc-service openrc-settingsd start +Exec=@libexecdir@/openrc-settingsd --update-rc-status User=root \ No newline at end of file diff --git a/data/org.freedesktop.locale1.service.in b/data/org.freedesktop.locale1.service.in index eda463a..1debcbb 100644 --- a/data/org.freedesktop.locale1.service.in +++ b/data/org.freedesktop.locale1.service.in @@ -1,4 +1,4 @@ [D-BUS Service] Name=org.freedesktop.locale1 -Exec=@rootsbindir@/rc-service openrc-settingsd start +Exec=@libexecdir@/openrc-settingsd --update-rc-status User=root \ No newline at end of file diff --git a/data/org.freedesktop.timedate1.service.in b/data/org.freedesktop.timedate1.service.in index 6138b3b..77dd26d 100644 --- a/data/org.freedesktop.timedate1.service.in +++ b/data/org.freedesktop.timedate1.service.in @@ -1,4 +1,4 @@ [D-BUS Service] Name=org.freedesktop.timedate1 -Exec=@rootsbindir@/rc-service openrc-settingsd start +Exec=@libexecdir@/openrc-settingsd --update-rc-status User=root \ No newline at end of file diff --git a/src/hostnamed.c b/src/hostnamed.c index b476cdb..dce16cd 100644 --- a/src/hostnamed.c +++ b/src/hostnamed.c @@ -30,6 +30,7 @@ #include "hostnamed.h" #include "hostname1-generated.h" +#include "main.h" #include "utils.h" #include "config.h" @@ -393,8 +394,8 @@ on_bus_acquired (GDBusConnection *connection, "/org/freedesktop/hostname1", &err)) { if (err != NULL) { - g_printerr ("Failed to export interface on /org/freedesktop/hostname1: %s\n", err->message); - g_error_free (err); + g_critical ("Failed to export interface on /org/freedesktop/hostname1: %s", err->message); + openrc_settingsd_exit (1); } } } @@ -405,6 +406,7 @@ on_name_acquired (GDBusConnection *connection, gpointer user_data) { g_debug ("Acquired the name %s", bus_name); + openrc_settingsd_component_started (); } static void @@ -413,10 +415,10 @@ on_name_lost (GDBusConnection *connection, gpointer user_data) { if (connection == NULL) - g_printerr ("Failed to acquire a dbus connection\n"); + g_critical ("Failed to acquire a dbus connection"); else - g_printerr ("Failed to acquire dbus name %s\n", bus_name); - exit(-1); + g_critical ("Failed to acquire dbus name %s", bus_name); + openrc_settingsd_exit (1); } /* Public functions */ diff --git a/src/localed.c b/src/localed.c index 5eb3f65..efc4a8b 100644 --- a/src/localed.c +++ b/src/localed.c @@ -26,6 +26,7 @@ #include "localed.h" #include "locale1-generated.h" +#include "main.h" #include "utils.h" #include "config.h" @@ -1235,8 +1236,8 @@ on_bus_acquired (GDBusConnection *connection, "/org/freedesktop/locale1", &err)) { if (err != NULL) { - g_printerr ("Failed to export interface on /org/freedesktop/locale1: %s\n", err->message); - g_error_free (err); + g_critical ("Failed to export interface on /org/freedesktop/locale1: %s", err->message); + openrc_settingsd_exit (1); } } } @@ -1247,6 +1248,7 @@ on_name_acquired (GDBusConnection *connection, gpointer user_data) { g_debug ("Acquired the name %s", bus_name); + openrc_settingsd_component_started (); } static void @@ -1255,10 +1257,10 @@ on_name_lost (GDBusConnection *connection, gpointer user_data) { if (connection == NULL) - g_printerr ("Failed to acquire a dbus connection\n"); + g_critical ("Failed to acquire a dbus connection"); else - g_printerr ("Failed to acquire dbus name %s\n", bus_name); - exit(-1); + g_critical ("Failed to acquire dbus name %s", bus_name); + openrc_settingsd_exit (1); } void 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 #include #include +#include + +#include #include #include +#include + #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); } diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..f9a30ea --- /dev/null +++ b/src/main.h @@ -0,0 +1,33 @@ +/* + Copyright 2012 Alexandre Rostovtsev + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be + included in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +*/ + +#ifndef _MAIN_H_ +#define _MAIN_H_ + +void +openrc_settingsd_component_started (); + +void +openrc_settingsd_exit (int status); + +#endif diff --git a/src/timedated.c b/src/timedated.c index 32e9171..4e5939e 100644 --- a/src/timedated.c +++ b/src/timedated.c @@ -30,6 +30,7 @@ #include "copypaste/hwclock.h" #include "timedated.h" #include "timedate1-generated.h" +#include "main.h" #include "utils.h" #include "config.h" @@ -651,8 +652,8 @@ on_bus_acquired (GDBusConnection *connection, "/org/freedesktop/timedate1", &err)) { if (err != NULL) { - g_printerr ("Failed to export interface on /org/freedesktop/timedate1: %s\n", err->message); - g_error_free (err); + g_critical ("Failed to export interface on /org/freedesktop/timedate1: %s", err->message); + openrc_settingsd_exit (1); } } } @@ -663,6 +664,7 @@ on_name_acquired (GDBusConnection *connection, gpointer user_data) { g_debug ("Acquired the name %s", bus_name); + openrc_settingsd_component_started (); } static void @@ -671,10 +673,10 @@ on_name_lost (GDBusConnection *connection, gpointer user_data) { if (connection == NULL) - g_printerr ("Failed to acquire a dbus connection\n"); + g_critical ("Failed to acquire a dbus connection"); else - g_printerr ("Failed to acquire dbus name %s\n", bus_name); - exit(-1); + g_critical ("Failed to acquire dbus name %s", bus_name); + openrc_settingsd_exit (1); } void diff --git a/src/utils.c b/src/utils.c index ba195e5..f76c335 100644 --- a/src/utils.c +++ b/src/utils.c @@ -22,7 +22,11 @@ */ #include +#include #include +#include + +#include #include #include @@ -32,13 +36,13 @@ #include "config.h" -GRegex *indent_regex = NULL; -GRegex *comment_regex = NULL; -GRegex *separator_regex = NULL; -GRegex *var_equals_regex = NULL; -GRegex *single_quoted_regex = NULL; -GRegex *double_quoted_regex = NULL; -GRegex *unquoted_regex = NULL; +static GRegex *indent_regex = NULL; +static GRegex *comment_regex = NULL; +static GRegex *separator_regex = NULL; +static GRegex *var_equals_regex = NULL; +static GRegex *single_quoted_regex = NULL; +static GRegex *double_quoted_regex = NULL; +static GRegex *unquoted_regex = NULL; /* Always returns TRUE */ gboolean @@ -51,6 +55,14 @@ _g_match_info_clear (GMatchInfo **match_info) return TRUE; } +gchar * +strstr0 (const gchar *haystack, const gchar *needle) +{ + if (haystack == NULL || needle == NULL) + return NULL; + return strstr (haystack, needle); +} + struct check_polkit_data { const gchar *unique_name; const gchar *action_id; diff --git a/src/utils.h b/src/utils.h index d0d36fe..f431387 100644 --- a/src/utils.h +++ b/src/utils.h @@ -40,6 +40,9 @@ struct _ShellParser gboolean _g_match_info_clear (GMatchInfo **match_info); +gchar * +strstr0 (const char *haystack, const char *needle); + void check_polkit_async (const gchar *unique_name, const gchar *action_id, -- cgit v1.2.3-65-gdbad