bb528e5885ddeda8d961c572551ec27da72d5bc3
[src/app-framework-main.git] / src / afm-launch.c
1 /*
2  Copyright 2015, 2016, 2017 IoT.bzh
3
4  author: José Bollo <jose.bollo@iot.bzh>
5
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
9
10      http://www.apache.org/licenses/LICENSE-2.0
11
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.
17 */
18
19 #define _GNU_SOURCE
20
21 #include <unistd.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <limits.h>
25 #include <errno.h>
26 #include <string.h>
27 #include <fcntl.h>
28 #include <assert.h>
29 #include <sys/stat.h>
30 #include <sys/types.h>
31 #include <poll.h>
32 #include <signal.h>
33
34 extern char **environ;
35
36 #include "verbose.h"
37 #include "afm-launch-mode.h"
38 #include "afm-launch.h"
39 #include "secmgr-wrap.h"
40
41 #define DEFAULT_TYPE "text/html"
42
43 /*
44  * structure for a launching type
45  */
46 struct type_list {
47         struct type_list *next; /* next type */
48         char type[1];           /* type name */
49 };
50
51 /*
52  * structure for launch vectors
53  */
54 struct exec_vector {
55         int has_readyfd;     /* has a request for readyness */
56         const char **args;   /* vector of arguments */
57 };
58
59 struct desc_launcher {
60         struct desc_launcher *next;   /* next launcher description */
61         enum afm_launch_mode mode;    /* the launch mode */
62         struct type_list *types;      /* the launched types */
63         struct exec_vector execs[2];  /* the launching vectors */
64 };
65
66 struct launchparam {
67         int port;
68         int readyfd;
69         char **uri;
70         const char *secret;
71         const char *datadir;
72         struct exec_vector *execs;
73 };
74
75 /*
76  * Structure for reading the configuration file
77  */
78 struct confread {
79         const char *filepath; /* path of the configuration file */
80         FILE *file;           /* handle to the file */
81         int lineno;           /* current line number */
82         int index;            /* start of the current token (in buffer) */
83         int length;           /* length of the current token */
84         char buffer[4096];    /* current line */
85 };
86
87 /*
88  * list of launch descriptions
89  */
90 struct desc_launcher *launchers = NULL;
91
92 /*
93  * the group when launched (to avoid the setgid effect)
94  */
95 static gid_t groupid = 0;
96
97 /*
98  * separators within configuration files
99  */
100 static const char separators[] = " \t\n";
101
102 /*
103  * default string emitted when for application not having signal
104  */
105 static const char readystr[] = "READY=1";
106
107 /*
108  * default time out for readiness of signaling applications
109  */
110 static const int ready_timeout = 1500;
111
112 #if defined(DUMP_LAUNCHERS)
113 /*
114  * dump all the known launchers to the 'file'
115  */
116 static void dump_launchers(FILE *file)
117 {
118         int j, k;
119         struct desc_launcher *desc;
120         struct type_list *type;
121
122         for (desc = launchers ; desc != NULL ; desc = desc->next) {
123                 fprintf(file, "mode %s\n", name_of_launch_mode(desc->mode));
124                 for (type = desc->types ; type != NULL ; type = type->next)
125                         fprintf(file, "%s\n", type->type);
126                 for ( j = 0 ; j < 2 ; j++)
127                         if (desc->execs[j].args != NULL) {
128                                 for (k = 0; desc->execs[j].args[k] != NULL; k++)
129                                         fprintf(file, "  %s",
130                                                         desc->execs[j].args[k]);
131                                 fprintf(file, "\n");
132                         }
133                 fprintf(file, "\n");
134         }
135 }
136 #endif
137
138 /*
139  * update 'cread' to point the the next token
140  * returns the length of the token that is nul if no
141  * more token exists in the line
142  */
143 static int next_token(struct confread *cread)
144 {
145         int idx = cread->index + cread->length;
146         cread->index = idx + (int)strspn(&cread->buffer[idx], separators);
147         cread->length = (int)strcspn(&cread->buffer[cread->index], separators);
148         return cread->length;
149 }
150
151 /*
152  * reads the next line, skipping empty lines or lines
153  * having only comments.
154  * returns either 0 at end of the file, -1 in case of error or
155  * in case of success the length of the first token.
156  */
157 static int read_line(struct confread *cread)
158 {
159         while (fgets(cread->buffer, sizeof cread->buffer, cread->file) != NULL) {
160                 cread->lineno++;
161                 cread->index = (int)strspn(cread->buffer, separators);
162                 if (cread->buffer[cread->index]
163                   && cread->buffer[cread->index] != '#') {
164                         cread->length = (int)strcspn(
165                                 &cread->buffer[cread->index], separators);
166                         assert(cread->length > 0);
167                         return cread->length;
168                 }
169         }
170         if (ferror(cread->file)) {
171                 ERROR("%s:%d: error while reading, %m", cread->filepath,
172                                                                 cread->lineno);
173                 return -1;
174         }
175         return 0;
176 }
177
178 /*
179  * extract from 'cread' a launch vector that is allocated in
180  * one piece of memory.
181  * 'cread' is left unchanged (index and length are not changed)
182  */
183 static const char **read_vector(struct confread *cread)
184 {
185         int index0, length0;
186         const char **vector;
187         char *args;
188         unsigned count, length;
189
190         /* record origin */
191         index0 = cread->index;
192         length0 = cread->length;
193
194         /* count */
195         count = 0;
196         length = 0;
197         while(cread->length) {
198                 count++;
199                 length += (unsigned)cread->length;
200                 next_token(cread);
201         }
202
203         /* allocates */
204         cread->index = index0;
205         cread->length = length0;
206         vector = malloc(length + count + (count + 1) * sizeof(char*));
207         if (vector == NULL)
208                 return NULL;
209
210         /* copies */
211         args = (char*)(vector + count + 1);
212         count = 0;
213         while(cread->length) {
214                 vector[count++] = args;
215                 memcpy(args, &cread->buffer[cread->index],
216                                                 (unsigned)cread->length);
217                 args += cread->length;
218                 *args++ = 0;
219                 next_token(cread);
220         }
221         vector[count] = NULL;
222         cread->index = index0;
223         cread->length = length0;
224         return vector;
225 }
226
227 /*
228  * Reads the type from 'cread' directly in the list item and return it.
229  * returns NULL in case or error.
230  * errno:
231  *  - EINVAL     extra characters
232  *  - ENOMEM     memory depletion
233  */
234 static struct type_list *read_type(struct confread *cread)
235 {
236         int index, length;
237         struct type_list *result;
238
239         /* record index and length */
240         index = cread->index;
241         length = cread->length;
242
243         /* check no extra characters */
244         if (next_token(cread)) {
245                 ERROR("%s:%d: extra characters found after type %.*s",
246                         cread->filepath, cread->lineno, length,
247                                                 &cread->buffer[index]);
248                 errno = EINVAL;
249                 return NULL;
250         }
251
252         /* allocate structure */
253         result = malloc(sizeof(struct type_list) + (unsigned)length);
254         if (result == NULL) {
255                 ERROR("%s:%d: out of memory", cread->filepath, cread->lineno);
256                 errno = ENOMEM;
257                 return NULL;
258         }
259
260         /* fill the structure */
261         memcpy(result->type, &cread->buffer[index], (unsigned)length);
262         result->type[length] = 0;
263         return result;
264 }
265
266 /*
267  * Reads the mode from 'cread' and return it.
268  * returns invalid_launch_mode in case or error.
269  * errno:
270  *  - EINVAL     no mode or extra characters or invalid mode
271  */
272 static enum afm_launch_mode read_mode(struct confread *cread)
273 {
274         int index, length;
275         enum afm_launch_mode result;
276
277         assert(cread->index == 0);
278         assert(!strncmp(&cread->buffer[cread->index], "mode", 4));
279
280         /* get the next token: the mode string */
281         if (!next_token(cread)) {
282                 ERROR("%s:%d: no mode value set", cread->filepath,
283                                                         cread->lineno);
284                 errno = EINVAL;
285                 return invalid_launch_mode;
286         }
287
288         /* record index and length */
289         index = cread->index;
290         length = cread->length;
291
292         /* check no extra characters */
293         if (next_token(cread)) {
294                 ERROR("%s:%d: extra characters found after mode %.*s",
295                         cread->filepath, cread->lineno, length,
296                                                 &cread->buffer[index]);
297                 errno = EINVAL;
298                 return invalid_launch_mode;
299         }
300
301         /* get the mode */
302         cread->buffer[index + length] = 0;
303         result = launch_mode_of_name(&cread->buffer[index]);
304         if (result == invalid_launch_mode) {
305                 ERROR("%s:%d: invalid mode value %s",
306                         cread->filepath, cread->lineno, &cread->buffer[index]);
307                 errno = EINVAL;
308         }
309         return result;
310 }
311
312 /*
313  * free the memory used by 'types'
314  */
315 static void free_type_list(struct type_list *types)
316 {
317         while (types != NULL) {
318                 struct type_list *next = types->next;
319                 free(types);
320                 types = next;
321         }
322 }
323
324 /*
325  * reads the configuration file handled by 'cread'
326  * and adds its contents to the launcher list
327  *
328  * returns 0 in case of success or -1 in case of error.
329  */
330 static int read_launchers(struct confread *cread)
331 {
332         int rc, has_readyfd;
333         struct type_list *types, *lt;
334         struct desc_launcher *desc;
335         enum afm_launch_mode mode;
336         const char **vector;
337
338         /* reads the file */
339         lt = NULL;
340         types = NULL;
341         desc = NULL;
342         mode = invalid_launch_mode;
343         rc = read_line(cread);
344         while (rc > 0) {
345                 if (cread->index == 0) {
346                         if (cread->length == 4
347                         && !memcmp(&cread->buffer[cread->index], "mode", 4)) {
348                                 /* check if allowed */
349                                 if (types != NULL) {
350                                         ERROR("%s:%d: mode found before"
351                                                         " launch vector",
352                                                         cread->filepath,
353                                                         cread->lineno);
354                                         errno = EINVAL;
355                                         free_type_list(types);
356                                         return -1;
357                                 }
358
359                                 /* read the mode */
360                                 mode = read_mode(cread);
361                                 if (mode == invalid_launch_mode)
362                                         return -1;
363                         } else {
364                                 if (mode == invalid_launch_mode) {
365                                         ERROR("%s:%d: mode not found"
366                                                         " before type",
367                                                         cread->filepath,
368                                                         cread->lineno);
369                                         errno = EINVAL;
370                                         assert(types == NULL);
371                                         return -1;
372                                 }
373                                 /* read a type */
374                                 lt = read_type(cread);
375                                 if (lt == NULL) {
376                                         free_type_list(types);
377                                         return -1;
378                                 }
379                                 lt->next = types;
380                                 types = lt;
381                         }
382                         desc = NULL;
383                 } else if (types == NULL && desc == NULL) {
384                         if (lt == NULL)
385                                 ERROR("%s:%d: untyped launch vector found",
386                                         cread->filepath, cread->lineno);
387                         else
388                                 ERROR("%s:%d: extra launch vector found"
389                                         " (the maximum count is 2)",
390                                         cread->filepath, cread->lineno);
391                         errno = EINVAL;
392                         return -1;
393                 } else {
394                         has_readyfd = NULL != strstr(
395                                         &cread->buffer[cread->index], "%R");
396                         vector = read_vector(cread);
397                         if (vector == NULL) {
398                                 ERROR("%s:%d: out of memory",
399                                         cread->filepath, cread->lineno);
400                                 free_type_list(types);
401                                 errno = ENOMEM;
402                                 return -1;
403                         }
404                         if (types) {
405                                 assert(desc == NULL);
406                                 desc = malloc(sizeof * desc);
407                                 if (desc == NULL) {
408                                         ERROR("%s:%d: out of memory",
409                                                 cread->filepath, cread->lineno);
410                                         free_type_list(types);
411                                         errno = ENOMEM;
412                                         return -1;
413                                 }
414                                 desc->next = launchers;
415                                 desc->mode = mode;
416                                 desc->types = types;
417                                 desc->execs[0].has_readyfd = has_readyfd;
418                                 desc->execs[0].args = vector;
419                                 desc->execs[1].has_readyfd = 0;
420                                 desc->execs[1].args = NULL;
421                                 types = NULL;
422                                 launchers = desc;
423                         } else {
424                                 desc->execs[1].has_readyfd = has_readyfd;
425                                 desc->execs[1].args = vector;
426                                 desc = NULL;
427                         }
428                 }
429                 rc = read_line(cread);
430         }
431         if (types != NULL) {
432                 ERROR("%s:%d: end of file found before launch vector",
433                         cread->filepath, cread->lineno);
434                 free_type_list(types);
435                 errno = EINVAL;
436                 return -1;
437         }
438         return rc;
439 }
440
441 /*
442  * reads the configuration file 'filepath'
443  * and adds its contents to the launcher list
444  *
445  * returns 0 in case of success or -1 in case of error.
446  */
447 static int read_configuration_file(const char *filepath)
448 {
449         int rc;
450         struct confread cread;
451
452         /* opens the configuration file */
453         cread.file = fopen(filepath, "r");
454         if (cread.file == NULL) {
455                 /* error */
456                 ERROR("can't read file %s: %m", filepath);
457                 rc = -1;
458         } else {
459                 /* reads it */
460                 cread.filepath = filepath;
461                 cread.lineno = 0;
462                 rc = read_launchers(&cread);
463                 fclose(cread.file);
464         }
465         return rc;
466 }
467
468 /*
469  * Creates a secret in 'buffer'
470  */
471 static void mksecret(char buffer[9])
472 {
473         snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
474 }
475
476 /*
477  * Allocates a port and return it.
478  */
479 static int mkport()
480 {
481         static int port_ring = 12345;
482         int port = port_ring;
483         if (port < 12345 || port > 15432)
484                 port = 12345;
485         port_ring = port + 1;
486         return port;
487 }
488
489 /*
490 %% %
491 %a appid                        desc->appid
492 %b bindings                     desc->bindings
493 %c content                      desc->content
494 %D datadir                      params->datadir
495 %H height                       desc->height
496 %h homedir                      desc->home
497 %I icondir                      FWK_ICON_DIR
498 %m mime-type                    desc->type
499 %n name                         desc->name
500 %P port                         params->port
501 %r rootdir                      desc->path
502 %R readyfd                      params->readyfd
503 %S secret                       params->secret
504 %W width                        desc->width
505 */
506
507 /*
508  * Union for handling either scalar arguments or vectorial arguments.
509  */
510 union arguments {
511         char *scalar;  /* string of space separated arguments */
512         char **vector; /* vector of arguments */
513 };
514
515 /*
516  * Computes the substitutions of 'args' according to the
517  * data of 'desc' and 'params'. The result is a single
518  * piece of memory (that must be freed in one time)
519  * containing either a vector or a string depending on
520  * the value of 'wants_vector'.
521  *
522  * The vectors are made of an array pointers terminated by
523  * the NULL pointer.
524  *
525  * Returns the resulting value or NULL in case of error
526  */
527 static union arguments instantiate_arguments(
528         const char * const     *args,
529         struct afm_launch_desc *desc,
530         struct launchparam     *params,
531         int                     wants_vector
532 )
533 {
534         const char * const *iter;
535         const char *p, *v;
536         char *data, c, sep;
537         unsigned n, s;
538         union arguments result;
539         char port[20], width[20], height[20], readyfd[20], mini[3];
540
541         /* init */
542         sep = wants_vector ? 0 : ' ';
543         mini[0] = '%';
544         mini[2] = 0;
545
546         /*
547          * loop that either compute the size and build the result
548          * advantage: appears only in one place
549          */
550         result.vector = NULL; /* initialise both to avoid */
551         result.scalar = NULL; /* a very stupid compiler warning */
552         data = NULL;          /* no data for the first iteration */
553         n = s = 0;
554         for (;;) {
555                 /* iterate over arguments */
556                 for (n = 0, iter = args ; (p = *iter) != NULL ; iter++) {
557                         /* init the vector */
558                         if (data && !sep)
559                                 result.vector[n] = data;
560                         n++;
561
562                         /* scan the argument */
563                         while((c = *p++) != 0) {
564                                 if (c != '%') {
565                                         /* standard character */
566                                         if (data)
567                                                 *data++ = c;
568                                         else
569                                                 s++;
570                                 } else {
571                                         /* substitutions */
572                                         /* (convert num->string only once) */
573                                         c = *p++;
574                                         switch (c) {
575                                         case 'a': v = desc->appid; break;
576                                         case 'b':
577                                                 v = "" /*TODO:desc->bindings*/;
578                                                 break;
579                                         case 'c': v = desc->content; break;
580                                         case 'D': v = params->datadir; break;
581                                         case 'H':
582                                                 if(!data)
583                                                         sprintf(height, "%d",
584                                                                 desc->height);
585                                                 v = height;
586                                                 break;
587                                         case 'h': v = desc->home; break;
588                                         case 'I': v = FWK_ICON_DIR; break;
589                                         case 'm': v = desc->type; break;
590                                         case 'n': v = desc->name; break;
591                                         case 'P':
592                                                 if(!data)
593                                                         sprintf(port, "%d",
594                                                                 params->port);
595                                                 v = port;
596                                                 break;
597                                         case 'R':
598                                                 if(!data)
599                                                         sprintf(readyfd, "%d",
600                                                              params->readyfd);
601                                                 v = readyfd;
602                                                 break;
603                                         case 'r': v = desc->path; break;
604                                         case 'S': v = params->secret; break;
605                                         case 'W':
606                                                 if(!data)
607                                                         sprintf(width, "%d",
608                                                                 desc->width);
609                                                 v = width;
610                                                 break;
611                                         case '%':
612                                                 c = 0;
613                                         default:
614                                                 mini[1] = c;
615                                                 v = mini;
616                                                 break;
617                                         }
618                                         if (data)
619                                                 data = stpcpy(data, v);
620                                         else
621                                                 s += (unsigned)strlen(v);
622                                 }
623                         }
624                         /* terminate the argument */
625                         if (data)
626                                 *data++ = sep;
627                         else
628                                 s++;
629                 }
630                 if (!data) {
631                         /* first iteration: allocation */
632                         if (sep) {
633                                 result.scalar = malloc(s);
634                                 data = result.scalar;
635                         } else {
636                                 result.vector = malloc((n+1)*sizeof(char*) + s);
637                                 if (result.vector != NULL)
638                                         data = (char*)(&result.vector[n + 1]);
639                         }
640                         if (!data) {
641                                 errno = ENOMEM;
642                                 return result;
643                         }
644                 } else {
645                         /* second iteration: termination */
646                         if (sep)
647                                 *--data = 0;
648                         else
649                                 result.vector[n] = NULL;
650                         return result;
651                 }
652         }
653 }
654
655 /*
656  * Launchs (fork-execs) the program described by 'exec'
657  * using the parameters of 'desc' and 'params' to instantiate
658  * it. The created process is attached to the process group 'progrp'.
659  *
660  * After being created and before to be launched, the process
661  * is put in its security environment and its directory is
662  * changed to params->datadir.
663  *
664  * Returns the pid of the created process or -1 in case of error.
665  */
666 static pid_t launch(
667         struct afm_launch_desc *desc,
668         struct launchparam     *params,
669         struct exec_vector     *exec,
670         pid_t                   progrp
671 )
672 {
673         int rc;
674         char **args, **env;
675         pid_t pid;
676         int rpipe[2];
677         struct pollfd pfd;
678
679         /* prepare the pipes */
680         rc = pipe(rpipe);
681         if (rc < 0) {
682                 ERROR("error while calling pipe2: %m");
683                 return -1;
684         }
685
686         /* instanciate the arguments */
687         params->readyfd = rpipe[1];
688         args = instantiate_arguments(exec->args, desc, params, 1).vector;
689         env = instantiate_arguments((const char * const*)environ,
690                                                 desc, params, 1).vector;
691         if (args == NULL || env == NULL) {
692                 close(rpipe[0]);
693                 close(rpipe[1]);
694                 free(args);
695                 free(env);
696                 ERROR("out of memory in master");
697                 errno = ENOMEM;
698                 return -1;
699         }
700
701         /* fork the master child */
702         pid = fork();
703         if (pid < 0) {
704
705                 /********* can't fork ************/
706
707                 close(rpipe[0]);
708                 close(rpipe[1]);
709                 free(args);
710                 free(env);
711                 ERROR("master fork failed: %m");
712                 return -1;
713         }
714         if (pid) {
715
716                 /********* in the parent process ************/
717
718                 close(rpipe[1]);
719                 free(args);
720                 free(env);
721                 pfd.fd = rpipe[0];
722                 pfd.events = POLLIN;
723
724                 /* wait for readyness */
725                 poll(&pfd, 1, ready_timeout);
726                 close(rpipe[0]);
727                 return pid;
728         }
729
730         /********* in the child process ************/
731
732         close(rpipe[0]);
733
734         /* avoid set-gid effect */
735         setresgid(groupid, groupid, groupid);
736
737         /* enter the process group */
738         rc = setpgid(0, progrp);
739         if (rc) {
740                 ERROR("setpgid failed");
741                 _exit(1);
742         }
743
744         /* enter security mode */
745         rc = secmgr_prepare_exec(desc->appid);
746         if (rc < 0) {
747                 ERROR("call to secmgr_prepare_exec failed: %m");
748                 _exit(1);
749         }
750
751         /* enter the datadirectory */
752         rc = mkdir(params->datadir, 0755);
753         if (rc && errno != EEXIST) {
754                 ERROR("creation of datadir %s failed: %m", params->datadir);
755                 _exit(1);
756         }
757         rc = chdir(params->datadir);
758         if (rc) {
759                 ERROR("can't enter the datadir %s: %m", params->datadir);
760                 _exit(1);
761         }
762
763         /* signal if needed */
764         if (!exec->has_readyfd) {
765                 write(rpipe[1], readystr, sizeof(readystr) - 1);
766                 close(rpipe[1]);
767         }
768
769         /* executes the process */
770         rc = execve(args[0], args, env);
771         ERROR("failed to exec master %s: %m", args[0]);
772         _exit(1);
773         return -1;
774 }
775
776 /*
777  * Launches the application 'desc' in local mode using
778  * 'params' and store the resulting pids in 'children'.
779  *
780  * Returns 0 in case of success or -1 in case of error.
781  */
782 static int launch_local(
783         struct afm_launch_desc *desc,
784         pid_t                   children[2],
785         struct launchparam     *params
786 )
787 {
788         /* launches the first, making it group leader */
789         children[0] = launch(desc, params, &params->execs[0], 0);
790         if (children[0] <= 0)
791                 return -1;
792
793         /* nothing more to launch ? */
794         if (params->execs[1].args == NULL)
795                 return 0;
796
797         /* launches the second in the group of the first */
798         children[1] = launch(desc, params, &params->execs[1], children[0]);
799         if (children[1] > 0)
800                 return 0;
801
802         /* kill all on error */
803         killpg(children[0], SIGKILL);
804         return -1;
805 }
806
807 /*
808  * Launches the application 'desc' in remote mode using
809  * 'params' and store the resulting pids in 'children'.
810  *
811  * Returns 0 in case of success or -1 in case of error.
812  */
813 static int launch_remote(
814         struct afm_launch_desc *desc,
815         pid_t                   children[2],
816         struct launchparam     *params
817 )
818 {
819         char *uri;
820
821         /* instanciate the uri */
822         if (params->execs[1].args == NULL)
823                 uri = NULL;
824         else
825                 uri = instantiate_arguments(params->execs[1].args, desc,
826                                                         params, 0).scalar;
827         if (uri == NULL) {
828                 ERROR("out of memory for remote uri");
829                 errno = ENOMEM;
830                 return -1;
831         }
832
833         /* launch the command */
834         children[0] = launch(desc, params, &params->execs[0], 0);
835         if (children[0] <= 0) {
836                 free(uri);
837                 return -1;
838         }
839
840         /* returns the uri in params */
841         *params->uri = uri;
842         return 0;
843 }
844
845 /*
846  * Searchs the launcher descritpion for the given 'type' and 'mode'
847  *
848  * Returns the description found or NULL if nothing matches.
849  */
850 static struct desc_launcher *search_launcher(const char *type,
851                                                 enum afm_launch_mode mode)
852 {
853         struct desc_launcher *dl;
854         struct type_list *tl;
855
856         for (dl = launchers ; dl ; dl = dl->next)
857                 if (dl->mode == mode)
858                         for (tl = dl->types ; tl != NULL ; tl = tl->next)
859                                 if (!strcasecmp(tl->type, type))
860                                         return dl;
861         return NULL;
862 }
863
864 /*
865  * Launches the application described by 'desc'
866  * and, in case of success, returns the resulting data
867  * in 'children' and 'uri'.
868  *
869  * Returns 0 in case of success or -1 in case of error.
870  */
871 int afm_launch(struct afm_launch_desc *desc, pid_t children[2], char **uri)
872 {
873         int rc;
874         char datadir[PATH_MAX];
875         char secret[9];
876         struct launchparam params;
877         const char *type;
878         struct desc_launcher *dl;
879
880         /* should be init */
881         assert(groupid != 0);
882         assert(is_valid_launch_mode(desc->mode));
883         assert(desc->mode == mode_local || uri != NULL);
884         assert(uri == NULL || *uri == NULL);
885
886         /* init */
887         children[0] = 0;
888         children[1] = 0;
889
890         /* what launcher ? */
891         type = desc->type != NULL && *desc->type ? desc->type : DEFAULT_TYPE;
892         dl = search_launcher(type, desc->mode);
893         if (dl == NULL) {
894                 ERROR("launcher not found for type %s and mode %s!",
895                                 type, name_of_launch_mode(desc->mode));
896                 errno = ENOENT;
897                 return -1;
898         }
899
900         /* prepare paths */
901         rc = snprintf(datadir, sizeof datadir, "%s/%s",
902                                                 desc->home, desc->appid);
903         if (rc < 0 || rc >= (int)sizeof datadir) {
904                 ERROR("overflow for datadir");
905                 errno = EINVAL;
906                 return -1;
907         }
908
909         /* make the secret and port */
910         mksecret(secret);
911         params.uri = uri;
912         params.port = mkport();
913         params.secret = secret;
914         params.datadir = datadir;
915         params.execs = dl->execs;
916
917         switch (desc->mode) {
918         case mode_local:
919                 return launch_local(desc, children, &params);
920         case mode_remote:
921                 return launch_remote(desc, children, &params);
922         default:
923                 assert(0);
924                 return -1;
925         }
926 }
927
928 /*
929  * Initialise the module
930  *
931  * Returns 0 on success or else -1 in case of failure
932  */
933 int afm_launch_initialize()
934 {
935         int rc;
936         gid_t r, e, s;
937
938         /* compute the groupid to set at launch */
939         getresgid(&r, &e, &s);
940         if (s && s != e)
941                 groupid = s; /* the original groupid is used */
942         else
943                 groupid = (gid_t)-1;
944
945         /* reads the configuration file */
946         rc = read_configuration_file(FWK_LAUNCH_CONF);
947 #if defined(DUMP_LAUNCHERS)
948         if (!rc)
949                 dump_launchers(stderr);
950 #endif
951         
952         return rc;
953 }
954