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