106 {
107 bool proceed = true;
108
111
113
114 uid_t euid = 0;
115 struct passwd* pw = nullptr;
116 struct group* gr = nullptr;
117
118 if ((pw = getpwuid(getuid())) == nullptr) {
119 proceed = false;
120 } else if ((gr = getgrgid(pw->pw_gid)) == nullptr) {
121 proceed = false;
122 } else if ((euid = geteuid()) == 0) {
126 } else {
127 const char* homedir = nullptr;
128 if ((homedir = std::getenv("XDG_CONFIG_HOME")) == nullptr) {
129 if ((homedir = std::getenv("HOME")) == nullptr) {
130 homedir = pw->pw_dir;
131 }
132 }
133
134 if (homedir != nullptr) {
136 logDirectory = std::string(homedir) +
"/.local/log/snode.c";
137 pidDirectory = std::string(homedir) +
"/.local/run/snode.c";
138 } else {
139 proceed = false;
140 }
141 }
142
145 std::filesystem::permissions(
147 (std::filesystem::perms::owner_all | std::filesystem::perms::group_read | std::filesystem::perms::group_exec) &
148 ~std::filesystem::perms::others_all);
149 if (geteuid() == 0) {
150 struct group* gr = nullptr;
151 if ((gr = getgrnam(
XSTR(GROUP_NAME))) !=
nullptr) {
153 std::cout <<
"Warning: Can not set group ownership of '" <<
configDirectory
154 << "' to 'snodec':" << strerror(errno) << std::endl;
155 }
156 } else {
157 std::cout << "Error: Can not find group 'snodec'. Add it using groupadd or addgroup" << std::endl;
158 std::cout << " and add the current user to this group." << std::endl;
160 proceed = false;
161 }
162 }
163 } else {
164 std::cout <<
"Error: Can not create directory '" <<
configDirectory <<
"'" << std::endl;
165 proceed = false;
166 }
167 }
168
169 if (proceed && !std::filesystem::exists(
logDirectory)) {
170 if (std::filesystem::create_directories(
logDirectory)) {
172 (std::filesystem::perms::owner_all | std::filesystem::perms::group_all) &
173 ~std::filesystem::perms::others_all);
174 if (geteuid() == 0) {
175 struct group* gr = nullptr;
176 if ((gr = getgrnam(
XSTR(GROUP_NAME))) !=
nullptr) {
177 if (chown(
logDirectory.c_str(), euid, gr->gr_gid) < 0) {
178 std::cout <<
"Warning: Can not set group ownership of '" <<
logDirectory <<
"' to 'snodec':" << strerror(errno)
179 << std::endl;
180 }
181 } else {
182 std::cout << "Error: Can not find group 'snodec'. Add it using groupadd or addgroup" << std::endl;
183 std::cout << " and add the current user to this group." << std::endl;
185 proceed = false;
186 }
187 }
188 } else {
189 std::cout <<
"Error: Can not create directory '" <<
logDirectory <<
"'" << std::endl;
190 proceed = false;
191 }
192 }
193
194 if (proceed && !std::filesystem::exists(
pidDirectory)) {
195 if (std::filesystem::create_directories(
pidDirectory)) {
197 (std::filesystem::perms::owner_all | std::filesystem::perms::group_all) &
198 ~std::filesystem::perms::others_all);
199 if (geteuid() == 0) {
200 struct group* gr = nullptr;
201 if ((gr = getgrnam(
XSTR(GROUP_NAME))) !=
nullptr) {
202 if (chown(
pidDirectory.c_str(), euid, gr->gr_gid) < 0) {
203 std::cout <<
"Warning: Can not set group ownership of '" <<
pidDirectory <<
"' to 'snodec':" << strerror(errno)
204 << std::endl;
205 }
206 } else {
207 std::cout << "Error: Can not find group 'snodec'. Add it using groupadd or addgroup." << std::endl;
208 std::cout << " and add the current user to this group." << std::endl;
210 proceed = false;
211 }
212 }
213 } else {
214 std::cout <<
"Error: Can not create directory '" <<
pidDirectory <<
"'" << std::endl;
215 proceed = false;
216 }
217 }
218
219 if (proceed) {
221
223 "' powered by SNode.C\n"
224 "(C) 2020-2025 Volker Christian <me@vchrist.at>\n"
225 "https://github.com/SNodeC/snode.c");
226
228 "-c,--config-file",
230 "Read a config file",
231 false)
232 ->take_all()
233 ->type_name("configfile")
234 ->check(!CLI::ExistingDirectory);
235
236 app->add_option_function<std::string>(
237 "-w,--write-config",
238 []([[maybe_unused]] const std::string& configFile) {
240 },
241 "Write config file and exit")
242 ->configurable(false)
244 ->type_name("[configfile]")
245 ->check(!CLI::ExistingDirectory)
246 ->expected(0, 1);
247
249 "-k,--kill",
250 "Kill running daemon")
251 ->configurable(false)
252 ->disable_flag_override();
253
255 "-i,--instance-alias",
256 "Make an instance also known as an alias in configuration files")
257 ->configurable(false)
258 ->type_name("instance=instance_alias [instance=instance_alias [...]]")
259 ->each([](const std::string& item) {
260 const auto it = item.find('=');
261 if (it != std::string::npos) {
262 aliases[item.substr(0, it)] = item.substr(it + 1);
263 } else {
264 throw CLI::ConversionError("Can not convert '" + item + "' to a 'instance=instance_alias' pair");
265 }
266 });
267
269
271 "-l,--log-level",
272 "Log level")
273 ->default_val(4)
274 ->type_name("level")
275 ->check(CLI::Range(0, 6))
276 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
277
279 "-v,--verbose-level",
280 "Verbose level")
281 ->default_val(2)
282 ->type_name("level")
283 ->check(CLI::Range(0, 10))
284 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
285
287 "-q{true},!-u,--quiet{true}",
288 "Quiet mode")
289 ->default_val("false")
290 ->type_name("bool")
291 ->check(CLI::IsMember({"true", "false"}))
292 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
293
295 "--log-file",
296 "Log file path")
298 ->type_name("logfile")
299 ->check(!CLI::ExistingDirectory)
300 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
301
303 "-e{true},!-n,--enforce-log-file{true}",
304 "Enforce writing of logs to file for foreground applications")
305 ->default_val("false")
306 ->type_name("bool")
307 ->check(CLI::IsMember({"true", "false"}))
308 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
309
311 "-d{true},!-f,--daemonize{true}",
312 "Start application as daemon")
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 "--user-name",
320 "Run daemon under specific user permissions")
321 ->default_val(pw->pw_name)
322 ->type_name("username")
324 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
325
327 "--group-name",
328 "Run daemon under specific group permissions")
329 ->default_val(gr->gr_name)
330 ->type_name("groupname")
332 ->group(
app->get_formatter()->get_label(
"Persistent Options"));
333
335
336 app->set_version_flag(
"--version",
"1.0-rc1",
"Framework version");
338 }
339
340 return proceed;
341 }
static CLI::App * addStandardFlags(CLI::App *app)
static std::string configDirectory
static CLI::Option * groupNameOpt
static CLI::App * addHelp(CLI::App *app)
static CLI::Option * quietOpt
static std::string pidDirectory
static CLI::Option * enforceLogFileOpt
static std::string logDirectory
static CLI::Option * userNameOpt