extern char **environ;
#include "verbose.h"
+#include "afm-launch-mode.h"
#include "afm-launch.h"
#include "secmgr-wrap.h"
#define DEFAULT_TYPE "text/html"
-const char separators[] = " \t\n";
-
-struct execdesc {
- char *type;
- char **execs[2];
+struct type_list {
+ struct type_list *next;
+ char type[1];
};
-struct launchers {
- int count;
- struct execdesc *descs;
+struct desc_list {
+ struct desc_list *next;
+ enum afm_launch_mode mode;
+ struct type_list *types;
+ char **execs[2];
};
-static struct launchers launchers = { 0, NULL };
-
struct launchparam {
int port;
+ char **uri;
const char *secret;
const char *datadir;
const char **master;
const char **slave;
};
+struct confread {
+ const char *filepath;
+ FILE *file;
+ int lineno;
+ int index;
+ int length;
+ char buffer[4096];
+};
+
+struct desc_list *launchers = NULL;
+
static gid_t groupid = 0;
-static int read_type(const char *buffer, const char *filepath, int line)
+const char separators[] = " \t\n";
+
+static void dump_launchers()
{
- size_t length;
- int count;
- struct execdesc *descs;
- char *type;
-
- /* check the type */
- length = strcspn(buffer, separators);
- assert(length);
- if (buffer[length + strspn(buffer + length, separators)] != 0) {
- ERROR("%s:%d: extra characters found after type", filepath, line);
- errno = EINVAL;
- return -1;
+ int j, k;
+ struct desc_list *desc;
+ struct type_list *type;
+
+ for (desc = launchers ; desc != NULL ; desc = desc->next) {
+ printf("mode %s\n", name_of_launch_mode(desc->mode));
+ for (type = desc->types ; type != NULL ; type = type->next)
+ printf("%s\n", type->type);
+ for ( j = 0 ; j < 2 ; j++)
+ if (desc->execs[j] != NULL) {
+ for (k = 0 ; desc->execs[j][k] != NULL ; k++)
+ printf(" %s", desc->execs[j][k]);
+ printf("\n");
+ }
+ printf("\n");
}
+}
- /* allocates data */
- type = strndup(buffer, length);
- count = launchers.count + 1;
- descs = realloc(launchers.descs, count * sizeof(struct execdesc));
- if (descs == NULL || type == NULL) {
- free(type);
- errno = ENOMEM;
+static int next_token(struct confread *cread)
+{
+ int idx = cread->index + cread->length;
+ cread->index = idx + strspn(&cread->buffer[idx], separators);
+ cread->length = strcspn(&cread->buffer[cread->index], separators);
+ return cread->length;
+}
+
+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);
+ assert(cread->length > 0);
+ return cread->length;
+ }
+ }
+ if (ferror(cread->file)) {
+ ERROR("%s:%d: error while reading, %m", cread->filepath, cread->lineno);
return -1;
}
-
- /* fill data */
- launchers.descs = descs;
- descs += count - 1;
- descs->type = type;
- descs->execs[0] = NULL;
- descs->execs[1] = NULL;
- launchers.count = count;
return 0;
}
-static int read_args(const char *buffer, int bottom, int offset, const char *filepath, int line)
+static char **read_vector(struct confread *cread)
{
+ int index0, length0;
char **vector, *args;
- size_t index, len, length;
- int count;
+ int count, length;
+
+ /* record origin */
+ index0 = cread->index;
+ length0 = cread->length;
/* count */
count = 0;
- length = index = 0;
- while(buffer[index]) {
+ length = 0;
+ while(cread->length) {
count++;
- /* skips the spaces */
- len = strcspn(buffer + index, separators);
- length += len;
- /* skips the spaces */
- index += len;
- index += strspn(buffer + index, separators);
+ length += cread->length;
+ next_token(cread);
}
+
/* allocates */
- while (bottom < launchers.count) {
- vector = malloc(length + count + (count + 1) * sizeof(char*));
- if (vector == NULL) {
- ERROR("%s:%d: out of memory", filepath, line);
- return -1;
- }
- args = (char*)(vector + count + 1);
- count = 0;
- index = 0;
- while(buffer[index]) {
- /* skips the spaces */
- len = strcspn(buffer + index, separators);
- vector[count++] = args;
- memcpy(args, buffer + index, len);
- args += len;
- index += len;
- *args++ = 0;
- /* skips the spaces */
- len = strspn(buffer + index, separators);
- index += len;
- }
- vector[count] = NULL;
- launchers.descs[bottom++].execs[offset] = vector;
+ cread->index = index0;
+ cread->length = length0;
+ vector = malloc(length + count + (count + 1) * sizeof(char*));
+ if (vector == NULL)
+ return NULL;
+
+ /* copies */
+ args = (char*)(vector + count + 1);
+ count = 0;
+ while(cread->length) {
+ vector[count++] = args;
+ memcpy(args, &cread->buffer[cread->index], cread->length);
+ args += cread->length;
+ *args++ = 0;
+ next_token(cread);
}
- return 0;
+ vector[count] = NULL;
+ cread->index = index0;
+ cread->length = length0;
+ return vector;
}
-static int read_launchers(FILE *file, const char *filepath)
+static struct type_list *read_type(struct confread *cread)
{
- char buffer[4096];
- int index, line, rc, bottom, offset, typed;
+ int index, length;
+ struct type_list *result;
+
+ /* record index and length */
+ index = cread->index;
+ length = cread->length;
+
+ /* 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]);
+ errno = EINVAL;
+ return NULL;
+ }
+
+ /* allocate structure */
+ result = malloc(sizeof(struct type_list) + length);
+ if (result == NULL) {
+ ERROR("%s:%d: out of memory", cread->filepath, cread->lineno);
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ /* fill the structure */
+ memcpy(result->type, &cread->buffer[index], length);
+ result->type[length] = 0;
+ return result;
+}
+
+static enum afm_launch_mode read_mode(struct confread *cread)
+{
+ int index, length;
+ enum afm_launch_mode result;
+
+ assert(cread->index == 0);
+ assert(!strncmp(&cread->buffer[cread->index], "mode", 4));
+
+ /* get the next token: the mode string */
+ if (!next_token(cread)) {
+ ERROR("%s:%d: no mode value set", cread->filepath, cread->lineno);
+ errno = EINVAL;
+ return invalid_launch_mode;
+ }
+
+ /* record index and length */
+ index = cread->index;
+ length = cread->length;
+
+ /* 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]);
+ errno = EINVAL;
+ return invalid_launch_mode;
+ }
+
+ /* get the mode */
+ cread->buffer[index + length] = 0;
+ result = launch_mode_of_string(&cread->buffer[index]);
+ if (result == invalid_launch_mode) {
+ ERROR("%s:%d: invalid mode value %s",
+ cread->filepath, cread->lineno, &cread->buffer[index]);
+ errno = EINVAL;
+ }
+ return result;
+}
+
+static void free_type_list(struct type_list *types)
+{
+ while (types != NULL) {
+ struct type_list *next = types->next;
+ free(types);
+ types = next;
+ }
+}
+
+static int read_launchers(struct confread *cread)
+{
+ int rc;
+ struct type_list *types, *lt;
+ struct desc_list *desc;
+ enum afm_launch_mode mode;
+ char **vector;
/* reads the file */
- line = 0;
- offset = 0;
- typed = 0;
- bottom = launchers.count;
- while (fgets(buffer, sizeof buffer, file) != NULL) {
- line++;
-
- /* find start of line */
- index = strspn(buffer, separators);
-
- /* skip empty lines and comments */
- if (buffer[index] == 0 || buffer[index] == '#')
- continue;
-
- if (index == 0) {
- if (!typed)
- bottom = launchers.count;
- rc = read_type(buffer, filepath, line);
- if (rc)
- return rc;
- if (!typed) {
- typed = 1;
- offset = 0;
+ lt = NULL;
+ types = NULL;
+ desc = NULL;
+ mode = invalid_launch_mode;
+ rc = read_line(cread);
+ while (rc > 0) {
+ if (cread->index == 0) {
+ if (cread->length == 4
+ && !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);
+ errno = EINVAL;
+ free_type_list(types);
+ return -1;
+ }
+
+ /* read the mode */
+ mode = read_mode(cread);
+ if (mode == invalid_launch_mode)
+ return -1;
+ } else {
+ if (mode == invalid_launch_mode) {
+ ERROR("%s:%d: mode not found before type",
+ cread->filepath, cread->lineno);
+ errno = EINVAL;
+ assert(types == NULL);
+ return -1;
+ }
+ /* read a type */
+ lt = read_type(cread);
+ if (lt == NULL) {
+ free_type_list(types);
+ return -1;
+ }
+ lt->next = types;
+ types = lt;
}
- } else if (!typed && !offset) {
- ERROR("%s:%d: untyped launcher found", filepath, line);
- errno = EINVAL;
- return -1;
- } else if (offset >= 2) {
- ERROR("%s:%d: extra launcher found", filepath, line);
+ desc = NULL;
+ } else if (types == NULL && desc == NULL) {
+ if (lt == NULL)
+ ERROR("%s:%d: untyped launch vector found",
+ cread->filepath, cread->lineno);
+ else
+ ERROR("%s:%d: extra launch vector found (2 max)",
+ cread->filepath, cread->lineno);
errno = EINVAL;
return -1;
} else {
- rc = read_args(buffer + index, bottom, offset, filepath, line);
- if (rc)
- return rc;
- offset++;
- typed = 0;
+ vector = read_vector(cread);
+ if (vector == NULL) {
+ ERROR("%s:%d: out of memory",
+ cread->filepath, cread->lineno);
+ free_type_list(types);
+ errno = ENOMEM;
+ return -1;
+ }
+ if (types) {
+ assert(desc == NULL);
+ desc = malloc(sizeof * desc);
+ if (desc == NULL) {
+ ERROR("%s:%d: out of memory",
+ cread->filepath, cread->lineno);
+ free_type_list(types);
+ errno = ENOMEM;
+ return -1;
+ }
+ desc->next = launchers;
+ desc->mode = mode;
+ desc->types = types;
+ desc->execs[0] = vector;
+ desc->execs[1] = NULL;
+ types = NULL;
+ launchers = desc;
+ } else {
+ desc->execs[1] = vector;
+ desc = NULL;
+ }
}
+ rc = read_line(cread);
}
- if (ferror(file)) {
- ERROR("%s:%d: error while reading, %m", filepath, line);
+ if (types != NULL) {
+ ERROR("%s:%d: end of file found before launch vector",
+ cread->filepath, cread->lineno);
+ free_type_list(types);
+ errno = EINVAL;
return -1;
}
- return 0;
+ return rc;
}
static int read_configuration_file(const char *filepath)
{
int rc;
- FILE *file;
+ struct confread cread;
/* opens the configuration file */
- file = fopen(filepath, "r");
- if (file == NULL) {
+ cread.file = fopen(filepath, "r");
+ if (cread.file == NULL) {
/* error */
ERROR("can't read file %s: %m", filepath);
rc = -1;
} else {
/* reads it */
- rc = read_launchers(file, filepath);
- fclose(file);
+ cread.filepath = filepath;
+ cread.lineno = 0;
+ rc = read_launchers(&cread);
+ fclose(cread.file);
}
return rc;
}
%% %
*/
-static char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params)
+union arguments {
+ char *scalar;
+ char **vector;
+};
+
+static union arguments instantiate_arguments(
+ const char **args,
+ struct afm_launch_desc *desc,
+ struct launchparam *params,
+ int wants_vector
+)
{
const char **iter, *p, *v;
- char *data, **result, port[20], width[20], height[20], mini[3], c;
+ char *data, port[20], width[20], height[20], mini[3], c, sep;
int n, s;
+ union arguments result;
/* 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;
- result = NULL;
n = s = 0;
for (;;) {
iter = args;
n = 0;
while (*iter) {
p = *iter++;
- if (data)
- result[n] = data;
+ if (data && !sep)
+ result.vector[n] = data;
n++;
while((c = *p++) != 0) {
if (c != '%') {
c = *p++;
switch (c) {
case 'I': v = FWK_ICON_DIR; break;
- case 'P': if(!data) sprintf(port, "%d", params->port); v = port; break;
case 'S': v = params->secret; break;
case 'D': v = params->datadir; break;
case 'r': v = desc->path; break;
case 'm': v = desc->type; break;
case 'n': v = desc->name; break;
case 'p': v = "" /*desc->plugins*/; break;
- case 'W': if(!data) sprintf(width, "%d", desc->width); v = width; break;
- case 'H': if(!data) sprintf(height, "%d", desc->height); v = height; break;
- case '%': c = 0;
- default: mini[1] = c; v = mini; break;
+ case 'P':
+ if(!data)
+ sprintf(port, "%d", params->port);
+ v = port;
+ break;
+ case 'W':
+ if(!data)
+ sprintf(width, "%d", desc->width);
+ v = width;
+ break;
+ case 'H':
+ if(!data)
+ sprintf(height, "%d", desc->height);
+ v = height;
+ break;
+ case '%':
+ c = 0;
+ default:
+ mini[1] = c;
+ v = mini;
+ break;
}
if (data)
data = stpcpy(data, v);
}
}
if (data)
- *data++ = 0;
+ *data++ = sep;
else
s++;
}
- if (data) {
- result[n] = NULL;
- return result;
- }
- /* allocation */
- result = malloc((n+1)*sizeof(char*) + s);
- if (result == NULL) {
- errno = ENOMEM;
- return NULL;
+ if (sep) {
+ assert(!wants_vector);
+ if (data) {
+ *--data = 0;
+ return result;
+ }
+ /* allocation */
+ result.scalar = malloc(s);
+ if (result.scalar == NULL) {
+ errno = ENOMEM;
+ return result;
+ }
+ data = result.scalar;
+ } else {
+ assert(wants_vector);
+ if (data) {
+ 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]);
}
- data = (char*)(&result[n + 1]);
}
}
return port;
}
-static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
+static int launch_local_1(
+ struct afm_launch_desc *desc,
+ pid_t children[2],
+ struct launchparam *params
+)
{
int rc;
char **args;
_exit(1);
}
- args = instantiate_arguments(params->master, desc, params);
+ args = instantiate_arguments(params->master, desc, params, 1).vector;
if (args == NULL) {
ERROR("out of memory in master");
}
_exit(1);
}
-static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
+static int launch_local_2(
+ struct afm_launch_desc *desc,
+ pid_t children[2],
+ struct launchparam *params
+)
{
int rc;
char message[10];
_exit(1);
}
- args = instantiate_arguments(params->slave, desc, params);
+ args = instantiate_arguments(params->slave, desc, params, 1).vector;
if (args == NULL) {
ERROR("out of memory in slave");
}
/********* still in the master child ************/
close(spipe[1]);
- args = instantiate_arguments(params->master, desc, params);
+ args = instantiate_arguments(params->master, desc, params, 1).vector;
if (args == NULL) {
ERROR("out of memory in master");
}
_exit(1);
}
+static int launch_local(
+ struct afm_launch_desc *desc,
+ pid_t children[2],
+ struct launchparam *params
+)
+{
+ if (params->slave == NULL)
+ return launch_local_1(desc, children, params);
+ return launch_local_2(desc, children, params);
+}
+
+static int launch_remote(
+ struct afm_launch_desc *desc,
+ pid_t children[2],
+ struct launchparam *params
+)
+{
+ int rc;
+ char *uri;
+
+ /* instanciate the uri */
+ if (params->slave == NULL)
+ uri = NULL;
+ else
+ uri = instantiate_arguments(params->slave, desc, params, 0).scalar;
+ if (uri == NULL) {
+ ERROR("out of memory for remote uri");
+ errno = ENOMEM;
+ return -1;
+ }
+
+ /* launch the command */
+ rc = launch_local_1(desc, children, params);
+ if (rc)
+ free(uri);
+ else
+ *params->uri = uri;
+ return rc;
+}
+
int afm_launch_initialize()
{
+ int rc;
gid_t r, e, s;
+
getresgid(&r, &e, &s);
if (s && s != e)
groupid = s;
else
groupid = -1;
- return read_configuration_file(FWK_LAUNCH_CONF);
+
+ rc = read_configuration_file(FWK_LAUNCH_CONF);
+ dump_launchers();
+ return rc;
}
-int afm_launch(struct afm_launch_desc *desc, pid_t children[2])
+static struct desc_list *search_launcher(const char *type, enum afm_launch_mode mode)
{
+ struct desc_list *dl;
+ struct type_list *tl;
+
+ for (dl = launchers ; dl ; dl = dl->next)
+ if (dl->mode == mode)
+ for (tl = dl->types ; tl != NULL ; tl = tl->next)
+ if (!strcmp(tl->type, type))
+ return dl;
+ return NULL;
+}
+
+int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
+{
+ int rc;
char datadir[PATH_MAX];
- int ikl, rc;
char secret[9];
struct launchparam params;
const char *type;
+ struct desc_list *dl;
/* should be init */
assert(groupid != 0);
+ assert(launch_mode_is_valid(desc->mode));
+ assert(desc->mode == mode_local || uri != NULL);
+ assert(uri == NULL || *uri == NULL);
/* init */
children[0] = 0;
/* what launcher ? */
type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
- ikl = 0;
- while (ikl < launchers.count && strcmp(type, launchers.descs[ikl].type))
- ikl++;
- if (ikl == launchers.count) {
- ERROR("type %s not found!", 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));
errno = ENOENT;
return -1;
}
/* make the secret and port */
mksecret(secret);
+ params.uri = uri;
params.port = mkport();
params.secret = secret;
params.datadir = datadir;
- params.master = (const char **)launchers.descs[ikl].execs[0];
- params.slave = (const char **)launchers.descs[ikl].execs[1];
-
- return params.slave ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);
+ params.master = (const char **)dl->execs[0];
+ params.slave = (const char **)dl->execs[1];
+
+ switch (desc->mode) {
+ case mode_local:
+ return launch_local(desc, children, ¶ms);
+ case mode_remote:
+ return launch_remote(desc, children, ¶ms);
+ default:
+ assert(0);
+ return -1;
+ }
}