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 */
406 result.vector = NULL;
407 result.scalar = NULL;
416 result.vector[n] = data;
418 while((c = *p++) != 0) {
427 case 'I': v = FWK_ICON_DIR; break;
428 case 'S': v = params->secret; break;
429 case 'D': v = params->datadir; break;
430 case 'r': v = desc->path; break;
431 case 'h': v = desc->home; break;
432 case 't': v = desc->tag; break;
433 case 'a': v = desc->appid; break;
434 case 'c': v = desc->content; break;
435 case 'm': v = desc->type; break;
436 case 'n': v = desc->name; break;
437 case 'p': v = "" /*desc->plugins*/; break;
440 sprintf(port, "%d", params->port);
445 sprintf(width, "%d", desc->width);
450 sprintf(height, "%d", desc->height);
461 data = stpcpy(data, v);
472 assert(!wants_vector);
478 result.scalar = malloc(s);
479 if (result.scalar == NULL) {
483 data = result.scalar;
485 assert(wants_vector);
487 result.vector[n] = NULL;
491 result.vector = malloc((n+1)*sizeof(char*) + s);
492 if (result.vector == NULL) {
496 data = (char*)(&result.vector[n + 1]);
501 static void mksecret(char buffer[9])
503 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
508 static int port_ring = 12345;
509 int port = port_ring;
510 if (port < 12345 || port > 15432)
512 port_ring = port + 1;
516 static int launch_local_1(
517 struct afm_launch_desc *desc,
519 struct launchparam *params
525 /* fork the master child */
526 children[0] = fork();
527 if (children[0] < 0) {
528 ERROR("master fork failed: %m");
532 /********* in the parent process ************/
536 /********* in the master child ************/
538 /* avoid set-gid effect */
539 setresgid(groupid, groupid, groupid);
541 /* enter the process group */
544 ERROR("setpgid failed");
548 /* enter security mode */
549 rc = secmgr_prepare_exec(desc->tag);
551 ERROR("call to secmgr_prepare_exec failed: %m");
555 /* enter the datadirectory */
556 rc = mkdir(params->datadir, 0755);
557 if (rc && errno != EEXIST) {
558 ERROR("creation of datadir %s failed: %m", params->datadir);
561 rc = chdir(params->datadir);
563 ERROR("can't enter the datadir %s: %m", params->datadir);
567 args = instantiate_arguments(params->master, desc, params, 1).vector;
569 ERROR("out of memory in master");
572 rc = execve(args[0], args, environ);
573 ERROR("failed to exec master %s: %m", args[0]);
578 static int launch_local_2(
579 struct afm_launch_desc *desc,
581 struct launchparam *params
590 /* prepare the pipes */
591 rc = pipe2(mpipe, O_CLOEXEC);
593 ERROR("error while calling pipe2: %m");
596 rc = pipe2(spipe, O_CLOEXEC);
598 ERROR("error while calling pipe2: %m");
604 /* fork the master child */
605 children[0] = fork();
606 if (children[0] < 0) {
607 ERROR("master fork failed: %m");
615 /********* in the parent process ************/
618 /* wait the ready signal (that transmit the slave pid) */
619 rc = read(mpipe[0], &children[1], sizeof children[1]);
622 ERROR("reading master pipe failed: %m");
626 assert(rc == sizeof children[1]);
627 /* start the child */
628 rc = write(spipe[1], "start", 5);
630 ERROR("writing slave pipe failed: %m");
639 /********* in the master child ************/
643 /* avoid set-gid effect */
644 setresgid(groupid, groupid, groupid);
646 /* enter the process group */
649 ERROR("setpgid failed");
653 /* enter security mode */
654 rc = secmgr_prepare_exec(desc->tag);
656 ERROR("call to secmgr_prepare_exec failed: %m");
660 /* enter the datadirectory */
661 rc = mkdir(params->datadir, 0755);
662 if (rc && errno != EEXIST) {
663 ERROR("creation of datadir %s failed: %m", params->datadir);
666 rc = chdir(params->datadir);
668 ERROR("can't enter the datadir %s: %m", params->datadir);
672 /* fork the slave child */
673 children[1] = fork();
674 if (children[1] < 0) {
675 ERROR("slave fork failed: %m");
678 if (children[1] == 0) {
679 /********* in the slave child ************/
681 rc = read(spipe[0], message, sizeof message);
683 ERROR("reading slave pipe failed: %m");
687 args = instantiate_arguments(params->slave, desc, params, 1).vector;
689 ERROR("out of memory in slave");
692 rc = execve(args[0], args, environ);
693 ERROR("failed to exec slave %s: %m", args[0]);
698 /********* still in the master child ************/
700 args = instantiate_arguments(params->master, desc, params, 1).vector;
702 ERROR("out of memory in master");
705 rc = write(mpipe[1], &children[1], sizeof children[1]);
707 ERROR("can't write master pipe: %m");
711 rc = execve(args[0], args, environ);
712 ERROR("failed to exec master %s: %m", args[0]);
718 static int launch_local(
719 struct afm_launch_desc *desc,
721 struct launchparam *params
724 if (params->slave == NULL)
725 return launch_local_1(desc, children, params);
726 return launch_local_2(desc, children, params);
729 static int launch_remote(
730 struct afm_launch_desc *desc,
732 struct launchparam *params
738 /* instanciate the uri */
739 if (params->slave == NULL)
742 uri = instantiate_arguments(params->slave, desc, params, 0).scalar;
744 ERROR("out of memory for remote uri");
749 /* launch the command */
750 rc = launch_local_1(desc, children, params);
758 int afm_launch_initialize()
763 getresgid(&r, &e, &s);
769 rc = read_configuration_file(FWK_LAUNCH_CONF);
774 static struct desc_list *search_launcher(const char *type, enum afm_launch_mode mode)
776 struct desc_list *dl;
777 struct type_list *tl;
779 for (dl = launchers ; dl ; dl = dl->next)
780 if (dl->mode == mode)
781 for (tl = dl->types ; tl != NULL ; tl = tl->next)
782 if (!strcmp(tl->type, type))
787 int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
790 char datadir[PATH_MAX];
792 struct launchparam params;
794 struct desc_list *dl;
797 assert(groupid != 0);
798 assert(launch_mode_is_valid(desc->mode));
799 assert(desc->mode == mode_local || uri != NULL);
800 assert(uri == NULL || *uri == NULL);
806 /* what launcher ? */
807 type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
808 dl = search_launcher(type, desc->mode);
810 ERROR("type %s not found for mode %s!", type, name_of_launch_mode(desc->mode));
816 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
817 if (rc < 0 || rc >= sizeof datadir) {
818 ERROR("overflow for datadir");
823 /* make the secret and port */
826 params.port = mkport();
827 params.secret = secret;
828 params.datadir = datadir;
829 params.master = (const char **)dl->execs[0];
830 params.slave = (const char **)dl->execs[1];
832 switch (desc->mode) {
834 return launch_local(desc, children, ¶ms);
836 return launch_remote(desc, children, ¶ms);