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