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-mode.h"
36 #include "afm-launch.h"
37 #include "secmgr-wrap.h"
39 #define DEFAULT_TYPE "text/html"
41 const char separators[] = " \t\n";
50 struct execdesc *descs;
53 static struct launchers launchers = { 0, NULL };
63 static gid_t groupid = 0;
74 static void dump_launchers(struct launchers *launchs)
77 for (i = 0 ; i < launchs->count ; i++) {
78 printf("%s\n", launchs->descs[i].type);
79 for ( j = 0 ; j < 2 ; j++)
80 if (launchs->descs[i].execs[j] != NULL) {
81 for (k = 0 ; launchs->descs[i].execs[j][k] != NULL ; k++)
82 printf(" %s", launchs->descs[i].execs[j][k]);
88 static int next_token(struct confread *cread)
90 cread->index += cread->length + strspn(&cread->buffer[cread->index + cread->length], separators);
91 cread->length = strcspn(&cread->buffer[cread->index], separators);
95 static int read_line(struct confread *cread)
97 while (fgets(cread->buffer, sizeof cread->buffer, cread->file) != NULL) {
99 cread->index = strspn(cread->buffer, separators);
100 if (cread->buffer[cread->index] && cread->buffer[cread->index] != '#') {
101 cread->length = strcspn(&cread->buffer[cread->index], separators);
102 assert(cread->length > 0);
103 return cread->length;
106 if (ferror(cread->file)) {
107 ERROR("%s:%d: error while reading, %m", cread->filepath, cread->lineno);
113 static char *dup_token(struct confread *cread)
115 assert(cread->length);
116 return strndup(&cread->buffer[cread->index], cread->length);
119 static char **dup_tokens_vector(struct confread *cread)
122 char **vector, *args;
126 index0 = cread->index;
127 length0 = cread->length;
132 while(cread->length) {
134 length += cread->length;
139 cread->index = index0;
140 cread->length = length0;
141 vector = malloc(length + count + (count + 1) * sizeof(char*));
146 args = (char*)(vector + count + 1);
148 while(cread->length) {
149 vector[count++] = args;
150 memcpy(args, &cread->buffer[cread->index], cread->length);
151 args += cread->length;
155 vector[count] = NULL;
156 cread->index = index0;
157 cread->length = length0;
161 static int read_type(struct confread *cread)
164 struct execdesc *descs;
168 type = dup_token(cread);
170 ERROR("%s:%d: out of memory", cread->filepath, cread->lineno);
176 if (next_token(cread)) {
177 ERROR("%s:%d: extra characters found after type %s", cread->filepath, cread->lineno, type);
184 count = launchers.count + 1;
185 descs = realloc(launchers.descs, count * sizeof(struct execdesc));
193 launchers.descs = descs;
196 descs->execs[0] = NULL;
197 descs->execs[1] = NULL;
198 launchers.count = count;
202 static int read_args(struct confread *cread, int bottom, int offset)
206 while (bottom < launchers.count) {
207 vector = dup_tokens_vector(cread);
208 if (vector == NULL) {
209 ERROR("%s:%d: out of memory", cread->filepath, cread->lineno);
212 launchers.descs[bottom++].execs[offset] = vector;
217 static int read_launchers(struct confread *cread)
219 int rc, bottom, offset, typed;
224 bottom = launchers.count;
225 rc = read_line(cread);
227 if (cread->index == 0) {
229 bottom = launchers.count;
230 rc = read_type(cread);
237 } else if (!typed && !offset) {
238 ERROR("%s:%d: untyped launcher found", cread->filepath, cread->lineno);
241 } else if (offset >= 2) {
242 ERROR("%s:%d: extra launcher found", cread->filepath, cread->lineno);
246 rc = read_args(cread, bottom, offset);
252 rc = read_line(cread);
257 static int read_configuration_file(const char *filepath)
260 struct confread cread;
262 /* opens the configuration file */
263 cread.file = fopen(filepath, "r");
264 if (cread.file == NULL) {
266 ERROR("can't read file %s: %m", filepath);
270 cread.filepath = filepath;
272 rc = read_launchers(&cread);
279 %I icondir FWK_ICON_DIR
281 %S secret params->secret
282 %D datadir params->datadir
283 %r rootdir desc->path
284 %h homedir desc->home
285 %t tag (smack label) desc->tag
287 %c content desc->content
288 %m mime-type desc->type
290 %p plugins desc->plugins
292 %H height desc->height
296 static char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params)
298 const char **iter, *p, *v;
299 char *data, **result, port[20], width[20], height[20], mini[3], c;
306 /* loop that either compute the size and build the result */
318 while((c = *p++) != 0) {
327 case 'I': v = FWK_ICON_DIR; break;
328 case 'P': if(!data) sprintf(port, "%d", params->port); v = port; break;
329 case 'S': v = params->secret; break;
330 case 'D': v = params->datadir; break;
331 case 'r': v = desc->path; break;
332 case 'h': v = desc->home; break;
333 case 't': v = desc->tag; break;
334 case 'a': v = desc->appid; break;
335 case 'c': v = desc->content; break;
336 case 'm': v = desc->type; break;
337 case 'n': v = desc->name; break;
338 case 'p': v = "" /*desc->plugins*/; break;
339 case 'W': if(!data) sprintf(width, "%d", desc->width); v = width; break;
340 case 'H': if(!data) sprintf(height, "%d", desc->height); v = height; break;
342 default: mini[1] = c; v = mini; break;
345 data = stpcpy(data, v);
360 result = malloc((n+1)*sizeof(char*) + s);
361 if (result == NULL) {
365 data = (char*)(&result[n + 1]);
369 static void mksecret(char buffer[9])
371 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
376 static int port_ring = 12345;
377 int port = port_ring;
378 if (port < 12345 || port > 15432)
380 port_ring = port + 1;
384 static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
389 /* fork the master child */
390 children[0] = fork();
391 if (children[0] < 0) {
392 ERROR("master fork failed: %m");
396 /********* in the parent process ************/
400 /********* in the master child ************/
402 /* avoid set-gid effect */
403 setresgid(groupid, groupid, groupid);
405 /* enter the process group */
408 ERROR("setpgid failed");
412 /* enter security mode */
413 rc = secmgr_prepare_exec(desc->tag);
415 ERROR("call to secmgr_prepare_exec failed: %m");
419 /* enter the datadirectory */
420 rc = mkdir(params->datadir, 0755);
421 if (rc && errno != EEXIST) {
422 ERROR("creation of datadir %s failed: %m", params->datadir);
425 rc = chdir(params->datadir);
427 ERROR("can't enter the datadir %s: %m", params->datadir);
431 args = instantiate_arguments(params->master, desc, params);
433 ERROR("out of memory in master");
436 rc = execve(args[0], args, environ);
437 ERROR("failed to exec master %s: %m", args[0]);
442 static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
450 /* prepare the pipes */
451 rc = pipe2(mpipe, O_CLOEXEC);
453 ERROR("error while calling pipe2: %m");
456 rc = pipe2(spipe, O_CLOEXEC);
458 ERROR("error while calling pipe2: %m");
464 /* fork the master child */
465 children[0] = fork();
466 if (children[0] < 0) {
467 ERROR("master fork failed: %m");
475 /********* in the parent process ************/
478 /* wait the ready signal (that transmit the slave pid) */
479 rc = read(mpipe[0], &children[1], sizeof children[1]);
482 ERROR("reading master pipe failed: %m");
486 assert(rc == sizeof children[1]);
487 /* start the child */
488 rc = write(spipe[1], "start", 5);
490 ERROR("writing slave pipe failed: %m");
499 /********* in the master child ************/
503 /* avoid set-gid effect */
504 setresgid(groupid, groupid, groupid);
506 /* enter the process group */
509 ERROR("setpgid failed");
513 /* enter security mode */
514 rc = secmgr_prepare_exec(desc->tag);
516 ERROR("call to secmgr_prepare_exec failed: %m");
520 /* enter the datadirectory */
521 rc = mkdir(params->datadir, 0755);
522 if (rc && errno != EEXIST) {
523 ERROR("creation of datadir %s failed: %m", params->datadir);
526 rc = chdir(params->datadir);
528 ERROR("can't enter the datadir %s: %m", params->datadir);
532 /* fork the slave child */
533 children[1] = fork();
534 if (children[1] < 0) {
535 ERROR("slave fork failed: %m");
538 if (children[1] == 0) {
539 /********* in the slave child ************/
541 rc = read(spipe[0], message, sizeof message);
543 ERROR("reading slave pipe failed: %m");
547 args = instantiate_arguments(params->slave, desc, params);
549 ERROR("out of memory in slave");
552 rc = execve(args[0], args, environ);
553 ERROR("failed to exec slave %s: %m", args[0]);
558 /********* still in the master child ************/
560 args = instantiate_arguments(params->master, desc, params);
562 ERROR("out of memory in master");
565 rc = write(mpipe[1], &children[1], sizeof children[1]);
567 ERROR("can't write master pipe: %m");
571 rc = execve(args[0], args, environ);
572 ERROR("failed to exec master %s: %m", args[0]);
578 int afm_launch_initialize()
583 getresgid(&r, &e, &s);
589 rc = read_configuration_file(FWK_LAUNCH_CONF);
590 dump_launchers(&launchers);
594 int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
596 char datadir[PATH_MAX];
599 struct launchparam params;
603 assert(groupid != 0);
604 assert(launch_mode_is_valid(desc->mode));
610 /* what launcher ? */
611 type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
613 while (ikl < launchers.count && strcmp(type, launchers.descs[ikl].type))
615 if (ikl == launchers.count) {
616 ERROR("type %s not found!", type);
622 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
623 if (rc < 0 || rc >= sizeof datadir) {
624 ERROR("overflow for datadir");
629 /* make the secret and port */
631 params.port = mkport();
632 params.secret = secret;
633 params.datadir = datadir;
634 params.master = (const char **)launchers.descs[ikl].execs[0];
635 params.slave = (const char **)launchers.descs[ikl].execs[1];
637 return params.slave ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);