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