-int main(int argc, char *argv[]) {
- AFB_session *session;
- char* programName = argv [0];
- int optionIndex = 0;
- int optc, ind, consoleFD;
- int pid, nbcmd, status;
- AFB_config cliconfig; // temp structure to store CLI option before file config upload
-
- // ------------- Build session handler & init config -------
- session = configInit ();
- memset(&cliconfig,0,sizeof(cliconfig));
- memset(&aliasdir ,0,sizeof(aliasdir));
- cliconfig.aliasdir = aliasdir;
-
- // GNU CLI getopts nterface.
- struct option ggcOption;
- struct option *gnuOptions;
-
- // ------------------ Process Command Line -----------------------
-
- // if no argument print help and return
- if (argc < 2) {
- printHelp(programName);
- return (-1);
- }
-
- // build GNU getopt info from cliOptions
- nbcmd = sizeof (cliOptions) / sizeof (AFB_options);
- gnuOptions = malloc (sizeof (ggcOption) * nbcmd);
- for (ind=0; ind < nbcmd;ind++) {
- gnuOptions [ind].name = cliOptions[ind].name;
- gnuOptions [ind].has_arg = cliOptions[ind].has_arg;
- gnuOptions [ind].flag = 0;
- gnuOptions [ind].val = cliOptions[ind].val;
- }
-
- // get all options from command line
- while ((optc = getopt_long (argc, argv, "vsp?", gnuOptions, &optionIndex))
- != EOF)
- {
- switch (optc)
- {
- case SET_VERBOSE:
- verbose = 1;
- break;
-
- case SET_TCP_PORT:
- if (optarg == 0) goto needValueForOption;
- if (!sscanf (optarg, "%d", &cliconfig.httpdPort)) goto notAnInteger;
- break;
-
- case SET_APITIMEOUT:
- if (optarg == 0) goto needValueForOption;
- if (!sscanf (optarg, "%d", &cliconfig.apiTimeout)) goto notAnInteger;
- break;
-
- case SET_CNTXTIMEOUT:
- if (optarg == 0) goto needValueForOption;
- if (!sscanf (optarg, "%d", &cliconfig.cntxTimeout)) goto notAnInteger;
- break;
-
- case SET_ROOT_DIR:
- if (optarg == 0) goto needValueForOption;
- cliconfig.rootdir = optarg;
- if (verbose) fprintf(stderr, "Forcing Rootdir=%s\n",cliconfig.rootdir);
- break;
-
- case SET_ROOT_BASE:
- if (optarg == 0) goto needValueForOption;
- cliconfig.rootbase = optarg;
- if (verbose) fprintf(stderr, "Forcing Rootbase=%s\n",cliconfig.rootbase);
- break;
-
- case SET_ROOT_API:
- if (optarg == 0) goto needValueForOption;
- cliconfig.rootapi = optarg;
- if (verbose) fprintf(stderr, "Forcing Rootapi=%s\n",cliconfig.rootapi);
- break;
-
- case SET_ROOT_ALIAS:
- if (optarg == 0) goto needValueForOption;
- if (aliascount < MAX_ALIAS) {
- aliasdir[aliascount].url = strsep(&optarg,":");
- if (optarg == NULL) {
- fprintf(stderr, "missing ':' in alias %s, ignored\n", aliasdir[aliascount].url);
- } else {
- aliasdir[aliascount].path = optarg;
- aliasdir[aliascount].len = strlen(aliasdir[aliascount].url);
- if (verbose) fprintf(stderr, "Alias url=%s path=%s\n", aliasdir[aliascount].url, aliasdir[aliascount].path);
- aliascount++;
- }
- } else {
- fprintf(stderr, "Too many aliases [max:%s] %s ignored\n", optarg, MAX_ALIAS-1);
- }
- break;
-
- case SET_AUTH_TOKEN:
- if (optarg == 0) goto needValueForOption;
- cliconfig.token = optarg;
- break;
-
- case SET_LDPATH:
- if (optarg == 0) goto needValueForOption;
- cliconfig.ldpaths = optarg;
- break;
-
- case SET_PID_FILE:
- if (optarg == 0) goto needValueForOption;
- cliconfig.pidfile = optarg;
- break;
-
- case SET_SESSION_DIR:
- if (optarg == 0) goto needValueForOption;
- cliconfig.sessiondir = optarg;
- break;
-
- case SET_CONFIG_FILE:
- if (optarg == 0) goto needValueForOption;
- cliconfig.configfile = optarg;
- break;
-
- case SET_CACHE_TO:
- if (optarg == 0) goto needValueForOption;
- if (!sscanf (optarg, "%d", &cliconfig.cacheTimeout)) goto notAnInteger;
- break;
-
- case SET_CONFIG_EXIT:
- if (optarg != 0) goto noValueForOption;
- session->configsave = 1;
- session->forceexit = 1;
- break;
-
- case SET_CONFIG_SAVE:
- if (optarg != 0) goto noValueForOption;
- session->configsave = 1;
- break;
-
- case SET_USERID:
- if (optarg == 0) goto needValueForOption;
- if (!sscanf (optarg, "%s", &cliconfig.setuid)) goto notAnInteger;
- break;
-
- case SET_FAKE_MOD:
- if (optarg != 0) goto noValueForOption;
- session->fakemod = 1;
- break;
-
- case SET_FORGROUND:
- if (optarg != 0) goto noValueForOption;
- session->foreground = 1;
- break;
-
- case SET_BACKGROUND:
- if (optarg != 0) goto noValueForOption;
- session->background = 1;
- break;
-
- case KILL_PREV_REST:
- if (optarg != 0) goto noValueForOption;
- session->killPrevious = 1;
- break;
-
- case KILL_PREV_EXIT:
- if (optarg != 0) goto noValueForOption;
- session->killPrevious = 2;
- break;
-
- case SET_MODE:
- if (optarg == 0) goto needValueForOption;
- if (!strcmp(optarg, "local")) cliconfig.mode = AFB_MODE_LOCAL;
- else if (!strcmp(optarg, "remote")) cliconfig.mode = AFB_MODE_REMOTE;
- else if (!strcmp(optarg, "global")) cliconfig.mode = AFB_MODE_GLOBAL;
- else goto badMode;
- break;
-
- case SET_READYFD:
- if (optarg == 0) goto needValueForOption;
- if (!sscanf (optarg, "%u", &session->readyfd)) goto notAnInteger;
- break;
-
- case DISPLAY_VERSION:
- if (optarg != 0) goto noValueForOption;
- printVersion();
- goto normalExit;
-
- case DISPLAY_HELP:
- default:
- printHelp(programName);
- goto normalExit;
-
- }
- }
-
- // if exist merge config file with CLI arguments
- configLoadFile (session, &cliconfig);
- initPlugins(session);
-
- // ------------------ sanity check ----------------------------------------
- if ((session->background) && (session->foreground)) {
- fprintf (stderr, "%s ERR: cannot select foreground & background at the same time\n",configTime());
- exit (-1);
- }
-
- // ------------------ Some useful default values -------------------------
- if ((session->background == 0) && (session->foreground == 0)) session->foreground=1;
-
- // open syslog if ever needed
- openlog("AFB-log", 0, LOG_DAEMON);
-
- // -------------- Try to kill any previous process if asked ---------------------
- if (session->killPrevious) {
- pid = readPidFile (session->config); // enforce commandline option
- switch (pid) {
- case -1:
- fprintf (stderr, "%s ERR:main --kill ignored no PID file [%s]\n",configTime(), session->config->pidfile);
- break;
- case 0:
- fprintf (stderr, "%s ERR:main --kill ignored no active AFB process\n",configTime());
- break;
- default:
- status = kill (pid,SIGINT );
- if (status == 0) {
- if (verbose) printf ("%s INF:main signal INTR sent to pid:%d \n", configTime(), pid);
- } else {
- // try kill -9
- status = kill (pid,9);
- if (status != 0) fprintf (stderr, "%s ERR:main failled to killed pid=%d \n",configTime(), pid);
- }
- } // end switch pid
-
- if (session->killPrevious >= 2) goto normalExit;
- } // end killPrevious
-
-
- // ------------------ clean exit on CTR-C signal ------------------------
- if (signal (SIGINT, signalQuit) == SIG_ERR) {
- fprintf (stderr, "%s Quit Signal received.",configTime());
- return (-1);
- }
-
- // save exitPoint context when returning from longjmp closeSession and exit
- status = setjmp (exitPoint); // return !+ when coming from longjmp
- if (status != 0) {
- if (verbose) printf ("INF:main returning from longjump after signal [%d]\n", status);
- closeSession (session);
- goto exitOnSignal;
- }
-
- // let's run this program with a low priority
- status=nice (20);
-
- // ------------------ Finaly Process Commands -----------------------------
- // if --save then store config on disk upfront
- if (session->configsave) configStoreFile (session);
- if (session->forceexit) exit (0);
-
- if (session->config->setuid) {
- int err;
- struct passwd *passwd;
- passwd=getpwnam(session->config->setuid);
-
- if (passwd == NULL) goto errorSetuid;
-
- err = setuid(passwd->pw_uid);
- if (err) goto errorSetuid;
- }
-
- // let's not take the risk to run as ROOT
- //if (getuid() == 0) goto errorNoRoot;
-
- // check session dir and create if it does not exist
- if (sessionCheckdir (session) != AFB_SUCCESS) goto errSessiondir;
- if (verbose) fprintf (stderr, "AFB:notice Init config done\n");
-
-
-
- // ---- run in foreground mode --------------------
- if (session->foreground) {
-
- if (verbose) fprintf (stderr,"AFB:notice Foreground mode\n");
-
- // write a pid file for --kill-previous and --raise-debug option
- status = writePidFile (session->config, getpid());
- if (status == -1) goto errorPidFile;
-
- // enter listening loop in foreground
- listenLoop(session);
- goto exitInitLoop;
- } // end foreground
-
-
- // --------- run in background mode -----------
- if (session->background) {
-
- // if (status != 0) goto errorCommand;
- if (verbose) printf ("AFB: Entering background mode\n");
-
- // open /dev/console to redirect output messAFBes
- consoleFD = open(session->config->console, O_WRONLY | O_APPEND | O_CREAT , 0640);
- if (consoleFD < 0) goto errConsole;
-
- // fork process when running background mode
- pid = fork ();
-
- // son process get all data in standalone mode
- if (pid == 0) {
-
- printf ("\nAFB: background mode [pid:%d console:%s]\n", getpid(),session->config->console);
- if (verbose) printf ("AFB:info use '%s --restart --rootdir=%s # [--pidfile=%s] to restart daemon\n", programName,session->config->rootdir, session->config->pidfile);
-
- // redirect default I/O on console
- close (2); status=dup(consoleFD); // redirect stderr
- close (1); status=dup(consoleFD); // redirect stdout
- close (0); // no need for stdin
- close (consoleFD);
-
- setsid(); // allow father process to fully exit
- sleep (2); // allow main to leave and release port
-
- fprintf (stderr, "----------------------------\n");
- fprintf (stderr, "%s INF:main background pid=%d\n", configTime(), getpid());
- fflush (stderr);
-
- // if everything look OK then look forever
- syslog (LOG_ERR, "AFB: Entering infinite loop in background mode");
+struct startup_req
+{
+ struct afb_xreq xreq;
+ char *api;
+ char *verb;
+ struct afb_config_list *current;
+ struct afb_session *session;
+};
+
+static void startup_call_reply(struct afb_xreq *xreq, int status, struct json_object *obj)
+{
+ struct startup_req *sreq = CONTAINER_OF_XREQ(struct startup_req, xreq);
+
+ if (status >= 0)
+ NOTICE("startup call %s returned %s", sreq->current->value, json_object_get_string(obj));
+ else {
+ ERROR("startup call %s ERROR! %s", sreq->current->value, json_object_get_string(obj));
+ exit(1);
+ }
+}
+
+static void startup_call_current(struct startup_req *sreq);
+
+static void startup_call_unref(struct afb_xreq *xreq)
+{
+ struct startup_req *sreq = CONTAINER_OF_XREQ(struct startup_req, xreq);
+
+ free(sreq->api);
+ free(sreq->verb);
+ json_object_put(sreq->xreq.json);
+ sreq->current = sreq->current->next;
+ if (sreq->current)
+ startup_call_current(sreq);
+ else {
+ afb_session_close(sreq->session);
+ afb_session_unref(sreq->session);
+ free(sreq);
+ }
+}
+
+static struct afb_xreq_query_itf startup_xreq_itf =
+{
+ .reply = startup_call_reply,
+ .unref = startup_call_unref
+};
+
+static void startup_call_current(struct startup_req *sreq)
+{
+ char *api, *verb, *json;
+
+ api = sreq->current->value;
+ verb = strchr(api, '/');
+ if (verb) {
+ json = strchr(verb, ':');
+ if (json) {
+ afb_xreq_init(&sreq->xreq, &startup_xreq_itf);
+ afb_context_init(&sreq->xreq.context, sreq->session, NULL);
+ sreq->xreq.context.validated = 1;
+ sreq->api = strndup(api, verb - api);
+ sreq->verb = strndup(verb + 1, json - verb - 1);
+ sreq->xreq.request.api = sreq->api;
+ sreq->xreq.request.verb = sreq->verb;
+ sreq->xreq.json = json_tokener_parse(json + 1);
+ if (sreq->api && sreq->verb && sreq->xreq.json) {
+ afb_xreq_process(&sreq->xreq, main_apiset);
+ return;
+ }
+ }
+ }
+ ERROR("Bad call specification %s", sreq->current->value);
+ exit(1);
+}
+
+static void run_startup_calls()
+{
+ struct afb_config_list *list;
+ struct startup_req *sreq;
+
+ list = config->calls;
+ if (list) {
+ sreq = calloc(1, sizeof *sreq);
+ sreq->session = afb_session_create(3600);
+ sreq->current = list;
+ startup_call_current(sreq);
+ }
+}