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/qmlviewer",
73 static const char *args_for_web_runtime[] = {
74 "/usr/share/qt5/examples/webkitwidgets/browser/browser",
75 "http://localhost:%P/%c?token=%S",
79 static const char *args_for_binary[] = {
86 const char **master_args;
87 const char **slave_args;
90 static struct execdesc known_launchers[] = {
91 { "text/html", args_for_afb_daemon, args_for_web_runtime },
92 { "application/x-executable", args_for_binary, NULL },
93 { "text/vnd.qt.qml", args_for_qmlviewer, NULL }
100 const char **master_args;
101 const char **slave_args;
104 static char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params)
106 const char **iter, *p, *v;
107 char *data, **result, port[20], width[20], height[20], mini[3], c;
114 /* loop that either compute the size and build the result */
124 while((c = *p++) != 0) {
133 case 'I': v = FWK_ICON_DIR; break;
134 case 'P': if(!x) sprintf(port, "%d", params->port); v = port; break;
135 case 'S': v = params->secret; break;
136 case 'D': v = params->datadir; break;
137 case 'r': v = desc->path; break;
138 case 'h': v = desc->home; break;
139 case 't': v = desc->tag; break;
140 case 'a': v = desc->appid; break;
141 case 'c': v = desc->content; break;
142 case 'm': v = desc->type; break;
143 case 'n': v = desc->name; break;
144 case 'p': v = "" /*desc->plugins*/; break;
145 case 'W': if(!x) sprintf(width, "%d", desc->width); v = width; break;
146 case 'H': if(!x) sprintf(height, "%d", desc->height); v = height; break;
148 default: mini[1] = c; v = mini; break;
151 data = stpcpy(data, v);
166 result = malloc((n+1)*sizeof(char*) + s);
167 if (result == NULL) {
171 data = (char*)(&result[n + 1]);
176 static void mksecret(char buffer[9])
178 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
183 static int port_ring = 12345;
184 int port = port_ring;
185 if (port < 12345 || port > 15432)
187 port_ring = port + 1;
193 static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
198 /* fork the master child */
199 children[0] = fork();
200 if (children[0] < 0) {
201 ERROR("master fork failed: %m");
205 /********* in the parent process ************/
209 /********* in the master child ************/
210 /* enter the process group */
213 ERROR("setpgid failed");
217 /* enter security mode */
218 rc = secmgr_prepare_exec(desc->tag);
220 ERROR("call to secmgr_prepare_exec failed: %m");
224 /* enter the datadirectory */
225 rc = mkdir(params->datadir, 0755);
226 if (rc && errno != EEXIST) {
227 ERROR("creation of datadir %s failed: %m", params->datadir);
230 rc = chdir(params->datadir);
232 ERROR("can't enter the datadir %s: %m", params->datadir);
236 args = instantiate_arguments(params->master_args, desc, params);
238 ERROR("out of memory in master");
241 rc = execve(args[0], args, environ);
242 ERROR("failed to exec master %s: %m", args[0]);
247 static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
255 /* prepare the pipes */
256 rc = pipe2(mpipe, O_CLOEXEC);
258 ERROR("error while calling pipe2: %m");
261 rc = pipe2(spipe, O_CLOEXEC);
263 ERROR("error while calling pipe2: %m");
269 /* fork the master child */
270 children[0] = fork();
271 if (children[0] < 0) {
272 ERROR("master fork failed: %m");
280 /********* in the parent process ************/
283 /* wait the ready signal (that transmit the slave pid) */
284 rc = read(mpipe[0], &children[1], sizeof children[1]);
286 ERROR("reading master pipe failed: %m");
292 assert(rc == sizeof children[1]);
293 /* start the child */
294 rc = write(spipe[1], "start", 5);
296 ERROR("writing slave pipe failed: %m");
305 /********* in the master child ************/
309 /* enter the process group */
312 ERROR("setpgid failed");
316 /* enter security mode */
317 rc = secmgr_prepare_exec(desc->tag);
319 ERROR("call to secmgr_prepare_exec failed: %m");
323 /* enter the datadirectory */
324 rc = mkdir(params->datadir, 0755);
325 if (rc && errno != EEXIST) {
326 ERROR("creation of datadir %s failed: %m", params->datadir);
329 rc = chdir(params->datadir);
331 ERROR("can't enter the datadir %s: %m", params->datadir);
335 /* fork the slave child */
336 children[1] = fork();
337 if (children[1] < 0) {
338 ERROR("slave fork failed: %m");
341 if (children[1] == 0) {
342 /********* in the slave child ************/
344 rc = read(spipe[0], message, sizeof message);
346 ERROR("reading slave pipe failed: %m");
350 args = instantiate_arguments(params->slave_args, desc, params);
352 ERROR("out of memory in slave");
355 rc = execve(args[0], args, environ);
356 ERROR("failed to exec slave %s: %m", args[0]);
361 /********* still in the master child ************/
363 args = instantiate_arguments(params->master_args, desc, params);
365 ERROR("out of memory in master");
368 rc = write(mpipe[1], &children[1], sizeof children[1]);
370 ERROR("can't write master pipe: %m");
374 rc = execve(args[0], args, environ);
375 ERROR("failed to exec master %s: %m", args[0]);
381 int afm_launch(struct afm_launch_desc *desc, pid_t children[2])
383 char datadir[PATH_MAX];
386 struct launchparam params;
388 /* what launcher ? */
390 if (desc->type != NULL && *desc->type) {
391 nkl = sizeof known_launchers / sizeof * known_launchers;
392 while (ikl < nkl && strcmp(desc->type, known_launchers[ikl].type))
395 ERROR("type %s not found!", desc->type);
402 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
403 if (rc < 0 || rc >= sizeof datadir) {
404 ERROR("overflow for datadir");
409 /* make the secret and port */
411 params.port = mkport();
412 params.secret = secret;
413 params.datadir = datadir;
414 params.master_args = known_launchers[ikl].master_args;
415 params.slave_args = known_launchers[ikl].slave_args;
417 return params.slave_args ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);