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",
65 static const char *args_for_qmlviewer[] = {
66 "/usr/bin/qt5/qmlscene",
76 static const char *args_for_web_runtime[] = {
77 "/usr/bin/web-runtime",
78 "http://localhost:%P/%c?token=%S",
82 static const char *args_for_binary[] = {
89 const char **master_args;
90 const char **slave_args;
93 static struct execdesc known_launchers[] = {
94 { "text/html", args_for_afb_daemon, args_for_web_runtime },
95 { "application/x-executable", args_for_binary, NULL },
96 { "text/vnd.qt.qml", args_for_qmlviewer, NULL }
103 const char **master_args;
104 const char **slave_args;
107 static char **instantiate_arguments(const char **args, struct afm_launch_desc *desc, struct launchparam *params)
109 const char **iter, *p, *v;
110 char *data, **result, port[20], width[20], height[20], mini[3], c;
117 /* loop that either compute the size and build the result */
128 while((c = *p++) != 0) {
137 case 'I': v = FWK_ICON_DIR; break;
138 case 'P': if(!data) sprintf(port, "%d", params->port); v = port; break;
139 case 'S': v = params->secret; break;
140 case 'D': v = params->datadir; break;
141 case 'r': v = desc->path; break;
142 case 'h': v = desc->home; break;
143 case 't': v = desc->tag; break;
144 case 'a': v = desc->appid; break;
145 case 'c': v = desc->content; break;
146 case 'm': v = desc->type; break;
147 case 'n': v = desc->name; break;
148 case 'p': v = "" /*desc->plugins*/; break;
149 case 'W': if(!data) sprintf(width, "%d", desc->width); v = width; break;
150 case 'H': if(!data) sprintf(height, "%d", desc->height); v = height; break;
152 default: mini[1] = c; v = mini; break;
155 data = stpcpy(data, v);
170 result = malloc((n+1)*sizeof(char*) + s);
171 if (result == NULL) {
175 data = (char*)(&result[n + 1]);
179 static void mksecret(char buffer[9])
181 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
186 static int port_ring = 12345;
187 int port = port_ring;
188 if (port < 12345 || port > 15432)
190 port_ring = port + 1;
196 static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
201 /* fork the master child */
202 children[0] = fork();
203 if (children[0] < 0) {
204 ERROR("master fork failed: %m");
208 /********* in the parent process ************/
212 /********* in the master child ************/
213 /* enter the process group */
216 ERROR("setpgid failed");
220 /* enter security mode */
221 rc = secmgr_prepare_exec(desc->tag);
223 ERROR("call to secmgr_prepare_exec failed: %m");
227 /* enter the datadirectory */
228 rc = mkdir(params->datadir, 0755);
229 if (rc && errno != EEXIST) {
230 ERROR("creation of datadir %s failed: %m", params->datadir);
233 rc = chdir(params->datadir);
235 ERROR("can't enter the datadir %s: %m", params->datadir);
239 args = instantiate_arguments(params->master_args, desc, params);
241 ERROR("out of memory in master");
244 rc = execve(args[0], args, environ);
245 ERROR("failed to exec master %s: %m", args[0]);
250 static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
258 /* prepare the pipes */
259 rc = pipe2(mpipe, O_CLOEXEC);
261 ERROR("error while calling pipe2: %m");
264 rc = pipe2(spipe, O_CLOEXEC);
266 ERROR("error while calling pipe2: %m");
272 /* fork the master child */
273 children[0] = fork();
274 if (children[0] < 0) {
275 ERROR("master fork failed: %m");
283 /********* in the parent process ************/
286 /* wait the ready signal (that transmit the slave pid) */
287 rc = read(mpipe[0], &children[1], sizeof children[1]);
290 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);