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