1ec43989625d638d72d993e66a3170fd0264e0fd
[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 #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                         (void)package_set_fault_info(pkg, util_timestamp(), NULL, NULL);
197                         dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, "", "");
198                         fault_broadcast_info(pkgname, "", "");
199                         DbgFree((char *)pkgname);
200
201                         s_info.fault_mark_count = 0;
202                         clear_log_file(slave);
203                         EINA_LIST_REVERSE_FOREACH_SAFE(s_info.call_list, l, n, info) {
204                                 if (info->slave != slave) {
205                                         continue;
206                                 }
207
208                                 s_info.call_list = eina_list_remove_list(s_info.call_list, l);
209
210                                 DbgFree(info->pkgname);
211                                 DbgFree(info->filename);
212                                 DbgFree(info->func);
213                                 DbgFree(info);
214                         }
215                         return 0;
216                 }
217                 DbgFree((char *)pkgname);
218         }
219
220         /*!
221          * \note
222          * Second step.
223          * Is it secured slave?
224          */
225         pkgname = package_find_by_secured_slave(slave);
226         if (pkgname) {
227                 pkg = package_find(pkgname);
228                 if (pkg) {
229                         (void)package_set_fault_info(pkg, util_timestamp(), NULL, NULL);
230                         dump_fault_info(slave_name(slave), slave_pid(slave), pkgname, "", "");
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
240                                 s_info.call_list = eina_list_remove_list(s_info.call_list, l);
241
242                                 DbgFree(info->pkgname);
243                                 DbgFree(info->filename);
244                                 DbgFree(info->func);
245                                 DbgFree(info);
246                         }
247                         return 0;
248                 }
249         }
250
251         /*!
252          * \note
253          * At last, check the pair of function call and return mark
254          */
255         checked = 0;
256         EINA_LIST_REVERSE_FOREACH_SAFE(s_info.call_list, l, n, info) {
257                 if (info->slave == slave) {
258                         const char *filename;
259                         const char *func;
260
261                         pkg = package_find(info->pkgname);
262                         if (!pkg) {
263                                 ErrPrint("Failed to find a package %s\n", info->pkgname);
264                                 continue;
265                         }
266
267                         filename = info->filename ? info->filename : "";
268                         func = info->func ? info->func : "";
269
270                         if (!checked) {
271                                 (void)package_set_fault_info(pkg, info->timestamp, info->filename, info->func);
272                                 fault_broadcast_info(info->pkgname, info->filename, info->func);
273                         } else {
274                                 DbgPrint("Treated as a false log\n");
275                                 dump_fault_info(
276                                         slave_name(info->slave), slave_pid(info->slave), info->pkgname, filename, func);
277                         }
278
279                         s_info.call_list = eina_list_remove_list(s_info.call_list, l);
280
281                         DbgFree(info->pkgname);
282                         DbgFree(info->filename);
283                         DbgFree(info->func);
284                         DbgFree(info);
285                         checked = 1;
286                 }
287         }
288
289         s_info.fault_mark_count = 0;
290         clear_log_file(slave);
291         return 0;
292 }
293
294 HAPI int fault_func_call(struct slave_node *slave, const char *pkgname, const char *filename, const char *func)
295 {
296         struct fault_info *info;
297
298         info = malloc(sizeof(*info));
299         if (!info) {
300                 return LB_STATUS_ERROR_MEMORY;
301         }
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
344                 if (strcmp(info->pkgname, pkgname)) {
345                         continue;
346                 }
347
348                 if (strcmp(info->filename, filename)) {
349                         continue;
350                 }
351
352                 if (strcmp(info->func, func)) {
353                         continue;
354                 }
355
356                 s_info.call_list = eina_list_remove_list(s_info.call_list, l);
357                 DbgFree(info->filename);
358                 DbgFree(info->pkgname);
359                 DbgFree(info->func);
360                 DbgFree(info);
361
362                 s_info.fault_mark_count--;
363                 return 0;
364         } 
365
366         return LB_STATUS_ERROR_NOT_EXIST;
367 }
368
369 /* End of a file */