12b77825c8edf58ccb834513667fdfaf444e1e64
[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 <stdlib.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <glib.h>
27 #include <iniparser.h>
28
29 #include "common/mm_resource_manager_utils.h"
30 #include "daemon/mm_resource_manager_daemon_priv.h"
31 #include "daemon/mm_resource_manager_daemon_conf.h"
32 #include "lib/mm_resource_manager.h"
33
34
35
36 #define PID_FILE "/tmp/.mm-res-mgr.pid"
37 #define PID_MSG_LEN     (16)
38
39
40 typedef enum {
41         MM_RESOURCE_MANAGER_DAEMON_NOW,
42         MM_RESOURCE_MANAGER_DAEMON_FAIL,
43         MM_RESOURCE_MANAGER_DAEMON_PARENT,
44 } daemonize_result_e;
45
46
47
48 static GMainLoop *main_loop;
49 static gboolean restart = FALSE;
50 int notify_fd[2];
51
52
53 static gboolean fork_wait(void);
54 static daemonize_result_e daemonize(const char *path);
55 static gboolean init_event(gpointer user_data);
56 static void daemon_loop();
57 static gboolean create_pid_file(void);
58 static gboolean create_ready_file(void);
59 static gboolean create_daemon_setup_file(void);
60 static gboolean remove_pid_file(void);
61 static gboolean remove_ready_file(void);
62 static gboolean remove_daemon_setup_file(void);
63 static int set_signal_handlers();
64 static void terminate_handler(int signum);
65 static void reload_conf_handler(int signum);
66 static void quit_main_loop();
67
68
69
70 static gboolean fork_wait(void)
71 {
72         pid_t pid;
73         int fds[2];
74         char msg[PID_MSG_LEN] = {'\0',};
75
76         MM_RM_RETVM_IF(pipe(fds) == -1, FALSE, "Failed to create pipe to get child status");
77
78         MM_RM_RETVM_IF((pid = fork()) < 0, FALSE, "Daemon fork failed");
79
80         if (pid != 0) {
81                 /* Read in a string from the pipe */
82                 MM_RM_RETVM_IF(read(fds[0], msg, sizeof(msg)) < 0,
83                         FALSE, "Failed to create pipe to get child status");
84
85                 close(fds[0]);
86                 close(fds[1]);
87
88                 /* Parent process closes up output side of pipe */
89                 if (!strcmp(msg, MSG_DONE)) {
90                         MM_RM_DEBUG("Successfully daemonized");
91                         exit(EXIT_SUCCESS);
92                 } else {
93                         MM_RM_ERROR("Daemonizing failed after fork");
94                         exit(EXIT_FAILURE);
95                 }
96         } else if (pid == 0) {
97                 /* Child process closes up input side of pipe */
98                 notify_fd[0] = fds[0];
99                 notify_fd[1] = fds[1];
100         }
101
102         return TRUE;
103 }
104
105 static daemonize_result_e daemonize(const char *path)
106 {
107         MM_RM_RETVM_IF(fork_wait() == FALSE, MM_RESOURCE_MANAGER_DAEMON_FAIL,
108                         "Daemon fork&wait to set waiting until child process of fork actually completes failed");
109
110         umask(0);
111         MM_RM_RETVM_IF(setsid() < 0, MM_RESOURCE_MANAGER_DAEMON_FAIL,
112                         "Daemon cannot set session id");
113         MM_RM_RETVM_IF(chdir(path ? path : "/") < 0,
114                         MM_RESOURCE_MANAGER_DAEMON_FAIL, "Daemon cannot chdir");
115
116         MM_RM_RETVM_IF(
117                         !freopen("/dev/null", "r", stdin) ||
118                         !freopen("/dev/null", "w", stdout) ||
119                         !freopen("/dev/null", "w", stderr),
120                         MM_RESOURCE_MANAGER_DAEMON_FAIL,
121                         "Daemon cannot redirect std streams");
122
123         MM_RM_DEBUG("Daemonize succeeded");
124
125         return MM_RESOURCE_MANAGER_DAEMON_NOW;
126 }
127
128 static gboolean init_event(gpointer user_data)
129 {
130         MM_RM_DEBUG("main loop = %p", main_loop);
131         if (!_mmrm_dmn_init())
132                 g_main_loop_quit(main_loop);
133
134         return G_SOURCE_REMOVE;
135 }
136
137 static void daemon_loop()
138 {
139         guint id = 0;
140
141         do {
142                 restart = FALSE;
143
144                 MM_RM_RETM_IF(!mm_resource_manager_reload_conf(),
145                                 "Daemon cannot reload conf");
146
147                 main_loop = g_main_loop_new(NULL, FALSE);
148                 MM_RM_RETM_IF(main_loop == NULL, "Daemon cannot create main loop");
149
150                 if ((id = g_timeout_add(100, init_event, NULL)) == 0) {
151                         MM_RM_ERROR("Init event cannot be added to main loop");
152                         goto end;
153                 }
154
155                 MM_RM_INFO("Daemon loop [%p] is ran", main_loop);
156                 g_main_loop_run(main_loop);
157                 MM_RM_INFO("Daemon loop end");
158
159 end:
160                 _mmrm_dmn_deinit();
161
162                 g_main_loop_unref(main_loop);
163                 main_loop = NULL;
164
165                 MM_RM_RETM_IF(g_source_remove(id) == FALSE, "Failed to remove %d", id);
166         } while (restart);
167 }
168
169 static gboolean create_pid_file(void)
170 {
171         int fd;
172         struct flock lock;
173         char pid_buf[PID_MSG_LEN] = {'\0',};
174
175         fd = open(PID_FILE, O_WRONLY | O_CREAT, (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
176         MM_RM_RETVM_IF(fd < 0, FALSE, "PID file cannot be created (%d)", errno);
177
178         lock.l_type = F_WRLCK;
179         lock.l_start = 0;
180         lock.l_whence = SEEK_SET;
181         lock.l_len = 1000;
182
183         if (fcntl(fd, F_SETLK, &lock) < 0) {
184                 if (errno != EACCES && errno != EAGAIN)
185                         MM_RM_ERROR("Fail to lock pidfile [%d]", errno);
186                 else
187                         MM_RM_ERROR("process is already running");
188
189                 goto error;
190         }
191
192         if (ftruncate(fd, 0) < 0) {
193                 MM_RM_ERROR("Fail to truncate pidfile [%d]", errno);
194                 goto error;
195         }
196
197         memset(pid_buf, 0, sizeof(pid_buf));
198         snprintf(pid_buf, sizeof(pid_buf), "%u", getpid());
199
200         if (write(fd, pid_buf, strlen(pid_buf)) != (int)strlen(pid_buf)) {
201                 MM_RM_ERROR("Fail to write pid to pidfile [%d]", errno);
202                 goto error;
203         }
204
205         close(fd);
206
207         MM_RM_INFO("PID file (%s) is created", PID_FILE);
208         return TRUE;
209
210 error:
211         close(fd);
212         return FALSE;
213 }
214
215 static gboolean create_ready_file(void)
216 {
217         int fd = -1;
218
219         if ((fd = creat(MM_RESOURCE_MANAGER_READY, 0644)) != -1) {
220                 MM_RM_INFO("ready file(%s) file was created", MM_RESOURCE_MANAGER_READY);
221                 close(fd);
222         } else {
223                 MM_RM_ERROR("cannot create ready file(%s), errno(%d)", MM_RESOURCE_MANAGER_READY, errno);
224                 return FALSE;
225         }
226
227         return TRUE;
228 }
229
230 static gboolean create_daemon_setup_file(void)
231 {
232         return create_pid_file() && create_ready_file();
233 }
234
235 static gboolean remove_pid_file(void)
236 {
237         if (unlink(PID_FILE) != 0) {
238                 LOGE("%s : unlink failed, errno(%d)", PID_FILE, errno);
239                 return FALSE;
240         }
241
242         return TRUE;
243 }
244
245 static gboolean remove_ready_file(void)
246 {
247         if (unlink(MM_RESOURCE_MANAGER_READY) != 0) {
248                 LOGE("%s : unlink failed, errno(%d)", MM_RESOURCE_MANAGER_READY, errno);
249                 return FALSE;
250         }
251
252         return TRUE;
253 }
254
255 static gboolean remove_daemon_setup_file(void)
256 {
257         return remove_pid_file() && remove_ready_file();
258 }
259
260 static int set_signal_handlers()
261 {
262         struct sigaction sa_term;
263         struct sigaction sa_reload_conf;
264         struct sigaction sa_ignore;
265
266         sa_term.sa_handler = terminate_handler;
267         sigemptyset(&sa_term.sa_mask);
268         sa_term.sa_flags = SA_RESETHAND;
269
270         sa_reload_conf.sa_handler = reload_conf_handler;
271         sigemptyset(&sa_reload_conf.sa_mask);
272         sa_reload_conf.sa_flags = 0;
273
274         sa_ignore.sa_handler = SIG_IGN;
275         sigemptyset(&sa_ignore.sa_mask);
276         sa_ignore.sa_flags = 0;
277
278         return sigaction(SIGTERM, &sa_term, NULL) != -1 &&
279                         sigaction(SIGINT, &sa_ignore, NULL) != -1 &&
280                         sigaction(SIGQUIT, &sa_ignore, NULL) != -1 &&
281                         sigaction(SIGHUP, &sa_reload_conf, NULL) != -1;
282 }
283
284 static void terminate_handler(int signum)
285 {
286         MM_RM_DEBUG("SIGTERM is received");
287         quit_main_loop();
288 }
289
290 static void reload_conf_handler(int signum)
291 {
292         MM_RM_DEBUG("SIGHUP is received");
293         restart = TRUE;
294         quit_main_loop();
295 }
296
297 static void quit_main_loop()
298 {
299         if (main_loop) {
300                 _mmrm_dmn_status_callback(MM_RESOURCE_MANAGER_STATUS_DISCONNECTED);
301                 g_main_loop_quit(main_loop);
302         }
303 }
304
305 int main(int argc, char *argv[])
306 {
307         switch (daemonize(NULL)) {
308
309         case MM_RESOURCE_MANAGER_DAEMON_NOW:
310                 MM_RM_RETVM_IF(!set_signal_handlers(), EXIT_FAILURE,
311                                 "Daemon cannot set signal handlers");
312                 MM_RM_RETVM_IF(!create_daemon_setup_file(), EXIT_FAILURE,
313                                 "Daemon cannot create setup file");
314
315                 daemon_loop();
316
317                 MM_RM_RETVM_IF(!remove_daemon_setup_file(), EXIT_FAILURE,
318                                 "Daemon cannot remove setup file");
319
320         case MM_RESOURCE_MANAGER_DAEMON_PARENT:
321                 return EXIT_SUCCESS;
322
323         case MM_RESOURCE_MANAGER_DAEMON_FAIL:
324                 return EXIT_FAILURE;
325         }
326
327         return EXIT_SUCCESS;
328 }