Clear cmdline up for loaders
[platform/core/appfw/launchpad.git] / src / launchpad_lib.c
1 /*
2  * Copyright (c) 2015 - 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #define _GNU_SOURCE
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/socket.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/prctl.h>
24 #include <malloc.h>
25 #ifdef _APPFW_FEATURE_LOADER_PRIORITY
26 #include <sys/time.h>
27 #include <sys/resource.h>
28 #endif
29 #include <bundle_internal.h>
30 #include <aul.h>
31 #include <security-manager.h>
32
33 #include "launchpad_common.h"
34 #include "launchpad.h"
35 #include "preexec.h"
36
37 #ifndef API
38 #define API __attribute__ ((visibility("default")))
39 #endif
40
41 #define AUL_PR_NAME 16
42 #define LOWEST_PRIO 20
43
44 static loader_lifecycle_callback_s *__loader_callbacks;
45 static loader_adapter_s *__loader_adapter;
46 static void *__loader_user_data;
47 static int __argc;
48 static char **__argv;
49 static bundle *__bundle;
50 static int __loader_type = LAUNCHPAD_TYPE_UNSUPPORTED;
51 static int __loader_id;
52
53 static void __at_exit_to_release_bundle(void)
54 {
55         if (__bundle)
56                 bundle_free(__bundle);
57 }
58
59 static int __prepare_exec(const char *appid, const char *app_path,
60                         const char *pkg_type, int type)
61 {
62         const char *file_name = NULL;
63         char process_name[AUL_PR_NAME] = { 0, };
64         int ret;
65
66         __preexec_run(pkg_type, appid, app_path);
67
68         /* SET PRIVILEGES*/
69         SECURE_LOGD("[candidata] appid : %s / pkg_type : %s / app_path : %s",
70                 appid, pkg_type, app_path);
71         ret = security_manager_prepare_app(appid);
72         if (ret != SECURITY_MANAGER_SUCCESS) {
73                 _D("fail to set privileges - " \
74                                 "check your package's credential: %d\n", ret);
75                 return -1;
76         }
77
78         /*
79          * SET DUMPABLE - for coredump
80          * This dumpable flag should be set after
81          * calling perm_app_set_privilege().
82          */
83         prctl(PR_SET_DUMPABLE, 1);
84
85         /* SET PROCESS NAME*/
86         if (app_path == NULL) {
87                 _D("app_path should not be NULL - check menu db");
88                 return -1;
89         }
90
91         file_name = strrchr(app_path, '/');
92         if (file_name == NULL) {
93                 _D("file_name is NULL");
94                 return -1;
95         }
96
97         file_name++;
98         if (*file_name == '\0') {
99                 _D("can't locate file name to execute");
100                 return -1;
101         }
102
103         memset(process_name, '\0', AUL_PR_NAME);
104         snprintf(process_name, AUL_PR_NAME, "%s", file_name);
105         prctl(PR_SET_NAME, process_name);
106
107         return 0;
108 }
109
110 static int __default_launch_cb(bundle *kb, const char *appid,
111                 const char *app_path, const char *root_path,
112                 const char *pkgid, const char *pkg_type, int loader_type)
113 {
114         char err_str[MAX_LOCAL_BUFSZ] = { 0, };
115         int ret;
116 #ifdef _APPFW_FEATURE_PRIORITY_CHANGE
117         int res;
118         const char *high_priority = bundle_get_val(kb, AUL_K_HIGHPRIORITY);
119
120         _D("high_priority: %s", high_priority);
121         if (strncmp(high_priority, "true", 4) == 0) {
122                 res = setpriority(PRIO_PROCESS, 0, -10);
123                 if (res == -1) {
124                         SECURE_LOGE("Setting process (%d) priority " \
125                                 "to -10 failed, errno: %d (%s)",
126                                 getpid(), errno,
127                                 strerror_r(errno, err_str, sizeof(err_str)));
128                 }
129         }
130         bundle_del(kb, AUL_K_HIGHPRIORITY);
131 #endif
132
133         ret = _mount_legacy_app_path(root_path, pkgid);
134         if (ret != 0)
135                 _W("Failed to mount legacy app path(%d)", errno);
136
137         if (__prepare_exec(appid, app_path, pkg_type, loader_type) < 0) {
138                 _E("__candidate_process_prepare_exec() failed");
139                 if (access(app_path, F_OK | R_OK)) {
140                         SECURE_LOGE("access() failed for file: \"%s\", " \
141                                 "error: %d (%s)", app_path, errno,
142                                 strerror_r(errno, err_str, sizeof(err_str)));
143                 }
144                 exit(-1);
145         }
146
147         return 0;
148 }
149
150 static int __candidate_process_launchpad_main_loop(app_pkt_t *pkt,
151                 char *out_app_path, int *out_argc, char ***out_argv, int type)
152 {
153         bundle *kb;
154         appinfo_t *menu_info = NULL;
155         const char *app_path = NULL;
156         int tmp_argc = 0;
157         char **tmp_argv = NULL;
158         int ret = -1;
159         int i;
160
161         kb = bundle_decode(pkt->data, pkt->len);
162         if (!kb) {
163                 _E("bundle decode error");
164                 exit(-1);
165         }
166
167         if (__bundle != NULL)
168                 bundle_free(__bundle);
169
170         __bundle = kb;
171         atexit(__at_exit_to_release_bundle);
172
173         menu_info = _appinfo_create(kb);
174         if (menu_info == NULL) {
175                 _D("such pkg no found");
176                 exit(-1);
177         }
178
179         if (menu_info->appid == NULL) {
180                 _E("Unable to get app_id");
181                 exit(-1);
182         }
183
184         if (type < 0) {
185                 _E("Invalid launchpad type: %d", type);
186                 exit(-1);
187         }
188
189         SECURE_LOGD("app id: %s, launchpad type: %d", menu_info->appid, type);
190
191         app_path = _appinfo_get_app_path(menu_info);
192         if (app_path == NULL) {
193                 _E("app_path is NULL");
194                 exit(-1);
195         }
196
197         if (app_path[0] != '/') {
198                 _E("app_path is not absolute path");
199                 exit(-1);
200         }
201
202         _modify_bundle(kb, /*cr.pid - unused parameter*/ 0, menu_info,
203                         pkt->cmd);
204
205         if (menu_info->pkgid == NULL) {
206                 _E("unable to get pkg_id from menu_info");
207                 exit(-1);
208         }
209
210         SECURE_LOGD("pkg id: %s", menu_info->pkgid);
211
212         tmp_argv = _create_argc_argv(kb, &tmp_argc);
213
214         __default_launch_cb(kb, menu_info->appid, app_path,
215                         menu_info->root_path, menu_info->pkgid,
216                         menu_info->pkg_type, type);
217
218         if (__loader_callbacks->launch) {
219                 ret = __loader_callbacks->launch(tmp_argc, tmp_argv, app_path,
220                                 menu_info->appid, menu_info->pkgid,
221                                 menu_info->pkg_type, __loader_user_data);
222         }
223
224         /* SET ENVIROMENT*/
225         _set_env(menu_info, kb);
226
227         if (out_app_path != NULL && out_argc != NULL && out_argv != NULL) {
228                 memset(out_app_path, '\0', strlen(out_app_path));
229                 snprintf(out_app_path, LOADER_ARG_LEN, "%s", app_path);
230
231                 *out_argv = tmp_argv;
232                 *out_argc = tmp_argc;
233                 (*out_argv)[LOADER_ARG_PATH] = out_app_path;
234
235                 for (i = 0; i < *out_argc; i++) {
236                         SECURE_LOGD("input argument %d : %s##", i,
237                                         (*out_argv)[i]);
238                 }
239         } else {
240                 exit(-1);
241         }
242
243         if (menu_info != NULL)
244                 _appinfo_free(menu_info);
245
246         if (__bundle) {
247                 bundle_free(__bundle);
248                 __bundle = NULL;
249         }
250
251         return ret;
252 }
253
254 static void __receiver_cb(int fd)
255 {
256         int ret = -1;
257         int recv_ret;
258         app_pkt_t *pkt;
259
260         _D("[candidate] ECORE_FD_READ");
261         pkt = (app_pkt_t *)malloc(sizeof(char) * AUL_SOCK_MAXBUFF);
262         if (!pkt) {
263                 _D("[candidate] out of memory1");
264                 exit(-1);
265         }
266         memset(pkt, 0, AUL_SOCK_MAXBUFF);
267
268         recv_ret = recv(fd, pkt, AUL_SOCK_MAXBUFF, 0);
269         if (recv_ret == -1) {
270                 _D("[condidate] recv error!");
271                 close(fd);
272                 free(pkt);
273                 exit(-1);
274         }
275         _D("[candidate] recv_ret: %d, pkt->len: %d", recv_ret, pkt->len);
276
277         __loader_adapter->remove_fd(__loader_user_data, fd);
278         close(fd);
279         ret = __candidate_process_launchpad_main_loop(pkt,
280                         __argv[LOADER_ARG_PATH], &__argc, &__argv,
281                         __loader_type);
282         SECURE_LOGD("[candidate] real app argv[0]: %s, real app argc: %d",
283                         __argv[LOADER_ARG_PATH], __argc);
284         free(pkt);
285
286         if (ret >= 0) {
287                 __loader_adapter->loop_quit(__loader_user_data);
288                 _D("[candidate] ecore main loop quit");
289         }
290 }
291
292 static int __before_loop(int argc, char **argv)
293 {
294         int client_fd;
295         int ret = -1;
296         bundle *extra = NULL;
297 #ifdef _APPFW_FEATURE_LOADER_PRIORITY
298         char err_str[MAX_LOCAL_BUFSZ] = { 0, };
299         int res = setpriority(PRIO_PROCESS, 0, LOWEST_PRIO);
300
301         if (res == -1) {
302                 SECURE_LOGE("Setting process (%d) priority to %d failed, " \
303                                 "errno: %d (%s)", getpid(), LOWEST_PRIO, errno,
304                                 strerror_r(errno, err_str, sizeof(err_str)));
305         }
306 #endif
307         __preexec_init(argc, argv);
308
309         /* Set new session ID & new process group ID*/
310         /* In linux, child can set new session ID without check permission */
311         /* TODO : should be add to check permission in the kernel*/
312         setsid();
313
314         memset(argv[LOADER_ARG_TYPE], 0, strlen(argv[LOADER_ARG_TYPE]));
315         memset(argv[LOADER_ARG_ID], 0, strlen(argv[LOADER_ARG_ID]));
316         if (argc > 3) {
317                 extra = bundle_decode((bundle_raw *)argv[LOADER_ARG_EXTRA],
318                                 strlen(argv[LOADER_ARG_EXTRA]));
319                 memset(argv[LOADER_ARG_EXTRA], 0, strlen(argv[LOADER_ARG_EXTRA]));
320         }
321
322         if (__loader_callbacks->create) {
323                 __loader_callbacks->create(extra, __loader_type,
324                                 __loader_user_data);
325                 ret = 0;
326         }
327
328         if (extra)
329                 bundle_free(extra);
330
331         malloc_trim(0);
332 #ifdef _APPFW_FEATURE_LOADER_PRIORITY
333         res = setpriority(PRIO_PGRP, 0, 0);
334         if (res == -1) {
335                 SECURE_LOGE("Setting process (%d) priority to 0 failed, " \
336                                 "errno: %d (%s)", getpid(), errno,
337                                 strerror_r(errno, err_str, sizeof(err_str)));
338         }
339 #endif
340         client_fd = _connect_to_launchpad(__loader_type, __loader_id);
341         if (client_fd == -1) {
342                 _D("Connecting to candidate process was failed.");
343                 return -1;
344         }
345
346         __loader_adapter->add_fd(__loader_user_data, client_fd, __receiver_cb);
347
348         return ret;
349 }
350
351 static int __after_loop(void)
352 {
353         if (__loader_callbacks->terminate) {
354                 return __loader_callbacks->terminate(__argc, __argv,
355                                 __loader_user_data);
356         }
357
358         return -1;
359 }
360
361 bundle *launchpad_loader_get_bundle()
362 {
363         return __bundle;
364 }
365
366 API int launchpad_loader_main(int argc, char **argv,
367                 loader_lifecycle_callback_s *callbacks,
368                 loader_adapter_s *adapter, void *user_data)
369 {
370         if (argc < 3) {
371                 _E("too few argument.");
372                 return -1;
373         }
374
375         __loader_type = argv[LOADER_ARG_TYPE][0] - '0';
376         if (__loader_type < 0 || __loader_type >= LAUNCHPAD_TYPE_MAX) {
377                 _E("invalid argument. (type: %d)", __loader_type);
378                 return -1;
379         }
380
381         __loader_id = atoi(argv[LOADER_ARG_ID]);
382
383         if (callbacks == NULL) {
384                 _E("invalid argument. callback is null");
385                 return -1;
386         }
387
388         if (adapter == NULL) {
389                 _E("invalid argument. adapter is null");
390                 return -1;
391         }
392
393         if (adapter->loop_begin == NULL || adapter->loop_quit == NULL
394                 || adapter->add_fd == NULL || adapter->remove_fd == NULL) {
395                 _E("invalid argument. adapter callback is null");
396                 return -1;
397         }
398
399         __loader_callbacks = callbacks;
400         __loader_adapter = adapter;
401         __loader_user_data = user_data;
402         __argc = argc;
403         __argv = argv;
404
405         if (__before_loop(argc, argv) != 0)
406                 return -1;
407
408         _D("[candidate] ecore main loop begin");
409         __loader_adapter->loop_begin(__loader_user_data);
410
411         return __after_loop();
412 }
413