Add signal handler for client process
[platform/core/multimedia/mm-resource-manager.git] / src / daemon / mm_resource_manager_daemon.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17
18
19 #include <sys/stat.h>
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"
25
26
27
28
29
30 typedef enum {
31         MM_RESOURCE_MANAGER_DAEMON_NOW,
32         MM_RESOURCE_MANAGER_DAEMON_FAIL,
33         MM_RESOURCE_MANAGER_DAEMON_PARENT,
34 } daemonize_result_e;
35
36
37
38 static GMainLoop *main_loop;
39 static gboolean restart = FALSE;
40 static struct sigaction rm_term_old_action;
41 static struct sigaction rm_int_old_action;
42 static struct sigaction rm_quit_old_action;
43 static struct sigaction rm_hup_old_action;
44 int notify_fd[2];
45
46
47 static gboolean fork_wait(void);
48 static daemonize_result_e daemonize(const char *path);
49 static gboolean init_event(gpointer user_data);
50 static void daemon_loop(void);
51 static gboolean remove_pid_file(void);
52 static gboolean remove_ready_file(void);
53 static gboolean remove_daemon_setup_file(void);
54 static int set_signal_handlers(void);
55 static void terminate_handler(int signo);
56 static void reload_conf_handler(int signo);
57 static void quit_main_loop(void);
58
59
60
61 static gboolean fork_wait(void)
62 {
63         pid_t pid;
64         int fds[2];
65         char msg[PID_MSG_LEN] = {'\0',};
66
67         MM_RM_RETVM_IF(pipe(fds) == -1, FALSE, "Failed to create pipe to get child status");
68
69         MM_RM_RETVM_IF((pid = fork()) < 0, FALSE, "Daemon fork failed");
70
71         if (pid != 0) {
72                 /* Read in a string from the pipe */
73                 MM_RM_RETVM_IF(read(fds[0], msg, sizeof(msg)) < 0,
74                         FALSE, "Failed to create pipe to get child status");
75
76                 close(fds[0]);
77                 close(fds[1]);
78
79                 /* Parent process closes up output side of pipe */
80                 if (!strcmp(msg, MSG_DONE)) {
81                         MM_RM_DEBUG("Successfully daemonized");
82                         exit(EXIT_SUCCESS);
83                 } else {
84                         MM_RM_ERROR("Daemonizing failed after fork");
85                         exit(EXIT_FAILURE);
86                 }
87         } else if (pid == 0) {
88                 /* Child process closes up input side of pipe */
89                 notify_fd[0] = fds[0];
90                 notify_fd[1] = fds[1];
91         }
92
93         return TRUE;
94 }
95
96 static daemonize_result_e daemonize(const char *path)
97 {
98         MM_RM_RETVM_IF(fork_wait() == FALSE, MM_RESOURCE_MANAGER_DAEMON_FAIL,
99                         "Daemon fork&wait to set waiting until child process of fork actually completes failed");
100
101         umask(0);
102         MM_RM_RETVM_IF(setsid() < 0, MM_RESOURCE_MANAGER_DAEMON_FAIL,
103                         "Daemon cannot set session id");
104         MM_RM_RETVM_IF(chdir(path ? path : "/") < 0,
105                         MM_RESOURCE_MANAGER_DAEMON_FAIL, "Daemon cannot chdir");
106
107         MM_RM_RETVM_IF(
108                         !freopen("/dev/null", "r", stdin) ||
109                         !freopen("/dev/null", "w", stdout) ||
110                         !freopen("/dev/null", "w", stderr),
111                         MM_RESOURCE_MANAGER_DAEMON_FAIL,
112                         "Daemon cannot redirect std streams");
113
114         MM_RM_DEBUG("Daemonize succeeded");
115
116         return MM_RESOURCE_MANAGER_DAEMON_NOW;
117 }
118
119 static gboolean init_event(gpointer user_data)
120 {
121         MM_RM_DEBUG("main loop = %p", main_loop);
122         if (!_mmrm_dmn_init())
123                 g_main_loop_quit(main_loop);
124
125         return G_SOURCE_REMOVE;
126 }
127
128 static void daemon_loop(void)
129 {
130         guint id = 0;
131
132         do {
133                 restart = FALSE;
134
135                 MM_RM_RETM_IF(!mm_resource_manager_reload_conf(), "Daemon cannot reload conf");
136
137                 main_loop = g_main_loop_new(NULL, FALSE);
138                 MM_RM_RETM_IF(main_loop == NULL, "Daemon cannot create main loop");
139
140                 if ((id = g_timeout_add(100, init_event, NULL)) == 0) {
141                         MM_RM_ERROR("Init event cannot be added to main loop");
142                         goto end;
143                 }
144
145                 MM_RM_INFO("Daemon loop [%p] is ran", main_loop);
146                 g_main_loop_run(main_loop);
147                 MM_RM_INFO("Daemon loop end");
148
149 end:
150                 _mmrm_dmn_deinit();
151
152                 g_main_loop_unref(main_loop);
153                 main_loop = NULL;
154
155                 MM_RM_RETM_IF(g_source_remove(id) == FALSE, "Failed to remove %d", id);
156         } while (restart);
157 }
158
159 static gboolean remove_pid_file(void)
160 {
161         if (unlink(PID_FILE) != 0) {
162                 LOGE("%s : unlink failed, errno(%d)", PID_FILE, errno);
163                 return FALSE;
164         }
165
166         return TRUE;
167 }
168
169 static gboolean remove_ready_file(void)
170 {
171         if (unlink(MM_RESOURCE_MANAGER_READY) != 0) {
172                 LOGE("%s : unlink failed, errno(%d)", MM_RESOURCE_MANAGER_READY, errno);
173                 return FALSE;
174         }
175
176         return TRUE;
177 }
178
179 static gboolean remove_daemon_setup_file(void)
180 {
181         return remove_pid_file() && remove_ready_file();
182 }
183
184 static int set_signal_handlers(void)
185 {
186         struct sigaction sa_term;
187         struct sigaction sa_reload_conf;
188         struct sigaction sa_ignore;
189
190         sa_term.sa_handler = terminate_handler;
191         sigemptyset(&sa_term.sa_mask);
192         sa_term.sa_flags = SA_RESETHAND;
193
194         sa_reload_conf.sa_handler = reload_conf_handler;
195         sigemptyset(&sa_reload_conf.sa_mask);
196         sa_reload_conf.sa_flags = 0;
197
198         sa_ignore.sa_handler = SIG_IGN;
199         sigemptyset(&sa_ignore.sa_mask);
200         sa_ignore.sa_flags = 0;
201
202         return sigaction(SIGTERM, &sa_term, &rm_term_old_action) != -1
203                         && sigaction(SIGINT, &sa_ignore, &rm_int_old_action) != -1
204                         && sigaction(SIGQUIT, &sa_ignore, &rm_quit_old_action) != -1
205                         && sigaction(SIGHUP, &sa_reload_conf, &rm_hup_old_action) != -1;
206 }
207
208 static void terminate_handler(int signo)
209 {
210         MM_RM_DEBUG("SIGTERM is received");
211         quit_main_loop();
212 }
213
214 static void reload_conf_handler(int signo)
215 {
216         MM_RM_DEBUG("SIGHUP is received");
217         restart = TRUE;
218         quit_main_loop();
219 }
220
221 static void quit_main_loop(void)
222 {
223         if (main_loop) {
224                 _mmrm_dmn_status_callback(MM_RESOURCE_MANAGER_STATUS_DISCONNECTED);
225                 g_main_loop_quit(main_loop);
226         }
227 }
228
229 int main(int argc, char *argv[])
230 {
231         switch (daemonize(NULL)) {
232
233         case MM_RESOURCE_MANAGER_DAEMON_NOW:
234                 MM_RM_RETVM_IF(!set_signal_handlers(), EXIT_FAILURE,
235                                 "Daemon cannot set signal handlers");
236
237                 daemon_loop();
238
239                 MM_RM_RETVM_IF(!remove_daemon_setup_file(), EXIT_FAILURE,
240                                 "Daemon cannot remove setup file");
241
242         case MM_RESOURCE_MANAGER_DAEMON_PARENT:
243                 return EXIT_SUCCESS;
244
245         case MM_RESOURCE_MANAGER_DAEMON_FAIL:
246                 return EXIT_FAILURE;
247         }
248
249         return EXIT_SUCCESS;
250 }