Browse Source

plugins: Add first empty plugin

Serj Kalichev 3 years ago
parent
commit
254f216120

+ 2 - 0
Makefile.am

@@ -26,10 +26,12 @@ noinst_HEADERS =
 EXTRA_DIST =
 	klish/Makefile.am \
 	dbs/Makefile.am \
+	plugins/Makefile.am \
 	bin/Makefile.am
 
 include $(top_srcdir)/klish/Makefile.am
 include $(top_srcdir)/dbs/Makefile.am
+include $(top_srcdir)/plugins/Makefile.am
 include $(top_srcdir)/bin/Makefile.am
 
 define CONTROL

+ 1 - 0
klish/kplugin.h

@@ -12,6 +12,7 @@
 #include <klish/ksym.h>
 
 // Current API version
+// Major and minor version numbers is uint8_t
 #define KPLUGIN_MAJOR 1
 #define KPLUGIN_MINOR 0
 

+ 7 - 0
plugins/Makefile.am

@@ -0,0 +1,7 @@
+plugindir = ${pkglibdir}/@PLUGINS_SUBDIR@
+plugin_LTLIBRARIES =
+
+EXTRA_DIST += \
+	plugins/klish/Makefile.am
+
+include $(top_srcdir)/plugins/klish/Makefile.am

+ 15 - 0
plugins/klish/Makefile.am

@@ -0,0 +1,15 @@
+db_LTLIBRARIES += kplugin-klish.la
+kplugin_klish_la_SOURCES =
+kplugin_klish_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version -module
+kplugin_klish_la_LIBS =
+kplugin_klish_la_CFLAGS = $(AM_LDFLAGS)
+kplugin_klish_la_LIBADD = libklish.la
+
+kplugin_klish_la_SOURCES += \
+	plugins/klish/plugin_init.c
+#	plugins/klish/hook_access.c \
+#	plugins/klish/hook_config.c \
+#	plugins/klish/hook_log.c \
+#	plugins/klish/sym_misc.c \
+#	plugins/klish/sym_script.c \
+#	plugins/klish/private.h

+ 88 - 0
plugins/klish/hook_access.c

@@ -0,0 +1,88 @@
+/*
+ * clish_access_callback.c
+ *
+ *
+ * callback hook to check whether the current user is a 
+ * member of the specified group (access string)
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <string.h>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+
+#include "lub/string.h"
+#include "lub/db.h"
+#include "clish/shell.h"
+
+/*--------------------------------------------------------- */
+/* Return values:
+ *    0 - access granted
+ *    !=0 - access denied
+ */
+CLISH_HOOK_ACCESS(clish_hook_access)
+{
+	int allowed = -1; /* assume the user is not allowed */
+#ifdef HAVE_GRP_H
+	int num_groups;
+	long ngroups_max;
+	gid_t *group_list;
+	int i;
+	char *tmp_access, *full_access;
+	char *saveptr = NULL;
+
+	assert(access);
+	full_access = lub_string_dup(access);
+	ngroups_max = sysconf(_SC_NGROUPS_MAX) + 1;
+	group_list = (gid_t *)malloc(ngroups_max * sizeof(gid_t));
+
+	/* Get the groups for the current user */
+	num_groups = getgroups(ngroups_max, group_list);
+	assert(num_groups != -1);
+
+	/* Now check these against the access provided */
+	/* The external loop goes trough the list of valid groups */
+	/* The allowed groups are indicated by a colon-separated (:) list. */
+	for (tmp_access = strtok_r(full_access, ":", &saveptr);
+		tmp_access; tmp_access = strtok_r(NULL, ":", &saveptr)) {
+		/* Check for the "*" wildcard */
+		if (0 == strcmp("*", tmp_access)) {
+			allowed = 0;
+			break;
+		}
+		/* The internal loop goes trough the system group list */
+		for (i = 0; i < num_groups; i++) {
+			struct group *ptr = lub_db_getgrgid(group_list[i]);
+			if (!ptr)
+				continue;
+			if (0 == strcmp(ptr->gr_name, tmp_access)) {
+				/* The current user is permitted to use this command */
+				allowed = 0;
+				free(ptr);
+				break;
+			}
+			free(ptr);
+		}
+		if (!allowed)
+			break;
+	}
+
+	lub_string_free(full_access);
+	free(group_list);
+#endif
+
+	clish_shell = clish_shell; /* Happy compiler */
+
+	return allowed;
+}
+
+/*--------------------------------------------------------- */

