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/share/qt5/examples/webkitwidgets/browser/browser",
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 char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params)
108 const char **iter, *p, *v;
109 char *data, **result, port[20], width[20], height[20], mini[3], c;
116 /* loop that either compute the size and build the result */
127 while((c = *p++) != 0) {
136 case 'I': v = FWK_ICON_DIR; break;
137 case 'P': if(!data) sprintf(port, "%d", params->port); v = port; break;
138 case 'S': v = params->secret; break;
139 case 'D': v = params->datadir; break;
140 case 'r': v = desc->path; break;
141 case 'h': v = desc->home; break;
142 case 't': v = desc->tag; break;
143 case 'a': v = desc->appid; break;
144 case 'c': v = desc->content; break;
145 case 'm': v = desc->type; break;
146 case 'n': v = desc->name; break;
147 case 'p': v = "" /*desc->plugins*/; break;
148 case 'W': if(!data) sprintf(width, "%d", desc->width); v = width; break;
149 case 'H': if(!data) sprintf(height, "%d", desc->height); v = height; break;
151 default: mini[1] = c; v = mini; break;
154 data = stpcpy(data, v);
169 result = malloc((n+1)*sizeof(char*) + s);
170 if (result == NULL) {
174 data = (char*)(&result[n + 1]);
178 static void mksecret(char buffer[9])
180 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
185 static int port_ring = 12345;
186 int port = port_ring;
187 if (port < 12345 || port > 15432)
189 port_ring = port + 1;
195 static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
200 /* fork the master child */
201 children[0] = fork();
202 if (children[0] < 0) {
203 ERROR("master fork failed: %m");
207 /********* in the parent process ************/
211 /********* in the master child ************/
212 /* enter the process group */
215 ERROR("setpgid failed");
219 /* enter security mode */
220 rc = secmgr_prepare_exec(desc->tag);
222 ERROR("call to secmgr_prepare_exec failed: %m");
226 /* enter the datadirectory */
227 rc = mkdir(params->datadir, 0755);
228 if (rc && errno != EEXIST) {
229 ERROR("creation of datadir %s failed: %m", params->datadir);
232 rc = chdir(params->datadir);
234 ERROR("can't enter the datadir %s: %m", params->datadir);
238 args = instantiate_arguments(params->master_args, desc, params);
240 ERROR("out of memory in master");
243 rc = execve(args[0], args, environ);
244 ERROR("failed to exec master %s: %m", args[0]);
249 static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
257 /* prepare the pipes */
258 rc = pipe2(mpipe, O_CLOEXEC);
260 ERROR("error while calling pipe2: %m");
263 rc = pipe2(spipe, O_CLOEXEC);
265 ERROR("error while calling pipe2: %m");
271 /* fork the master child */
272 children[0] = fork();
273 if (children[0] < 0) {
274 ERROR("master fork failed: %m");
282 /********* in the parent process ************/
285 /* wait the ready signal (that transmit the slave pid) */
286 rc = read(mpipe[0], &children[1], sizeof children[1]);
289 ERROR("reading master pipe failed: %m");
293 assert(rc == sizeof children[1]);
294 /* start the child */
295 rc = write(spipe[1], "start", 5);
297 ERROR("writing slave pipe failed: %m");
306 /********* in the master child ************/
310 /* enter the process group */
313 ERROR("setpgid failed");
317 /* enter security mode */
318 rc = secmgr_prepare_exec(desc->tag);
320 ERROR("call to secmgr_prepare_exec failed: %m");
324 /* enter the datadirectory */
325 rc = mkdir(params->datadir, 0755);
326 if (rc && errno != EEXIST) {
327 ERROR("creation of datadir %s failed: %m", params->datadir);
330 rc = chdir(params->datadir);
332 ERROR("can't enter the datadir %s: %m", params->datadir);
336 /* fork the slave child */
337 children[1] = fork();
338 if (children[1] < 0) {
339 ERROR("slave fork failed: %m");
342 if (children[1] == 0) {
343 /********* in the slave child ************/
345 rc = read(spipe[0], message, sizeof message);
347 ERROR("reading slave pipe failed: %m");
351 args = instantiate_arguments(params->slave_args, desc, params);
353 ERROR("out of memory in slave");
356 rc = execve(args[0], args, environ);
357 ERROR("failed to exec slave %s: %m", args[0]);
362 /********* still in the master child ************/
364 args = instantiate_arguments(params->master_args, desc, params);
366 ERROR("out of memory in master");
369 rc = write(mpipe[1], &children[1], sizeof children[1]);
371 ERROR("can't write master pipe: %m");
375 rc = execve(args[0], args, environ);
376 ERROR("failed to exec master %s: %m", args[0]);
382 int afm_launch(struct afm_launch_desc *desc, pid_t children[2])
384 char datadir[PATH_MAX];
387 struct launchparam params;
389 /* what launcher ? */
391 if (desc->type != NULL && *desc->type) {
392 nkl = sizeof known_launchers / sizeof * known_launchers;
393 while (ikl < nkl && strcmp(desc->type, known_launchers[ikl].type))
396 ERROR("type %s not found!", desc->type);
403 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
404 if (rc < 0 || rc >= sizeof datadir) {
405 ERROR("overflow for datadir");
410 /* make the secret and port */
412 params.port = mkport();
413 params.secret = secret;
414 params.datadir = datadir;
415 params.master_args = known_launchers[ikl].master_args;
416 params.slave_args = known_launchers[ikl].slave_args;
418 return params.slave_args ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);