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"
38 #define DEFAULT_TYPE "text/html"
40 const char separators[] = " \t\n";
49 struct execdesc *descs;
52 static struct launchers launchers = { 0, NULL };
62 static gid_t groupid = 0;
73 static void dump_launchers(struct launchers *launchs)
76 for (i = 0 ; i < launchs->count ; i++) {
77 printf("%s\n", launchs->descs[i].type);
78 for ( j = 0 ; j < 2 ; j++)
79 if (launchs->descs[i].execs[j] != NULL) {
80 for (k = 0 ; launchs->descs[i].execs[j][k] != NULL ; k++)
81 printf(" %s", launchs->descs[i].execs[j][k]);
87 static int next_token(struct confread *cread)
89 cread->index += cread->length + strspn(&cread->buffer[cread->index + cread->length], separators);
90 cread->length = strcspn(&cread->buffer[cread->index], separators);
94 static int read_line(struct confread *cread)
96 while (fgets(cread->buffer, sizeof cread->buffer, cread->file) != NULL) {
98 cread->index = strspn(cread->buffer, separators);
99 if (cread->buffer[cread->index] && cread->buffer[cread->index] != '#') {
100 cread->length = strcspn(&cread->buffer[cread->index], separators);
101 assert(cread->length > 0);
102 return cread->length;
105 if (ferror(cread->file)) {
106 ERROR("%s:%d: error while reading, %m", cread->filepath, cread->lineno);
112 static char *dup_token(struct confread *cread)
114 assert(cread->length);
115 return strndup(&cread->buffer[cread->index], cread->length);
118 static char **dup_tokens_vector(struct confread *cread)
121 char **vector, *args;
125 index0 = cread->index;
126 length0 = cread->length;
131 while(cread->length) {
133 length += cread->length;
138 cread->index = index0;
139 cread->length = length0;
140 vector = malloc(length + count + (count + 1) * sizeof(char*));
145 args = (char*)(vector + count + 1);
147 while(cread->length) {
148 vector[count++] = args;
149 memcpy(args, &cread->buffer[cread->index], cread->length);
150 args += cread->length;
154 vector[count] = NULL;
155 cread->index = index0;
156 cread->length = length0;
160 static int read_type(struct confread *cread)
163 struct execdesc *descs;
167 type = dup_token(cread);
169 ERROR("%s:%d: out of memory", cread->filepath, cread->lineno);
175 if (next_token(cread)) {
176 ERROR("%s:%d: extra characters found after type %s", cread->filepath, cread->lineno, type);
183 count = launchers.count + 1;
184 descs = realloc(launchers.descs, count * sizeof(struct execdesc));
192 launchers.descs = descs;
195 descs->execs[0] = NULL;
196 descs->execs[1] = NULL;
197 launchers.count = count;
201 static int read_args(struct confread *cread, int bottom, int offset)
205 while (bottom < launchers.count) {
206 vector = dup_tokens_vector(cread);
207 if (vector == NULL) {
208 ERROR("%s:%d: out of memory", cread->filepath, cread->lineno);
211 launchers.descs[bottom++].execs[offset] = vector;
216 static int read_launchers(struct confread *cread)
218 int rc, bottom, offset, typed;
223 bottom = launchers.count;
224 rc = read_line(cread);
226 if (cread->index == 0) {
228 bottom = launchers.count;
229 rc = read_type(cread);
236 } else if (!typed && !offset) {
237 ERROR("%s:%d: untyped launcher found", cread->filepath, cread->lineno);
240 } else if (offset >= 2) {
241 ERROR("%s:%d: extra launcher found", cread->filepath, cread->lineno);
245 rc = read_args(cread, bottom, offset);
251 rc = read_line(cread);
256 static int read_configuration_file(const char *filepath)
259 struct confread cread;
261 /* opens the configuration file */
262 cread.file = fopen(filepath, "r");
263 if (cread.file == NULL) {
265 ERROR("can't read file %s: %m", filepath);
269 cread.filepath = filepath;
271 rc = read_launchers(&cread);
278 %I icondir FWK_ICON_DIR
280 %S secret params->secret
281 %D datadir params->datadir
282 %r rootdir desc->path
283 %h homedir desc->home
284 %t tag (smack label) desc->tag
286 %c content desc->content
287 %m mime-type desc->type
289 %p plugins desc->plugins
291 %H height desc->height
295 static char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params)
297 const char **iter, *p, *v;
298 char *data, **result, port[20], width[20], height[20], mini[3], c;
305 /* loop that either compute the size and build the result */
317 while((c = *p++) != 0) {
326 case 'I': v = FWK_ICON_DIR; break;
327 case 'P': if(!data) sprintf(port, "%d", params->port); v = port; break;
328 case 'S': v = params->secret; break;
329 case 'D': v = params->datadir; break;
330 case 'r': v = desc->path; break;
331 case 'h': v = desc->home; break;
332 case 't': v = desc->tag; break;
333 case 'a': v = desc->appid; break;
334 case 'c': v = desc->content; break;
335 case 'm': v = desc->type; break;
336 case 'n': v = desc->name; break;
337 case 'p': v = "" /*desc->plugins*/; break;
338 case 'W': if(!data) sprintf(width, "%d", desc->width); v = width; break;
339 case 'H': if(!data) sprintf(height, "%d", desc->height); v = height; break;
341 default: mini[1] = c; v = mini; break;
344 data = stpcpy(data, v);
359 result = malloc((n+1)*sizeof(char*) + s);
360 if (result == NULL) {
364 data = (char*)(&result[n + 1]);
368 static void mksecret(char buffer[9])
370 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
375 static int port_ring = 12345;
376 int port = port_ring;
377 if (port < 12345 || port > 15432)
379 port_ring = port + 1;
383 static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
388 /* fork the master child */
389 children[0] = fork();
390 if (children[0] < 0) {
391 ERROR("master fork failed: %m");
395 /********* in the parent process ************/
399 /********* in the master child ************/
401 /* avoid set-gid effect */
402 setresgid(groupid, groupid, groupid);
404 /* enter the process group */
407 ERROR("setpgid failed");
411 /* enter security mode */
412 rc = secmgr_prepare_exec(desc->tag);
414 ERROR("call to secmgr_prepare_exec failed: %m");
418 /* enter the datadirectory */
419 rc = mkdir(params->datadir, 0755);
420 if (rc && errno != EEXIST) {
421 ERROR("creation of datadir %s failed: %m", params->datadir);
424 rc = chdir(params->datadir);
426 ERROR("can't enter the datadir %s: %m", params->datadir);
430 args = instantiate_arguments(params->master, desc, params);
432 ERROR("out of memory in master");
435 rc = execve(args[0], args, environ);
436 ERROR("failed to exec master %s: %m", args[0]);
441 static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
449 /* prepare the pipes */
450 rc = pipe2(mpipe, O_CLOEXEC);
452 ERROR("error while calling pipe2: %m");
455 rc = pipe2(spipe, O_CLOEXEC);
457 ERROR("error while calling pipe2: %m");
463 /* fork the master child */
464 children[0] = fork();
465 if (children[0] < 0) {
466 ERROR("master fork failed: %m");
474 /********* in the parent process ************/
477 /* wait the ready signal (that transmit the slave pid) */
478 rc = read(mpipe[0], &children[1], sizeof children[1]);
481 ERROR("reading master pipe failed: %m");
485 assert(rc == sizeof children[1]);
486 /* start the child */
487 rc = write(spipe[1], "start", 5);
489 ERROR("writing slave pipe failed: %m");
498 /********* in the master child ************/
502 /* avoid set-gid effect */
503 setresgid(groupid, groupid, groupid);
505 /* enter the process group */
508 ERROR("setpgid failed");
512 /* enter security mode */
513 rc = secmgr_prepare_exec(desc->tag);
515 ERROR("call to secmgr_prepare_exec failed: %m");
519 /* enter the datadirectory */
520 rc = mkdir(params->datadir, 0755);
521 if (rc && errno != EEXIST) {
522 ERROR("creation of datadir %s failed: %m", params->datadir);
525 rc = chdir(params->datadir);
527 ERROR("can't enter the datadir %s: %m", params->datadir);
531 /* fork the slave child */
532 children[1] = fork();
533 if (children[1] < 0) {
534 ERROR("slave fork failed: %m");
537 if (children[1] == 0) {
538 /********* in the slave child ************/
540 rc = read(spipe[0], message, sizeof message);
542 ERROR("reading slave pipe failed: %m");
546 args = instantiate_arguments(params->slave, desc, params);
548 ERROR("out of memory in slave");
551 rc = execve(args[0], args, environ);
552 ERROR("failed to exec slave %s: %m", args[0]);
557 /********* still in the master child ************/
559 args = instantiate_arguments(params->master, desc, params);
561 ERROR("out of memory in master");
564 rc = write(mpipe[1], &children[1], sizeof children[1]);
566 ERROR("can't write master pipe: %m");
570 rc = execve(args[0], args, environ);
571 ERROR("failed to exec master %s: %m", args[0]);
577 int afm_launch_initialize()
582 getresgid(&r, &e, &s);
588 rc = read_configuration_file(FWK_LAUNCH_CONF);
589 dump_launchers(&launchers);
593 int afm_launch(struct afm_launch_desc *desc, pid_t children[2])
595 char datadir[PATH_MAX];
598 struct launchparam params;
602 assert(groupid != 0);
608 /* what launcher ? */
609 type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
611 while (ikl < launchers.count && strcmp(type, launchers.descs[ikl].type))
613 if (ikl == launchers.count) {
614 ERROR("type %s not found!", type);
620 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
621 if (rc < 0 || rc >= sizeof datadir) {
622 ERROR("overflow for datadir");
627 /* make the secret and port */
629 params.port = mkport();
630 params.secret = secret;
631 params.datadir = datadir;
632 params.master = (const char **)launchers.descs[ikl].execs[0];
633 params.slave = (const char **)launchers.descs[ikl].execs[1];
635 return params.slave ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);