Support legacy image for backward-compatibility
[platform/core/appfw/app2sd.git] / test / src / test_app2ext.c
1 /*
2  * test_app2ext
3  *
4  * Copyright (c) 2016 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  */
19
20 #include <stdio.h>
21 #include <assert.h>
22 #include <stdlib.h>
23 #include <unistd.h>
24 #include <malloc.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <sys/wait.h>
29 #include <sys/types.h>
30 #include <getopt.h>
31 #include <unzip.h>
32 #include <storage-internal.h>
33 #include <tzplatform_config.h>
34
35 #include "app2ext_interface.h"
36
37 #define SUCCESS 0
38 #define FAIL 1
39 #define CMD_LEN 256
40 #define TEST_PKGNAME "org.example.basicuiapplication"
41 #define TEST_PKGNAME_PATH "/tmp/org.example.basicuiapplication-1.0.0-arm.tpk"
42 #define OWNER_ROOT 0
43 #define GLOBAL_USER tzplatform_getuid(TZ_SYS_GLOBALAPP_USER)
44
45 app2ext_handle *handle = NULL;
46
47 char pkg_ro_content_rpm[3][5] = { "bin", "res", "lib" };
48
49 #define COUNT_OF_ERROR_LIST APP2EXT_ERROR_ENUM_MAX
50 char error_list[COUNT_OF_ERROR_LIST][100] = {
51         "SUCCESS",
52         "APP2EXT_ERROR_UNKNOWN",
53         "APP2EXT_ERROR_INVALID_ARGUMENTS",
54         "APP2EXT_ERROR_MOVE",
55         "APP2EXT_ERROR_PRE_UNINSTALL",
56         "APP2EXT_ERROR_MMC_STATUS",
57         "APP2EXT_ERROR_DB_INITIALIZE",
58         "APP2EXT_ERROR_SQLITE_REGISTRY",
59         "APP2EXT_ERROR_PASSWD_GENERATION",
60         "APP2EXT_ERROR_MMC_INFORMATION",
61         "APP2EXT_ERROR_MMC_INSUFFICIENT_MEMORY",
62         "APP2EXT_ERROR_DELETE_DIRECTORY",
63         "APP2EXT_ERROR_CREATE_SYMLINK",
64         "APP2EXT_ERROR_CREATE_DIRECTORY",
65         "APP2EXT_ERROR_DELETE_LINK_FILE",
66         "APP2EXT_ERROR_PKG_EXISTS",
67         "APP2EXT_ERROR_ACCESS_FILE",
68         "APP2EXT_ERROR_OPEN_DIR",
69         "APP2EXT_ERROR_ALREADY_FILE_PRESENT",
70         "APP2EXT_ERROR_FILE_ABSENT",
71         "APP2EXT_ERROR_STRCMP_FAILED",
72         "APP2EXT_ERROR_INVALID_PACKAGE",
73         "APP2EXT_ERROR_CREATE_DIR_ENTRY",
74         "APP2EXT_ERROR_COPY_DIRECTORY",
75         "APP2EXT_ERROR_INVALID_CASE",
76         "APP2EXT_ERROR_SYMLINK_ALREADY_EXISTS",
77         "APP2EXT_ERROR_APPEND_HASH_TO_FILE",
78         "APP2EXT_ERROR_CREATE_DEVICE",
79         "APP2EXT_ERROR_DO_LOSETUP",
80         "APP2EXT_ERROR_CREATE_FS",
81         "APP2EXT_ERROR_MOUNT_PATH",
82         "APP2EXT_ERROR_CLEANUP",
83         "APP2EXT_ERROR_MOUNT",
84         "APP2EXT_ERROR_REMOUNT",
85         "APP2EXT_ERROR_PIPE_CREATION",
86         "APP2EXT_ERROR_LOOPBACK_DEVICE_UNAVAILABLE",
87         "APP2EXT_ERROR_VCONF_REGISTRY",
88         "APP2EXT_ERROR_FIND_ASSOCIATED_DEVICE_NODE",
89         "APP2EXT_ERROR_UNMOUNT",
90         "APP2EXT_ERROR_DELETE_LOOPBACK_DEVICE",
91         "APP2EXT_ERROR_DETACH_LOOPBACK_DEVICE",
92         "APP2EXT_ERROR_ALREADY_MOUNTED",
93         "APP2EXT_ERROR_PLUGIN_INIT_FAILED",
94         "APP2EXT_ERROR_PLUGIN_DEINIT_FAILED",
95         "APP2EXT_ERROR_DBUS_FAILED",
96         "APP2EXT_ERROR_MEMORY_ALLOC_FAILED",
97         "APP2EXT_ERROR_OPERATION_NOT_PERMITTED",
98         "APP2EXT_ERROR_SAME_LOOPBACK_DEVICE_EXISTS",
99         "APP2EXT_ERROR_PKGMGR_ERROR",
100         "APP2EXT_ERROR_NOENTRY",
101 #ifdef TIZEN_FEATURE_APP2SD_DMCRYPT_ENCRYPTION
102         "APP2EXT_ERROR_SETUP_DMCRYPT_DEVICE",
103         "APP2EXT_ERROR_OPEN_DMCRYPT_DEVICE",
104         "APP2EXT_ERROR_CLOSE_DMCRYPT_DEVICE",
105         "APP2EXT_ERROR_FIND_ASSOCIATED_DMCRYPT_DEVICE_NODE",
106         "APP2EXT_ERROR_DMCRYPT_DEVICE_UNAVAILABLE",
107 #endif
108 };
109
110 static void usage(void)
111 {
112         printf("\n");
113         printf("*************************************************\n");
114         printf("App2sd test usage:\n");
115         printf("Pre-condition: /tmp/org.example.basicuiapplication-1.0.0-arm.tpk\n");
116         printf("All tests assume the target uid as default user.\n");
117         printf("\n");
118         printf("<INSTALL>\n");
119         printf("1.#test_app2ext --pre-install\n");
120         printf("2.#pkgcmd -it tpk {pkg-path}\n");
121         printf("3.#test_app2ext --post-install\n");
122         printf("------------------------------------------------\n");
123         printf("\n");
124         printf("<UPGRADE>\n");
125         printf("1.#test_app2ext --pre-upgrade\n");
126         printf("2.#pkgcmd -it tpk {pkg-path}\n");
127         printf("3.#test_app2ext --post-upgrade\n");
128         printf("------------------------------------------------\n");
129         printf("\n");
130         printf("<INSTALL>\n");
131         printf("1.#test_app2ext --pre-uninstall\n");
132         printf("2.#pkgcmd -un {pkg-id}\n");
133         printf("3.#test_app2ext --post-uninstall\n");
134         printf("------------------------------------------------\n");
135         printf("\n");
136         printf("<MOVE PKG TEST>\n");
137         printf("#test_app2ext --move-to-ext\n");
138         printf("#test_app2ext --move-to-int\n");
139         printf("------------------------------------------------\n");
140         printf("\n");
141         printf("<ENABLE(mount)/DISABLE(umount) TEST W/ Installed PKG>\n");
142         printf("#test_app2ext --enable\n");
143         printf("#test_app2ext --disable\n");
144         printf("#test_app2ext --enable-full\n");
145         printf("#test_app2ext --disable-full\n");
146         printf("------------------------------------------------\n");
147         printf("\n");
148         printf("<MIGRATION TRIGGER TEST>\n");
149         printf("Pre-condition: install test package and copy legacy image to app2sd.\n");
150         printf("#test_app2ext --migrate-all\n");
151         printf("------------------------------------------------\n");
152         printf("**************************************************\n");
153         printf("\n");
154 }
155
156 #define OPTVAL_PRE_INSTALL              1000
157 #define OPTVAL_POST_INSTALL             1001
158 #define OPTVAL_PRE_UNINSTALL            1002
159 #define OPTVAL_POST_UNINSTALL           1003
160 #define OPTVAL_PRE_UPGRADE              1004
161 #define OPTVAL_POST_UPGRADE             1005
162 #define OPTVAL_MOVE_TO_EXTERNAL         1006
163 #define OPTVAL_MOVE_TO_INTERNAL         1007
164 #define OPTVAL_ENABLE_APP               1008
165 #define OPTVAL_DISABLE_APP              1009
166 #define OPTVAL_ENABLE_FULL              1010
167 #define OPTVAL_DISABLE_FULL             1011
168 #define OPTVAL_MIGRATE_ALL              1012
169 #define OPTVAL_USAGE                    1013
170
171 /* Supported options */
172 const struct option long_opts[] = {
173         { "pre-install", 0, NULL, OPTVAL_PRE_INSTALL },
174         { "post-install", 0, NULL, OPTVAL_POST_INSTALL },
175         { "pre-uninstall", 0, NULL, OPTVAL_PRE_UNINSTALL },
176         { "post-uninstall", 0, NULL, OPTVAL_POST_UNINSTALL },
177         { "pre-upgrade", 0, NULL, OPTVAL_PRE_UPGRADE },
178         { "post-upgrade", 0, NULL, OPTVAL_POST_UPGRADE },
179         { "move-to-ext", 0, NULL, OPTVAL_MOVE_TO_EXTERNAL },
180         { "move-to-int", 0, NULL, OPTVAL_MOVE_TO_INTERNAL },
181         { "enable", 0, NULL, OPTVAL_ENABLE_APP },
182         { "disable", 0, NULL, OPTVAL_DISABLE_APP },
183         { "enable-full", 0, NULL, OPTVAL_ENABLE_FULL },
184         { "disable-full", 0, NULL, OPTVAL_DISABLE_FULL },
185         { "migrate-all", 0, NULL, OPTVAL_MIGRATE_ALL },
186         { "help", 0, NULL, OPTVAL_USAGE },
187         { "usage", 0, NULL, OPTVAL_USAGE },
188         { 0, 0, 0, 0 }  /* sentinel */
189 };
190
191 void clear_dir_list(GList *dir_list)
192 {
193         GList *list = NULL;
194         app2ext_dir_details *dir_detail = NULL;
195
196         if (dir_list) {
197                 list = g_list_first(dir_list);
198                 while (list) {
199                         dir_detail = (app2ext_dir_details *)list->data;
200                         if (dir_detail && dir_detail->name)
201                                 free(dir_detail->name);
202
203                         list = g_list_next(list);
204                 }
205                 g_list_free(dir_list);
206         }
207 }
208
209 GList *populate_dir_details()
210 {
211         GList *dir_list = NULL;
212         GList *list = NULL;
213         app2ext_dir_details *dir_detail = NULL;
214         int i;
215
216         for (i = 0; i < 3; i++) {
217                 dir_detail = (app2ext_dir_details *)calloc(1, sizeof(app2ext_dir_details));
218                 if (dir_detail == NULL) {
219                         printf("memory allocation failed\n");
220                         goto FINISH_OFF;
221                 }
222
223                 dir_detail->name = (char *)calloc(1, sizeof(char) * (strlen(pkg_ro_content_rpm[i]) + 2));
224                 if (dir_detail->name == NULL) {
225                         printf("memory allocation failed\n");
226                         free(dir_detail);
227                         goto FINISH_OFF;
228                 }
229                 snprintf(dir_detail->name, (strlen(pkg_ro_content_rpm[i]) + 1), "%s", pkg_ro_content_rpm[i]);
230                 dir_detail->type = APP2EXT_DIR_RO;
231                 dir_list = g_list_append(dir_list, dir_detail);
232         }
233
234         if (dir_list) {
235                 list = g_list_first(dir_list);
236                 while (list) {
237                         dir_detail = (app2ext_dir_details *)list->data;
238                         list = g_list_next(list);
239                 }
240         }
241
242         return dir_list;
243
244 FINISH_OFF:
245
246         clear_dir_list(dir_list);
247
248         return NULL;
249 }
250
251 static int get_unzip_size(const char *item, unsigned long long *size)
252 {
253         int ret = 0;
254         unzFile uzf = NULL;
255         char *filename = NULL;
256         unz_file_info fileInfo = { 0 };
257
258         if (!item || !size) {
259                 printf("get size : invalid argument\n");
260                 return -1;
261         }
262         uzf = unzOpen64(item);
263         if (uzf == NULL) {
264                 printf("get size : failed to open item : [%s]\n", item);
265                 *size = 0;
266                 return -1;
267         } else {
268                 ret = unzGoToFirstFile(uzf);
269                 if (ret != UNZ_OK) {
270                         printf("get size : error get first zip file\n");
271                         unzClose(uzf);
272                         *size = 0;
273                         return -1;
274                 } else {
275                         do {
276                                 ret = unzOpenCurrentFile(uzf);
277                                 if (ret != UNZ_OK) {
278                                         printf("get size : error unzOpenCurrentFile\n");
279                                         unzClose(uzf);
280                                         *size = 0;
281                                         return -1;
282                                 }
283
284                                 filename = (char *)calloc(1, 4096);
285                                 ret = unzGetCurrentFileInfo(uzf, &fileInfo, filename, (4096 - 1), NULL, 0, NULL, 0);
286                                 *size = (unsigned long long)fileInfo.uncompressed_size + *size;
287                                 if (ret != UNZ_OK) {
288                                         printf("get size : error get current file info\n");
289                                         unzCloseCurrentFile(uzf);
290                                         *size = 0;
291                                         free(filename);
292                                         filename = NULL;
293                                         break;
294                                 }
295
296                                 free(filename);
297                                 filename = NULL;
298                         } while (unzGoToNextFile(uzf) == UNZ_OK);
299                 }
300         }
301         unzClose(uzf);
302
303         return 0;
304 }
305
306 static void print_error_code(const char *func_name, int ret)
307 {
308         if (ret < 0 || ret > COUNT_OF_ERROR_LIST - 1)
309                 printf("%s failed : unknown error(%d)\n", func_name, ret);
310         else
311                 printf("%s return(%s)\n", func_name, error_list[ret]);
312 }
313
314 static int pre_app_install()
315 {
316         GList *dir_list = NULL;
317         int ret = -1;
318         unsigned long long size_byte = 0;
319         int size_mega = 0;
320
321         printf("pre_app_install for [%s]\n", TEST_PKGNAME_PATH);
322
323         dir_list = populate_dir_details();
324         if (dir_list == NULL) {
325                 printf("error in populating the directory list\n");
326                 return -1;
327         }
328
329         /* size : in MB */
330         ret = get_unzip_size(TEST_PKGNAME_PATH, &size_byte);
331         if (ret < 0 || size_byte == 0)
332                 printf("wrong pkg size, ret(%d), size_byte(%llu)\n", ret, size_byte);
333
334         size_mega = size_byte / (1024 * 1024) + 1;
335         printf("get pkg size : (%d)MB\n", size_mega);
336
337         ret = handle->interface.client_pre_install(TEST_PKGNAME,
338                 dir_list, size_mega);
339         print_error_code(__func__, ret);
340
341         clear_dir_list(dir_list);
342
343         return ret;
344 }
345
346 static int post_app_install()
347 {
348         int ret = -1;
349
350         ret = handle->interface.client_post_install(TEST_PKGNAME,
351                 APP2EXT_STATUS_SUCCESS);
352         print_error_code(__func__, ret);
353
354         return ret;
355 }
356
357 static int app_enable()
358 {
359         int ret = -1;
360
361         ret = handle->interface.client_enable(TEST_PKGNAME);
362         print_error_code(__func__, ret);
363
364         return ret;
365 }
366
367 static int app_disable()
368 {
369         int ret = -1;
370
371         ret = handle->interface.client_disable(TEST_PKGNAME);
372         print_error_code(__func__, ret);
373
374         return ret;
375 }
376
377 static int fullpkg_enable()
378 {
379         int ret = -1;
380
381         ret = handle->interface.client_enable_full_pkg();
382         print_error_code(__func__, ret);
383
384         return ret;
385 }
386
387 static int fullpkg_disable()
388 {
389         int ret = -1;
390
391         ret = handle->interface.client_disable_full_pkg();
392         print_error_code(__func__, ret);
393
394         return ret;
395 }
396
397 static int migrate_all()
398 {
399         int ret = -1;
400
401         ret = handle->interface.client_migrate_legacy_all();
402         print_error_code(__func__, ret);
403
404         return ret;
405 }
406
407 static int pre_app_uninstall()
408 {
409         int ret = -1;
410
411         printf("pre_app_uninstall for [%s]\n", TEST_PKGNAME);
412
413         ret = handle->interface.client_pre_uninstall(TEST_PKGNAME);
414         print_error_code(__func__, ret);
415
416         return ret;
417 }
418
419 static int post_app_uninstall()
420 {
421         int ret = -1;
422
423         ret = handle->interface.client_post_uninstall(TEST_PKGNAME);
424         print_error_code(__func__, ret);
425
426         return ret;
427 }
428
429 static int pre_app_upgrade()
430 {
431         GList *dir_list = NULL;
432         int ret = -1;
433         unsigned long long size_byte = 0;
434         int size_mega = 0;
435
436         printf("pre_app_upgrade for [%s]\n", TEST_PKGNAME);
437
438         dir_list = populate_dir_details();
439         if (dir_list == NULL) {
440                 printf("Error in populating the directory list\n");
441                 return -1;
442         }
443
444         /* size : in MB */
445         ret = get_unzip_size(TEST_PKGNAME_PATH, &size_byte);
446         if (ret < 0 || size_byte == 0)
447                 printf("wrong pkg size, ret(%d), size_byte(%llu)\n", ret, size_byte);
448
449         size_mega = size_byte / (1024 * 1024) + 1;
450         printf("get pkg size : (%d)MB\n", size_mega);
451
452         ret = handle->interface.client_pre_upgrade(TEST_PKGNAME, dir_list,
453                 size_mega);
454         print_error_code(__func__, ret);
455
456         clear_dir_list(dir_list);
457
458         return ret;
459 }
460
461 static int post_app_upgrade()
462 {
463         int ret = -1;
464
465         ret = handle->interface.client_post_upgrade(TEST_PKGNAME,
466                 APP2EXT_STATUS_SUCCESS);
467         print_error_code(__func__, ret);
468
469         return ret;
470 }
471
472 static int app_move_to_external()
473 {
474         GList *dir_list = NULL;
475         int ret = -1;
476
477         printf("app_move_to_external  %s\n", TEST_PKGNAME);
478
479         dir_list = populate_dir_details();
480         if (dir_list == NULL) {
481                 printf("Error in populating the directory list\n");
482                 return -1;
483         }
484
485         printf("pkg %s will be moved to sd card\n", TEST_PKGNAME);
486         ret = handle->interface.client_pre_move(TEST_PKGNAME,
487                 dir_list, APP2EXT_MOVE_TO_EXT);
488         print_error_code(__func__, ret);
489         ret = handle->interface.client_post_move(TEST_PKGNAME,
490                 APP2EXT_MOVE_TO_EXT);
491         print_error_code(__func__, ret);
492
493         clear_dir_list(dir_list);
494
495         return ret;
496 }
497
498 static int app_move_to_internal()
499 {
500         GList *dir_list = NULL;
501         int ret = -1;
502
503         printf("app_move_to_internal  %s\n", TEST_PKGNAME);
504
505         dir_list = populate_dir_details();
506         if (dir_list == NULL) {
507                 printf("Error in populating the directory list\n");
508                 return -1;
509         }
510
511         printf("pkg %s will be moved to internal memory\n", TEST_PKGNAME);
512         ret = handle->interface.client_pre_move(TEST_PKGNAME,
513                 dir_list, APP2EXT_MOVE_TO_PHONE);
514         print_error_code(__func__, ret);
515         ret = handle->interface.client_post_move(TEST_PKGNAME,
516                 APP2EXT_MOVE_TO_PHONE);
517         print_error_code(__func__, ret);
518
519         clear_dir_list(dir_list);
520
521         return ret;
522 }
523
524 int main(int argc, char **argv)
525 {
526         int ret = 0;
527         int opt_idx = 0;
528         int c;
529         int storage_id = 0;
530         char *sd_mount_path = NULL;
531         uid_t uid = getuid();
532
533         /* check user */
534         if (uid != OWNER_ROOT) {
535                 printf("only root user allowed\n");
536                 return 0;
537         }
538
539         /* check sdcard info */
540         ret = storage_get_primary_sdcard(&storage_id, &sd_mount_path);
541         if (ret != STORAGE_ERROR_NONE) {
542                 printf("failed to get primary sdcard (%d)\n", ret);
543                 if (sd_mount_path)
544                         free(sd_mount_path);
545                 return -1;
546         }
547         if (sd_mount_path) {
548                 printf("primary sdcard: id(%d), mount_path(%s)\n",
549                 storage_id, sd_mount_path);
550                 free(sd_mount_path);
551         } else {
552                 printf("there is no primary sdcard\n");
553         }
554
555         handle = app2ext_init(APP2EXT_SD_CARD);
556         if (handle == NULL) {
557                 ret = APP2EXT_ERROR_PLUGIN_INIT_FAILED;
558                 printf("app2ext_init failed (%s)\n", error_list[ret]);
559                 return -1;
560         }
561
562         /* Parse argv */
563         optind = 1;  /* Initialize optind to clear prev. index */
564         while (1) {
565                 c = getopt_long(argc, argv, "", long_opts, &opt_idx);
566                 if (-1 == c) {
567                         usage();
568                         break;  /* Parse is end */
569                 }
570                 switch (c) {
571                 case OPTVAL_PRE_INSTALL:
572                         pre_app_install();
573                         break;
574                 case OPTVAL_POST_INSTALL:
575                         post_app_install();
576                         break;
577                 case OPTVAL_PRE_UNINSTALL:
578                         pre_app_uninstall();
579                         break;
580                 case OPTVAL_POST_UNINSTALL:
581                         post_app_uninstall();
582                         break;
583                 case OPTVAL_PRE_UPGRADE:
584                         pre_app_upgrade();
585                         break;
586                 case OPTVAL_POST_UPGRADE:
587                         post_app_upgrade();
588                         break;
589                 case OPTVAL_MOVE_TO_EXTERNAL:
590                         app_move_to_external();
591                         break;
592                 case OPTVAL_MOVE_TO_INTERNAL:
593                         app_move_to_internal();
594                         break;
595                 case OPTVAL_ENABLE_APP:
596                         app_enable();
597                         break;
598                 case OPTVAL_DISABLE_APP:
599                         app_disable();
600                         break;
601                 case OPTVAL_ENABLE_FULL:
602                         fullpkg_enable();
603                         break;
604                 case OPTVAL_DISABLE_FULL:
605                         fullpkg_disable();
606                         break;
607                 case OPTVAL_MIGRATE_ALL:
608                         migrate_all();
609                         break;
610                 case OPTVAL_USAGE:
611                 default:
612                         usage();
613                         break;
614                 }
615
616                 break;
617         }
618
619         app2ext_deinit(handle);
620
621         return 0;
622 }