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)) {
471 ERROR("bad internal description of the application to launch: %s", json_object_get_string(appli));
479 static const char *null = NULL;
480 desc->bindings = &null;
484 desc->home = homeappdir;
489 /**************** report state of runner *********************/
492 * Creates a json object that describes the state of 'runner'.
494 * Returns the created object or NULL in case of error.
496 static json_object *mkstate(struct apprun *runner)
499 struct json_object *result, *obj, *pids;
503 result = json_object_new_object();
508 if (!j_add_integer(result, "runid", runner->runid))
512 if (is_alive(runner)) {
513 pids = j_add_new_array(result, "pids");
516 if (!j_add_integer(pids, NULL, runner->pids[0]))
518 if (runner->pids[1] && !j_add_integer(pids, NULL, runner->pids[1]))
523 switch(runner->state) {
532 state = "terminated";
535 if (!j_add_string(result, "state", state))
538 /* the application id */
539 rc = json_object_object_get_ex(runner->appli, "public", &obj);
541 rc = json_object_object_get_ex(obj, "id", &obj);
543 if (!j_add(result, "id", obj))
545 json_object_get(obj);
551 json_object_put(result);
557 /**************** API handling ************************/
560 * Starts the application described by 'appli' for the 'mode'.
561 * In case of remote start, it returns in uri the uri to
564 * A reference to 'appli' is kept during the live of the
565 * runner. This is made using json_object_get. Thus be aware
566 * that further modifications to 'appli' might create errors.
568 * Returns the runid in case of success or -1 in case of error
570 int afm_run_start(struct json_object *appli, enum afm_launch_mode mode,
573 struct apprun *runner;
574 struct afm_launch_desc desc;
576 sigset_t saved, blocked;
578 assert(is_valid_launch_mode(mode));
579 assert(mode == mode_local || uri != NULL);
580 assert(uri == NULL || *uri == NULL);
582 /* prepare to launch */
583 rc = fill_launch_desc(appli, mode, &desc);
586 runner = createrunner(appli);
590 /* block children signals until launched */
591 sigemptyset(&blocked);
592 sigaddset(&blocked, SIGCHLD);
593 sigprocmask(SIG_BLOCK, &blocked, &saved);
596 rc = afm_launch(&desc, runner->pids, uri);
599 sigprocmask(SIG_SETMASK, &saved, NULL);
600 ERROR("can't start, afm_launch failed: %m");
606 runner->state = as_running;
610 /* unblock children signal now */
611 sigprocmask(SIG_SETMASK, &saved, NULL);
616 * Returns the runid of a previously started application 'appli'
617 * or if none is running, starts the application described by 'appli'
620 * A reference to 'appli' is kept during the live of the
621 * runner. This is made using json_object_get. Thus be aware
622 * that further modifications to 'appli' might create errors.
624 * Returns the runid in case of success or -1 in case of error
626 int afm_run_once(struct json_object *appli)
628 struct apprun *runner = getrunner_appli(appli);
629 return runner && is_alive(runner) ? runner->runid : afm_run_start(appli, mode_local, NULL);
633 * Terminates the runner of 'runid'
635 * Returns 0 in case of success or -1 in case of error
637 int afm_run_terminate(int runid)
639 return killrunner(runid, SIGTERM, as_terminating);
643 * Stops (aka pause) the runner of 'runid'
645 * Returns 0 in case of success or -1 in case of error
647 int afm_run_pause(int runid)
649 return killrunner(runid, SIGSTOP, as_paused);
653 * Continue (aka resume) the runner of 'runid'
655 * Returns 0 in case of success or -1 in case of error
657 int afm_run_resume(int runid)
659 return killrunner(runid, SIGCONT, as_running);
663 * Get the list of the runners.
665 * Returns the list or NULL in case of error.
667 struct json_object *afm_run_list()
669 struct json_object *result, *obj;
670 struct apprun *runner;
673 /* creates the object */
674 result = json_object_new_array();
678 /* iterate over runners */
679 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
680 runner = runners_by_runid[i];
682 if (is_alive(runner)) {
683 /* adds the living runner */
684 obj = mkstate(runner);
687 if (json_object_array_add(result, obj) == -1) {
688 json_object_put(obj);
692 runner = runner->next_by_runid;
698 json_object_put(result);
705 * Get the state of the runner of 'runid'.
707 * Returns the state or NULL in case of success
709 struct json_object *afm_run_state(int runid)
711 struct apprun *runner = getrunner(runid);
712 if (runner == NULL || is_dead(runner)) {
716 return mkstate(runner);
719 /**************** INITIALISATION **********************/
722 * Initialize the module
729 struct passwd passwd, *pw;
730 struct sigaction siga;
733 rc = afm_launch_initialize();
737 /* computes the 'homeappdir' */
739 rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
740 if (rc || pw == NULL) {
741 errno = rc ? errno : ENOENT;
742 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
745 rc = asprintf(&homeappdir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
748 ERROR("allocating homeappdir for uid=%d failed", (int)me);
751 rc = create_directory(homeappdir, 0755, 1);
752 if (rc && errno != EEXIST) {
753 ERROR("creation of directory %s failed: %m", homeappdir);
757 rc = smack_remove_label_for_path(homeappdir,
758 XATTR_NAME_SMACKTRANSMUTE, 0);
759 if (rc < 0 && errno != ENODATA) {
760 ERROR("can't remove smack transmutation of directory %s: %m",
765 rc = smack_set_label_for_path(homeappdir, XATTR_NAME_SMACK, 0,
768 ERROR("can't set smack label %s to directory %s: %m",
769 fwk_user_app_label, homeappdir);
773 /* install signal handlers */
774 siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
775 sigemptyset(&siga.sa_mask);
776 sigaddset(&siga.sa_mask, SIGCHLD);
777 siga.sa_sigaction = on_sigchld;
778 sigaction(SIGCHLD, &siga, NULL);