Create server setup file after dbus connection
[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 int notify_fd[2];
41
42
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();
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();
51 static void terminate_handler(int signum);
52 static void reload_conf_handler(int signum);
53 static void quit_main_loop();
54
55
56
57 static gboolean fork_wait(void)
58 {
59         pid_t pid;
60         int fds[2];
61         char msg[PID_MSG_LEN] = {'\0',};
62
63         MM_RM_RETVM_IF(pipe(fds) == -1, FALSE, "Failed to create pipe to get child status");
64
65         MM_RM_RETVM_IF((pid = fork()) < 0, FALSE, "Daemon fork failed");
66
67         if (pid != 0) {
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");
71
72                 close(fds[0]);
73                 close(fds[1]);
74
75                 /* Parent process closes up output side of pipe */
76                 if (!strcmp(msg, MSG_DONE)) {
77                         MM_RM_DEBUG("Successfully daemonized");
78                         exit(EXIT_SUCCESS);
79                 } else {
80                         MM_RM_ERROR("Daemonizing failed after fork");
81                         exit(EXIT_FAILURE);
82                 }
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];
87         }
88
89         return TRUE;
90 }
91
92 static daemonize_result_e daemonize(const char *path)
93 {
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");
96
97         umask(0);
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");
102
103         MM_RM_RETVM_IF(
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");
109
110         MM_RM_DEBUG("Daemonize succeeded");
111
112         return MM_RESOURCE_MANAGER_DAEMON_NOW;
113 }
114
115 static gboolean init_event(gpointer user_data)
116 {
117         MM_RM_DEBUG("main loop = %p", main_loop);
118         if (!_mmrm_dmn_init())
119                 g_main_loop_quit(main_loop);
120
121         return G_SOURCE_REMOVE;
122 }
123
124 static void daemon_loop()
125 {
126         guint id = 0;
127
128         do {
129                 restart = FALSE;
130
131                 MM_RM_RETM_IF(!mm_resource_manager_reload_conf(),
132                                 "Daemon cannot reload conf");
133
134                 main_loop = g_main_loop_new(NULL, FALSE);
135                 MM_RM_RETM_IF(main_loop == NULL, "Daemon cannot create main loop");
136
137                 if ((id = g_timeout_add(100, init_event, NULL)) == 0) {
138                         MM_RM_ERROR("Init event cannot be added to main loop");
139                         goto end;
140                 }
141
142                 MM_RM_INFO("Daemon loop [%p] is ran", main_loop);
143                 g_main_loop_run(main_loop);
144                 MM_RM_INFO("Daemon loop end");
145
146 end:
147                 _mmrm_dmn_deinit();
148
149                 g_main_loop_unref(main_loop);
150                 main_loop = NULL;
151
152                 MM_RM_RETM_IF(g_source_remove(id) == FALSE, "Failed to remove %d", id);
153         } while (restart);
154 }
155
156 static gboolean remove_pid_file(void)
157 {
158         if (unlink(PID_FILE) != 0) {
159                 LOGE("%s : unlink failed, errno(%d)", PID_FILE, errno);
160                 return FALSE;
161         }
162
163         return TRUE;
164 }
165
166 static gboolean remove_ready_file(void)
167 {
168         if (unlink(MM_RESOURCE_MANAGER_READY) != 0) {
169                 LOGE("%s : unlink failed, errno(%d)", MM_RESOURCE_MANAGER_READY, errno);
170                 return FALSE;
171         }
172
173         return TRUE;
174 }
175
176 static gboolean remove_daemon_setup_file(void)
177 {
178         return remove_pid_file() && remove_ready_file();
179 }
180
181 static int set_signal_handlers()
182 {
183         struct sigaction sa_term;
184         struct sigaction sa_reload_conf;
185         struct sigaction sa_ignore;
186
187         sa_term.sa_handler = terminate_handler;
188         sigemptyset(&sa_term.sa_mask);
189         sa_term.sa_flags = SA_RESETHAND;
190
191         sa_reload_conf.sa_handler = reload_conf_handler;
192         sigemptyset(&sa_reload_conf.sa_mask);
193         sa_reload_conf.sa_flags = 0;
194
195         sa_ignore.sa_handler = SIG_IGN;
196         sigemptyset(&sa_ignore.sa_mask);
197         sa_ignore.sa_flags = 0;
198
199         return sigaction(SIGTERM, &sa_term, NULL) != -1 &&
200                         sigaction(SIGINT, &sa_ignore, NULL) != -1 &&
201                         sigaction(SIGQUIT, &sa_ignore, NULL) != -1 &&
202                         sigaction(SIGHUP, &sa_reload_conf, NULL) != -1;
203 }
204
205 static void terminate_handler(int signum)
206 {
207         MM_RM_DEBUG("SIGTERM is received");
208         quit_main_loop();
209 }
210
211 static void reload_conf_handler(int signum)
212 {
213         MM_RM_DEBUG("SIGHUP is received");
214         restart = TRUE;
215         quit_main_loop();
216 }
217
218 static void quit_main_loop()
219 {
220         if (main_loop) {
221                 _mmrm_dmn_status_callback(MM_RESOURCE_MANAGER_STATUS_DISCONNECTED);
222                 g_main_loop_quit(main_loop);
223         }
224 }
225
226 int main(int argc, char *argv[])
227 {
228         switch (daemonize(NULL)) {
229
230         case MM_RESOURCE_MANAGER_DAEMON_NOW:
231                 MM_RM_RETVM_IF(!set_signal_handlers(), EXIT_FAILURE,
232                                 "Daemon cannot set signal handlers");
233
234                 daemon_loop();
235
236                 MM_RM_RETVM_IF(!remove_daemon_setup_file(), EXIT_FAILURE,
237                                 "Daemon cannot remove setup file");
238
239         case MM_RESOURCE_MANAGER_DAEMON_PARENT:
240                 return EXIT_SUCCESS;
241
242         case MM_RESOURCE_MANAGER_DAEMON_FAIL:
243                 return EXIT_FAILURE;
244         }
245
246         return EXIT_SUCCESS;
247 }