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