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