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(
"-w,--write-config",
"Write config file and exit")
261 ->configurable(false)
263 ->type_name("[configfile]")
264 ->check(!CLI::ExistingDirectory)
265 ->expected(0, 1);
266
268 "-k,--kill",
269 "Kill running daemon")
270 ->configurable(false)
271 ->disable_flag_override();
272
274 "-i,--instance-alias",
275 "Make an instance also known as an alias in configuration files")
276 ->configurable(false)
277 ->type_name("instance=instance_alias [instance=instance_alias [...]]")
278 ->each([](const std::string& item) {
279 const auto it = item.find('=');
280 if (it != std::string::npos) {
281 aliases[item.substr(0, it)] = item.substr(it + 1);
282 } else {
283 throw CLI::ConversionError("Can not convert '" + item + "' to a 'instance=instance_alias' pair");
284 }
285 });
286
288
290 "-l,--log-level",
291 "Log level")
292 ->default_val(4)
293 ->type_name("level")
294 ->check(CLI::Range(0, 6))
295 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
296
298 "-v,--verbose-level",
299 "Verbose level")
300 ->default_val(2)
301 ->type_name("level")
302 ->check(CLI::Range(0, 10))
303 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
304
306 "-q{true},!-u,--quiet{true}",
307 "Quiet mode")
308 ->default_val("false")
309 ->type_name("bool")
310 ->check(CLI::IsMember({"true", "false"}))
311 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
312
314 "--log-file",
315 "Log file path")
317 ->type_name("logfile")
318 ->check(!CLI::ExistingDirectory)
319 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
320
322 "-e{true},!-n,--enforce-log-file{true}",
323 "Enforce writing of logs to file for foreground applications")
324 ->default_val("false")
325 ->type_name("bool")
326 ->check(CLI::IsMember({"true", "false"}))
327 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
328
330 "-d{true},!-f,--daemonize{true}",
331 "Start application as daemon")
332 ->default_val("false")
333 ->type_name("bool")
334 ->check(CLI::IsMember({"true", "false"}))
335 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
336
338 "--user-name",
339 "Run daemon under specific user permissions")
340 ->default_val(pw->pw_name)
341 ->type_name("username")
343 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
344
346 "--group-name",
347 "Run daemon under specific group permissions")
348 ->default_val(gr->gr_name)
349 ->type_name("groupname")
351 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
352
354
355 app->set_version_flag(
"--version",
"1.0-rc1",
"Framework version");
357 }
358
359 return proceed;
360 }
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