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