X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=NativeLauncher%2Futil%2Futils.cc;h=9f34fb4e922d0e663952cc3f190adbffbe8a5f1e;hb=9ab4547491e1bc0ba0564581a9390ed63b09348e;hp=2cc1026eda65050f9f86bf8859c1c2ab1faf0b07;hpb=8cd6fb2c60ac74259fdce9615836949e9d0ef7fc;p=platform%2Fcore%2Fdotnet%2Flauncher.git diff --git a/NativeLauncher/util/utils.cc b/NativeLauncher/util/utils.cc index 2cc1026..9f34fb4 100644 --- a/NativeLauncher/util/utils.cc +++ b/NativeLauncher/util/utils.cc @@ -1,9 +1,33 @@ +/* + * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved + * + * 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. + */ #include +#include #include #include #include #include +#include +#include +#include + +#include +#include + +#include #include #include @@ -11,319 +35,854 @@ #include #include #include +#include #include +#include +#include +#include "log.h" #include "utils.h" +#include "path_manager.h" + +static bool iCompare(const std::string& a, int aOffset, const std::string& b, int bOffset, int length) +{ + return static_cast(a.length()) - length >= aOffset && + static_cast(b.length()) - length >= bOffset && + std::equal(b.begin() + bOffset, b.begin() + bOffset + length, a.begin() + aOffset, + [](unsigned char a, unsigned char b) + { return std::tolower(a) == std::tolower(b); }); +} + +bool isManagedAssembly(const std::string& fileName) +{ + return iCompare(fileName, fileName.size()-4, ".dll", 0, 4) && !isNativeImage(fileName); +} + +bool isNativeImage(const std::string& fileName) +{ + return iCompare(fileName, fileName.size()-7, ".ni", 0, 3); +} + +std::string concatPath(const std::string& path1, const std::string& path2) +{ + std::string path(path1); + if (path.back() == PATH_SEPARATOR) { + path.append(path2); + } else { + path += PATH_SEPARATOR; + path.append(path2); + } + + return path; +} + +void splitPath(const std::string& path, std::vector& out) +{ + std::istringstream ss(path); + std::string token; + + while (std::getline(ss, token, ':')) { + out.push_back(token); + } +} + +std::string getAbsolutePath(const std::string& path) +{ + std::string absPath; + char *realPath = realpath(path.c_str(), NULL); + if (realPath) { + absPath.assign(realPath); + free(realPath); + } + + return absPath; +} + +std::string getRootPath(const std::string& pkgId) +{ + int ret = 0; + char *path = 0; + std::string rootPath; + + pkgmgrinfo_pkginfo_h pkg_handle; + ret = pkgmgrGetPkgInfo(pkgId, &pkg_handle); + if (ret != 0) { + return rootPath; + } + + ret = pkgmgrinfo_pkginfo_get_root_path(pkg_handle, &path); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return rootPath; + } + rootPath = path; + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + + return rootPath; +} + +std::string getExecName(const std::string& pkgId) +{ + char *exec = NULL; + char *appId = 0; + std::string execName; + + pkgmgrinfo_pkginfo_h pkg_handle; + int ret = pkgmgrGetPkgInfo(pkgId, &pkg_handle); + if (ret != 0) { + return execName; + } + + ret = pkgmgrinfo_pkginfo_get_mainappid(pkg_handle, &appId); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return execName; + } + + pkgmgrinfo_appinfo_h app_handle; + ret = pkgmgrGetAppInfo(appId, &app_handle); + if (ret != 0) { + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return execName; + } + + ret = pkgmgrinfo_appinfo_get_exec(app_handle, &exec); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_appinfo_destroy_appinfo(app_handle); + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return execName; + } + execName = std::string(exec).substr(std::string(exec).rfind('/') + 1); + + pkgmgrinfo_appinfo_destroy_appinfo(app_handle); + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + + return execName; +} + +std::string getAppType(const std::string& pkgId) +{ + char *appId = 0; + char *type = 0; + std::string appType; + + pkgmgrinfo_pkginfo_h pkg_handle; + int ret = pkgmgrGetPkgInfo(pkgId, &pkg_handle); + if (ret != 0) { + return appType; + } + + ret = pkgmgrinfo_pkginfo_get_mainappid(pkg_handle, &appId); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return appType; + } + + pkgmgrinfo_appinfo_h app_handle; + ret = pkgmgrGetAppInfo(appId, &app_handle); + if (ret != 0) { + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return appType; + } + + ret = pkgmgrinfo_appinfo_get_apptype(app_handle, &type); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_appinfo_destroy_appinfo(app_handle); + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return appType; + } + appType = type; + + pkgmgrinfo_appinfo_destroy_appinfo(app_handle); + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + + return appType; +} -bool ICompare(const std::string& a, const std::string& b) +std::string getMetadataValue(const std::string& pkgId, const std::string& key) { - return a.length() == b.length() && - std::equal(b.begin(), b.end(), a.begin(), - [](unsigned char a, unsigned char b) - { return std::tolower(a) == std::tolower(b); }); + char *value = NULL; + char *appId = 0; + std::string metadataValue; + + pkgmgrinfo_pkginfo_h pkg_handle; + int ret = pkgmgrGetPkgInfo(pkgId, &pkg_handle); + if (ret != 0) { + return metadataValue; + } + + ret = pkgmgrinfo_pkginfo_get_mainappid(pkg_handle, &appId); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return metadataValue; + } + + pkgmgrinfo_appinfo_h app_handle; + ret = pkgmgrGetAppInfo(appId, &app_handle); + if (ret != 0) { + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return metadataValue; + } + + ret = pkgmgrinfo_appinfo_get_metadata_value(app_handle, key.c_str(), &value); + if (ret != PMINFO_R_OK) { + pkgmgrinfo_appinfo_destroy_appinfo(app_handle); + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + return metadataValue; + } + metadataValue = std::string(value); + + pkgmgrinfo_appinfo_destroy_appinfo(app_handle); + pkgmgrinfo_pkginfo_destroy_pkginfo(pkg_handle); + + return metadataValue; } -bool ICompare(const std::string& a, int a_offset, const std::string& b, int b_offset, int length) +bool isReadOnlyArea(const std::string& path) { - return static_cast(a.length()) - length >= a_offset && - static_cast(b.length()) - length >= b_offset && - std::equal(b.begin() + b_offset, b.begin() + b_offset + length, a.begin() + a_offset, - [](unsigned char a, unsigned char b) - { return std::tolower(a) == std::tolower(b); }); + FILE *f = NULL; + struct mntent *m = NULL; + + // "/opt/usr" is mounted to "RW" only + if (path.find("/opt/usr") != std::string::npos) { + return false; + } + + // check whether "/" is mounted to RO or not + f = setmntent("/proc/mounts", "r"); + if (!f) { + // return true for fail case to generate NI files under RW area. + return true; + } + + while((m = getmntent(f))) { + if (m->mnt_dir != NULL && strcmp(m->mnt_dir, "/") == 0 && + m->mnt_opts != NULL && strstr(m->mnt_opts, "ro,") != NULL) { + endmntent(f); + return true; + } + } + endmntent(f); + return false; + +} + +std::string getBaseName(const std::string& path) +{ + auto pos = path.find_last_of(PATH_SEPARATOR); + if (pos != std::string::npos) + return path.substr(0, pos); + else + return std::string("."); + return path; +} + +std::string replaceAll(const std::string& str, const std::string& pattern, const std::string& replace) +{ + std::string result = str; + std::string::size_type pos = 0; + std::string::size_type offset = 0; + + while ((pos = result.find(pattern, offset)) != std::string::npos) { + result.replace(result.begin() + pos, result.begin() + pos + pattern.size(), replace); + offset = pos + replace.size(); + } + + return result; } -bool IsManagedAssembly(const std::string& filename) +std::string changeExtension(const std::string& path, const std::string& from, const std::string& to) { - return ICompare(filename, filename.size()-4, ".dll", 0, 4) || - ICompare(filename, filename.size()-4, ".exe", 0, 4); + return path.substr(0, path.rfind(from)) + to; } -bool IsNativeImage(const std::string& filename) +bool isFile(const std::string& path) { - return ICompare(filename, filename.size()-7, ".ni", 0, 3); + struct stat sb; + return lstat(path.c_str(), &sb) == 0; } -std::string ReadSelfPath() +bool isSymlinkFile(const std::string& path) { - char buff[PATH_MAX]; - ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1); - if (len != -1) { - buff[len] = '\0'; - return std::string(buff); - } + struct stat sb; + if (lstat(path.c_str(), &sb) != 0) { + return false; + } + return (sb.st_mode & S_IFMT) == S_IFLNK; +} - return ""; +bool isDirectory(const std::string& path) +{ + struct stat sb; + if (stat(path.c_str(), &sb) != 0) { + return false; + } + return (sb.st_mode & S_IFMT) == S_IFDIR; } -std::string ConcatPath(const std::string& path1, const std::string& path2) +std::string getAssemblyNameFromPath(const std::string& path) { - std::string path(path1); - if (path.back() == PATH_SEPARATOR) - { - path.append(path2); - } - else - { - path += PATH_SEPARATOR; - path.append(path2); - } + std::string ret(getFileName(path)); + + if (ret.find_last_of(".") == std::string::npos) + return ret; + ret.erase(ret.find_last_of(".")); + + if (ret.size() > 3 && std::equal(ret.begin() + ret.size() - 3, ret.end(), ".ni")) + ret.erase(ret.size() - 3); - return path; + return ret; } -void AppendPath(std::string& path1, const std::string& path2) +void addAssembliesFromDirectories(const std::vector& directories, std::string& list) { - if (path1.back() == PATH_SEPARATOR) - { - path1.append(path2); - } - else - { - path1 += PATH_SEPARATOR; - path1.append(path2); - } + std::vector assems; + std::unordered_map assemPaths; + + auto reader = [&assems, &assemPaths](const std::string& path, const std::string& filename) { + if (isManagedAssembly(filename) || isNativeImage(filename)) { + std::string assem = getAssemblyNameFromPath(filename); + + if (assemPaths.count(assem) == 0) { + assems.push_back(assem); + assemPaths[assem] = path; + } else if (isManagedAssembly(assemPaths[assem]) && isNativeImage(filename)) { + // Update only if a native image is found in the same directory. + // For example, if we have two directories = { X, Y } where X contains A.dll and + // Y contains both A.dll and A.ni.dll, always A.dll in X will be used. + if (getBaseName(assemPaths[assem]).compare(getBaseName(path)) == 0) + assemPaths[assem] = path; + } + } + }; + for (auto& directory : directories) + scanFilesInDirectory(directory, reader, 0); + + if (!list.empty() && list.back() != ':') + list.push_back(':'); + + for (auto& assem : assems) + list += assemPaths[assem] + ":"; + + if (list.back() == ':') + list.pop_back(); } -std::string AbsolutePath(const std::string& path) +void scanFilesInDirectory(const std::string& directory, FileReader reader, unsigned int depth) { - std::string absPath; + DIR *dir; + struct dirent* entry; + bool isDir; + + dir = opendir(directory.c_str()); + + if (dir == nullptr) + return; + + std::vector innerDirectories; + + while ((entry = readdir(dir)) != nullptr) { + isDir = false; + std::string path = concatPath(directory, entry->d_name); + switch (entry->d_type) { + case DT_REG: break; + case DT_DIR: + isDir = true; + break; + // symlink is added to the list even if there is no original file. + // It used to remove broken symlinks related to TAC + case DT_LNK: + break; + case DT_UNKNOWN: + continue; + default: + continue; + } + if (!isDir) + reader(path, entry->d_name); + else if (depth > 0 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) + innerDirectories.push_back(path); + } + + if (depth > 0) + for (auto& d : innerDirectories) + scanFilesInDirectory(d, reader, depth - 1); + + closedir(dir); +} - char realPath[PATH_MAX]; - if (realpath(path.c_str(), realPath) != nullptr && realPath[0] != '\0') - { - absPath.assign(realPath); - } +void copySmackAndOwnership(const std::string& fromPath, const std::string& toPath, bool isSymlink) +{ + char* label = NULL; + struct stat info; + + if (isSymlink) { + // change smack label for symbolic link. + if (smack_lgetlabel(fromPath.c_str(), &label, SMACK_LABEL_ACCESS) == 0) { + if (smack_lsetlabel(toPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) { + _SERR("Fail to set smack label"); + } + free(label); + } + + // change owner and groupsfor symbolic link. + // change mode is skipped for symlink because permission of symlink file is meaningless. + if (!lstat(fromPath.c_str(), &info)) { + if (lchown(toPath.c_str(), info.st_uid, info.st_gid) == -1) + _SERR("Failed to change owner and group name"); + } + } else { + // change smack label + if (smack_getlabel(fromPath.c_str(), &label, SMACK_LABEL_ACCESS) == 0) { + if (smack_setlabel(toPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) { + _SERR("Fail to set smack label"); + } + free(label); + } + + // change owner, groups and mode for generated ni file. + if (!stat(fromPath.c_str(), &info)) { + if (chown(toPath.c_str(), info.st_uid, info.st_gid) == -1) + _SERR("Failed to change owner and group name"); + if (chmod(toPath.c_str(), info.st_mode) == -1) + _SERR("Failed to change mode"); + } + } +} - return absPath; +static bool setOwnership(const bf::path& path, uid_t uid, gid_t gid) +{ + int fd = open(path.c_str(), O_RDONLY); + if (fd < 0) { + _ERR("Can't open directory: %s", path.c_str()); + return false; + } + int ret = fchown(fd, uid, gid); + close(fd); + if (ret != 0) { + _ERR("Failed to change owner of: %s", path.c_str()); + return false; + } + return true; +} + +static bool setDirPermissions(const bf::path& path, bf::perms permissions) +{ + bs::error_code error; + bf::permissions(path, permissions, error); + if (error) { + _ERR("Failed to set permissions for directory: %s, %s", path.c_str(), error.message().c_str()); + return false; + } + return true; } -std::string Basename(const std::string& path) +static bool setDirOwnershipAndPermissions(const bf::path& path, bf::perms permissions, uid_t uid, gid_t gid) { - auto pos = path.find_last_of(PATH_SEPARATOR); - if (pos != std::string::npos) - { - return path.substr(0, pos); - } - else - { - return std::string("."); - } - return path; + if (!setOwnership(path, uid, gid)) { + _ERR("Failed to change owner: %s, (uid: %d, gid: %d)", path.c_str(), uid, gid); + return false; + } + if (!setDirPermissions(path, permissions)) { + _ERR("Failed to change permission: %s, (%d)", path.c_str(), permissions); + return false; + } + return true; } -bool EndWithIgnoreCase(const std::string& str1, const std::string& str2, std::string& filename) +static bool copyOwnershipAndPermissions(const bf::path& path, const bf::path& path2) { - std::string::size_type len1 = str1.length(); - std::string::size_type len2 = str2.length(); - if (len2 > len1) return false; + if (!exist(path)) { + _ERR("Failed to copy ownership and permissions from %s to %s", path.c_str(), path2.c_str()); + return false; + } + bs::error_code error; + bf::perms permissions = bf::status(path, error).permissions(); + if (error) { + _ERR("Failed to copy ownership and permissions : %s", error.message().c_str()); + return false; + } + struct stat stats; + if (stat(path.c_str(), &stats) != 0) { + return false; + } + if (!setDirOwnershipAndPermissions(path2, permissions, stats.st_uid, stats.st_gid)) { + _ERR("Failed to copy ownership and permissions from %s to %s", path.c_str(), path2.c_str()); + return false; + } + return true; +} - int i = 0; - bool result = std::all_of(str1.cend() - len2, str1.end(), - [&i, &str2] (char x) { - return std::tolower(x) == std::tolower(str2[i++]); - }); - if (result) - { - filename = str1.substr(0, len1 - len2); - } - return result; +bool exist(const bf::path& path) +{ + bs::error_code error; + int ret = bf::exists(path, error); + if (error) { + if ((error.value() != bs::errc::success) && (error.value() != bs::errc::no_such_file_or_directory)) { + _ERR("Failed to check %s exists : %s", path.c_str(), error.message().c_str()); + } + } + return ret; } -bool FileNotExist(const std::string& path) +bool createDir(const bf::path& path) { - struct stat sb; - return stat(path.c_str(), &sb) != 0; + if (exist(path)) { + return true; + } + bs::error_code error; + bf::create_directories(path, error); + if (error) { + _ERR("Failed to create directory: %s", error.message().c_str()); + return false; + } + return true; +} + +bool copyDir(const bf::path& path1, const bf::path& path2, FSFlag flags) +{ + try { + // Check whether the function call is valid + if (!exist(path1) || !bf::is_directory(path1)) { + _ERR("Source directory %s does not exist or is not a directory", path1.c_str()); + return false; + } + if (!exist(path2)) { + // Create the destination directory + if (!createDir(path2)) { + _ERR("Unable to create destination directory %s", path2.c_str()); + return false; + } + if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS) { + copyOwnershipAndPermissions(path1, path2); + } + } else { + if (!(flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE))) { + _ERR("Destination directory %s already exists", path2.c_str()); + return false; + } + if (flags & (FS_MERGE_OVERWRITE | FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS)) { + copyOwnershipAndPermissions(path1, path2); + } + } + } catch (const bf::filesystem_error& error) { + _ERR("Failed to copy directory: %s", error.what()); + return false; + } + + // Iterate through the source directory + try { + for (bf::directory_iterator file(path1); file != bf::directory_iterator(); ++file) { + bf::path current(file->path()); + bf::path target = path2 / current.filename(); + if (bf::is_symlink(bf::symlink_status(current))) { + if ((flags & (FS_MERGE_SKIP | FS_MERGE_OVERWRITE)) && exist(target)) { + continue; + } + bs::error_code error; + bf::copy_symlink(current, target, error); + if (error) { + _ERR("Failed to copy symlink: %s, %s", current.c_str(), error.message().c_str()); + return false; + } + } else if (bf::is_directory(current)) { + // Found directory: Recursion + if (!copyDir(current, target, flags)) { + return false; + } + } else { + if ((flags & FS_MERGE_SKIP) && exist(target)) { + continue; + } + bf::path destination = target; + if (flags & FS_COMMIT_COPY_FILE) { + destination = bf::unique_path(target.parent_path() / "%%%%-%%%%-%%%%-%%%%"); + } + if (flags & FS_MERGE_OVERWRITE) { + bf::copy_file(current, destination, bf::copy_option::overwrite_if_exists); + } else { + bf::copy_file(current, destination); + } + if (flags & FS_PRESERVE_OWNERSHIP_AND_PERMISSIONS) { + copyOwnershipAndPermissions(current, destination); + } + if (flags & FS_COMMIT_COPY_FILE) { + if (flags & FS_MERGE_OVERWRITE) { + bf::remove(target); + } + bf::rename(destination, target); + } + } + } + } catch (const bf::filesystem_error& error) { + _ERR("Failed to copy directory: %s", error.what()); + return false; + } + + return true; +} + +bool copyFile(const bf::path& path1, const bf::path& path2) +{ + bs::error_code error; + if (!exist(path1)) { + return false; + } + bf::copy_file(path1, path2, bf::copy_option::overwrite_if_exists, error); + if (error) { + _ERR("copy file %s due to error [%s]", path1.c_str(), error.message().c_str()); + return false; + } + return true; +} + +bool moveFile(const bf::path& path1, const bf::path& path2) +{ + if (!exist(path1) || exist(path2)) { + return false; + } + bs::error_code error; + bf::rename(path1, path2, error); + if (error) { + _ERR("Cannot move file: %s. Will copy/remove... with error [%s]", path1.c_str(), error.message().c_str()); + bf::copy_file(path1, path2, bf::copy_option::overwrite_if_exists, error); + if (error) { + _ERR("Cannot copy file %s due to error [%s]", path1.c_str(), error.message().c_str()); + return false; + } + bf::remove_all(path1, error); + if (error) { + _ERR("Cannot remove old file when coping: %s with error [%s]", path1.c_str(), error.message().c_str()); + return false; + } + } + return true; +} + +bool removeFile(const bf::path& path) +{ + if (!exist(path)) { + return true; + } + bs::error_code error; + bf::remove(path, error); + if (error) { + _ERR("Cannot remove: %s, %s", path.c_str(), error.message().c_str()); + return false; + } + return true; +} + +bool removeAll(const bf::path& path) +{ + if (!exist(path)) { + return true; + } + bs::error_code error; + bf::remove_all(path, error); + if (error) { + _ERR("Cannot remove: %s, %s", path.c_str(), error.message().c_str()); + return false; + } + return true; +} + +void setCmdName(const std::string& name) +{ + #define PRC_NAME_LENGTH 16 + + char processName[PRC_NAME_LENGTH] = {0, }; + + if (name.empty()) + return; + + memset(processName, '\0', PRC_NAME_LENGTH); + snprintf(processName, PRC_NAME_LENGTH, "%s", name.c_str()); + prctl(PR_SET_NAME, processName); +} + +std::string getFileName(const std::string& path) +{ + std::string ret(path); + size_t index = ret.find_last_of(PATH_SEPARATOR); + return index == std::string::npos ? ret : ret.substr(index + 1); +} + +std::string SHA256(const std::string& path) +{ + int bytesRead = 0; + const int bufSize = 32768; + + unsigned int digest_len = 0; + unsigned char* digest = NULL; + + std::stringstream ss; + EVP_MD_CTX *mdctx = NULL; + std::string output = ""; + + FILE *file = fopen(path.c_str(), "rb"); + if (!file) { + return output; + } + + char *buffer = (char*)malloc(bufSize); + if (!buffer) { + goto cleanup4; + } + + mdctx = EVP_MD_CTX_new(); + if (mdctx == NULL) { + _ERR("Message Digest Context creation NULL"); + goto cleanup3; + } + + digest = (unsigned char*)OPENSSL_malloc(EVP_MD_size(EVP_sha256())); + if (!digest) { + _ERR("Memory Allocation for SHA256 failed"); + goto cleanup2; + } + + if (!EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) { + _ERR("Message Digest init failed"); + goto cleanup1; + } + + while ((bytesRead = fread(buffer, 1, bufSize, file))) { + if (!EVP_DigestUpdate(mdctx, buffer, bytesRead)) { + _ERR("Message Digest update failed"); + goto cleanup1; + } + } + + if (!EVP_DigestFinal_ex(mdctx, digest, &digest_len)) { + _ERR("Message Digest Finalization falied"); + goto cleanup1; + } + + for (unsigned int i = 0; i < digest_len; i++) { + ss << std::hex << std::setw(2) << std::setfill('0') << (int)digest[i]; + } + output = ss.str(); + +cleanup1: + EVP_MD_CTX_free(mdctx); +cleanup2: + OPENSSL_free(digest); +cleanup3: + free(buffer); +cleanup4: + fclose(file); + + return output; +} + +int pkgmgrGetPkgInfo(const std::string& pkgId, pkgmgrinfo_pkginfo_h* handle) +{ + uid_t uid = 0; + int ret = 0; + + if (pkgmgr_installer_info_get_target_uid(&uid) < 0) { + _ERR("Failed to get UID"); + return -1; + } + + ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, handle); + if (ret != PMINFO_R_OK) { + _ERR("Failed to get pkginfo (%d)", ret); + return -1; + } + + return 0; +} + +int pkgmgrGetAppInfo(const std::string& appId, pkgmgrinfo_appinfo_h* handle) +{ + uid_t uid = 0; + int ret = 0; + + if (pkgmgr_installer_info_get_target_uid(&uid) < 0) { + _ERR("Failed to get UID"); + return -1; + } + + ret = pkgmgrinfo_appinfo_get_usr_appinfo(appId.c_str(), uid, handle); + if (ret != PMINFO_R_OK) { + _ERR("Failed to get appinfo (%d)", ret); + return -1; + } + + return 0; +} + +int pkgmgrMDFilterForeach(pkgmgrinfo_appinfo_metadata_filter_h handle, + pkgmgrinfo_app_list_cb app_cb, + void *user_data) +{ + uid_t uid = 0; + int ret = 0; + + if (pkgmgr_installer_info_get_target_uid(&uid) < 0) { + _ERR("Failed to get UID"); + return -1; + } + + + ret = pkgmgrinfo_appinfo_usr_metadata_filter_foreach(handle, app_cb, user_data, uid); + if (ret != PMINFO_R_OK) { + _ERR("Failed to execute the metadata filter query (%d)", ret); + return -1; + } + + return 0; +} + +void printHWClockLog(const char* format, ...) +{ + char buf[1024] = {0,}; + va_list ap; + + va_start(ap, format); + vsnprintf(buf, sizeof(buf), format, ap); + va_end(ap); + + prctl(PR_TASK_PERF_USER_TRACE, buf, strlen(buf)); } -static bool ExtCheckAndGetFileNameIfExist(const std::string& dir, const std::string& ext, struct dirent* entry, std::string& filename) +const char* getNCDBStartupHook() { - std::string fname(entry->d_name); - if (fname.length() < ext.length() || - fname.compare(fname.length() - ext.length(), ext.length(), ext) != 0) - { - return false; - } - std::string fullname = ConcatPath(dir, entry->d_name); - switch (entry->d_type) - { - case DT_REG: break; - case DT_LNK: - case DT_UNKNOWN: - if (FileNotExist(fullname)) - { - return false; - } - default: - return false; - } - - filename = fullname; - - return true; -} - -std::string StripNIDLL(const std::string& path) -{ - std::string npath(path); - if (path.size() < 5) return npath; - if (strncasecmp(path.c_str() + path.size() - 4, ".dll", 4)) - { - npath = path.substr(0, path.size()-4); - }else if (strncasecmp(path.c_str() + path.size() - 4, ".exe", 4)) - { - npath = path.substr(0, path.size()-4); - } - if (strncasecmp(npath.c_str() + npath.size() - 3, ".ni", 3)) - { - return npath.substr(0, npath.size()-3); - } - return npath; + return "/home/owner/share/tmp/sdk_tools/netcoredbg/ncdbhook.dll"; } -std::string JoinStrings(const std::vector& strings, const char* const delimeter) +bool isNCDBStartupHookProvided() { - switch (strings.size()) - { - case 0: - return ""; - case 1: - return strings[0]; - default: - std::ostringstream os; - std::copy(strings.begin(), strings.end()-1, std::ostream_iterator(os, delimeter)); - os << *strings.rbegin(); - return os.str(); - } -} - -struct AssemblyFile -{ - std::string noext; - std::string ext; -}; - -bool operator == (const AssemblyFile& lhs, const AssemblyFile& rhs) -{ - return lhs.noext == rhs.noext && lhs.ext == rhs.ext; -} - -namespace std -{ - template<> - struct hash - { - std::size_t operator () (const AssemblyFile& f) const - { - const std::size_t h1 = std::hash{}(f.noext); - const std::size_t h2 = std::hash{}(f.ext); - - return h1 ^ (h2 << 1); - } - }; -} - -void AssembliesInDirectory(const std::vector& directories, std::string& tpaList) -{ - std::unordered_map addedAssemblies; - - auto reader = [&addedAssemblies] (const char* path) - { - std::string _path(path); - - std::string::size_type dotp = _path.rfind('.'); - std::string ext = dotp != std::string::npos ? _path.substr(dotp) : ""; - std::string noext; - bool ni = false; - - if (IsManagedAssembly(_path)) - { - if (IsNativeImage(_path)) - { - noext = _path.substr(0, _path.size()-7); - ni = true; - } - else - { - noext = _path.substr(0, _path.size()-4); - } - - AssemblyFile f = {noext, ext}; - addedAssemblies[f] = ni; - } - }; - - for (auto directory : directories) - { - ScanFilesInDir(directory.c_str(), reader, 1); - } - - for (auto kv : addedAssemblies) - { - tpaList += kv.first.noext + (kv.second ? ".ni" : "") + kv.first.ext + ':'; - } - - if (tpaList.back() == ':') - tpaList.pop_back(); -} - -void ScanFilesInDir(const char* directory, FileReader reader, unsigned int depth) -{ - DIR *dir; - struct dirent* entry; - bool isDir; - - dir = opendir(directory); - - if (dir == nullptr) - { - //_ERR("Can not open directory : %s", directory); - return; - } - - std::vector innerDirectories; - - while ((entry = readdir(dir)) != nullptr) - { - isDir = false; - std::string path = ConcatPath(directory, entry->d_name); - switch (entry->d_type) - { - case DT_REG: break; - case DT_DIR: - isDir = true; - break; - case DT_LNK: - case DT_UNKNOWN: - struct stat sb; - if (stat(path.c_str(), &sb) == -1) - { - continue; - } - - if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode)) - { - break; - } - default: - continue; - } - if (!isDir) - { - reader(path.c_str()); - } - else if (depth > 1 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) - { - innerDirectories.push_back(path); - } - } - - if (depth != 0) - { - for (auto& d : innerDirectories) - { - ScanFilesInDir(d.c_str(), reader, depth-1); - } - } - - closedir(dir); + char *env = nullptr; + env = getenv("DOTNET_STARTUP_HOOKS"); + if (env == nullptr) + return false; + + // Note, `DOTNET_STARTUP_HOOKS` env could provide list of dlls with ':' delimiter, + // for example: "/path1/name1.dll:/path2/name2.dll" + while (*env != '\0') + { + const char *ncdbCur = getNCDBStartupHook(); + while (*ncdbCur != '\0' && *env != '\0' && *env != ':') + { + if (*ncdbCur != *env) + break; + + ncdbCur++; + env++; + + if (*ncdbCur == '\0' && (*env == '\0' || *env == ':')) + return true; + } + while (*env != '\0' && *env != ':') + { + env++; + } + if (*env == ':') + env++; + } + + return false; }