4 author: José Bollo <jose.bollo@iot.bzh>
6 Licensed under the Apache License, Version 2.0 (the "License");
7 you may not use this file except in compliance with the License.
8 You may obtain a copy of the License at
10 http://www.apache.org/licenses/LICENSE-2.0
12 Unless required by applicable law or agreed to in writing, software
13 distributed under the License is distributed on an "AS IS" BASIS,
14 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 See the License for the specific language governing permissions and
16 limitations under the License.
30 #include <sys/types.h>
32 extern char **environ;
35 #include "afm-launch.h"
36 #include "secmgr-wrap.h"
39 %I icondir FWK_ICON_DIR
41 %S secret params->secret
42 %D datadir params->datadir
45 %t tag (smack label) desc->tag
47 %c content desc->content
48 %m mime-type desc->type
50 %p plugins desc->plugins
52 %H height desc->height
55 #define DEFAULT_TYPE "text/html"
57 const char separators[] = " \t\n";
65 static const char *args_for_afb_daemon[] = {
66 "/usr/bin/afb-daemon",
74 static const char *args_for_qmlviewer[] = {
75 "/usr/bin/qt5/qmlscene",
85 static const char *args_for_web_runtime[] = {
86 "/usr/bin/web-runtime",
87 "http://localhost:%P/%c?token=%S",
91 static const char *args_for_binary[] = {
96 static struct execdesc known_launchers[] = {
97 { "text/html", args_for_afb_daemon, args_for_web_runtime },
98 { "application/x-executable", args_for_binary, NULL },
99 { "text/vnd.qt.qml", args_for_qmlviewer, NULL },
106 struct execdesc *descs;
109 static struct launchers launchers = { 0, NULL };
119 static gid_t groupid = 0;
121 static int read_type(const char *buffer, const char *filepath, int line)
125 struct execdesc *descs;
129 length = strcspn(buffer, separators);
131 if (buffer[length + strspn(buffer + length, separators)] != 0) {
132 ERROR("%s:%d: extra characters found after type", filepath, line);
138 type = strndup(buffer, length);
139 count = launchers.count + 1;
140 descs = realloc(launchers.descs, count * sizeof(struct execdesc));
141 if (descs == NULL || type == NULL) {
148 launchers.descs = descs;
151 descs->execs[0] = NULL;
152 descs->execs[1] = NULL;
153 launchers.count = count;
157 static int read_args(const char *buffer, int bottom, int offset, const char *filepath, int line)
159 char **vector, *args;
160 size_t index, len, length;
166 while(buffer[index]) {
168 /* skips the spaces */
169 len = strcspn(buffer + index, separators);
171 /* skips the spaces */
173 index += strspn(buffer + index, separators);
176 while (bottom < launchers.count) {
177 vector = malloc(length + count + (count + 1) * sizeof(char*));
178 if (vector == NULL) {
179 ERROR("%s:%d: out of memory", filepath, line);
182 args = (char*)(vector + count + 1);
185 while(buffer[index]) {
186 /* skips the spaces */
187 len = strcspn(buffer + index, separators);
188 vector[count++] = args;
189 memcpy(args, buffer + index, len);
193 /* skips the spaces */
194 len = strspn(buffer + index, separators);
197 vector[count] = NULL;
198 launchers.descs[bottom++].execs[offset] = vector;
203 static int read_launchers(FILE *file, const char *filepath)
206 int index, line, rc, bottom, offset, typed;
212 bottom = launchers.count;
213 while (fgets(buffer, sizeof buffer, file) != NULL) {
216 /* find start of line */
217 index = strspn(buffer, separators);
219 /* skip empty lines and comments */
220 if (buffer[index] == 0 || buffer[index] == '#')
225 bottom = launchers.count;
226 rc = read_type(buffer, filepath, line);
233 } else if (!typed && !offset) {
234 ERROR("%s:%d: untyped launcher found", filepath, line);
237 } else if (offset >= 2) {
238 ERROR("%s:%d: extra launcher found", filepath, line);
242 rc = read_args(buffer + index, bottom, offset, filepath, line);
250 ERROR("%s:%d: error while reading, %m", filepath, line);
256 static int read_configuration_file(const char *filepath)
261 /* opens the configuration file */
262 file = fopen(filepath, "r");
265 ERROR("can't read file %s: %m", filepath);
269 rc = read_launchers(file, filepath);
275 static char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params)
277 const char **iter, *p, *v;
278 char *data, **result, port[20], width[20], height[20], mini[3], c;
285 /* loop that either compute the size and build the result */
297 while((c = *p++) != 0) {
306 case 'I': v = FWK_ICON_DIR; break;
307 case 'P': if(!data) sprintf(port, "%d", params->port); v = port; break;
308 case 'S': v = params->secret; break;
309 case 'D': v = params->datadir; break;
310 case 'r': v = desc->path; break;
311 case 'h': v = desc->home; break;
312 case 't': v = desc->tag; break;
313 case 'a': v = desc->appid; break;
314 case 'c': v = desc->content; break;
315 case 'm': v = desc->type; break;
316 case 'n': v = desc->name; break;
317 case 'p': v = "" /*desc->plugins*/; break;
318 case 'W': if(!data) sprintf(width, "%d", desc->width); v = width; break;
319 case 'H': if(!data) sprintf(height, "%d", desc->height); v = height; break;
321 default: mini[1] = c; v = mini; break;
324 data = stpcpy(data, v);
339 result = malloc((n+1)*sizeof(char*) + s);
340 if (result == NULL) {
344 data = (char*)(&result[n + 1]);
348 static void mksecret(char buffer[9])
350 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
355 static int port_ring = 12345;
356 int port = port_ring;
357 if (port < 12345 || port > 15432)
359 port_ring = port + 1;
363 static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
368 /* fork the master child */
369 children[0] = fork();
370 if (children[0] < 0) {
371 ERROR("master fork failed: %m");
375 /********* in the parent process ************/
379 /********* in the master child ************/
381 /* avoid set-gid effect */
382 setresgid(groupid, groupid, groupid);
384 /* enter the process group */
387 ERROR("setpgid failed");
391 /* enter security mode */
392 rc = secmgr_prepare_exec(desc->tag);
394 ERROR("call to secmgr_prepare_exec failed: %m");
398 /* enter the datadirectory */
399 rc = mkdir(params->datadir, 0755);
400 if (rc && errno != EEXIST) {
401 ERROR("creation of datadir %s failed: %m", params->datadir);
404 rc = chdir(params->datadir);
406 ERROR("can't enter the datadir %s: %m", params->datadir);
410 args = instantiate_arguments(params->master, desc, params);
412 ERROR("out of memory in master");
415 rc = execve(args[0], args, environ);
416 ERROR("failed to exec master %s: %m", args[0]);
421 static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
429 /* prepare the pipes */
430 rc = pipe2(mpipe, O_CLOEXEC);
432 ERROR("error while calling pipe2: %m");
435 rc = pipe2(spipe, O_CLOEXEC);
437 ERROR("error while calling pipe2: %m");
443 /* fork the master child */
444 children[0] = fork();
445 if (children[0] < 0) {
446 ERROR("master fork failed: %m");
454 /********* in the parent process ************/
457 /* wait the ready signal (that transmit the slave pid) */
458 rc = read(mpipe[0], &children[1], sizeof children[1]);
461 ERROR("reading master pipe failed: %m");
465 assert(rc == sizeof children[1]);
466 /* start the child */
467 rc = write(spipe[1], "start", 5);
469 ERROR("writing slave pipe failed: %m");
478 /********* in the master child ************/
482 /* avoid set-gid effect */
483 setresgid(groupid, groupid, groupid);
485 /* enter the process group */
488 ERROR("setpgid failed");
492 /* enter security mode */
493 rc = secmgr_prepare_exec(desc->tag);
495 ERROR("call to secmgr_prepare_exec failed: %m");
499 /* enter the datadirectory */
500 rc = mkdir(params->datadir, 0755);
501 if (rc && errno != EEXIST) {
502 ERROR("creation of datadir %s failed: %m", params->datadir);
505 rc = chdir(params->datadir);
507 ERROR("can't enter the datadir %s: %m", params->datadir);
511 /* fork the slave child */
512 children[1] = fork();
513 if (children[1] < 0) {
514 ERROR("slave fork failed: %m");
517 if (children[1] == 0) {
518 /********* in the slave child ************/
520 rc = read(spipe[0], message, sizeof message);
522 ERROR("reading slave pipe failed: %m");
526 args = instantiate_arguments(params->slave, desc, params);
528 ERROR("out of memory in slave");
531 rc = execve(args[0], args, environ);
532 ERROR("failed to exec slave %s: %m", args[0]);
537 /********* still in the master child ************/
539 args = instantiate_arguments(params->master, desc, params);
541 ERROR("out of memory in master");
544 rc = write(mpipe[1], &children[1], sizeof children[1]);
546 ERROR("can't write master pipe: %m");
550 rc = execve(args[0], args, environ);
551 ERROR("failed to exec master %s: %m", args[0]);
557 int afm_launch_initialize()
560 getresgid(&r, &e, &s);
565 return read_configuration_file(FWK_LAUNCH_CONF);
568 int afm_launch(struct afm_launch_desc *desc, pid_t children[2])
570 char datadir[PATH_MAX];
573 struct launchparam params;
577 assert(groupid != 0);
583 /* what launcher ? */
584 type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
586 while (ikl < launchers.count && strcmp(type, launchers.descs[ikl].type))
588 if (ikl == launchers.count) {
589 ERROR("type %s not found!", type);
595 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
596 if (rc < 0 || rc >= sizeof datadir) {
597 ERROR("overflow for datadir");
602 /* make the secret and port */
604 params.port = mkport();
605 params.secret = secret;
606 params.datadir = datadir;
607 params.master = (const char **)launchers.descs[ikl].execs[0];
608 params.slave = (const char **)launchers.descs[ikl].execs[1];
610 return params.slave ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);