X-Git-Url: https://gerrit.automotivelinux.org/gerrit/gitweb?a=blobdiff_plain;f=src%2Fafm-launch.c;h=cd820c5be7b8721ea10bab7f5b9e6eedb21f0c97;hb=997dbadce8ee4a3345b5a9074dcf60010c5781bc;hp=bdd5ab1384a0b5ca229248f9153b703e5a5df16f;hpb=ed93a5f30bc5be7daed1738812e090707a319090;p=src%2Fapp-framework-main.git diff --git a/src/afm-launch.c b/src/afm-launch.c index bdd5ab1..cd820c5 100644 --- a/src/afm-launch.c +++ b/src/afm-launch.c @@ -32,9 +32,336 @@ extern char **environ; #include "verbose.h" +#include "afm-launch-mode.h" #include "afm-launch.h" #include "secmgr-wrap.h" +#define DEFAULT_TYPE "text/html" + +struct type_list { + struct type_list *next; + char type[1]; +}; + +struct desc_list { + struct desc_list *next; + enum afm_launch_mode mode; + struct type_list *types; + char **execs[2]; +}; + +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; + +const char separators[] = " \t\n"; + +static void dump_launchers() +{ + 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"); + } +} + +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; + } + return 0; +} + +static char **read_vector(struct confread *cread) +{ + int index0, length0; + char **vector, *args; + int count, length; + + /* record origin */ + index0 = cread->index; + length0 = cread->length; + + /* count */ + count = 0; + length = 0; + while(cread->length) { + count++; + length += cread->length; + next_token(cread); + } + + /* allocates */ + 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); + } + vector[count] = NULL; + cread->index = index0; + cread->length = length0; + return vector; +} + +static struct type_list *read_type(struct confread *cread) +{ + 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 */ + 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; + } + 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 { + 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 (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 rc; +} + +static int read_configuration_file(const char *filepath) +{ + int rc; + struct confread cread; + + /* opens the configuration file */ + cread.file = fopen(filepath, "r"); + if (cread.file == NULL) { + /* error */ + ERROR("can't read file %s: %m", filepath); + rc = -1; + } else { + /* reads it */ + cread.filepath = filepath; + cread.lineno = 0; + rc = read_launchers(&cread); + fclose(cread.file); + } + return rc; +} + /* %I icondir FWK_ICON_DIR %P port params->port @@ -50,70 +377,34 @@ extern char **environ; %p plugins desc->plugins %W width desc->width %H height desc->height +%% % */ -static const char *args_for_afb_daemon[] = { - "/usr/bin/afb-daemon", - "--alias=/icons:%I", - "--port=%P", - "--rootdir=%D", - "--token=%S", - NULL -}; - -static const char *args_for_qmlviewer[] = { - "/usr/bin/qt5/qmlscene", - "-fullscreen", - "-I", - "%r", - "-I", - "%r/imports", - "%r/%c", - NULL -}; - -static const char *args_for_web_runtime[] = { - "/usr/share/qt5/examples/webkitwidgets/browser/browser", - "http://localhost:%P/%c?token=%S", - NULL +union arguments { + char *scalar; + char **vector; }; -static const char *args_for_binary[] = { - "%r/%c", - NULL -}; - -struct execdesc { - const char *type; - const char **master_args; - const char **slave_args; -}; - -static struct execdesc known_launchers[] = { - { "text/html", args_for_afb_daemon, args_for_web_runtime }, - { "application/x-executable", args_for_binary, NULL }, - { "text/vnd.qt.qml", args_for_qmlviewer, NULL } -}; - -struct launchparam { - int port; - const char *secret; - const char *datadir; - const char **master_args; - const char **slave_args; -}; - -static char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params) +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; n = s = 0; for (;;) { @@ -121,8 +412,8 @@ static char **instantiate_arguments(const char **args, struct afm_launch_desc *d 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 != '%') { @@ -134,7 +425,6 @@ static char **instantiate_arguments(const char **args, struct afm_launch_desc *d 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; @@ -145,10 +435,27 @@ static char **instantiate_arguments(const char **args, struct afm_launch_desc *d 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); @@ -157,21 +464,37 @@ static char **instantiate_arguments(const char **args, struct afm_launch_desc *d } } 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]); } } @@ -190,9 +513,11 @@ static int mkport() 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; @@ -209,6 +534,10 @@ static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct l } /********* in the master child ************/ + + /* avoid set-gid effect */ + setresgid(groupid, groupid, groupid); + /* enter the process group */ rc = setpgid(0, 0); if (rc) { @@ -235,7 +564,7 @@ static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct l _exit(1); } - args = instantiate_arguments(params->master_args, desc, params); + args = instantiate_arguments(params->master, desc, params, 1).vector; if (args == NULL) { ERROR("out of memory in master"); } @@ -246,7 +575,11 @@ static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct l _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]; @@ -307,6 +640,9 @@ static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct l close(mpipe[0]); close(spipe[1]); + /* avoid set-gid effect */ + setresgid(groupid, groupid, groupid); + /* enter the process group */ rc = setpgid(0, 0); if (rc) { @@ -348,7 +684,7 @@ static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct l _exit(1); } - args = instantiate_arguments(params->slave_args, desc, params); + args = instantiate_arguments(params->slave, desc, params, 1).vector; if (args == NULL) { ERROR("out of memory in slave"); } @@ -361,7 +697,7 @@ static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct l /********* still in the master child ************/ close(spipe[1]); - args = instantiate_arguments(params->master_args, desc, params); + args = instantiate_arguments(params->master, desc, params, 1).vector; if (args == NULL) { ERROR("out of memory in master"); } @@ -379,24 +715,101 @@ static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct l _exit(1); } -int afm_launch(struct afm_launch_desc *desc, pid_t children[2]) +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; + + rc = read_configuration_file(FWK_LAUNCH_CONF); + dump_launchers(); + return rc; +} + +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, nkl, 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; + children[1] = 0; /* what launcher ? */ - ikl = 0; - if (desc->type != NULL && *desc->type) { - nkl = sizeof known_launchers / sizeof * known_launchers; - while (ikl < nkl && strcmp(desc->type, known_launchers[ikl].type)) - ikl++; - if (ikl == nkl) { - ERROR("type %s not found!", desc->type); - errno = ENOENT; - return -1; - } + 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)); + errno = ENOENT; + return -1; } /* prepare paths */ @@ -409,12 +822,21 @@ int afm_launch(struct afm_launch_desc *desc, pid_t children[2]) /* make the secret and port */ mksecret(secret); + params.uri = uri; params.port = mkport(); params.secret = secret; params.datadir = datadir; - params.master_args = known_launchers[ikl].master_args; - params.slave_args = known_launchers[ikl].slave_args; - - return params.slave_args ? 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; + } }