summaryrefslogtreecommitdiffstats
path: root/src/shell.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/shell.c')
-rw-r--r--src/shell.c219
1 files changed, 116 insertions, 103 deletions
diff --git a/src/shell.c b/src/shell.c
index e1161d4..0b9bef5 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -32,145 +32,158 @@
#include <sys/wait.h>
-bool fastd_shell_command_exec(fastd_context_t *ctx, const fastd_shell_command_t *command, const fastd_peer_t *peer, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *peer_addr, int *ret) {
- if (!fastd_shell_command_isset(command))
- return true;
+static void shell_command_setenv(fastd_context_t *ctx, pid_t pid, const fastd_peer_t *peer, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *peer_addr) {
+ /* both INET6_ADDRSTRLEN and IFNAMESIZE already include space for the zero termination, so there is no need to add space for the '%' here. */
+ char buf[INET6_ADDRSTRLEN+IF_NAMESIZE];
- bool ok = false;
- char *cwd = get_current_dir_name();
+ snprintf(buf, sizeof(buf), "%u", (unsigned)pid);
+ setenv("FASTD_PID", buf, 1);
+ if (ctx->ifname) {
+ setenv("INTERFACE", ctx->ifname, 1);
+ }
+ else if (ctx->conf->ifname) {
+ char ifname[IF_NAMESIZE];
- if (!chdir(command->dir)) {
- /* both INET6_ADDRSTRLEN and IFNAMESIZE already include space for the zero termination, so there is no need to add space for the '%' here. */
- char buf[INET6_ADDRSTRLEN+IF_NAMESIZE];
+ strncpy(ifname, ctx->conf->ifname, sizeof(ifname)-1);
+ ifname[sizeof(ifname)-1] = 0;
- snprintf(buf, sizeof(buf), "%u", (unsigned)getpid());
- setenv("FASTD_PID", buf, 1);
+ setenv("INTERFACE", ifname, 1);
+ }
+ else {
+ unsetenv("INTERFACE");
+ }
- if (ctx->ifname) {
- setenv("INTERFACE", ctx->ifname, 1);
- }
- else if (ctx->conf->ifname) {
- char ifname[IF_NAMESIZE];
+ snprintf(buf, sizeof(buf), "%u", ctx->conf->mtu);
+ setenv("INTERFACE_MTU", buf, 1);
- strncpy(ifname, ctx->conf->ifname, sizeof(ifname)-1);
- ifname[sizeof(ifname)-1] = 0;
+ if (peer && peer->config && peer->config->name)
+ setenv("PEER_NAME", peer->config->name, 1);
+ else
+ unsetenv("PEER_NAME");
- setenv("INTERFACE", ifname, 1);
- }
- else {
- unsetenv("INTERFACE");
- }
+ switch(local_addr ? local_addr->sa.sa_family : AF_UNSPEC) {
+ case AF_INET:
+ inet_ntop(AF_INET, &local_addr->in.sin_addr, buf, sizeof(buf));
+ setenv("LOCAL_ADDRESS", buf, 1);
+
+ snprintf(buf, sizeof(buf), "%u", ntohs(local_addr->in.sin_port));
+ setenv("LOCAL_PORT", buf, 1);
- snprintf(buf, sizeof(buf), "%u", ctx->conf->mtu);
- setenv("INTERFACE_MTU", buf, 1);
+ break;
- if (peer && peer->config && peer->config->name)
- setenv("PEER_NAME", peer->config->name, 1);
- else
- unsetenv("PEER_NAME");
+ case AF_INET6:
+ inet_ntop(AF_INET6, &local_addr->in6.sin6_addr, buf, sizeof(buf));
- switch(local_addr ? local_addr->sa.sa_family : AF_UNSPEC) {
- case AF_INET:
- inet_ntop(AF_INET, &local_addr->in.sin_addr, buf, sizeof(buf));
- setenv("LOCAL_ADDRESS", buf, 1);
+ if (IN6_IS_ADDR_LINKLOCAL(&local_addr->in6.sin6_addr)) {
+ if (if_indextoname(local_addr->in6.sin6_scope_id, buf+strlen(buf)+1))
+ buf[strlen(buf)] = '%';
+ }
- snprintf(buf, sizeof(buf), "%u", ntohs(local_addr->in.sin_port));
- setenv("LOCAL_PORT", buf, 1);
+ setenv("LOCAL_ADDRESS", buf, 1);
- break;
+ snprintf(buf, sizeof(buf), "%u", ntohs(local_addr->in6.sin6_port));
+ setenv("LOCAL_PORT", buf, 1);
- case AF_INET6:
- inet_ntop(AF_INET6, &local_addr->in6.sin6_addr, buf, sizeof(buf));
+ break;
- if (IN6_IS_ADDR_LINKLOCAL(&local_addr->in6.sin6_addr)) {
- if (if_indextoname(local_addr->in6.sin6_scope_id, buf+strlen(buf)+1))
- buf[strlen(buf)] = '%';
- }
+ default:
+ unsetenv("LOCAL_ADDRESS");
+ unsetenv("LOCAL_PORT");
+ }
- setenv("LOCAL_ADDRESS", buf, 1);
+ switch(peer_addr ? peer_addr->sa.sa_family : AF_UNSPEC) {
+ case AF_INET:
+ inet_ntop(AF_INET, &peer_addr->in.sin_addr, buf, sizeof(buf));
+ setenv("PEER_ADDRESS", buf, 1);
- snprintf(buf, sizeof(buf), "%u", ntohs(local_addr->in6.sin6_port));
- setenv("LOCAL_PORT", buf, 1);
+ snprintf(buf, sizeof(buf), "%u", ntohs(peer_addr->in.sin_port));
+ setenv("PEER_PORT", buf, 1);
- break;
+ break;
- default:
- unsetenv("LOCAL_ADDRESS");
- unsetenv("LOCAL_PORT");
+ case AF_INET6:
+ inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, buf, sizeof(buf));
+
+ if (IN6_IS_ADDR_LINKLOCAL(&peer_addr->in6.sin6_addr)) {
+ if (if_indextoname(peer_addr->in6.sin6_scope_id, buf+strlen(buf)+1))
+ buf[strlen(buf)] = '%';
}
- switch(peer_addr ? peer_addr->sa.sa_family : AF_UNSPEC) {
- case AF_INET:
- inet_ntop(AF_INET, &peer_addr->in.sin_addr, buf, sizeof(buf));
- setenv("PEER_ADDRESS", buf, 1);
+ setenv("PEER_ADDRESS", buf, 1);
+
+ snprintf(buf, sizeof(buf), "%u", ntohs(peer_addr->in6.sin6_port));
+ setenv("PEER_PORT", buf, 1);
- snprintf(buf, sizeof(buf), "%u", ntohs(peer_addr->in.sin_port));
- setenv("PEER_PORT", buf, 1);
+ break;
- break;
+ default:
+ unsetenv("PEER_ADDRESS");
+ unsetenv("PEER_PORT");
+ }
- case AF_INET6:
- inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, buf, sizeof(buf));
+ ctx->conf->protocol->set_shell_env(ctx, peer);
+}
- if (IN6_IS_ADDR_LINKLOCAL(&peer_addr->in6.sin6_addr)) {
- if (if_indextoname(peer_addr->in6.sin6_scope_id, buf+strlen(buf)+1))
- buf[strlen(buf)] = '%';
- }
+static bool shell_command_do_exec(fastd_context_t *ctx, const fastd_shell_command_t *command, const fastd_peer_t *peer, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *peer_addr, pid_t *pid_ret) {
+ pid_t parent = getpid();
- setenv("PEER_ADDRESS", buf, 1);
+ pid_t pid = fork();
+ if (pid < 0) {
+ pr_error_errno(ctx, "shell_command_do_exec: fork");
+ return false;
+ }
+ else if (pid > 0) {
+ if (pid_ret)
+ *pid_ret = pid;
- snprintf(buf, sizeof(buf), "%u", ntohs(peer_addr->in6.sin6_port));
- setenv("PEER_PORT", buf, 1);
+ return true;
+ }
- break;
+ /* child process */
+ if (chdir(command->dir))
+ _exit(126);
- default:
- unsetenv("PEER_ADDRESS");
- unsetenv("PEER_PORT");
- }
+ shell_command_setenv(ctx, parent, peer, local_addr, peer_addr);
- ctx->conf->protocol->set_shell_env(ctx, peer);
+ execl("/bin/sh", "sh", "-c", command->command, (char*)NULL);
+ _exit(127);
+}
- if (command->sync) {
- int result = system(command->command);
+bool fastd_shell_command_exec_sync(fastd_context_t *ctx, const fastd_shell_command_t *command, const fastd_peer_t *peer, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *peer_addr, int *ret) {
+ if (!fastd_shell_command_isset(command))
+ return true;
- if (ret) {
- *ret = result;
- ok = true;
- }
- else {
- if (WIFSIGNALED(result))
- pr_error(ctx, "command exited with signal %i", WTERMSIG(result));
- else if (WEXITSTATUS(result))
- pr_warn(ctx, "command exited with status %i", WEXITSTATUS(result));
- else
- ok = true;
- }
+ pid_t pid;
+ if (!shell_command_do_exec(ctx, command, peer, local_addr, peer_addr, &pid))
+ return false;
- }
- else {
- pid_t pid = fork();
- if (pid == 0) {
- execl("/bin/sh", "sh", "-c", command->command, (char*)NULL);
- _exit(127);
- }
- else if (pid > 0) {
- ok = true;
- }
- else {
- pr_error_errno(ctx, "fastd_shell_exec_command: fork");
- }
- }
+ int status;
+ if (waitpid(pid, &status, 0) <= 0) {
+ pr_error_errno(ctx, "fastd_shell_command_exec_sync: waitpid");
+ return false;
+ }
- if(chdir(cwd))
- pr_error(ctx, "can't chdir to `%s': %s", cwd, strerror(errno));
+ if (ret) {
+ *ret = status;
}
else {
- pr_error(ctx, "can't chdir to `%s': %s", command->dir, strerror(errno));
+ if (WIFSIGNALED(status))
+ pr_warn(ctx, "command exited with signal %i", WTERMSIG(status));
+ else if (WEXITSTATUS(status))
+ pr_warn(ctx, "command exited with status %i", WEXITSTATUS(status));
}
- free(cwd);
+ return true;
+}
+
+
+void fastd_shell_command_exec(fastd_context_t *ctx, const fastd_shell_command_t *command, const fastd_peer_t *peer, const fastd_peer_address_t *local_addr, const fastd_peer_address_t *peer_addr) {
+ if (!fastd_shell_command_isset(command))
+ return;
- return ok;
+ if (command->sync)
+ fastd_shell_command_exec_sync(ctx, command, peer, local_addr, peer_addr, NULL);
+ else
+ shell_command_do_exec(ctx, command, peer, local_addr, peer_addr, NULL);
}