136 {
137 bool proceed = true;
138
141
143
144 uid_t euid = 0;
145 struct passwd* pw = nullptr;
146 struct group* gr = nullptr;
147
148 if ((pw = getpwuid(getuid())) == nullptr) {
149 proceed = false;
150 } else if ((gr = getgrgid(pw->pw_gid)) == nullptr) {
151 proceed = false;
152 } else if ((euid = geteuid()) == 0) {
156 } else {
157 const char* homedir = nullptr;
158 if ((homedir = std::getenv("XDG_CONFIG_HOME")) == nullptr) {
159 if ((homedir = std::getenv("HOME")) == nullptr) {
160 homedir = pw->pw_dir;
161 }
162 }
163
164 if (homedir != nullptr) {
166 logDirectory = std::string(homedir) +
"/.local/log/snode.c";
167 pidDirectory = std::string(homedir) +
"/.local/run/snode.c";
168 } else {
169 proceed = false;
170 }
171 }
172
175 std::filesystem::permissions(
177 (std::filesystem::perms::owner_all | std::filesystem::perms::group_read | std::filesystem::perms::group_exec) &
178 ~std::filesystem::perms::others_all);
179 if (geteuid() == 0) {
180 struct group* gr = nullptr;
181 if ((gr = getgrnam(
XSTR(GROUP_NAME))) !=
nullptr) {
183 std::cout <<
"Warning: Can not set group ownership of '" <<
configDirectory
184 << "' to 'snodec':" << strerror(errno) << std::endl;
185 }
186 } else {
187 std::cout << "Error: Can not find group 'snodec'. Add it using groupadd or addgroup" << std::endl;
188 std::cout << " and add the current user to this group." << std::endl;
190 proceed = false;
191 }
192 }
193 } else {
194 std::cout <<
"Error: Can not create directory '" <<
configDirectory <<
"'" << std::endl;
195 proceed = false;
196 }
197 }
198
199 if (proceed && !std::filesystem::exists(
logDirectory)) {
200 if (std::filesystem::create_directories(
logDirectory)) {
202 (std::filesystem::perms::owner_all | std::filesystem::perms::group_all) &
203 ~std::filesystem::perms::others_all);
204 if (geteuid() == 0) {
205 struct group* gr = nullptr;
206 if ((gr = getgrnam(
XSTR(GROUP_NAME))) !=
nullptr) {
207 if (chown(
logDirectory.c_str(), euid, gr->gr_gid) < 0) {
208 std::cout <<
"Warning: Can not set group ownership of '" <<
logDirectory <<
"' to 'snodec':" << strerror(errno)
209 << std::endl;
210 }
211 } else {
212 std::cout << "Error: Can not find group 'snodec'. Add it using groupadd or addgroup" << std::endl;
213 std::cout << " and add the current user to this group." << std::endl;
215 proceed = false;
216 }
217 }
218 } else {
219 std::cout <<
"Error: Can not create directory '" <<
logDirectory <<
"'" << std::endl;
220 proceed = false;
221 }
222 }
223
224 if (proceed && !std::filesystem::exists(
pidDirectory)) {
225 if (std::filesystem::create_directories(
pidDirectory)) {
227 (std::filesystem::perms::owner_all | std::filesystem::perms::group_all) &
228 ~std::filesystem::perms::others_all);
229 if (geteuid() == 0) {
230 struct group* gr = nullptr;
231 if ((gr = getgrnam(
XSTR(GROUP_NAME))) !=
nullptr) {
232 if (chown(
pidDirectory.c_str(), euid, gr->gr_gid) < 0) {
233 std::cout <<
"Warning: Can not set group ownership of '" <<
pidDirectory <<
"' to 'snodec':" << strerror(errno)
234 << std::endl;
235 }
236 } else {
237 std::cout << "Error: Can not find group 'snodec'. Add it using groupadd or addgroup." << std::endl;
238 std::cout << " and add the current user to this group." << std::endl;
240 proceed = false;
241 }
242 }
243 } else {
244 std::cout <<
"Error: Can not create directory '" <<
pidDirectory <<
"'" << std::endl;
245 proceed = false;
246 }
247 }
248
249 if (proceed) {
251
253 "' powered by SNode.C\n"
254 "(C) 2020-2025 Volker Christian <me@vchrist.at>\n"
255 "https://github.com/SNodeC/snode.c");
256
258 "-c,--config-file",
260 "Read a config file",
261 false)
262 ->take_all()
263 ->type_name("configfile")
264 ->check(!CLI::ExistingDirectory);
265
266 app->add_option(
"-w,--write-config",
"Write config file and exit")
267 ->configurable(false)
269 ->type_name("configfile")
270 ->check(!CLI::ExistingDirectory)
271 ->expected(0, 1);
272
274 "-k,--kill",
275 "Kill running daemon")
276 ->configurable(false)
277 ->disable_flag_override();
278
280 "-i,--instance-alias",
281 "Make an instance also known as an alias in configuration files")
282 ->configurable(false)
283 ->type_name("instance=instance_alias [instance=instance_alias [...]]")
284 ->each([](const std::string& item) {
285 const auto it = item.find('=');
286 if (it != std::string::npos) {
287 aliases[item.substr(0, it)] = item.substr(it + 1);
288 } else {
289 throw CLI::ConversionError("Can not convert '" + item + "' to a 'instance=instance_alias' pair");
290 }
291 });
292
294
296 "-l,--log-level",
297 "Log level")
298 ->default_val(4)
299 ->type_name("level")
300 ->check(CLI::Range(0, 6))
301 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
302
304 "-v,--verbose-level",
305 "Verbose level")
306 ->default_val(2)
307 ->type_name("level")
308 ->check(CLI::Range(0, 10))
309 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
310
312 "-q{true},!-u,--quiet{true}",
313 "Quiet mode")
314 ->default_val("false")
315 ->type_name("bool")
316 ->check(CLI::IsMember({"true", "false"}))
317 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
318
320 "--log-file",
321 "Log file path")
323 ->type_name("logfile")
324 ->check(!CLI::ExistingDirectory)
325 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
326
328 "-e{true},!-n,--enforce-log-file{true}",
329 "Enforce writing of logs to file for foreground applications")
330 ->default_val("false")
331 ->type_name("bool")
332 ->check(CLI::IsMember({"true", "false"}))
333 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
334
336 "-d{true},!-f,--daemonize{true}",
337 "Start application as daemon")
338 ->default_val("false")
339 ->type_name("bool")
340 ->check(CLI::IsMember({"true", "false"}))
341 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
342
344 "--user-name",
345 "Run daemon under specific user permissions")
346 ->default_val(pw->pw_name)
347 ->type_name("username")
349 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
350
352 "--group-name",
353 "Run daemon under specific group permissions")
354 ->default_val(gr->gr_name)
355 ->type_name("groupname")
357 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
358
360
361 app->set_version_flag(
"--version",
"1.0-rc1",
"Framework version");
363 }
364
365 return proceed;
366 }
static CLI::Option * enforceLogFileOpt
static std::string configDirectory
static std::string logDirectory
static CLI::Option * quietOpt