summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastien Braun2010-10-05 15:30:04 +0200
committerSebastien Braun2010-10-05 18:15:51 +0200
commitac05f7d367ae9983e7996738871efbdbf3ec66e8 (patch)
treecff16aee36f2afcb00df6842cb0e9bab82c86c16
parentAdd description to input event handlers so they can (diff)
downloadpvs-ac05f7d367ae9983e7996738871efbdbf3ec66e8.tar.gz
pvs-ac05f7d367ae9983e7996738871efbdbf3ec66e8.tar.xz
pvs-ac05f7d367ae9983e7996738871efbdbf3ec66e8.zip
Implement privileged input daemon, first version without handlers.
-rw-r--r--src/input/CMakeLists.txt45
-rw-r--r--src/input/inputHandlerChain.h8
-rw-r--r--src/input/privilegedHandlerForwarder.cpp82
-rw-r--r--src/input/privilegedHandlerForwarder.h32
-rw-r--r--src/input/pvsPrivInputHandler.cpp108
-rw-r--r--src/input/pvsPrivInputHandler.h45
-rw-r--r--src/input/pvsPrivInputSocket.cpp196
-rw-r--r--src/input/pvsPrivInputSocket.h31
-rw-r--r--src/input/pvsprivinputd.cpp147
9 files changed, 687 insertions, 7 deletions
diff --git a/src/input/CMakeLists.txt b/src/input/CMakeLists.txt
index aa52ec3..5f009c5 100644
--- a/src/input/CMakeLists.txt
+++ b/src/input/CMakeLists.txt
@@ -2,18 +2,51 @@ INCLUDE(${QT_USE_FILE})
SET(pvsinput_SRCS
inputEvent.cpp
+ inputEventHandler.cpp
)
+
+if(UNIX)
+ set(pvsprivinputd_SRCS
+ pvsprivinputd.cpp
+ pvsPrivInputHandler.cpp
+ pvsCheckPrivileges.cpp
+ )
+
+ set(pvsprivinputd_MOC_HDRS
+ pvsPrivInputHandler.h
+ )
-IF(UNIX)
- list(APPEND pvsinput_SRCS
- x11InputUtils.cpp
+ qt4_wrap_cpp(pvsprivinputd_MOC_SRCS
+ ${pvsprivinputd_MOC_HDRS}
+ )
+
+ add_executable(pvsprivinputd
+ ${pvsprivinputd_SRCS}
+ ${pvsprivinputd_MOC_SRCS}
+ )
+
+ set_property(SOURCE ${pvsprivinputd_SRCS} ${pvsprivinputd_MOC_SRCS}
+ APPEND
+ PROPERTY COMPILE_FLAGS " -I${QT_QTCORE_INCLUDE_DIR} -I${QT_QTDBUS_INCLUDE_DIR} -I${QT_QTNETWORK_INCLUDE_DIR}")
+
+ target_link_libraries(pvsprivinputd
+ pvsinput
+ ${QT_QTCORE_LIBRARY}
+ ${QT_QTDBUS_LIBRARY}
+ ${QT_QTNETWORK_LIBRARY}
+ )
+
+ list(APPEND pvsinput_SRCS
+ pvsPrivInputSocket.cpp
+ x11InputUtils.cpp
x11FakeKeyboardHandler.cpp
- x11FakeMouseHandler.cpp)
-ENDIF()
+ x11FakeMouseHandler.cpp
+ privilegedHandlerForwarder.cpp
+ )
+endif()
ADD_LIBRARY(
pvsinput
STATIC
- ${pvsinput_HDRS}
${pvsinput_SRCS}
)
diff --git a/src/input/inputHandlerChain.h b/src/input/inputHandlerChain.h
index 4bb9fe5..61c3d62 100644
--- a/src/input/inputHandlerChain.h
+++ b/src/input/inputHandlerChain.h
@@ -22,13 +22,19 @@
#include "x11FakeKeyboardHandler.h"
#include "x11FakeMouseHandler.h"
+#include "privilegedHandlerForwarder.h"
typedef boost::mpl::list<
Handler<X11FakeKeyboardHandler, policy::RequireSystem<policy::UnixLike> >,
Handler<X11FakeMouseButtonHandler, policy::RequireSystem<policy::UnixLike> >,
- Handler<X11FakeMouseMovementHandler, policy::RequireSystem<policy::UnixLike> >
+ Handler<X11FakeMouseMovementHandler, policy::RequireSystem<policy::UnixLike> >,
+ Handler<PrivilegedHandlerForwarder>
>::type unprivileged_handler_list;
typedef InputEventHandlerChain<unprivileged_handler_list> unprivileged_handler_chain;
+typedef boost::mpl::list<
+>::type privileged_handler_list;
+
+typedef InputEventHandlerChain<privileged_handler_list> privileged_handler_chain;
#endif /* INPUTHANDLERCHAIN_H_ */
diff --git a/src/input/privilegedHandlerForwarder.cpp b/src/input/privilegedHandlerForwarder.cpp
new file mode 100644
index 0000000..3c0b3bd
--- /dev/null
+++ b/src/input/privilegedHandlerForwarder.cpp
@@ -0,0 +1,82 @@
+/*
+ # 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/
+ # --------------------------------------------------------------------------
+ # inputHandlerChain.cpp:
+ # - Forward privileged input events to a special handler process - implementation
+ # --------------------------------------------------------------------------
+ */
+
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <cassert>
+#include <cerrno>
+#include <cstring>
+#include <string>
+#include <QSettings>
+#include <QtDebug>
+#include "pvsPrivInputSocket.h"
+#include "privilegedHandlerForwarder.h"
+
+using namespace std;
+
+#ifndef UNIX_PATH_MAX
+# define UNIX_PATH_MAX 108 /* according to unix(7) */
+#endif
+
+void PrivilegedHandlerForwarder::initialize()
+{
+ QSettings settings(QSettings::NativeFormat, QSettings::SystemScope, "openslx", "pvsinputd");
+
+ QString defaultPath = "/tmp/pvsprivinputd.sock";
+ QByteArray socketPath = settings.value("socketpath", defaultPath).toString().toLocal8Bit();
+
+ _socket = pvsPrivInputMakeClientSocket();
+ if(_socket < 0)
+ {
+ return;
+ }
+}
+
+void PrivilegedHandlerForwarder::handle(InputEvent const& evt, InputEventContext const*)
+{
+ qDebug("Trying to handle %s in PrivilegedHandlerForwarder", evt.toString().c_str());
+ if(_socket < 0)
+ {
+ initialize();
+ }
+
+ QByteArray data;
+ QDataStream strm(&data, QIODevice::WriteOnly);
+ strm.setByteOrder(QDataStream::BigEndian);
+ strm << evt;
+
+ assert(data.size() == 8);
+
+ int delta = 0;
+ int count = 0;
+ do {
+ delta = write(_socket, data.constData(), data.size());
+ if(delta < 0)
+ {
+ qWarning("Error while communicating with pvsprivinputd: %s", strerror(errno));
+ close(_socket);
+
+ // Try again:
+ initialize();
+ }
+ else if(delta != 8)
+ {
+ // This should normally not happen.
+ qWarning("Could not send a complete packet. Only %d bytes sent", delta);
+ }
+ count++;
+ } while(delta != 8 && count < 3);
+}
diff --git a/src/input/privilegedHandlerForwarder.h b/src/input/privilegedHandlerForwarder.h
new file mode 100644
index 0000000..37e8f24
--- /dev/null
+++ b/src/input/privilegedHandlerForwarder.h
@@ -0,0 +1,32 @@
+/*
+ # 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/
+ # --------------------------------------------------------------------------
+ # inputHandlerChain.h:
+ # - Forward privileged input events to a special handler process.
+ # --------------------------------------------------------------------------
+ */
+
+#ifndef PRIVILEGEDHANDLERFORWARDER_H_
+#define PRIVILEGEDHANDLERFORWARDER_H_
+
+#include "inputEventHandler.h"
+
+class PrivilegedHandlerForwarder : public DefaultInputEventHandler<InputEvent::ET_SPECIAL>
+{
+public:
+ void handle(InputEvent const& evt, InputEventContext const* = 0);
+ void initialize();
+
+private:
+ int _socket;
+};
+
+#endif /* PRIVILEGEDHANDLERFORWARDER_H_ */
diff --git a/src/input/pvsPrivInputHandler.cpp b/src/input/pvsPrivInputHandler.cpp
new file mode 100644
index 0000000..70ed1bc
--- /dev/null
+++ b/src/input/pvsPrivInputHandler.cpp
@@ -0,0 +1,108 @@
+/*
+ # 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/
+ # --------------------------------------------------------------------------
+ # pvsPrivInputHandler.h
+ # - Handle privileged input connection requests - implementation
+ # --------------------------------------------------------------------------
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <cerrno>
+#include <QtDebug>
+#include <QSocketNotifier>
+#include "inputEvent.h"
+#include "inputEventHandler.h"
+#include "pvsPrivInputSocket.h"
+#include "pvsPrivInputHandler.h"
+
+using namespace std;
+
+class PrivInputContext : public InputEventContext
+{
+public:
+ PrivInputContext(pid_t pid, uid_t uid, gid_t gid)
+ : _pid(pid), _uid(uid), _gid(gid)
+ {
+ }
+
+ pid_t getSenderPid() const
+ {
+ return _pid;
+ }
+
+ uid_t getSenderUid() const
+ {
+ return _uid;
+ }
+
+ gid_t getSenderGid() const
+ {
+ return _gid;
+ }
+
+private:
+ pid_t _pid;
+ uid_t _uid;
+ gid_t _gid;
+};
+
+PVSPrivInputHandler::PVSPrivInputHandler(int fd, QObject* parent) :
+ QObject(parent)
+{
+ _fd = fd;
+ _notifier = new QSocketNotifier(fd, QSocketNotifier::Read, this);
+ _notifier->setEnabled(true);
+ connect(_notifier, SIGNAL(activated(int)), this, SLOT(canRead()));
+}
+
+PVSPrivInputHandler::~PVSPrivInputHandler()
+{
+ delete _notifier;
+}
+
+void PVSPrivInputHandler::canRead()
+{
+ _notifier->setEnabled(false);
+
+ // We need to retrieve the credentials of the process:
+ size_t siz = 8;
+ _messageAssembly.clear();
+ _messageAssembly.resize(8);
+ pid_t pid;
+ uid_t uid;
+ gid_t gid;
+ int err;
+
+ if(!pvsPrivInputRecvMessage(_fd, _messageAssembly.data(), siz, pid, uid, gid, &err))
+ {
+ close(_fd);
+ deleteLater();
+ return;
+ }
+ else
+ {
+ if(siz != 8)
+ {
+ qWarning("Malformed PVS Input Event packet");
+ return;
+ }
+ QDataStream strm(&_messageAssembly, QIODevice::ReadOnly);
+ InputEvent evt;
+ strm.setByteOrder(QDataStream::BigEndian);
+ strm >> evt;
+ PrivInputContext ctx(pid, uid, gid);
+ _handlerChain.handle(evt, &ctx);
+ }
+
+ _notifier->setEnabled(true);
+}
diff --git a/src/input/pvsPrivInputHandler.h b/src/input/pvsPrivInputHandler.h
new file mode 100644
index 0000000..9980cdf
--- /dev/null
+++ b/src/input/pvsPrivInputHandler.h
@@ -0,0 +1,45 @@
+/*
+ # 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/
+ # --------------------------------------------------------------------------
+ # pvsPrivInputHandler.h
+ # - Handle privileged input connection requests - interface
+ # --------------------------------------------------------------------------
+ */
+
+#ifndef PVSPRIVINPUTHANDLER_H_
+#define PVSPRIVINPUTHANDLER_H_
+
+#include <QObject>
+#include <QHash>
+#include <QPointer>
+#include "inputHandlerChain.h"
+
+class QSocketNotifier;
+
+class PVSPrivInputHandler : public QObject
+{
+ Q_OBJECT
+public:
+ PVSPrivInputHandler(int fd, QObject* parent = 0);
+ virtual ~PVSPrivInputHandler();
+
+private slots:
+ void canRead();
+
+private:
+ QSocketNotifier* _notifier;
+ QByteArray _messageAssembly;
+ int _bytes;
+ int _fd;
+ privileged_handler_chain _handlerChain;
+};
+
+#endif /* PVSPRIVINPUTHANDLER_H_ */
diff --git a/src/input/pvsPrivInputSocket.cpp b/src/input/pvsPrivInputSocket.cpp
new file mode 100644
index 0000000..2428582
--- /dev/null
+++ b/src/input/pvsPrivInputSocket.cpp
@@ -0,0 +1,196 @@
+/*
+ # 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/
+ # --------------------------------------------------------------------------
+ # pvsPrivInputSocket.h:
+ # - Centralize knowledge of socket address and connection options
+ # for pvsprivinputd - implementation
+ # --------------------------------------------------------------------------
+ */
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <cerrno>
+#include <QtDebug>
+#include <QSettings>
+#include "pvsPrivInputSocket.h"
+
+using namespace std;
+
+#ifndef UNIX_PATH_MAX
+# define UNIX_PATH_MAX 108 /* according to unix(7) */
+#endif
+
+QString pvsPrivInputGetSocketAddress()
+{
+ QSettings settings(QSettings::NativeFormat, QSettings::SystemScope, "openslx", "pvsprivinputd");
+ return settings.value("socketpath", "/tmp/pvsprivinputd.sock").toString();
+}
+
+int pvsPrivInputMakeClientSocket()
+{
+ int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if(sock < 0)
+ {
+ qWarning("Could not create a socket: %s", strerror(errno));
+ return -1;
+ }
+
+ QByteArray socketPath = pvsPrivInputGetSocketAddress().toLocal8Bit();
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, socketPath.constData(), UNIX_PATH_MAX - 1);
+ if(connect(sock, reinterpret_cast<struct sockaddr*>(&addr),
+ sizeof(addr)) < 0)
+ {
+ qWarning("Could not connect to pvsprivinputd at %s: %s", socketPath.constData(), strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ return sock;
+}
+
+int pvsPrivInputMakeServerSocket()
+{
+ int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
+ if(sock < 0)
+ {
+ qCritical("Could not create a socket: %s", strerror(errno));
+ return -1;
+ }
+
+ // Bind to the address:
+ QByteArray socketPath = pvsPrivInputGetSocketAddress().toLocal8Bit();
+ struct sockaddr_un addr;
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ strncpy(addr.sun_path, socketPath.constData(), UNIX_PATH_MAX - 1);
+ if(bind(sock, reinterpret_cast<struct sockaddr*>(&addr), sizeof(addr)) < 0)
+ {
+ qCritical("Could not bind socket to %s", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+ // Announce that credentials are requested:
+ int passcred = 1;
+ if(setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &passcred, sizeof(passcred)) < 0)
+ {
+ // We will not operate without credentials.
+ qCritical("Could not request peer credentials: %s", strerror(errno));
+ close(sock);
+ return -1;
+ }
+
+#if 0 /* Only for SOCK_STREAM: */
+ // Listen for connections:
+ if(listen(sock, 1) < 0)
+ {
+ qCritical("Could not listen for connections to %s: %s", socketPath.constData(), strerror(errno));
+ close(sock);
+ return -1;
+ }
+#endif
+
+ return sock;
+}
+
+bool pvsPrivInputSendMessage(int sock, void* buf, size_t _len, int* err)
+{
+ /*
+ * Portability note: All UNIX-like systems can transmit credentials over UNIX
+ * sockets, but only Linux does it automagically.
+ */
+
+ long len = (long)_len;
+
+ // send(2) does not split messages on a SOCK_DGRAM socket.
+ int e = send(sock, buf, len, 0);
+ if(e < 0)
+ {
+ qWarning("Failed to send message of length %d over socket %d: %s", (unsigned)len, e, strerror(errno));
+ if(err)
+ *err = errno;
+ return false;
+ }
+ else if(e < len)
+ {
+ qWarning("Failed to send a complete message of length %d over socket %d, only %d bytes were sent", (unsigned)len, sock, e);
+ if(err)
+ *err = errno;
+ return false;
+ }
+
+ return true;
+}
+
+bool pvsPrivInputRecvMessage(int sock, void* buf, size_t& len,
+ pid_t& pid, uid_t& uid, gid_t& gid, int* err)
+{
+ struct iovec iov;
+ struct msghdr msg;
+ char ctlbuf[1024];
+ iov.iov_base = buf;
+ iov.iov_len = len;
+ msg.msg_name = 0;
+ msg.msg_namelen = 0;
+ msg.msg_iov = &iov;
+ msg.msg_iovlen = 1;
+ msg.msg_control = &ctlbuf;
+ msg.msg_controllen = sizeof(ctlbuf);
+ msg.msg_flags = 0;
+ int bytes_read = recvmsg(sock, &msg, 0);
+ if(bytes_read < 0)
+ {
+ qWarning("Could not read from socket: %s", strerror(errno));
+ if(err)
+ *err = errno;
+ return false;
+ }
+
+ pid = -1;
+ uid = -1;
+ gid = -1;
+
+ struct cmsghdr* cmsg;
+ for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+ {
+ if(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_CREDENTIALS)
+ {
+ struct ucred* creds = reinterpret_cast<struct ucred*>(CMSG_DATA(cmsg));
+ pid = creds->pid;
+ uid = creds->uid;
+ gid = creds->gid;
+ break;
+ }
+ else if(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS)
+ {
+ // We need to close passed file descriptors. If we don't, we
+ // have a denial-of-service vulnerability.
+ int* fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
+ unsigned num_fds = cmsg->cmsg_len / sizeof(int);
+ for(unsigned i = 0; i < num_fds; i++)
+ {
+ close(fds[i]);
+ }
+ }
+ }
+
+ if(pid == (pid_t)-1 || uid == (uid_t)-1 || gid == (gid_t)-1)
+ {
+ *err = 0;
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/input/pvsPrivInputSocket.h b/src/input/pvsPrivInputSocket.h
new file mode 100644
index 0000000..e6fb0c0
--- /dev/null
+++ b/src/input/pvsPrivInputSocket.h
@@ -0,0 +1,31 @@
+/*
+ # 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/
+ # --------------------------------------------------------------------------
+ # pvsPrivInputSocket.h:
+ # - Centralize knowledge of socket address and connection options
+ # for pvsprivinputd - interface
+ # --------------------------------------------------------------------------
+ */
+
+#ifndef PVSPRIVINPUTSOCKET_H_
+#define PVSPRIVINPUTSOCKET_H_
+
+#include <sys/types.h>
+#include <cstring>
+#include <QString>
+
+QString pvsPrivInputGetSocketAddress();
+int pvsPrivInputMakeClientSocket();
+int pvsPrivInputMakeServerSocket();
+bool pvsPrivInputSendMessage(int sock, void* buf, size_t len, int* err = 0);
+bool pvsPrivInputRecvMessage(int sock, void* buf, size_t& len, pid_t& pid, uid_t& uid, gid_t& gid, int* err = 0);
+
+#endif /* PVSPRIVINPUTSOCKET_H_ */
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 <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 <cstring>
+#include <QtDebug>
+#include <QSettings>
+#include <QCoreApplication>
+#include <QStringList>
+#include <QSocketNotifier>
+#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;
+}