bool isNativeImage(const std::string& filePath);
/**
- * @brief find assembly files in the directories
- * @param[in] directories
- * @param[out] ":" seperated assembly path list
+ * @brief Resolve assembly files from directories and append their paths to the given list.
+ * @remark If a native image exists for an assembly in the same directory, it will be used.
+ * If multiple assemblies of the same name exist, the first one will be used.
+ * @param[in] directories list of directories
+ * @param[out] list colon-separated string of assembly paths
*/
-void assembliesInDirectory(const std::vector<std::string>& directories, std::string& tpaList);
+void addAssembliesFromDirectories(const std::vector<std::string>& directories, std::string& list);
/**
- * @brief function pointer for file reader
+ * @brief File search callback
+ * @param[in] path full path to a resolved file
+ * @param[in] filename file name
*/
-typedef std::function<void (const std::string&, const char*)> FileReader;
+typedef std::function<void (const std::string& path, const std::string& filename)> FileReader;
/**
- * @brief scan files in the given directory and run file reader function for that
- * @param[in] directory
- * @param[in] file reader function
- * @param[in] scan depth
+ * @brief Scan all files in the given directory.
+ * @param[in] directory path to a root directory
+ * @param[in] reader callback for iteration
+ * @param[in] depth recursive search depth
*/
-void scanFilesInDir(const std::string& directory, FileReader reader, unsigned int depth);
+void scanFilesInDirectory(const std::string& directory, FileReader reader, unsigned int depth);
/**
* @brief copy smack and ownership.
* @brief change command name of the current process for access via ps command
* @param[in] name
*/
-void setCmdName(const char* name);
+void setCmdName(const std::string& name);
/**
- * @brief get file name from the path
- * @param[in] file path
- * @return return file name if exist otherwise null.
+ * @brief Get the file name from the specified path.
+ * @remark An empty string will be returned if the path string ends with a path separator character.
+ * @param[in] path path to a file
+ * @return a substring after the path separator character
*/
-char* getFileNameFromPath(char* path);
+std::string getFileName(const std::string& path);
#endif /* __UTILS_H__ */
/*
- * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Copyright (c) 2020 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.
* limitations under the License.
*/
-#include "dotnet_launcher.h"
+#include <dlfcn.h>
+#include <string>
+#include "coreclr_host.h"
#include "utils.h"
-#include "log.h"
-using tizen::runtime::dotnetcore::CoreRuntime;
+static const char* CLR_PATH = "/usr/share/dotnet.tizen/netcoreapp";
+static const char* TOOL_PATH = "/home/owner/share/.dotnet/tools";
-int main(int argc, char *argv[])
-{
- _INFO("##### Run in corerun mode #####");
+void DisplayUsage() {
+ fprintf(stdout,
+ "Execute a .NET application or command.\n\n"
+ "Usage: dotnet [options] [path-to-executable] [arguments]\n"
+ "Usage: dotnet [command] [arguments]\n\n"
+ "Options:\n"
+ "-h, --help show this help message\n"
+ "--clr-path <path> path to libcoreclr.so and runtime assemblies\n"
+ "--tool-path <path> path to the tool installation directory\n"
+ "--additionalprobingpath <path> path containing assemblies to probe for\n"
+ "--globalizationinvariant run in globalization invariant mode\n\n"
+ "Commands:\n"
+ "counters monitor or collect performance counters\n"
+ "dump capture or analyze a coredump\n"
+ "gcdump capture a heapdump\n"
+ "trace collect or convert a diagnostic event trace\n");
+}
+
+int main(int argc, const char* argv[]) {
+#ifdef __arm__
+ // libunwind library is used to unwind stack frame, but libunwind for ARM
+ // does not support ARM vfpv3/NEON registers in DWARF format correctly.
+ // Therefore let's disable stack unwinding using DWARF information
+ // See https://github.com/dotnet/runtime/issues/6479
+ //
+ // libunwind use following methods to unwind stack frame.
+ // UNW_ARM_METHOD_ALL 0xFF
+ // UNW_ARM_METHOD_DWARF 0x01
+ // UNW_ARM_METHOD_FRAME 0x02
+ // UNW_ARM_METHOD_EXIDX 0x04
+ putenv(const_cast<char*>("UNW_ARM_UNWIND_METHOD=6"));
+#endif // __arm__
+
+ argv++;
+ argc--;
+
+ if (argc <= 0) {
+ DisplayUsage();
+ return -1;
+ }
+
+ std::string clrFilesPath(CLR_PATH);
+ std::string toolDllsPath(TOOL_PATH);
+
+ std::string managedAssemblyPath;
+ std::string additionalProbingPath;
+ bool globalizationInvariant = false;
+
+ while (argc > 0) {
+ std::string arg(argv[0]);
+
+ if (arg == "-?" || arg == "-h" || arg == "--help") {
+ DisplayUsage();
+ return 0;
+ } else if (arg == "--clr-path" && argc > 1) {
+ clrFilesPath = argv[1];
+ argc--;
+ argv++;
+ } else if (arg == "--tool-path" && argc > 1) {
+ toolDllsPath = argv[1];
+ argc--;
+ argv++;
+ } else if (arg == "--additionalprobingpath" && argc > 1) {
+ additionalProbingPath = absolutePath(argv[1]);
+ argc--;
+ argv++;
+ } else if (arg == "--globalizationinvariant") {
+ globalizationInvariant = true;
+ } else if ((arg == "--runtimeconfig" || arg == "--depsfile") && argc > 1) {
+ // Just for compatibility with corefx tests.
+ // See ParseArguments() in coreclr/hosts/unixcorerun/corerun.cpp.
+ argc--;
+ argv++;
+ } else if (arg.at(0) == '-') {
+ fprintf(stderr, "Unknown option %s.\n", argv[0]);
+ DisplayUsage();
+ return -1;
+ } else if (isManagedAssembly(arg) || isNativeImage(arg)) {
+ if (!isFileExist(arg)) {
+ fprintf(stderr, "The specified file does not exist.\n");
+ return -1;
+ }
+ managedAssemblyPath = arg;
+ argc--;
+ argv++;
+ break;
+ } else if (arg == "exec") {
+ // 'dotnet' and 'dotnet exec' can be alternatively used.
+ } else if (arg == "tool") {
+ fprintf(stderr, "This command is not currently supported.\n");
+ return -1;
+ } else {
+ managedAssemblyPath = toolDllsPath + "/dotnet-" + arg;
+
+ if (isFileExist(managedAssemblyPath + ".ni.dll")) {
+ managedAssemblyPath += ".ni.dll";
+ } else if (isFileExist(managedAssemblyPath + ".dll")) {
+ managedAssemblyPath += ".dll";
+ } else {
+ fprintf(stderr,
+ "Could not execute because dotnet-%s does not exist.\n"
+ "Follow the instructions for tool installation: https://github.com/Samsung/diagnostic-tools\n", argv[0]);
+ return -1;
+ }
+
+ // Implicit compatibility mode for System.CommandLine.
+ std::string termValue(getenv("TERM"));
+ if (termValue == "linux") {
+ setenv("TERM", "xterm", 1);
+ }
+
+ argc--;
+ argv++;
+ break;
+ }
+
+ argc--;
+ argv++;
+ }
+
+ std::string currentExeAbsolutePath = absolutePath("/proc/self/exe");
+ if (currentExeAbsolutePath.empty()) {
+ fprintf(stderr, "Failed to get the current executable's absolute path.\n");
+ return -1;
+ }
- if (argc < 2) {
- _SOUT("No parameter");
+ std::string clrFilesAbsolutePath = absolutePath(clrFilesPath);
+ if (clrFilesAbsolutePath.empty()) {
+ fprintf(stderr, "Failed to resolve the full path to the CLR files.\n");
return -1;
}
- if (!isManagedAssembly(argv[1]) && !isNativeImage(argv[1])) {
- _SOUT("first parameter should be assembly file");
+ std::string managedAssemblyAbsolutePath = absolutePath(managedAssemblyPath);
+ if (managedAssemblyAbsolutePath.empty()) {
+ fprintf(stderr, "Failed to get the managed assembly's absolute path.\n");
return -1;
}
- // remove executable and assembly path form the arguments and pass that to managed code
- int vargc = argc - 2;
- std::vector<char*> vargs;
- for (int i = 0; i < vargc; i++) {
- vargs.push_back(argv[2 + i]);
+ std::string coreclrLibPath(clrFilesAbsolutePath + "/libcoreclr.so");
+ std::string appPath = baseName(managedAssemblyAbsolutePath);
+ std::string nativeDllSearchDirs(appPath);
+ nativeDllSearchDirs += ":" + additionalProbingPath;
+ nativeDllSearchDirs += ":" + clrFilesAbsolutePath;
+
+ std::string tpaList(managedAssemblyAbsolutePath);
+ // For now we don't parse .deps.json file but let application DLLs can override runtime DLLs.
+ std::vector<std::string> tpaDirs = { appPath, additionalProbingPath, clrFilesAbsolutePath };
+ addAssembliesFromDirectories(tpaDirs, tpaList);
+
+ void* coreclrLib = dlopen(coreclrLibPath.c_str(), RTLD_NOW | RTLD_LOCAL);
+ if (coreclrLib == nullptr) {
+ const char* error = dlerror();
+ fprintf(stderr, "dlopen failed to open the libcoreclr.so with error %s\n", error);
+ return -1;
}
- // set command name to assembly file
- char* fileName = getFileNameFromPath(argv[1]);
- setCmdName(fileName);
-
- CoreRuntime* runtime = new CoreRuntime("corerun");
+ coreclr_initialize_ptr initializeCoreCLR = (coreclr_initialize_ptr)dlsym(coreclrLib, "coreclr_initialize");
+ coreclr_execute_assembly_ptr executeAssembly = (coreclr_execute_assembly_ptr)dlsym(coreclrLib, "coreclr_execute_assembly");
+ coreclr_shutdown_ptr shutdownCoreCLR = (coreclr_shutdown_ptr)dlsym(coreclrLib, "coreclr_shutdown");
+
+ if (initializeCoreCLR == nullptr) {
+ fprintf(stderr, "Function coreclr_initialize not found in the libcoreclr.so\n");
+ return -1;
+ } else if (executeAssembly == nullptr) {
+ fprintf(stderr, "Function coreclr_execute_assembly not found in the libcoreclr.so\n");
+ return -1;
+ } else if (shutdownCoreCLR == nullptr) {
+ fprintf(stderr, "Function coreclr_shutdown not found in the libcoreclr.so\n");
+ return -1;
+ }
- // get absolute path of input dll file
- std::string absoluteDllPath = absolutePath(argv[1]);
- std::string absoluteRootPath = baseName(absoluteDllPath);
+ const char* propertyKeys[] = {
+ "TRUSTED_PLATFORM_ASSEMBLIES",
+ "APP_PATHS",
+ "APP_NI_PATHS",
+ "NATIVE_DLL_SEARCH_DIRECTORIES",
+ "System.Globalization.Invariant",
+ };
+ const char* propertyValues[] = {
+ tpaList.c_str(),
+ appPath.c_str(),
+ appPath.c_str(),
+ nativeDllSearchDirs.c_str(),
+ globalizationInvariant ? "true" : "false",
+ };
- if (runtime->initialize(LaunchMode::corerun, false, absoluteRootPath.c_str()) != 0) {
- _SOUT("Failed to initialize");
+ void* hostHandle;
+ unsigned int domainId;
+
+ int st = initializeCoreCLR(
+ currentExeAbsolutePath.c_str(),
+ "dotnet",
+ sizeof(propertyKeys) / sizeof(propertyKeys[0]),
+ propertyKeys,
+ propertyValues,
+ &hostHandle,
+ &domainId);
+
+ if (st < 0) {
+ fprintf(stderr, "coreclr_initialize failed - status: 0x%08x\n", st);
return -1;
}
- // launch application
- if (runtime->launch(fileName, absoluteRootPath.c_str(), absoluteDllPath.c_str(), vargc, &vargs[0])) {
- _SOUT("Failed to launch");
+ // Set the current process's command name.
+ std::string managedAssemblyName = getFileName(managedAssemblyAbsolutePath);
+ setCmdName(managedAssemblyName);
+
+ int exitCode = -1;
+
+ st = executeAssembly(
+ hostHandle,
+ domainId,
+ argc,
+ argv,
+ managedAssemblyAbsolutePath.c_str(),
+ (unsigned int*)&exitCode);
+
+ if (st < 0) {
+ fprintf(stderr, "coreclr_execute_assembly failed - status: 0x%08x\n", st);
+ exitCode = -1;
+ }
+
+ st = shutdownCoreCLR(hostHandle, domainId);
+ if (st < 0) {
+ fprintf(stderr, "coreclr_shutdown failed - status: 0x%08x\n", st);
return -1;
}
- return 0;
+ return exitCode;
}
-
}
// set command name to assembly file
- setCmdName(getFileNameFromPath(standalonePath));
+ setCmdName(getFileName(standalonePath));
// change cmdline from dotnet-launcher to executable path
int cmdlineSize = paddingExist ? APPID_MAX_LENGTH : APPID_MAX_LENGTH - PaddingOption.length();
snprintf(argv[0], cmdlineSize - 1, "%s", standalonePath);
// initialize CoreRuntime (standalone mode enable, dlog redirection enable, root path NULL)
- if (runtime->initialize(LaunchMode::launcher, true, appRootPath) != 0) {
+ if (runtime->initialize(LaunchMode::launcher) != 0) {
_ERR("Failed to initialize");
return -1;
}
}
// initialize CoreRuntime (launchmode, dlog redirection enable, root path NULL)
- if (runtime->initialize(LaunchMode::loader, true, NULL) != 0) {
+ if (runtime->initialize(LaunchMode::loader) != 0) {
_ERR("Failed to initialized");
} else {
_INFO("Success to initialized");
dispose();
}
-int CoreRuntime::initialize(LaunchMode launchMode, bool useDlog, const char* rootPath)
+int CoreRuntime::initialize(LaunchMode launchMode)
{
// checkInjection checks dotnet-launcher run mode
// At the moment, this mechanism is used only when the Memory Profiler is started.
return -1;
}
- if (useDlog && !pluginHasLogControl()) {
+ if (!pluginHasLogControl()) {
if (initializeLogManager() < 0) {
_ERR("Failed to initnialize LogManager");
return -1;
// To avoid gdbus blocking issue, below function should be called after fork()
initEnvForSpecialFolder();
+ __fd = open("/proc/self", O_DIRECTORY);
+ if (__fd < 0) {
+ _ERR("Failed to open /proc/self");
+ return -1;
+ }
+
std::string tpa = getTPA();
std::string runtimeDir = getRuntimeDir();
std::string appName = std::string("dotnet-launcher-") + std::to_string(getpid());
- std::string probePath;
- std::string NIprobePath;
- std::string nativeLibPath;
-
- if (launchMode == LaunchMode::corerun) {
- probePath = rootPath;
- NIprobePath = rootPath;
- nativeLibPath = rootPath;
- } else {
- __fd = open("/proc/self", O_DIRECTORY);
- if (__fd < 0) {
- _ERR("Failed to open /proc/self");
- return -1;
- }
- std::string appRoot = std::string("/proc/self/fd/") + std::to_string(__fd);
- std::string appBin = concatPath(appRoot, "bin");
- std::string appLib = concatPath(appRoot, "lib");
- std::string appTac = concatPath(appBin, TAC_SYMLINK_SUB_DIR);
- probePath = appRoot + ":" + appBin + ":" + appLib + ":" + appTac;
- NIprobePath = concatPath(appBin, APP_NI_SUB_DIR) + ":" + concatPath(appLib, APP_NI_SUB_DIR) + ":" + appTac;
- nativeLibPath = getExtraNativeLibDirs(appRoot) + ":" + appBin + ":" + appLib + ":" + __nativeLibDirectory + ":" + runtimeDir;
- }
+ std::string appRoot = std::string("/proc/self/fd/") + std::to_string(__fd);
+ std::string appBin = concatPath(appRoot, "bin");
+ std::string appLib = concatPath(appRoot, "lib");
+ std::string appTac = concatPath(appBin, TAC_SYMLINK_SUB_DIR);
+ std::string probePath = appRoot + ":" + appBin + ":" + appLib + ":" + appTac;
+ std::string NIprobePath = concatPath(appBin, APP_NI_SUB_DIR) + ":" + concatPath(appLib, APP_NI_SUB_DIR) + ":" + appTac;
+ std::string nativeLibPath = getExtraNativeLibDirs(appRoot) + ":" + appBin + ":" + appLib + ":" + __nativeLibDirectory + ":" + runtimeDir;
if (!initializeCoreClr(appName.c_str(), probePath.c_str(), NIprobePath.c_str(), nativeLibPath.c_str(), tpa.c_str())) {
_ERR("Failed to initialize coreclr");
public:
CoreRuntime(const char* mode);
~CoreRuntime();
- int initialize(LaunchMode mode, bool useDlog, const char* rootPath);
+ int initialize(LaunchMode mode);
void dispose();
int launch(const char* appId, const char* root, const char* path, int argc, char* argv[]);
appPaths.pop_back();
}
- auto convert = [&appPaths, flags](const std::string& path, const char* name) {
+ auto convert = [&appPaths, flags](const std::string& path, const std::string& filename) {
if (strstr(path.c_str(), TAC_SHA_256_INFO) != NULL)
return;
if (!crossgen(path, appPaths.c_str(), flags)) {
}
};
for (auto& nuget : nugets) {
- scanFilesInDir(concatPath(__DOTNET_DIR, nuget), convert, -1);
+ scanFilesInDirectory(concatPath(__DOTNET_DIR, nuget), convert, -1);
}
}
std::vector<std::string> tpaAssemblies;
splitPath(__tpa, tpaAssemblies);
- auto convert = [&appPaths, flags, tpaAssemblies](const std::string& path, const char* name) {
+ auto convert = [&appPaths, flags, tpaAssemblies](const std::string& path, const std::string& filename) {
bool isAppNI = flags & NI_FLAGS_APPNI;
if (isAppNI) {
for (auto& tpa : tpaAssemblies) {
- if (!strcmp(replaceAll(tpa.substr(tpa.rfind('/') + 1), ".ni.dll", ".dll").c_str(), name)) {
- fprintf(stderr, "%s present in the TPA list skips generation of NI file.\n", name);
+ if (!strcmp(replaceAll(tpa.substr(tpa.rfind('/') + 1), ".ni.dll", ".dll").c_str(), filename.c_str())) {
+ fprintf(stderr, "%s present in the TPA list skips generation of NI file.\n", filename.c_str());
return;
}
}
};
for (int i = 0; i < count; i++) {
- scanFilesInDir(rootPaths[i], convert, 1);
+ scanFilesInDirectory(rootPaths[i], convert, 0);
}
tpaAssemblies.clear();
void removeNiUnderDirs(const std::string rootPaths[], int count)
{
- auto convert = [](const std::string& path, std::string name) {
+ auto convert = [](const std::string& path, const std::string& filename) {
if (isNativeImage(path)) {
if (remove(path.c_str())) {
fprintf(stderr, "Failed to remove %s\n", path.c_str());
};
for (int i = 0; i < count; i++) {
- scanFilesInDir(rootPaths[i], convert, -1);
+ scanFilesInDirectory(rootPaths[i], convert, -1);
}
}
std::getline(cacheFile, platform_tpa);
cacheFile.close();
} else {
- std::vector<std::string> tpaDir;
- tpaDir.push_back(getRuntimeDir());
- tpaDir.push_back(getTizenFXDir());
- tpaDir.push_back(getTizenFXRefDir());
- assembliesInDirectory(tpaDir, platform_tpa);
+ std::vector<std::string> tpaDirs = { getRuntimeDir(), getTizenFXDir(), getTizenFXRefDir() };
+ addAssembliesFromDirectories(tpaDirs, platform_tpa);
}
return platform_tpa;
plugin_tpa = plugin_tpa_list;
} else if (!__dllPath->extra_dirs.empty()){
_INFO("plugin extra directory found. use plugin extra directroy for TPA");
- assembliesInDirectory(__dllPath->extra_dirs, plugin_tpa);
+ addAssembliesFromDirectories(__dllPath->extra_dirs, plugin_tpa);
}
return plugin_tpa;
return 0;
}
-std::string stripNiDLL(const std::string& path)
+std::string getAssemblyNameFromPath(const std::string& path)
{
- std::string niPath(path);
- if (path.size() < 5) return niPath;
- if (!strncasecmp(path.c_str() + path.size() - 4, ".dll", 4))
- niPath = path.substr(0, path.size()-4);
- else if (!strncasecmp(path.c_str() + path.size() - 4, ".exe", 4))
- niPath = path.substr(0, path.size()-4);
+ std::string ret(getFileName(path));
- if (!strncasecmp(niPath.c_str() + niPath.size() - 3, ".ni", 3))
- return niPath.substr(0, niPath.size()-3);
+ if (ret.find_last_of(".") == std::string::npos)
+ return ret;
+ ret.erase(ret.find_last_of("."));
- return niPath;
+ if (ret.size() > 3 && std::equal(ret.begin() + ret.size() - 3, ret.end(), ".ni"))
+ ret.erase(ret.size() - 3);
+
+ return ret;
}
-void assembliesInDirectory(const std::vector<std::string>& directories, std::string& tpaList)
-{
- std::map<std::string, std::string> assemblyList;
- std::map<std::string, std::string> tmpList;
-
- auto reader = [&assemblyList, &tmpList] (const std::string& path, const char* name) {
- if (isManagedAssembly(path) || isNativeImage(path)) {
- std::string dllName = stripNiDLL(name);
- std::pair<std::map<std::string, std::string>::iterator, bool> ret;
- ret = tmpList.insert(std::pair<std::string, std::string>(dllName, path));
- if (ret.second == false) {
- if (isNativeImage(path))
- tmpList[dllName] = path;
+void addAssembliesFromDirectories(const std::vector<std::string>& directories, std::string& list) {
+ std::vector<std::string> assems;
+ std::unordered_map<std::string, std::string> 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 (baseName(assemPaths[assem]).compare(baseName(path)) == 0)
+ assemPaths[assem] = path;
}
}
};
+ for (auto& directory : directories)
+ scanFilesInDirectory(directory, reader, 0);
- for (auto directory : directories) {
- scanFilesInDir(directory.c_str(), reader, 1);
- // merge scaned dll list to tpa list.
- // if the dll is already exist in the list, that is skipped.
- assemblyList.insert(tmpList.begin(), tmpList.end());
- }
+ if (!list.empty() && list.back() != ':')
+ list.push_back(':');
- std::map<std::string, std::string>::iterator it;
- for (it = assemblyList.begin(); it != assemblyList.end(); it++)
- tpaList += it->second + ':';
+ for (auto& assem : assems)
+ list += assemPaths[assem] + ":";
- if (tpaList.back() == ':')
- tpaList.pop_back();
+ if (list.back() == ':')
+ list.pop_back();
}
-void scanFilesInDir(const std::string& directory, FileReader reader, unsigned int depth)
+void scanFilesInDirectory(const std::string& directory, FileReader reader, unsigned int depth)
{
DIR *dir;
struct dirent* entry;
}
if (!isDir)
reader(path, entry->d_name);
- else if (depth > 1 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
+ else if (depth > 0 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
innerDirectories.push_back(path);
}
- if (depth != 0)
+ if (depth > 0)
for (auto& d : innerDirectories)
- scanFilesInDir(d.c_str(), reader, depth - 1);
+ scanFilesInDirectory(d, reader, depth - 1);
closedir(dir);
}
return true;
}
-void setCmdName(const char* name)
+void setCmdName(const std::string& name)
{
#define PRC_NAME_LENGTH 16
char processName[PRC_NAME_LENGTH] = {0, };
- if (name == NULL || *name == '\0') {
+ if (name.empty())
return;
- }
memset(processName, '\0', PRC_NAME_LENGTH);
- snprintf(processName, PRC_NAME_LENGTH, "%s", name);
+ snprintf(processName, PRC_NAME_LENGTH, "%s", name.c_str());
prctl(PR_SET_NAME, processName);
}
-char* getFileNameFromPath(char* path)
+std::string getFileName(const std::string& path)
{
- char* fileName = strrchr(path, PATH_SEPARATOR);
- if (fileName != NULL && *fileName != '\0') {
- return ++fileName;
- }
-
- return NULL;
+ std::string ret(path);
+ size_t index = ret.find_last_of(PATH_SEPARATOR);
+ return index == std::string::npos ? ret : ret.substr(index + 1);
}
-