summaryrefslogtreecommitdiffstats
path: root/src/input/pvsprivinputd.cpp
diff options
context:
space:
mode:
authorFabian Schillinger2010-11-01 17:35:27 +0100
committerFabian Schillinger2010-11-01 17:35:27 +0100
commitea3fb17345e5f82db9f2e98a8062e95797700ace (patch)
tree1da0d1a8ec9455364386af78762d0f6fed187824 /src/input/pvsprivinputd.cpp
parentProcess start/stop/view functionality (diff)
parent[PVSGUI] No X required for --help and --version (diff)
downloadpvs-ea3fb17345e5f82db9f2e98a8062e95797700ace.tar.gz
pvs-ea3fb17345e5f82db9f2e98a8062e95797700ace.tar.xz
pvs-ea3fb17345e5f82db9f2e98a8062e95797700ace.zip
Merge branch 'master' of openslx.org:pvs
Conflicts: CMakeLists.txt src/core/pvsConnectionManager.cpp src/pvs.cpp src/pvs.h
Diffstat (limited to 'src/input/pvsprivinputd.cpp')
-rw-r--r--src/input/pvsprivinputd.cpp262
1 files changed, 262 insertions, 0 deletions
diff --git a/src/input/pvsprivinputd.cpp b/src/input/pvsprivinputd.cpp
new file mode 100644
index 0000000..e6ae155
--- /dev/null
+++ b/src/input/pvsprivinputd.cpp
@@ -0,0 +1,262 @@
+/*
+ # Copyright (c) 2009 - OpenSLX Project, Computer Center University of Freiburg
+ #
+ # This program is free software distributed under the GPL version 2.
+ # See http://openslx.org/COPYING
+ #
+ # If you have any feedback please consult http://openslx.org/feedback and
+ # send your suggestions, praise, or complaints to feedback@openslx.org
+ #
+ # General information about OpenSLX can be found at http://openslx.org/
+ # --------------------------------------------------------------------------
+ # pvsprivinputd.cpp:
+ # - Handle privileged input events - daemon
+ # --------------------------------------------------------------------------
+ */
+
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <signal.h>
+#include <unistd.h>
+#include <cerrno>
+#include <cstdlib>
+#include <cstdio>
+#include <cstring>
+#include <QtDebug>
+#include <QFileInfo>
+#include <QSettings>
+#include <QCoreApplication>
+#include <QStringList>
+#include <QSocketNotifier>
+#include "pvsCheckPrivileges.h"
+#include "pvsPrivInputSocket.h"
+#include "pvsPrivInputHandler.h"
+#include "pvsPrivInputSignalHandler.h"
+#include "pvsSyslog.h"
+
+using namespace std;
+
+#ifndef UNIX_PATH_MAX
+# define UNIX_PATH_MAX 108 /* according to unix(7) */
+#endif
+
+QByteArray socketPath;
+int signalFds[2];
+
+QTextStream qout(stdout, QIODevice::WriteOnly);
+QTextStream qerr(stderr, QIODevice::WriteOnly);
+
+static void unlinkSocket()
+{
+ if(!socketPath.isNull())
+ {
+ unlink(socketPath.constData());
+ }
+}
+
+static void onCaughtSignal(int signum)
+{
+ pvsPrivInputSendMessage(signalFds[0], &signum, sizeof(signum), 0);
+}
+
+static void usage()
+{
+ qout << QObject::tr(
+ "Usage: %1 [--help|-h] [--daemon|-d] [--log=<Logger>|-l<Logger>]\n"
+ "\n"
+ "Options:\n"
+ " --help, -h Show this message\n"
+ " --daemon, -d Run in background\n"
+ " --log=<Logger>,\n"
+ " -l<Logger> Redirect all output to <Logger>\n"
+ " valid values are:\n"
+ " - any file name\n"
+ " - `syslog' to redirect output to the system log\n"
+ " - `null' to discard output (default)\n"
+ " (without quotes)\n"
+ "\n"
+ "Signals:\n"
+ " SIGINT, SIGTERM (or press Ctrl+C when run in foreground)\n"
+ " Quit\n"
+ " SIGHUP Reload configuration and cached user data\n").arg(qApp->arguments().at(0)) << flush;
+}
+
+int main(int argc, char** argv)
+{
+ QCoreApplication app(argc, argv);
+ app.setApplicationName("pvsprivinputd");
+ app.setOrganizationName("openslx");
+
+ bool no_fork = true;
+ QString logTarget = "null";
+
+ foreach(QString arg, app.arguments().mid(1))
+ {
+ if(arg == "--daemon" || arg == "-d")
+ {
+ no_fork = false;
+ }
+ else if(arg.startsWith("-l"))
+ {
+ logTarget = arg.mid(2);
+ }
+ else if(arg.startsWith("--log="))
+ {
+ logTarget = arg.mid(6);
+ }
+ else if(arg == "--help" || arg == "-h")
+ {
+ usage();
+ return EXIT_SUCCESS;
+ }
+ else
+ {
+ qout << "Unexpected argument: " << arg << endl;
+ usage();
+ return EXIT_FAILURE;
+ }
+ }
+
+ if(logTarget != "null" && logTarget != "syslog")
+ {
+ logTarget = QFileInfo(logTarget).absoluteFilePath();
+ qout << "Writing log to " << logTarget << endl;
+ }
+
+ if(!no_fork)
+ {
+ pid_t pid;
+ pid_t sid;
+
+ pid = fork();
+ if(pid < 0)
+ {
+ qCritical("Could not fork: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ if(pid > 0)
+ {
+ exit(EXIT_SUCCESS);
+ }
+
+ // We are now inside a child process.
+ // Detach from parent:
+ sid = setsid();
+ if(sid < 0)
+ {
+ qCritical("Could not detach from parent process: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+
+ // Change to some benign directory:
+ if(chdir("/") < 0)
+ {
+ qCritical("Could not change directory: %s", strerror(errno));
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ // Okay, we are running as a daemon. Defer reopening standard file descriptors
+ // so we can report errors.
+
+ // Set the file creation mask to allow all processes to connect to
+ // the socket (access control is handled differently):
+ umask(0);
+
+ // Store the socket path before the signal handler is installed so it does not risk segfaulting
+ // due to bad timing.
+ socketPath = pvsPrivInputGetSocketAddress().toLocal8Bit();
+
+ // Ignore SIGPIPE. Connection errors are handled internally.
+ // According to signal(2), the only error is that the signal number
+ // is invalid. This cannot happen.
+ signal(SIGPIPE, SIG_IGN);
+
+ // Create our socket:
+ int sock = pvsPrivInputMakeServerSocket();
+ if(sock < 0)
+ {
+ exit(EXIT_FAILURE);
+ }
+
+ // Install our main object
+ PVSPrivInputHandler handler(sock);
+
+ // set up signal handling:
+ if(socketpair(AF_UNIX, SOCK_DGRAM, 0, signalFds) < 0)
+ {
+ qCritical("Could not set up signal handling. Giving up.");
+ exit(EXIT_FAILURE);
+ }
+ PVSPrivInputSignalHandler sigHandler;
+ QSocketNotifier sigintWatcher(signalFds[1], QSocketNotifier::Read);
+ sigHandler.allowUnauthenticatedKilling(!pvsPrivInputEnableReceiveCredentials(signalFds[1]));
+ QObject::connect(&sigintWatcher, SIGNAL(activated(int)), &sigHandler, SLOT(signalReceived(int)));
+ QObject::connect(&sigHandler, SIGNAL(terminate()), &app, SLOT(quit()));
+ QObject::connect(&sigHandler, SIGNAL(reloadConfiguration()), PVSCheckPrivileges::instance(), SLOT(updateCachedUserDatabase()));
+ QObject::connect(&sigHandler, SIGNAL(reloadConfiguration()), PVSCheckPrivileges::instance(), SLOT(rereadConfiguration()));
+ signal(SIGINT, onCaughtSignal);
+ signal(SIGTERM, onCaughtSignal);
+ signal(SIGHUP, onCaughtSignal);
+
+ PVSLogRedirector* logRedir = 0;
+ QSocketNotifier* logNotif = 0;
+ // Our setup is complete.
+ if(!no_fork)
+ {
+ // Reopen standard file descriptors:
+ freopen("/dev/null", "r", stdin);
+
+ if(logTarget == "null")
+ {
+ freopen("/dev/null", "w", stdout);
+ freopen("/dev/null", "w", stderr);
+ }
+ else if(logTarget == "syslog")
+ {
+ logRedir = new PVSSyslogRedirector();
+ }
+ else
+ {
+ logRedir = new PVSLogfileRedirector(logTarget);
+ }
+
+ if(logRedir)
+ {
+ int logFds[2];
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, logFds) < 0)
+ {
+ qWarning("Could not open a socket pair: %s", strerror(errno));
+ return EXIT_FAILURE;
+ }
+
+ logNotif = new QSocketNotifier(logFds[1], QSocketNotifier::Read);
+ QObject::connect(logNotif, SIGNAL(activated(int)), logRedir, SLOT(inputAvailableOn(int)));
+
+ // redirect stdout and stderr:
+ dup2(logFds[0], 1);
+ dup2(logFds[0], 2);
+ }
+ }
+
+ atexit(unlinkSocket);
+
+ qout << "PVS Privileged Input Daemon initialization complete. Entering main loop." << endl;
+
+ // and run the main loop.
+ int ret = app.exec();
+
+ if(logRedir)
+ {
+ delete logNotif;
+ delete logRedir;
+ }
+
+ PVSCheckPrivileges::deleteInstance();
+
+ qout << "PVS Privileged Input Daemon deinitialization complete. Exiting." << endl;
+
+ return ret;
+}