Add support for L4Re Virtio Sockets
[src/app-framework-binder.git] / src / main-afb-daemon.c
1 /*
2  * Copyright (C) 2015-2019 "IoT.bzh"
3  * Author "Fulup Ar Foll"
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 <stdlib.h>
22 #include <stdio.h>
23 #include <stdint.h>
24 #include <signal.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <limits.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <sys/stat.h>
31 #include <sys/wait.h>
32
33 #if !defined(NO_CALL_PERSONALITY)
34 #include <sys/personality.h>
35 #endif
36
37 #include <json-c/json.h>
38
39 #if WITH_SYSTEMD
40 #   include <systemd/sd-daemon.h>
41 #endif
42
43 #include "afb-args.h"
44 #include "afb-apiset.h"
45 #include "afb-autoset.h"
46 #include "afb-api-so.h"
47 #if WITH_DBUS_TRANSPARENCY
48 #   include "afb-api-dbus.h"
49 #endif
50 #include "afb-api-ws.h"
51 #include "afb-xreq.h"
52 #include "afb-session.h"
53 #include "verbose.h"
54 #include "afb-common.h"
55 #include "afb-export.h"
56 #include "afb-monitor.h"
57 #if WITH_AFB_HOOK
58 #include "afb-hook.h"
59 #include "afb-hook-flags.h"
60 #endif
61 #include "afb-debug.h"
62 #if WITH_SUPERVISION
63 #   include "afb-supervision.h"
64 #endif
65 #if WITH_LIBMICROHTTPD
66 #   include "afb-hsrv.h"
67 #   include "afb-hreq.h"
68 #   include "afb-hswitch.h"
69 #endif
70
71 #include "process-name.h"
72 #include "wrap-json.h"
73 #include "jobs.h"
74 #include "sig-monitor.h"
75 #include "watchdog.h"
76
77 #if !defined(DEFAULT_BINDER_INTERFACE)
78 #  define DEFAULT_BINDER_INTERFACE NULL
79 #endif
80
81 /*
82    if SELF_PGROUP == 0 the launched command is the group leader
83    if SELF_PGROUP != 0 afb-daemon is the group leader
84 */
85 #define SELF_PGROUP 0
86
87 struct afb_apiset *main_apiset;
88 struct json_object *main_config;
89
90 static pid_t childpid;
91
92 /**
93  * Tiny helper around putenv: add the variable name=value
94  *
95  * @param name name of the variable to set
96  * @param value value to set to the variable
97  *
98  * @return 0 in case of success or -1 in case of error (with errno set to ENOMEM)
99  */
100 static int addenv(const char *name, const char *value)
101 {
102         char *head, *middle;
103
104         head = malloc(2 + strlen(name) + strlen(value));
105         if (head == NULL) {
106                 errno = ENOMEM;
107                 return -1;
108         }
109         middle = stpcpy(head, name);
110         middle[0] = '=';
111         strcpy(&middle[1], value);
112         return putenv(head);
113 }
114
115 /**
116  * Tiny helper around addenv that export the real path
117  *
118  * @param name name of the variable to set
119  * @param path the path value to export to the variable
120  *
121  * @return 0 in case of success or -1 in case of error (with errno set to ENOMEM)
122  */
123 static int addenv_realpath(const char *name, const char *path)
124 {
125         char buffer[PATH_MAX];
126         char *p = realpath(path, buffer);
127         return p ? addenv(name, p) : -1;
128 }
129
130 /**
131  * Tiny helper around addenv that export an integer
132  *
133  * @param name name of the variable to set
134  * @param value the integer value to export
135  *
136  * @return 0 in case of success or -1 in case of error (with errno set to ENOMEM)
137  */
138 static int addenv_int(const char *name, int value)
139 {
140         char buffer[64];
141         snprintf(buffer, sizeof buffer, "%d", value);
142         return addenv(name, buffer);
143 }
144
145 /*----------------------------------------------------------
146  |   helpers for handling list of arguments
147  +--------------------------------------------------------- */
148
149 static const char *run_for_config_array_opt(const char *name,
150                                             int (*run) (void *closure, const char *value),
151                                             void *closure)
152 {
153         int i, n, rc;
154         struct json_object *array, *value;
155
156         if (json_object_object_get_ex(main_config, name, &array)) {
157                 if (!json_object_is_type(array, json_type_array))
158                         return json_object_get_string(array);
159                 n = (int)json_object_array_length(array);
160                 for (i = 0 ; i < n ; i++) {
161                         value = json_object_array_get_idx(array, i);
162                         rc = run(closure, json_object_get_string(value));
163                         if (!rc)
164                                 return json_object_get_string(value);
165                 }
166         }
167         return NULL;
168 }
169
170 static int run_start(void *closure, const char *value)
171 {
172         int (*starter) (const char *value, struct afb_apiset *declare_set, struct afb_apiset *call_set) = closure;
173         return starter(value, main_apiset, main_apiset) >= 0;
174 }
175
176 static void apiset_start_list(const char *name,
177                         int (*starter) (const char *value, struct afb_apiset *declare_set, struct afb_apiset *call_set),
178                         const char *message)
179 {
180         const char *item = run_for_config_array_opt(name, run_start, starter);
181         if (item) {
182                 ERROR("can't start %s %s", message, item);
183                 exit(1);
184         }
185 }
186
187 /*----------------------------------------------------------
188  | exit_handler
189  |   Handles on exit specific actions
190  +--------------------------------------------------------- */
191 static void exit_handler()
192 {
193         struct sigaction siga;
194
195         memset(&siga, 0, sizeof siga);
196         siga.sa_handler = SIG_IGN;
197         sigaction(SIGTERM, &siga, NULL);
198
199         if (SELF_PGROUP)
200                 killpg(0, SIGTERM);
201         else if (childpid > 0)
202                 killpg(childpid, SIGTERM);
203 }
204
205 static void on_sigterm(int signum, siginfo_t *info, void *uctx)
206 {
207         NOTICE("Received SIGTERM");
208         exit(0);
209 }
210
211 static void on_sighup(int signum, siginfo_t *info, void *uctx)
212 {
213         NOTICE("Received SIGHUP");
214         /* TODO */
215 }
216
217 static void setup_daemon()
218 {
219         struct sigaction siga;
220
221         /* install signal handlers */
222         memset(&siga, 0, sizeof siga);
223         siga.sa_flags = SA_SIGINFO;
224
225         siga.sa_sigaction = on_sigterm;
226         sigaction(SIGTERM, &siga, NULL);
227
228         siga.sa_sigaction = on_sighup;
229         sigaction(SIGHUP, &siga, NULL);
230
231         /* handle groups */
232         atexit(exit_handler);
233
234         /* ignore any SIGPIPE */
235         signal(SIGPIPE, SIG_IGN);
236 }
237
238 /*----------------------------------------------------------
239  | daemonize
240  |   set the process in background
241  +--------------------------------------------------------- */
242 static void daemonize()
243 {
244         int fd = 0, daemon, nostdin;
245         const char *output;
246         pid_t pid;
247
248         daemon = 0;
249         output = NULL;
250         wrap_json_unpack(main_config, "{s?b s?s}", "daemon", &daemon, "output", &output);
251         nostdin = 0;
252
253         if (output) {
254                 fd = open(output, O_WRONLY | O_APPEND | O_CREAT, 0640);
255                 if (fd < 0) {
256                         ERROR("Can't open output %s", output);
257                         exit(1);
258                 }
259         }
260
261         if (daemon) {
262                 INFO("entering background mode");
263
264                 pid = fork();
265                 if (pid == -1) {
266                         ERROR("Failed to fork daemon process");
267                         exit(1);
268                 }
269                 if (pid != 0)
270                         _exit(0);
271
272                 nostdin = 1;
273         }
274
275         /* closes the input */
276         if (output) {
277                 NOTICE("Redirecting output to %s", output);
278                 close(2);
279                 dup(fd);
280                 close(1);
281                 dup(fd);
282                 close(fd);
283         }
284
285         if (nostdin)
286                 close(0); /* except if 'daemon', ctrl+C still works after that */
287 }
288
289 /*---------------------------------------------------------
290  | http server
291  |   Handles the HTTP server
292  +--------------------------------------------------------- */
293 #if WITH_LIBMICROHTTPD
294 static int init_alias(void *closure, const char *spec)
295 {
296         struct afb_hsrv *hsrv = closure;
297         char *path = strchr(spec, ':');
298
299         if (path == NULL) {
300                 ERROR("Missing ':' in alias %s. Alias ignored", spec);
301                 return 1;
302         }
303         *path++ = 0;
304         INFO("Alias for url=%s to path=%s", spec, path);
305         return afb_hsrv_add_alias(hsrv, spec, afb_common_rootdir_get_fd(), path,
306                                   0, 0);
307 }
308
309 static int init_http_server(struct afb_hsrv *hsrv)
310 {
311         int rc;
312         const char *rootapi, *roothttp, *rootbase;
313
314         roothttp = NULL;
315         rc = wrap_json_unpack(main_config, "{ss ss s?s}",
316                                 "rootapi", &rootapi,
317                                 "rootbase", &rootbase,
318                                 "roothttp", &roothttp);
319         if (rc < 0) {
320                 ERROR("Can't get HTTP server config");
321                 exit(1);
322         }
323
324         if (!afb_hsrv_add_handler(hsrv, rootapi,
325                         afb_hswitch_websocket_switch, main_apiset, 20))
326                 return 0;
327
328         if (!afb_hsrv_add_handler(hsrv, rootapi,
329                         afb_hswitch_apis, main_apiset, 10))
330                 return 0;
331
332         if (run_for_config_array_opt("alias", init_alias, hsrv))
333                 return 0;
334
335         if (roothttp != NULL) {
336                 if (!afb_hsrv_add_alias(hsrv, "",
337                         afb_common_rootdir_get_fd(), roothttp, -10, 1))
338                         return 0;
339         }
340
341         if (!afb_hsrv_add_handler(hsrv, rootbase,
342                         afb_hswitch_one_page_api_redirect, NULL, -20))
343                 return 0;
344
345         return 1;
346 }
347
348 static struct afb_hsrv *start_http_server()
349 {
350         int rc;
351         const char *uploaddir, *rootdir;
352         struct afb_hsrv *hsrv;
353         int cache_timeout, http_port;
354
355         rc = wrap_json_unpack(main_config, "{ss ss si si}",
356                                 "uploaddir", &uploaddir,
357                                 "rootdir", &rootdir,
358                                 "cache-eol", &cache_timeout,
359                                 "port", &http_port);
360         if (rc < 0) {
361                 ERROR("Can't get HTTP server start config");
362                 exit(1);
363         }
364
365         if (afb_hreq_init_download_path(uploaddir)) {
366                 ERROR("unable to set the upload directory %s", uploaddir);
367                 return NULL;
368         }
369
370         hsrv = afb_hsrv_create();
371         if (hsrv == NULL) {
372                 ERROR("memory allocation failure");
373                 return NULL;
374         }
375
376         if (!afb_hsrv_set_cache_timeout(hsrv, cache_timeout)
377             || !init_http_server(hsrv)) {
378                 ERROR("initialisation of httpd failed");
379                 afb_hsrv_put(hsrv);
380                 return NULL;
381         }
382
383         NOTICE("Waiting port=%d rootdir=%s", http_port, rootdir);
384         NOTICE("Browser URL= http://localhost:%d", http_port);
385
386         rc = afb_hsrv_start(hsrv, 15);
387         if (!rc) {
388                 ERROR("starting of httpd failed");
389                 afb_hsrv_put(hsrv);
390                 return NULL;
391         }
392
393         rc = afb_hsrv_add_interface_tcp(hsrv, DEFAULT_BINDER_INTERFACE, (uint16_t) http_port);
394         if (!rc) {
395                 ERROR("setting interface failed");
396                 afb_hsrv_put(hsrv);
397                 return NULL;
398         }
399
400         return hsrv;
401 }
402 #endif
403
404 /*---------------------------------------------------------
405  | execute_command
406  +--------------------------------------------------------- */
407
408 static void wait_child_and_exit()
409 {
410         pid_t pidchld = childpid;
411
412         childpid = 0;
413         if (!SELF_PGROUP)
414                 killpg(pidchld, SIGKILL);
415         waitpid(pidchld, NULL, 0);
416         exit(0);
417 }
418
419 static void on_sigchld(int signum, siginfo_t *info, void *uctx)
420 {
421         if (info->si_pid == childpid) {
422                 switch (info->si_code) {
423                 case CLD_EXITED:
424                 case CLD_KILLED:
425                 case CLD_DUMPED:
426                         jobs_exit(wait_child_and_exit);
427                 default:
428                         break;
429                 }
430         }
431 }
432
433 /*
434 # @@ @
435 # @p port
436 # @t token
437 */
438
439 #define SUBST_CHAR  '@'
440 #define SUBST_STR   "@"
441
442 static char *instanciate_string(const char *arg, const char *port, const char *token)
443 {
444         char *resu, *it, *wr;
445         int chg, dif;
446
447         /* get the changes */
448         chg = 0;
449         dif = 0;
450         it = strchrnul(arg, SUBST_CHAR);
451         while (*it) {
452                 switch(*++it) {
453                 case 'p': chg++; dif += (int)strlen(port) - 2; break;
454                 case 't': chg++; dif += (int)strlen(token) - 2; break;
455                 case SUBST_CHAR: it++; chg++; dif--; break;
456                 default: break;
457                 }
458                 it = strchrnul(it, SUBST_CHAR);
459         }
460
461         /* return arg when no change */
462         if (!chg)
463                 return strdup(arg);
464
465         /* allocates the result */
466         resu = malloc((it - arg) + dif + 1);
467         if (!resu) {
468                 ERROR("out of memory");
469                 return NULL;
470         }
471
472         /* instanciate the arguments */
473         wr = resu;
474         for (;;) {
475                 it = strchrnul(arg, SUBST_CHAR);
476                 wr = mempcpy(wr, arg, it - arg);
477                 if (!*it)
478                         break;
479                 switch(*++it) {
480                 case 'p': wr = stpcpy(wr, port); break;
481                 case 't': wr = stpcpy(wr, token); break;
482                 default: *wr++ = SUBST_CHAR; /*@fallthrough@*/
483                 case SUBST_CHAR: *wr++ = *it;
484                 }
485                 arg = ++it;
486         }
487
488         *wr = 0;
489         return resu;
490 }
491
492 static int instanciate_environ(const char *port, const char *token)
493 {
494         extern char **environ;
495         char *repl;
496         int i;
497
498         /* instantiate the environment */
499         for (i = 0 ; environ[i] ; i++) {
500                 repl = instanciate_string(environ[i], port, token);
501                 if (!repl)
502                         return -1;
503                 environ[i] = repl;
504         }
505         return 0;
506 }
507
508 static char **instanciate_command_args(struct json_object *exec, const char *port, const char *token)
509 {
510         char **result;
511         char *repl;
512         int i, n;
513
514         /* allocates the result */
515         n = (int)json_object_array_length(exec);
516         result = malloc((n + 1) * sizeof * result);
517         if (!result) {
518                 ERROR("out of memory");
519                 return NULL;
520         }
521
522         /* instanciate the arguments */
523         for (i = 0 ; i < n ; i++) {
524                 repl = instanciate_string(json_object_get_string(json_object_array_get_idx(exec, i)), port, token);
525                 if (!repl) {
526                         while(i)
527                                 free(result[--i]);
528                         free(result);
529                         return NULL;
530                 }
531                 result[i] = repl;
532         }
533         result[i] = NULL;
534         return result;
535 }
536
537 static int execute_command()
538 {
539         struct json_object *exec, *oport;
540         struct sigaction siga;
541         char port[20];
542         const char *token;
543         char **args;
544         int rc;
545
546         /* check whether a command is to execute or not */
547         if (!json_object_object_get_ex(main_config, "exec", &exec))
548                 return 0;
549
550         if (SELF_PGROUP)
551                 setpgid(0, 0);
552
553         /* install signal handler */
554         memset(&siga, 0, sizeof siga);
555         siga.sa_sigaction = on_sigchld;
556         siga.sa_flags = SA_SIGINFO;
557         sigaction(SIGCHLD, &siga, NULL);
558
559         /* fork now */
560         childpid = fork();
561         if (childpid)
562                 return 0;
563
564         /* compute the string for port */
565         if (json_object_object_get_ex(main_config, "port", &oport))
566                 rc = snprintf(port, sizeof port, "%s", json_object_get_string(oport));
567         else
568                 rc = snprintf(port, sizeof port, "%cp", SUBST_CHAR);
569         if (rc < 0 || rc >= (int)(sizeof port)) {
570                 ERROR("port->txt failed");
571         }
572         else {
573                 /* instantiate arguments and environment */
574                 token = afb_session_initial_token();
575                 args = instanciate_command_args(exec, port, token);
576                 if (args && instanciate_environ(port, token) >= 0) {
577                         /* run */
578                         if (!SELF_PGROUP)
579                                 setpgid(0, 0);
580                         execv(args[0], args);
581                         ERROR("can't launch %s: %m", args[0]);
582                 }
583         }
584         exit(1);
585         return -1;
586 }
587
588 /*---------------------------------------------------------
589  | startup calls
590  +--------------------------------------------------------- */
591
592 struct startup_req
593 {
594         struct afb_xreq xreq;
595         char *api;
596         char *verb;
597         struct json_object *calls;
598         int index;
599         int count;
600         const char *callspec;
601         struct afb_session *session;
602 };
603
604 static void startup_call_reply(struct afb_xreq *xreq, struct json_object *object, const char *error, const char *info)
605 {
606         struct startup_req *sreq = CONTAINER_OF_XREQ(struct startup_req, xreq);
607
608         info = info ?: "";
609         if (!error) {
610                 NOTICE("startup call %s returned %s (%s)", sreq->callspec, json_object_get_string(object), info);
611                 json_object_put(object);
612         } else {
613                 ERROR("startup call %s ERROR! %s (%s)", sreq->callspec, error, info);
614                 exit(1);
615         }
616 }
617
618 static void startup_call_current(struct startup_req *sreq);
619
620 static void startup_call_unref(struct afb_xreq *xreq)
621 {
622         struct startup_req *sreq = CONTAINER_OF_XREQ(struct startup_req, xreq);
623
624         free(sreq->api);
625         free(sreq->verb);
626         json_object_put(sreq->xreq.json);
627         if (++sreq->index < sreq->count)
628                 startup_call_current(sreq);
629         else {
630                 afb_session_close(sreq->session);
631                 afb_session_unref(sreq->session);
632                 free(sreq);
633         }
634 }
635
636 static struct afb_xreq_query_itf startup_xreq_itf =
637 {
638         .reply = startup_call_reply,
639         .unref = startup_call_unref
640 };
641
642 static void startup_call_current(struct startup_req *sreq)
643 {
644         const char *api, *verb, *json;
645         enum json_tokener_error jerr;
646
647         sreq->callspec = json_object_get_string(json_object_array_get_idx(sreq->calls, sreq->index)),
648         api = sreq->callspec;
649         verb = strchr(api, '/');
650         if (verb) {
651                 json = strchr(verb, ':');
652                 if (json) {
653                         afb_xreq_init(&sreq->xreq, &startup_xreq_itf);
654                         afb_context_init(&sreq->xreq.context, sreq->session, NULL);
655                         sreq->xreq.context.validated = 1;
656                         sreq->api = strndup(api, verb - api);
657                         sreq->verb = strndup(verb + 1, json - verb - 1);
658                         sreq->xreq.request.called_api = sreq->api;
659                         sreq->xreq.request.called_verb = sreq->verb;
660                         sreq->xreq.json = json_tokener_parse_verbose(json + 1, &jerr);
661                         if (sreq->api && sreq->verb && jerr == json_tokener_success) {
662                                 afb_xreq_process(&sreq->xreq, main_apiset);
663                                 return;
664                         }
665                 }
666         }
667         ERROR("Bad call specification %s", sreq->callspec);
668         exit(1);
669 }
670
671 static void run_startup_calls()
672 {
673         struct json_object *calls;
674         struct startup_req *sreq;
675         int count;
676
677         if (json_object_object_get_ex(main_config, "call", &calls)
678          && json_object_is_type(calls, json_type_array)
679          && (count = (int)json_object_array_length(calls))) {
680                 sreq = calloc(1, sizeof *sreq);
681                 sreq->session = afb_session_create(3600);
682                 sreq->calls = calls;
683                 sreq->index = 0;
684                 sreq->count = count;
685                 startup_call_current(sreq);
686         }
687 }
688
689 /*---------------------------------------------------------
690  | job for starting the daemon
691  +--------------------------------------------------------- */
692
693 static void start(int signum, void *arg)
694 {
695 #if WITH_AFB_HOOK
696         const char *tracereq = NULL, *traceapi = NULL, *traceevt = NULL,
697 #if !defined(REMOVE_LEGACY_TRACE)
698                 *tracesvc = NULL, *traceditf = NULL,
699 #endif
700                 *traceses = NULL, *traceglob = NULL;
701 #endif
702         const char *workdir = NULL, *rootdir = NULL, *token = NULL;
703         struct json_object *settings = NULL;
704         int max_session_count, session_timeout, api_timeout;
705         int rc;
706 #if WITH_LIBMICROHTTPD
707         const char *rootapi = NULL;
708         int no_httpd = 0, http_port = -1;
709         struct afb_hsrv *hsrv;
710 #endif
711
712
713         afb_debug("start-entry");
714
715         if (signum) {
716                 ERROR("start aborted: received signal %s", strsignal(signum));
717                 exit(1);
718         }
719
720         rc = wrap_json_unpack(main_config, "{"
721                         "ss ss s?s"
722                         "si si si"
723 #if WITH_LIBMICROHTTPD
724                         "s?b s?i s?s"
725 #endif
726 #if WITH_AFB_HOOK
727 #if !defined(REMOVE_LEGACY_TRACE)
728                         "s?s s?s"
729 #endif
730                         "s?s s?s s?s s?s s?s"
731 #endif
732                         "s?o"
733                         "}",
734
735                         "rootdir", &rootdir,
736                         "workdir", &workdir,
737                         "token", &token,
738
739                         "apitimeout", &api_timeout,
740                         "cntxtimeout", &session_timeout,
741                         "session-max", &max_session_count,
742
743 #if WITH_LIBMICROHTTPD
744                         "no-httpd", &no_httpd,
745                         "port", &http_port,
746                         "rootapi", &rootapi,
747 #endif
748 #if WITH_AFB_HOOK
749 #if !defined(REMOVE_LEGACY_TRACE)
750                         "tracesvc", &tracesvc,
751                         "traceditf", &traceditf,
752 #endif
753                         "tracereq", &tracereq,
754                         "traceapi", &traceapi,
755                         "traceevt", &traceevt,
756                         "traceses",  &traceses,
757                         "traceglob", &traceglob,
758 #endif
759                         "set", &settings
760                         );
761         if (rc < 0) {
762                 ERROR("Unable to get start config");
763                 exit(1);
764         }
765
766         /* initialize session handling */
767         if (afb_session_init(max_session_count, session_timeout, token)) {
768                 ERROR("initialisation of session manager failed");
769                 goto error;
770         }
771
772         /* set the directories */
773         mkdir(workdir, S_IRWXU | S_IRGRP | S_IXGRP);
774         if (chdir(workdir) < 0) {
775                 ERROR("Can't enter working dir %s", workdir);
776                 goto error;
777         }
778         if (afb_common_rootdir_set(rootdir) < 0) {
779                 ERROR("failed to set common root directory %s", rootdir);
780                 goto error;
781         }
782         if (addenv_realpath("AFB_WORKDIR", "."     /* resolved by realpath */)
783          || addenv_realpath("AFB_ROOTDIR", rootdir /* relative to current directory */)) {
784                 ERROR("can't set DIR environment");
785                 goto error;
786         }
787
788 #if WITH_LIBMICROHTTPD
789         /* setup HTTP */
790         if (!no_httpd) {
791                 if (http_port < 0) {
792                         ERROR("no port is defined");
793                         goto error;
794                 }
795                 if (http_port == 0) {
796                         ERROR("random port is not implemented");
797                         goto error;
798                 }
799                 if (addenv_int("AFB_PORT", http_port)
800                  || addenv("AFB_TOKEN", afb_session_initial_token())) {
801                         ERROR("can't set HTTP environment");
802                         goto error;
803                 }
804         }
805 #endif
806
807         /* configure the daemon */
808         afb_export_set_config(settings);
809         main_apiset = afb_apiset_create("main", api_timeout);
810         if (!main_apiset) {
811                 ERROR("can't create main api set");
812                 goto error;
813         }
814         if (afb_monitor_init(main_apiset, main_apiset) < 0) {
815                 ERROR("failed to setup monitor");
816                 goto error;
817         }
818 #if WITH_SUPERVISION
819         if (afb_supervision_init(main_apiset, main_config) < 0) {
820                 ERROR("failed to setup supervision");
821                 goto error;
822         }
823 #endif
824
825 #if WITH_AFB_HOOK
826         /* install hooks */
827         if (tracereq)
828                 afb_hook_create_xreq(NULL, NULL, NULL, afb_hook_flags_xreq_from_text(tracereq), NULL, NULL);
829 #if !defined(REMOVE_LEGACY_TRACE)
830         if (traceapi || tracesvc || traceditf)
831                 afb_hook_create_api(NULL, afb_hook_flags_api_from_text(traceapi)
832                         | afb_hook_flags_legacy_ditf_from_text(traceditf)
833                         | afb_hook_flags_legacy_svc_from_text(tracesvc), NULL, NULL);
834 #else
835         if (traceapi)
836                 afb_hook_create_api(NULL, afb_hook_flags_api_from_text(traceapi), NULL, NULL);
837 #endif
838         if (traceevt)
839                 afb_hook_create_evt(NULL, afb_hook_flags_evt_from_text(traceevt), NULL, NULL);
840         if (traceses)
841                 afb_hook_create_session(NULL, afb_hook_flags_session_from_text(traceses), NULL, NULL);
842         if (traceglob)
843                 afb_hook_create_global(afb_hook_flags_global_from_text(traceglob), NULL, NULL);
844 #endif
845
846         /* load bindings and apis */
847         afb_debug("start-load");
848 #if WITH_DYNAMIC_BINDING
849         apiset_start_list("binding", afb_api_so_add_binding, "the binding");
850         apiset_start_list("ldpaths", afb_api_so_add_pathset_fails, "the binding path set");
851         apiset_start_list("weak-ldpaths", afb_api_so_add_pathset_nofails, "the weak binding path set");
852 #endif
853         apiset_start_list("auto-api", afb_autoset_add_any, "the automatic api path set");
854 #if WITH_DBUS_TRANSPARENCY
855         apiset_start_list("dbus-client", afb_api_dbus_add_client, "the afb-dbus client");
856 #endif
857         apiset_start_list("ws-client", afb_api_ws_add_client_weak, "the afb-websocket client");
858
859         DEBUG("Init config done");
860
861         /* start the services */
862         afb_debug("start-start");
863 #if !defined(NO_CALL_PERSONALITY)
864         personality((unsigned long)-1L);
865 #endif
866         if (afb_apiset_start_all_services(main_apiset) < 0)
867                 goto error;
868
869         /* export started apis */
870         apiset_start_list("ws-server", afb_api_ws_add_server, "the afb-websocket service");
871 #if WITH_DBUS_TRANSPARENCY
872         apiset_start_list("dbus-server", afb_api_dbus_add_server, "the afb-dbus service");
873 #endif
874
875         /* start the HTTP server */
876 #if WITH_LIBMICROHTTPD
877         afb_debug("start-http");
878         if (!no_httpd) {
879                 if (!afb_hreq_init_cookie(http_port, rootapi, session_timeout)) {
880                         ERROR("initialisation of HTTP cookies failed");
881                         goto error;
882                 }
883
884                 hsrv = start_http_server();
885                 if (hsrv == NULL)
886                         goto error;
887         }
888 #endif
889
890         /* run the startup calls */
891         afb_debug("start-call");
892         run_startup_calls();
893
894         /* run the command */
895         afb_debug("start-exec");
896         if (execute_command() < 0)
897                 goto error;
898
899         /* ready */
900 #if WITH_SYSTEMD
901         sd_notify(1, "READY=1");
902 #endif
903
904         /* activate the watchdog */
905 #if HAS_WATCHDOG
906         if (watchdog_activate() < 0)
907                 ERROR("can't start the watchdog");
908 #endif
909
910         return;
911 error:
912         exit(1);
913 }
914
915 /*---------------------------------------------------------
916  | main
917  |   Parse option and launch action
918  +--------------------------------------------------------- */
919
920 int main(int argc, char *argv[])
921 {
922         struct json_object *obj;
923         afb_debug("main-entry");
924
925         // ------------- Build session handler & init config -------
926         main_config = afb_args_parse(argc, argv);
927         if (sig_monitor_init(
928                 !json_object_object_get_ex(main_config, "trap-faults", &obj)
929                         || json_object_get_boolean(obj)) < 0) {
930                 ERROR("failed to initialise signal handlers");
931                 return 1;
932         }
933
934
935         if (json_object_object_get_ex(main_config, "name", &obj)) {
936                 verbose_set_name(json_object_get_string(obj), 0);
937                 process_name_set_name(json_object_get_string(obj));
938                 process_name_replace_cmdline(argv, json_object_get_string(obj));
939         }
940         afb_debug("main-args");
941
942         // --------- run -----------
943         daemonize();
944         INFO("running with pid %d", getpid());
945
946         /* set the daemon environment */
947         setup_daemon();
948
949         afb_debug("main-start");
950
951         /* enter job processing */
952         jobs_start(3, 0, 50, start, NULL);
953         WARNING("hoops returned from jobs_enter! [report bug]");
954         return 1;
955 }
956