4de0fd261b07ab3b9a96b61ad3d0471572dc4f8a
[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, *pids;
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 pids */
437         switch(runner->state) {
438         case as_starting:
439         case as_running:
440         case as_stopped:
441                 pids = j_add_new_array(result, "pids");
442                 if (!pids)
443                         goto error2;
444                 if (!j_add_integer(pids, NULL, runner->pids[0]))
445                         goto error2;
446                 if (runner->pids[1] && !j_add_integer(pids, NULL, runner->pids[1]))
447                         goto error2;
448                 break;
449         default:
450                 break;
451         }
452
453         /* the state */
454         switch(runner->state) {
455         case as_starting:
456         case as_running:
457                 state = "running";
458                 break;
459         case as_stopped:
460                 state = "stopped";
461                 break;
462         default:
463                 state = "terminated";
464                 break;
465         }
466         if (!j_add_string(result, "state", state))
467                 goto error2;
468
469         /* the application id */
470         rc = json_object_object_get_ex(runner->appli, "public", &obj);
471         assert(rc);
472         rc = json_object_object_get_ex(obj, "id", &obj);
473         assert(rc);
474         if (!j_add(result, "id", obj))
475                 goto error2;
476         json_object_get(obj);
477
478         /* done */
479         return result;
480
481 error2:
482         json_object_put(result);
483 error:
484         errno = ENOMEM;
485         return NULL;
486 }
487
488 /**************** API handling ************************/
489
490 /*
491  * Starts the application described by 'appli' for the 'mode'.
492  * In case of remote start, it returns in uri the uri to
493  * connect to.
494  *
495  * A reference to 'appli' is kept during the live of the
496  * runner. This is made using json_object_get. Thus be aware
497  * that further modifications to 'appli' might create errors.
498  *
499  * Returns 0 in case of success or -1 in case of error
500  */
501 int afm_run_start(struct json_object *appli, enum afm_launch_mode mode,
502                                                         char **uri)
503 {
504         static struct apprun *runner;
505         struct afm_launch_desc desc;
506         int rc;
507         sigset_t saved, blocked;
508
509         assert(is_valid_launch_mode(mode));
510         assert(mode == mode_local || uri != NULL);
511         assert(uri == NULL || *uri == NULL);
512
513         /* prepare to launch */
514         rc = fill_launch_desc(appli, mode, &desc);
515         if (rc)
516                 return rc;
517         runner = createrunner(appli);
518         if (!runner)
519                 return -1;
520
521         /* block children signals until launched */
522         sigemptyset(&blocked);
523         sigaddset(&blocked, SIGCHLD);
524         sigprocmask(SIG_BLOCK, &blocked, &saved);
525
526         /* launch now */
527         rc = afm_launch(&desc, runner->pids, uri);
528         if (rc < 0) {
529                 /* fork failed */
530                 sigprocmask(SIG_SETMASK, &saved, NULL);
531                 ERROR("can't start, afm_launch failed: %m");
532                 freerunner(runner);
533                 return -1;
534         }
535
536         /* insert the pid */
537         runner->state = as_running;
538         pgid_insert(runner);
539         rc = runner->runid;
540
541         /* unblock children signal now */
542         sigprocmask(SIG_SETMASK, &saved, NULL);
543         return rc;
544 }
545
546 /*
547  * Terminates the runner of 'runid'
548  *
549  * Returns 0 in case of success or -1 in case of error
550  */
551 int afm_run_terminate(int runid)
552 {
553         return killrunner(runid, SIGTERM, as_terminating);
554 }
555
556 /*
557  * Stops (aka pause) the runner of 'runid'
558  *
559  * Returns 0 in case of success or -1 in case of error
560  */
561 int afm_run_stop(int runid)
562 {
563         return killrunner(runid, SIGSTOP, as_stopped);
564 }
565
566 /*
567  * Continue (aka resume) the runner of 'runid'
568  *
569  * Returns 0 in case of success or -1 in case of error
570  */
571 int afm_run_continue(int runid)
572 {
573         return killrunner(runid, SIGCONT, as_running);
574 }
575
576 /*
577  * Get the list of the runners.
578  *
579  * Returns the list or NULL in case of error.
580  */
581 struct json_object *afm_run_list()
582 {
583         struct json_object *result, *obj;
584         struct apprun *runner;
585         int i;
586
587         /* creates the object */
588         result = json_object_new_array();
589         if (result == NULL)
590                 goto error;
591
592         /* iterate over runners */
593         for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
594                 runner = runners_by_runid[i];
595                 while (runner) {
596                         if (runner->state != as_terminating
597                                         && runner->state != as_terminated) {
598                                 /* adds the living runner */
599                                 obj = mkstate(runner);
600                                 if (obj == NULL)
601                                         goto error2;
602                                 if (json_object_array_add(result, obj) == -1) {
603                                         json_object_put(obj);
604                                         goto error2;
605                                 }
606                         }
607                         runner = runner->next_by_runid;
608                 }
609         }
610         return result;
611
612 error2:
613         json_object_put(result);
614 error:
615         errno = ENOMEM;
616         return NULL;
617 }
618
619 /*
620  * Get the state of the runner of 'runid'.
621  *
622  * Returns the state or NULL in case of success
623  */
624 struct json_object *afm_run_state(int runid)
625 {
626         struct apprun *runner = getrunner(runid);
627         if (runner == NULL || runner->state == as_terminating
628                                 || runner->state == as_terminated) {
629                 errno = ENOENT;
630                 return NULL;
631         }
632         return mkstate(runner);
633 }
634
635 /**************** INITIALISATION **********************/
636
637 /*
638  * Initialize the module
639  */
640 int afm_run_init()
641 {
642         char buf[2048];
643         int rc;
644         uid_t me;
645         struct passwd passwd, *pw;
646         struct sigaction siga;
647
648         /* init launcher */
649         rc = afm_launch_initialize();
650         if (rc)
651                 return rc;
652
653         /* computes the 'homeappdir' */
654         me = geteuid();
655         rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
656         if (rc || pw == NULL) {
657                 errno = rc ? errno : ENOENT;
658                 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
659                 return -1;
660         }
661         rc = asprintf(&homeappdir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
662         if (rc < 0) {
663                 errno = ENOMEM;
664                 ERROR("allocating homeappdir for uid=%d failed", (int)me);
665                 return -1;
666         }
667         rc = create_directory(homeappdir, 0755, 1);
668         if (rc && errno != EEXIST) {
669                 ERROR("creation of directory %s failed: %m", homeappdir);
670                 free(homeappdir);
671                 return -1;
672         }
673         rc = smack_remove_label_for_path(homeappdir,
674                                                 XATTR_NAME_SMACKTRANSMUTE, 0);
675         if (rc < 0 && errno != ENODATA) {
676                 ERROR("can't remove smack transmutation of directory %s: %m",
677                                                                 homeappdir);
678                 free(homeappdir);
679                 return -1;
680         }
681         rc = smack_set_label_for_path(homeappdir, XATTR_NAME_SMACK, 0,
682                                                         fwk_user_app_label);
683         if (rc < 0) {
684                 ERROR("can't set smack label %s to directory %s: %m",
685                                         fwk_user_app_label, homeappdir);
686                 free(homeappdir);
687                 return -1;
688         }
689         /* install signal handlers */
690         siga.sa_flags = SA_SIGINFO | SA_NOCLDWAIT;
691         sigemptyset(&siga.sa_mask);
692         sigaddset(&siga.sa_mask, SIGCHLD);
693         siga.sa_sigaction = on_sigchld;
694         sigaction(SIGCHLD, &siga, NULL);
695         return 0;
696 }
697