2 Copyright 2020 Robert Nagy
4 Copyright 2012 Alexandre Rostovtsev
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 #include <libdaemon/dfork.h>
30 #include "hostnamed.h"
31 #include "timedated.h"
35 #define DEFAULT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE)
38 static gboolean debug
= FALSE
;
39 static gboolean foreground
= FALSE
;
40 static gboolean use_syslog
= FALSE
;
41 static gboolean read_only
= FALSE
;
42 static gboolean print_version
= FALSE
;
44 static guint components_started
= 0;
45 G_LOCK_DEFINE_STATIC (components_started
);
47 static gboolean started
= FALSE
;
49 static GOptionEntry option_entries
[] =
51 { "debug", 'd', 0, G_OPTION_ARG_NONE
, &debug
, "Enable debugging messages", NULL
},
52 { "foreground", 'f', 0, G_OPTION_ARG_NONE
, &foreground
, "Do not daemonize", NULL
},
53 { "read-only", 'r', 0, G_OPTION_ARG_NONE
, &read_only
, "Run in read-only mode", NULL
},
54 { "version", 'v', 0, G_OPTION_ARG_NONE
, &print_version
, "Show version information", NULL
},
59 log_level_to_syslog (GLogLevelFlags log_level
)
61 switch (log_level
& G_LOG_LEVEL_MASK
) {
62 case G_LOG_LEVEL_ERROR
:
63 case G_LOG_LEVEL_CRITICAL
:
65 case G_LOG_LEVEL_WARNING
:
67 case G_LOG_LEVEL_MESSAGE
:
69 case G_LOG_LEVEL_INFO
:
71 case G_LOG_LEVEL_DEBUG
:
78 log_handler (const gchar
*log_domain
,
79 GLogLevelFlags log_level
,
83 const gchar
*debug_domains
= NULL
;
84 GString
*result
= NULL
;
85 gchar
*result_data
= NULL
;
87 debug_domains
= g_getenv ("G_MESSAGES_DEBUG");
88 if (!debug
&& !(log_level
& DEFAULT_LEVELS
) && g_strcmp0 (debug_domains
, "all") && strstr0 (debug_domains
, log_domain
) == NULL
)
91 result
= g_string_new (NULL
);
93 g_string_append_printf (result
, "poetteringd[%lu]: ", (gulong
)getpid ());
94 if (log_domain
!= NULL
)
95 g_string_append_printf (result
, "%s: ", log_domain
);
98 switch (log_level
& G_LOG_LEVEL_MASK
) {
99 case G_LOG_LEVEL_ERROR
:
100 case G_LOG_LEVEL_CRITICAL
:
101 g_string_append (result
, "ERROR: ");
103 case G_LOG_LEVEL_WARNING
:
104 g_string_append (result
, "WARNING: ");
106 case G_LOG_LEVEL_MESSAGE
:
107 g_string_append (result
, "Notice: ");
109 case G_LOG_LEVEL_INFO
:
110 g_string_append (result
, "Info: ");
112 case G_LOG_LEVEL_DEBUG
:
113 g_string_append (result
, "Debug: ");
118 g_string_append (result
, message
);
120 g_string_append (result
, "(NULL)");
122 result_data
= g_string_free (result
, FALSE
);
125 openlog ("poetteringd", LOG_PID
, LOG_DAEMON
);
126 syslog (log_level_to_syslog (log_level
), "%s", result_data
);
128 g_printerr ("%s\n", result_data
);
130 g_free (result_data
);
134 poetteringd_exit (int status
)
136 GFile
*pidfile
= NULL
;
139 daemon_retval_send (status
);
141 pidfile
= g_file_new_for_path (PIDFILE
);
142 g_file_delete (pidfile
, NULL
, NULL
);
144 g_clear_object (&pidfile
);
148 /* This is called each time we successfully grab a bus name when starting up */
150 poetteringd_component_started ()
152 gchar
*pidstring
= NULL
;
154 GFile
*pidfile
= NULL
;
156 G_LOCK (components_started
);
158 components_started
++;
159 /* We want all component names (hostnamed, localed, timedated) to be grabbed */
160 if (components_started
< NCOMPONENTS
)
163 pidfile
= g_file_new_for_path (PIDFILE
);
164 pidstring
= g_strdup_printf ("%lu", (gulong
)getpid ());
165 if (!g_file_replace_contents (pidfile
, pidstring
, strlen(pidstring
), NULL
, FALSE
, G_FILE_CREATE_NONE
, NULL
, NULL
, &err
)) {
166 g_critical ("Failed to write " PIDFILE
": %s", err
->message
);
167 poetteringd_exit (1);
171 daemon_retval_send (0);
176 G_UNLOCK (components_started
);
177 g_clear_object (&pidfile
);
182 main (gint argc
, gchar
*argv
[])
184 GError
*error
= NULL
;
185 GOptionContext
*option_context
;
186 GMainLoop
*loop
= NULL
;
189 g_log_set_default_handler (log_handler
, NULL
);
191 option_context
= g_option_context_new ("- systemd-ish D-Bus service");
192 g_option_context_add_main_entries (option_context
, option_entries
, NULL
);
193 if (!g_option_context_parse (option_context
, &argc
, &argv
, &error
)) {
194 g_critical ("Failed to parse options: %s", error
->message
);
199 g_print ("poettingerd %s\n", VERSION
);
204 if (daemon_retval_init () < 0) {
205 g_critical ("Failed to create pipe");
208 if ((pid
= daemon_fork ()) < 0) {
210 daemon_retval_done ();
216 /* Wait 20 seconds for daemon_retval_send() in the daemon process */
217 if ((ret
= daemon_retval_wait (20)) < 0) {
218 g_critical ("Timed out waiting for daemon process: %s", strerror(errno
));
220 } else if (ret
> 0) {
221 g_critical ("Daemon process returned error code %d", ret
);
228 daemon_close_all (-1);
231 hostnamed_init (read_only
);
232 timedated_init (read_only
);
233 systemd_init (read_only
);
234 loop
= g_main_loop_new (NULL
, FALSE
);
235 g_main_loop_run (loop
);
237 g_main_loop_unref (loop
);
239 timedated_destroy ();
240 hostnamed_destroy ();
243 g_clear_error (&error
);
244 poetteringd_exit (0);