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>
34 extern char **environ;
37 #include "afm-launch-mode.h"
38 #include "afm-launch.h"
39 #include "secmgr-wrap.h"
41 #define DEFAULT_TYPE "text/html"
44 struct type_list *next;
54 struct desc_list *next;
55 enum afm_launch_mode mode;
56 struct type_list *types;
57 struct exec_vector execs[2];
66 struct exec_vector *execs;
78 struct desc_list *launchers = NULL;
80 static gid_t groupid = 0;
82 static const char separators[] = " \t\n";
83 static const char readystr[] = "READY=1";
84 static const int ready_timeout = 1500;
86 static void dump_launchers()
89 struct desc_list *desc;
90 struct type_list *type;
92 for (desc = launchers ; desc != NULL ; desc = desc->next) {
93 printf("mode %s\n", name_of_launch_mode(desc->mode));
94 for (type = desc->types ; type != NULL ; type = type->next)
95 printf("%s\n", type->type);
96 for ( j = 0 ; j < 2 ; j++)
97 if (desc->execs[j].args != NULL) {
98 for (k = 0 ; desc->execs[j].args[k] != NULL ; k++)
99 printf(" %s", desc->execs[j].args[k]);
106 static int next_token(struct confread *cread)
108 int idx = cread->index + cread->length;
109 cread->index = idx + strspn(&cread->buffer[idx], separators);
110 cread->length = strcspn(&cread->buffer[cread->index], separators);
111 return cread->length;
114 static int read_line(struct confread *cread)
116 while (fgets(cread->buffer, sizeof cread->buffer, cread->file) != NULL) {
118 cread->index = strspn(cread->buffer, separators);
119 if (cread->buffer[cread->index] && cread->buffer[cread->index] != '#') {
120 cread->length = strcspn(&cread->buffer[cread->index], separators);
121 assert(cread->length > 0);
122 return cread->length;
125 if (ferror(cread->file)) {
126 ERROR("%s:%d: error while reading, %m", cread->filepath, cread->lineno);
132 static const char **read_vector(struct confread *cread)
140 index0 = cread->index;
141 length0 = cread->length;
146 while(cread->length) {
148 length += cread->length;
153 cread->index = index0;
154 cread->length = length0;
155 vector = malloc(length + count + (count + 1) * sizeof(char*));
160 args = (char*)(vector + count + 1);
162 while(cread->length) {
163 vector[count++] = args;
164 memcpy(args, &cread->buffer[cread->index], cread->length);
165 args += cread->length;
169 vector[count] = NULL;
170 cread->index = index0;
171 cread->length = length0;
175 static struct type_list *read_type(struct confread *cread)
178 struct type_list *result;
180 /* record index and length */
181 index = cread->index;
182 length = cread->length;
184 /* check no extra characters */
185 if (next_token(cread)) {
186 ERROR("%s:%d: extra characters found after type %.*s",
187 cread->filepath, cread->lineno, length, &cread->buffer[index]);
192 /* allocate structure */
193 result = malloc(sizeof(struct type_list) + length);
194 if (result == NULL) {
195 ERROR("%s:%d: out of memory", cread->filepath, cread->lineno);
200 /* fill the structure */
201 memcpy(result->type, &cread->buffer[index], length);
202 result->type[length] = 0;
206 static enum afm_launch_mode read_mode(struct confread *cread)
209 enum afm_launch_mode result;
211 assert(cread->index == 0);
212 assert(!strncmp(&cread->buffer[cread->index], "mode", 4));
214 /* get the next token: the mode string */
215 if (!next_token(cread)) {
216 ERROR("%s:%d: no mode value set", cread->filepath, cread->lineno);
218 return invalid_launch_mode;
221 /* record index and length */
222 index = cread->index;
223 length = cread->length;
225 /* check no extra characters */
226 if (next_token(cread)) {
227 ERROR("%s:%d: extra characters found after mode %.*s",
228 cread->filepath, cread->lineno, length, &cread->buffer[index]);
230 return invalid_launch_mode;
234 cread->buffer[index + length] = 0;
235 result = launch_mode_of_string(&cread->buffer[index]);
236 if (result == invalid_launch_mode) {
237 ERROR("%s:%d: invalid mode value %s",
238 cread->filepath, cread->lineno, &cread->buffer[index]);
244 static void free_type_list(struct type_list *types)
246 while (types != NULL) {
247 struct type_list *next = types->next;
253 static int read_launchers(struct confread *cread)
256 struct type_list *types, *lt;
257 struct desc_list *desc;
258 enum afm_launch_mode mode;
265 mode = invalid_launch_mode;
266 rc = read_line(cread);
268 if (cread->index == 0) {
269 if (cread->length == 4
270 && !memcmp(&cread->buffer[cread->index], "mode", 4)) {
271 /* check if allowed */
273 ERROR("%s:%d: mode found before launch vector",
274 cread->filepath, cread->lineno);
276 free_type_list(types);
281 mode = read_mode(cread);
282 if (mode == invalid_launch_mode)
285 if (mode == invalid_launch_mode) {
286 ERROR("%s:%d: mode not found before type",
287 cread->filepath, cread->lineno);
289 assert(types == NULL);
293 lt = read_type(cread);
295 free_type_list(types);
302 } else if (types == NULL && desc == NULL) {
304 ERROR("%s:%d: untyped launch vector found",
305 cread->filepath, cread->lineno);
307 ERROR("%s:%d: extra launch vector found (2 max)",
308 cread->filepath, cread->lineno);
312 has_readyfd = NULL != strstr(&cread->buffer[cread->index], "%R");
313 vector = read_vector(cread);
314 if (vector == NULL) {
315 ERROR("%s:%d: out of memory",
316 cread->filepath, cread->lineno);
317 free_type_list(types);
322 assert(desc == NULL);
323 desc = malloc(sizeof * desc);
325 ERROR("%s:%d: out of memory",
326 cread->filepath, cread->lineno);
327 free_type_list(types);
331 desc->next = launchers;
334 desc->execs[0].has_readyfd = has_readyfd;
335 desc->execs[0].args = vector;
336 desc->execs[1].has_readyfd = 0;
337 desc->execs[1].args = NULL;
341 desc->execs[1].has_readyfd = has_readyfd;
342 desc->execs[1].args = vector;
346 rc = read_line(cread);
349 ERROR("%s:%d: end of file found before launch vector",
350 cread->filepath, cread->lineno);
351 free_type_list(types);
358 static int read_configuration_file(const char *filepath)
361 struct confread cread;
363 /* opens the configuration file */
364 cread.file = fopen(filepath, "r");
365 if (cread.file == NULL) {
367 ERROR("can't read file %s: %m", filepath);
371 cread.filepath = filepath;
373 rc = read_launchers(&cread);
382 %c content desc->content
383 %D datadir params->datadir
384 %H height desc->height
385 %h homedir desc->home
386 %I icondir FWK_ICON_DIR
387 %m mime-type desc->type
389 %p plugins desc->plugins
391 %r rootdir desc->path
392 %R readyfd params->readyfd
393 %S secret params->secret
402 static union arguments instantiate_arguments(
403 const char * const *args,
404 struct afm_launch_desc *desc,
405 struct launchparam *params,
409 const char * const *iter;
411 char *data, port[20], width[20], height[20], readyfd[20], mini[3], c, sep;
413 union arguments result;
416 sep = wants_vector ? 0 : ' ';
420 /* loop that either compute the size and build the result */
421 result.vector = NULL;
422 result.scalar = NULL;
431 result.vector[n] = data;
433 while((c = *p++) != 0) {
442 case 'a': v = desc->appid; break;
443 case 'c': v = desc->content; break;
444 case 'D': v = params->datadir; break;
447 sprintf(height, "%d", desc->height);
450 case 'h': v = desc->home; break;
451 case 'I': v = FWK_ICON_DIR; break;
452 case 'm': v = desc->type; break;
453 case 'n': v = desc->name; break;
456 sprintf(port, "%d", params->port);
459 case 'p': v = "" /*desc->plugins*/; break;
462 sprintf(readyfd, "%d", params->readyfd);
465 case 'r': v = desc->path; break;
466 case 'S': v = params->secret; break;
469 sprintf(width, "%d", desc->width);
480 data = stpcpy(data, v);
491 assert(!wants_vector);
497 result.scalar = malloc(s);
498 if (result.scalar == NULL) {
502 data = result.scalar;
504 assert(wants_vector);
506 result.vector[n] = NULL;
510 result.vector = malloc((n+1)*sizeof(char*) + s);
511 if (result.vector == NULL) {
515 data = (char*)(&result.vector[n + 1]);
521 struct afm_launch_desc *desc,
522 struct launchparam *params,
523 struct exec_vector *exec,
533 /* prepare the pipes */
536 ERROR("error while calling pipe2: %m");
540 /* instanciate the arguments */
541 params->readyfd = rpipe[1];
542 args = instantiate_arguments(exec->args, desc, params, 1).vector;
546 ERROR("out of memory in master");
551 /* fork the master child */
555 /********* can't fork ************/
560 ERROR("master fork failed: %m");
565 /********* in the parent process ************/
571 poll(&pfd, 1, ready_timeout);
576 /********* in the child process ************/
580 /* avoid set-gid effect */
581 setresgid(groupid, groupid, groupid);
583 /* enter the process group */
584 rc = setpgid(0, progrp);
586 ERROR("setpgid failed");
590 /* enter security mode */
591 rc = secmgr_prepare_exec(desc->appid);
593 ERROR("call to secmgr_prepare_exec failed: %m");
597 /* enter the datadirectory */
598 rc = mkdir(params->datadir, 0755);
599 if (rc && errno != EEXIST) {
600 ERROR("creation of datadir %s failed: %m", params->datadir);
603 rc = chdir(params->datadir);
605 ERROR("can't enter the datadir %s: %m", params->datadir);
609 /* signal if needed */
610 if (!exec->has_readyfd) {
611 write(rpipe[1], readystr, sizeof(readystr) - 1);
615 /* executes the process */
616 rc = execve(args[0], args, environ);
617 ERROR("failed to exec master %s: %m", args[0]);
622 static int launch_local(
623 struct afm_launch_desc *desc,
625 struct launchparam *params
628 children[0] = launch(desc, params, ¶ms->execs[0], 0);
629 if (children[0] <= 0)
632 if (params->execs[1].args == NULL)
635 children[1] = launch(desc, params, ¶ms->execs[1], children[0]);
639 killpg(children[0], SIGKILL);
643 static int launch_remote(
644 struct afm_launch_desc *desc,
646 struct launchparam *params
651 /* instanciate the uri */
652 if (params->execs[1].args == NULL)
655 uri = instantiate_arguments(params->execs[1].args, desc, params, 0).scalar;
657 ERROR("out of memory for remote uri");
662 /* launch the command */
663 children[0] = launch(desc, params, ¶ms->execs[0], 0);
664 if (children[0] <= 0) {
673 static void mksecret(char buffer[9])
675 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
680 static int port_ring = 12345;
681 int port = port_ring;
682 if (port < 12345 || port > 15432)
684 port_ring = port + 1;
688 static struct desc_list *search_launcher(const char *type, enum afm_launch_mode mode)
690 struct desc_list *dl;
691 struct type_list *tl;
693 for (dl = launchers ; dl ; dl = dl->next)
694 if (dl->mode == mode)
695 for (tl = dl->types ; tl != NULL ; tl = tl->next)
696 if (!strcmp(tl->type, type))
701 int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
704 char datadir[PATH_MAX];
706 struct launchparam params;
708 struct desc_list *dl;
711 assert(groupid != 0);
712 assert(launch_mode_is_valid(desc->mode));
713 assert(desc->mode == mode_local || uri != NULL);
714 assert(uri == NULL || *uri == NULL);
720 /* what launcher ? */
721 type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
722 dl = search_launcher(type, desc->mode);
724 ERROR("type %s not found for mode %s!", type, name_of_launch_mode(desc->mode));
730 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->appid);
731 if (rc < 0 || rc >= sizeof datadir) {
732 ERROR("overflow for datadir");
737 /* make the secret and port */
740 params.port = mkport();
741 params.secret = secret;
742 params.datadir = datadir;
743 params.execs = dl->execs;
745 switch (desc->mode) {
747 return launch_local(desc, children, ¶ms);
749 return launch_remote(desc, children, ¶ms);
756 int afm_launch_initialize()
761 getresgid(&r, &e, &s);
767 rc = read_configuration_file(FWK_LAUNCH_CONF);
768 /* dump_launchers(); */