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