-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsys_util.h
164 lines (133 loc) · 4.72 KB
/
sys_util.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright (c) 2022, Eugene Gershnik
// SPDX-License-Identifier: BSD-3-Clause
#ifndef HEADER_SYS_UTIL_H_INCLUDED
#define HEADER_SYS_UTIL_H_INCLUDED
inline sys_string to_urn(const Uuid & val) {
std::array<char, 36> buf;
val.to_chars(buf, Uuid::lowercase);
sys_string_builder builder;
builder.reserve_storage(46);
builder.append(S("urn:uuid:"));
builder.append(buf.data(), buf.size());
return builder.build();
}
inline sys_string to_sys_string(const Uuid & val) {
std::array<char, 36> buf;
val.to_chars(buf, Uuid::lowercase);
return sys_string(buf.data(), buf.size());
}
class Identity {
public:
Identity(uid_t uid, gid_t gid) : m_data(uid, gid) {
}
static auto my() -> Identity {
return Identity(getuid(), getgid());
}
static auto myEffective() -> Identity {
return Identity(geteuid(), getegid());
}
static auto admin() -> Identity {
#ifdef ADMIN_GROUP_NAME
auto adminGroup = ptl::Group::getByName(ADMIN_GROUP_NAME);
return Identity(0, adminGroup ? adminGroup->gr_gid: 0);
#else
return Identity(0, 0);
#endif
}
#if CAN_CREATE_USERS
static auto createDaemonUser(const sys_string & name) -> Identity;
#endif
void setMyIdentity() const {
ptl::setGroups({});
ptl::setGid(gid());
ptl::setUid(uid());
}
auto uid() const -> uid_t { return m_data.first; }
auto gid() const -> gid_t { return m_data.second; }
private:
std::pair<uid_t, gid_t> m_data;
};
#if HAVE_SYSTEMD
class SystemdLevelFormatter : public spdlog::custom_flag_formatter
{
public:
void format(const spdlog::details::log_msg & msg, const std::tm &, spdlog::memory_buf_t & dest) override
{
std::string_view level;
switch(msg.level) {
case SPDLOG_LEVEL_CRITICAL: level = SD_CRIT; break;
case SPDLOG_LEVEL_ERROR: level = SD_ERR; break;
case SPDLOG_LEVEL_WARN: level = SD_WARNING; break;
case SPDLOG_LEVEL_INFO: level = SD_INFO; break;
default: level = SD_DEBUG; break;
}
dest.append(level.data(), level.data() + level.size());
}
std::unique_ptr<custom_flag_formatter> clone() const override
{
return spdlog::details::make_unique<SystemdLevelFormatter>();
}
};
#endif
#if HAVE_OS_LOG
class OsLogHandle {
public:
static auto get() noexcept -> os_log_t {
if (!s_handle)
s_handle = os_log_create(WSDDN_BUNDLE_IDENTIFIER, s_category);
return s_handle;
}
static void resetInChild() noexcept {
if (s_handle) {
os_release(s_handle);
s_handle = nullptr;
s_category = "child";
}
}
private:
static os_log_t s_handle;
static const char * s_category;
};
template<typename Mutex>
class OsLogSink : public spdlog::sinks::base_sink<Mutex>
{
using super = spdlog::sinks::base_sink<Mutex>;
protected:
void sink_it_(const spdlog::details::log_msg& msg) override {
spdlog::memory_buf_t formatted;
super::formatter_->format(msg, formatted);
formatted.append(std::array{'\0'});
os_log_type_t type;
switch(msg.level) {
case SPDLOG_LEVEL_CRITICAL: type = OS_LOG_TYPE_FAULT; break;
case SPDLOG_LEVEL_ERROR: type = OS_LOG_TYPE_ERROR; break;
case SPDLOG_LEVEL_WARN: type = OS_LOG_TYPE_DEFAULT; break;
case SPDLOG_LEVEL_INFO: type = OS_LOG_TYPE_INFO; break;
default: type = OS_LOG_TYPE_DEBUG; break;
}
os_log_with_type(OsLogHandle::get(), type, "%{public}s", formatted.data());
}
void flush_() override {
}
};
#endif
inline void createMissingDirs(const std::filesystem::path & path, mode_t mode,
std::optional<Identity> owner) {
auto absPath = absolute(path);
auto start = absPath.root_path();
auto it = absPath.begin();
std::advance(it, std::distance(start.begin(), start.end()));
for(auto end = absPath.end(); it != end; ++it) {
start /= *it;
//we need this check because makeDirectory might fail with things
//other than EEXIST like permissions
if (exists(start))
continue;
ptl::AllowedErrors<EEXIST> ec; //but we also need this exception to avoid TOCTOU, sigh
ptl::makeDirectory(start, mode, ec);
ptl::changeMode(start, mode);
if (owner)
ptl::changeOwner(start, owner->uid(), owner->gid());
}
}
#endif