| 1 | /* |
| 2 | * Copyright Andrey Semashev 2016. |
| 3 | * Distributed under the Boost Software License, Version 1.0. |
| 4 | * (See accompanying file LICENSE_1_0.txt or copy at |
| 5 | * http://www.boost.org/LICENSE_1_0.txt) |
| 6 | */ |
| 7 | /*! |
| 8 | * \file posix/object_name.cpp |
| 9 | * \author Andrey Semashev |
| 10 | * \date 06.03.2016 |
| 11 | * |
| 12 | * \brief This header is the Boost.Log library implementation, see the library documentation |
| 13 | * at http://www.boost.org/doc/libs/release/libs/log/doc/html/index.html. |
| 14 | */ |
| 15 | |
| 16 | #include <boost/log/detail/config.hpp> |
| 17 | #include <unistd.h> |
| 18 | #include <sys/types.h> |
| 19 | #if defined(__ANDROID__) && (__ANDROID_API__+0) < 21 |
| 20 | #include <sys/syscall.h> |
| 21 | #endif |
| 22 | #if !defined(BOOST_LOG_NO_GETPWUID_R) |
| 23 | #include <pwd.h> |
| 24 | #endif |
| 25 | #include <cstddef> |
| 26 | #include <cstring> |
| 27 | #include <limits> |
| 28 | #include <string> |
| 29 | #include <vector> |
| 30 | #include <boost/move/utility_core.hpp> |
| 31 | #include <boost/type_traits/make_unsigned.hpp> |
| 32 | #include <boost/spirit/include/karma_uint.hpp> |
| 33 | #include <boost/spirit/include/karma_generate.hpp> |
| 34 | #include <boost/log/utility/ipc/object_name.hpp> |
| 35 | #include <boost/log/detail/header.hpp> |
| 36 | |
| 37 | namespace karma = boost::spirit::karma; |
| 38 | |
| 39 | namespace boost { |
| 40 | |
| 41 | BOOST_LOG_OPEN_NAMESPACE |
| 42 | |
| 43 | namespace ipc { |
| 44 | |
| 45 | BOOST_LOG_ANONYMOUS_NAMESPACE { |
| 46 | |
| 47 | #if defined(__ANDROID__) && (__ANDROID_API__+0) < 21 |
| 48 | // Until Android API version 21 NDK does not define getsid wrapper in libc, although there is the corresponding syscall |
| 49 | inline pid_t getsid(pid_t pid) BOOST_NOEXCEPT |
| 50 | { |
| 51 | return static_cast< pid_t >(::syscall(__NR_getsid, pid)); |
| 52 | } |
| 53 | #endif |
| 54 | |
| 55 | //! Formats an integer identifier into the string |
| 56 | template< typename Identifier > |
| 57 | inline void format_id(Identifier id, std::string& str) |
| 58 | { |
| 59 | // Note: in the code below, avoid involving locale for string formatting to make sure the names are as stable as possible |
| 60 | typedef typename boost::make_unsigned< Identifier >::type unsigned_id_t; |
| 61 | char buf[std::numeric_limits< unsigned_id_t >::digits10 + 2]; |
| 62 | char* p = buf; |
| 63 | |
| 64 | typedef karma::uint_generator< unsigned_id_t, 10 > unsigned_id_gen; |
| 65 | karma::generate(p, unsigned_id_gen(), static_cast< unsigned_id_t >(id)); |
| 66 | str.append(buf, p); |
| 67 | } |
| 68 | |
| 69 | //! Returns a prefix string for a shared resource according to the scope |
| 70 | std::string get_scope_prefix(object_name::scope ns) |
| 71 | { |
| 72 | std::string prefix = "/boost.log." ; |
| 73 | switch (ns) |
| 74 | { |
| 75 | case object_name::process_group: |
| 76 | { |
| 77 | prefix.append(s: "pgid." ); |
| 78 | #if !defined(BOOST_LOG_NO_GETPGRP) |
| 79 | format_id(id: getpgrp(), str&: prefix); |
| 80 | #else |
| 81 | format_id(getuid(), prefix); |
| 82 | #endif |
| 83 | } |
| 84 | break; |
| 85 | |
| 86 | case object_name::session: |
| 87 | { |
| 88 | prefix.append(s: "sid." ); |
| 89 | #if !defined(BOOST_LOG_NO_GETSID) |
| 90 | format_id(id: getsid(pid: 0), str&: prefix); |
| 91 | #else |
| 92 | format_id(getuid(), prefix); |
| 93 | #endif |
| 94 | } |
| 95 | break; |
| 96 | |
| 97 | case object_name::user: |
| 98 | { |
| 99 | const uid_t uid = getuid(); |
| 100 | |
| 101 | #if !defined(BOOST_LOG_NO_GETPWUID_R) |
| 102 | long limit = sysconf(_SC_GETPW_R_SIZE_MAX); |
| 103 | if (limit <= 0) |
| 104 | limit = 65536; |
| 105 | std::vector< char > string_storage; |
| 106 | string_storage.resize(new_size: static_cast< std::size_t >(limit)); |
| 107 | passwd pwd = {}, *result = NULL; |
| 108 | |
| 109 | try |
| 110 | { |
| 111 | const int err = getpwuid_r(uid: uid, resultbuf: &pwd, buffer: &string_storage[0], buflen: string_storage.size(), result: &result); |
| 112 | if (err == 0 && result && result->pw_name) |
| 113 | { |
| 114 | prefix += "user." ; |
| 115 | prefix += result->pw_name; |
| 116 | } |
| 117 | else |
| 118 | { |
| 119 | prefix += "uid." ; |
| 120 | format_id(id: uid, str&: prefix); |
| 121 | } |
| 122 | |
| 123 | // Avoid leaving sensitive data in memory, if there is any |
| 124 | std::memset(s: &pwd, c: 0, n: sizeof(pwd)); |
| 125 | std::memset(s: &string_storage[0], c: 0, n: string_storage.size()); |
| 126 | } |
| 127 | catch (...) |
| 128 | { |
| 129 | std::memset(s: &pwd, c: 0, n: sizeof(pwd)); |
| 130 | std::memset(s: &string_storage[0], c: 0, n: string_storage.size()); |
| 131 | throw; |
| 132 | } |
| 133 | #else |
| 134 | prefix += "uid." ; |
| 135 | format_id(uid, prefix); |
| 136 | #endif |
| 137 | } |
| 138 | break; |
| 139 | |
| 140 | default: |
| 141 | prefix += "global" ; |
| 142 | break; |
| 143 | } |
| 144 | |
| 145 | prefix.push_back(c: '.'); |
| 146 | |
| 147 | return BOOST_LOG_NRVO_RESULT(prefix); |
| 148 | } |
| 149 | |
| 150 | } // namespace |
| 151 | |
| 152 | //! Constructor from the object name |
| 153 | BOOST_LOG_API object_name::object_name(scope ns, const char* str) : |
| 154 | m_name(get_scope_prefix(ns) + str) |
| 155 | { |
| 156 | } |
| 157 | |
| 158 | //! Constructor from the object name |
| 159 | BOOST_LOG_API object_name::object_name(scope ns, std::string const& str) : |
| 160 | m_name(get_scope_prefix(ns) + str) |
| 161 | { |
| 162 | } |
| 163 | |
| 164 | } // namespace ipc |
| 165 | |
| 166 | BOOST_LOG_CLOSE_NAMESPACE // namespace log |
| 167 | |
| 168 | } // namespace boost |
| 169 | |
| 170 | #include <boost/log/detail/footer.hpp> |
| 171 | |