diff options
author | Sebastien Braun | 2010-10-06 15:19:44 +0200 |
---|---|---|
committer | Sebastien Braun | 2010-10-07 09:30:24 +0200 |
commit | aeeb2b034f50ad2938b1c32507f20070a26c1849 (patch) | |
tree | 54dfca1f4dff7202c012adfc26070cfc3c9a222c /src/input | |
parent | Install PolKit policy file (diff) | |
download | pvs-aeeb2b034f50ad2938b1c32507f20070a26c1849.tar.gz pvs-aeeb2b034f50ad2938b1c32507f20070a26c1849.tar.xz pvs-aeeb2b034f50ad2938b1c32507f20070a26c1849.zip |
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.
Diffstat (limited to 'src/input')
-rw-r--r-- | src/input/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/input/pvsSyslog.cpp | 133 | ||||
-rw-r--r-- | src/input/pvsSyslog.h | 63 | ||||
-rw-r--r-- | src/input/pvsprivinputd.cpp | 116 |
4 files changed, 308 insertions, 6 deletions
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 <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <cerrno> +#include <syslog.h> +#include <QFile> +#include <QTextStream> +#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 <QObject> +#include <QString> + +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 <unistd.h> #include <cerrno> #include <cstdlib> +#include <cstdio> #include <cstring> #include <QtDebug> +#include <QFileInfo> #include <QSettings> #include <QCoreApplication> #include <QStringList> @@ -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=<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 = 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; } |