blob: 83dc0c96562c62a114305a96a514f7064133c95d [file] [log] [blame]
Pau Espin Pedrol92016772019-03-18 17:24:34 +01001/* Simple Osmocom System Monitor (osysmon): Support for monitoring through shell commands */
2
3/* (C) 2019 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
4 * All Rights Reserved.
5 * Author: Pau Espin Pedrol <pespin@sysmocom.de>
6 *
7 * SPDX-License-Identifier: GPL-2.0+
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
22 * MA 02110-1301, USA.
23 */
24
25#include <string.h>
26#include <stdio.h>
27#include <errno.h>
28#include <sys/sysinfo.h>
29
30#include <osmocom/vty/vty.h>
31#include <osmocom/vty/command.h>
32
33#include "osysmon.h"
34#include "value_node.h"
35
36/***********************************************************************
37 * Data model
38 ***********************************************************************/
39
40struct osysmon_shellcmd {
41 struct llist_head list;
42 struct {
43 const char *name;
44 const char *cmd;
45 } cfg;
46};
47
48static struct osysmon_shellcmd *osysmon_shellcmd_find(const char *name)
49{
50 struct osysmon_shellcmd *oc;
51
52 llist_for_each_entry(oc, &g_oss->shellcmds, list) {
53 if (!strcmp(oc->cfg.name, name))
54 return oc;
55 }
56 return NULL;
57}
58
59static struct osysmon_shellcmd *osysmon_shellcmd_add(const char *name, const char *cmd)
60{
61 struct osysmon_shellcmd *oc;
62
63 if (osysmon_shellcmd_find(name))
64 return NULL;
65
66 oc = talloc_zero(g_oss, struct osysmon_shellcmd);
67 OSMO_ASSERT(oc);
68 oc->cfg.name = talloc_strdup(oc, name);
69 oc->cfg.cmd = talloc_strdup(oc, cmd);
70 llist_add_tail(&oc->list, &g_oss->shellcmds);
71 return oc;
72}
73
74static void osysmon_shellcmd_destroy(struct osysmon_shellcmd *oc)
75{
76 llist_del(&oc->list);
77 talloc_free(oc);
78}
79
80static void osysmon_shellcmd_run(struct osysmon_shellcmd *oc, struct value_node *parent)
81{
82 char buf[512];
83 FILE *f;
84 char *p = buf;
85 long offset = 0;
86
87 f = popen(oc->cfg.cmd, "r");
88 if (!f) {
89 snprintf(buf, sizeof(buf), "<popen failed (%d)>", errno);
90 value_node_add(parent, oc->cfg.name, buf);
91 return;
92 }
93
94 while ((offset = fread(p, 1, sizeof(buf) - 1 - (p - buf), f)) != 0) {
95 p += offset;
96 *p = '\0';
97 }
98
99 pclose(f);
100
101 if (buf != p) {
102 if (*(p - 1) == '\n') /* Remove final new line if exists */
103 *(p - 1) = '\0';
104 value_node_add(parent, oc->cfg.name, buf);
105 } else {
106 value_node_add(parent, oc->cfg.name, "<EMPTY>");
107 }
108}
109
110/***********************************************************************
111 * VTY
112 ***********************************************************************/
113
114#define CMD_STR "Configure a shell command to be executed\n"
115DEFUN(cfg_shellcmd, cfg_shellcmd_cmd,
116 "shellcmd NAME .TEXT",
117 CMD_STR "Name of this shell command snippet\n" "Command to run\n")
118{
119 struct osysmon_shellcmd *oc;
120 char *concat = argv_concat(argv, argc, 1);
121 oc = osysmon_shellcmd_add(argv[0], concat);
122 talloc_free(concat);
123 if (!oc) {
124 vty_out(vty, "Couldn't add shell cmd, maybe it exists?%s", VTY_NEWLINE);
125 return CMD_WARNING;
126 }
127 return CMD_SUCCESS;
128}
129
130DEFUN(cfg_no_shellcmd, cfg_no_shellcmd_cmd,
131 "no shellcmd NAME",
132 NO_STR CMD_STR "Name of this shell command snippet\n")
133{
134 struct osysmon_shellcmd *oc;
135 oc = osysmon_shellcmd_find(argv[0]);
136 if (!oc) {
137 vty_out(vty, "Cannot find shell cmd for '%s'%s", argv[0], VTY_NEWLINE);
138 return CMD_WARNING;
139 }
140 osysmon_shellcmd_destroy(oc);
141 return CMD_SUCCESS;
142}
143
144
145static void osysmon_shellcmd_vty_init(void)
146{
147 install_element(CONFIG_NODE, &cfg_shellcmd_cmd);
148 install_element(CONFIG_NODE, &cfg_no_shellcmd_cmd);
149}
150
151/***********************************************************************
152 * Runtime Code
153 ***********************************************************************/
154
155/* called once on startup before config file parsing */
156int osysmon_shellcmd_init()
157{
158 osysmon_shellcmd_vty_init();
159 return 0;
160}
161
162/* called periodically */
163int osysmon_shellcmd_poll(struct value_node *parent)
164{
165 struct value_node *vn_file;
166 struct osysmon_shellcmd *oc;
167
Daniel Willmann85d0fb22019-11-07 16:59:15 +0100168 if (llist_empty(&g_oss->shellcmds))
169 return 0;
170
Pau Espin Pedrol92016772019-03-18 17:24:34 +0100171 vn_file = value_node_add(parent, "shellcmd", NULL);
172
173 llist_for_each_entry(oc, &g_oss->shellcmds, list)
174 osysmon_shellcmd_run(oc, vn_file);
175
176 return 0;
177}