+ 218 - 0
plugins/klish/hook_config.c

@@ -0,0 +1,218 @@
+/*
+ * clish_config_callback.c
+ *
+ *
+ * Callback hook to execute config operations.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <limits.h>
+#include <string.h>
+
+#include "konf/net.h"
+#include "konf/buf.h"
+#include "konf/query.h"
+#include "lub/string.h"
+#include "lub/conv.h"
+#include "clish/shell.h"
+
+static int send_request(konf_client_t * client, char *command);
+
+/*--------------------------------------------------------- */
+static unsigned short str2ushort(const char *str)
+{
+	unsigned short num = 0;
+	lub_conv_atous(str, &num, 0);
+	return num;
+}
+
+/*--------------------------------------------------------- */
+/* Return values:
+ *    0 - success
+ *    !=0 - fail
+ */
+
+CLISH_HOOK_CONFIG(clish_hook_config)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	const clish_command_t *cmd = clish_context__get_cmd(clish_context);
+	clish_config_t *config;
+	char *command = NULL;
+	konf_client_t *client;
+	konf_buf_t *buf = NULL;
+	char *str = NULL;
+	char *tstr;
+	char tmp[PATH_MAX + 100];
+	clish_config_op_e op;
+	unsigned int num;
+	const char *escape_chars = lub_string_esc_quoted;
+
+	if (!this)
+		return 0;
+
+	client = clish_shell__get_client(this);
+	if (!client)
+		return 0;
+
+	config = clish_command__get_config(cmd);
+	op = clish_config__get_op(config);
+
+	switch (op) {
+
+	case CLISH_CONFIG_NONE:
+		return 0;
+
+	case CLISH_CONFIG_SET:
+		/* Add set operation */
+		lub_string_cat(&command, "-s");
+
+		/* Add entered line */
+		tstr = clish_shell__get_line(clish_context);
+		str = lub_string_encode(tstr, escape_chars);
+		lub_string_free(tstr);
+		lub_string_cat(&command, " -l \"");
+		lub_string_cat(&command, str);
+		lub_string_cat(&command, "\"");
+		lub_string_free(str);
+
+		/* Add splitter */
+		if (!clish_config__get_splitter(config))
+			lub_string_cat(&command, " -i");
+
+		/* Add unique */
+		if (!clish_config__get_unique(config))
+			lub_string_cat(&command, " -n");
+
+		break;
+
+	case CLISH_CONFIG_UNSET:
+		/* Add unset operation */
+		lub_string_cat(&command, "-u");
+		break;
+
+	case CLISH_CONFIG_DUMP:
+		/* Add dump operation */
+		lub_string_cat(&command, "-d");
+
+		/* Add filename */
+		str = clish_shell_expand(clish_config__get_file(config), SHELL_VAR_ACTION, clish_context);
+		if (str) {
+			lub_string_cat(&command, " -f \"");
+			if (str[0] != '\0')
+				lub_string_cat(&command, str);
+			else
+				lub_string_cat(&command, "/tmp/running-config");
+			lub_string_cat(&command, "\"");
+			lub_string_free(str);
+		}
+		break;
+
+	default:
+		return -1;
+	};
+
+	/* Add pattern */
+	if ((CLISH_CONFIG_SET == op) || (CLISH_CONFIG_UNSET == op)) {
+		tstr = clish_shell_expand(clish_config__get_pattern(config), SHELL_VAR_REGEX, clish_context);
+		if (!tstr) {
+			lub_string_free(command);
+			return -1;
+		}
+		str = lub_string_encode(tstr, escape_chars);
+		lub_string_free(tstr);
+		lub_string_cat(&command, " -r \"");
+		lub_string_cat(&command, str);
+		lub_string_cat(&command, "\"");
+		lub_string_free(str);
+	}
+
+	/* Add priority */
+	if (clish_config__get_priority(config) != 0) {
+		snprintf(tmp, sizeof(tmp) - 1, " -p 0x%x",
+			clish_config__get_priority(config));
+		tmp[sizeof(tmp) - 1] = '\0';
+		lub_string_cat(&command, tmp);
+	}
+
+	/* Add sequence */
+	if (clish_config__get_seq(config)) {
+		str = clish_shell_expand(clish_config__get_seq(config), SHELL_VAR_ACTION, clish_context);
+		snprintf(tmp, sizeof(tmp) - 1, " -q %u", str2ushort(str));
+		tmp[sizeof(tmp) - 1] = '\0';
+		lub_string_cat(&command, tmp);
+		lub_string_free(str);
+	}
+
+	/* Add pwd */
+	if (clish_config__get_depth(config)) {
+		str = clish_shell_expand(clish_config__get_depth(config), SHELL_VAR_ACTION, clish_context);
+		num = str2ushort(str);
+		lub_string_free(str);
+	} else {
+		num = clish_command__get_depth(cmd);
+	}
+	str = clish_shell__get_pwd_full(this, num);
+	if (str) {
+		lub_string_cat(&command, " ");
+		lub_string_cat(&command, str);
+		lub_string_free(str);
+	}
+
+#ifdef DEBUG
+	fprintf(stderr, "CONFIG request: %s\n", command);
+#endif
+	if (send_request(client, command) < 0) {
+		fprintf(stderr, "Cannot write to the running-config.\n");
+	}
+	if (konf_client_recv_answer(client, &buf) < 0) {
+		fprintf(stderr, "The error while request to the config daemon.\n");
+	}
+	lub_string_free(command);
+
+	/* Postprocessing. Get data from daemon etc. */
+	switch (op) {
+
+	case CLISH_CONFIG_DUMP:
+		if (buf) {
+			konf_buf_lseek(buf, 0);
+			while ((str = konf_buf_preparse(buf))) {
+				if (strlen(str) == 0) {
+					lub_string_free(str);
+					break;
+				}
+				tinyrl_printf(clish_shell__get_tinyrl(this),
+					"%s\n", str);
+				lub_string_free(str);
+			}
+			konf_buf_delete(buf);
+		}
+		break;
+
+	default:
+		break;
+	};
+
+	return 0;
+}
+
+/*--------------------------------------------------------- */
+
+static int send_request(konf_client_t * client, char *command)
+{
+	if ((konf_client_connect(client) < 0))
+		return -1;
+
+	if (konf_client_send(client, command) < 0) {
+		if (konf_client_reconnect(client) < 0)
+			return -1;
+		if (konf_client_send(client, command) < 0)
+			return -1;
+	}
+
+	return 0;
+}

