Fix memory leak
[platform/framework/web/wrt.git] / src / wrt-launcher / wrt-launcher.cpp
1 /*
2  * Copyright (c) 2011 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 #include <iostream>
17 #include <string>
18 #include <app.h>
19 #include <app_manager.h>
20 #include <string.h>
21 #include <getopt.h>
22 #include <stdlib.h>
23 #include <signal.h>
24 #include <unistd.h>
25 #include <pwd.h>
26 #include <sys/types.h>
27 #include <dpl/wrt-dao-ro/WrtDatabase.h>
28 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
29 #include <dpl/wrt-dao-ro/feature_dao_read_only.h>
30 #include <dpl/wrt-dao-ro/common_dao_types.h>
31 #include <dpl/wrt-dao-ro/wrt_db_types.h>
32 #include <dpl/wrt-dao-rw/global_dao.h>
33 #include <dpl/wrt-dao-ro/global_dao_read_only.h>
34 #include <dpl/wrt-dao-ro/config_parser_data.h>
35 #include <dpl/exception.h>
36
37 #define TIMEOUT_DEFAULT     10
38 #define ROOT_DEFAULT_UID 0
39 #define ROOT_DEFAULT_GID 0
40 #define WEBAPP_DEFAULT_UID  5000
41 #define WEBAPP_DEFAULT_GID  5000
42 #define LOGGING_DEFAULT_GID 6509
43 #define RETURN_ERROR -1
44
45 static const char *program;
46
47 class DBConnection
48 {
49   public:
50     void AttachDatabase()
51     {
52         WrtDB::WrtDatabase::attachToThreadRW();
53     }
54
55     void DetachDatabase()
56     {
57         WrtDB::WrtDatabase::detachFromThread();
58     }
59 };
60
61 static std::unique_ptr<DBConnection> g_dbConnection;
62
63 typedef struct
64 {
65     char* guid;           /**< the widget's id
66                            * (read from its config.xml during installation)*/
67     char* name;         /**< the widget's name
68                          * (read from its config.xml during installation)*/
69     char* version;      /**< the widget's varsion
70                          * (read from its config.xml during installation)*/
71     char* pkg_id;       /**< the widget's pkg id */
72
73     char* app_id;
74 } widget_info;
75
76 static void free_widget_info(widget_info* widget_info)
77 {
78     if (widget_info) {
79         delete[] widget_info->guid;
80         delete[] widget_info->name;
81         delete[] widget_info->version;
82         delete[] widget_info->pkg_id;
83         delete[] widget_info->app_id;
84         delete widget_info;
85     }
86 }
87
88 static char* new_strdup(const char *str)
89 {
90     size_t size = strlen(str);
91     char* ret = new char[size + 1];
92     strcpy(ret, str);
93     return ret;
94 }
95
96 static bool attachDbConnection()
97 {
98     if (NULL == g_dbConnection.get()) {
99         Try {
100             g_dbConnection.reset(new DBConnection());
101             g_dbConnection->AttachDatabase();
102         }
103         Catch(DPL::DB::SqlConnection::Exception::Base) {
104             LogDebug("Fail to connect DB");
105             return FALSE;
106         }
107     }
108     return TRUE;
109 }
110
111 static bool display_widget_info()
112 {
113     if (!attachDbConnection()) {
114         return FALSE;
115     }
116
117     WidgetDAOReadOnlyList widgetList =
118         WrtDB::WidgetDAOReadOnly::getWidgetList();
119
120     printf("%3s %32s %16s %64s %16s %24s\n",
121            "No", "Name", "Version", "GUID", "Package ID", "App ID");
122     printf("%3s %32s %16s %64s %16s %24s\n",
123            "--", "--", "----", "-------", "-----", "-----");
124
125     int number = 1;
126     FOREACH(dao, widgetList) {
127         widget_info *info = new widget_info;
128         memset(info, 0x00, sizeof(widget_info));
129
130         WrtDB::WidgetGUID guid = (*dao)->getGUID();
131         DPL::Optional<DPL::String> version = (*dao)->getVersion();
132         WrtDB::TizenAppId appid = (*dao)->getTzAppId();
133         WrtDB::TizenPkgId pkgid = (*dao)->getTizenPkgId();
134
135
136         /*get WidgetName*/
137         DPL::Optional<DPL::String> widget_name;
138         DPL::OptionalString dl = (*dao)->getDefaultlocale();
139         WrtDB::WidgetLocalizedInfo localizedInfo;
140         if (dl.IsNull()) {
141             DPL::String languageTag(L"");
142             localizedInfo = (*dao)->getLocalizedInfo(languageTag);
143         } else {
144             localizedInfo = (*dao)->getLocalizedInfo(*dl);
145         }
146
147         widget_name = localizedInfo.name;
148
149         /*end get WidgetName*/
150         if (!widget_name.IsNull()) {
151             info->name = new_strdup(DPL::ToUTF8String(*widget_name).c_str());
152         }
153         if (!version.IsNull()) {
154             info->version = new_strdup(DPL::ToUTF8String(*version).c_str());
155         } else {
156             std::string installedWidgetVersionString;
157             installedWidgetVersionString = "";
158             info->version = new_strdup(installedWidgetVersionString.c_str());
159         }
160         if (!guid.IsNull()) {
161             info->guid = new_strdup(DPL::ToUTF8String(*guid).c_str());
162         }
163
164         info->app_id = new_strdup(DPL::ToUTF8String(appid).c_str());
165         info->pkg_id = new_strdup(DPL::ToUTF8String(pkgid).c_str());
166
167         printf("%3i %32s %16s %64s %16s %24s\n",
168                number++,
169                !info->name ? "[NULL]" : info->name,
170                !info->version ? "[NULL]" : info->version,
171                !info->guid ? "[NULL]" : info->guid,
172                !info->pkg_id ? "[NULL]" : info->pkg_id,
173                !info->app_id ? "[NULL]" : info->app_id);
174
175         free_widget_info(info);
176     }
177
178     return 1;
179 }
180
181 static void print_help(FILE *stream, int /*exit_code*/)
182 {
183     fprintf(stream, "Usage : %s [ ... ]\n", program);
184     fprintf(
185         stream,
186         "   -h                        --help              Display this usage information.\n"
187         "   -l                        --list              Display installed widgets list\n"
188         "   -s [tizen application ID] --start             Launch widget with tizen application ID\n"
189         "   -k [tizen application ID] --kill              Kill widget with tizen application ID\n"
190         "   -r [tizen application ID] --is-running        Check whether widget is running by tizen application ID,\n"
191         "                                                 If widget is running, 0(zero) will be returned.\n"
192         "   -d                        --debug             Activate debug mode\n"
193         "   -t [second]               --timeout           Set timeout of response from widget in debug mode\n"
194         "   -c [1]or[0]               --compliance-mode   Set compliancemode\n"
195         "   -i [imei]                 --fake-imei         Set fakeimei\n"
196         "   -m [meid]                 --fake-meid         Set fakemeid\n"
197         "    if you emit this option, 5 seconds is set in debug mode\n"
198         );
199 }
200
201 static void sighandler(int signo, siginfo_t *si, void *data);
202
203 int main(int argc, char* argv[])
204 {
205     UNHANDLED_EXCEPTION_HANDLER_BEGIN
206     {
207         int next_opt, opt_idx = 0;
208         int timeout = TIMEOUT_DEFAULT;
209         char applicationId[256] = "";
210         char temp_arg[256] = "";
211         char pid[6] = "";
212         char op = '\0';
213         bool isDebugMode = false;
214         struct sigaction sigact;
215         bool dispHelp = false;
216         bool dispList = false;
217
218         service_h serviceHandle = NULL;
219         int ret = SERVICE_ERROR_NONE;
220
221         program = argv[0];
222
223         static struct option long_options[] = {
224             { "help", no_argument, 0, 'h' },
225             { "list", no_argument, 0, 'l' },
226             { "start", required_argument, 0, 's' },
227             { "kill", required_argument, 0, 'k' },
228             { "is-running", required_argument, 0, 'r' },
229             { "debug", no_argument, 0, 'd' },
230             { "timeout", required_argument, 0, 't' },
231             { "compliance-mode", required_argument, 0, 'c' },
232             { "fake-imei", required_argument, 0, 'i' },
233             { "fake-meid", required_argument, 0, 'm' },
234             { 0, 0, 0, 0 }
235         };
236
237         if (argv[1] == NULL) {
238             /* exit if any argument doesn't exist */
239             print_help(stdout, 0);
240             return -1;
241         }
242
243         if (ROOT_DEFAULT_UID == geteuid()) {
244             if (RETURN_ERROR == setuid(ROOT_DEFAULT_UID)) {
245                 perror("Fail to set uid");
246             }
247         }
248         if (ROOT_DEFAULT_GID == getegid()) {
249             if (RETURN_ERROR == setgid(ROOT_DEFAULT_GID)) {
250                 perror("Fail to set gid");
251             }
252         }
253
254         do {
255             next_opt = getopt_long(argc,
256                                    argv,
257                                    "hls:k:r:dt:v:c:i:m:",
258                                    long_options,
259                                    &opt_idx);
260
261             switch (next_opt) {
262             case 'h':
263                 if (!dispHelp) {
264                     print_help(stdout, 0);
265                     dispHelp = true;
266                 }
267                 break;
268
269             case 'l':
270                 if (dispList) {
271                     break;
272                 }
273                 if (!display_widget_info()) {
274                     printf("Fail to display the list of installed widgets");
275                     return -1;
276                 }
277                 dispList = true;
278                 break;
279
280             case 's':
281             case 'k':
282             case 'r':
283                 strncpy(temp_arg, optarg, strlen(optarg));
284                 op = next_opt;
285                 break;
286
287             case 't':
288                 timeout = atoi(optarg);
289                 if (timeout < 0) {
290                     timeout = TIMEOUT_DEFAULT;
291                 }
292                 break;
293
294             case 'd':
295                 // create service
296                 ret = service_create(&serviceHandle);
297                 if (SERVICE_ERROR_NONE != ret && NULL == serviceHandle) {
298                     LogError("Fail to create service");
299                     return FALSE;
300                 }
301
302                 // set debug mode
303                 ret = service_add_extra_data(serviceHandle,
304                                              "debug",
305                                              "true");
306                 if (SERVICE_ERROR_NONE != ret) {
307                     LogError("Fail to set debug mode [" << ret << "]");
308                     service_destroy(serviceHandle);
309                     return FALSE;
310                 }
311
312                 // set pid
313                 snprintf(pid, sizeof(pid), "%d", getpid());
314                 ret = service_add_extra_data(serviceHandle,
315                                              "pid",
316                                              pid);
317                 if (SERVICE_ERROR_NONE != ret) {
318                     LogError("Fail to set pid [" << ret << "]");
319                     service_destroy(serviceHandle);
320                     return FALSE;
321                 }
322                 isDebugMode = true;
323                 break;
324
325             case 'c':
326                 strncpy(temp_arg, optarg, strlen(optarg));
327                 if (!attachDbConnection()) {
328                     return FALSE;
329                 }
330                 if (!strcmp("1", temp_arg)) {
331                     WrtDB::GlobalDAO::setComplianceMode(true);
332                 } else {
333                     WrtDB::GlobalDAO::setComplianceMode(false);
334                 }
335                 break;
336             case 'i':
337                 strncpy(temp_arg, optarg, strlen(optarg));
338                 if (!attachDbConnection()) {
339                     return FALSE;
340                 }
341                 WrtDB::GlobalDAO::setComplianceFakeImei(temp_arg);
342                 break;
343             case 'm':
344                 strncpy(temp_arg, optarg, strlen(optarg));
345                 if (!attachDbConnection()) {
346                     return FALSE;
347                 }
348                 WrtDB::GlobalDAO::setComplianceFakeMeid(temp_arg);
349                 break;
350
351             case -1:
352                 break;
353
354             default:
355                 print_help(stdout, 0);
356                 break;
357             }
358         } while (next_opt != -1);
359
360         if ((op == 's') || (op == 'k') || (op == 'r')) {
361             std::string temp;
362
363             if (NULL == g_dbConnection.get()) {
364                 Try {
365                     g_dbConnection.reset(new DBConnection());
366                     g_dbConnection->AttachDatabase();
367                 }
368                 Catch(DPL::DB::SqlConnection::Exception::Base) {
369                     LogDebug("Fail to connect DB");
370                     return FALSE;
371                 }
372             }
373             DPL::OptionalString normal_str = DPL::FromUTF8String(temp_arg);
374             WrtDB::NormalizeAndTrimSpaceString(normal_str);
375             std::string normal_arg = DPL::ToUTF8String(*normal_str);
376
377             WidgetDAOReadOnlyList widgetList =
378                 WrtDB::WidgetDAOReadOnly::getWidgetList();
379             FOREACH(dao, widgetList) {
380                 WrtDB::TizenAppId tizenAppId = (*dao)->getTzAppId();
381                 if (!strcmp(DPL::ToUTF8String(tizenAppId).c_str(),
382                             normal_arg.c_str()))
383                 {
384                     temp = DPL::ToUTF8String(tizenAppId);
385                     break;
386                 }
387             }
388             if (!temp.empty()) {
389                 strncpy(applicationId, temp.c_str(), strlen(temp.c_str()));
390             } else {
391                 printf("result: %s\n", "failed");
392                 return -1;
393             }
394         }
395
396         if (op == 's') {
397             /* check if this is request for debug mode, or not */
398             if (true == isDebugMode) {
399                 /* wait for return from the widget */
400                 sigemptyset(&sigact.sa_mask);
401                 sigact.sa_flags = SA_SIGINFO;
402                 sigact.sa_restorer = NULL;
403                 sigact.sa_sigaction = sighandler;
404
405                 if (sigaction(SIGRTMIN, &sigact, 0) == 1) {
406                     printf("result: %s\n", "failed");
407                     return -1;
408                 }
409             } else {
410                 // case of "-d" option, service_create is already allocated
411                 // create service
412                 ret = service_create(&serviceHandle);
413                 if (SERVICE_ERROR_NONE != ret && NULL == serviceHandle) {
414                     printf("result: %s\n", "failed");
415                     return -1;
416                 }
417             }
418
419             if (strlen(applicationId) > 0) {
420                 // do setuid to '5000' uid to communicate
421                 //with webapp using RT signal.
422                 gid_t group_list[1];
423                 group_list[0] = LOGGING_DEFAULT_GID;
424
425                 if (setgroups(sizeof(group_list), group_list) < 0) {
426                     printf("result: %s\n", "failed");
427                     return -1;
428                 }
429
430                 if (setreuid(WEBAPP_DEFAULT_UID, WEBAPP_DEFAULT_GID) < 0) {
431                     printf("result: %s\n", "failed");
432                     return -1;
433                 }
434
435                 // set package
436                 ret = service_set_package(serviceHandle, applicationId);
437                 if (SERVICE_ERROR_NONE != ret) {
438                     printf("result: %s\n", "failed");
439                     service_destroy(serviceHandle);
440                     return -1;
441                 }
442
443                 //launch service
444                 ret = service_send_launch_request(serviceHandle, NULL, NULL);
445                 if (SERVICE_ERROR_NONE != ret) {
446                     printf("result: %s\n", "failed");
447                     service_destroy(serviceHandle);
448                     return -1;
449                 }
450
451                 service_destroy(serviceHandle);
452             } else {
453                 printf("result: %s\n", "failed");
454                 return -1;
455             }
456
457             if (true == isDebugMode) {
458                 // wait RTS signal from widget by 5 second
459                 sleep(timeout);
460                 printf("result: %s\n", "failed");
461                 return -1;
462             }
463             // This text should be showed for IDE
464             printf("result: %s\n", "launched");
465             return 0;
466         } else if (op == 'k') {
467             bool isRunning = false;
468
469             //checks whether the application is running
470             ret = app_manager_is_running(applicationId, &isRunning);
471             if (APP_MANAGER_ERROR_NONE != ret) {
472                 printf("result: %s\n", "failed");
473                 return -1;
474             }
475
476             if (true == isRunning) {
477                 // get app_context for running application
478                 // app_context must be released with app_context_destroy
479                 app_context_h appCtx = NULL;
480                 ret = app_manager_get_app_context(applicationId, &appCtx);
481                 if (APP_MANAGER_ERROR_NONE != ret) {
482                     printf("result: %s\n", "failed");
483                     return -1;
484                 }
485
486                 // terminate app_context_h
487                 ret = app_manager_terminate_app(appCtx);
488                 if (APP_MANAGER_ERROR_NONE != ret) {
489                     printf("result: %s\n", "failed");
490                     app_context_destroy(appCtx);
491                     return -1;
492                 } else {
493                     printf("result: %s\n", "killed");
494                     app_context_destroy(appCtx);
495                     return 0;
496                 }
497             } else {
498                 printf("result: %s\n", "App isn't running");
499                 return 0;
500             }
501         } else if (op == 'r') {
502             bool isRunning = false;
503             ret = app_manager_is_running(applicationId, &isRunning);
504
505             if (APP_MANAGER_ERROR_NONE != ret) {
506                 printf("result: %s\n", "failed");
507                 return -1;
508             }
509
510             if (true == isRunning) {
511                 printf("result: %s\n", "running");
512                 return 0;
513             } else {
514                 printf("result: %s\n", "not running");
515                 return -1;
516             }
517         }
518
519         return 0 ;
520     }
521     UNHANDLED_EXCEPTION_HANDLER_END
522 }
523
524 static void sighandler(int signo, siginfo_t *si, void* /*data*/)
525 {
526     /* check if this signal is type of RTS */
527     if (si->si_code == SI_QUEUE) {
528         //int port;
529         //printf("RTS pid : %d\n", si->si_pid);
530         //port = (int) si->si_value.sival_ptr;
531         //printf("RTS debug port : %d\n", port);
532         // This sival_int is wrt's status (like WRT_SUCCESS..)
533         // enum WRT_SUCCESS is 0
534         if (si->si_value.sival_int > 0) {
535             printf("port: %d\n", (int)si->si_value.sival_int);
536             printf("result: %s\n", "launched");
537         } else {
538             printf("result: %s\n", "failed");
539         }
540     } else {
541         printf("Not RT signal : %d\n", signo);
542     }
543     exit(0);
544 }