2 Copyright 2015, 2016, 2017 IoT.bzh
4 author: José Bollo <jose.bollo@iot.bzh>
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
10 http://www.apache.org/licenses/LICENSE-2.0
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.
25 #include <sys/types.h>
32 #include <linux/xattr.h>
34 #include "simulation/smack.h"
36 #include <sys/smack.h>
39 #include <json-c/json.h>
42 #include "utils-dir.h"
43 #include "utils-json.h"
44 #include "afm-launch-mode.h"
45 #include "afm-launch.h"
49 * State of a launched/running application
52 as_starting, /* start in progress */
53 as_running, /* started and running */
54 as_paused, /* paused */
55 as_terminating, /* termination in progress */
56 as_terminated /* terminated */
60 * Structure for recording a runner
63 struct apprun *next_by_runid; /* link for hashing by runid */
64 struct apprun *next_by_pgid; /* link for hashing by pgid */
65 int runid; /* runid */
66 pid_t pids[2]; /* pids (0: group leader, 1: slave) */
67 enum appstate state; /* current state of the application */
68 json_object *appli; /* json object describing the application */
72 * Count of item by hash table
74 #define ROOT_RUNNERS_COUNT 32
77 * Maximum count of simultaneous running application
79 #define MAX_RUNNER_COUNT 32767
82 * Hash tables of runners by runid and by pgid
84 static struct apprun *runners_by_runid[ROOT_RUNNERS_COUNT];
85 static struct apprun *runners_by_pgid[ROOT_RUNNERS_COUNT];
88 * List of terminated runners
90 static struct apprun *terminated_runners = NULL;
95 static int runnercount = 0;
100 static int runnerid = 0;
103 * Path name of the directory for applications in the
104 * home directory of the user.
106 static const char fwk_user_app_dir[] = FWK_USER_APP_DIR;
107 static const char fwk_user_app_label[] = FWK_USER_APP_DIR_LABEL;
110 * Path of the root directory for applications of the
113 static char *homeappdir;
115 /****************** manages pids **********************/
118 * Get a runner by its 'pid' (NULL if not found)
120 static struct apprun *runner_of_pid(pid_t pid)
123 struct apprun *result;
125 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
126 result = runners_by_pgid[i];
127 while (result != NULL) {
128 if (result->pids[0] == pid || result->pids[1] == pid)
130 result = result->next_by_pgid;
136 /****************** manages pgids **********************/
139 * Get a runner by its 'pgid' (NULL if not found)
141 static struct apprun *runner_of_pgid(pid_t pgid)
143 struct apprun *result;
145 result = runners_by_pgid[pgid & (ROOT_RUNNERS_COUNT - 1)];
146 while (result && result->pids[0] != pgid)
147 result = result->next_by_pgid;
152 * Insert a 'runner' for its pgid
154 static void pgid_insert(struct apprun *runner)
156 struct apprun **prev;
158 prev = &runners_by_pgid[runner->pids[0] & (ROOT_RUNNERS_COUNT - 1)];
159 runner->next_by_pgid = *prev;
164 * Remove a 'runner' for its pgid
166 static void pgid_remove(struct apprun *runner)
168 struct apprun **prev;
170 prev = &runners_by_pgid[runner->pids[0] & (ROOT_RUNNERS_COUNT - 1)];
172 if (*prev == runner) {
173 *prev = runner->next_by_pgid;
176 prev = &(*prev)->next_by_pgid;
180 /****************** manages runners (by runid) **********************/
183 * Is a 'runner' alive?
185 static inline int is_alive(struct apprun *runner)
187 switch(runner->state) {
197 * Is a 'runner' dead?
199 static inline int is_dead(struct apprun *runner)
201 switch(runner->state) {
211 * Is a 'runner' running?
213 static inline int is_running(struct apprun *runner)
215 switch(runner->state) {
225 * Is a 'runner' paused?
227 static inline int is_paused(struct apprun *runner)
229 switch(runner->state) {
238 * Get a runner by its 'runid' (NULL if not found)
240 static struct apprun *getrunner(int runid)
242 struct apprun *result;
244 result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
245 while (result && result->runid != runid)
246 result = result->next_by_runid;
251 * Get first runner of 'appli' (NULL if not found)
253 static struct apprun *getrunner_appli(json_object *appli)
256 struct apprun *result;
258 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
259 result = runners_by_pgid[i];
260 while (result != NULL) {
261 if (result->appli == appli)
263 result = result->next_by_pgid;
270 * Free an existing 'runner'
272 static void freerunner(struct apprun *runner)
274 struct apprun **prev;
276 /* get previous pointer to runner */
277 prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
279 while(*prev != runner) {
280 prev = &(*prev)->next_by_runid;
285 *prev = runner->next_by_runid;
289 json_object_put(runner->appli);
294 * Cleans the list of runners from its terminated
296 static void cleanrunners()
298 struct apprun *runner;
299 while (terminated_runners) {
300 runner = terminated_runners;
301 terminated_runners = runner->next_by_pgid;
307 * Create a new runner for the 'appli'
309 * Returns the created runner or NULL
312 static struct apprun *createrunner(json_object *appli)
314 struct apprun *result;
315 struct apprun **prev;
321 if (runnercount >= MAX_RUNNER_COUNT) {
327 if (runnerid > MAX_RUNNER_COUNT)
329 } while(getrunner(runnerid));
331 /* create the structure */
332 result = calloc(1, sizeof * result);
336 /* initialize it linked to the list */
337 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
338 result->next_by_runid = *prev;
339 result->next_by_pgid = NULL;
340 result->runid = runnerid;
341 result->pids[0] = result->pids[1] = 0;
342 result->state = as_starting;
343 result->appli = json_object_get(appli);
350 /**************** signaling ************************/
352 static void started(int runid)
356 static void paused(int runid)
360 static void resumed(int runid)
364 static void terminated(int runid)
368 static void removed(int runid)
372 /**************** running ************************/
375 * Sends (with pgkill) the signal 'sig' to the process group
376 * for 'runid' and put the runner's state to 'tostate'
377 * in case of success.
379 * Only processes in the state 'as_running' or 'as_paused'
382 * Returns 0 in case of success or -1 in case of error.
384 static int killrunner(int runid, int sig, enum appstate tostate)
387 struct apprun *runner = getrunner(runid);
388 if (runner == NULL) {
392 else if (is_dead(runner)) {
396 else if (runner->state == tostate) {
400 rc = killpg(runner->pids[0], sig);
402 runner->state = tostate;
408 * Signal callback called on SIGCHLD. This is set using sigaction.
410 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
412 struct apprun *runner;
414 /* retrieves the runner */
415 runner = runner_of_pid(info->si_pid);
419 /* known runner, inspect cause of signal */
420 switch(info->si_code) {
425 /* update the state */
426 runner->state = as_terminated;
427 /* remove it from pgid list */
429 runner->next_by_pgid = terminated_runners;
430 terminated_runners = runner;
431 /* ensures that all the group terminates */
432 killpg(runner->pids[0], SIGKILL);
436 /* update the state */
437 runner->state = as_paused;
441 /* update the state */
442 runner->state = as_running;
447 /**************** handle afm_launch_desc *********************/
450 * Initialize the data of the launch description 'desc'
451 * for the application 'appli' and the 'mode'.
453 * Returns 0 in case of success or -1 in case of error.
455 static int fill_launch_desc(struct json_object *appli,
456 enum afm_launch_mode mode, struct afm_launch_desc *desc)
460 assert(is_valid_launch_mode(mode));
463 if(!j_read_object_at(appli, "public", &pub)
464 || !j_read_string_at(appli, "path", &desc->path)
465 || !j_read_string_at(appli, "id", &desc->appid)
466 || !j_read_string_at(appli, "content", &desc->content)
467 || !j_read_string_at(appli, "type", &desc->type)
468 || !j_read_string_at(pub, "name", &desc->name)
469 || !j_read_integer_at(pub, "width", &desc->width)
470 || !j_read_integer_at(pub, "height", &desc->height)) {
478 static const char *null = NULL;
479 desc->bindings = &null;
483 desc->home = homeappdir;
488 /**************** report state of runner *********************/
491 * Creates a json object that describes the state of 'runner'.
493 * Returns the created object or NULL in case of error.
495 static json_object *mkstate(struct apprun *runner)
498 struct json_object *result, *obj, *pids;
502 result = json_object_new_object();
507 if (!j_add_integer(result, "runid", runner->runid))
511 if (is_alive(runner)) {
512 pids = j_add_new_array(result, "pids");
515 if (!j_add_integer(pids, NULL, runner->pids[0]))
517 if (runner->pids[1] && !j_add_integer(pids, NULL, runner->pids[1]))
522 switch(runner->state) {
531 state = "terminated";
534 if (!j_add_string(result, "state", state))
537 /* the application id */
538 rc = json_object_object_get_ex(runner->appli, "public", &obj);
540 rc = json_object_object_get_ex(obj, "id", &obj);
542 if (!j_add(result, "id", obj))
544 json_object_get(obj);
550 json_object_put(result);
556 /**************** API handling ************************/
559 * Starts the application described by 'appli' for the 'mode'.
560 * In case of remote start, it returns in uri the uri to
563 * A reference to 'appli' is kept during the live of the
564 * runner. This is made using json_object_get. Thus be aware
565 * that further modifications to 'appli' might create errors.
567 * Returns the runid in case of success or -1 in case of error
569 int afm_run_start(struct json_object *appli, enum afm_launch_mode mode,
572 struct apprun *runner;
573 struct afm_launch_desc desc;
575 sigset_t saved, blocked;
577 assert(is_valid_launch_mode(mode));
578 assert(mode == mode_local || uri != NULL);
579 assert(uri == NULL || *uri == NULL);
581 /* prepare to launch */
582 rc = fill_launch_desc(appli, mode, &desc);
585 runner = createrunner(appli);
589 /* block children signals until launched */
590 sigemptyset(&blocked);
591 sigaddset(&blocked, SIGCHLD);
592 sigprocmask(SIG_BLOCK, &blocked, &saved);
595 rc = afm_launch(&desc, runner->pids, uri);
598 sigprocmask(SIG_SETMASK, &saved, NULL);
599 ERROR("can't start, afm_launch failed: %m");
605 runner->state = as_running;
609 /* unblock children signal now */
610 sigprocmask(SIG_SETMASK, &saved, NULL);
615 * Returns the runid of a previously started application 'appli'
616 * or if none is running, starts the application described by 'appli'
619 * A reference to 'appli' is kept during the live of the
620 * runner. This is made using json_object_get. Thus be aware
621 * that further modifications to 'appli' might create errors.
623 * Returns the runid in case of success or -1 in case of error
625 int afm_run_once(struct json_object *appli)
627 struct apprun *runner = getrunner_appli(appli);
628 return runner && is_alive(runner) ? runner->runid : afm_run_start(appli, mode_local, NULL);
632 * Terminates the runner of 'runid'
634 * Returns 0 in case of success or -1 in case of error
636 int afm_run_terminate(int runid)
638 return killrunner(runid, SIGTERM, as_terminating);
642 * Stops (aka pause) the runner of 'runid'
644 * Returns 0 in case of success or -1 in case of error
646 int afm_run_pause(int runid)
648 return killrunner(runid, SIGSTOP, as_paused);
652 * Continue (aka resume) the runner of 'runid'
654 * Returns 0 in case of success or -1 in case of error
656 int afm_run_resume(int runid)
658 return killrunner(runid, SIGCONT, as_running);
662 * Get the list of the runners.
664 * Returns the list or NULL in case of error.
666 struct json_object *afm_run_list()
668 struct json_object *result, *obj;
669 struct apprun *runner;
672 /* creates the object */
673 result = json_object_new_array();
677 /* iterate over runners */
678 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
679 runner = runners_by_runid[i];
681 if (is_alive(runner)) {
682 /* adds the living runner */
683 obj = mkstate(runner);
686 if (json_object_array_add(result, obj) == -1) {
687 json_object_put(obj);
691 runner = runner->next_by_runid;
697 json_object_put(result);
704 * Get the state of the runner of 'runid'.
706 * Returns the state or NULL in case of success
708 struct json_object *afm_run_state(int runid)
710 struct apprun *runner = getrunner(runid);
711 if (runner == NULL || is_dead(runner)) {
715 return mkstate(runner);
718 /**************** INITIALISATION **********************/
721 * Initialize the module
728 struct passwd passwd, *pw;
729 struct sigaction siga;
732 rc = afm_launch_initialize();
736 /* computes the 'homeappdir' */
738 rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
739 if (rc || pw == NULL) {
740 errno = rc ? errno : ENOENT;
741 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
744 rc = asprintf(&homeappdir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
747 ERROR("allocating homeappdir for uid=%d failed", (int)me);
750 rc = create_directory(homeappdir, 0755, 1);
751 if (rc && errno != EEXIST) {
752 ERROR("creation of directory %s failed: %m", homeappdir);
756 rc = smack_remove_label_for_path(homeappdir,
757 XATTR_NAME_SMACKTRANSMUTE, 0);
758 if (rc < 0 && errno != ENODATA) {
759 ERROR("can't remove smack transmutation of directory %s: %m",
764 rc = smack_set_label_for_path(homeappdir, XATTR_NAME_SMACK, 0,
767 ERROR("can't set smack label %s to directory %s: %m",
768 fwk_user_app_label, homeappdir);
772 /* install signal handlers */
773 siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
774 sigemptyset(&siga.sa_mask);
775 sigaddset(&siga.sa_mask, SIGCHLD);
776 siga.sa_sigaction = on_sigchld;
777 sigaction(SIGCHLD, &siga, NULL);