+ 44 - 0
plugins/klish/hook_log.c

@@ -0,0 +1,44 @@
+/*
+ * callback_log.c
+ *
+ * Callback hook to log users's commands
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <pwd.h>
+
+#include "clish/shell.h"
+
+#define SYSLOG_IDENT "klish"
+
+/*--------------------------------------------------------- */
+CLISH_HOOK_LOG(clish_hook_log)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	struct passwd *user = NULL;
+	char *uname = NULL;
+
+	/* Initialization */
+	if (!line) {
+		openlog(SYSLOG_IDENT, LOG_PID,
+			clish_shell__get_log_facility(this));
+		return 0;
+	}
+
+	/* Log the given line */
+	/* Try to get username from environment variables
+	 * USER and LOGNAME and then from /etc/passwd.
+	 */
+	user = clish_shell__get_user(this);
+	if (!(uname = getenv("USER"))) {
+		if (!(uname = getenv("LOGNAME")))
+			uname = user ? user->pw_name : "unknown";
+	}
+	syslog(LOG_INFO, "%u(%s) %s : %d",
+		user ? user->pw_uid : getuid(), uname, line, retcode);
+
+	return 0;
+}

+ 48 - 0
plugins/klish/plugin_init.c

@@ -0,0 +1,48 @@
+/*
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include <faux/faux.h>
+#include <klish/kplugin.h>
+
+//#include "private.h"
+
+
+const uint8_t kplugin_klish_major = KPLUGIN_MAJOR;
+const uint8_t kplugin_klish_minor = KPLUGIN_MINOR;
+
+
+int kplugin_klish_init(kcontext_t *context)
+{
+	/* Add hooks */
+/*	clish_plugin_add_phook(plugin, clish_hook_access,
+		"clish_hook_access", CLISH_SYM_TYPE_ACCESS);
+	clish_plugin_add_phook(plugin, clish_hook_config,
+		"clish_hook_config", CLISH_SYM_TYPE_CONFIG);
+	clish_plugin_add_phook(plugin, clish_hook_log,
+		"clish_hook_log", CLISH_SYM_TYPE_LOG);
+*/
+
+	/* Add builtin syms */
+/*	clish_plugin_add_psym(plugin, clish_close, "clish_close");
+	clish_plugin_add_psym(plugin, clish_overview, "clish_overview");
+	clish_plugin_add_psym(plugin, clish_source, "clish_source");
+	clish_plugin_add_psym(plugin, clish_source_nostop, "clish_source_nostop");
+	clish_plugin_add_psym(plugin, clish_history, "clish_history");
+	clish_plugin_add_psym(plugin, clish_nested_up, "clish_nested_up");
+	clish_plugin_add_psym(plugin, clish_nop, "clish_nop");
+	clish_plugin_add_psym(plugin, clish_wdog, "clish_wdog");
+	clish_plugin_add_psym(plugin, clish_macros, "clish_macros");
+	clish_plugin_add_osym(plugin, clish_script, "clish_script");
+	clish_plugin_add_psym(plugin, clish_machine_interface, "clish_machine_interface");
+	clish_plugin_add_psym(plugin, clish_human_interface, "clish_human_interface");
+	clish_plugin_add_psym(plugin, clish_print_script, "clish_print_script");
+	clish_plugin_add_psym(plugin, clish_print_var, "clish_print_var");
+*/
+	context = context; // Happy compiler
+
+	return 0;
+}

