<commit_before>// bdls_processutil.cpp                                               -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bdls_processutil.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bdls_processutil_cpp,"$Id$ $CSID$")

#include <bdls_filesystemutil.h>
#include <bdls_pathutil.h>

#include <bdlsb_fixedmemoutstreambuf.h>

#include <bslma_allocator.h>
#include <bslmf_assert.h>
#include <bsls_assert.h>
#include <bsls_atomicoperations.h>
#include <bsls_log.h>
#include <bsls_platform.h>

#include <bsl_algorithm.h>
#include <bsl_cstdio.h>
#include <bsl_cstdlib.h>
#include <bsl_iostream.h>

#include <sys/types.h>        // must precede 'stat.h'
#include <sys/stat.h>         // 'stat'

#if defined BSLS_PLATFORM_OS_UNIX
# include <limits.h>           // 'PATH_MAX'
# include <unistd.h>           // 'getpid'

# if defined BSLS_PLATFORM_OS_AIX
#   include <bslmf_assert.h>
#   include <sys/procfs.h>
#   include <procinfo.h>
# elif defined BSLS_PLATFORM_OS_DARWIN
#   include <libproc.h>
# elif defined BSLS_PLATFORM_OS_LINUX
#   include <bslma_deallocatorguard.h>
#   include <bsls_types.h>
#   include <errno.h>            // ::program_invocation_name
# elif defined BSLS_PLATFORM_OS_SOLARIS
#   include <bsl_fstream.h>
# else
#   error Unrecognized Platform
# endif
#else    // if defined BSLS_PLATFORM_OS_WINDOWS
# include <bdlde_charconvertutf16.h>
# include <windows.h>
#endif

namespace {
namespace u {

using namespace BloombergLP;

// This macro is equivalent to calling 'BSLS_LOG_ERROR(...)', except that it
// uses a static atomic int to only emit one trace per process.

#define U_LOG_ERROR_ONCE(...)                                                 \
    do {                                                                      \
        static bsls::AtomicOperations::AtomicTypes::Int done = { 0 };         \
        if (0 == bsls::AtomicOperations::testAndSwapInt(&done, 0, 1)) {       \
            if (bsls::LogSeverity::e_ERROR <=                                 \
                                            bsls::Log::severityThreshold()) { \
                bsls::Log::logFormattedMessage(bsls::LogSeverity::e_ERROR,    \
                                               __FILE__,                      \
                                               __LINE__,                      \
                                               __VA_ARGS__);                  \
            }                                                                 \
        }                                                                     \
    } while (false)

static
const char *doesProcExist()
    // Return a ptr to a string describing whether "/proc" exists or not.
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    return "";
#else
    return bdls::FilesystemUtil::isDirectory("/proc", true)
                                                 ? "\"/proc\" exists."
                                                 : "\"/proc\" does not exist.";
#endif
}

static inline
int getPid()
    // Return the process id.  Having this be separate from 'Obj::getProcessId'
    // allows us to call it inline within the component.
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    return static_cast<int>(GetCurrentProcessId());
#else
    return static_cast<int>(::getpid());
#endif
}

static inline
bool isExecutable(const char *path)
    // On Unix, return 'true' if the file at the specified 'path' exists, is
    // not a directory, and is executable (or is a symbolic link to such a
    // file) and 'false' otherwise.  On Windows, return 'true' if the file
    // exists and is not a directory.
{
#if defined BSLS_PLATFORM_OS_UNIX
    const int executableBits = S_IXUSR | S_IXGRP | S_IXOTH;

# if defined(BSLS_PLATFORM_OS_CYGWIN) || \
    (defined(BSLS_PLATFORM_OS_DARWIN) && defined(_DARWIN_FEATURE_64_BIT_INODE))
    struct stat s;
    int rc = ::stat(path, &s);
# else
    struct stat64 s;
    int rc = ::stat64(path, &s);
# endif
#else    // Windows
    const int executableBits = S_IEXEC;

    struct _stati64 s;
    int rc = ::_stati64(path, &s);
#endif

    return 0 == rc && !(s.st_mode & S_IFDIR) && (s.st_mode & executableBits);
}

