0fd533c0aa4b232ca4f0d65921a91bbf5c6cbb3a
[src/app-framework-main.git] / src / af-run.c
1 /*
2  Copyright 2015 IoT.bzh
3
4  Licensed under the Apache License, Version 2.0 (the "License");
5  you may not use this file except in compliance with the License.
6  You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15 */
16
17 #include <fcntl.h>
18 #include <unistd.h>
19 #include <signal.h>
20 #include <pwd.h>
21 #include <sys/types.h>
22 #include <errno.h>
23 #include <assert.h>
24 #include <stdio.h>
25 #include <limits.h>
26 #include <string.h>
27
28 #include <json.h>
29
30 #include "verbose.h"
31 #include "utils-dir.h"
32 #include "wgt-info.h"
33
34 enum appstate {
35         as_starting,
36         as_running,
37         as_stopped,
38         as_terminating,
39         as_terminated
40 };
41
42 struct apprun {
43         struct apprun *next_by_runid;
44         struct apprun *next_by_pgid;
45         int runid;
46         pid_t pgid;
47         enum appstate state;
48         json_object *appli;
49 };
50
51 #define ROOT_RUNNERS_COUNT  32
52 #define MAX_RUNNER_COUNT    32767
53
54 static struct apprun *runners_by_runid[ROOT_RUNNERS_COUNT];
55 static struct apprun *runners_by_pgid[ROOT_RUNNERS_COUNT];
56 static int runnercount = 0;
57 static int runnerid = 0;
58
59 static const char fwk_user_app_dir[] = FWK_USER_APP_DIR;
60 static char *homeappdir;
61
62 /****************** manages pgids **********************/
63
64 /* get a runner by its pgid */
65 static struct apprun *runner_of_pgid(pid_t pgid)
66 {
67         struct apprun *result = runners_by_pgid[(int)(pgid & (ROOT_RUNNERS_COUNT - 1))];
68         while (result && result->pgid != pgid)
69                 result = result->next_by_pgid;
70         return result;
71 }
72
73 /* insert a runner for its pgid */
74 static void pgid_insert(struct apprun *runner)
75 {
76         struct apprun **prev = &runners_by_runid[(int)(runner->pgid & (ROOT_RUNNERS_COUNT - 1))];
77         runner->next_by_pgid = *prev;
78         *prev = runner;
79 }
80
81 /* remove a runner for its pgid */
82 static void pgid_remove(struct apprun *runner)
83 {
84         struct apprun **prev = &runners_by_runid[(int)(runner->pgid & (ROOT_RUNNERS_COUNT - 1))];
85         runner->next_by_pgid = *prev;
86         *prev = runner;
87 }
88
89 /****************** manages pids **********************/
90
91 /* get a runner by its pid */
92 static struct apprun *runner_of_pid(pid_t pid)
93 {
94         /* try avoiding system call */
95         struct apprun *result = runner_of_pgid(pid);
96         if (result == NULL)
97                 result = runner_of_pgid(getpgid(pid));
98         return result;
99 }
100
101 /****************** manages runners (by runid) **********************/
102
103 /* get a runner by its runid */
104 static struct apprun *getrunner(int runid)
105 {
106         struct apprun *result = runners_by_runid[runid & (ROOT_RUNNERS_COUNT - 1)];
107         while (result && result->runid != runid)
108                 result = result->next_by_runid;
109         return result;
110 }
111
112 /* free an existing runner */
113 static void freerunner(struct apprun *runner)
114 {
115         struct apprun **prev = &runners_by_runid[runner->runid & (ROOT_RUNNERS_COUNT - 1)];
116         assert(*prev);
117         while(*prev != runner) {
118                 prev = &(*prev)->next_by_runid;
119                 assert(*prev);
120         }
121         *prev = runner->next_by_runid;
122         json_object_put(runner->appli);
123         free(runner);
124         runnercount--;
125 }
126
127 /* create a new runner */
128 static struct apprun *createrunner(json_object *appli)
129 {
130         struct apprun *result;
131         struct apprun **prev;
132
133         if (runnercount >= MAX_RUNNER_COUNT)
134                 return NULL;
135         do {
136                 runnerid++;
137                 if (runnerid > MAX_RUNNER_COUNT)
138                         runnerid = 1;
139         } while(getrunner(runnerid));
140         result = calloc(1, sizeof * result);
141         if (result) {
142                 prev = &runners_by_runid[runnerid & (ROOT_RUNNERS_COUNT - 1)];
143                 result->next_by_runid = *prev;
144                 result->next_by_pgid = NULL;
145                 result->runid = runnerid;
146                 result->pgid = 0;
147                 result->state = as_starting;
148                 result->appli = json_object_get(appli);
149                 *prev = result;
150                 runnercount++;
151         }
152         return result;
153 }
154
155 /**************** signaling ************************/
156
157 static void started(int runid)
158 {
159 }
160
161 static void stopped(int runid)
162 {
163 }
164
165 static void continued(int runid)
166 {
167 }
168
169 static void terminated(int runid)
170 {
171 }
172
173 static void removed(int runid)
174 {
175 }
176
177 /**************** running ************************/
178
179 static int killrunner(int runid, int sig, enum appstate tostate)
180 {
181         int rc;
182         struct apprun *runner = getrunner(runid);
183         if (runner == NULL) {
184                 errno = ENOENT;
185                 rc = -1;
186         }
187         else if (runner->state != as_running && runner->state != as_stopped) {
188                 errno = EPERM;
189                 rc = -1;
190         }
191         else if (runner->state == tostate) {
192                 rc = 0;
193         }
194         else {
195                 rc = killpg(runner->pgid, sig);
196                 if (!rc)
197                         runner->state = tostate;
198         }
199         return rc;
200 }
201
202 /**************** summarizing the application *********************/
203
204 struct applisum {
205         const char *path;
206         const char *tag;
207         const char *appid;
208         const char *content;
209         const char *type;
210         const char *name;
211         int width;
212         int height;
213 };
214
215 /**************** API handling ************************/
216
217 int af_run_start(struct json_object *appli)
218 {
219         const char *path;
220         const char *id;
221         return -1;
222 }
223
224 int af_run_terminate(int runid)
225 {
226         return killrunner(runid, SIGTERM, as_terminating);
227 }
228
229 int af_run_stop(int runid)
230 {
231         return killrunner(runid, SIGSTOP, as_stopped);
232 }
233
234 int af_run_continue(int runid)
235 {
236         return killrunner(runid, SIGCONT, as_running);
237 }
238
239 static json_object *mkstate(struct apprun *runner, const char **runidstr)
240 {
241         const char *state;
242         struct json_object *result, *obj, *runid;
243         int rc;
244
245         /* the structure */
246         result = json_object_new_object();
247         if (result == NULL)
248                 goto error;
249
250         /* the runid */
251         runid = json_object_new_int(runner->runid);
252         if (runid == NULL)
253                 goto error2;
254         json_object_object_add(result, "runid", obj); /* TODO TEST STATUS */
255
256         /* the state */
257         switch(runner->state) {
258         case as_starting:
259         case as_running:
260                 state = "running";
261                 break;
262         case as_stopped:
263                 state = "stopped";
264                 break;
265         default:
266                 state = "terminated";
267                 break;
268         }
269         obj = json_object_new_string(state);
270         if (obj == NULL)
271                 goto error2;
272         json_object_object_add(result, "state", obj); /* TODO TEST STATUS */
273
274         /* the application id */
275         rc = json_object_object_get_ex(runner->appli, "public", &obj);
276         assert(rc);
277         rc = json_object_object_get_ex(obj, "id", &obj);
278         assert(rc);
279         json_object_object_add(result, "id", obj); /* TODO TEST STATUS */
280         json_object_get(obj);
281
282         /* done */
283         if (runidstr)
284                 *runidstr = json_object_get_string(runid);
285         return result;
286
287 error2:
288         json_object_put(result);
289 error:
290         errno = ENOMEM;
291         return NULL;
292 }
293
294 struct json_object *af_run_list()
295 {
296         struct json_object *result, *obj;
297         struct apprun *runner;
298         const char *runidstr;
299         int i;
300
301         /* creates the object */
302         result = json_object_new_object();
303         if (result == NULL) {
304                 errno = ENOMEM;
305                 return NULL;            
306         }
307
308         for (i = 0 ; i < ROOT_RUNNERS_COUNT ; i++) {
309                 for (runner = runners_by_runid[i] ; runner ; runner = runner->next_by_runid) {
310                         if (runner->state != as_terminating && runner->state != as_terminated) {
311                                 obj = mkstate(runner, &runidstr);
312                                 if (obj == NULL) {
313                                         json_object_put(result);
314                                         return NULL;
315                                 }
316                                 /* TODO status ? */
317                                 json_object_object_add(result, runidstr, obj);
318                         }
319                 }
320         }
321         return result;
322 }
323
324 struct json_object *af_run_state(int runid)
325 {
326         struct apprun *runner = getrunner(runid);
327         if (runner == NULL || runner->state == as_terminating || runner->state == as_terminated) {
328                 errno = ENOENT;
329                 return NULL;
330         }
331         return mkstate(runner, NULL);
332 }
333
334 /**************** INITIALISATION **********************/
335
336 int af_run_init()
337 {
338         char buf[2048];
339         char dir[PATH_MAX];
340         int rc;
341         uid_t me;
342         struct passwd passwd, *pw;
343
344         /* computes the 'homeappdir' */
345         me = geteuid();
346         rc = getpwuid_r(me, &passwd, buf, sizeof buf, &pw);
347         if (rc || pw == NULL) {
348                 errno = rc ? errno : ENOENT;
349                 ERROR("getpwuid_r failed for uid=%d: %m",(int)me);
350                 return -1;
351         }
352         rc = snprintf(dir, sizeof dir, "%s/%s", passwd.pw_dir, fwk_user_app_dir);
353         if (rc >= sizeof dir) {
354                 ERROR("buffer overflow in user_app_dir for uid=%d",(int)me);
355                 return -1;
356         }
357         rc = create_directory(dir, 0755, 1);
358         if (rc && errno != EEXIST) {
359                 ERROR("creation of directory %s failed in user_app_dir: %m", dir);
360                 return -1;
361         }
362         homeappdir = strdup(dir);
363         if (homeappdir == NULL) {
364                 errno = ENOMEM;
365                 ERROR("out of memory in user_app_dir for %s : %m", dir);
366                 return -1;
367         }
368
369         /* install signal handlers */
370         
371         return 0;
372 }
373