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