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;
64 static int read_type(const char *buffer, const char *filepath, int line)
68 struct execdesc *descs;
72 length = strcspn(buffer, separators);
74 if (buffer[length + strspn(buffer + length, separators)] != 0) {
75 ERROR("%s:%d: extra characters found after type", filepath, line);
81 type = strndup(buffer, length);
82 count = launchers.count + 1;
83 descs = realloc(launchers.descs, count * sizeof(struct execdesc));
84 if (descs == NULL || type == NULL) {
91 launchers.descs = descs;
94 descs->execs[0] = NULL;
95 descs->execs[1] = NULL;
96 launchers.count = count;
100 static int read_args(const char *buffer, int bottom, int offset, const char *filepath, int line)
102 char **vector, *args;
103 size_t index, len, length;
109 while(buffer[index]) {
111 /* skips the spaces */
112 len = strcspn(buffer + index, separators);
114 /* skips the spaces */
116 index += strspn(buffer + index, separators);
119 while (bottom < launchers.count) {
120 vector = malloc(length + count + (count + 1) * sizeof(char*));
121 if (vector == NULL) {
122 ERROR("%s:%d: out of memory", filepath, line);
125 args = (char*)(vector + count + 1);
128 while(buffer[index]) {
129 /* skips the spaces */
130 len = strcspn(buffer + index, separators);
131 vector[count++] = args;
132 memcpy(args, buffer + index, len);
136 /* skips the spaces */
137 len = strspn(buffer + index, separators);
140 vector[count] = NULL;
141 launchers.descs[bottom++].execs[offset] = vector;
146 static int read_launchers(FILE *file, const char *filepath)
149 int index, line, rc, bottom, offset, typed;
155 bottom = launchers.count;
156 while (fgets(buffer, sizeof buffer, file) != NULL) {
159 /* find start of line */
160 index = strspn(buffer, separators);
162 /* skip empty lines and comments */
163 if (buffer[index] == 0 || buffer[index] == '#')
168 bottom = launchers.count;
169 rc = read_type(buffer, filepath, line);
176 } else if (!typed && !offset) {
177 ERROR("%s:%d: untyped launcher found", filepath, line);
180 } else if (offset >= 2) {
181 ERROR("%s:%d: extra launcher found", filepath, line);
185 rc = read_args(buffer + index, bottom, offset, filepath, line);
193 ERROR("%s:%d: error while reading, %m", filepath, line);
199 static int read_configuration_file(const char *filepath)
204 /* opens the configuration file */
205 file = fopen(filepath, "r");
208 ERROR("can't read file %s: %m", filepath);
212 rc = read_launchers(file, filepath);
219 %I icondir FWK_ICON_DIR
221 %S secret params->secret
222 %D datadir params->datadir
223 %r rootdir desc->path
224 %h homedir desc->home
225 %t tag (smack label) desc->tag
227 %c content desc->content
228 %m mime-type desc->type
230 %p plugins desc->plugins
232 %H height desc->height
236 static char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params)
238 const char **iter, *p, *v;
239 char *data, **result, port[20], width[20], height[20], mini[3], c;
246 /* loop that either compute the size and build the result */
258 while((c = *p++) != 0) {
267 case 'I': v = FWK_ICON_DIR; break;
268 case 'P': if(!data) sprintf(port, "%d", params->port); v = port; break;
269 case 'S': v = params->secret; break;
270 case 'D': v = params->datadir; break;
271 case 'r': v = desc->path; break;
272 case 'h': v = desc->home; break;
273 case 't': v = desc->tag; break;
274 case 'a': v = desc->appid; break;
275 case 'c': v = desc->content; break;
276 case 'm': v = desc->type; break;
277 case 'n': v = desc->name; break;
278 case 'p': v = "" /*desc->plugins*/; break;
279 case 'W': if(!data) sprintf(width, "%d", desc->width); v = width; break;
280 case 'H': if(!data) sprintf(height, "%d", desc->height); v = height; break;
282 default: mini[1] = c; v = mini; break;
285 data = stpcpy(data, v);
300 result = malloc((n+1)*sizeof(char*) + s);
301 if (result == NULL) {
305 data = (char*)(&result[n + 1]);
309 static void mksecret(char buffer[9])
311 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
316 static int port_ring = 12345;
317 int port = port_ring;
318 if (port < 12345 || port > 15432)
320 port_ring = port + 1;
324 static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
329 /* fork the master child */
330 children[0] = fork();
331 if (children[0] < 0) {
332 ERROR("master fork failed: %m");
336 /********* in the parent process ************/
340 /********* in the master child ************/
342 /* avoid set-gid effect */
343 setresgid(groupid, groupid, groupid);
345 /* enter the process group */
348 ERROR("setpgid failed");
352 /* enter security mode */
353 rc = secmgr_prepare_exec(desc->tag);
355 ERROR("call to secmgr_prepare_exec failed: %m");
359 /* enter the datadirectory */
360 rc = mkdir(params->datadir, 0755);
361 if (rc && errno != EEXIST) {
362 ERROR("creation of datadir %s failed: %m", params->datadir);
365 rc = chdir(params->datadir);
367 ERROR("can't enter the datadir %s: %m", params->datadir);
371 args = instantiate_arguments(params->master, desc, params);
373 ERROR("out of memory in master");
376 rc = execve(args[0], args, environ);
377 ERROR("failed to exec master %s: %m", args[0]);
382 static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
390 /* prepare the pipes */
391 rc = pipe2(mpipe, O_CLOEXEC);
393 ERROR("error while calling pipe2: %m");
396 rc = pipe2(spipe, O_CLOEXEC);
398 ERROR("error while calling pipe2: %m");
404 /* fork the master child */
405 children[0] = fork();
406 if (children[0] < 0) {
407 ERROR("master fork failed: %m");
415 /********* in the parent process ************/
418 /* wait the ready signal (that transmit the slave pid) */
419 rc = read(mpipe[0], &children[1], sizeof children[1]);
422 ERROR("reading master pipe failed: %m");
426 assert(rc == sizeof children[1]);
427 /* start the child */
428 rc = write(spipe[1], "start", 5);
430 ERROR("writing slave pipe failed: %m");
439 /********* in the master child ************/
443 /* avoid set-gid effect */
444 setresgid(groupid, groupid, groupid);
446 /* enter the process group */
449 ERROR("setpgid failed");
453 /* enter security mode */
454 rc = secmgr_prepare_exec(desc->tag);
456 ERROR("call to secmgr_prepare_exec failed: %m");
460 /* enter the datadirectory */
461 rc = mkdir(params->datadir, 0755);
462 if (rc && errno != EEXIST) {
463 ERROR("creation of datadir %s failed: %m", params->datadir);
466 rc = chdir(params->datadir);
468 ERROR("can't enter the datadir %s: %m", params->datadir);
472 /* fork the slave child */
473 children[1] = fork();
474 if (children[1] < 0) {
475 ERROR("slave fork failed: %m");
478 if (children[1] == 0) {
479 /********* in the slave child ************/
481 rc = read(spipe[0], message, sizeof message);
483 ERROR("reading slave pipe failed: %m");
487 args = instantiate_arguments(params->slave, desc, params);
489 ERROR("out of memory in slave");
492 rc = execve(args[0], args, environ);
493 ERROR("failed to exec slave %s: %m", args[0]);
498 /********* still in the master child ************/
500 args = instantiate_arguments(params->master, desc, params);
502 ERROR("out of memory in master");
505 rc = write(mpipe[1], &children[1], sizeof children[1]);
507 ERROR("can't write master pipe: %m");
511 rc = execve(args[0], args, environ);
512 ERROR("failed to exec master %s: %m", args[0]);
518 int afm_launch_initialize()
521 getresgid(&r, &e, &s);
526 return read_configuration_file(FWK_LAUNCH_CONF);
529 int afm_launch(struct afm_launch_desc *desc, pid_t children[2])
531 char datadir[PATH_MAX];
534 struct launchparam params;
538 assert(groupid != 0);
544 /* what launcher ? */
545 type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
547 while (ikl < launchers.count && strcmp(type, launchers.descs[ikl].type))
549 if (ikl == launchers.count) {
550 ERROR("type %s not found!", type);
556 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
557 if (rc < 0 || rc >= sizeof datadir) {
558 ERROR("overflow for datadir");
563 /* make the secret and port */
565 params.port = mkport();
566 params.secret = secret;
567 params.datadir = datadir;
568 params.master = (const char **)launchers.descs[ikl].execs[0];
569 params.slave = (const char **)launchers.descs[ikl].execs[1];
571 return params.slave ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);