/* Simple Osmocom System Monitor (osysmon): Support for monitoring through shell commands */ /* (C) 2019 by sysmocom - s.f.m.c. GmbH * All Rights Reserved. * Author: Pau Espin Pedrol * * SPDX-License-Identifier: GPL-2.0+ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include #include #include #include #include #include #include "osysmon.h" #include "value_node.h" /*********************************************************************** * Data model ***********************************************************************/ struct osysmon_shellcmd { struct llist_head list; struct { const char *name; const char *cmd; } cfg; }; static struct osysmon_shellcmd *osysmon_shellcmd_find(const char *name) { struct osysmon_shellcmd *oc; llist_for_each_entry(oc, &g_oss->shellcmds, list) { if (!strcmp(oc->cfg.name, name)) return oc; } return NULL; } static struct osysmon_shellcmd *osysmon_shellcmd_add(const char *name, const char *cmd) { struct osysmon_shellcmd *oc; if (osysmon_shellcmd_find(name)) return NULL; oc = talloc_zero(g_oss, struct osysmon_shellcmd); OSMO_ASSERT(oc); oc->cfg.name = talloc_strdup(oc, name); oc->cfg.cmd = talloc_strdup(oc, cmd); llist_add_tail(&oc->list, &g_oss->shellcmds); return oc; } static void osysmon_shellcmd_destroy(struct osysmon_shellcmd *oc) { llist_del(&oc->list); talloc_free(oc); } static void osysmon_shellcmd_run(struct osysmon_shellcmd *oc, struct value_node *parent) { char buf[512]; FILE *f; char *p = buf; long offset = 0; f = popen(oc->cfg.cmd, "r"); if (!f) { snprintf(buf, sizeof(buf), "", errno); value_node_add(parent, oc->cfg.name, buf); return; } while ((offset = fread(p, 1, sizeof(buf) - 1 - (p - buf), f)) != 0) { p += offset; *p = '\0'; } pclose(f); if (buf != p) { if (*(p - 1) == '\n') /* Remove final new line if exists */ *(p - 1) = '\0'; value_node_add(parent, oc->cfg.name, buf); } else { value_node_add(parent, oc->cfg.name, ""); } } /*********************************************************************** * VTY ***********************************************************************/ #define CMD_STR "Configure a shell command to be executed\n" DEFUN(cfg_shellcmd, cfg_shellcmd_cmd, "shellcmd NAME .TEXT", CMD_STR "Name of this shell command snippet\n" "Command to run\n") { struct osysmon_shellcmd *oc; char *concat = argv_concat(argv, argc, 1); oc = osysmon_shellcmd_add(argv[0], concat); talloc_free(concat); if (!oc) { vty_out(vty, "Couldn't add shell cmd, maybe it exists?%s", VTY_NEWLINE); return CMD_WARNING; } return CMD_SUCCESS; } DEFUN(cfg_no_shellcmd, cfg_no_shellcmd_cmd, "no shellcmd NAME", NO_STR CMD_STR "Name of this shell command snippet\n") { struct osysmon_shellcmd *oc; oc = osysmon_shellcmd_find(argv[0]); if (!oc) { vty_out(vty, "Cannot find shell cmd for '%s'%s", argv[0], VTY_NEWLINE); return CMD_WARNING; } osysmon_shellcmd_destroy(oc); return CMD_SUCCESS; } static void osysmon_shellcmd_vty_init(void) { install_element(CONFIG_NODE, &cfg_shellcmd_cmd); install_element(CONFIG_NODE, &cfg_no_shellcmd_cmd); } /*********************************************************************** * Runtime Code ***********************************************************************/ /* called once on startup before config file parsing */ int osysmon_shellcmd_init() { osysmon_shellcmd_vty_init(); return 0; } /* called periodically */ int osysmon_shellcmd_poll(struct value_node *parent) { struct value_node *vn_file; struct osysmon_shellcmd *oc; vn_file = value_node_add(parent, "shellcmd", NULL); llist_for_each_entry(oc, &g_oss->shellcmds, list) osysmon_shellcmd_run(oc, vn_file); return 0; }