static inline
bool isExecutable(const bsl::string& path)
{
    return isExecutable(path.c_str());
}

#if defined(BSLS_PLATFORM_OS_UNIX)
static
void resolveSymLinksIfAny(bsl::string *fileName)
    // If the specified 'fileName' is a symlink, resolve it and overwrite
    // 'fileName' with the new value, but only if the new value refers to an
    // executable file.  The behavior is undefined unless '*fileName' is an
    // executable file or a symlink to one.  Note that this will only write
    // over 'fileName' if 'fileName' is a link to an executable file.
{
    BSLS_ASSERT_SAFE(isExecutable(*fileName));

    struct stat s;
    int rc = ::lstat(fileName->c_str(), &s);
    if (0 == rc && S_ISLNK(s.st_mode)) {
        // It's a symbolic link.  Resolve it.

#if defined PATH_MAX
        bsl::string linkString(PATH_MAX, '\0');
#else
        bsl::string linkString(4 * 1024, '\0');
#endif

        const char *pLinkString = ::realpath(fileName->c_str(),
                                             &linkString[0]);
        const bsl::size_t len = linkString.find('\0');
        if (0 != pLinkString && 0 < len && bsl::string::npos != len) {
            linkString.resize(len);

            if (isExecutable(linkString)) {
                fileName->assign(linkString);
            }
        }
    }
}
#else
static inline
void resolveSymLinksIfAny(bsl::string *)
    // No symlinks on Windows.  No-op.
{
}
#endif<commit_msg>Fix unused function warning on Darwin (#3831)<commit_after>// bdls_processutil.cpp                                               -*-C++-*-

// ----------------------------------------------------------------------------
//                                   NOTICE
//
// This component is not up to date with current BDE coding standards, and
// should not be used as an example for new development.
// ----------------------------------------------------------------------------

#include <bdls_processutil.h>

#include <bsls_ident.h>
BSLS_IDENT_RCSID(bdls_processutil_cpp,"$Id$ $CSID$")

#include <bdls_filesystemutil.h>
#include <bdls_pathutil.h>

#include <bdlsb_fixedmemoutstreambuf.h>

#include <bslma_allocator.h>
#include <bslmf_assert.h>
#include <bsls_assert.h>
#include <bsls_atomicoperations.h>
#include <bsls_log.h>
#include <bsls_platform.h>

#include <bsl_algorithm.h>
#include <bsl_cstdio.h>
#include <bsl_cstdlib.h>
#include <bsl_iostream.h>

#include <sys/types.h>        // must precede 'stat.h'
#include <sys/stat.h>         // 'stat'

#if defined BSLS_PLATFORM_OS_UNIX
# include <limits.h>           // 'PATH_MAX'
# include <unistd.h>           // 'getpid'

# if defined BSLS_PLATFORM_OS_AIX
#   include <bslmf_assert.h>
#   include <sys/procfs.h>
#   include <procinfo.h>
# elif defined BSLS_PLATFORM_OS_DARWIN
#   include <libproc.h>
# elif defined BSLS_PLATFORM_OS_LINUX
#   include <bslma_deallocatorguard.h>
#   include <bsls_types.h>
#   include <errno.h>            // ::program_invocation_name
# elif defined BSLS_PLATFORM_OS_SOLARIS
#   include <bsl_fstream.h>
# else
#   error Unrecognized Platform
# endif
#else    // if defined BSLS_PLATFORM_OS_WINDOWS
# include <bdlde_charconvertutf16.h>
# include <windows.h>
#endif

