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 */
126 while((c = *p++) != 0) {
135 case 'I': v = FWK_ICON_DIR; break;
136 case 'P': if(!x) sprintf(port, "%d", params->port); v = port; break;
137 case 'S': v = params->secret; break;
138 case 'D': v = params->datadir; break;
139 case 'r': v = desc->path; break;
140 case 'h': v = desc->home; break;
141 case 't': v = desc->tag; break;
142 case 'a': v = desc->appid; break;
143 case 'c': v = desc->content; break;
144 case 'm': v = desc->type; break;
145 case 'n': v = desc->name; break;
146 case 'p': v = "" /*desc->plugins*/; break;
147 case 'W': if(!x) sprintf(width, "%d", desc->width); v = width; break;
148 case 'H': if(!x) sprintf(height, "%d", desc->height); v = height; break;
150 default: mini[1] = c; v = mini; break;
153 data = stpcpy(data, v);
168 result = malloc((n+1)*sizeof(char*) + s);
169 if (result == NULL) {
173 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]);
288 ERROR("reading master pipe failed: %m");
294 assert(rc == sizeof children[1]);
295 /* start the child */
296 rc = write(spipe[1], "start", 5);
298 ERROR("writing slave pipe failed: %m");
307 /********* in the master child ************/
311 /* enter the process group */
314 ERROR("setpgid failed");
318 /* enter security mode */
319 rc = secmgr_prepare_exec(desc->tag);
321 ERROR("call to secmgr_prepare_exec failed: %m");
325 /* enter the datadirectory */
326 rc = mkdir(params->datadir, 0755);
327 if (rc && errno != EEXIST) {
328 ERROR("creation of datadir %s failed: %m", params->datadir);
331 rc = chdir(params->datadir);
333 ERROR("can't enter the datadir %s: %m", params->datadir);
337 /* fork the slave child */
338 children[1] = fork();
339 if (children[1] < 0) {
340 ERROR("slave fork failed: %m");
343 if (children[1] == 0) {
344 /********* in the slave child ************/
346 rc = read(spipe[0], message, sizeof message);
348 ERROR("reading slave pipe failed: %m");
352 args = instantiate_arguments(params->slave_args, desc, params);
354 ERROR("out of memory in slave");
357 rc = execve(args[0], args, environ);
358 ERROR("failed to exec slave %s: %m", args[0]);
363 /********* still in the master child ************/
365 args = instantiate_arguments(params->master_args, desc, params);
367 ERROR("out of memory in master");
370 rc = write(mpipe[1], &children[1], sizeof children[1]);
372 ERROR("can't write master pipe: %m");
376 rc = execve(args[0], args, environ);
377 ERROR("failed to exec master %s: %m", args[0]);
383 int afm_launch(struct afm_launch_desc *desc, pid_t children[2])
385 char datadir[PATH_MAX];
388 struct launchparam params;
390 /* what launcher ? */
392 if (desc->type != NULL && *desc->type) {
393 nkl = sizeof known_launchers / sizeof * known_launchers;
394 while (ikl < nkl && strcmp(desc->type, known_launchers[ikl].type))
397 ERROR("type %s not found!", desc->type);
404 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
405 if (rc < 0 || rc >= sizeof datadir) {
406 ERROR("overflow for datadir");
411 /* make the secret and port */
413 params.port = mkport();
414 params.secret = secret;
415 params.datadir = datadir;
416 params.master_args = known_launchers[ikl].master_args;
417 params.slave_args = known_launchers[ikl].slave_args;
419 return params.slave_args ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);