f4f55e5851c6cdd42c5f7fbc91aafa4d876298fa
[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_paused,      /* paused */
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  * Is a 'runner' alive?
184  */
185 static inline int is_alive(struct apprun *runner)
186 {
187         switch(runner->state) {
188         case as_terminating:
189         case as_terminated:
190                 return 0;
191         default:
192                 return 1;
193         }
194 }
195
196 /*
197  * Is a 'runner' dead?
198  */
199 static inline int is_dead(struct apprun *runner)
200 {
201         switch(runner->state) {
202         case as_terminating:
203         case as_terminated:
204                 return 1;
205         default:
206                 return 0;
207         }
208 }
209
210 /*
211  * Is a 'runner' running?
212  */
213 static inline int is_running(struct apprun *runner)
214 {
215         switch(runner->state) {
216         case as_starting:
217         case as_running:
218                 return 1;
219         default:
220                 return 0;
221         }
222 }
223
224 /*
225  * Is a 'runner' paused?
226  */
227 static inline int is_paused(struct apprun *runner)
228 {
229         switch(runner->state) {
230         case as_paused:
231                 return 1;
232         default:
233                 return 0;
234         }
235 }
236
237 /*
238  * Get a runner by its 'runid'  (NULL if not found)
239  */
240 static struct apprun *getrunner(int runid)
241 {
242         struct apprun *result;
243
244         result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
245         while (result && result->runid != runid)
246                 result = result->next_by_runid;
247         return result;
248 }
249
250 /*
251  * Get first runner of 'appli' (NULL if not found)
252  */
253 static struct apprun *getrunner_appli(json_object *appli)
254 {
255         int i;
256         struct apprun *result;
257
258         for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
259                 result = runners_by_pgid[i];
260                 while (result != NULL) {
261                         if (result->appli == appli)
262                                 return result;
263                         result = result->next_by_pgid;
264                 }
265         }
266         return NULL;
267 }
268
269 /*
270  * Free an existing 'runner'
271  */
272 static void freerunner(struct apprun *runner)
273 {
274         struct apprun **prev;
275
276         /* get previous pointer to runner */
277         prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
278         assert(*prev);
279         while(*prev != runner) {
280                 prev = &(*prev)->next_by_runid;
281                 assert(*prev);
282         }
283
284         /* unlink */
285         *prev = runner->next_by_runid;
286         runnercount--;
287
288         /* release/free */
289         json_object_put(runner->appli);
290         free(runner);
291 }
292
293 /*
294  * Cleans the list of runners from its terminated
295  */
296 static void cleanrunners()
297 {
298         struct apprun *runner;
299         while (terminated_runners) {
300                 runner = terminated_runners;
301                 terminated_runners = runner->next_by_pgid;
302                 freerunner(runner);
303         }
304 }
305
306 /*
307  * Create a new runner for the 'appli'
308  *
309  * Returns the created runner or NULL
310  * in case of error.
311  */
312 static struct apprun *createrunner(json_object *appli)
313 {
314         struct apprun *result;
315         struct apprun **prev;
316
317         /* cleanup */
318         cleanrunners();
319
320         /* get a runid */
321         if (runnercount >= MAX_RUNNER_COUNT) {
322                 errno = EAGAIN;
323                 return NULL;
324         }
325         do {
326                 runnerid++;
327                 if (runnerid > MAX_RUNNER_COUNT)
328                         runnerid = 1;
329         } while(getrunner(runnerid));
330
331         /* create the structure */
332         result = calloc(1, sizeof * result);
333         if (result == NULL)
334                 errno = ENOMEM;
335         else {
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);
344                 *prev = result;
345                 runnercount++;
346         }
347         return result;
348 }
349
350 /**************** signaling ************************/
351 #if 0
352 static void started(int runid)
353 {
354 }
355
356 static void paused(int runid)
357 {
358 }
359
360 static void resumed(int runid)
361 {
362 }
363
364 static void terminated(int runid)
365 {
366 }
367
368 static void removed(int runid)
369 {
370 }
371 #endif
372 /**************** running ************************/
373
374 /*
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.
378  *
379  * Only processes in the state 'as_running' or 'as_paused'
380  * can be signalled.
381  *
382  * Returns 0 in case of success or -1 in case of error.
383  */
384 static int killrunner(int runid, int sig, enum appstate tostate)
385 {
386         int rc;
387         struct apprun *runner = getrunner(runid);
388         if (runner == NULL) {
389                 errno = ENOENT;
390                 rc = -1;
391         }
392         else if (is_dead(runner)) {
393                 errno = EINVAL;
394                 rc = -1;
395         }
396         else if (runner->state == tostate) {
397                 rc = 0;
398         }
399         else {
400                 rc = killpg(runner->pids[0], sig);
401                 if (!rc)
402                         runner->state = tostate;
403         }
404         return rc;
405 }
406
407 /*
408  * Signal callback called on SIGCHLD. This is set using sigaction.
409  */
410 static void on_sigchld(int signum, siginfo_t *info, void *uctxt)
411 {
412         struct apprun *runner;
413
414         /* retrieves the runner */
415         runner = runner_of_pid(info->si_pid);
416         if (!runner)
417                 return;
418
419         /* known runner, inspect cause of signal */
420         switch(info->si_code) {
421         case CLD_EXITED:
422         case CLD_KILLED:
423         case CLD_DUMPED:
424         case CLD_TRAPPED:
425                 /* update the state */
426                 runner->state = as_terminated;
427                 /* remove it from pgid list */
428                 pgid_remove(runner);
429                 runner->next_by_pgid = terminated_runners;
430                 terminated_runners = runner;
431                 /* ensures that all the group terminates */
432                 killpg(runner->pids[0], SIGKILL);
433                 break;
434
435         case CLD_STOPPED:
436                 /* update the state */
437                 runner->state = as_paused;
438                 break;
439
440         case CLD_CONTINUED:
441                 /* update the state */
442                 runner->state = as_running;
443                 break;
444         }
445 }
446
447 /**************** handle afm_launch_desc *********************/
448
449 /*
450  * Initialize the data of the launch description 'desc'
451  * for the application 'appli' and the 'mode'.
452  *
453  * Returns 0 in case of success or -1 in case of error.
454  */
455 static int fill_launch_desc(struct json_object *appli,
456                 enum afm_launch_mode mode, struct afm_launch_desc *desc)
457 {
458         json_object *pub;
459
460         assert(is_valid_launch_mode(mode));
461
462         /* main items */
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                 errno = EINVAL;
472                 return -1;
473         }
474
475         /* bindings */
476         {
477                 /* TODO */
478                 static const char *null = NULL;
479                 desc->bindings = &null;
480         }
481
482         /* finaly */
483         desc->home = homeappdir;
484         desc->mode = mode;
485         return 0;
486 }
487
488 /**************** report state of runner *********************/
489
490 /*
491  * Creates a json object that describes the state of 'runner'.
492  *
493  * Returns the created object or NULL in case of error.
494  */
495 static json_object *mkstate(struct apprun *runner)
496 {
497         const char *state;
498         struct json_object *result, *obj, *pids;
499         int rc;
500
501         /* the structure */
502         result = json_object_new_object();
503         if (result == NULL)
504                 goto error;
505
506         /* the runid */
507         if (!j_add_integer(result, "runid", runner->runid))
508                 goto error2;
509
510         /* the pids */
511         if (is_alive(runner)) {
512                 pids = j_add_new_array(result, "pids");
513                 if (!pids)
514                         goto error2;
515                 if (!j_add_integer(pids, NULL, runner->pids[0]))
516                         goto error2;
517                 if (runner->pids[1] && !j_add_integer(pids, NULL, runner->pids[1]))
518                         goto error2;
519         }
520
521         /* the state */
522         switch(runner->state) {
523         case as_starting:
524         case as_running:
525                 state = "running";
526                 break;
527         case as_paused:
528                 state = "paused";
529                 break;
530         default:
531                 state = "terminated";
532                 break;
533         }
534         if (!j_add_string(result, "state", state))
535                 goto error2;
536
537         /* the application id */
538         rc = json_object_object_get_ex(runner->appli, "public", &obj);
539         assert(rc);
540         rc = json_object_object_get_ex(obj, "id", &obj);
541         assert(rc);
542         if (!j_add(result, "id", obj))
543                 goto error2;
544         json_object_get(obj);
545
546         /* done */
547         return result;
548
549 error2:
550         json_object_put(result);
551 error:
552         errno = ENOMEM;
553         return NULL;
554 }
555
556 /**************** API handling ************************/
557
558 /*
559  * Starts the application described by 'appli' for the 'mode'.
560  * In case of remote start, it returns in uri the uri to
561  * connect to.
562  *
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.
566  *
567  * Returns the runid in case of success or -1 in case of error
568  */
569 int afm_run_start(struct json_object *appli, enum afm_launch_mode mode,
570                                                         char **uri)
571 {
572         struct apprun *runner;
573         struct afm_launch_desc desc;
574         int rc;
575         sigset_t saved, blocked;
576
577         assert(is_valid_launch_mode(mode));
578         assert(mode == mode_local || uri != NULL);
579         assert(uri == NULL || *uri == NULL);
580
581         /* prepare to launch */
582         rc = fill_launch_desc(appli, mode, &desc);
583         if (rc)
584                 return rc;
585         runner = createrunner(appli);
586         if (!runner)
587                 return -1;
588
589         /* block children signals until launched */
590         sigemptyset(&blocked);
591         sigaddset(&blocked, SIGCHLD);
592         sigprocmask(SIG_BLOCK, &blocked, &saved);
593
594         /* launch now */
595         rc = afm_launch(&desc, runner->pids, uri);
596         if (rc < 0) {
597                 /* fork failed */
598                 sigprocmask(SIG_SETMASK, &saved, NULL);
599                 ERROR("can't start, afm_launch failed: %m");
600                 freerunner(runner);
601                 return -1;
602         }
603
604         /* insert the pid */
605         runner->state = as_running;
606         pgid_insert(runner);
607         rc = runner->runid;
608
609         /* unblock children signal now */
610         sigprocmask(SIG_SETMASK, &saved, NULL);
611         return rc;
612 }
613
614 /*
615  * Returns the runid of a previously started application 'appli'
616  * or if none is running, starts the application described by 'appli'
617  * in local mode.
618  *
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.
622  *
623  * Returns the runid in case of success or -1 in case of error
624  */
625 int afm_run_once(struct json_object *appli)
626 {
627         struct apprun *runner = getrunner_appli(appli);
628         return runner && is_alive(runner) ? runner->runid : afm_run_start(appli, mode_local, NULL);
629 }
630
631 /*
632  * Terminates the runner of 'runid'
633  *
634  * Returns 0 in case of success or -1 in case of error
635  */
636 int afm_run_terminate(int runid)
637 {
638         return killrunner(runid, SIGTERM, as_terminating);
639 }
640
641 /*
642  * Stops (aka pause) the runner of 'runid'
643  *
644  * Returns 0 in case of success or -1 in case of error
645  */
646 int afm_run_pause(int runid)
647 {
648         return killrunner(runid, SIGSTOP, as_paused);
649 }
650
651 /*
652  * Continue (aka resume) the runner of 'runid'
653  *
654  * Returns 0 in case of success or -1 in case of error
655  */
656 int afm_run_resume(int runid)
657 {
658         return killrunner(runid, SIGCONT, as_running);
659 }
660
661 /*
662  * Get the list of the runners.
663  *
664  * Returns the list or NULL in case of error.
665  */
666 struct json_object *afm_run_list()
667 {
668         struct json_object *result, *obj;
669         struct apprun *runner;
670         int i;
671
672         /* creates the object */
673         result = json_object_new_array();
674         if (result == NULL)
675                 goto error;
676
677         /* iterate over runners */
678         for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
679                 runner = runners_by_runid[i];
680                 while (runner) {
681                         if (is_alive(runner)) {
682                                 /* adds the living runner */
683                                 obj = mkstate(runner);
684                                 if (obj == NULL)
685                                         goto error2;
686                                 if (json_object_array_add(result, obj) == -1) {
687                                         json_object_put(obj);
688                                         goto error2;
689                                 }
690                         }
691                         runner = runner->next_by_runid;
692                 }
693         }
694         return result;
695
696 error2:
697         json_object_put(result);
698 error:
699         errno = ENOMEM;
700         return NULL;
701 }
702
703 /*
704  * Get the state of the runner of 'runid'.
705  *
706  * Returns the state or NULL in case of success
707  */
708 struct json_object *afm_run_state(int runid)
709 {
710         struct apprun *runner = getrunner(runid);
711         if (runner == NULL || is_dead(runner)) {
712                 errno = ENOENT;
713                 return NULL;
714         }
715         return mkstate(runner);
716 }
717
718 /**************** INITIALISATION **********************/
719
720 /*
721  * Initialize the module
722  */
723 int afm_run_init()
724 {
725         char buf[2048];
726         int rc;
727         uid_t me;
728         struct passwd passwd, *pw;
729         struct sigaction siga;
730
731         /* init launcher */
732         rc = afm_launch_initialize();
733         if (rc)
734                 return rc;
735
736         /* computes the 'homeappdir' */
737         me = geteuid();
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);
742                 return -1;
743         }
744         rc = asprintf(&homeappdir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
745         if (rc < 0) {
746                 errno = ENOMEM;
747                 ERROR("allocating homeappdir for uid=%d failed", (int)me);
748                 return -1;
749         }
750         rc = create_directory(homeappdir, 0755, 1);
751         if (rc && errno != EEXIST) {
752                 ERROR("creation of directory %s failed: %m", homeappdir);
753                 free(homeappdir);
754                 return -1;
755         }
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",
760                                                                 homeappdir);
761                 free(homeappdir);
762                 return -1;
763         }
764         rc = smack_set_label_for_path(homeappdir, XATTR_NAME_SMACK, 0,
765                                                         fwk_user_app_label);
766         if (rc < 0) {
767                 ERROR("can't set smack label %s to directory %s: %m",
768                                         fwk_user_app_label, homeappdir);
769                 free(homeappdir);
770                 return -1;
771         }
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);
778         return 0;
779 }
780