+ 27 - 0
plugins/klish/private.h

@@ -0,0 +1,27 @@
+/*
+ * builtin private.h
+ */
+
+#include "clish/plugin.h"
+#include "clish/shell.h"
+
+/* Hooks */
+CLISH_HOOK_ACCESS(clish_hook_access);
+CLISH_HOOK_CONFIG(clish_hook_config);
+CLISH_HOOK_LOG(clish_hook_log);
+
+/* Navy, etc. syms */
+CLISH_PLUGIN_SYM(clish_close);
+CLISH_PLUGIN_SYM(clish_source);
+CLISH_PLUGIN_SYM(clish_source_nostop);
+CLISH_PLUGIN_SYM(clish_overview);
+CLISH_PLUGIN_SYM(clish_history);
+CLISH_PLUGIN_SYM(clish_nested_up);
+CLISH_PLUGIN_SYM(clish_nop);
+CLISH_PLUGIN_SYM(clish_wdog);
+CLISH_PLUGIN_OSYM(clish_script);
+CLISH_PLUGIN_SYM(clish_macros);
+CLISH_PLUGIN_SYM(clish_machine_interface);
+CLISH_PLUGIN_SYM(clish_human_interface);
+CLISH_PLUGIN_SYM(clish_print_script);
+CLISH_PLUGIN_SYM(clish_print_var);

+ 303 - 0
plugins/klish/sym_misc.c

