2 * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
20 #include <iniparser.h>
21 #include "common/mm_resource_manager_utils.h"
22 #include "daemon/mm_resource_manager_daemon_priv.h"
23 #include "daemon/mm_resource_manager_daemon_conf.h"
24 #include "lib/mm_resource_manager.h"
31 MM_RESOURCE_MANAGER_DAEMON_NOW,
32 MM_RESOURCE_MANAGER_DAEMON_FAIL,
33 MM_RESOURCE_MANAGER_DAEMON_PARENT,
38 static GMainLoop *main_loop;
39 static gboolean restart = FALSE;
43 static gboolean fork_wait(void);
44 static daemonize_result_e daemonize(const char *path);
45 static gboolean init_event(gpointer user_data);
46 static void daemon_loop(void);
47 static gboolean remove_pid_file(void);
48 static gboolean remove_ready_file(void);
49 static gboolean remove_daemon_setup_file(void);
50 static int set_signal_handlers(void);
51 static void terminate_handler(int signum);
52 static void reload_conf_handler(int signum);
53 static void quit_main_loop(void);
57 static gboolean fork_wait(void)
61 char msg[PID_MSG_LEN] = {'\0',};
63 MM_RM_RETVM_IF(pipe(fds) == -1, FALSE, "Failed to create pipe to get child status");
65 MM_RM_RETVM_IF((pid = fork()) < 0, FALSE, "Daemon fork failed");
68 /* Read in a string from the pipe */
69 MM_RM_RETVM_IF(read(fds[0], msg, sizeof(msg)) < 0,
70 FALSE, "Failed to create pipe to get child status");
75 /* Parent process closes up output side of pipe */
76 if (!strcmp(msg, MSG_DONE)) {
77 MM_RM_DEBUG("Successfully daemonized");
80 MM_RM_ERROR("Daemonizing failed after fork");
83 } else if (pid == 0) {
84 /* Child process closes up input side of pipe */
85 notify_fd[0] = fds[0];
86 notify_fd[1] = fds[1];
92 static daemonize_result_e daemonize(const char *path)
94 MM_RM_RETVM_IF(fork_wait() == FALSE, MM_RESOURCE_MANAGER_DAEMON_FAIL,
95 "Daemon fork&wait to set waiting until child process of fork actually completes failed");
98 MM_RM_RETVM_IF(setsid() < 0, MM_RESOURCE_MANAGER_DAEMON_FAIL,
99 "Daemon cannot set session id");
100 MM_RM_RETVM_IF(chdir(path ? path : "/") < 0,
101 MM_RESOURCE_MANAGER_DAEMON_FAIL, "Daemon cannot chdir");
104 !freopen("/dev/null", "r", stdin) ||
105 !freopen("/dev/null", "w", stdout) ||
106 !freopen("/dev/null", "w", stderr),
107 MM_RESOURCE_MANAGER_DAEMON_FAIL,
108 "Daemon cannot redirect std streams");
110 MM_RM_DEBUG("Daemonize succeeded");
112 return MM_RESOURCE_MANAGER_DAEMON_NOW;
115 static gboolean init_event(gpointer user_data)
117 MM_RM_DEBUG("main loop = %p", main_loop);
118 if (!_mmrm_dmn_init())
119 g_main_loop_quit(main_loop);
121 return G_SOURCE_REMOVE;
124 static void daemon_loop(void)
131 MM_RM_RETM_IF(!mm_resource_manager_reload_conf(), "Daemon cannot reload conf");
133 main_loop = g_main_loop_new(NULL, FALSE);
134 MM_RM_RETM_IF(main_loop == NULL, "Daemon cannot create main loop");
136 if ((id = g_timeout_add(100, init_event, NULL)) == 0) {
137 MM_RM_ERROR("Init event cannot be added to main loop");
141 MM_RM_INFO("Daemon loop [%p] is ran", main_loop);
142 g_main_loop_run(main_loop);
143 MM_RM_INFO("Daemon loop end");
148 g_main_loop_unref(main_loop);
151 MM_RM_RETM_IF(g_source_remove(id) == FALSE, "Failed to remove %d", id);
155 static gboolean remove_pid_file(void)
157 if (unlink(PID_FILE) != 0) {
158 LOGE("%s : unlink failed, errno(%d)", PID_FILE, errno);
165 static gboolean remove_ready_file(void)
167 if (unlink(MM_RESOURCE_MANAGER_READY) != 0) {
168 LOGE("%s : unlink failed, errno(%d)", MM_RESOURCE_MANAGER_READY, errno);
175 static gboolean remove_daemon_setup_file(void)
177 return remove_pid_file() && remove_ready_file();
180 static int set_signal_handlers(void)
182 struct sigaction sa_term;
183 struct sigaction sa_reload_conf;
184 struct sigaction sa_ignore;
186 sa_term.sa_handler = terminate_handler;
187 sigemptyset(&sa_term.sa_mask);
188 sa_term.sa_flags = SA_RESETHAND;
190 sa_reload_conf.sa_handler = reload_conf_handler;
191 sigemptyset(&sa_reload_conf.sa_mask);
192 sa_reload_conf.sa_flags = 0;
194 sa_ignore.sa_handler = SIG_IGN;
195 sigemptyset(&sa_ignore.sa_mask);
196 sa_ignore.sa_flags = 0;
198 return sigaction(SIGTERM, &sa_term, NULL) != -1 &&
199 sigaction(SIGINT, &sa_ignore, NULL) != -1 &&
200 sigaction(SIGQUIT, &sa_ignore, NULL) != -1 &&
201 sigaction(SIGHUP, &sa_reload_conf, NULL) != -1;
204 static void terminate_handler(int signum)
206 MM_RM_DEBUG("SIGTERM is received");
210 static void reload_conf_handler(int signum)
212 MM_RM_DEBUG("SIGHUP is received");
217 static void quit_main_loop(void)
220 _mmrm_dmn_status_callback(MM_RESOURCE_MANAGER_STATUS_DISCONNECTED);
221 g_main_loop_quit(main_loop);
225 int main(int argc, char *argv[])
227 switch (daemonize(NULL)) {
229 case MM_RESOURCE_MANAGER_DAEMON_NOW:
230 MM_RM_RETVM_IF(!set_signal_handlers(), EXIT_FAILURE,
231 "Daemon cannot set signal handlers");
234 setenv("GCOV_PREFIX", "/tmp", 1);
239 MM_RM_RETVM_IF(!remove_daemon_setup_file(), EXIT_FAILURE,
240 "Daemon cannot remove setup file");
242 case MM_RESOURCE_MANAGER_DAEMON_PARENT:
245 case MM_RESOURCE_MANAGER_DAEMON_FAIL: