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.
23 #include <sys/types.h>
33 #include "utils-dir.h"
35 #include "afm-launch.h"
46 struct apprun *next_by_runid;
47 struct apprun *next_by_pgid;
49 pid_t pids[2]; /* 0: group leader, 1: slave (appli) */
54 #define ROOT_RUNNERS_COUNT 32
55 #define MAX_RUNNER_COUNT 32767
57 static struct apprun *runners_by_runid[ROOT_RUNNERS_COUNT];
58 static struct apprun *runners_by_pgid[ROOT_RUNNERS_COUNT];
59 static int runnercount = 0;
60 static int runnerid = 0;
62 static const char fwk_user_app_dir[] = FWK_USER_APP_DIR;
63 static char *homeappdir;
65 /****************** manages pgids **********************/
67 /* get a runner by its pgid */
68 static struct apprun *runner_of_pgid(pid_t pgid)
70 struct apprun *result = runners_by_pgid[(int)(pgid & (ROOT_RUNNERS_COUNT - 1))];
71 while (result && result->pids[0] != pgid)
72 result = result->next_by_pgid;
76 /* insert a runner for its pgid */
77 static void pgid_insert(struct apprun *runner)
79 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
80 runner->next_by_pgid = *prev;
84 /* remove a runner for its pgid */
85 static void pgid_remove(struct apprun *runner)
87 struct apprun **prev = &runners_by_runid[(int)(runner->pids[0] & (ROOT_RUNNERS_COUNT - 1))];
88 runner->next_by_pgid = *prev;
92 /****************** manages pids **********************/
94 /* get a runner by its pid */
95 static struct apprun *runner_of_pid(pid_t pid)
97 /* try avoiding system call */
98 struct apprun *result = runner_of_pgid(pid);
100 result = runner_of_pgid(getpgid(pid));
101 if (result && result->pids[1] != pid)
107 /****************** manages runners (by runid) **********************/
109 /* get a runner by its runid */
110 static struct apprun *getrunner(int runid)
112 struct apprun *result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
113 while (result && result->runid != runid)
114 result = result->next_by_runid;
118 /* free an existing runner */
119 static void freerunner(struct apprun *runner)
121 struct apprun **prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
123 while(*prev != runner) {
124 prev = &(*prev)->next_by_runid;
127 *prev = runner->next_by_runid;
128 json_object_put(runner->appli);
133 /* create a new runner */
134 static struct apprun *createrunner(json_object *appli)
136 struct apprun *result;
137 struct apprun **prev;
139 if (runnercount >= MAX_RUNNER_COUNT) {
145 if (runnerid > MAX_RUNNER_COUNT)
147 } while(getrunner(runnerid));
148 result = calloc(1, sizeof * result);
152 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
153 result->next_by_runid = *prev;
154 result->next_by_pgid = NULL;
155 result->runid = runnerid;
156 result->pids[0] = result->pids[1] = 0;
157 result->state = as_starting;
158 result->appli = json_object_get(appli);
165 /**************** signaling ************************/
167 static void started(int runid)
171 static void stopped(int runid)
175 static void continued(int runid)
179 static void terminated(int runid)
183 static void removed(int runid)
187 /**************** running ************************/
189 static int killrunner(int runid, int sig, enum appstate tostate)
192 struct apprun *runner = getrunner(runid);
193 if (runner == NULL) {
197 else if (runner->state != as_running && runner->state != as_stopped) {
201 else if (runner->state == tostate) {
205 rc = killpg(runner->pids[0], sig);
207 runner->state = tostate;
212 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
214 struct apprun *runner;
216 runner = runner_of_pgid(info->si_pid);
220 switch(info->si_code) {
225 runner->state = as_terminated;
230 runner->state = as_stopped;
234 runner->state = as_running;
239 /**************** handle afm_launch_desc *********************/
241 static int get_jstr(struct json_object *obj, const char *key, const char **value)
244 return json_object_object_get_ex(obj, key, &data)
245 && json_object_get_type(data) == json_type_string
246 && (*value = json_object_get_string(data)) != NULL;
249 static int get_jint(struct json_object *obj, const char *key, int *value)
252 return json_object_object_get_ex(obj, key, &data)
253 && json_object_get_type(data) == json_type_int
254 && ((*value = (int)json_object_get_int(data)), 1);
257 static int fill_launch_desc(struct json_object *appli, struct afm_launch_desc *desc)
262 if(!json_object_object_get_ex(appli, "public", &pub)
263 || !get_jstr(appli, "path", &desc->path)
264 || !get_jstr(appli, "id", &desc->tag)
265 || !get_jstr(appli, "content", &desc->content)
266 || !get_jstr(appli, "type", &desc->type)
267 || !get_jstr(pub, "name", &desc->name)
268 || !get_jint(pub, "width", &desc->width)
269 || !get_jint(pub, "height", &desc->height)) {
277 static const char *null = NULL;
278 desc->plugins = &null;
282 desc->home = homeappdir;
286 /**************** API handling ************************/
288 int afm_run_start(struct json_object *appli)
290 static struct apprun *runner;
291 struct afm_launch_desc desc;
293 sigset_t saved, blocked;
295 /* prepare to launch */
296 rc = fill_launch_desc(appli, &desc);
299 runner = createrunner(appli);
303 /* block children signals until launched */
304 sigemptyset(&blocked);
305 sigaddset(&blocked, SIGCHLD);
306 sigprocmask(SIG_BLOCK, &blocked, &saved);
309 rc = afm_launch(&desc, runner->pids);
312 sigprocmask(SIG_SETMASK, &saved, NULL);
313 ERROR("can't start, afm_launch failed: %m");
319 runner->state = as_running;
323 /* unblock children signal now */
324 sigprocmask(SIG_SETMASK, &saved, NULL);
328 int afm_run_terminate(int runid)
330 return killrunner(runid, SIGTERM, as_terminating);
333 int afm_run_stop(int runid)
335 return killrunner(runid, SIGSTOP, as_stopped);
338 int afm_run_continue(int runid)
340 return killrunner(runid, SIGCONT, as_running);
343 static json_object *mkstate(struct apprun *runner)
346 struct json_object *result, *obj;
350 result = json_object_new_object();
355 obj = json_object_new_int(runner->runid);
358 json_object_object_add(result, "runid", obj); /* TODO TEST STATUS */
361 switch(runner->state) {
370 state = "terminated";
373 obj = json_object_new_string(state);
376 json_object_object_add(result, "state", obj); /* TODO TEST STATUS */
378 /* the application id */
379 rc = json_object_object_get_ex(runner->appli, "public", &obj);
381 rc = json_object_object_get_ex(obj, "id", &obj);
383 json_object_object_add(result, "id", obj); /* TODO TEST STATUS */
384 json_object_get(obj);
390 json_object_put(result);
396 struct json_object *afm_run_list()
398 struct json_object *result, *obj;
399 struct apprun *runner;
402 /* creates the object */
403 result = json_object_new_array();
404 if (result == NULL) {
409 for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
410 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
411 if (runner->state != as_terminating && runner->state != as_terminated) {
412 obj = mkstate(runner);
414 json_object_put(result);
418 json_object_array_add(result, obj);
425 struct json_object *afm_run_state(int runid)
427 struct apprun *runner = getrunner(runid);
428 if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
432 return mkstate(runner);
435 /**************** INITIALISATION **********************/
443 struct passwd passwd, *pw;
444 struct sigaction siga;
446 /* computes the 'homeappdir' */
448 rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
449 if (rc || pw == NULL) {
450 errno = rc ? errno : ENOENT;
451 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
454 rc = snprintf(dir, sizeof dir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
455 if (rc >= sizeof dir) {
456 ERROR("buffer overflow in user_app_dir for uid=%d",(int)me);
459 rc = create_directory(dir, 0755, 1);
460 if (rc && errno != EEXIST) {
461 ERROR("creation of directory %s failed in user_app_dir: %m", dir);
464 homeappdir = strdup(dir);
465 if (homeappdir == NULL) {
467 ERROR("out of memory in user_app_dir for %s : %m", dir);
471 /* install signal handlers */
472 siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
473 sigemptyset(&siga.sa_mask);
474 sigaddset(&siga.sa_mask, SIGCHLD);
475 siga.sa_sigaction = on_sigchld;
476 sigaction(SIGCHLD, &siga, NULL);