Update SMACK, Fix a crash of terminating sequence, etc, ...
[apps/livebox/data-provider-master.git] / src / fault_manager.c
1 /*
2  * Copyright 2013  Samsung Electronics Co., Ltd
3  *
4  * Licensed under the Flora License, Version 1.1 (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://floralicense.org/license/
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 #include <stdio.h>
18 #include <string.h>
19 #include <stdlib.h> /* free */
20
21 #include <gio/gio.h>
22
23 #include <Eina.h>
24 #include <packet.h>
25 #include <dlog.h>
26 #include <livebox-errno.h>
27
28 #include "util.h"
29 #include "debug.h"
30 #include "slave_life.h"
31 #include "slave_rpc.h"
32 #include "client_life.h"
33 #include "instance.h"
34 #include "client_rpc.h"
35 #include "package.h"
36 #include "conf.h"
37 #include "critical_log.h"
38
39 static struct info {
40         Eina_List *call_list;
41         int fault_mark_count;
42 } s_info = {
43         .call_list = NULL,
44         .fault_mark_count = 0,
45 };
46
47 struct fault_info {
48         struct slave_node *slave;
49         double timestamp;
50         char *pkgname;
51         char *filename;
52         char *func;
53 };
54
55 HAPI int const fault_is_occured(void)
56 {
57         return s_info.fault_mark_count;
58 }
59
60 static void clear_log_file(struct slave_node *slave)
61 {
62         char filename[BUFSIZ];
63
64         snprintf(filename, sizeof(filename), "%s/slave.%d", SLAVE_LOG_PATH, slave_pid(slave));
65
66         unlink(filename);
67 }
68
69 static char *check_log_file(struct slave_node *slave)
70 {
71         char pkgname[BUFSIZ];
72         const char *pattern = "liblive-";
73         char *ptr;
74         FILE *fp;
75         int i;
76         char filename[BUFSIZ];
77
78         snprintf(filename, sizeof(filename), "%s/slave.%d", SLAVE_LOG_PATH, slave_pid(slave));
79         fp = fopen(filename, "rt");
80         if (!fp) {
81                 ErrPrint("No log file found [%s]\n", strerror(errno));
82                 return NULL;
83         }
84
85         ptr = fgets(pkgname, sizeof(pkgname), fp);
86         if (fclose(fp) != 0)
87                 ErrPrint("fclose: %s\n", strerror(errno));
88         if (ptr != pkgname) {
89                 ErrPrint("Invalid log\n");
90                 return NULL;
91         }
92
93         for (i = 0; pattern[i] && (pattern[i] == pkgname[i]); i++); /*!< Check pattern of filename */
94         if (strlen(pattern) != i) {
95                 ErrPrint("Pattern is not matched: %d\n", i);
96                 return NULL;
97         }
98
99         ptr = pkgname + i;
100         i = strlen(ptr) - 3; /* Skip the ".so" */
101         if (i <= 0 || strcmp(ptr + i, ".so")) {
102                 ErrPrint("Extension is not matched\n");
103                 return NULL;
104         }
105                 
106         ptr[i] = '\0'; /*!< Truncate tailer ".so" */
107         if (unlink(filename) < 0)
108                 ErrPrint("Failed to unlink %s\n", filename);
109
110         return strdup(ptr);
111 }
112
113 HAPI void fault_unicast_info(struct client_node *client, const char *pkgname, const char *filename, const char *func)
114 {
115         struct packet *packet;
116
117         if (!client || !pkgname || !filename || !func)
118                 return;
119
120         packet = packet_create_noack("fault_package", "sss", pkgname, filename, func);
121         if (!packet)
122                 return;
123
124         client_rpc_async_request(client, packet);
125         DbgPrint("Fault package: %s\n", pkgname);
126 }
127
128 HAPI void fault_broadcast_info(const char *pkgname, const char *filename, const char *func)
129 {
130         struct packet *packet;
131
132         packet = packet_create_noack("fault_package", "sss", pkgname, filename, func);
133         if (!packet) {
134                 ErrPrint("Failed to create a param\n");
135                 return;
136         }
137
138         client_broadcast(NULL, packet);
139         DbgPrint("Fault package: %s\n", pkgname);
140 }
141
142 static inline void dump_fault_info(const char *name, pid_t pid, const char *pkgname, const char *filename, const char *funcname)
143 {
144         CRITICAL_LOG("Slavename: %s[%d]\n"      \
145                         "Package: %s\n"         \
146                         "Filename: %s\n"        \
147                         "Funcname: %s\n", name, pid, pkgname, filename, funcname);
148 }
149
150 HAPI int fault_info_set(struct slave_node *slave, const char *pkgname, const char *id, const char *func)
151 {
152         struct pkg_info *pkg;
153         int ret;
154
155         pkg = package_find(pkgname);
156         if (!pkg)
157                 return LB_STATUS_ERROR_NOT_EXIST;
158
159         ret = package_set_fault_info(pkg, util_timestamp(), id, func);
160         if (ret < 0)
161                 return LB_STATUS_ERROR_FAULT;
162
163         dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, id, func);
164         ErrPrint("Set fault %s(%d)\n", !ret ? "Success" : "Failed", ret);
165         fault_broadcast_info(pkgname, id, func);
166
167         /*!
168          * \note
169          * Update statistics
170          */
171         s_info.fault_mark_count++;
172         return LB_STATUS_SUCCESS;
173 }
174
175 HAPI int fault_check_pkgs(struct slave_node *slave)
176 {
177         struct fault_info *info;
178         struct pkg_info *pkg;
179         const char *pkgname;
180         Eina_List *l;
181         Eina_List *n;
182         int checked;
183
184         /*!
185          * \note
186          * First step.
187          * Check the log file
188          */
189         pkgname = (const char *)check_log_file(slave);
190         if (pkgname) {
191                 pkg = package_find(pkgname);
192                 if (pkg) {
193                         int ret;
194                         ret = package_set_fault_info(pkg, util_timestamp(), NULL, NULL);
195                         dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, "", "");
196                         ErrPrint("Set fault %s(%d)\n", !ret ? "Success" : "Failed", ret);
197                         fault_broadcast_info(pkgname, "", "");
198                         DbgFree((char *)pkgname);
199
200                         s_info.fault_mark_count = 0;
201                         clear_log_file(slave);
202                         EINA_LIST_REVERSE_FOREACH_SAFE(s_info.call_list, l, n, info) {
203                                 if (info->slave != slave)
204                                         continue;
205
206                                 s_info.call_list = eina_list_remove_list(s_info.call_list, l);
207
208                                 DbgFree(info->pkgname);
209                                 DbgFree(info->filename);
210                                 DbgFree(info->func);
211                                 DbgFree(info);
212                         }
213                         return 0;
214                 }
215                 DbgFree((char *)pkgname);
216         }
217
218         /*!
219          * \note
220          * Second step.
221          * Is it secured slave?
222          */
223         pkgname = package_find_by_secured_slave(slave);
224         if (pkgname) {
225                 pkg = package_find(pkgname);
226                 if (pkg) {
227                         int ret;
228                         ret = package_set_fault_info(pkg, util_timestamp(), NULL, NULL);
229                         dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, "", "");
230                         ErrPrint("Set fault %s(%d)\n", !ret ? "Success" : "Failed", ret);
231                         fault_broadcast_info(pkgname, "", "");
232
233                         s_info.fault_mark_count = 0;
234                         clear_log_file(slave);
235                         EINA_LIST_REVERSE_FOREACH_SAFE(s_info.call_list, l, n, info) {
236                                 if (info->slave != slave)
237                                         continue;
238
239                                 s_info.call_list = eina_list_remove_list(s_info.call_list, l);
240
241                                 DbgFree(info->pkgname);
242                                 DbgFree(info->filename);
243                                 DbgFree(info->func);
244                                 DbgFree(info);
245                         }
246                         return 0;
247                 }
248         }
249
250         /*!
251          * \note
252          * At last, check the pair of function call and return mark
253          */
254         checked = 0;
255         EINA_LIST_REVERSE_FOREACH_SAFE(s_info.call_list, l, n, info) {
256                 if (info->slave == slave) {
257                         const char *filename;
258                         const char *func;
259
260                         pkg = package_find(info->pkgname);
261                         if (!pkg) {
262                                 ErrPrint("Failed to find a package %s\n", info->pkgname);
263                                 continue;
264                         }
265
266                         filename = info->filename ? info->filename : "";
267                         func = info->func ? info->func : "";
268
269                         if (!checked) {
270                                 int ret;
271                                 ret = package_set_fault_info(pkg, info->timestamp, info->filename, info->func);
272                                 fault_broadcast_info(info->pkgname, info->filename, info->func);
273                                 ErrPrint("Set fault %s(%d)\n", !ret ? "Success" : "Failed", ret);
274                         } else {
275                                 DbgPrint("Treated as a false log\n");
276                                 dump_fault_info(
277                                         slave_name(info->slave), slave_pid(info->slave), info->pkgname, filename, func);
278                         }
279
280                         s_info.call_list = eina_list_remove_list(s_info.call_list, l);
281
282                         DbgFree(info->pkgname);
283                         DbgFree(info->filename);
284                         DbgFree(info->func);
285                         DbgFree(info);
286                         checked = 1;
287                 }
288         }
289
290         s_info.fault_mark_count = 0;
291         clear_log_file(slave);
292         return 0;
293 }
294
295 HAPI int fault_func_call(struct slave_node *slave, const char *pkgname, const char *filename, const char *func)
296 {
297         struct fault_info *info;
298
299         info = malloc(sizeof(*info));
300         if (!info)
301                 return LB_STATUS_ERROR_MEMORY;
302
303         info->slave = slave;
304
305         info->pkgname = strdup(pkgname);
306         if (!info->pkgname) {
307                 DbgFree(info);
308                 return LB_STATUS_ERROR_MEMORY;
309         }
310
311         info->filename = strdup(filename);
312         if (!info->filename) {
313                 DbgFree(info->pkgname);
314                 DbgFree(info);
315                 return LB_STATUS_ERROR_MEMORY;
316         }
317
318         info->func = strdup(func);
319         if (!info->func) {
320                 DbgFree(info->filename);
321                 DbgFree(info->pkgname);
322                 DbgFree(info);
323                 return LB_STATUS_ERROR_MEMORY;
324         }
325
326         info->timestamp = util_timestamp();
327
328         s_info.call_list = eina_list_append(s_info.call_list, info);
329
330         s_info.fault_mark_count++;
331         return LB_STATUS_SUCCESS;
332 }
333
334 HAPI int fault_func_ret(struct slave_node *slave, const char *pkgname, const char *filename, const char *func)
335 {
336         struct fault_info *info;
337         Eina_List *l;
338
339         EINA_LIST_FOREACH(s_info.call_list, l, info) {
340                 if (info->slave != slave)
341                         continue;
342
343                 if (strcmp(info->pkgname, pkgname))
344                         continue;
345
346                 if (strcmp(info->filename, filename))
347                         continue;
348
349                 if (strcmp(info->func, func))
350                         continue;
351
352                 s_info.call_list = eina_list_remove_list(s_info.call_list, l);
353                 DbgFree(info->filename);
354                 DbgFree(info->pkgname);
355                 DbgFree(info->func);
356                 DbgFree(info);
357
358                 s_info.fault_mark_count--;
359                 return 0;
360         } 
361
362         return LB_STATUS_ERROR_NOT_EXIST;
363 }
364
365 /* End of a file */