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"
42 struct type_list *next;
47 struct desc_list *next;
48 enum afm_launch_mode mode;
49 struct type_list *types;
71 struct desc_list *launchers = NULL;
73 static gid_t groupid = 0;
75 const char separators[] = " \t\n";
77 static void dump_launchers()
80 struct desc_list *desc;
81 struct type_list *type;
83 for (desc = launchers ; desc != NULL ; desc = desc->next) {
84 printf("mode %s\n", name_of_launch_mode(desc->mode));
85 for (type = desc->types ; type != NULL ; type = type->next)
86 printf("%s\n", type->type);
87 for ( j = 0 ; j < 2 ; j++)
88 if (desc->execs[j] != NULL) {
89 for (k = 0 ; desc->execs[j][k] != NULL ; k++)
90 printf(" %s", desc->execs[j][k]);
97 static int next_token(struct confread *cread)
99 int idx = cread->index + cread->length;
100 cread->index = idx + strspn(&cread->buffer[idx], separators);
101 cread->length = strcspn(&cread->buffer[cread->index], separators);
102 return cread->length;
105 static int read_line(struct confread *cread)
107 while (fgets(cread->buffer, sizeof cread->buffer, cread->file) != NULL) {
109 cread->index = strspn(cread->buffer, separators);
110 if (cread->buffer[cread->index] && cread->buffer[cread->index] != '#') {
111 cread->length = strcspn(&cread->buffer[cread->index], separators);
112 assert(cread->length > 0);
113 return cread->length;
116 if (ferror(cread->file)) {
117 ERROR("%s:%d: error while reading, %m", cread->filepath, cread->lineno);
123 static char **read_vector(struct confread *cread)
126 char **vector, *args;
130 index0 = cread->index;
131 length0 = cread->length;
136 while(cread->length) {
138 length += cread->length;
143 cread->index = index0;
144 cread->length = length0;
145 vector = malloc(length + count + (count + 1) * sizeof(char*));
150 args = (char*)(vector + count + 1);
152 while(cread->length) {
153 vector[count++] = args;
154 memcpy(args, &cread->buffer[cread->index], cread->length);
155 args += cread->length;
159 vector[count] = NULL;
160 cread->index = index0;
161 cread->length = length0;
165 static struct type_list *read_type(struct confread *cread)
168 struct type_list *result;
170 /* record index and length */
171 index = cread->index;
172 length = cread->length;
174 /* check no extra characters */
175 if (next_token(cread)) {
176 ERROR("%s:%d: extra characters found after type %.*s",
177 cread->filepath, cread->lineno, length, &cread->buffer[index]);
182 /* allocate structure */
183 result = malloc(sizeof(struct type_list) + length);
184 if (result == NULL) {
185 ERROR("%s:%d: out of memory", cread->filepath, cread->lineno);
190 /* fill the structure */
191 memcpy(result->type, &cread->buffer[index], length);
192 result->type[length] = 0;
196 static enum afm_launch_mode read_mode(struct confread *cread)
199 enum afm_launch_mode result;
201 assert(cread->index == 0);
202 assert(!strncmp(&cread->buffer[cread->index], "mode", 4));
204 /* get the next token: the mode string */
205 if (!next_token(cread)) {
206 ERROR("%s:%d: no mode value set", cread->filepath, cread->lineno);
208 return invalid_launch_mode;
211 /* record index and length */
212 index = cread->index;
213 length = cread->length;
215 /* check no extra characters */
216 if (next_token(cread)) {
217 ERROR("%s:%d: extra characters found after mode %.*s",
218 cread->filepath, cread->lineno, length, &cread->buffer[index]);
220 return invalid_launch_mode;
224 cread->buffer[index + length] = 0;
225 result = launch_mode_of_string(&cread->buffer[index]);
226 if (result == invalid_launch_mode) {
227 ERROR("%s:%d: invalid mode value %s",
228 cread->filepath, cread->lineno, &cread->buffer[index]);
234 static void free_type_list(struct type_list *types)
236 while (types != NULL) {
237 struct type_list *next = types->next;
243 static int read_launchers(struct confread *cread)
246 struct type_list *types, *lt;
247 struct desc_list *desc;
248 enum afm_launch_mode mode;
255 mode = invalid_launch_mode;
256 rc = read_line(cread);
258 if (cread->index == 0) {
259 if (cread->length == 4
260 && !memcmp(&cread->buffer[cread->index], "mode", 4)) {
261 /* check if allowed */
263 ERROR("%s:%d: mode found before launch vector",
264 cread->filepath, cread->lineno);
266 free_type_list(types);
271 mode = read_mode(cread);
272 if (mode == invalid_launch_mode)
275 if (mode == invalid_launch_mode) {
276 ERROR("%s:%d: mode not found before type",
277 cread->filepath, cread->lineno);
279 assert(types == NULL);
283 lt = read_type(cread);
285 free_type_list(types);
292 } else if (types == NULL && desc == NULL) {
294 ERROR("%s:%d: untyped launch vector found",
295 cread->filepath, cread->lineno);
297 ERROR("%s:%d: extra launch vector found (2 max)",
298 cread->filepath, cread->lineno);
302 vector = read_vector(cread);
303 if (vector == NULL) {
304 ERROR("%s:%d: out of memory",
305 cread->filepath, cread->lineno);
306 free_type_list(types);
311 assert(desc == NULL);
312 desc = malloc(sizeof * desc);
314 ERROR("%s:%d: out of memory",
315 cread->filepath, cread->lineno);
316 free_type_list(types);
320 desc->next = launchers;
323 desc->execs[0] = vector;
324 desc->execs[1] = NULL;
328 desc->execs[1] = vector;
332 rc = read_line(cread);
335 ERROR("%s:%d: end of file found before launch vector",
336 cread->filepath, cread->lineno);
337 free_type_list(types);
344 static int read_configuration_file(const char *filepath)
347 struct confread cread;
349 /* opens the configuration file */
350 cread.file = fopen(filepath, "r");
351 if (cread.file == NULL) {
353 ERROR("can't read file %s: %m", filepath);
357 cread.filepath = filepath;
359 rc = read_launchers(&cread);
366 %I icondir FWK_ICON_DIR
368 %S secret params->secret
369 %D datadir params->datadir
370 %r rootdir desc->path
371 %h homedir desc->home
372 %t tag (smack label) desc->tag
374 %c content desc->content
375 %m mime-type desc->type
377 %p plugins desc->plugins
379 %H height desc->height
388 static union arguments instantiate_arguments(
390 struct afm_launch_desc *desc,
391 struct launchparam *params,
395 const char **iter, *p, *v;
396 char *data, port[20], width[20], height[20], mini[3], c, sep;
398 union arguments result;
401 sep = wants_vector ? 0 : ' ';
405 /* loop that either compute the size and build the result */
414 result.vector[n] = data;
416 while((c = *p++) != 0) {
425 case 'I': v = FWK_ICON_DIR; break;
426 case 'S': v = params->secret; break;
427 case 'D': v = params->datadir; break;
428 case 'r': v = desc->path; break;
429 case 'h': v = desc->home; break;
430 case 't': v = desc->tag; break;
431 case 'a': v = desc->appid; break;
432 case 'c': v = desc->content; break;
433 case 'm': v = desc->type; break;
434 case 'n': v = desc->name; break;
435 case 'p': v = "" /*desc->plugins*/; break;
438 sprintf(port, "%d", params->port);
443 sprintf(width, "%d", desc->width);
448 sprintf(height, "%d", desc->height);
459 data = stpcpy(data, v);
470 assert(!wants_vector);
476 result.scalar = malloc(s);
477 if (result.scalar == NULL) {
481 data = result.scalar;
483 assert(wants_vector);
485 result.vector[n] = NULL;
489 result.vector = malloc((n+1)*sizeof(char*) + s);
490 if (result.vector == NULL) {
494 data = (char*)(&result.vector[n + 1]);
499 static void mksecret(char buffer[9])
501 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
506 static int port_ring = 12345;
507 int port = port_ring;
508 if (port < 12345 || port > 15432)
510 port_ring = port + 1;
514 static int launch_local_1(
515 struct afm_launch_desc *desc,
517 struct launchparam *params
523 /* fork the master child */
524 children[0] = fork();
525 if (children[0] < 0) {
526 ERROR("master fork failed: %m");
530 /********* in the parent process ************/
534 /********* in the master child ************/
536 /* avoid set-gid effect */
537 setresgid(groupid, groupid, groupid);
539 /* enter the process group */
542 ERROR("setpgid failed");
546 /* enter security mode */
547 rc = secmgr_prepare_exec(desc->tag);
549 ERROR("call to secmgr_prepare_exec failed: %m");
553 /* enter the datadirectory */
554 rc = mkdir(params->datadir, 0755);
555 if (rc && errno != EEXIST) {
556 ERROR("creation of datadir %s failed: %m", params->datadir);
559 rc = chdir(params->datadir);
561 ERROR("can't enter the datadir %s: %m", params->datadir);
565 args = instantiate_arguments(params->master, desc, params, 1).vector;
567 ERROR("out of memory in master");
570 rc = execve(args[0], args, environ);
571 ERROR("failed to exec master %s: %m", args[0]);
576 static int launch_local_2(
577 struct afm_launch_desc *desc,
579 struct launchparam *params
588 /* prepare the pipes */
589 rc = pipe2(mpipe, O_CLOEXEC);
591 ERROR("error while calling pipe2: %m");
594 rc = pipe2(spipe, O_CLOEXEC);
596 ERROR("error while calling pipe2: %m");
602 /* fork the master child */
603 children[0] = fork();
604 if (children[0] < 0) {
605 ERROR("master fork failed: %m");
613 /********* in the parent process ************/
616 /* wait the ready signal (that transmit the slave pid) */
617 rc = read(mpipe[0], &children[1], sizeof children[1]);
620 ERROR("reading master pipe failed: %m");
624 assert(rc == sizeof children[1]);
625 /* start the child */
626 rc = write(spipe[1], "start", 5);
628 ERROR("writing slave pipe failed: %m");
637 /********* in the master child ************/
641 /* avoid set-gid effect */
642 setresgid(groupid, groupid, groupid);
644 /* enter the process group */
647 ERROR("setpgid failed");
651 /* enter security mode */
652 rc = secmgr_prepare_exec(desc->tag);
654 ERROR("call to secmgr_prepare_exec failed: %m");
658 /* enter the datadirectory */
659 rc = mkdir(params->datadir, 0755);
660 if (rc && errno != EEXIST) {
661 ERROR("creation of datadir %s failed: %m", params->datadir);
664 rc = chdir(params->datadir);
666 ERROR("can't enter the datadir %s: %m", params->datadir);
670 /* fork the slave child */
671 children[1] = fork();
672 if (children[1] < 0) {
673 ERROR("slave fork failed: %m");
676 if (children[1] == 0) {
677 /********* in the slave child ************/
679 rc = read(spipe[0], message, sizeof message);
681 ERROR("reading slave pipe failed: %m");
685 args = instantiate_arguments(params->slave, desc, params, 1).vector;
687 ERROR("out of memory in slave");
690 rc = execve(args[0], args, environ);
691 ERROR("failed to exec slave %s: %m", args[0]);
696 /********* still in the master child ************/
698 args = instantiate_arguments(params->master, desc, params, 1).vector;
700 ERROR("out of memory in master");
703 rc = write(mpipe[1], &children[1], sizeof children[1]);
705 ERROR("can't write master pipe: %m");
709 rc = execve(args[0], args, environ);
710 ERROR("failed to exec master %s: %m", args[0]);
716 static int launch_local(
717 struct afm_launch_desc *desc,
719 struct launchparam *params
722 if (params->slave == NULL)
723 return launch_local_1(desc, children, params);
724 return launch_local_2(desc, children, params);
727 static int launch_remote(
728 struct afm_launch_desc *desc,
730 struct launchparam *params
736 /* instanciate the uri */
737 if (params->slave == NULL)
740 uri = instantiate_arguments(params->slave, desc, params, 0).scalar;
742 ERROR("out of memory for remote uri");
747 /* launch the command */
748 rc = launch_local_1(desc, children, params);
756 int afm_launch_initialize()
761 getresgid(&r, &e, &s);
767 rc = read_configuration_file(FWK_LAUNCH_CONF);
772 static struct desc_list *search_launcher(const char *type, enum afm_launch_mode mode)
774 struct desc_list *dl;
775 struct type_list *tl;
777 for (dl = launchers ; dl ; dl = dl->next)
778 if (dl->mode == mode)
779 for (tl = dl->types ; tl != NULL ; tl = tl->next)
780 if (!strcmp(tl->type, type))
785 int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
788 char datadir[PATH_MAX];
790 struct launchparam params;
792 struct desc_list *dl;
795 assert(groupid != 0);
796 assert(launch_mode_is_valid(desc->mode));
797 assert(desc->mode == mode_local || uri != NULL);
798 assert(uri == NULL || *uri == NULL);
804 /* what launcher ? */
805 type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
806 dl = search_launcher(type, desc->mode);
808 ERROR("type %s not found for mode %s!", type, name_of_launch_mode(desc->mode));
814 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
815 if (rc < 0 || rc >= sizeof datadir) {
816 ERROR("overflow for datadir");
821 /* make the secret and port */
824 params.port = mkport();
825 params.secret = secret;
826 params.datadir = datadir;
827 params.master = (const char **)dl->execs[0];
828 params.slave = (const char **)dl->execs[1];
830 switch (desc->mode) {
832 return launch_local(desc, children, ¶ms);
834 return launch_remote(desc, children, ¶ms);