remove unused header
[poetteringd.git] / main.c
blob2b8162f245c234c5b65693cc5a0176f6557131ee
1 /*
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
21 #include <errno.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <syslog.h>
26 #include <libdaemon/dfork.h>
28 #include <glib.h>
30 #include "hostnamed.h"
31 #include "timedated.h"
32 #include "systemd.h"
33 #include "utils.h"
35 #define DEFAULT_LEVELS (G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE)
36 #define NCOMPONENTS 3
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 },
55 { NULL }
58 static int
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:
64 return LOG_ERR;
65 case G_LOG_LEVEL_WARNING:
66 return LOG_WARNING;
67 case G_LOG_LEVEL_MESSAGE:
68 return LOG_NOTICE;
69 case G_LOG_LEVEL_INFO:
70 return LOG_INFO;
71 case G_LOG_LEVEL_DEBUG:
72 return LOG_DEBUG;
74 return LOG_NOTICE;
77 static void
78 log_handler (const gchar *log_domain,
79 GLogLevelFlags log_level,
80 const gchar *message,
81 gpointer user_data)
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)
89 return;
91 result = g_string_new (NULL);
92 if (!use_syslog)
93 g_string_append_printf (result, "poetteringd[%lu]: ", (gulong)getpid ());
94 if (log_domain != NULL)
95 g_string_append_printf (result, "%s: ", log_domain);
97 if (!use_syslog)
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: ");
102 break;
103 case G_LOG_LEVEL_WARNING:
104 g_string_append (result, "WARNING: ");
105 break;
106 case G_LOG_LEVEL_MESSAGE:
107 g_string_append (result, "Notice: ");
108 break;
109 case G_LOG_LEVEL_INFO:
110 g_string_append (result, "Info: ");
111 break;
112 case G_LOG_LEVEL_DEBUG:
113 g_string_append (result, "Debug: ");
114 break;
117 if (message != NULL)
118 g_string_append (result, message);
119 else
120 g_string_append (result, "(NULL)");
122 result_data = g_string_free (result, FALSE);
124 if (use_syslog) {
125 openlog ("poetteringd", LOG_PID, LOG_DAEMON);
126 syslog (log_level_to_syslog (log_level), "%s", result_data);
127 } else
128 g_printerr ("%s\n", result_data);
130 g_free (result_data);
133 void
134 poetteringd_exit (int status)
136 GFile *pidfile = NULL;
138 if (!foreground)
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);
145 exit (status);
148 /* This is called each time we successfully grab a bus name when starting up */
149 void
150 poetteringd_component_started ()
152 gchar *pidstring = NULL;
153 GError *err = 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)
161 goto out;
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);
170 if (!foreground)
171 daemon_retval_send (0);
173 started = TRUE;
175 out:
176 G_UNLOCK (components_started);
177 g_clear_object (&pidfile);
178 g_free (pidstring);
181 gint
182 main (gint argc, gchar *argv[])
184 GError *error = NULL;
185 GOptionContext *option_context;
186 GMainLoop *loop = NULL;
187 pid_t pid;
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);
195 return 1;
198 if (print_version) {
199 g_print ("poettingerd %s\n", VERSION);
200 return 0;
203 if (!foreground) {
204 if (daemon_retval_init () < 0) {
205 g_critical ("Failed to create pipe");
206 return 1;
208 if ((pid = daemon_fork ()) < 0) {
209 /* Fork failed */
210 daemon_retval_done ();
211 return 1;
212 } else if (pid) {
213 /* Parent */
214 int ret;
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));
219 return 255;
220 } else if (ret > 0) {
221 g_critical ("Daemon process returned error code %d", ret);
222 return ret;
224 return 0;
226 /* Daemon */
227 use_syslog = TRUE;
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 ();
241 systemd_destroy ();
243 g_clear_error (&error);
244 poetteringd_exit (0);