From ac05f7d367ae9983e7996738871efbdbf3ec66e8 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Tue, 5 Oct 2010 15:30:04 +0200 Subject: Implement privileged input daemon, first version without handlers. --- src/input/pvsprivinputd.cpp | 147 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) create mode 100644 src/input/pvsprivinputd.cpp (limited to 'src/input/pvsprivinputd.cpp') diff --git a/src/input/pvsprivinputd.cpp b/src/input/pvsprivinputd.cpp new file mode 100644 index 0000000..3a5e1a8 --- /dev/null +++ b/src/input/pvsprivinputd.cpp @@ -0,0 +1,147 @@ +/* + # 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "pvsPrivInputSocket.h" +#include "pvsPrivInputHandler.h" + +using namespace std; + +#ifndef UNIX_PATH_MAX +# define UNIX_PATH_MAX 108 /* according to unix(7) */ +#endif + +QByteArray socketPath; +int sigintFds[2]; + +static void unlinkSocket() +{ + if(!socketPath.isNull()) + { + unlink(socketPath.constData()); + } +} + +static void onInterrupt(int) +{ + char buf[] = { '!' }; + char msg[] = "SIGINT caught. Quitting.\n"; + write(sigintFds[0], buf, 1); + write(1, msg, sizeof(msg)-1); +} + +int main(int argc, char** argv) +{ + QCoreApplication app(argc, argv); + app.setApplicationName("pvsprivinputd"); + app.setOrganizationName("openslx"); + + bool no_fork = app.arguments().contains("--no-fork", Qt::CaseInsensitive); + 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); + + // 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); + + // set up signal handling: + if(socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFds) < 0) + { + qCritical("Could not set up signal handling. Giving up."); + exit(EXIT_FAILURE); + } + socketPath = pvsPrivInputGetSocketAddress().toLocal8Bit(); + QSocketNotifier sigintWatcher(sigintFds[1], QSocketNotifier::Read); + QObject::connect(&sigintWatcher, SIGNAL(activated(int)), &app, SLOT(quit())); + signal(SIGINT, onInterrupt); + + // Create our socket: + int sock = pvsPrivInputMakeServerSocket(); + if(sock < 0) + { + exit(EXIT_FAILURE); + } + + // Our setup is complete. + if(!no_fork) + { + // Reopen standard file descriptors: + freopen("/dev/null", "r", stdin); + freopen("/dev/null", "w", stderr); + freopen("/dev/null", "w", stdout); + } + + // Install our main object + PVSPrivInputHandler handler(sock); + + atexit(unlinkSocket); + + // and run the main loop. + int ret = app.exec(); + + return ret; +} -- cgit v1.2.3-55-g7522 From 6afd810d1954018791456a7cebca0d275c50ed95 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 6 Oct 2010 15:08:03 +0200 Subject: Refactor signal handling in pvsprivinputd Only use one socketpair and delegate the actual decision of what to do when a specific signal is received to a special object. --- src/input/CMakeLists.txt | 2 + src/input/pvsPrivInputSignalHandler.cpp | 69 +++++++++++++++++++++++++++++++++ src/input/pvsPrivInputSignalHandler.h | 47 ++++++++++++++++++++++ src/input/pvsPrivInputSocket.cpp | 14 ++++++- src/input/pvsPrivInputSocket.h | 1 + src/input/pvsprivinputd.cpp | 40 +++++++++++-------- 6 files changed, 155 insertions(+), 18 deletions(-) create mode 100644 src/input/pvsPrivInputSignalHandler.cpp create mode 100644 src/input/pvsPrivInputSignalHandler.h (limited to 'src/input/pvsprivinputd.cpp') diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 29c463a..fcb5ff5 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -18,6 +18,7 @@ if(UNIX) pvsprivinputd.cpp pvsPrivInputHandler.cpp pvsCheckPrivileges.cpp + pvsPrivInputSignalHandler.cpp rebootSystemHandler.cpp killX11Handler.cpp sayHelloHandler.cpp @@ -26,6 +27,7 @@ if(UNIX) set(pvsprivinputd_MOC_HDRS pvsPrivInputHandler.h pvsCheckPrivileges.h + pvsPrivInputSignalHandler.h ) qt4_wrap_cpp(pvsprivinputd_MOC_SRCS diff --git a/src/input/pvsPrivInputSignalHandler.cpp b/src/input/pvsPrivInputSignalHandler.cpp new file mode 100644 index 0000000..b09c335 --- /dev/null +++ b/src/input/pvsPrivInputSignalHandler.cpp @@ -0,0 +1,69 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # pvsPrivInputSignalHandler.cpp: + # - Handle signals forwarded over a file descriptor - implementation + # -------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include "pvsPrivInputSocket.h" +#include "pvsPrivInputSignalHandler.h" + +void PVSPrivInputSignalHandler::signalReceived(int sigfd) +{ + int signum; + + pid_t pid; + uid_t uid; + gid_t gid; + int err; + size_t siz = sizeof(signum); + + if(!pvsPrivInputRecvMessage(sigfd, &signum, siz, pid, uid, gid, &err)) + { + qWarning("Should have received a signal but could not read message: %s", strerror(err)); + return; + } + + if(siz != sizeof(signum)) + { + qWarning("Sould have received a message of size %d bytes but got %d bytes instead. Discarding message.", (int)sizeof(signum), (int)siz); + return; + } + + if(!_allowUnauthenticatedKilling && pid != getpid()) + { + qCritical("SOMETHING STRANGE IS GOING ON!\nReceived signal %d from PID %d\nPlease kill me instead of sending me signal notifications.", signum, (int)pid); + return; + } + + switch(signum) + { + case SIGINT: + qDebug("Caught SIGINT. Quitting."); + emit terminate(); + break; + case SIGTERM: + qDebug("Caught SIGTERM. Quitting."); + emit terminate(); + break; + case SIGHUP: + qDebug("Caught SIGHUP. Reloading configuration."); + emit reloadConfiguration(); + break; + default: + qWarning("Received signal %d, but don't know how to handle it.", signum); + } +} diff --git a/src/input/pvsPrivInputSignalHandler.h b/src/input/pvsPrivInputSignalHandler.h new file mode 100644 index 0000000..cb75c86 --- /dev/null +++ b/src/input/pvsPrivInputSignalHandler.h @@ -0,0 +1,47 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # pvsPrivInputSignalHandler.h: + # - Handle signals forwarded over a file descriptor - interface + # -------------------------------------------------------------------------- + */ + +#ifndef PVSPRIVINPUTSIGNALHANDLER_H_ +#define PVSPRIVINPUTSIGNALHANDLER_H_ + +#include + +class PVSPrivInputSignalHandler : public QObject +{ + Q_OBJECT +public: + PVSPrivInputSignalHandler(QObject* parent = 0) + : QObject(parent) + { + } + + void allowUnauthenticatedKilling(bool value) + { + _allowUnauthenticatedKilling = value; + } + +public slots: + void signalReceived(int sigfd); + +signals: + void terminate(); + void reloadConfiguration(); + +private: + bool _allowUnauthenticatedKilling; +}; + +#endif /* PVSPRIVINPUTSIGNALHANDLER_H_ */ diff --git a/src/input/pvsPrivInputSocket.cpp b/src/input/pvsPrivInputSocket.cpp index c491dd9..df5dff5 100644 --- a/src/input/pvsPrivInputSocket.cpp +++ b/src/input/pvsPrivInputSocket.cpp @@ -60,6 +60,17 @@ QString pvsPrivInputGetSocketAddress() return pvsPrivInputGetSettings()->value("socketpath", "/tmp/pvsprivinputd.sock").toString(); } +bool pvsPrivInputEnableReceiveCredentials(int sock) +{ + int passcred = 1; + if(setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &passcred, sizeof(passcred)) < 0) + { + return false; + } + else + { + return true; + } } int pvsPrivInputMakeClientSocket() @@ -110,8 +121,7 @@ int pvsPrivInputMakeServerSocket() } // Announce that credentials are requested: - int passcred = 1; - if(setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &passcred, sizeof(passcred)) < 0) + if(!pvsPrivInputEnableReceiveCredentials(sock)) { // We will not operate without credentials. qCritical("Could not request peer credentials: %s", strerror(errno)); diff --git a/src/input/pvsPrivInputSocket.h b/src/input/pvsPrivInputSocket.h index 879ca99..447360b 100644 --- a/src/input/pvsPrivInputSocket.h +++ b/src/input/pvsPrivInputSocket.h @@ -28,6 +28,7 @@ QSettings* pvsPrivInputGetSettings(); QSettings* pvsPrivInputReopenSettings(); QString pvsPrivInputGetSettingsPath(); QString pvsPrivInputGetSocketAddress(); +bool pvsPrivInputEnableReceiveCredentials(int sock); int pvsPrivInputMakeClientSocket(); int pvsPrivInputMakeServerSocket(); bool pvsPrivInputSendMessage(int sock, void* buf, size_t len, int* err = 0); diff --git a/src/input/pvsprivinputd.cpp b/src/input/pvsprivinputd.cpp index 3a5e1a8..361bf9f 100644 --- a/src/input/pvsprivinputd.cpp +++ b/src/input/pvsprivinputd.cpp @@ -30,6 +30,7 @@ #include #include "pvsPrivInputSocket.h" #include "pvsPrivInputHandler.h" +#include "pvsPrivInputSignalHandler.h" using namespace std; @@ -38,7 +39,7 @@ using namespace std; #endif QByteArray socketPath; -int sigintFds[2]; +int signalFds[2]; static void unlinkSocket() { @@ -48,12 +49,9 @@ static void unlinkSocket() } } -static void onInterrupt(int) +static void onCaughtSignal(int signum) { - char buf[] = { '!' }; - char msg[] = "SIGINT caught. Quitting.\n"; - write(sigintFds[0], buf, 1); - write(1, msg, sizeof(msg)-1); + pvsPrivInputSendMessage(signalFds[0], &signum, sizeof(signum), 0); } int main(int argc, char** argv) @@ -103,28 +101,38 @@ int main(int argc, char** argv) // 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); - // set up signal handling: - if(socketpair(AF_UNIX, SOCK_STREAM, 0, sigintFds) < 0) + // Create our socket: + int sock = pvsPrivInputMakeServerSocket(); + if(sock < 0) { - qCritical("Could not set up signal handling. Giving up."); exit(EXIT_FAILURE); } - socketPath = pvsPrivInputGetSocketAddress().toLocal8Bit(); - QSocketNotifier sigintWatcher(sigintFds[1], QSocketNotifier::Read); - QObject::connect(&sigintWatcher, SIGNAL(activated(int)), &app, SLOT(quit())); - signal(SIGINT, onInterrupt); - // Create our socket: - int sock = pvsPrivInputMakeServerSocket(); - if(sock < 0) + // 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); // Our setup is complete. if(!no_fork) -- cgit v1.2.3-55-g7522 From c5c91f40c02d7b8611fb5e479f340fe19254592f Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 6 Oct 2010 15:09:43 +0200 Subject: Fix deletion order bug PVSCheckPrivileges::instance() is statically allocated. When it is deleted, the QCoreApplication is already gone (since it is stack- allocated), and the destructor of QFileSystemWatcher waits forever. --- src/input/pvsCheckPrivileges.cpp | 13 +++++++++++-- src/input/pvsCheckPrivileges.h | 1 + src/input/pvsprivinputd.cpp | 3 +++ 3 files changed, 15 insertions(+), 2 deletions(-) (limited to 'src/input/pvsprivinputd.cpp') diff --git a/src/input/pvsCheckPrivileges.cpp b/src/input/pvsCheckPrivileges.cpp index 71c5861..57b5d8b 100644 --- a/src/input/pvsCheckPrivileges.cpp +++ b/src/input/pvsCheckPrivileges.cpp @@ -100,8 +100,17 @@ Q_DECLARE_METATYPE(QStringStringMap) PVSCheckPrivileges* PVSCheckPrivileges::instance() { - static PVSCheckPrivileges static_instance; - return &static_instance; + static PVSCheckPrivileges* static_instance = 0; + if(!static_instance) + { + static_instance = new PVSCheckPrivileges(); + } + return static_instance; +} + +void PVSCheckPrivileges::deleteInstance() +{ + delete instance(); } PVSCheckPrivileges::PVSCheckPrivileges(QObject* parent) diff --git a/src/input/pvsCheckPrivileges.h b/src/input/pvsCheckPrivileges.h index fc82e4c..ec6c591 100644 --- a/src/input/pvsCheckPrivileges.h +++ b/src/input/pvsCheckPrivileges.h @@ -114,6 +114,7 @@ public: } static PVSCheckPrivileges* instance(); + static void deleteInstance(); bool require(SessionKind sessionKind, CachedInputContext const& sender); bool require(UserPrivilege userPrivilege, CachedInputContext const& sender); diff --git a/src/input/pvsprivinputd.cpp b/src/input/pvsprivinputd.cpp index 361bf9f..2f19d90 100644 --- a/src/input/pvsprivinputd.cpp +++ b/src/input/pvsprivinputd.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "pvsCheckPrivileges.h" #include "pvsPrivInputSocket.h" #include "pvsPrivInputHandler.h" #include "pvsPrivInputSignalHandler.h" @@ -151,5 +152,7 @@ int main(int argc, char** argv) // and run the main loop. int ret = app.exec(); + + PVSCheckPrivileges::deleteInstance(); return ret; } -- cgit v1.2.3-55-g7522 From aeeb2b034f50ad2938b1c32507f20070a26c1849 Mon Sep 17 00:00:00 2001 From: Sebastien Braun Date: Wed, 6 Oct 2010 15:19:44 +0200 Subject: Implement log targets for pvsprivinputd Also: - add command line options and usage message. - change --no-fork to --daemon to bring it in line with the pvs daemon. --- src/input/CMakeLists.txt | 2 + src/input/pvsSyslog.cpp | 133 ++++++++++++++++++++++++++++++++++++++++++++ src/input/pvsSyslog.h | 63 +++++++++++++++++++++ src/input/pvsprivinputd.cpp | 116 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 308 insertions(+), 6 deletions(-) create mode 100644 src/input/pvsSyslog.cpp create mode 100644 src/input/pvsSyslog.h (limited to 'src/input/pvsprivinputd.cpp') diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt index 0cf5177..a2e6fda 100644 --- a/src/input/CMakeLists.txt +++ b/src/input/CMakeLists.txt @@ -18,6 +18,7 @@ if(UNIX) pvsprivinputd.cpp pvsPrivInputHandler.cpp pvsCheckPrivileges.cpp + pvsSyslog.cpp pvsPrivInputSignalHandler.cpp rebootSystemHandler.cpp killX11Handler.cpp @@ -27,6 +28,7 @@ if(UNIX) set(pvsprivinputd_MOC_HDRS pvsPrivInputHandler.h pvsCheckPrivileges.h + pvsSyslog.h pvsPrivInputSignalHandler.h ) diff --git a/src/input/pvsSyslog.cpp b/src/input/pvsSyslog.cpp new file mode 100644 index 0000000..6a9be31 --- /dev/null +++ b/src/input/pvsSyslog.cpp @@ -0,0 +1,133 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # pvsSyslog.cpp: + # - Send output to syslog or to a file - implementation + # -------------------------------------------------------------------------- + */ + +#include +#include +#include +#include +#include +#include +#include +#include "pvsSyslog.h" + +using namespace std; + +#define PVS_LOG_BUFSIZ 8192 + +void PVSLogRedirector::inputAvailableOn(int fd) +{ + QByteArray readbuf; + readbuf.resize(PVS_LOG_BUFSIZ); + ssize_t siz; + bool cont = true; + + do + { + siz = recv(fd, readbuf.data(), readbuf.size(), MSG_DONTWAIT); + if(siz > 0) + { + _buf.append(readbuf.constData(), siz); + + // Send lines: + int oldnpos = -1; + int npos = -1; + while((npos = _buf.indexOf('\n', oldnpos + 1)) >= 0) + { + if((oldnpos + 1) == npos) + { + oldnpos = npos; + continue; + } + QString line = QString::fromLocal8Bit(_buf.constData() + oldnpos + 1, npos - oldnpos - 1); + doRedirectInput(line); + oldnpos = npos; + } + + // All complete lines have been sent. Remove sent bytes from buffer. + _buf.remove(0, oldnpos + 1); + + // If line length is too large, send it now. + if(_buf.size() >= BUFSIZ) + { + QString longLine = QString::fromLocal8Bit(_buf.constData(), _buf.size()); + doRedirectInput(longLine); + _buf.clear(); + } + } + else if(siz == 0) + { + // Socket closed on other end. + break; + } + else if(siz < 0) + { + int err = errno; + switch(err) + { + case EAGAIN: +#if defined(EWOULDBLOCK) && (EWOULDBLOCK != EAGAIN) + case EWOULDBLOCK: +#endif + // We read all there is to read. + cont = false; + break; + default: + // Something happened. + // We can't inform the user via qDebug() and friends as that would loop right back to us again, + // so we emit a log line. + doRedirectInput(QString("Error in logging code: Could not read log input: %s").arg(strerror(err))); + cont = false; + } + } + } + while(cont); +} + +PVSSyslogRedirector::PVSSyslogRedirector() +{ + openlog("pvsprivinputd", LOG_PID, LOG_USER); +} + +PVSSyslogRedirector::~PVSSyslogRedirector() +{ + closelog(); +} + +void PVSSyslogRedirector::doRedirectInput(QString const& line) +{ + QByteArray bytes = line.toLocal8Bit(); + syslog(LOG_NOTICE, "%s", bytes.data()); +} + +PVSLogfileRedirector::PVSLogfileRedirector(QString const& filename) +{ + _file = new QFile(filename, this); + _file->open(QIODevice::Append); + _stream = new QTextStream(_file); +} + +PVSLogfileRedirector::~PVSLogfileRedirector() +{ + _stream->flush(); + _file->close(); + delete _stream; + delete _file; +} + +void PVSLogfileRedirector::doRedirectInput(QString const& line) +{ + *_stream << line << flush; +} diff --git a/src/input/pvsSyslog.h b/src/input/pvsSyslog.h new file mode 100644 index 0000000..8c9591a --- /dev/null +++ b/src/input/pvsSyslog.h @@ -0,0 +1,63 @@ +/* + # 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/ + # -------------------------------------------------------------------------- + # pvsSyslog.h: + # - Send output to syslog or to a file - interface + # -------------------------------------------------------------------------- + */ + +#ifndef PVSSYSLOG_H_ +#define PVSSYSLOG_H_ + +#include +#include + +class PVSLogRedirector : public QObject +{ + Q_OBJECT +public slots: + void inputAvailableOn(int fd); + +protected: + virtual void doRedirectInput(QString const& line) = 0; + +private: + QByteArray _buf; +}; + +class PVSSyslogRedirector : public PVSLogRedirector +{ +public: + PVSSyslogRedirector(); + virtual ~PVSSyslogRedirector(); + +protected: + void doRedirectInput(QString const& line); +}; + +class QFile; +class QTextStream; + +class PVSLogfileRedirector : public PVSLogRedirector +{ +public: + PVSLogfileRedirector(QString const& filename); + virtual ~PVSLogfileRedirector(); + +protected: + void doRedirectInput(QString const& line); + +private: + QFile* _file; + QTextStream* _stream; +}; + +#endif /* PVSSYSLOG_H_ */ diff --git a/src/input/pvsprivinputd.cpp b/src/input/pvsprivinputd.cpp index 2f19d90..e6ae155 100644 --- a/src/input/pvsprivinputd.cpp +++ b/src/input/pvsprivinputd.cpp @@ -22,8 +22,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -32,6 +34,7 @@ #include "pvsPrivInputSocket.h" #include "pvsPrivInputHandler.h" #include "pvsPrivInputSignalHandler.h" +#include "pvsSyslog.h" using namespace std; @@ -42,6 +45,9 @@ using namespace std; QByteArray socketPath; int signalFds[2]; +QTextStream qout(stdout, QIODevice::WriteOnly); +QTextStream qerr(stderr, QIODevice::WriteOnly); + static void unlinkSocket() { if(!socketPath.isNull()) @@ -55,13 +61,70 @@ 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=|-l]\n" + "\n" + "Options:\n" + " --help, -h Show this message\n" + " --daemon, -d Run in background\n" + " --log=,\n" + " -l Redirect all output to \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 = app.arguments().contains("--no-fork", Qt::CaseInsensitive); + 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; @@ -118,6 +181,9 @@ int main(int argc, char** argv) exit(EXIT_FAILURE); } + // Install our main object + PVSPrivInputHandler handler(sock); + // set up signal handling: if(socketpair(AF_UNIX, SOCK_DGRAM, 0, signalFds) < 0) { @@ -135,24 +201,62 @@ int main(int argc, char** argv) 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); - freopen("/dev/null", "w", stderr); - freopen("/dev/null", "w", stdout); - } - // Install our main object - PVSPrivInputHandler handler(sock); + 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; } -- cgit v1.2.3-55-g7522