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