From dc4d29d0b8c3393ab8ba85b6278fd231b1191509 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Jos=C3=A9=20Bollo?= <jose.bollo@iot.bzh>
Date: Tue, 15 Mar 2016 11:10:27 +0100
Subject: [PATCH] afm-launch: comments and improvements
MIME-Version: 1.0
Content-Type: text/plain; charset=utf8
Content-Transfer-Encoding: 8bit

Change-Id: I1b0745dfe659d26efdcd686b117fd7d64ed3a440
Signed-off-by: José Bollo <jose.bollo@iot.bzh>
---
 src/afm-launch-mode.c |  71 +++++++++-
 src/afm-launch-mode.h |  10 +-
 src/afm-launch.c      | 365 ++++++++++++++++++++++++++++++++++++--------------
 src/afm-launch.h      |  25 ++--
 src/afm-user-daemon.c |  25 +++-
 5 files changed, 369 insertions(+), 127 deletions(-)

diff --git a/src/afm-launch-mode.c b/src/afm-launch-mode.c
index 99add62..79a31f4 100644
--- a/src/afm-launch-mode.c
+++ b/src/afm-launch-mode.c
@@ -17,28 +17,85 @@
 */
 
 #include <string.h>
+#include <assert.h>
 
 #include "afm-launch-mode.h"
 
+/*
+ * There is actually 2 possible launch mode:
+ *  - local
+ *  - remote
+ */
 static const char s_mode_local[] = "local";
 static const char s_mode_remote[] = "remote";
 
-enum afm_launch_mode launch_mode_of_string(const char *s)
+/*
+ * Records the current default mode
+ */
+static enum afm_launch_mode default_mode = mode_local;
+
+/*
+ * Set the default launch mode to 'mode'
+ */
+int is_valid_launch_mode(enum afm_launch_mode mode)
+{
+	switch(mode) {
+	case mode_local:
+	case mode_remote:
+		return 1;
+	default:
+		return 0;
+	}
+}
+
+/*
+ * Get the default launch mode
+ *
+ * Ensure a valid result
+ */
+enum afm_launch_mode get_default_launch_mode()
+{
+	return default_mode;
+}
+
+/*
+ * Set the default launch mode to 'mode'
+ *
+ * Requires 'mode' to be valid
+ */
+void set_default_launch_mode(enum afm_launch_mode mode)
 {
-	if (s) {
-		if (!strcmp(s, s_mode_local))
+	assert(is_valid_launch_mode(mode));
+	default_mode = mode;
+}
+
+/*
+ * Get the launch mode corresponding to the 'name'
+ *
+ * Returns invalid_launch_mode if the 'name' is not valid.
+ */
+enum afm_launch_mode launch_mode_of_name(const char *name)
+{
+	if (name) {
+		if (!strcmp(name, s_mode_local))
 			return mode_local;
-		if (!strcmp(s, s_mode_remote))
+		if (!strcmp(name, s_mode_remote))
 			return mode_remote;
 	}
 	return invalid_launch_mode;
 }
 
-const char *name_of_launch_mode(enum afm_launch_mode m)
+/*
+ * Get the name of the launch 'mode'
+ *
+ * Requires 'mode' to be valid
+ */
+const char *name_of_launch_mode(enum afm_launch_mode mode)
 {
-	switch (m) {
+	assert(is_valid_launch_mode(mode));
+	switch (mode) {
 	case mode_local:  return s_mode_local;
 	case mode_remote: return s_mode_remote;
-	default:          return "(INVALID LAUNCH MODE)";
+	default:          return NULL;
 	}
 }
diff --git a/src/afm-launch-mode.h b/src/afm-launch-mode.h
index 4b840ab..f845d40 100644
--- a/src/afm-launch-mode.h
+++ b/src/afm-launch-mode.h
@@ -22,11 +22,11 @@ enum afm_launch_mode {
 	mode_remote  = 2
 };
 
-#define default_launch_mode  mode_local
+extern int is_valid_launch_mode(enum afm_launch_mode mode);
 
-#define launch_mode_is_valid(x)  ((x)==mode_local || (x)==mode_remote)
-#define is_valid_launch_mode(x)  ((x)==mode_local || (x)==mode_remote)
+extern enum afm_launch_mode get_default_launch_mode();
+extern void set_default_launch_mode(enum afm_launch_mode mode);
 
-enum afm_launch_mode launch_mode_of_string(const char *s);
-const char *name_of_launch_mode(enum afm_launch_mode m);
+extern enum afm_launch_mode launch_mode_of_name(const char *name);
+extern const char *name_of_launch_mode(enum afm_launch_mode mode);
 
diff --git a/src/afm-launch.c b/src/afm-launch.c
index 612d102..13f2bf9 100644
--- a/src/afm-launch.c
+++ b/src/afm-launch.c
@@ -40,21 +40,27 @@ extern char **environ;
 
 #define DEFAULT_TYPE "text/html"
 
+/*
+ * structure for a launching type
+ */
 struct type_list {
-	struct type_list *next;
-	char type[1];
+	struct type_list *next; /* next type */
+	char type[1];           /* type name */
 };
 
+/*
+ * structure for launch vectors
+ */
 struct exec_vector {
-	int has_readyfd;
-	const char **args;
+	int has_readyfd;     /* has a request for readyness */
+	const char **args;   /* vector of arguments */
 };
 
-struct desc_list {
-	struct desc_list *next;
-	enum afm_launch_mode mode;
-	struct type_list *types;
-	struct exec_vector execs[2];
+struct desc_launcher {
+	struct desc_launcher *next;   /* next launcher description */
+	enum afm_launch_mode mode;    /* the launch mode */
+	struct type_list *types;      /* the launched types */
+	struct exec_vector execs[2];  /* the launching vectors */
 };
 
 struct launchparam {
@@ -66,43 +72,72 @@ struct launchparam {
 	struct exec_vector *execs;
 };
 
+/*
+ * Structure for reading the configuration file
+ */
 struct confread {
-	const char *filepath;
-	FILE *file;
-	int lineno;
-	int index;
-	int length;
-	char buffer[4096];
+	const char *filepath; /* path of the configuration file */
+	FILE *file;           /* handle to the file */
+	int lineno;           /* current line number */
+	int index;            /* start of the current token (in buffer) */
+	int length;           /* length of the current token */
+	char buffer[4096];    /* current line */
 };
 
-struct desc_list *launchers = NULL;
+/*
+ * list of launch descriptions
+ */
+struct desc_launcher *launchers = NULL;
 
+/*
+ * the group when launched (to avoid the setgid effect)
+ */
 static gid_t groupid = 0;
 
+/*
+ * separators within configuration files
+ */
 static const char separators[] = " \t\n";
+
+/*
+ * default string emitted when for application not having signal
+ */
 static const char readystr[] = "READY=1";
+
+/*
+ * default time out for readiness of signaling applications
+ */
 static const int ready_timeout = 1500;
 
-static void dump_launchers()
+/*
+ * dump all the known launchers to the 'file'
+ */
+static void dump_launchers(FILE *file)
 {
 	int j, k;
-	struct desc_list *desc;
+	struct desc_launcher *desc;
 	struct type_list *type;
 
 	for (desc = launchers ; desc != NULL ; desc = desc->next) {
-		printf("mode %s\n", name_of_launch_mode(desc->mode));
+		fprintf(file, "mode %s\n", name_of_launch_mode(desc->mode));
 		for (type = desc->types ; type != NULL ; type = type->next)
-			printf("%s\n", type->type);
+			fprintf(file, "%s\n", type->type);
 		for ( j = 0 ; j < 2 ; j++)
 			if (desc->execs[j].args != NULL) {
-				for (k = 0 ; desc->execs[j].args[k] != NULL ; k++)
-					printf("  %s", desc->execs[j].args[k]);
-				printf("\n");
+				for (k = 0; desc->execs[j].args[k] != NULL; k++)
+					fprintf(file, "  %s",
+							desc->execs[j].args[k]);
+				fprintf(file, "\n");
 			}
-		printf("\n");
+		fprintf(file, "\n");
 	}
 }
 
+/*
+ * update 'cread' to point the the next token
+ * returns the length of the token that is nul if no
+ * more token exists in the line
+ */
 static int next_token(struct confread *cread)
 {
 	int idx = cread->index + cread->length;
@@ -111,24 +146,38 @@ static int next_token(struct confread *cread)
 	return cread->length;
 }
 
+/*
+ * reads the next line, skipping empty lines or lines
+ * having only comments.
+ * returns either 0 at end of the file, -1 in case of error or
+ * in case of success the length of the first token.
+ */
 static int read_line(struct confread *cread)
 {
 	while (fgets(cread->buffer, sizeof cread->buffer, cread->file) != NULL) {
 		cread->lineno++;
 		cread->index = strspn(cread->buffer, separators);
-		if (cread->buffer[cread->index] && cread->buffer[cread->index] != '#') {
-			cread->length = strcspn(&cread->buffer[cread->index], separators);
+		if (cread->buffer[cread->index]
+		  && cread->buffer[cread->index] != '#') {
+			cread->length = strcspn(&cread->buffer[cread->index],
+								separators);
 			assert(cread->length > 0);
 			return cread->length;
 		}
 	}
 	if (ferror(cread->file)) {
-		ERROR("%s:%d: error while reading, %m", cread->filepath, cread->lineno);
+		ERROR("%s:%d: error while reading, %m", cread->filepath,
+								cread->lineno);
 		return -1;
 	}
 	return 0;
 }
 
+/*
+ * extract from 'cread' a launch vector that is allocated in
+ * one piece of memory.
+ * 'cread' is left unchanged (index and length are not changed)
+ */
 static const char **read_vector(struct confread *cread)
 {
 	int index0, length0;
@@ -172,6 +221,13 @@ static const char **read_vector(struct confread *cread)
 	return vector;
 }
 
+/*
+ * Reads the type from 'cread' directly in the list item and return it.
+ * returns NULL in case or error.
+ * errno:
+ *  - EINVAL     extra characters
+ *  - ENOMEM     memory depletion
+ */
 static struct type_list *read_type(struct confread *cread)
 {
 	int index, length;
@@ -184,7 +240,8 @@ static struct type_list *read_type(struct confread *cread)
 	/* check no extra characters */
 	if (next_token(cread)) {
 		ERROR("%s:%d: extra characters found after type %.*s",
-			cread->filepath, cread->lineno, length, &cread->buffer[index]);
+			cread->filepath, cread->lineno, length,
+						&cread->buffer[index]);
 		errno = EINVAL;
 		return NULL;
 	}
@@ -203,6 +260,12 @@ static struct type_list *read_type(struct confread *cread)
 	return result;
 }
 
+/*
+ * Reads the mode from 'cread' and return it.
+ * returns invalid_launch_mode in case or error.
+ * errno:
+ *  - EINVAL     no mode or extra characters or invalid mode
+ */
 static enum afm_launch_mode read_mode(struct confread *cread)
 {
 	int index, length;
@@ -213,7 +276,8 @@ static enum afm_launch_mode read_mode(struct confread *cread)
 
 	/* get the next token: the mode string */
 	if (!next_token(cread)) {
-		ERROR("%s:%d: no mode value set", cread->filepath, cread->lineno);
+		ERROR("%s:%d: no mode value set", cread->filepath,
+							cread->lineno);
 		errno = EINVAL;
 		return invalid_launch_mode;
 	}
@@ -225,14 +289,15 @@ static enum afm_launch_mode read_mode(struct confread *cread)
 	/* check no extra characters */
 	if (next_token(cread)) {
 		ERROR("%s:%d: extra characters found after mode %.*s",
-			cread->filepath, cread->lineno, length, &cread->buffer[index]);
+			cread->filepath, cread->lineno, length,
+						&cread->buffer[index]);
 		errno = EINVAL;
 		return invalid_launch_mode;
 	}
 
 	/* get the mode */
 	cread->buffer[index + length] = 0;
-	result = launch_mode_of_string(&cread->buffer[index]);
+	result = launch_mode_of_name(&cread->buffer[index]);
 	if (result == invalid_launch_mode) {
 		ERROR("%s:%d: invalid mode value %s",
 			cread->filepath, cread->lineno, &cread->buffer[index]);
@@ -241,6 +306,9 @@ static enum afm_launch_mode read_mode(struct confread *cread)
 	return result;
 }
 
+/*
+ * free the memory used by 'types'
+ */
 static void free_type_list(struct type_list *types)
 {
 	while (types != NULL) {
@@ -250,11 +318,17 @@ static void free_type_list(struct type_list *types)
 	}
 }
 
+/*
+ * reads the configuration file handled by 'cread'
+ * and adds its contents to the launcher list
+ *
+ * returns 0 in case of success or -1 in case of error.
+ */
 static int read_launchers(struct confread *cread)
 {
 	int rc, has_readyfd;
 	struct type_list *types, *lt;
-	struct desc_list *desc;
+	struct desc_launcher *desc;
 	enum afm_launch_mode mode;
 	const char **vector;
 
@@ -270,8 +344,10 @@ static int read_launchers(struct confread *cread)
 			&& !memcmp(&cread->buffer[cread->index], "mode", 4)) {
 				/* check if allowed */
 				if (types != NULL) {
-					ERROR("%s:%d: mode found before launch vector",
-						cread->filepath, cread->lineno);
+					ERROR("%s:%d: mode found before"
+							" launch vector",
+							cread->filepath,
+							cread->lineno);
 					errno = EINVAL;
 					free_type_list(types);
 					return -1;
@@ -283,8 +359,10 @@ static int read_launchers(struct confread *cread)
 					return -1;
 			} else {
 				if (mode == invalid_launch_mode) {
-					ERROR("%s:%d: mode not found before type",
-							cread->filepath, cread->lineno);
+					ERROR("%s:%d: mode not found"
+							" before type",
+							cread->filepath,
+							cread->lineno);
 					errno = EINVAL;
 					assert(types == NULL);
 					return -1;
@@ -304,12 +382,14 @@ static int read_launchers(struct confread *cread)
 				ERROR("%s:%d: untyped launch vector found",
 					cread->filepath, cread->lineno);
 			else
-				ERROR("%s:%d: extra launch vector found (2 max)",
+				ERROR("%s:%d: extra launch vector found"
+					" (the maximum count is 2)",
 					cread->filepath, cread->lineno);
 			errno = EINVAL;
 			return -1;
 		} else {
-			has_readyfd = NULL != strstr(&cread->buffer[cread->index], "%R");
+			has_readyfd = NULL != strstr(
+					&cread->buffer[cread->index], "%R");
 			vector = read_vector(cread);
 			if (vector == NULL) {
 				ERROR("%s:%d: out of memory",
@@ -355,6 +435,12 @@ static int read_launchers(struct confread *cread)
 	return rc;
 }
 
+/*
+ * reads the configuration file 'filepath'
+ * and adds its contents to the launcher list
+ *
+ * returns 0 in case of success or -1 in case of error.
+ */
 static int read_configuration_file(const char *filepath)
 {
 	int rc;
@@ -376,6 +462,27 @@ static int read_configuration_file(const char *filepath)
 	return rc;
 }
 
+/*
+ * Creates a secret in 'buffer'
+ */
+static void mksecret(char buffer[9])
+{
+	snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
+}
+
+/*
+ * Allocates a port and return it.
+ */
+static int mkport()
+{
+	static int port_ring = 12345;
+	int port = port_ring;
+	if (port < 12345 || port > 15432)
+		port = 12345;
+	port_ring = port + 1;
+	return port;
+}
+
 /*
 %% %
 %a appid			desc->appid
@@ -394,11 +501,26 @@ static int read_configuration_file(const char *filepath)
 %W width			desc->width
 */
 
+/*
+ * Union for handling either scalar arguments or vectorial arguments.
+ */
 union arguments {
-	char *scalar;
-	char **vector;
+	char *scalar;  /* string of space separated arguments */
+	char **vector; /* vector of arguments */
 };
 
+/*
+ * Computes the substitutions of 'args' according to the
+ * data of 'desc' and 'params'. The result is a single
+ * piece of memory (that must be freed in one time)
+ * containing either a vector or a string depending on
+ * the value of 'wants_vector'.
+ *
+ * The vectors are made of an array pointers terminated by
+ * the NULL pointer.
+ *
+ * Returns the resulting value or NULL in case of error
+ */
 static union arguments instantiate_arguments(
 	const char * const     *args,
 	struct afm_launch_desc *desc,
@@ -408,35 +530,43 @@ static union arguments instantiate_arguments(
 {
 	const char * const *iter;
 	const char *p, *v;
-	char *data, port[20], width[20], height[20], readyfd[20], mini[3], c, sep;
+	char *data, c, sep;
 	int n, s;
 	union arguments result;
+	char port[20], width[20], height[20], readyfd[20], mini[3];
 
 	/* init */
 	sep = wants_vector ? 0 : ' ';
 	mini[0] = '%';
 	mini[2] = 0;
 
-	/* loop that either compute the size and build the result */
-	result.vector = NULL;
-	result.scalar = NULL;
-	data = NULL;
+	/*
+	 * loop that either compute the size and build the result
+	 * advantage: appears only in one place
+	 */
+	result.vector = NULL; /* initialise both to avoid */
+	result.scalar = NULL; /* a very stupid compiler warning */
+	data = NULL;          /* no data for the first iteration */
 	n = s = 0;
 	for (;;) {
-		iter = args;
-		n = 0;
-		while (*iter) {
-			p = *iter++;
+		/* iterate over arguments */
+		for (n = 0, iter = args ; (p = *iter) != NULL ; iter++) {
+			/* init the vector */
 			if (data && !sep)
 				result.vector[n] = data;
 			n++;
+
+			/* scan the argument */
 			while((c = *p++) != 0) {
 				if (c != '%') {
+					/* standard character */
 					if (data)
 						*data++ = c;
 					else
 						s++;
 				} else {
+					/* substitutions */
+					/* (convert num->string only once) */
 					c = *p++;
 					switch (c) {
 					case 'a': v = desc->appid; break;
@@ -444,7 +574,8 @@ static union arguments instantiate_arguments(
 					case 'D': v = params->datadir; break;
 					case 'H':
 						if(!data)
-							sprintf(height, "%d", desc->height);
+							sprintf(height, "%d",
+								desc->height);
 						v = height;
 						break;
 					case 'h': v = desc->home; break;
@@ -453,20 +584,25 @@ static union arguments instantiate_arguments(
 					case 'n': v = desc->name; break;
 					case 'P':
 						if(!data)
-							sprintf(port, "%d", params->port);
+							sprintf(port, "%d",
+								params->port);
 						v = port;
 						break;
-					case 'p': v = "" /*desc->plugins*/; break;
+					case 'p':
+						v = "" /*TODO:desc->plugins*/;
+						break;
 					case 'R':
 						if(!data)
-							sprintf(readyfd, "%d", params->readyfd);
+							sprintf(readyfd, "%d",
+							     params->readyfd);
 						v = readyfd;
 						break;
 					case 'r': v = desc->path; break;
 					case 'S': v = params->secret; break;
 					case 'W':
 						if(!data)
-							sprintf(width, "%d", desc->width);
+							sprintf(width, "%d",
+								desc->width);
 						v = width;
 						break;
 					case '%':
@@ -482,41 +618,48 @@ static union arguments instantiate_arguments(
 						s += strlen(v);
 				}
 			}
+			/* terminate the argument */
 			if (data)
 				*data++ = sep;
 			else
 				s++;
 		}
-		if (sep) {
-			assert(!wants_vector);
-			if (data) {
-				*--data = 0;
-				return result;
+		if (!data) {
+			/* first iteration: allocation */
+			if (sep) {
+				result.scalar = malloc(s);
+				data = result.scalar;
+			} else {
+				result.vector = malloc((n+1)*sizeof(char*) + s);
+				if (result.vector != NULL)
+					data = (char*)(&result.vector[n + 1]);
 			}
-			/* allocation */
-			result.scalar = malloc(s);
-			if (result.scalar == NULL) {
+			if (!data) {
 				errno = ENOMEM;
 				return result;
 			}
-			data = result.scalar;
 		} else {
-			assert(wants_vector);
-			if (data) {
+			/* second iteration: termination */
+			if (sep)
+				*--data = 0;
+			else
 				result.vector[n] = NULL;
-				return result;
-			}
-			/* allocation */
-			result.vector = malloc((n+1)*sizeof(char*) + s);
-			if (result.vector == NULL) {
-				errno = ENOMEM;
-				return result;
-			}
-			data = (char*)(&result.vector[n + 1]);
+			return result;
 		}
 	}
 }
 
+/*
+ * Launchs (fork-execs) the program described by 'exec'
+ * using the parameters of 'desc' and 'params' to instantiate
+ * it. The created process is attached to the process group 'progrp'.
+ *
+ * After being created and before to be launched, the process
+ * is put in its security environment and its directory is
+ * changed to params->datadir.
+ *
+ * Returns the pid of the created process or -1 in case of error.
+ */
 static pid_t launch(
 	struct afm_launch_desc *desc,
 	struct launchparam     *params,
@@ -568,6 +711,8 @@ static pid_t launch(
 		free(args);
 		pfd.fd = rpipe[0];
 		pfd.events = POLLIN;
+
+		/* wait for readyness */
 		poll(&pfd, 1, ready_timeout);
 		close(rpipe[0]);
 		return pid;
@@ -619,27 +764,43 @@ static pid_t launch(
 	return -1;
 }
 
+/*
+ * Launches the application 'desc' in local mode using
+ * 'params' and store the resulting pids in 'children'.
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
 static int launch_local(
 	struct afm_launch_desc *desc,
 	pid_t                   children[2],
 	struct launchparam     *params
 )
 {
+	/* launches the first, making it group leader */
 	children[0] = launch(desc, params, &params->execs[0], 0);
 	if (children[0] <= 0)
 		return -1;
 
+	/* nothing more to launch ? */
 	if (params->execs[1].args == NULL)
 		return 0;
 
+	/* launches the second in the group of the first */
 	children[1] = launch(desc, params, &params->execs[1], children[0]);
 	if (children[1] > 0)
 		return 0;
 
+	/* kill all on error */
 	killpg(children[0], SIGKILL);
 	return -1;
 }
 
+/*
+ * Launches the application 'desc' in remote mode using
+ * 'params' and store the resulting pids in 'children'.
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
 static int launch_remote(
 	struct afm_launch_desc *desc,
 	pid_t                   children[2],
@@ -652,7 +813,8 @@ static int launch_remote(
 	if (params->execs[1].args == NULL)
 		uri = NULL;
 	else
-		uri = instantiate_arguments(params->execs[1].args, desc, params, 0).scalar;
+		uri = instantiate_arguments(params->execs[1].args, desc,
+							params, 0).scalar;
 	if (uri == NULL) {
 		ERROR("out of memory for remote uri");
 		errno = ENOMEM;
@@ -666,28 +828,20 @@ static int launch_remote(
 		return -1;
 	}
 
+	/* returns the uri in params */
 	*params->uri = uri;
 	return 0;
 }
 
-static void mksecret(char buffer[9])
-{
-	snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
-}
-
-static int mkport()
-{
-	static int port_ring = 12345;
-	int port = port_ring;
-	if (port < 12345 || port > 15432)
-		port = 12345;
-	port_ring = port + 1;
-	return port;
-}
-
-static struct desc_list *search_launcher(const char *type, enum afm_launch_mode mode)
+/*
+ * Searchs the launcher descritpion for the given 'type' and 'mode'
+ *
+ * Returns the description found or NULL if nothing matches.
+ */
+static struct desc_launcher *search_launcher(const char *type,
+						enum afm_launch_mode mode)
 {
-	struct desc_list *dl;
+	struct desc_launcher *dl;
 	struct type_list *tl;
 
 	for (dl = launchers ; dl ; dl = dl->next)
@@ -698,6 +852,13 @@ static struct desc_list *search_launcher(const char *type, enum afm_launch_mode
 	return NULL;
 }
 
+/*
+ * Launches the application described by 'desc'
+ * and, in case of success, returns the resulting data
+ * in 'children' and 'uri'.
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
 int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
 {
 	int rc;
@@ -705,11 +866,11 @@ int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
 	char secret[9];
 	struct launchparam params;
 	const char *type;
-	struct desc_list *dl;
+	struct desc_launcher *dl;
 
 	/* should be init */
 	assert(groupid != 0);
-	assert(launch_mode_is_valid(desc->mode));
+	assert(is_valid_launch_mode(desc->mode));
 	assert(desc->mode == mode_local || uri != NULL);
 	assert(uri == NULL || *uri == NULL);
 
@@ -721,13 +882,15 @@ int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
 	type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
 	dl = search_launcher(type, desc->mode);
 	if (dl == NULL) {
-		ERROR("type %s not found for mode %s!", type, name_of_launch_mode(desc->mode));
+		ERROR("launcher not found for type %s and mode %s!",
+				type, name_of_launch_mode(desc->mode));
 		errno = ENOENT;
 		return -1;
 	}
 
 	/* prepare paths */
-	rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->appid);
+	rc = snprintf(datadir, sizeof datadir, "%s/%s",
+						desc->home, desc->appid);
 	if (rc < 0 || rc >= sizeof datadir) {
 		ERROR("overflow for datadir");
 		errno = EINVAL;
@@ -753,19 +916,25 @@ int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
 	}
 }
 
+/*
+ * Initialise the module
+ *
+ * Returns 0 on success or else -1 in case of failure
+ */
 int afm_launch_initialize()
 {
 	int rc;
 	gid_t r, e, s;
 
+	/* compute the groupid to set at launch */
 	getresgid(&r, &e, &s);
 	if (s && s != e)
-		groupid = s;
+		groupid = s; /* the original groupid is used */
 	else
 		groupid = -1;
 
 	rc = read_configuration_file(FWK_LAUNCH_CONF);
-	/* dump_launchers(); */
+	/* dump_launchers(stderr); */
 	return rc;
 }
 
diff --git a/src/afm-launch.h b/src/afm-launch.h
index 552dd18..ec5a88a 100644
--- a/src/afm-launch.h
+++ b/src/afm-launch.h
@@ -16,18 +16,23 @@
  limitations under the License.
 */
 
+/*
+ * Structure describing what is to be launched
+ */
 struct afm_launch_desc {
-	const char *path;
-	const char *appid;
-	const char *content;
-	const char *type;
-	const char *name;
-	const char *home;
-	const char **plugins;
-	int width;
-	int height;
-	enum afm_launch_mode mode;
+	const char *path;          /* to the widget directory */
+	const char *appid;         /* application identifier */
+	const char *content;       /* content to launch */
+	const char *type;          /* type to launch */
+	const char *name;          /* name of the application */
+	const char *home;          /* home directory of the applications */
+	const char **plugins;      /* plugins for the application */
+	int width;                 /* requested width */
+	int height;                /* requested height */
+	enum afm_launch_mode mode; /* launch mode */
 };
 
 int afm_launch_initialize();
+
 int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri);
+
diff --git a/src/afm-user-daemon.c b/src/afm-user-daemon.c
index 40b5971..04f5fea 100644
--- a/src/afm-user-daemon.c
+++ b/src/afm-user-daemon.c
@@ -37,10 +37,11 @@ static const char appname[] = "afm-user-daemon";
 static void usage()
 {
 	printf(
-		"usage: %s [-q] [-v] [-r rootdir]... [-a appdir]...\n"
+		"usage: %s [-q] [-v] [-m mode] [-r rootdir]... [-a appdir]...\n"
 		"\n"
 		"   -a appdir    adds an application directory\n"
 		"   -r rootdir   adds a root directory of applications\n"
+		"   -m mode      set default launch mode (local or remote)\n"
 		"   -d           run as a daemon\n"
 		"   -q           quiet\n"
 		"   -v           verbose\n"
@@ -52,6 +53,7 @@ static void usage()
 static struct option options[] = {
 	{ "root",        required_argument, NULL, 'r' },
 	{ "application", required_argument, NULL, 'a' },
+	{ "mode",        required_argument, NULL, 'm' },
 	{ "daemon",      no_argument,       NULL, 'd' },
 	{ "quiet",       no_argument,       NULL, 'q' },
 	{ "verbose",     no_argument,       NULL, 'v' },
@@ -126,15 +128,15 @@ static void on_start(struct jreq *jreq, struct json_object *obj)
 	/* get the parameters */
 	mode = invalid_launch_mode;
 	if (j_read_string(obj, &appid)) {
-		mode = default_launch_mode;
+		mode = get_default_launch_mode();
 	} else if (j_read_string_at(obj, "id", &appid)) {
 		if (j_read_string_at(obj, "mode", &modestr)) {
-			mode = launch_mode_of_string(modestr);
+			mode = launch_mode_of_name(modestr);
 		} else {
-			mode = default_launch_mode;
+			mode = get_default_launch_mode();
 		}
 	}
-	if (!launch_mode_is_valid(mode)) {
+	if (!is_valid_launch_mode(mode)) {
 		jbus_reply_error_s(jreq, error_bad_request);
 		return;
 	}
@@ -267,11 +269,12 @@ static int daemonize()
 int main(int ac, char **av)
 {
 	int i, daemon = 0;
+	enum afm_launch_mode mode;
 
 	LOGAUTH(appname);
 
 	/* first interpretation of arguments */
-	while ((i = getopt_long(ac, av, "hdqvr:a:", options, NULL)) >= 0) {
+	while ((i = getopt_long(ac, av, "hdqvr:a:m:", options, NULL)) >= 0) {
 		switch (i) {
 		case 'h':
 			usage();
@@ -290,6 +293,14 @@ int main(int ac, char **av)
 			break;
 		case 'a':
 			break;
+		case 'm':
+			mode = launch_mode_of_name(optarg);
+			if (!is_valid_launch_mode(mode)) {
+				ERROR("invalid mode '%s'", optarg);
+				return 1;
+			}
+			set_default_launch_mode(mode);
+			break;
 		case ':':
 			ERROR("missing argument value");
 			return 1;
@@ -321,7 +332,7 @@ int main(int ac, char **av)
 
 	/* second interpretation of arguments */
 	optind = 1;
-	while ((i = getopt_long(ac, av, "hdqvr:a:", options, NULL)) >= 0) {
+	while ((i = getopt_long(ac, av, "hdqvr:a:m:", options, NULL)) >= 0) {
 		switch (i) {
 		case 'r':
 			if (afm_db_add_root(afdb, optarg)) {
-- 
2.16.6