--- /dev/null
+//
+// Open Service Platform
+// Copyright (c) 2012 Samsung Electronics Co., Ltd.
+//
+// Licensed under the Apache License, Version 2.0 (the License);
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+/**
+ * @file CompatibilityManager.cpp
+ * @brief This is the implementation file for %CompatibilityManager class.
+ */
+
+#include <sys/stat.h>
+#include <sys/mount.h>
+#include <dirent.h>
+#include <errno.h>
+#include <unique_ptr.h>
+
+#include <FIoDirectory.h>
+#include <FBase_StringConverter.h>
+#include <FSys_EnvironmentImpl.h>
+
+#include "InstallerDefs.h"
+#include "CompatibilityManager.h"
+#include "SmackManager.h"
+
+using namespace Tizen::App;
+using namespace Tizen::Base;
+using namespace Tizen::Io;
+using namespace Tizen::System;
+
+struct _OspDir
+{
+ char path[PATH_MAX];
+ mode_t mode;
+ bool appPrivilege;
+};
+
+struct _LinkDir
+{
+ char srcPath[PATH_MAX];
+ char destPath[PATH_MAX];
+};
+
+struct _PathInfo
+{
+ char destPath[PATH_MAX];
+};
+
+
+CompatibilityManager::CompatibilityManager(void)
+{
+}
+
+CompatibilityManager::~CompatibilityManager(void)
+{
+}
+
+bool
+CompatibilityManager::PrepareDataCaging(const String& rootPath, const PackageId& packageId)
+{
+ bool res = true;
+ int result = 0;
+ char* pCwd = null;
+
+ std::unique_ptr<char[]> pRootPath(_StringConverter::CopyToCharArrayN(rootPath));
+ TryCatch(pRootPath != null, res = false, "The memory is insufficient.");
+
+ res = CleanDirectories(rootPath, packageId);
+ TryCatch(res == true, , "CleanDirectories(%ls, %ls) failed.", rootPath.GetPointer(), packageId.GetPointer());
+
+ pCwd = get_current_dir_name();
+ TryCatch(pCwd != null, res = false, "get_current_dir_name() failed. [errno = %d(%s)]", errno, strerror(errno));
+
+ umask(0000);
+
+ result = chdir(pRootPath.get());
+ TryCatch(result == 0, res = false, "chdir(%s) failed. [errno = %d(%s)]", pRootPath.get(), errno, strerror(errno));
+
+ res = CreateOspInternalDirectories(rootPath, packageId);
+ TryCatch(res == true, , "CreateOspInternalDirectories(%ls, %ls) failed.", rootPath.GetPointer(), packageId.GetPointer());
+
+ res = CreateSlpDirectories();
+ TryCatch(res == true, , "CreateSlpDirectories() failed.");
+
+ res = CreateSymbolicLink();
+ TryCatch(res == true, , "CreateSymbolicLink() failed.");
+
+ result = chdir(pCwd);
+ TryCatch(result == 0, res = false, "chdir(%s) failed. [errno = %d(%s)]", pCwd, errno, strerror(errno));
+
+CATCH:
+ if (pCwd)
+ {
+ free(pCwd);
+ }
+
+ umask(0022);
+
+ AppLog("[Tizen::Io] result = [%s]", res?"true":"false");
+
+ return res;
+}
+
+bool
+CompatibilityManager::FinalizeDataCaging(const String& rootPath)
+{
+ int res = 0;
+ unsigned int i = 0;
+
+ static const struct _PathInfo mountPath[] =
+ {
+ { "./csa" },
+ { "./dev/pts" },
+ { "./dev/shm" },
+ { "./dev" },
+ { "./etc" },
+ { "./lib" },
+ { "./media" },
+ { "./mnt" },
+ { "./opt/usr" },
+ { "./opt/var/kdb/db" },
+ { "./opt/storage/sdcard" },
+ { "./opt" },
+ { "./proc" },
+ { "./sbin" },
+ { "./smack" },
+ { "./srv" },
+ { "./sys/kernel/debug" },
+ { "./sys" },
+ { "./tmp" },
+ { "./usr" },
+ { "./var/run" },
+ { "./var" },
+ { "./data/Share" },
+ { "./data/Share2" },
+ { "./Share" },
+ { "./Share2" },
+ { "./Media" },
+ { "./Storagecard/Media" },
+ { "./ShareExt" },
+ { "./Share2Ext" },
+ { "./HomeExt/Share" },
+ { "./HomeExt/Share2" },
+ { "./HomeExt" }
+ };
+
+ std::unique_ptr<char[]> pAppRootPath(_StringConverter::CopyToCharArrayN(rootPath));
+ TryReturn(pAppRootPath, false, "The memory is insufficient.");
+
+ res = chdir(pAppRootPath.get());
+ TryReturn(res == 0, false, "chdir() failed. (%d, %s), path = [%ls]", errno, strerror(errno), rootPath.GetPointer());
+
+ for (i = 0; i < sizeof(mountPath) / sizeof(struct _PathInfo); ++i)
+ {
+ res = umount2(mountPath[i].destPath, MNT_DETACH);
+ TryReturn((res == 0) || (errno == EINVAL) || (errno == ENOENT), false, "umount2() failed. (%d, %s), path = [%s]", errno, strerror(errno), mountPath[i].destPath);
+ }
+
+ char* pPackageId = strrchr(pAppRootPath.get(), '/');
+ char mountFlag[PATH_MAX] = {0, };
+
+ sprintf(mountFlag, "/tmp/osp-compat/mount/internal/%s", ++pPackageId);
+ res = unlink(mountFlag);
+ if ((res == -1) && (errno != ENOENT))
+ {
+ AppLog("unlink(%s) failed, errno: %d (%s)", mountFlag, errno, strerror(errno));
+ return false;
+ }
+
+ memset(mountFlag, 0, PATH_MAX);
+ sprintf(mountFlag, "/tmp/osp-compat/mount/external/%s", pPackageId);
+ res = unlink(mountFlag);
+ if ((res == -1) && (errno != ENOENT))
+ {
+ AppLog("unlink(%s) failed, errno: %d (%s)", mountFlag, errno, strerror(errno));
+ return false;
+ }
+
+ AppLog("[Tizen::Io] FinalizeDataCaging() succeeded, rootPath: %ls", rootPath.GetPointer());
+ return true;
+}
+
+bool
+CompatibilityManager::CleanDirectories(const String& rootPath, const PackageId& packageId)
+{
+ int ret = 0;
+ char removeCmd[PATH_MAX] = {0, };
+
+ String ospSharePkgIdPath = _EnvironmentImpl::GetOspCompatSharedPath();
+ ospSharePkgIdPath.Append(L"share/");
+ ospSharePkgIdPath.Append(packageId);
+
+ String ospShare2PkgIdPath = _EnvironmentImpl::GetOspCompatSharedPath();
+ ospShare2PkgIdPath.Append(L"share2/");
+ ospShare2PkgIdPath.Append(packageId);
+
+ sprintf(removeCmd, "rm -rf %ls", ospSharePkgIdPath.GetPointer());
+ AppLog("removeCmd = [%s]", removeCmd);
+
+ ret = system(removeCmd);
+ TryReturn(ret != -1, false, "system(%s) failed.", removeCmd);
+
+ memset(removeCmd, 0, PATH_MAX);
+
+ sprintf(removeCmd, "rm -rf %ls", ospShare2PkgIdPath.GetPointer());
+ AppLog("removeCmd = [%s]", removeCmd);
+
+ ret = system(removeCmd);
+ TryReturn(ret != -1, false, "system(%s) failed.", removeCmd);
+
+ AppLog("[Tizen::Io] CleanDirectories() succeeded, rootPath: %ls", rootPath.GetPointer());
+ return true;
+}
+
+bool
+CompatibilityManager::LinkOspSharePath(const String& rootPath, const PackageId& packageId)
+{
+ const char* pOspCompatSharedPath = "/opt/usr/share/.osp-compat/\0";
+
+ std::unique_ptr<char[]> pRootPath(_StringConverter::CopyToCharArrayN(rootPath));
+ TryReturn(pRootPath, false, "The memory is insufficient.");
+
+ std::unique_ptr<char[]> pPackageId(_StringConverter::CopyToCharArrayN(packageId));
+ TryReturn(pPackageId, false, "The memory is insufficient.");
+
+ char ospAppSharePath[PATH_MAX] = {0, };
+ char ospAppShare2Path[PATH_MAX] = {0, };
+ char ospSharePkgIdPath[PATH_MAX] = {0, };
+ char ospShare2PkgIdPath[PATH_MAX] = {0, };
+
+ strncpy(ospAppSharePath, pRootPath.get(), strlen(pRootPath.get()));
+ strncat(ospAppSharePath, "/shared/data", 12);
+
+ strncpy(ospSharePkgIdPath, pOspCompatSharedPath, strlen(pOspCompatSharedPath));
+ strncat(ospSharePkgIdPath, "share/", 6);
+ strncat(ospSharePkgIdPath, pPackageId.get(), strlen(pPackageId.get()));
+
+ strncpy(ospAppShare2Path, pRootPath.get(), strlen(pRootPath.get()));
+ strncat(ospAppShare2Path, "/shared/trusted", 15);
+
+ strncpy(ospShare2PkgIdPath, pOspCompatSharedPath, strlen(pOspCompatSharedPath));
+ strncat(ospShare2PkgIdPath, "share2/", 7);
+ strncat(ospShare2PkgIdPath, pPackageId.get(), strlen(pPackageId.get()));
+
+ unlink(ospSharePkgIdPath);
+ unlink(ospShare2PkgIdPath);
+
+ InstallerUtil::CreateSymlink(ospAppSharePath, ospSharePkgIdPath);
+ InstallerUtil::CreateSymlink(ospAppShare2Path, ospShare2PkgIdPath);
+
+ return true;
+}
+
+bool
+CompatibilityManager::CreateOspInternalDirectories(const String& rootPath, const PackageId& packageId)
+{
+ result r = E_SUCCESS;
+ bool res = true;
+ int ret = 0;
+ unsigned int i = 0;
+ int uid = 5000;
+ struct _OspDir appSubDir[] =
+ {
+ { "./shared", 0755, false },
+ { "./data/Share", 0000, true }, // mount from /opt/usr/share/.osp-compat/share/{pkgId}
+ { "./data/Share2", 0000, true }, // mount from /opt/usr/share/.osp-compat/share2/{pkgId}
+ { "./Share", 0000, false }, // mount from /opt/usr/share/.osp-compat/share
+ { "./Share2", 0000, false }, // mount from /opt/usr/share/.osp-compat/share2
+ { "./Media", 0000, false }, // mount from /opt/usr/media
+ { "./Storagecard", 0705, false },
+ { "./Storagecard/Media", 0000, false }, // mount from /opt/storage/sdcard
+ };
+ struct _OspDir mediaDir[] =
+ {
+ { "/opt/usr/media/Images", 0777, false },
+ { "/opt/usr/media/Sounds", 0777, false },
+ { "/opt/usr/media/Videos", 0777, false },
+ { "/opt/usr/media/Others", 0777, false }
+ };
+
+ String ospCompatSharedPath = _EnvironmentImpl::GetOspCompatSharedPath();
+ String ospShareAppIdPath(L"share/");
+ String ospShare2AppIdPath(L"share2/");
+
+ r = ospShareAppIdPath.Insert(ospCompatSharedPath, 0);
+ TryReturn(!IsFailed(r), false, "String::Insert() failed. [error: %s]", GetErrorMessage(r));
+
+ r = ospShare2AppIdPath.Insert(ospCompatSharedPath, 0);
+ TryReturn(!IsFailed(r), false, "String::Insert() failed. [error: %s]", GetErrorMessage(r));
+
+ for (i = 0; i < sizeof(appSubDir) / sizeof(struct _OspDir); i++)
+ {
+ ret = mkdir(appSubDir[i].path, appSubDir[i].mode);
+ if (ret == -1 && errno != 17) // EEXIST
+ {
+ AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), appSubDir[i].path, appSubDir[i].mode);
+ return false;
+ }
+
+ if (appSubDir[i].appPrivilege)
+ {
+ ret = chown(appSubDir[i].path, uid, uid);
+ if (ret == -1)
+ {
+ AppLog("chown() failed (%s), path: %s, uid: %d", strerror(errno), appSubDir[i].path, uid);
+ return false;
+ }
+ }
+ }
+
+ SmackManager smackManager;
+ smackManager.AddLabelDir(L"_", L"./Storagecard");
+
+ ospShareAppIdPath.Append(packageId);
+
+ std::unique_ptr<char[]> pOspShareAppIdPath(_StringConverter::CopyToCharArrayN(ospShareAppIdPath));
+ TryReturn(pOspShareAppIdPath, false, "The memory is insufficient.");
+
+ ret = mkdir(pOspShareAppIdPath.get(), 0705);
+ if (ret == -1 && errno != 17) // EEXIST
+ {
+ AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), pOspShareAppIdPath.get(), 0705);
+ return false;
+ }
+
+ ret = chown(pOspShareAppIdPath.get(), uid, uid);
+ if (ret == -1)
+ {
+ AppLog("chown() failed (%s), path: %s, uid: %d", strerror(errno), pOspShareAppIdPath.get(), uid);
+ return false;
+ }
+
+ ospShare2AppIdPath.Append(packageId);
+
+ std::unique_ptr<char[]> pOspShare2AppIdPath(_StringConverter::CopyToCharArrayN(ospShare2AppIdPath));
+ TryReturn(pOspShare2AppIdPath, false, "The memory is insufficient.");
+
+ ret = mkdir(pOspShare2AppIdPath.get(), 0705);
+ if (ret == -1 && errno != 17) // EEXIST
+ {
+ AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), pOspShare2AppIdPath.get(), 0705);
+ return false;
+ }
+
+ ret = chown(pOspShare2AppIdPath.get(), uid, uid);
+ if (ret == -1)
+ {
+ AppLog("chown() failed (%s), path: %s, uid: %d", strerror(errno), pOspShare2AppIdPath.get(), uid);
+ return false;
+ }
+
+ for (i = 0; i < sizeof(mediaDir) / sizeof(struct _OspDir); ++i)
+ {
+ ret = mkdir(mediaDir[i].path, mediaDir[i].mode);
+ if (ret == -1 && errno != 17) // EEXIST
+ {
+ AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), mediaDir[i].path, mediaDir[i].mode);
+ return false;
+ }
+
+ ret = chown(mediaDir[i].path, 5000, 5000);
+ TryReturn(ret == 0, false, "chown() failed (%d, %s), path: %s, uid: 5000, gid: 5000", errno, strerror(errno), mediaDir[i].path);
+ }
+
+ String appSharedDataPath(rootPath);
+ appSharedDataPath.Append(L"/shared/data");
+
+ String appSharedTrustedPath(rootPath);
+ appSharedTrustedPath.Append(L"/shared/trusted");
+
+ r = Directory::Remove(appSharedDataPath, true);
+ TryReturn(r == E_SUCCESS, false, "Directory::Remove(%ls) failed.", appSharedDataPath.GetPointer());
+
+ r = Directory::Remove(appSharedTrustedPath, true);
+ TryReturn(r == E_SUCCESS, false, "Directory::Remove(%ls) failed.", appSharedTrustedPath.GetPointer());
+
+ res = InstallerUtil::CreateSymlink(ospShareAppIdPath, L"./shared/data");
+ TryReturn(res == true, false, "CreateSymlink() failed, errno: %d (%s), link: ./shared/data -> %s", errno, strerror(errno), pOspShareAppIdPath.get());
+
+ res = InstallerUtil::CreateSymlink(ospShare2AppIdPath, L"./shared/trusted");
+ TryReturn(res == true, false, " CreateSymlink() failed, errno: %d (%s), link: ./shared/trusted -> %s", errno, strerror(errno), pOspShare2AppIdPath.get());
+
+ AppLog("[Tizen::Io] CreateOspInternalDirectories() succeeded, rootPath: %ls", rootPath.GetPointer());
+ return true;
+}
+
+bool
+CompatibilityManager::CreateSlpDirectories(void)
+{
+ unsigned int i = 0;
+ int ret = 0;
+ struct _OspDir slpDir[] =
+ {
+ { "./csa", 0000, false },
+ { "./dev", 0000, false },
+ { "./etc", 0000, false },
+ { "./lib", 0000, false },
+ { "./media", 0000, false },
+ { "./mnt", 0000, false },
+ { "./opt", 0000, false },
+ { "./proc", 0000, false },
+ { "./sbin", 0000, false },
+ { "./smack", 0000, false },
+ { "./srv", 0000, false },
+ { "./sys", 0000, false },
+ { "./tmp", 0000, false },
+ { "./usr", 0000, false },
+ { "./var", 0000, false }
+ };
+
+ for (i = 0; i < sizeof(slpDir) / sizeof(struct _OspDir); i++)
+ {
+ ret = mkdir(slpDir[i].path, slpDir[i].mode);
+ if (ret == -1 && errno != 17) // EEXIST
+ {
+ AppLog("mkdir() failed (%s), path: %s, mode: 0%o", strerror(errno), slpDir[i].path, slpDir[i].mode);
+ return false;
+ }
+ }
+
+ AppLog("[Tizen::Io] CreateSlpDirectories() succeeded.");
+ return true;
+}
+
+bool
+CompatibilityManager::CreateSymbolicLink(void)
+{
+ struct _LinkDir linkDirList[] =
+ {
+ { "/opt/home", "./home" },
+ { "/opt/home/root", "./root" },
+ { "/mnt/mmc", "./sdcard" }
+ };
+
+ for (unsigned int i = 0; i < sizeof(linkDirList) / sizeof(struct _LinkDir); ++i)
+ {
+ InstallerUtil::CreateSymlink(linkDirList[i].srcPath, linkDirList[i].destPath);
+ }
+
+ AppLog("[Tizen::Io] CreateSymbolicLink() succeeded.");
+ return true;
+}