namespace {
namespace u {

using namespace BloombergLP;

// This macro is equivalent to calling 'BSLS_LOG_ERROR(...)', except that it
// uses a static atomic int to only emit one trace per process.

#define U_LOG_ERROR_ONCE(...)                                                 \
    do {                                                                      \
        static bsls::AtomicOperations::AtomicTypes::Int done = { 0 };         \
        if (0 == bsls::AtomicOperations::testAndSwapInt(&done, 0, 1)) {       \
            if (bsls::LogSeverity::e_ERROR <=                                 \
                                            bsls::Log::severityThreshold()) { \
                bsls::Log::logFormattedMessage(bsls::LogSeverity::e_ERROR,    \
                                               __FILE__,                      \
                                               __LINE__,                      \
                                               __VA_ARGS__);                  \
            }                                                                 \
        }                                                                     \
    } while (false)

static
const char *doesProcExist()
    // Return a ptr to a string describing whether "/proc" exists or not.
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    return "";
#else
    return bdls::FilesystemUtil::isDirectory("/proc", true)
                                                 ? "\"/proc\" exists."
                                                 : "\"/proc\" does not exist.";
#endif
}

static inline
int getPid()
    // Return the process id.  Having this be separate from 'Obj::getProcessId'
    // allows us to call it inline within the component.
{
#ifdef BSLS_PLATFORM_OS_WINDOWS
    return static_cast<int>(GetCurrentProcessId());
#else
    return static_cast<int>(::getpid());
#endif
}

static inline
bool isExecutable(const char *path)
    // On Unix, return 'true' if the file at the specified 'path' exists, is
    // not a directory, and is executable (or is a symbolic link to such a
    // file) and 'false' otherwise.  On Windows, return 'true' if the file
    // exists and is not a directory.
{
#if defined BSLS_PLATFORM_OS_UNIX
    const int executableBits = S_IXUSR | S_IXGRP | S_IXOTH;

# if defined(BSLS_PLATFORM_OS_CYGWIN) || \
    (defined(BSLS_PLATFORM_OS_DARWIN) && defined(_DARWIN_FEATURE_64_BIT_INODE))
    struct stat s;
    int rc = ::stat(path, &s);
# else
    struct stat64 s;
    int rc = ::stat64(path, &s);
# endif
#else    // Windows
    const int executableBits = S_IEXEC;

    struct _stati64 s;
    int rc = ::_stati64(path, &s);
#endif

    return 0 == rc && !(s.st_mode & S_IFDIR) && (s.st_mode & executableBits);
}

static inline
bool isExecutable(const bsl::string& path)
{
    return isExecutable(path.c_str());
}


#if defined(BSLS_PLATFORM_OS_LINUX)   || \
    defined(BSLS_PLATFORM_OS_AIX)     || \
    defined(BSLS_PLATFORM_OS_SOLARIS)
static
void resolveSymLinksIfAny(bsl::string *fileName)
    // If the specified 'fileName' is a symlink, resolve it and overwrite
    // 'fileName' with the new value, but only if the new value refers to an
    // executable file.  The behavior is undefined unless '*fileName' is an
    // executable file or a symlink to one.  Note that this will only write
    // over 'fileName' if 'fileName' is a link to an executable file.
{
    BSLS_ASSERT_SAFE(isExecutable(*fileName));

    struct stat s;
    int rc = ::lstat(fileName->c_str(), &s);
    if (0 == rc && S_ISLNK(s.st_mode)) {
        // It's a symbolic link.  Resolve it.

#if defined PATH_MAX
        bsl::string linkString(PATH_MAX, '\0');
#else
        bsl::string linkString(4 * 1024, '\0');
#endif

        const char *pLinkString = ::realpath(fileName->c_str(),
                                             &linkString[0]);
        const bsl::size_t len = linkString.find('\0');
        if (0 != pLinkString && 0 < len && bsl::string::npos != len) {
            linkString.resize(len);

            if (isExecutable(linkString)) {
                fileName->assign(linkString);
            }
        }
    }
}
#endif
{'fraction_non_alphanumeric': 0.13413804828289697, 'fraction_numerical': 0.005270316218973139, 'mean_word_length': 1.8335741811175337, 'pattern_counts': {'":': 0, '<': 69, '<?xml version=': 0, '>': 71, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 58, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '111971', 'n_tokens_mistral': 3629, 'n_tokens_neox': 3539, 'n_words': 923}