Skip to content

Commit 3340da8

Browse files
committed
core/command: add --daemonize
1 parent 9d21a01 commit 3340da8

File tree

1 file changed

+78
-4
lines changed

1 file changed

+78
-4
lines changed

src/core/main.cpp

Lines changed: 78 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#include "main.hpp"
22
#include <algorithm>
3+
#include <array>
4+
#include <cerrno>
35
#include <cstdio>
46
#include <cstdlib>
57
#include <limits>
@@ -8,6 +10,7 @@
810
#include <CLI/App.hpp>
911
#include <CLI/CLI.hpp> // NOLINT: Need to include this for impls of some CLI11 classes
1012
#include <CLI/Validators.hpp>
13+
#include <fcntl.h>
1114
#include <qapplication.h>
1215
#include <qcontainerfwd.h>
1316
#include <qcoreapplication.h>
@@ -55,6 +58,34 @@ using qs::ipc::IpcClient;
5558
void checkCrashRelaunch(char** argv, QCoreApplication* coreApplication);
5659
int runCommand(int argc, char** argv, QCoreApplication* coreApplication);
5760

61+
int DAEMON_PIPE = -1; // NOLINT
62+
void exitDaemon(int code) {
63+
if (DAEMON_PIPE == -1) return;
64+
65+
if (write(DAEMON_PIPE, &code, sizeof(int)) == -1) {
66+
qCritical().nospace() << "Failed to write daemon exit command with error code " << errno << ": "
67+
<< qt_error_string();
68+
}
69+
70+
close(DAEMON_PIPE);
71+
72+
close(STDIN_FILENO);
73+
close(STDOUT_FILENO);
74+
close(STDERR_FILENO);
75+
76+
if (open("/dev/null", O_RDONLY) != STDIN_FILENO) { // NOLINT
77+
qFatal() << "Failed to open /dev/null on stdin";
78+
}
79+
80+
if (open("/dev/null", O_WRONLY) != STDOUT_FILENO) { // NOLINT
81+
qFatal() << "Failed to open /dev/null on stdout";
82+
}
83+
84+
if (open("/dev/null", O_WRONLY) != STDERR_FILENO) { // NOLINT
85+
qFatal() << "Failed to open /dev/null on stderr";
86+
}
87+
}
88+
5889
int main(int argc, char** argv) {
5990
QCoreApplication::setApplicationName("quickshell");
6091

@@ -66,7 +97,10 @@ int main(int argc, char** argv) {
6697
auto* coreApplication = new QCoreApplication(qArgC, argv);
6798

6899
checkCrashRelaunch(argv, coreApplication);
69-
return runCommand(argc, argv, coreApplication);
100+
auto code = runCommand(argc, argv, coreApplication);
101+
102+
exitDaemon(code);
103+
return code;
70104
}
71105

72106
class QStringOption {
@@ -133,6 +167,7 @@ struct CommandState {
133167
bool printVersion = false;
134168
bool killAll = false;
135169
bool noDuplicate = false;
170+
bool daemonize = false;
136171
} misc;
137172
};
138173

@@ -241,8 +276,11 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) {
241276
cli.add_flag("-V,--version", state.misc.printVersion)
242277
->description("Print quickshell's version and exit.");
243278

244-
cli.add_flag("--no-duplicate", state.misc.noDuplicate)
279+
cli.add_flag("-n,--no-duplicate", state.misc.noDuplicate)
245280
->description("Exit immediately if another instance of the given config is running.");
281+
282+
cli.add_flag("-d,--daemonize", state.misc.daemonize)
283+
->description("Detach from the controlling terminal.");
246284
}
247285

248286
{
@@ -295,6 +333,40 @@ int runCommand(int argc, char** argv, QCoreApplication* coreApplication) {
295333

296334
CLI11_PARSE(cli, argc, argv);
297335

336+
// Has to happen before extra threads are spawned.
337+
if (state.misc.daemonize) {
338+
auto closepipes = std::array<int, 2>();
339+
if (pipe(closepipes.data()) == -1) {
340+
qFatal().nospace() << "Failed to create messaging pipes for daemon with error " << errno
341+
<< ": " << qt_error_string();
342+
}
343+
344+
DAEMON_PIPE = closepipes[1];
345+
346+
pid_t pid = fork(); // NOLINT (include)
347+
348+
if (pid == -1) {
349+
qFatal().nospace() << "Failed to fork daemon with error " << errno << ": "
350+
<< qt_error_string();
351+
} else if (pid == 0) {
352+
close(closepipes[0]);
353+
354+
if (setsid() == -1) {
355+
qFatal().nospace() << "Failed to setsid with error " << errno << ": " << qt_error_string();
356+
}
357+
} else {
358+
close(closepipes[1]);
359+
qInfo() << "Daemon launched.";
360+
361+
int ret = 0;
362+
if (read(closepipes[0], &ret, sizeof(int)) == -1) {
363+
qFatal() << "Failed to wait for daemon launch (it may have crashed)";
364+
}
365+
366+
return ret;
367+
}
368+
}
369+
298370
{
299371
auto level = state.log.verbosity == 0 ? QtWarningMsg
300372
: state.log.verbosity == 1 ? QtInfoMsg
@@ -489,7 +561,7 @@ int readLogFile(CommandState& cmd) {
489561

490562
int listInstances(CommandState& cmd) {
491563
auto* basePath = QsPaths::instance()->baseRunDir();
492-
if (!basePath) exit(-1); // NOLINT
564+
if (!basePath) return -1; // NOLINT
493565

494566
QString path;
495567
QString configFilePath;
@@ -648,7 +720,7 @@ int launchFromCommand(CommandState& cmd, QCoreApplication* coreApplication) {
648720
{
649721
InstanceLockInfo info;
650722
if (cmd.misc.noDuplicate && selectInstance(cmd, &info) == 0) {
651-
qCDebug(logBare) << "An instance of this configuration is already running.";
723+
qCInfo(logBare) << "An instance of this configuration is already running.";
652724
return 0;
653725
}
654726
}
@@ -834,6 +906,8 @@ int launch(const LaunchArgs& args, char** argv, QCoreApplication* coreApplicatio
834906
auto root = RootWrapper(args.configPath, shellId);
835907
QGuiApplication::setQuitOnLastWindowClosed(false);
836908

909+
exitDaemon(0);
910+
837911
auto code = QGuiApplication::exec();
838912
delete app;
839913
return code;

0 commit comments

Comments
 (0)