e5026cd08c85e6e7580d2496e33ecffc8c5bc781
[platform/framework/native/installer.git] / src / Manager / CompatibilityManager.cpp
1 //
2 // Open Service Platform
3 // Copyright (c) 2012 Samsung Electronics Co., Ltd.
4 //
5 // Licensed under the Apache License, Version 2.0 (the License);
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
8 //
9 //     http://www.apache.org/licenses/LICENSE-2.0
10 //
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
16 //
17 /**
18  * @file        CompatibilityManager.cpp
19  * @brief       This is the implementation file for %CompatibilityManager class.
20  */
21
22 #include <sys/stat.h>
23 #include <sys/mount.h>
24 #include <dirent.h>
25 #include <errno.h>
26 #include <unique_ptr.h>
27
28 #include <FIoFile.h>
29 #include <FIoDirectory.h>
30 #include <FBase_StringConverter.h>
31 #include <FSys_EnvironmentImpl.h>
32
33 #include "InstallerDefs.h"
34 #include "CompatibilityManager.h"
35 #include "SmackManager.h"
36
37 using namespace Tizen::App;
38 using namespace Tizen::Base;
39 using namespace Tizen::Io;
40 using namespace Tizen::System;
41
42 struct _OspDir
43 {
44         char path[PATH_MAX];
45         mode_t mode;
46         bool appPrivilege;
47 };
48
49 struct _LinkDir
50 {
51         char srcPath[PATH_MAX];
52         char destPath[PATH_MAX];
53 };
54
55 struct _PathInfo
56 {
57     char destPath[PATH_MAX];
58 };
59
60
61 CompatibilityManager::CompatibilityManager(void)
62 {
63 }
64
65 CompatibilityManager::~CompatibilityManager(void)
66 {
67 }
68
69 bool
70 CompatibilityManager::PrepareDataCaging(const String& rootPath, const PackageId& packageId)
71 {
72         bool res = true;
73         int result = 0;
74         char* pCwd = null;
75
76         std::unique_ptr<char[]> pRootPath(_StringConverter::CopyToCharArrayN(rootPath));
77         TryCatch(pRootPath != null, res = false, "The memory is insufficient.");
78
79         res = CleanDirectories(rootPath, packageId);
80         TryCatch(res == true, , "CleanDirectories(%ls, %ls) failed.", rootPath.GetPointer(), packageId.GetPointer());
81
82         pCwd = get_current_dir_name();
83         TryCatch(pCwd != null, res = false, "get_current_dir_name() failed. [errno = %d(%s)]", errno, strerror(errno));
84
85         umask(0000);
86
87         result = chdir(pRootPath.get());
88         TryCatch(result == 0, res = false, "chdir(%s) failed. [errno = %d(%s)]", pRootPath.get(), errno, strerror(errno));
89
90         res = CreateOspInternalDirectories(rootPath, packageId);
91         TryCatch(res == true, , "CreateOspInternalDirectories(%ls, %ls) failed.", rootPath.GetPointer(), packageId.GetPointer());
92
93         res = CreateSlpDirectories();
94         TryCatch(res == true, , "CreateSlpDirectories() failed.");
95
96         res = CreateSymbolicLink();
97         TryCatch(res == true, , "CreateSymbolicLink() failed.");
98
99         result = chdir(pCwd);
100         TryCatch(result == 0, res = false, "chdir(%s) failed. [errno = %d(%s)]", pCwd, errno, strerror(errno));
101
102 CATCH:
103         if (pCwd)
104         {
105                 free(pCwd);
106         }
107
108         umask(0022);
109
110         AppLog("[Tizen::Io] result  = [%s]", res?"true":"false");
111
112         return res;
113 }
114
115 bool
116 CompatibilityManager::FinalizeDataCaging(const String& rootPath)
117 {
118         int res = 0;
119         unsigned int i = 0;
120
121         static const struct _PathInfo mountPath[] =
122         {
123                 { "./csa" },
124                 { "./dev/pts" },
125                 { "./dev/shm" },
126                 { "./dev" },
127                 { "./etc" },
128                 { "./lib" },
129                 { "./media" },
130                 { "./mnt" },
131                 { "./opt/usr" },
132                 { "./opt/var/kdb/db" },
133                 { "./opt/storage/sdcard" },
134                 { "./opt" },
135                 { "./proc" },
136                 { "./sbin" },
137                 { "./smack" },
138                 { "./srv" },
139                 { "./sys/kernel/debug" },
140                 { "./sys" },
141                 { "./tmp" },
142                 { "./usr" },
143                 { "./var/run" },
144                 { "./var" },
145                 { "./data/Share" },
146                 { "./data/Share2" },
147                 { "./Share" },
148                 { "./Share2" },
149                 { "./Media" },
150                 { "./Storagecard/Media" },
151                 { "./ShareExt" },
152                 { "./Share2Ext" },
153                 { "./HomeExt/Share" },
154                 { "./HomeExt/Share2" },
155                 { "./HomeExt" }
156         };
157
158         std::unique_ptr<char[]> pAppRootPath(_StringConverter::CopyToCharArrayN(rootPath));
159         TryReturn(pAppRootPath, false, "The memory is insufficient.");
160
161         res = chdir(pAppRootPath.get());
162         TryReturn(res == 0, false, "chdir() failed. (%d, %s), path = [%ls]", errno, strerror(errno), rootPath.GetPointer());
163
164         for (i = 0; i < sizeof(mountPath) / sizeof(struct _PathInfo); ++i)
165         {
166                 res = umount2(mountPath[i].destPath, MNT_DETACH);
167                 TryReturn((res == 0) || (errno == EINVAL) || (errno == ENOENT), false, "umount2() failed. (%d, %s), path = [%s]", errno, strerror(errno), mountPath[i].destPath);
168         }
169
170         char* pPackageId = strrchr(pAppRootPath.get(), '/');
171         char mountFlag[PATH_MAX] = {0, };
172
173         sprintf(mountFlag, "/tmp/osp-compat/mount/internal/%s", ++pPackageId);
174         res = unlink(mountFlag);
175         if ((res == -1) && (errno != ENOENT))
176         {
177                 AppLog("unlink(%s) failed, errno: %d (%s)", mountFlag, errno, strerror(errno));
178                 return false;
179         }
180
181         memset(mountFlag, 0, PATH_MAX);
182         sprintf(mountFlag, "/tmp/osp-compat/mount/external/%s", pPackageId);
183         res = unlink(mountFlag);
184         if ((res == -1) && (errno != ENOENT))
185         {
186                 AppLog("unlink(%s) failed, errno: %d (%s)", mountFlag, errno, strerror(errno));
187                 return false;
188         }
189
190         AppLog("[Tizen::Io] FinalizeDataCaging() succeeded, rootPath: %ls", rootPath.GetPointer());
191         return true;
192 }
193
194 bool
195 CompatibilityManager::CleanDirectories(const String& rootPath, const PackageId& packageId)
196 {
197         int ret = 0;
198         char removeCmd[PATH_MAX] = {0, };
199
200         String ospSharePkgIdPath = _EnvironmentImpl::GetOspCompatSharedPath();
201         ospSharePkgIdPath.Append(L"share/");
202         ospSharePkgIdPath.Append(packageId);
203
204         String ospShare2PkgIdPath = _EnvironmentImpl::GetOspCompatSharedPath();
205         ospShare2PkgIdPath.Append(L"share2/");
206         ospShare2PkgIdPath.Append(packageId);
207
208         sprintf(removeCmd, "rm -rf %ls", ospSharePkgIdPath.GetPointer());
209         AppLog("removeCmd  = [%s]", removeCmd);
210
211         ret = system(removeCmd);
212         TryReturn(ret != -1, false, "system(%s) failed.", removeCmd);
213
214         memset(removeCmd, 0, PATH_MAX);
215
216         sprintf(removeCmd, "rm -rf %ls", ospShare2PkgIdPath.GetPointer());
217         AppLog("removeCmd  = [%s]", removeCmd);
218
219         ret = system(removeCmd);
220         TryReturn(ret != -1, false, "system(%s) failed.", removeCmd);
221
222         AppLog("[Tizen::Io] CleanDirectories() succeeded, rootPath: %ls", rootPath.GetPointer());
223         return true;
224 }
225
226 bool
227 CompatibilityManager::LinkOspSharePath(const String& rootPath, const PackageId& packageId)
228 {
229         int ret = 0;
230         const char* pOspCompatSharedPath = "/opt/usr/share/.osp-compat/\0";
231
232         std::unique_ptr<char[]> pRootPath(_StringConverter::CopyToCharArrayN(rootPath));
233         TryReturn(pRootPath, false, "The memory is insufficient.");
234
235         std::unique_ptr<char[]> pPackageId(_StringConverter::CopyToCharArrayN(packageId));
236         TryReturn(pPackageId, false, "The memory is insufficient.");
237
238         char ospAppSharePath[PATH_MAX] = {0, };
239         char ospAppShare2Path[PATH_MAX] = {0, };
240         char ospSharePkgIdPath[PATH_MAX] = {0, };
241         char ospShare2PkgIdPath[PATH_MAX] = {0, };
242
243         strncpy(ospAppSharePath, pRootPath.get(), strlen(pRootPath.get()));
244         strncat(ospAppSharePath, "/shared/data", 12);
245
246         strncpy(ospSharePkgIdPath, pOspCompatSharedPath, strlen(pOspCompatSharedPath));
247         strncat(ospSharePkgIdPath, "share/", 6);
248         strncat(ospSharePkgIdPath, pPackageId.get(), strlen(pPackageId.get()));
249
250         strncpy(ospAppShare2Path, pRootPath.get(), strlen(pRootPath.get()));
251         strncat(ospAppShare2Path, "/shared/trusted", 15);
252
253         strncpy(ospShare2PkgIdPath, pOspCompatSharedPath, strlen(pOspCompatSharedPath));
254         strncat(ospShare2PkgIdPath, "share2/", 7);
255         strncat(ospShare2PkgIdPath, pPackageId.get(), strlen(pPackageId.get()));
256
257         unlink(ospSharePkgIdPath);
258         unlink(ospShare2PkgIdPath);
259
260         SmackManager smackManager;
261
262         ret = symlink(ospAppSharePath, ospSharePkgIdPath);
263         smackManager.AddLabelDir(L"_", ospSharePkgIdPath);
264
265         ret = symlink(ospAppShare2Path, ospShare2PkgIdPath);
266         smackManager.AddLabelDir(L"_", ospShare2PkgIdPath);
267
268         return true;
269 }
270
271 bool
272 CompatibilityManager::PrepareVirtualRoot(const Tizen::Base::String& rootPath, const Tizen::App::PackageId& packageId)
273 {
274         result r = E_SUCCESS;
275         bool res = true;
276         int result = 0;
277         char* pCwd = null;
278         String destPath = rootPath + DIR_VIRTUAL_ROOT;
279         SmackManager smackManager;
280
281         std::unique_ptr<char[]> pVirtualRootPath(_StringConverter::CopyToCharArrayN(destPath));
282         TryCatch(pVirtualRootPath != null, res = false, "The memory is insufficient.");
283
284         pCwd = get_current_dir_name();
285         TryCatch(pCwd != null, res = false, "get_current_dir_name() failed. [errno = %d(%s)]", errno, strerror(errno));
286
287         // appRoot/virtual-root
288         if (File::IsFileExist(destPath) == false)
289         {
290                 r = Directory::Create(destPath, false);
291                 TryCatch(!IsFailed(r), res = false, "Directory::Create() failed");
292         }
293
294         InstallerUtil::ChangeDirectoryPermission(destPath, PERM_BASE, true);
295
296         result = chdir(pVirtualRootPath.get());
297         TryCatch(result == 0, res = false, "chdir(%s) failed. [errno = %d(%s)]", pVirtualRootPath.get(), errno, strerror(errno));
298
299         res = CreateVirtualRootDirectories();
300         TryCatch(res == true, , "CreateVirtualRootDirectories() failed.");
301
302         smackManager.SetupPath(packageId, destPath, SMACK_DIR_TYPE_PRIVATE);
303
304         res = CreateSymbolicLink();
305         TryCatch(res == true, , "CreateSymbolicLink() failed.");
306
307         result = chdir(pCwd);
308         TryCatch(result == 0, res = false, "chdir(%s) failed. [errno = %d(%s)]", pCwd, errno, strerror(errno));
309
310 CATCH:
311         if (pCwd)
312         {
313                 free(pCwd);
314         }
315
316         AppLog("[Tizen::Io] result  = [%s]", res?"true":"false");
317
318         return res;
319 }
320
321 bool
322 CompatibilityManager::FinalizeVirtualRoot(const String& rootPath)
323 {
324         int res = 0;
325         unsigned int i = 0;
326         String destPath = rootPath + DIR_VIRTUAL_ROOT;
327         static const struct _PathInfo mountPath[] =
328         {
329                         { "./bin" },
330                         { "./cache" },
331                         { "./csa" },
332                         { "./data" },
333                         { "./dev" },
334                         { "./etc" },
335                         { "./lib" },
336                         { "./media" },
337                         { "./mnt" },
338                         { "./opt" },
339                         { "./proc" },
340                         { "./run" },
341                         { "./sbin" },
342                         { "./smack" },
343                         { "./srv" },
344                         { "./sys" },
345                         { "./system" },
346                         { "./tmp" },
347                         { "./usr" },
348                         { "./var" }
349         };
350
351         std::unique_ptr<char[]> pVirtualRootPath(_StringConverter::CopyToCharArrayN(destPath));
352         TryReturn(pVirtualRootPath, false, "The memory is insufficient.");
353
354         res = chdir(pVirtualRootPath.get());
355         TryReturn(res == 0, false, "chdir() failed. (%d, %s), path = [%ls]", errno, strerror(errno), destPath.GetPointer());
356
357         for (i = 0; i < sizeof(mountPath) / sizeof(struct _PathInfo); ++i)
358         {
359                 res = umount2(mountPath[i].destPath, MNT_DETACH);
360                 TryReturn((res == 0) || (errno == EINVAL) || (errno == ENOENT), false, "umount2() failed. (%d, %s), path = [%s]", errno, strerror(errno), mountPath[i].destPath);
361         }
362
363         AppLog("[Tizen::Io] FinalizeVirtualRoot() succeeded, path: %ls", destPath.GetPointer());
364         return true;
365 }
366
367 bool
368 CompatibilityManager::CreateOspInternalDirectories(const String& rootPath, const PackageId& packageId)
369 {
370         result r = E_SUCCESS;
371         bool res = true;
372         int ret = 0;
373         unsigned int i = 0;
374         int uid = 5000;
375         struct _OspDir appSubDir[] =
376         {
377                 { "./shared", 0755, false },
378                 { "./data/Share", 0000, true }, // mount from /opt/usr/share/.osp-compat/share/{pkgId}
379                 { "./data/Share2", 0000, true },        // mount from /opt/usr/share/.osp-compat/share2/{pkgId}
380                 { "./Share", 0000, false },     // mount from /opt/usr/share/.osp-compat/share
381                 { "./Share2", 0000, false },    // mount from /opt/usr/share/.osp-compat/share2
382                 { "./Media", 0000, false },     // mount from /opt/usr/media
383                 { "./Storagecard", 0705, false },
384                 { "./Storagecard/Media", 0000, false }, // mount from /opt/storage/sdcard
385         };
386         struct _OspDir mediaDir[] =
387         {
388                 { "/opt/usr/media/Images", 0777, false },
389                 { "/opt/usr/media/Sounds", 0777, false },
390                 { "/opt/usr/media/Videos", 0777, false },
391                 { "/opt/usr/media/Others", 0777, false }
392         };
393
394         String ospCompatSharedPath = _EnvironmentImpl::GetOspCompatSharedPath();
395         String ospShareAppIdPath(L"share/");
396         String ospShare2AppIdPath(L"share2/");
397
398         r = ospShareAppIdPath.Insert(ospCompatSharedPath, 0);
399         TryReturn(!IsFailed(r), false, "String::Insert() failed. [error: %s]", GetErrorMessage(r));
400
401         r = ospShare2AppIdPath.Insert(ospCompatSharedPath, 0);
402         TryReturn(!IsFailed(r), false, "String::Insert() failed. [error: %s]", GetErrorMessage(r));
403
404         for (i = 0; i < sizeof(appSubDir) / sizeof(struct _OspDir); i++)
405         {
406                 ret = mkdir(appSubDir[i].path, appSubDir[i].mode);
407                 if (ret == -1 && errno != 17) // EEXIST
408                 {
409                         AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), appSubDir[i].path, appSubDir[i].mode);
410                         return false;
411                 }
412
413                 if (appSubDir[i].appPrivilege)
414                 {
415                         ret = chown(appSubDir[i].path, uid, uid);
416                         if (ret == -1)
417                         {
418                                 AppLog("chown() failed (%s), path: %s, uid: %d", strerror(errno), appSubDir[i].path, uid);
419                                 return false;
420                         }
421                 }
422         }
423
424         SmackManager smackManager;
425         smackManager.SetupPath(packageId, L"./Storagecard", SMACK_DIR_TYPE_ANY_LABEL, L"_");
426
427         ospShareAppIdPath.Append(packageId);
428
429         std::unique_ptr<char[]> pOspShareAppIdPath(_StringConverter::CopyToCharArrayN(ospShareAppIdPath));
430         TryReturn(pOspShareAppIdPath, false, "The memory is insufficient.");
431
432         ret = mkdir(pOspShareAppIdPath.get(), 0705);
433         if (ret == -1 && errno != 17) // EEXIST
434         {
435                 AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), pOspShareAppIdPath.get(), 0705);
436                 return false;
437         }
438
439         ret = chown(pOspShareAppIdPath.get(), uid, uid);
440         if (ret == -1)
441         {
442                 AppLog("chown() failed (%s), path: %s, uid: %d", strerror(errno), pOspShareAppIdPath.get(), uid);
443                 return false;
444         }
445
446         ospShare2AppIdPath.Append(packageId);
447
448         std::unique_ptr<char[]> pOspShare2AppIdPath(_StringConverter::CopyToCharArrayN(ospShare2AppIdPath));
449         TryReturn(pOspShare2AppIdPath, false, "The memory is insufficient.");
450
451         ret = mkdir(pOspShare2AppIdPath.get(), 0705);
452         if (ret == -1 && errno != 17) // EEXIST
453         {
454                 AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), pOspShare2AppIdPath.get(), 0705);
455                 return false;
456         }
457
458         ret = chown(pOspShare2AppIdPath.get(), uid, uid);
459         if (ret == -1)
460         {
461                 AppLog("chown() failed (%s), path: %s, uid: %d", strerror(errno), pOspShare2AppIdPath.get(), uid);
462                 return false;
463         }
464
465         for (i = 0; i < sizeof(mediaDir) / sizeof(struct _OspDir); ++i)
466         {
467                 ret = mkdir(mediaDir[i].path, mediaDir[i].mode);
468                 if (ret == -1 && errno != 17) // EEXIST
469                 {
470                         AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), mediaDir[i].path, mediaDir[i].mode);
471                         return false;
472                 }
473
474                 ret = chown(mediaDir[i].path, 5000, 5000);
475                 TryReturn(ret == 0, false, "chown() failed (%d, %s), path: %s, uid: 5000, gid: 5000", errno, strerror(errno), mediaDir[i].path);
476         }
477
478         String appSharedDataPath(rootPath);
479         appSharedDataPath.Append(L"/shared/data");
480
481         String appSharedTrustedPath(rootPath);
482         appSharedTrustedPath.Append(L"/shared/trusted");
483
484         r = Directory::Remove(appSharedDataPath, true);
485         TryReturn(r == E_SUCCESS, false, "Directory::Remove(%ls) failed.", appSharedDataPath.GetPointer());
486
487         r = Directory::Remove(appSharedTrustedPath, true);
488         TryReturn(r == E_SUCCESS, false, "Directory::Remove(%ls) failed.", appSharedTrustedPath.GetPointer());
489
490         res = InstallerUtil::CreateSymlink(ospShareAppIdPath, L"./shared/data");
491         TryReturn(res == true, false, "CreateSymlink() failed, errno: %d (%s), link: ./shared/data -> %s", errno, strerror(errno), pOspShareAppIdPath.get());
492
493         res = InstallerUtil::CreateSymlink(ospShare2AppIdPath, L"./shared/trusted");
494         TryReturn(res == true, false, " CreateSymlink() failed, errno: %d (%s), link: ./shared/trusted -> %s", errno, strerror(errno), pOspShare2AppIdPath.get());
495
496         AppLog("[Tizen::Io] CreateOspInternalDirectories() succeeded, rootPath: %ls", rootPath.GetPointer());
497         return true;
498 }
499
500 bool
501 CompatibilityManager::CreateSlpDirectories(void)
502 {
503         unsigned int i = 0;
504         int ret = 0;
505         struct _OspDir slpDir[] =
506         {
507                 { "./csa", 0000, false },
508                 { "./dev", 0000, false },
509                 { "./etc", 0000, false },
510                 { "./lib", 0000, false },
511                 { "./media", 0000, false },
512                 { "./mnt", 0000, false },
513                 { "./opt", 0000, false },
514                 { "./proc", 0000, false },
515                 { "./sbin", 0000, false },
516                 { "./smack", 0000, false },
517                 { "./srv", 0000, false },
518                 { "./sys", 0000, false },
519                 { "./tmp", 0000, false },
520                 { "./usr", 0000, false },
521                 { "./var", 0000, false }
522         };
523
524         for (i = 0; i < sizeof(slpDir) / sizeof(struct _OspDir); i++)
525         {
526                 ret = mkdir(slpDir[i].path, slpDir[i].mode);
527                 if (ret == -1 && errno != 17) // EEXIST
528                 {
529                         AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), slpDir[i].path, slpDir[i].mode);
530                         return false;
531                 }
532         }
533
534         AppLog("[Tizen::Io] CreateSlpDirectories() succeeded.");
535         return true;
536 }
537
538 bool
539 CompatibilityManager::CreateSymbolicLink(void)
540 {
541         struct _LinkDir linkDirList[] =
542         {
543                 { "/opt/home", "./home" },
544                 { "/opt/home/root", "./root" },
545                 { "/mnt/mmc", "./sdcard" }
546         };
547
548         for (unsigned int i = 0; i < sizeof(linkDirList) / sizeof(struct _LinkDir); ++i)
549         {
550                 InstallerUtil::CreateSymlink(linkDirList[i].srcPath, linkDirList[i].destPath);
551         }
552
553         AppLog("[Tizen::Io] CreateSymbolicLink() succeeded.");
554         return true;
555 }
556
557 bool
558 CompatibilityManager::CreateVirtualRootDirectories(void)
559 {
560         unsigned int i = 0;
561         int ret = 0;
562         struct _OspDir virtualRootDir[] =
563         {
564                         { "./bin", 0000, false },
565                         { "./cache", 0000, false },
566                         { "./csa", 0000, false },
567                         { "./data", 0000, false },
568                         { "./dev", 0000, false },
569                         { "./etc", 0000, false },
570                         { "./lib", 0000, false },
571                         { "./media", 0000, false },
572                         { "./mnt", 0000, false },
573                         { "./opt", 0000, false },
574                         { "./proc", 0000, false },
575                         { "./run", 0000, false },
576                         { "./sbin", 0000, false },
577                         { "./smack", 0000, false },
578                         { "./srv", 0000, false },
579                         { "./sys", 0000, false },
580                         { "./system", 0000, false },
581                         { "./tmp", 0000, false },
582                         { "./usr", 0000, false },
583                         { "./var", 0000, false }
584         };
585
586         for (i = 0; i < sizeof(virtualRootDir) / sizeof(struct _OspDir); i++)
587         {
588                 ret = mkdir(virtualRootDir[i].path, virtualRootDir[i].mode);
589                 if (ret == -1 && errno != 17) // EEXIST
590                 {
591                         AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), virtualRootDir[i].path, virtualRootDir[i].mode);
592                         return false;
593                 }
594         }
595
596         AppLog("[Tizen::Io] CreateVirtualRootDirectories() succeeded.");
597         return true;
598 }