Ignore procfs status changes when pkg_id or app_id is NULL
[platform/core/connectivity/stc-manager.git] / plugin / procfs / stcplugin-procfs.c
1 /*
2  * Copyright (c) 2017 Samsung Electronics Co., Ltd.
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 #include <stdbool.h>
18 #include <unistd.h>
19 #include <string.h>
20 #include <stdlib.h>
21 #include <stdio.h>
22 #include <signal.h>
23 #include <errno.h>
24 #include <sys/socket.h>
25 #include <linux/netlink.h>
26 #include <linux/connector.h>
27 #include <linux/cn_proc.h>
28 #include <glib.h>
29
30 #include "stc-plugin-iface-procfs.h"
31 #include "stc-helper-net-cls.h"
32 #include "stc-helper-procfs.h"
33 #include "stc-helper-nl.h"
34 #include "stc-plugin-monitor.h"
35 #include "stc-plugin-exception.h"
36
37 //LCOV_EXCL_START
38 typedef struct {
39         pid_t pid;
40 } proc_key_s;
41
42 typedef struct {
43         char cmdline[PROC_NAME_MAX];
44         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
45 } proc_value_s;
46
47 typedef struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
48         struct nlmsghdr nl_hdr;
49         struct __attribute__ ((__packed__)) {
50                 struct cn_msg cn_msg;
51                 enum proc_cn_mcast_op cn_mcast;
52         };
53 } nl_connector_msg_s;
54
55 typedef struct __attribute__ ((aligned(NLMSG_ALIGNTO))) {
56         struct nlmsghdr nl_hdr;
57         struct __attribute__ ((__packed__)) {
58                 struct cn_msg cn_msg;
59                 struct proc_event proc_ev;
60         };
61 } nl_connector_proc_event_s;
62
63 static int nl_connector_sock = -1;
64 static guint nl_connector_gsource_id = 0;
65 static GTree *proc_tree;
66
67 static gboolean __process_nl_connector_message(GIOChannel *source,
68                                                GIOCondition condition,
69                                                gpointer user_data);
70
71 static int __proc_tree_key_compare(gconstpointer a, gconstpointer b,
72                                    gpointer UNUSED user_data)
73 {
74         proc_key_s *key_a = (proc_key_s *)a;
75         proc_key_s *key_b = (proc_key_s *)b;
76
77         return key_a->pid - key_b->pid;
78 }
79
80 static void __proc_tree_value_free(gpointer data)
81 {
82         proc_value_s *value = (proc_value_s *)data;
83
84         FREE(value);
85 }
86
87 static void __proc_tree_key_free(gpointer data)
88 {
89         proc_key_s *key = (proc_key_s *)data;
90
91         FREE(key);
92 }
93
94 static proc_value_s * __proc_tree_lookup(const proc_key_s *key)
95 {
96         proc_value_s *lookup;
97
98         if (proc_tree == NULL) {
99                 STC_LOGE("tree is null");
100                 return NULL;
101         }
102
103         lookup = g_tree_lookup(proc_tree, key);
104         return lookup;
105 }
106
107 /*
108 static gboolean __proc_tree_foreach_print(gpointer key, gpointer value,
109                                           gpointer data)
110 {
111         proc_key_s *proc_key = (proc_key_s *)key;
112         proc_value_s *proc_value = (proc_value_s *)value;
113
114         STC_LOGD("Proc pid [\033[1;33m%d\033[0;m] ppid [%s] "
115                 "cmdline [\033[0;34m%s\033[0;m]", proc_key->pid,
116                 proc_value->status[PROC_STATUS_PPID], proc_value->cmdline);
117
118         return FALSE;
119 }
120
121 static void __proc_tree_printall(void)
122 {
123         g_tree_foreach(proc_tree, __proc_tree_foreach_print, NULL);
124 }
125 */
126
127 static proc_value_s * __proc_tree_find_parent(proc_value_s *value)
128 {
129         proc_value_s *parent = NULL;
130         proc_value_s *lookup = value;
131
132         do {
133                 proc_key_s key;
134                 key.pid = atoi(lookup->status[PROC_STATUS_PPID]);
135                 lookup = __proc_tree_lookup(&key);
136                 if (lookup != NULL)
137                         parent = lookup;
138         } while (lookup);
139
140         if (STC_STAT_LOG) {
141                 if (parent != NULL)
142                         STC_LOGD("\033[0;35mPARENT\033[0;m: tgid[\033[1;33m%s\033[0;m] "
143                                 "pid[%s] ppid[%s] cmdline[\033[0;34m%s\033[0;m] name[%s]",
144                                 parent->status[PROC_STATUS_TGID], parent->status[PROC_STATUS_PID],
145                                 parent->status[PROC_STATUS_PPID], parent->cmdline,
146                                 parent->status[PROC_STATUS_NAME]);
147         }
148
149         return parent;
150 }
151
152 stc_error_e stc_plugin_procfs_status_changed(stc_cmd_type_e cmd,
153         pid_t pid,
154         const gchar *app_id,
155         const gchar *pkg_id,
156         stc_app_type_e app_type)
157 {
158         stc_error_e ret = STC_ERROR_NONE;
159
160         if (!pkg_id || !app_id) {
161                 ret = STC_ERROR_INVALID_PARAMETER;
162                 return ret;
163         }
164
165         if ((pkg_id && app_id) && STC_STAT_LOG)
166                 STC_LOGD("cmd[%d] pkgid[%s] appid[%s] pid[%d] type[%d]",
167                         cmd, pkg_id, app_id, pid, app_type);
168
169         switch (cmd) {
170         case STC_CMD_SET_FOREGRD:
171         {
172                 uint32_t fg_classid = STC_UNKNOWN_CLASSID;
173                 uint32_t bg_classid = STC_UNKNOWN_CLASSID;
174                 char *bg_app_id = NULL;
175                 stc_app_value_s app_value;
176                 stc_proc_value_s proc_value;
177
178                 memset(&app_value, 0, sizeof(stc_app_value_s));
179                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
180
181                 bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
182
183                 app_value.type = app_type;
184                 app_value.state = STC_APP_STATE_FOREGROUND;
185                 app_value.processes = NULL;
186
187                 proc_value.pid = pid;
188                 proc_value.ground = STC_APP_STATE_FOREGROUND;
189
190                 bg_classid = get_classid_by_app_id(bg_app_id, FALSE);
191                 fg_classid = get_classid_by_app_id(app_id, TRUE);
192
193                 stc_plugin_monitor_add_app(fg_classid, app_id, pkg_id, app_value);
194
195                 stc_plugin_monitor_move_proc(bg_classid, fg_classid);
196
197                 stc_plugin_monitor_add_proc(fg_classid, app_id, proc_value);
198                 stc_plugin_monitor_update_proc_ground(fg_classid, app_id, proc_value);
199
200                 FREE(bg_app_id);
201                 break;
202         }
203         case STC_CMD_SET_BACKGRD:
204         {
205                 uint32_t bg_classid = STC_UNKNOWN_CLASSID;
206                 uint32_t fg_classid = STC_UNKNOWN_CLASSID;
207                 char *bg_app_id = NULL;
208                 stc_app_value_s app_value;
209                 stc_proc_value_s proc_value;
210
211                 memset(&app_value, 0, sizeof(stc_app_value_s));
212                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
213
214                 bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
215
216                 app_value.type = app_type;
217                 app_value.state = STC_APP_STATE_BACKGROUND;
218                 app_value.processes = NULL;
219
220                 proc_value.pid = pid;
221                 proc_value.ground = STC_APP_STATE_BACKGROUND;
222
223                 fg_classid = get_classid_by_app_id(app_id, FALSE);
224                 bg_classid = get_classid_by_app_id(bg_app_id, TRUE);
225
226                 stc_plugin_monitor_add_app(bg_classid, bg_app_id, pkg_id, app_value);
227
228                 stc_plugin_monitor_move_proc(fg_classid, bg_classid);
229
230                 stc_plugin_monitor_add_proc(bg_classid, bg_app_id, proc_value);
231                 stc_plugin_monitor_update_proc_ground(bg_classid, bg_app_id, proc_value);
232
233                 FREE(bg_app_id);
234                 break;
235         }
236         case STC_CMD_SET_APP_LAUNCHED:
237         {
238                 uint32_t classid = STC_UNKNOWN_CLASSID;
239                 stc_app_value_s app_value;
240                 stc_proc_value_s proc_value;
241
242                 memset(&app_value, 0, sizeof(stc_app_value_s));
243                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
244
245                 classid = get_classid_by_app_id(app_id, FALSE);
246
247                 app_value.type = app_type;
248                 app_value.state = STC_APP_STATE_FOREGROUND;
249                 app_value.processes = NULL;
250
251                 proc_value.pid = pid;
252                 proc_value.ground = STC_APP_STATE_FOREGROUND;
253
254                 stc_plugin_monitor_add_app(classid, app_id, pkg_id, app_value);
255                 stc_plugin_monitor_add_proc(classid, app_id, proc_value);
256
257                 break;
258         }
259         case STC_CMD_SET_SERVICE_LAUNCHED:
260         {
261                 uint32_t classid = STC_UNKNOWN_CLASSID;
262                 char *bg_app_id = NULL;
263                 stc_app_value_s app_value;
264                 stc_proc_value_s proc_value;
265                 gboolean is_exist;
266
267                 memset(&app_value, 0, sizeof(stc_app_value_s));
268                 memset(&proc_value, 0, sizeof(stc_proc_value_s));
269
270                 classid = get_classid_by_app_id(app_id, FALSE);
271                 is_exist = stc_plugin_monitor_lookup_app(classid);
272                 if (is_exist) {
273                         app_value.type = app_type;
274                         app_value.state = STC_APP_STATE_FOREGROUND;
275                         app_value.processes = NULL;
276
277                         proc_value.pid = pid;
278                         proc_value.ground = STC_APP_STATE_FOREGROUND;
279
280                         stc_plugin_monitor_add_app(classid, app_id, pkg_id, app_value);
281                         stc_plugin_monitor_add_proc(classid, app_id, proc_value);
282                 } else {
283                         bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
284                         classid = get_classid_by_app_id(bg_app_id, TRUE);
285
286                         app_value.type = app_type;
287                         app_value.state = STC_APP_STATE_BACKGROUND;
288                         app_value.processes = NULL;
289
290                         proc_value.pid = pid;
291                         proc_value.ground = STC_APP_STATE_BACKGROUND;
292
293                         stc_plugin_monitor_add_app(classid, bg_app_id, pkg_id, app_value);
294                         stc_plugin_monitor_add_proc(classid, bg_app_id, proc_value);
295
296                         FREE(bg_app_id);
297                 }
298                 break;
299         }
300         case STC_CMD_SET_TERMINATED:
301         {
302                 uint32_t classid = STC_UNKNOWN_CLASSID;
303                 char *bg_app_id = NULL;
304
305                 if (app_type == STC_APP_TYPE_NONE) {
306                         bg_app_id = g_strconcat(app_id, STC_BACKGROUND_APP_SUFFIX, NULL);
307                         classid = get_classid_by_app_id(bg_app_id, FALSE);
308                 }
309
310                 if (classid == STC_UNKNOWN_CLASSID)
311                         classid = get_classid_by_app_id(bg_app_id, FALSE);
312
313                 stc_plugin_monitor_remove_proc(classid, pid);
314
315                 FREE(bg_app_id);
316                 break;
317         }
318         default:
319                 STC_LOGE("Unhandled command");
320                 ret = STC_ERROR_INVALID_PARAMETER;
321         }
322
323         return ret;
324 }
325
326 static void __proc_tree_add(proc_key_s *key, proc_value_s *value)
327 {
328         proc_value_s *lookup;
329         proc_value_s *parent;
330
331         if (proc_tree == NULL) {
332                 STC_LOGE("tree is null");
333                 return;
334         }
335
336         if (key == NULL || value == NULL) {
337                 if (STC_STAT_LOG)
338                         STC_LOGE("invalid parameters");
339                 return;
340         }
341
342         lookup = g_tree_lookup(proc_tree, key);
343         if (lookup)
344                 return;
345
346         proc_key_s *proc_key = MALLOC0(proc_key_s, 1);
347         if (proc_key == NULL) {
348                 STC_LOGE("memory allocation failed");
349                 return;
350         }
351
352         proc_value_s *proc_value = MALLOC0(proc_value_s, 1);
353         if (proc_value == NULL) {
354                 STC_LOGE("memory allocation failed");
355                 FREE(proc_key);
356                 return;
357         }
358
359         memcpy(proc_key, key, sizeof(proc_key_s));
360         memcpy(proc_value, value, sizeof(proc_value_s));
361
362         g_tree_insert(proc_tree, proc_key, proc_value);
363
364         /*
365         __proc_tree_printall();
366         */
367
368         parent = __proc_tree_find_parent(proc_value);
369         if (parent != NULL)
370                 stc_plugin_procfs_status_changed(STC_CMD_SET_SERVICE_LAUNCHED, proc_key->pid,
371                         parent->cmdline, parent->cmdline, STC_APP_TYPE_SERVICE);
372         else
373                 stc_plugin_procfs_status_changed(STC_CMD_SET_SERVICE_LAUNCHED, proc_key->pid,
374                         proc_value->cmdline, proc_value->cmdline, STC_APP_TYPE_SERVICE);
375 }
376
377 static void __proc_tree_remove(const proc_key_s *key,
378                                                 const proc_value_s *value)
379 {
380         if (proc_tree == NULL) {
381                 STC_LOGE("tree is null");
382                 return;
383         }
384
385         stc_plugin_procfs_status_changed(STC_CMD_SET_TERMINATED, key->pid,
386                         value->cmdline, value->cmdline, STC_APP_TYPE_NONE);
387
388         g_tree_remove(proc_tree, key);
389
390         /*
391         __proc_tree_printall();
392         */
393 }
394
395 static gboolean __check_excn(char *cmdline)
396 {
397         stc_error_e ret = STC_ERROR_NONE;
398
399         if (cmdline[0] == '(')
400                 return TRUE;
401
402         ret = stc_plugin_check_exception_by_cmdline(cmdline);
403         if (ret == STC_ERROR_UNINITIALIZED ||
404                 ret == STC_ERROR_NO_DATA)
405                 return FALSE;
406         else
407                 return TRUE;
408 }
409
410 static void __open_nl_connector_sock(void)
411 {
412         __STC_LOG_FUNC_ENTER__;
413         GIOChannel *gio = NULL;
414
415         if (nl_connector_sock != -1 &&
416             nl_connector_gsource_id != 0) {
417                 STC_LOGE("Socket is already open");
418                 __STC_LOG_FUNC_EXIT__;
419                 return;
420         }
421
422         if (nl_connector_sock != -1) {
423                 close(nl_connector_sock);
424                 nl_connector_sock = -1;
425         }
426
427         if (nl_connector_gsource_id != 0) {
428                 g_source_remove(nl_connector_gsource_id);
429                 nl_connector_gsource_id = 0;
430         }
431
432         nl_connector_sock = create_netlink(NETLINK_CONNECTOR, CN_IDX_PROC);
433         if (nl_connector_sock == -1) {
434                 __STC_LOG_FUNC_EXIT__;
435                 return;
436         }
437
438         gio = g_io_channel_unix_new(nl_connector_sock);
439         nl_connector_gsource_id =
440                 g_io_add_watch(gio, G_IO_IN | G_IO_ERR | G_IO_HUP,
441                                (GIOFunc) __process_nl_connector_message,
442                                NULL);
443         g_io_channel_unref(gio);
444         __STC_LOG_FUNC_EXIT__;
445 }
446
447 static void __close_nl_connector_sock(void)
448 {
449         __STC_LOG_FUNC_ENTER__;
450         if (nl_connector_sock != -1) {
451                 close(nl_connector_sock);
452                 nl_connector_sock = -1;
453         }
454
455         if (nl_connector_gsource_id != 0) {
456                 g_source_remove(nl_connector_gsource_id);
457                 nl_connector_gsource_id = 0;
458         }
459         __STC_LOG_FUNC_EXIT__;
460 }
461
462 static void __reopen_nl_connector_sock(void)
463 {
464         __close_nl_connector_sock();
465         __open_nl_connector_sock();
466 }
467
468 static void __process_event_fork(int tgid, int pid)
469 {
470         char cmdline[PROC_NAME_MAX] = {0, };
471         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
472
473         /* TODO: Add newly created thread to the process tasks */
474         if (tgid != pid)
475                 return;
476
477         memset(status, 0x0, sizeof(status));
478
479         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
480             STC_ERROR_NONE == proc_get_status(pid, status)) {
481
482                 if (__check_excn(cmdline))
483                         return;
484
485                 unsigned int i;
486                 proc_key_s key;
487                 proc_value_s value;
488
489                 memset(&key, 0x0, sizeof(proc_key_s));
490                 memset(&value, 0x0, sizeof(proc_value_s));
491
492                 key.pid = tgid;
493                 for (i = 0; i < PROC_STATUS_CNT; ++i)
494                         g_strlcpy(value.status[i], status[i], sizeof(value.status[i]));
495                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
496
497                 if (STC_STAT_LOG)
498                         STC_LOGD("\033[1;32mFORK\033[0;m: tgid[\033[1;33m%d\033[0;m] "
499                         "ppid[%s] cmdline[\033[0;34m%s\033[0;m] pid[%d]",
500                         tgid, status[PROC_STATUS_PPID], cmdline, pid);
501
502                 __proc_tree_add(&key, &value);
503         }
504 }
505
506 static void __process_event_exec(int tgid, int pid)
507 {
508         char cmdline[PROC_NAME_MAX] = {0, };
509         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
510
511         /* TODO: Add newly created thread to the process tasks */
512         if (tgid != pid)
513                 return;
514
515         memset(status, 0x0, sizeof(status));
516
517         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
518             STC_ERROR_NONE == proc_get_status(pid, status)) {
519
520                 if (__check_excn(cmdline))
521                         return;
522
523                 unsigned int i;
524                 proc_key_s key;
525                 proc_value_s value;
526
527                 memset(&key, 0x0, sizeof(proc_key_s));
528                 memset(&value, 0x0, sizeof(proc_value_s));
529
530                 key.pid = tgid;
531                 for (i = 0; i < PROC_STATUS_CNT; ++i)
532                         g_strlcpy(value.status[i], status[i],
533                                   sizeof(value.status[i]));
534                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
535
536                 if (STC_STAT_LOG)
537                         STC_LOGD("\033[1;32mEXEC\033[0;m: tgid[\033[1;33m%d\033[0;m] "
538                         "ppid[%s] cmdline[\033[0;34m%s\033[0;m] pid[%d]",
539                         tgid, status[PROC_STATUS_PPID], cmdline, pid);
540
541                 __proc_tree_add(&key, &value);
542         }
543 }
544
545 static void __process_event_exit(int tgid, int pid, int exit_code)
546 {
547         proc_key_s key;
548         proc_value_s *lookup;
549
550         if (tgid != pid)
551                 return;
552
553         key.pid = tgid;
554         lookup = __proc_tree_lookup(&key);
555         if (lookup == NULL) /* unmonitored process */
556                 return;
557
558         if (STC_STAT_LOG)
559                 STC_LOGD("\033[1;31mEXIT\033[0;m: tgid[\033[1;33m%d\033[0;m] "
560                         "cmdline[\033[0;34m%s\033[0;m] pid[%d] exitcode[%d]",
561                         tgid, lookup->cmdline, pid, exit_code);
562
563         __proc_tree_remove(&key, lookup);
564 }
565
566 static gboolean __process_nl_connector_message(GIOChannel *source,
567                                                GIOCondition condition,
568                                                gpointer user_data)
569 {
570         int ret;
571         int sock = g_io_channel_unix_get_fd(source);
572         nl_connector_proc_event_s msg;
573
574         if ((condition & G_IO_ERR) || (condition & G_IO_HUP) ||
575             (condition & G_IO_NVAL)) {
576                 /* G_IO_ERR/G_IO_HUP/G_IO_NVAL received */
577
578                 STC_LOGE("Netlink Connector socket received G_IO event, closing"
579                          " socket. G_IO_ERR [%u], G_IO_HUP [%u], G_IO_NVAL [%u]",
580                          (condition & G_IO_ERR), (condition & G_IO_HUP),
581                          (condition & G_IO_NVAL));
582                 __reopen_nl_connector_sock();
583                 __STC_LOG_FUNC_EXIT__;
584                 return FALSE;
585         }
586
587         memset(&msg, 0, sizeof(nl_connector_proc_event_s));
588
589         ret = read(sock, &msg, sizeof(nl_connector_proc_event_s));
590         if (ret == 0) {
591                 __STC_LOG_FUNC_EXIT__;
592                 return TRUE;
593         }
594
595         switch (msg.proc_ev.what) {
596         case PROC_EVENT_FORK:
597                 __process_event_fork(msg.proc_ev.event_data.fork.child_tgid,
598                                      msg.proc_ev.event_data.fork.child_pid);
599                 break;
600         case PROC_EVENT_EXEC:
601                 __process_event_exec(msg.proc_ev.event_data.exec.process_tgid,
602                                      msg.proc_ev.event_data.exec.process_pid);
603                 break;
604         case PROC_EVENT_EXIT:
605                 __process_event_exit(msg.proc_ev.event_data.exit.process_tgid,
606                                      msg.proc_ev.event_data.exit.process_pid,
607                                      msg.proc_ev.event_data.exit.exit_code);
608                 break;
609         default:
610                 break;
611         }
612
613         return TRUE;
614 }
615
616 static int __subscribe_proc_events(void)
617 {
618         __STC_LOG_FUNC_ENTER__;
619         nl_connector_msg_s msg;
620         int ret;
621         int sock = nl_connector_sock;
622
623         if (sock == -1) {
624                 __STC_LOG_FUNC_EXIT__;
625                 return STC_ERROR_INVALID_PARAMETER;
626         }
627
628         memset(&msg, 0, sizeof(nl_connector_msg_s));
629
630         msg.nl_hdr.nlmsg_len = sizeof(nl_connector_msg_s);
631         msg.nl_hdr.nlmsg_pid = getpid();
632         msg.nl_hdr.nlmsg_type = NLMSG_DONE;
633
634         msg.cn_msg.id.idx = CN_IDX_PROC;
635         msg.cn_msg.id.val = CN_VAL_PROC;
636         msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
637
638         msg.cn_mcast = PROC_CN_MCAST_LISTEN;
639
640         ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
641         if (ret == -1) {
642                 STC_LOGE("Error sending netlink connector message");
643                 __STC_LOG_FUNC_EXIT__;
644                 return STC_ERROR_FAIL;
645         }
646
647         __STC_LOG_FUNC_EXIT__;
648         return STC_ERROR_NONE;
649 }
650
651 static int __unsubscribe_proc_events(void)
652 {
653         __STC_LOG_FUNC_ENTER__;
654         nl_connector_msg_s msg;
655         int ret;
656         int sock = nl_connector_sock;
657
658         if (sock == -1) {
659                 __STC_LOG_FUNC_EXIT__;
660                 return STC_ERROR_INVALID_PARAMETER;
661         }
662
663         memset(&msg, 0, sizeof(nl_connector_msg_s));
664
665         msg.nl_hdr.nlmsg_len = sizeof(nl_connector_msg_s);
666         msg.nl_hdr.nlmsg_pid = getpid();
667         msg.nl_hdr.nlmsg_type = NLMSG_DONE;
668
669         msg.cn_msg.id.idx = CN_IDX_PROC;
670         msg.cn_msg.id.val = CN_VAL_PROC;
671         msg.cn_msg.len = sizeof(enum proc_cn_mcast_op);
672
673         msg.cn_mcast = PROC_CN_MCAST_IGNORE;
674
675         ret = send(sock, &msg, sizeof(nl_connector_msg_s), 0);
676         if (ret == -1) {
677                 STC_LOGE("Error sending netlink connector message");
678                 __STC_LOG_FUNC_EXIT__;
679                 return STC_ERROR_FAIL;
680         }
681
682         __STC_LOG_FUNC_EXIT__;
683         return STC_ERROR_NONE;
684 }
685
686 static bool __process_pid_cb(pid_t pid, void *user_data)
687 {
688         char cmdline[PROC_NAME_MAX] = {0, };
689         char status[PROC_STATUS_CNT][PROC_BUF_MAX];
690
691         memset(status, 0x0, sizeof(status));
692
693         if (STC_ERROR_NONE == proc_get_cmdline(pid, cmdline) &&
694             STC_ERROR_NONE == proc_get_status(pid, status)) {
695
696                 if (__check_excn(cmdline))
697                         return true;
698
699                 unsigned int i;
700                 proc_key_s key;
701                 proc_value_s value;
702
703                 memset(&key, 0x0, sizeof(proc_key_s));
704                 memset(&value, 0x0, sizeof(proc_value_s));
705
706                 key.pid = pid;
707                 for (i = 0; i < PROC_STATUS_CNT; ++i)
708                         g_strlcpy(value.status[i], status[i], sizeof(value.status[i]));
709                 g_strlcpy(value.cmdline, cmdline, sizeof(value.cmdline));
710
711                 __proc_tree_add(&key, &value);
712         }
713
714         return true;
715 }
716
717 int stc_plugin_procfs_initialize(void)
718 {
719         __STC_LOG_FUNC_ENTER__;
720         int ret = STC_ERROR_NONE;
721
722         proc_tree = g_tree_new_full(__proc_tree_key_compare, NULL,
723                                     __proc_tree_key_free,
724                                     __proc_tree_value_free);
725
726         /* TODO: Fill proc tree with current procfs state */
727
728         __open_nl_connector_sock();
729         ret = __subscribe_proc_events();
730
731         __STC_LOG_FUNC_EXIT__;
732         return ret;
733 }
734
735 int stc_plugin_procfs_deinitialize(void)
736 {
737         __STC_LOG_FUNC_ENTER__;
738         int ret = STC_ERROR_NONE;
739
740         if (nl_connector_sock == -1) {
741                 STC_LOGD("socket already closed");
742                 return STC_ERROR_NONE;
743         }
744
745         ret = __unsubscribe_proc_events();
746         __close_nl_connector_sock();
747
748         g_tree_destroy(proc_tree);
749         proc_tree = NULL;
750
751         __STC_LOG_FUNC_EXIT__;
752         return ret;
753 }
754
755 stc_error_e stc_plugin_procfs_load(void)
756 {
757         __STC_LOG_FUNC_ENTER__;
758
759         proc_foreach_pid(__process_pid_cb, NULL);
760
761         __STC_LOG_FUNC_EXIT__;
762         return STC_ERROR_NONE;
763 }
764
765 API stc_plugin_procfs_s stc_plugin_procfs = {
766         .initialize_plugin =
767                 stc_plugin_procfs_initialize,
768         .deinitialize_plugin =
769                 stc_plugin_procfs_deinitialize,
770         .procfs_load =
771                 stc_plugin_procfs_load,
772         .procfs_status_changed =
773                 stc_plugin_procfs_status_changed
774 };
775 //LCOV_EXCL_STOP