aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2017-01-04 18:52:32 +0100
committerJosé Bollo <jose.bollo@iot.bzh>2017-01-05 15:21:19 +0100
commit84e049cf2312286ad1895cbebc82cabd5c30b9bb (patch)
tree7d2163d9de7258736daf3850d36bd9c0797ba02c
parent4247029ca95bf3d3205410dc3b516ef27a220f69 (diff)
Adds options --no-httpd and --exec
The option option --exec use the remaining arguments of the command line (at the right of --exec) as a command to launch with its arguments. Arguments can use @p (for port), @t (for token) or @@ for @. When the option --exec is given, the command is launched as soon as afb-daemon is ready. When the command die, afb-daemon exits and before exiting, afb-daemon kills the launched command and its childs. The option --no-http forbids the activation of the HTTP server. Change-Id: Icdd91d84c818796b5ac6ea5d33ff3549a2fe3c25 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
-rw-r--r--doc/afb-overview.md11
-rw-r--r--src/afb-config.c37
-rw-r--r--src/afb-config.h4
-rw-r--r--src/main.c159
4 files changed, 185 insertions, 26 deletions
diff --git a/doc/afb-overview.md b/doc/afb-overview.md
index c66f84ea..6272b5d2 100644
--- a/doc/afb-overview.md
+++ b/doc/afb-overview.md
@@ -232,6 +232,17 @@ The launch options for binder **afb-daemon** are:
Get all in background mode
+ --no-httpd
+
+ Forbids HTTP serve
+
+ --exec
+
+ Must be the last option for afb-daemon. The remaining
+ arguments define a command that afb-daemon will launch.
+ The sequences @p, @t and @@ of the arguments are replaced
+ with the port, the token and @.
+
Future development of afb-daemon
--------------------------------
diff --git a/src/afb-config.c b/src/afb-config.c
index 4754c958..e2fec3a0 100644
--- a/src/afb-config.c
+++ b/src/afb-config.c
@@ -88,7 +88,11 @@
#define SET_TRACEREQ 27
-#define SHORTOPTS "vqhV"
+#define SET_NO_HTTPD 28
+
+#define SET_EXEC 'e'
+
+#define SHORTOPTS "vqhVe"
// Command line structure hold cli --command + help text
typedef struct {
@@ -120,7 +124,7 @@ static AFB_options cliOptions[] = {
{SET_SESSION_DIR, 1, "sessiondir", "Sessions file path [default rootdir/sessions]"},
- {SET_LDPATH, 1, "ldpaths", "Load bindingss from dir1:dir2:... [default = " BINDING_INSTALL_DIR "]"},
+ {SET_LDPATH, 1, "ldpaths", "Load bindings from dir1:dir2:... [default = " BINDING_INSTALL_DIR "]"},
{SET_AUTH_TOKEN, 1, "token", "Initial Secret [default=no-session, --token= for session without authentication]"},
{DISPLAY_VERSION, 0, "version", "Display version and copyright"},
@@ -139,6 +143,9 @@ static AFB_options cliOptions[] = {
{SET_TRACEREQ, 1, "tracereq", "Log the requests: no, common, extra, all"},
+ {SET_NO_HTTPD, 0, "no-httpd", "Forbids HTTP service"},
+ {SET_EXEC, 0, "exec", "Execute the remaining arguments"},
+
{0, 0, NULL, NULL}
/* *INDENT-ON* */
};
@@ -447,6 +454,16 @@ static void parse_arguments(int argc, char **argv, struct afb_config *config)
config->tracereq = argvalenum(optionIndex, tracereq_desc);
break;
+ case SET_NO_HTTPD:
+ noarg(optionIndex);
+ config->noHttpd = 1;
+ break;
+
+ case SET_EXEC:
+ config->exec = &argv[optind];
+ optind = argc;
+ break;
+
case DISPLAY_VERSION:
noarg(optionIndex);
printVersion(stdout);
@@ -526,6 +543,7 @@ void afb_config_dump(struct afb_config *config)
{
struct afb_config_list *l;
struct enumdesc *e;
+ char **v;
#define NN(x) (x)?:""
#define P(...) fprintf(stderr, __VA_ARGS__)
@@ -534,10 +552,12 @@ void afb_config_dump(struct afb_config *config)
#define S(x) PF(x);P("%s",NN(config->x));PE;
#define D(x) PF(x);P("%d",config->x);PE;
#define H(x) PF(x);P("%x",config->x);PE;
+#define B(x) PF(x);P("%s",config->x?"yes":"no");PE;
#define L(x) PF(x);l=config->x;if(l){P("%s\n",NN(l->value));for(l=l->next;l;l=l->next)P("-- %15s %s\n","",NN(l->value));}else PE;
-#define E(x,d) for(e=d;e->name&&e->value!=config->x;e++);PF(x);if(e->name)P("%s",e->name);else P("%d",config->x);PE;
+#define E(x,d) for(e=d;e->name&&e->value!=config->x;e++);if(e->name){PF(x);P("%s",e->name);PE;}else{D(x);}
+#define V(x) P("-- %15s:", #x);for(v=config->x;v&&*v;v++)P(" %s",*v); PE;
- P("-- BEGIN OF CONFIG --\n");
+ P("---BEGIN-OF-CONFIG---\n");
S(console)
S(rootdir)
S(roothttp)
@@ -554,8 +574,10 @@ void afb_config_dump(struct afb_config *config)
L(so_bindings)
L(ldpaths)
+ V(exec)
+
D(httpdPort)
- D(background)
+ B(background)
D(readyfd)
D(cacheTimeout)
D(apiTimeout)
@@ -563,10 +585,13 @@ void afb_config_dump(struct afb_config *config)
D(nbSessionMax)
E(mode,mode_desc)
E(tracereq,tracereq_desc)
- P("-- END OF CONFIG --\n");
+ B(noHttpd)
+ P("---END-OF-CONFIG---\n");
+#undef V
#undef E
#undef L
+#undef B
#undef H
#undef D
#undef S
diff --git a/src/afb-config.h b/src/afb-config.h
index 542a617e..eb76abe8 100644
--- a/src/afb-config.h
+++ b/src/afb-config.h
@@ -34,6 +34,7 @@ struct afb_config {
char *rootapi; // Base URL for REST APIs
char *sessiondir; // where to store mixer session files
char *token; // initial authentication token [default NULL no session]
+
struct afb_config_list *aliases;
struct afb_config_list *dbus_clients;
struct afb_config_list *dbus_servers;
@@ -42,6 +43,8 @@ struct afb_config {
struct afb_config_list *so_bindings;
struct afb_config_list *ldpaths;
+ char **exec;
+
int httpdPort;
int background; // run in backround mode
int readyfd; // a #fd to signal when ready to serve
@@ -51,6 +54,7 @@ struct afb_config {
int nbSessionMax; // max count of sessions
int mode; // mode of listening
int tracereq;
+ int noHttpd;
};
extern struct afb_config *afb_config_parse_arguments(int argc, char **argv);
diff --git a/src/main.c b/src/main.c
index ac93de4f..9fbbb072 100644
--- a/src/main.c
+++ b/src/main.c
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <sys/wait.h>
#include <systemd/sd-event.h>
@@ -46,6 +47,9 @@
#include <afb/afb-binding.h>
+static struct afb_config *config;
+static pid_t childpid;
+
/*----------------------------------------------------------
| helpers for handling list of arguments
+--------------------------------------------------------- */
@@ -83,19 +87,21 @@ static void start_list(struct afb_config_list *list,
}
/*----------------------------------------------------------
- | closeSession
- | try to close everything before leaving
+ | exit_handler
+ | Handles on exit specific actions
+--------------------------------------------------------- */
-static void closeSession(int status, void *data)
+static void exit_handler()
{
- /* struct afb_config *config = data; */
+ if (childpid > 0)
+ killpg(childpid, SIGKILL);
+ /* TODO: check whether using SIGHUP isn't better */
}
/*----------------------------------------------------------
| daemonize
| set the process in background
+--------------------------------------------------------- */
-static void daemonize(struct afb_config *config)
+static void daemonize()
{
int consoleFD;
int pid;
@@ -155,7 +161,7 @@ static int init_alias(void *closure, char *spec)
0, 0);
}
-static int init_http_server(struct afb_hsrv *hsrv, struct afb_config *config)
+static int init_http_server(struct afb_hsrv *hsrv)
{
if (!afb_hsrv_add_handler
(hsrv, config->rootapi, afb_hswitch_websocket_switch, NULL, 20))
@@ -183,7 +189,7 @@ static int init_http_server(struct afb_hsrv *hsrv, struct afb_config *config)
return 1;
}
-static struct afb_hsrv *start_http_server(struct afb_config *config)
+static struct afb_hsrv *start_http_server()
{
int rc;
struct afb_hsrv *hsrv;
@@ -200,7 +206,7 @@ static struct afb_hsrv *start_http_server(struct afb_config *config)
}
if (!afb_hsrv_set_cache_timeout(hsrv, config->cacheTimeout)
- || !init_http_server(hsrv, config)) {
+ || !init_http_server(hsrv)) {
ERROR("initialisation of httpd failed");
afb_hsrv_put(hsrv);
return NULL;
@@ -221,6 +227,114 @@ static struct afb_hsrv *start_http_server(struct afb_config *config)
}
/*---------------------------------------------------------
+ | execute_command
+ |
+ +--------------------------------------------------------- */
+
+static void on_sigchld(int signum, siginfo_t *info, void *uctx)
+{
+ if (info->si_pid == childpid) {
+ switch (info->si_code) {
+ case CLD_EXITED:
+ case CLD_KILLED:
+ case CLD_DUMPED:
+ childpid = 0;
+ killpg(info->si_pid, SIGKILL);
+ waitpid(info->si_pid, NULL, 0);
+ exit(0);
+ }
+ }
+}
+
+/*
+# @@ @
+# @p port
+# @t token
+*/
+
+#define SUBST_CHAR '@'
+#define SUBST_STR "@"
+
+static int instanciate_command_args()
+{
+ char *orig, *repl, *sub, *val, port[20];
+ int i, rc, r;
+ size_t s, l;
+
+ rc = snprintf(port, sizeof port, "%d", config->httpdPort);
+ if (rc < 0 || rc >= (int)(sizeof port))
+ return -1;
+
+ for (i = 0 ; (orig = config->exec[i]) ; i++) {
+ repl = 0;
+ s = 0;
+ for(;;) {
+ sub = strchrnul(orig, SUBST_CHAR);
+ l = sub - orig;
+ if (repl)
+ repl = mempcpy(repl, orig, l);
+ else
+ s += l;
+ if (!*sub) {
+ /* at end */
+ if (repl || orig == config->exec[i])
+ break;
+ repl = malloc(1 + s);
+ if (!repl)
+ return -1;
+ orig = config->exec[i];
+ config->exec[i] = repl;
+ repl[s] = 0;
+ } else {
+ r = 2;
+ switch(sub[1]) {
+ case 'p': val = port; break;
+ case 't': val = config->token ? : ""; break;
+ default: r = 1;
+ case SUBST_CHAR: val = SUBST_STR; break;
+ }
+ orig = &sub[r];
+ l = strlen(val);
+ if (repl)
+ repl = mempcpy(repl, val, l);
+ else
+ s += l;
+ }
+ }
+ }
+ return 0;
+}
+
+static int execute_command()
+{
+ struct sigaction siga;
+
+ /* check whether a command is to execute or not */
+ if (!config->exec || !config->exec[0])
+ return 0;
+
+ /* install signal handler */
+ memset(&siga, 0, sizeof siga);
+ siga.sa_sigaction = on_sigchld;
+ siga.sa_flags = SA_SIGINFO;
+ sigaction(SIGCHLD, &siga, NULL);
+
+ /* fork now */
+ childpid = fork();
+ if (childpid)
+ return 0;
+
+ /* makes arguments */
+ if (instanciate_command_args() >= 0) {
+ setpgid(0, 0);
+ execv(config->exec[0], config->exec);
+ ERROR("can't launch %s: %m", config->exec[0]);
+ }
+ exit(1);
+ return -1;
+}
+
+/*---------------------------------------------------------
| main
| Parse option and launch action
+--------------------------------------------------------- */
@@ -228,14 +342,13 @@ static struct afb_hsrv *start_http_server(struct afb_config *config)
int main(int argc, char *argv[])
{
struct afb_hsrv *hsrv;
- struct afb_config *config;
struct sd_event *eventloop;
LOGAUTH("afb-daemon");
// ------------- Build session handler & init config -------
config = afb_config_parse_arguments(argc, argv);
- on_exit(closeSession, config);
+ atexit(exit_handler);
// ------------------ sanity check ----------------------------------------
if (config->httpdPort <= 0) {
@@ -243,8 +356,7 @@ int main(int argc, char *argv[])
exit(1);
}
- afb_session_init(config->nbSessionMax, config->cntxTimeout,
- config->token, afb_apis_count());
+ afb_session_init(config->nbSessionMax, config->cntxTimeout, config->token, afb_apis_count());
afb_api_so_set_timeout(config->apiTimeout);
start_list(config->dbus_clients, afb_api_dbus_add_client, "the afb-dbus client");
@@ -254,8 +366,7 @@ int main(int argc, char *argv[])
start_list(config->dbus_servers, afb_api_dbus_add_server, "the afb-dbus service");
start_list(config->ws_servers, afb_api_ws_add_server, "the afb-websocket service");
- if (!afb_hreq_init_cookie
- (config->httpdPort, config->rootapi, config->cntxTimeout)) {
+ if (!afb_hreq_init_cookie(config->httpdPort, config->rootapi, config->cntxTimeout)) {
ERROR("initialisation of cookies failed");
exit(1);
}
@@ -288,7 +399,7 @@ int main(int argc, char *argv[])
if (config->background) {
// --------- in background mode -----------
INFO("entering background mode");
- daemonize(config);
+ daemonize();
} else {
// ---- in foreground mode --------------------
INFO("entering foreground mode");
@@ -301,20 +412,28 @@ int main(int argc, char *argv[])
if (config->tracereq)
afb_hook_req_create(NULL, NULL, NULL, config->tracereq, NULL, NULL);
- /* start the HTTP server */
- hsrv = start_http_server(config);
- if (hsrv == NULL)
- exit(1);
-
/* start the services */
if (afb_apis_start_all_services(1) < 0)
exit(1);
+ /* start the HTTP server */
+ if (!config->noHttpd) {
+ hsrv = start_http_server();
+ if (hsrv == NULL)
+ exit(1);
+ }
+
+ /* run the command */
+ if (execute_command() < 0)
+ exit(1);
+
+ /* signal that ready */
if (config->readyfd != 0) {
static const char readystr[] = "READY=1";
write(config->readyfd, readystr, sizeof(readystr) - 1);
close(config->readyfd);
}
+
// infinite loop
eventloop = afb_common_get_event_loop();
for (;;)