update dates of headers
[src/app-framework-main.git] / src / afm-run.c
1 /*
2  Copyright 2015, 2016 IoT.bzh
3
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 <fcntl.h>
22 #include <unistd.h>
23 #include <signal.h>
24 #include <pwd.h>
25 #include <sys/types.h>
26 #include <errno.h>
27 #include <assert.h>
28 #include <stdio.h>
29 #include <limits.h>
30 #include <string.h>
31
32 #include <linux/xattr.h>
33 #if SIMULATE_LIBSMACK
34 #include "simulation/smack.h"
35 #else
36 #include <sys/smack.h>
37 #endif
38
39 #include <json-c/json.h>
40
41 #include "verbose.h"
42 #include "utils-dir.h"
43 #include "utils-json.h"
44 #include "afm-launch-mode.h"
45 #include "afm-launch.h"
46 #include "afm-run.h"
47
48 /*
49  * State of a launched/running application
50  */
51 enum appstate {
52         as_starting,    /* start in progress */
53         as_running,     /* started and running */
54         as_stopped,     /* stopped */
55         as_terminating, /* termination in progress */
56         as_terminated   /* terminated */
57 };
58
59 /*
60  * Structure for recording a runner
61  */
62 struct apprun {
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 */
69 };
70
71 /*
72  * Count of item by hash table
73  */
74 #define ROOT_RUNNERS_COUNT  32
75
76 /*
77  * Maximum count of simultaneous running application
78  */
79 #define MAX_RUNNER_COUNT    32767
80
81 /*
82  * Hash tables of runners by runid and by pgid
83  */
84 static struct apprun *runners_by_runid[ROOT_RUNNERS_COUNT];
85 static struct apprun *runners_by_pgid[ROOT_RUNNERS_COUNT];
86
87 /*
88  * List of terminated runners
89  */
90 static struct apprun *terminated_runners = NULL;
91
92 /*
93  * Count of runners
94  */
95 static int runnercount = 0;
96
97 /*
98  * Last given runid
99  */
100 static int runnerid = 0;
101
102 /*
103  * Path name of the directory for applications in the
104  * home directory of the user.
105  */
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;
108
109 /*
110  * Path of the root directory for applications of the
111  * current user
112  */
113 static char *homeappdir;
114
115 /****************** manages pids **********************/
116
117 /*
118  * Get a runner by its 'pid' (NULL if not found)
119  */
120 static struct apprun *runner_of_pid(pid_t pid)
121 {
122         int i;
123         struct apprun *result;
124
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)
129                                 return result;
130                         result = result->next_by_pgid;
131                 }
132         }
133         return NULL;
134 }
135
136 /****************** manages pgids **********************/
137
138 /*
139  * Get a runner by its 'pgid' (NULL if not found)
140  */
141 static struct apprun *runner_of_pgid(pid_t pgid)
142 {
143         struct apprun *result;
144
145         result = runners_by_pgid[pgid & (ROOT_RUNNERS_COUNT - 1)];
146         while (result && result->pids[0] != pgid)
147                 result = result->next_by_pgid;
148         return result;
149 }
150
151 /*
152  * Insert a 'runner' for its pgid
153  */
154 static void pgid_insert(struct apprun *runner)
155 {
156         struct apprun **prev;
157
158         prev = &runners_by_pgid[runner->pids[0] & (ROOT_RUNNERS_COUNT - 1)];
159         runner->next_by_pgid = *prev;
160         *prev = runner;
161 }
162
163 /*
164  * Remove a 'runner' for its pgid
165  */
166 static void pgid_remove(struct apprun *runner)
167 {
168         struct apprun **prev;
169
170         prev = &runners_by_pgid[runner->pids[0] & (ROOT_RUNNERS_COUNT - 1)];
171         while (*prev) {
172                 if (*prev == runner) {
173                         *prev = runner->next_by_pgid;
174                         break;
175                 }
176                 prev = &(*prev)->next_by_pgid;
177         }
178 }
179
180 /****************** manages runners (by runid) **********************/
181
182 /*
183  * Get a runner by its 'runid'  (NULL if not found)
184  */
185 static struct apprun *getrunner(int runid)
186 {
187         struct apprun *result;
188
189         result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
190         while (result && result->runid != runid)
191                 result = result->next_by_runid;
192         return result;
193 }
194
195 /*
196  * Free an existing 'runner'
197  */
198 static void freerunner(struct apprun *runner)
199 {
200         struct apprun **prev;
201
202         /* get previous pointer to runner */
203         prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
204         assert(*prev);
205         while(*prev != runner) {
206                 prev = &(*prev)->next_by_runid;
207                 assert(*prev);
208         }
209
210         /* unlink */
211         *prev = runner->next_by_runid;
212         runnercount--;
213
214         /* release/free */
215         json_object_put(runner->appli);
216         free(runner);
217 }
218
219 /*
220  * Cleans the list of runners from its terminated
221  */
222 static void cleanrunners()
223 {
224         struct apprun *runner;
225         while (terminated_runners) {
226                 runner = terminated_runners;
227                 terminated_runners = runner->next_by_pgid;
228                 freerunner(runner);
229         }
230 }
231
232 /*
233  * Create a new runner for the 'appli'
234  *
235  * Returns the created runner or NULL
236  * in case of error.
237  */
238 static struct apprun *createrunner(json_object *appli)
239 {
240         struct apprun *result;
241         struct apprun **prev;
242
243         /* cleanup */
244         cleanrunners();
245
246         /* get a runid */
247         if (runnercount >= MAX_RUNNER_COUNT) {
248                 errno = EAGAIN;
249                 return NULL;
250         }
251         do {
252                 runnerid++;
253                 if (runnerid > MAX_RUNNER_COUNT)
254                         runnerid = 1;
255         } while(getrunner(runnerid));
256
257         /* create the structure */
258         result = calloc(1, sizeof * result);
259         if (result == NULL)
260                 errno = ENOMEM;
261         else {
262                 /* initialize it linked to the list */
263                 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
264                 result->next_by_runid = *prev;
265                 result->next_by_pgid = NULL;
266                 result->runid = runnerid;
267                 result->pids[0] = result->pids[1] = 0;
268                 result->state = as_starting;
269                 result->appli = json_object_get(appli);
270                 *prev = result;
271                 runnercount++;
272         }
273         return result;
274 }
275
276 /**************** signaling ************************/
277 #if 0
278 static void started(int runid)
279 {
280 }
281
282 static void stopped(int runid)
283 {
284 }
285
286 static void continued(int runid)
287 {
288 }
289
290 static void terminated(int runid)
291 {
292 }
293
294 static void removed(int runid)
295 {
296 }
297 #endif
298 /**************** running ************************/
299
300 /*
301  * Sends (with pgkill) the signal 'sig' to the process group
302  * for 'runid' and put the runner's state to 'tostate'
303  * in case of success.
304  *
305  * Only processes in the state 'as_running' or 'as_stopped'
306  * can be signalled.
307  *
308  * Returns 0 in case of success or -1 in case of error.
309  */
310 static int killrunner(int runid, int sig, enum appstate tostate)
311 {
312         int rc;
313         struct apprun *runner = getrunner(runid);
314         if (runner == NULL) {
315                 errno = ENOENT;
316                 rc = -1;
317         }
318         else if (runner->state != as_running && runner->state != as_stopped) {
319                 errno = EINVAL;
320                 rc = -1;
321         }
322         else if (runner->state == tostate) {
323                 rc = 0;
324         }
325         else {
326                 rc = killpg(runner->pids[0], sig);
327                 if (!rc)
328                         runner->state = tostate;
329         }
330         return rc;
331 }
332
333 /*
334  * Signal callback called on SIGCHLD. This is set using sigaction.
335  */
336 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
337 {
338         struct apprun *runner;
339
340         /* retrieves the runner */
341         runner = runner_of_pid(info->si_pid);
342         if (!runner)
343                 return;
344
345         /* known runner, inspect cause of signal */
346         switch(info->si_code) {
347         case CLD_EXITED:
348         case CLD_KILLED:
349         case CLD_DUMPED:
350         case CLD_TRAPPED:
351                 /* update the state */
352                 runner->state = as_terminated;
353                 /* remove it from pgid list */
354                 pgid_remove(runner);
355                 runner->next_by_pgid = terminated_runners;
356                 terminated_runners = runner;
357                 /* ensures that all the group stops */
358                 killpg(runner->pids[0], SIGKILL);
359                 break;
360
361         case CLD_STOPPED:
362                 /* update the state */
363                 runner->state = as_stopped;
364                 break;
365
366         case CLD_CONTINUED:
367                 /* update the state */
368                 runner->state = as_running;
369                 break;
370         }
371 }
372
373 /**************** handle afm_launch_desc *********************/
374
375 /*
376  * Initialize the data of the launch description 'desc'
377  * for the application 'appli' and the 'mode'.
378  *
379  * Returns 0 in case of success or -1 in case of error.
380  */
381 static int fill_launch_desc(struct json_object *appli,
382                 enum afm_launch_mode mode, struct afm_launch_desc *desc)
383 {
384         json_object *pub;
385
386         assert(is_valid_launch_mode(mode));
387
388         /* main items */
389         if(!j_read_object_at(appli, "public", &pub)
390         || !j_read_string_at(appli, "path", &desc->path)
391         || !j_read_string_at(appli, "id", &desc->appid)
392         || !j_read_string_at(appli, "content", &desc->content)
393         || !j_read_string_at(appli, "type", &desc->type)
394         || !j_read_string_at(pub, "name", &desc->name)
395         || !j_read_integer_at(pub, "width", &desc->width)
396         || !j_read_integer_at(pub, "height", &desc->height)) {
397                 errno = EINVAL;
398                 return -1;
399         }
400
401         /* bindings */
402         {
403                 /* TODO */
404                 static const char *null = NULL;
405                 desc->bindings = &null;
406         }
407
408         /* finaly */
409         desc->home = homeappdir;
410         desc->mode = mode;
411         return 0;
412 }
413
414 /**************** report state of runner *********************/
415
416 /*
417  * Creates a json object that describes the state of 'runner'.
418  *
419  * Returns the created object or NULL in case of error.
420  */
421 static json_object *mkstate(struct apprun *runner)
422 {
423         const char *state;
424         struct json_object *result, *obj;
425         int rc;
426
427         /* the structure */
428         result = json_object_new_object();
429         if (result == NULL)
430                 goto error;
431
432         /* the runid */
433         if (!j_add_integer(result, "runid", runner->runid))
434                 goto error2;
435
436         /* the state */
437         switch(runner->state) {
438         case as_starting:
439         case as_running:
440                 state = "running";
441                 break;
442         case as_stopped:
443                 state = "stopped";
444                 break;
445         default:
446                 state = "terminated";
447                 break;
448         }
449         if (!j_add_string(result, "state", state))
450                 goto error2;
451
452         /* the application id */
453         rc = json_object_object_get_ex(runner->appli, "public", &obj);
454         assert(rc);
455         rc = json_object_object_get_ex(obj, "id", &obj);
456         assert(rc);
457         if (!j_add(result, "id", obj))
458                 goto error2;
459         json_object_get(obj);
460
461         /* done */
462         return result;
463
464 error2:
465         json_object_put(result);
466 error:
467         errno = ENOMEM;
468         return NULL;
469 }
470
471 /**************** API handling ************************/
472
473 /*
474  * Starts the application described by 'appli' for the 'mode'.
475  * In case of remote start, it returns in uri the uri to
476  * connect to.
477  *
478  * A reference to 'appli' is kept during the live of the
479  * runner. This is made using json_object_get. Thus be aware
480  * that further modifications to 'appli' might create errors.
481  *
482  * Returns 0 in case of success or -1 in case of error
483  */
484 int afm_run_start(struct json_object *appli, enum afm_launch_mode mode,
485                                                         char **uri)
486 {
487         static struct apprun *runner;
488         struct afm_launch_desc desc;
489         int rc;
490         sigset_t saved, blocked;
491
492         assert(is_valid_launch_mode(mode));
493         assert(mode == mode_local || uri != NULL);
494         assert(uri == NULL || *uri == NULL);
495
496         /* prepare to launch */
497         rc = fill_launch_desc(appli, mode, &desc);
498         if (rc)
499                 return rc;
500         runner = createrunner(appli);
501         if (!runner)
502                 return -1;
503
504         /* block children signals until launched */
505         sigemptyset(&blocked);
506         sigaddset(&blocked, SIGCHLD);
507         sigprocmask(SIG_BLOCK, &blocked, &saved);
508
509         /* launch now */
510         rc = afm_launch(&desc, runner->pids, uri);
511         if (rc < 0) {
512                 /* fork failed */
513                 sigprocmask(SIG_SETMASK, &saved, NULL);
514                 ERROR("can't start, afm_launch failed: %m");
515                 freerunner(runner);
516                 return -1;
517         }
518
519         /* insert the pid */
520         runner->state = as_running;
521         pgid_insert(runner);
522         rc = runner->runid;
523
524         /* unblock children signal now */
525         sigprocmask(SIG_SETMASK, &saved, NULL);
526         return rc;
527 }
528
529 /*
530  * Terminates the runner of 'runid'
531  *
532  * Returns 0 in case of success or -1 in case of error
533  */
534 int afm_run_terminate(int runid)
535 {
536         return killrunner(runid, SIGTERM, as_terminating);
537 }
538
539 /*
540  * Stops (aka pause) the runner of 'runid'
541  *
542  * Returns 0 in case of success or -1 in case of error
543  */
544 int afm_run_stop(int runid)
545 {
546         return killrunner(runid, SIGSTOP, as_stopped);
547 }
548
549 /*
550  * Continue (aka resume) the runner of 'runid'
551  *
552  * Returns 0 in case of success or -1 in case of error
553  */
554 int afm_run_continue(int runid)
555 {
556         return killrunner(runid, SIGCONT, as_running);
557 }
558
559 /*
560  * Get the list of the runners.
561  *
562  * Returns the list or NULL in case of error.
563  */
564 struct json_object *afm_run_list()
565 {
566         struct json_object *result, *obj;
567         struct apprun *runner;
568         int i;
569
570         /* creates the object */
571         result = json_object_new_array();
572         if (result == NULL)
573                 goto error;
574
575         /* iterate over runners */
576         for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
577                 runner = runners_by_runid[i];
578                 while (runner) {
579                         if (runner->state != as_terminating
580                                         && runner->state != as_terminated) {
581                                 /* adds the living runner */
582                                 obj = mkstate(runner);
583                                 if (obj == NULL)
584                                         goto error2;
585                                 if (json_object_array_add(result, obj) == -1) {
586                                         json_object_put(obj);
587                                         goto error2;
588                                 }
589                         }
590                         runner = runner->next_by_runid;
591                 }
592         }
593         return result;
594
595 error2:
596         json_object_put(result);
597 error:
598         errno = ENOMEM;
599         return NULL;
600 }
601
602 /*
603  * Get the state of the runner of 'runid'.
604  *
605  * Returns the state or NULL in case of success
606  */
607 struct json_object *afm_run_state(int runid)
608 {
609         struct apprun *runner = getrunner(runid);
610         if (runner == NULL || runner->state == as_terminating
611                                 || runner->state == as_terminated) {
612                 errno = ENOENT;
613                 return NULL;
614         }
615         return mkstate(runner);
616 }
617
618 /**************** INITIALISATION **********************/
619
620 /*
621  * Initialize the module
622  */
623 int afm_run_init()
624 {
625         char buf[2048];
626         int rc;
627         uid_t me;
628         struct passwd passwd, *pw;
629         struct sigaction siga;
630
631         /* init launcher */
632         rc = afm_launch_initialize();
633         if (rc)
634                 return rc;
635
636         /* computes the 'homeappdir' */
637         me = geteuid();
638         rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
639         if (rc || pw == NULL) {
640                 errno = rc ? errno : ENOENT;
641                 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
642                 return -1;
643         }
644         rc = asprintf(&homeappdir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
645         if (rc < 0) {
646                 errno = ENOMEM;
647                 ERROR("allocating homeappdir for uid=%d failed", (int)me);
648                 return -1;
649         }
650         rc = create_directory(homeappdir, 0755, 1);
651         if (rc && errno != EEXIST) {
652                 ERROR("creation of directory %s failed: %m", homeappdir);
653                 free(homeappdir);
654                 return -1;
655         }
656         rc = smack_remove_label_for_path(homeappdir,
657                                                 XATTR_NAME_SMACKTRANSMUTE, 0);
658         if (rc < 0 && errno != ENODATA) {
659                 ERROR("can't remove smack transmutation of directory %s: %m",
660                                                                 homeappdir);
661                 free(homeappdir);
662                 return -1;
663         }
664         rc = smack_set_label_for_path(homeappdir, XATTR_NAME_SMACK, 0,
665                                                         fwk_user_app_label);
666         if (rc < 0) {
667                 ERROR("can't set smack label %s to directory %s: %m",
668                                         fwk_user_app_label, homeappdir);
669                 free(homeappdir);
670                 return -1;
671         }
672         /* install signal handlers */
673         siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
674         sigemptyset(&siga.sa_mask);
675         sigaddset(&siga.sa_mask, SIGCHLD);
676         siga.sa_sigaction = on_sigchld;
677         sigaction(SIGCHLD, &siga, NULL);
678         return 0;
679 }
680