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 */
130 while((c = *p++) != 0) {
139 case 'I': v = FWK_ICON_DIR; break;
140 case 'P': if(!data) sprintf(port, "%d", params->port); v = port; break;
141 case 'S': v = params->secret; break;
142 case 'D': v = params->datadir; break;
143 case 'r': v = desc->path; break;
144 case 'h': v = desc->home; break;
145 case 't': v = desc->tag; break;
146 case 'a': v = desc->appid; break;
147 case 'c': v = desc->content; break;
148 case 'm': v = desc->type; break;
149 case 'n': v = desc->name; break;
150 case 'p': v = "" /*desc->plugins*/; break;
151 case 'W': if(!data) sprintf(width, "%d", desc->width); v = width; break;
152 case 'H': if(!data) sprintf(height, "%d", desc->height); v = height; break;
154 default: mini[1] = c; v = mini; break;
157 data = stpcpy(data, v);
172 result = malloc((n+1)*sizeof(char*) + s);
173 if (result == NULL) {
177 data = (char*)(&result[n + 1]);
181 static void mksecret(char buffer[9])
183 snprintf(buffer, 9, "%08lX", (0xffffffff & random()));
188 static int port_ring = 12345;
189 int port = port_ring;
190 if (port < 12345 || port > 15432)
192 port_ring = port + 1;
198 static int launchexec1(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
203 /* fork the master child */
204 children[0] = fork();
205 if (children[0] < 0) {
206 ERROR("master fork failed: %m");
210 /********* in the parent process ************/
214 /********* in the master child ************/
216 /* avoid set-gid effect */
217 setresgid(groupid, groupid, groupid);
219 /* enter the process group */
222 ERROR("setpgid failed");
226 /* enter security mode */
227 rc = secmgr_prepare_exec(desc->tag);
229 ERROR("call to secmgr_prepare_exec failed: %m");
233 /* enter the datadirectory */
234 rc = mkdir(params->datadir, 0755);
235 if (rc && errno != EEXIST) {
236 ERROR("creation of datadir %s failed: %m", params->datadir);
239 rc = chdir(params->datadir);
241 ERROR("can't enter the datadir %s: %m", params->datadir);
245 args = instantiate_arguments(params->master_args, desc, params);
247 ERROR("out of memory in master");
250 rc = execve(args[0], args, environ);
251 ERROR("failed to exec master %s: %m", args[0]);
256 static int launchexec2(struct afm_launch_desc *desc, pid_t children[2], struct launchparam *params)
264 /* prepare the pipes */
265 rc = pipe2(mpipe, O_CLOEXEC);
267 ERROR("error while calling pipe2: %m");
270 rc = pipe2(spipe, O_CLOEXEC);
272 ERROR("error while calling pipe2: %m");
278 /* fork the master child */
279 children[0] = fork();
280 if (children[0] < 0) {
281 ERROR("master fork failed: %m");
289 /********* in the parent process ************/
292 /* wait the ready signal (that transmit the slave pid) */
293 rc = read(mpipe[0], &children[1], sizeof children[1]);
296 ERROR("reading master pipe failed: %m");
300 assert(rc == sizeof children[1]);
301 /* start the child */
302 rc = write(spipe[1], "start", 5);
304 ERROR("writing slave pipe failed: %m");
313 /********* in the master child ************/
317 /* avoid set-gid effect */
318 setresgid(groupid, groupid, groupid);
320 /* enter the process group */
323 ERROR("setpgid failed");
327 /* enter security mode */
328 rc = secmgr_prepare_exec(desc->tag);
330 ERROR("call to secmgr_prepare_exec failed: %m");
334 /* enter the datadirectory */
335 rc = mkdir(params->datadir, 0755);
336 if (rc && errno != EEXIST) {
337 ERROR("creation of datadir %s failed: %m", params->datadir);
340 rc = chdir(params->datadir);
342 ERROR("can't enter the datadir %s: %m", params->datadir);
346 /* fork the slave child */
347 children[1] = fork();
348 if (children[1] < 0) {
349 ERROR("slave fork failed: %m");
352 if (children[1] == 0) {
353 /********* in the slave child ************/
355 rc = read(spipe[0], message, sizeof message);
357 ERROR("reading slave pipe failed: %m");
361 args = instantiate_arguments(params->slave_args, desc, params);
363 ERROR("out of memory in slave");
366 rc = execve(args[0], args, environ);
367 ERROR("failed to exec slave %s: %m", args[0]);
372 /********* still in the master child ************/
374 args = instantiate_arguments(params->master_args, desc, params);
376 ERROR("out of memory in master");
379 rc = write(mpipe[1], &children[1], sizeof children[1]);
381 ERROR("can't write master pipe: %m");
385 rc = execve(args[0], args, environ);
386 ERROR("failed to exec master %s: %m", args[0]);
392 static void afm_launch_init_group()
396 getresgid(&r, &e, &s);
404 int afm_launch(struct afm_launch_desc *desc, pid_t children[2])
406 char datadir[PATH_MAX];
409 struct launchparam params;
412 afm_launch_init_group();
414 /* what launcher ? */
416 if (desc->type != NULL && *desc->type) {
417 nkl = sizeof known_launchers / sizeof * known_launchers;
418 while (ikl < nkl && strcmp(desc->type, known_launchers[ikl].type))
421 ERROR("type %s not found!", desc->type);
428 rc = snprintf(datadir, sizeof datadir, "%s/%s", desc->home, desc->tag);
429 if (rc < 0 || rc >= sizeof datadir) {
430 ERROR("overflow for datadir");
435 /* make the secret and port */
437 params.port = mkport();
438 params.secret = secret;
439 params.datadir = datadir;
440 params.master_args = known_launchers[ikl].master_args;
441 params.slave_args = known_launchers[ikl].slave_args;
443 return params.slave_args ? launchexec2(desc, children, ¶ms) : launchexec1(desc, children, ¶ms);