view misc/executable.cpp @ 563:668975a91fb2

Misc: add executable.cpp, get the executable path
author David Demelier <markand@malikania.fr>
date Tue, 21 Jun 2016 15:55:57 +0200
parents
children f8616f9fc9d5
line wrap: on
line source

#include <string>
#include <stdexcept>

#if defined(__linux__)
#  include <unistd.h>

#  include <cerrno>
#  include <cstring>
#  include <stdexcept>
#elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__OpenBSD__)
#  if defined(__NetBSD__)
#    include <sys/param.h>
#  else
#    include <sys/types.h>
#  endif

#  if defined(__OpenBSD__)
#    include <unistd.h>
#  endif

#  include <sys/sysctl.h>

#  include <array>
#  include <cerrno>
#  include <climits>
#  include <cstddef>
#  include <cstdlib>
#  include <cstring>
#  include <stdexcept>
#elif defined(__APPLE__)
#  include <cerrno>
#  include <cstring>
#  include <libproc.h>
#  include <unistd.h>
#elif defined(_WIN32)
#  include <Windows.h>
#endif

#if defined(__linux__)

std::string executable()
{
    std::string result;

    result.resize(2048, '\0');

    auto size = readlink("/proc/self/exe", &result[0], 2048);

    if (size < 0)
        throw std::runtime_error(std::strerror(errno));

    result.resize(size, '\0');

    return result;
}

#elif defined(__FreeBSD__) || defined(__DragonFly__)

std::string executable()
{
    std::array<int, 4> mib{ CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
    std::string result;
    std::size_t size = PATH_MAX + 1;

    result.resize(size, '\0');

    if (sysctl(mib.data(), 4, &result[0], &size, nullptr, 0) < 0)
        throw std::runtime_error(std::strerror(errno));

    result.resize(size, '\0');

    return result;
}

#elif defined(__APPLE__)

std::string executable()
{
    std::string result;
    std::size_t size = PROC_PIDPATHINFO_MAXSIZE;

    result.resize(size, '\0');

    if ((size = proc_pidpath(getpid(), &result[0], size)) == 0)
        throw std::runtime_error(std::strerror(errno));

    result.resize(size, '\0');

    return result;
}

#elif defined(_WIN32)

std::string executable()
{
    std::string result;
    std::size_t size = PATH_MAX;

    result.resize(size, '\0');

    if (!(size = GetModuleFileNameA(nullptr, &result[0], size)))
        throw std::runtime_error("GetModuleFileName error");

    result.resize(size, '\0');

    return result;
}

#elif defined(__NetBSD__)

std::string executable()
{
        std::string result;

#if defined(KERN_PROC_PATHNAME)
        std::array<int, 4> mib{ CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME };
        std::size_t size = MAXPATHLEN;

        result.resize(size, '\0');

        if (sysctl(mib.data(), 4, &result[0], &size, nullptr, 0) < 0)
            throw std::runtime_error(std::strerror(errno));

        result.resize(size, '\0');
#else
        result.resize(2048, '\0');

        auto size = readlink("/proc/curproc/exe", &result[0], 2048);

        if (size < 0)
            throw std::runtime_error(std::strerror(errno));

        result.resize(size, '\0');
#endif

        return result;
}

#elif defined(__OpenBSD__)

std::string executable()
{
    char **paths, *path;
    std::string result;
    std::size_t len;
    std::array<int, 4> mib{ CTL_KERN, KERN_PROC_ARGS, getpid(), KERN_PROC_ARGV };

    if (sysctl(mib.data(), 4, nullptr, &len, nullptr, 0) == -1)
        throw std::runtime_error(std::strerror(errno));
    if ((paths = static_cast<char **>(malloc(len))) == nullptr)
        throw std::runtime_error(std::strerror(errno));

    sysctl(mib.data(), 4, paths, &len, nullptr, 0);

    if ((path = static_cast<char *>(std::malloc(PATH_MAX + 1))) == nullptr) {
        std::free(paths);
        throw std::runtime_error(std::strerror(errno));
    }

    realpath(paths[0], path);
    result = path;

    std::free(paths);
    std::free(path);

    return result;
}

#else

std::string executable()
{
    // Not supported.
    return "";
}

#endif