@@ -0,0 +1,303 @@
+/*
+ * sym_navy.c
+ */
+#include "private.h"
+#include "lub/ctype.h"
+#include "lub/string.h"
+#include "lub/argv.h"
+#include "lub/conv.h"
+
+#include <assert.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <signal.h>
+#include <fcntl.h>
+
+/*----------------------------------------------------------- */
+/* Terminate the current shell session */
+CLISH_PLUGIN_SYM(clish_close)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	clish_shell__set_state(this, SHELL_STATE_CLOSING);
+
+	script = script; /* Happy compiler */
+	out = out; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+/*
+ Open a file and interpret it as a script in the context of a new
+ thread. Whether the script continues after command, but not script, 
+ errors depends on the value of the stop_on_error flag.
+*/
+static int clish_source_internal(clish_context_t *context,
+	const char *fn, int stop_on_error)
+{
+	int result = -1;
+	const char *filename = fn;
+	struct stat fileStat;
+
+	/* the exception proves the rule... */
+	clish_shell_t *this = clish_context__get_shell(context);
+
+	/*
+	 * Check file specified is not a directory 
+	 */
+	if ((0 == stat((char *)filename, &fileStat)) &&
+		(!S_ISDIR(fileStat.st_mode))) {
+		/*
+		 * push this file onto the file stack associated with this
+		 * session. This will be closed by clish_shell_pop_file() 
+		 * when it is finished with.
+		 */
+		result = clish_shell_push_file(this, filename,
+			stop_on_error);
+	}
+
+	return result ? -1 : 0;
+}
+
+/*----------------------------------------------------------- */
+/*
+ Open a file and interpret it as a script in the context of a new
+ thread. Invoking a script in this way will cause the script to
+ stop on the first error
+*/
+CLISH_PLUGIN_SYM(clish_source)
+{
+	clish_context_t *context = (clish_context_t *)clish_context;
+
+	out = out; /* Happy compiler */
+
+	return (clish_source_internal(context, script, 1));
+}
+
+/*----------------------------------------------------------- */
+/*
+ Open a file and interpret it as a script in the context of a new
+ thread. Invoking a script in this way will cause the script to
+ continue after command, but not script, errors.
+*/
+CLISH_PLUGIN_SYM(clish_source_nostop)
+{
+	clish_context_t *context = (clish_context_t *)clish_context;
+
+	out = out; /* Happy compiler */
+
+	return (clish_source_internal(context, script, 0));
+}
+
+/*----------------------------------------------------------- */
+/*
+ Show the shell overview
+*/
+CLISH_PLUGIN_SYM(clish_overview)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	tinyrl_t *tinyrl = clish_shell__get_tinyrl(this);
+	tinyrl_printf(tinyrl, "%s\n", clish_shell__get_overview(this));
+
+	script = script; /* Happy compiler */
+	out = out; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+CLISH_PLUGIN_SYM(clish_history)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	tinyrl_t *tinyrl = clish_shell__get_tinyrl(this);
+	tinyrl_history_t *history = tinyrl__get_history(tinyrl);
+	tinyrl_history_iterator_t iter;
+	const tinyrl_history_entry_t *entry;
+	unsigned int limit = 0;
+	const char *arg = script;
+
+	if (arg && ('\0' != *arg)) {
+		lub_conv_atoui(arg, &limit, 0);
+		if (0 == limit) {
+			/* unlimit the history list */
+			(void)tinyrl_history_unstifle(history);
+		} else {
+			/* limit the scope of the history list */
+			tinyrl_history_stifle(history, limit);
+		}
+	}
+	for (entry = tinyrl_history_getfirst(history, &iter);
+		entry; entry = tinyrl_history_getnext(&iter)) {
+		/* dump the details of this entry */
+		tinyrl_printf(tinyrl,
+			"%5d  %s\n",
+			tinyrl_history_entry__get_index(entry),
+			tinyrl_history_entry__get_line(entry));
+	}
+
+	out = out; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+/*
+ * Find out the previous view in the stack and go to it
+ */
+CLISH_PLUGIN_SYM(clish_nested_up)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	unsigned int depth;
+
+	if (!this)
+		return -1;
+	/* If depth=0 then exit */
+	if (((depth = clish_shell__get_depth(this)) == 0) ||
+		!clish_shell__set_depth(this, --depth)) {
+		clish_shell__set_state(this, SHELL_STATE_CLOSING);
+		return 0;
+	}
+
+	script = script; /* Happy compiler */
+	out = out; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+/*
+ * Builtin: NOP function
+ */
+CLISH_PLUGIN_SYM(clish_nop)
+{
+	script = script; /* Happy compiler */
+	out = out; /* Happy compiler */
+	clish_context = clish_context; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+/*
+ * Builtin: Set watchdog timeout. The "0" to turn watchdog off.
+ */
+CLISH_PLUGIN_SYM(clish_wdog)
+{
+	const char *arg = script;
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	unsigned int wdto = 0;
+
+	/* Turn off watchdog if no args */
+	if (!arg || ('\0' == *arg)) {
+		clish_shell__set_wdog_timeout(this, 0);
+		return 0;
+	}
+
+	lub_conv_atoui(arg, &wdto, 0);
+	clish_shell__set_wdog_timeout(this, wdto);
+
+	out = out; /* Happy compiler */
+
+	return 0;
+}
+
+/*--------------------------------------------------------- */
+/*
+ * Get the ACTION context as a macros
+ */
+CLISH_PLUGIN_SYM(clish_macros)
+{
+	if (!script) /* Nothing to do */
+		return 0;
+	*out = lub_string_dup(script);
+
+	clish_context = clish_context; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+CLISH_PLUGIN_SYM(clish_machine_interface)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	clish_shell_set_machine_interface(this);
+
+	script = script; /* Happy compiler */
+	out = out; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+CLISH_PLUGIN_SYM(clish_human_interface)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	clish_shell_set_human_interface(this);
+
+	script = script; /* Happy compiler */
+	out = out; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+/*
+ * Builtin: Print script
+ */
+CLISH_PLUGIN_SYM(clish_print_script)
+{
+	if (!script)
+		return 0;
+	printf("%s\n", script);
+
+	out = out; /* Happy compiler */
+	clish_context = clish_context; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */
+/*
+ * Builtin: Print param
+ */
+CLISH_PLUGIN_SYM(clish_print_var)
+{
+	char *str = NULL;
+	char *copy = NULL;
+	char *varname = NULL;
+	char *t = NULL;
+
+	// Script contains variable name
+	if (!script)
+		return 0;
+
+	// Remove all spaces from var name
+	copy = lub_string_dup(script);
+	varname = copy;
+	while (*varname && lub_ctype_isspace(*varname))
+		varname++;
+	t = varname;
+	while (*t && !lub_ctype_isspace(*t))
+		t++;
+	*t = '\0';
+
+	str = clish_shell_expand_var(varname, clish_context);
+	lub_string_free(copy);
+	if (!str)
+		return 0;
+	printf("%s\n", str);
+	lub_string_free(str);
+
+	out = out; /* Happy compiler */
+	clish_context = clish_context; /* Happy compiler */
+
+	return 0;
+}
+
+/*----------------------------------------------------------- */

+ 98 - 0
plugins/klish/sym_script.c

@@ -0,0 +1,98 @@
+/*
+ * sym_script.c
+ *
+ * Function to execute a shell script.
+ */
+
+#include "private.h"
+#include "lub/string.h"
+#include "konf/buf.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <limits.h>
+
+/*--------------------------------------------------------- */
+CLISH_PLUGIN_OSYM(clish_script)
+{
+	clish_shell_t *this = clish_context__get_shell(clish_context);
+	const clish_action_t *action = clish_context__get_action(clish_context);
+	const char *shebang = NULL;
+	pid_t cpid = -1;
+	int res;
+	char fifo_name[PATH_MAX];
+	FILE *wpipe;
+	char *command = NULL;
+
+	assert(this);
+	if (!script) /* Nothing to do */
+		return 0;
+
+	/* Find out shebang */
+	if (action)
+		shebang = clish_action__get_shebang(action);
+	if (!shebang)
+		shebang = clish_shell__get_default_shebang(this);
+	assert(shebang);
+
+#ifdef DEBUG
+	fprintf(stderr, "SHEBANG: #!%s\n", shebang);
+	fprintf(stderr, "SCRIPT: %s\n", script);
+#endif /* DEBUG */
+
+	/* Create FIFO */
+	if (! clish_shell_mkfifo(this, fifo_name, sizeof(fifo_name))) {
+		fprintf(stderr, "Error: Can't create temporary FIFO.\n"
+			"Error: The ACTION will be not executed.\n");
+		return -1;
+	}
+
+	/* Create process to write to FIFO */
+	cpid = fork();
+	if (cpid == -1) {
+		fprintf(stderr, "Error: Can't fork the write process.\n"
+			"Error: The ACTION will be not executed.\n");
+		clish_shell_rmfifo(this, fifo_name);
+		return -1;
+	}
+
+	/* Child: write to FIFO */
+	if (cpid == 0) {
+		wpipe = fopen(fifo_name, "w");
+		if (!wpipe)
+			_exit(-1);
+		fwrite(script, strlen(script), 1, wpipe);
+		fclose(wpipe);
+		_exit(0);
+	}
+
+	/* Parent */
+	/* Prepare command */
+	lub_string_cat(&command, shebang);
+	lub_string_cat(&command, " ");
+	lub_string_cat(&command, fifo_name);
+
+	res = system(command);
+
+	/* Wait for the writing process */
+	kill(cpid, SIGTERM);
+	while (waitpid(cpid, NULL, 0) != cpid);
+
+	/* Clean up */
+	lub_string_free(command);
+	clish_shell_rmfifo(this, fifo_name);
+
+#ifdef DEBUG
+	fprintf(stderr, "RETCODE: %d\n", WEXITSTATUS(res));
+#endif /* DEBUG */
+	return WEXITSTATUS(res);
+}