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.
30 #include <sys/types.h>
32 extern char **environ;
35 #include "afm-launch.h"
36 #include "secmgr-wrap.h"
39 %I icondir FWK_ICON_DIR
41 %S secret params->secret
42 %D datadir params->datadir
45 %t tag (smack label) desc->tag
47 %c content desc->content
48 %m mime-type desc->type
50 %p plugins desc->plugins
52 %H height desc->height
55 static const char *args_for_afb_daemon[] = {
56 "/usr/bin/afb-daemon",
64 static const char *args_for_qmlviewer[] = {
65 "/usr/bin/qt5/qmlscene",
75 static const char *args_for_web_runtime[] = {
76 "/usr/bin/web-runtime",
77 "http://localhost:%P/%c?token=%S",
81 static const char *args_for_binary[] = {
88 const char **master_args;
89 const char **slave_args;
92 static struct execdesc known_launchers[] = {
93 { "text/html", args_for_afb_daemon, args_for_web_runtime },
94 { "application/x-executable", args_for_binary, NULL },
95 { "text/vnd.qt.qml", args_for_qmlviewer, NULL }
102 const char **master_args;
103 const char **slave_args;
106 static gid_t groupid = 0;
108 static char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params)
110 const char **iter, *p, *v;
111 char *data, **result, port[20], width[20], height[20], mini[3], c;
118 /* loop that either compute the size and build the result */
129 while((c = *p++) != 0) {
138 case 'I': v = FWK_ICON_DIR; break;
139 case 'P': if(!data) sprintf(port, "%d", params->port); v = port; break;
140 case 'S': v = params->secret; break;
141 case 'D': v = params->datadir; break;
142 case 'r': v = desc->path; break;
143 case 'h': v = desc->home; break;
144 case 't': v = desc->tag; break;
145 case 'a': v = desc->appid; break;
146 case 'c': v = desc->content; break;
147 case 'm': v = desc->type; break;
148 case 'n': v = desc->name; break;
149 case 'p': v = "" /*desc->plugins*/; break;
150 case 'W': if(!data) sprintf(width, "%d", desc->width); v = width; break;
151 case 'H': if(!data) sprintf(height, "%d", desc->height); v = height; break;
153 default: mini[1] = c; v = mini; break;
156 data = stpcpy(data, v);
171 result = malloc((n+1)*sizeof(char*) + s);
172 if (result == NULL) {
176 data = (char*)(&result[n + 1]);
180 static void mksecret(char buffer[9])
182 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
187 static int port_ring = 12345;
188 int port = port_ring;
189 if (port < 12345 || port > 15432)
191 port_ring = port + 1;
197 static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
202 /* fork the master child */
203 children[0] = fork();
204 if (children[0] < 0) {
205 ERROR("master fork failed: %m");
209 /********* in the parent process ************/
213 /********* in the master child ************/
215 /* avoid set-gid effect */
216 setresgid(groupid, groupid, groupid);
218 /* enter the process group */
221 ERROR("setpgid failed");
225 /* enter security mode */
226 rc = secmgr_prepare_exec(desc->tag);
228 ERROR("call to secmgr_prepare_exec failed: %m");
232 /* enter the datadirectory */
233 rc = mkdir(params->datadir, 0755);
234 if (rc && errno != EEXIST) {
235 ERROR("creation of datadir %s failed: %m", params->datadir);
238 rc = chdir(params->datadir);
240 ERROR("can't enter the datadir %s: %m", params->datadir);
244 args = instantiate_arguments(params->master_args, desc, params);
246 ERROR("out of memory in master");
249 rc = execve(args[0], args, environ);
250 ERROR("failed to exec master %s: %m", args[0]);
255 static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
263 /* prepare the pipes */
264 rc = pipe2(mpipe, O_CLOEXEC);
266 ERROR("error while calling pipe2: %m");
269 rc = pipe2(spipe, O_CLOEXEC);
271 ERROR("error while calling pipe2: %m");
277 /* fork the master child */
278 children[0] = fork();
279 if (children[0] < 0) {
280 ERROR("master fork failed: %m");
288 /********* in the parent process ************/
291 /* wait the ready signal (that transmit the slave pid) */
292 rc = read(mpipe[0], &children[1], sizeof children[1]);
295 ERROR("reading master pipe failed: %m");
299 assert(rc == sizeof children[1]);
300 /* start the child */
301 rc = write(spipe[1], "start", 5);
303 ERROR("writing slave pipe failed: %m");
312 /********* in the master child ************/
316 /* avoid set-gid effect */
317 setresgid(groupid, groupid, groupid);
319 /* enter the process group */
322 ERROR("setpgid failed");
326 /* enter security mode */
327 rc = secmgr_prepare_exec(desc->tag);
329 ERROR("call to secmgr_prepare_exec failed: %m");
333 /* enter the datadirectory */
334 rc = mkdir(params->datadir, 0755);
335 if (rc && errno != EEXIST) {
336 ERROR("creation of datadir %s failed: %m", params->datadir);
339 rc = chdir(params->datadir);
341 ERROR("can't enter the datadir %s: %m", params->datadir);
345 /* fork the slave child */
346 children[1] = fork();
347 if (children[1] < 0) {
348 ERROR("slave fork failed: %m");
351 if (children[1] == 0) {
352 /********* in the slave child ************/
354 rc = read(spipe[0], message, sizeof message);
356 ERROR("reading slave pipe failed: %m");
360 args = instantiate_arguments(params->slave_args, desc, params);
362 ERROR("out of memory in slave");
365 rc = execve(args[0], args, environ);
366 ERROR("failed to exec slave %s: %m", args[0]);
371 /********* still in the master child ************/
373 args = instantiate_arguments(params->master_args, desc, params);
375 ERROR("out of memory in master");
378 rc = write(mpipe[1], &children[1], sizeof children[1]);
380 ERROR("can't write master pipe: %m");
384 rc = execve(args[0], args, environ);
385 ERROR("failed to exec master %s: %m", args[0]);
391 static void afm_launch_init_group()
395 getresgid(&r, &e, &s);
403 int afm_launch(struct afm_launch_desc *desc, pid_t children[2])
405 char datadir[PATH_MAX];
408 struct launchparam params;
411 afm_launch_init_group();
413 /* what launcher ? */
415 if (desc->type != NULL && *desc->type) {
416 nkl = sizeof known_launchers / sizeof * known_launchers;
417 while (ikl < nkl && strcmp(desc->type, known_launchers[ikl].type))
420 ERROR("type %s not found!", desc->type);
427 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
428 if (rc < 0 || rc >= sizeof datadir) {
429 ERROR("overflow for datadir");
434 /* make the secret and port */
436 params.port = mkport();
437 params.secret = secret;
438 params.datadir = datadir;
439 params.master_args = known_launchers[ikl].master_args;
440 params.slave_args = known_launchers[ikl].slave_args;
442 return params.slave_args ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);