File indexing completed on 2024-04-28 11:40:31

0001 /*
0002     This file is part of the KDE libraries
0003     SPDX-FileCopyrightText: 1999 Waldo Bastian <bastian@kde.org>
0004 
0005     SPDX-License-Identifier: LGPL-2.0-only
0006 */
0007 
0008 #ifndef _KLAUNCHER_H_
0009 #define _KLAUNCHER_H_
0010 
0011 #include <qplatformdefs.h>
0012 
0013 #include <config-kdeinit.h> // HAVE_X11
0014 
0015 #if defined(Q_OS_WIN) || defined(Q_OS_OSX)
0016 #define USE_KPROCESS_FOR_KIOSLAVES
0017 #endif
0018 #ifdef Q_CC_MSVC
0019 typedef unsigned int pid_t;
0020 #endif
0021 
0022 #include <QString>
0023 #include <QSocketNotifier>
0024 #include <QTimer>
0025 #include <QList>
0026 #include <QObject>
0027 #include <QProcess>
0028 #include <QDateTime>
0029 #include <QUrl>
0030 #include <QDBusConnection>
0031 #include <QDBusMessage>
0032 #include <QDBusContext>
0033 
0034 #include <KService>
0035 #include <kio/idleslave.h>
0036 #include <kio/connectionserver.h>
0037 
0038 using KIO::IdleSlave;
0039 
0040 class KSlaveLauncherAdaptor;
0041 
0042 struct xcb_connection_t;
0043 
0044 class SlaveWaitRequest
0045 {
0046 public:
0047     pid_t pid;
0048     QDBusMessage transaction;
0049 };
0050 
0051 class KLaunchRequest
0052 {
0053 public:
0054     QString name;
0055     QStringList arg_list;
0056     QString dbus_name;
0057     QString tolerant_dbus_name;
0058     enum status_t { Init = 0, Launching, Running, Error, Done };
0059     pid_t pid;
0060     status_t status;
0061     QDBusMessage transaction;
0062     KService::DBusStartupType dbus_startup_type;
0063     bool wait; //wait until the process dies before finishing the request
0064     QString errorMsg;
0065 #if HAVE_X11
0066     QByteArray startup_id; // "" is the default, "0" for none
0067     QByteArray startup_dpy; // Display to send startup notification to.
0068 #endif
0069     QStringList envs; // env. variables to be app's environment
0070     QString cwd;
0071 #ifdef USE_KPROCESS_FOR_KIOSLAVES
0072 protected:
0073     QProcess *process;
0074     friend class KLauncher;
0075 #endif
0076 };
0077 
0078 struct serviceResult {
0079     int result;        // 0 means success. > 0 means error (-1 means pending)
0080     QString dbusName; // Contains DBUS name on success
0081     QString error;     // Contains error description on failure.
0082     pid_t pid;
0083 };
0084 
0085 class KLauncher : public QObject, protected QDBusContext
0086 {
0087     Q_OBJECT
0088 
0089 public:
0090 #ifndef USE_KPROCESS_FOR_KIOSLAVES
0091     KLauncher(int kdeinitSocket);
0092 #else
0093     KLauncher();
0094 #endif
0095 
0096     ~KLauncher() override;
0097 
0098     void close();
0099 
0100 public Q_SLOTS:
0101     Q_NORETURN void destruct(); // exit!
0102 
0103 protected:
0104     void processDied(pid_t pid, long exitStatus);
0105 
0106     void requestStart(KLaunchRequest *request);
0107     void requestDone(KLaunchRequest *request);
0108 
0109     bool start_service(KService::Ptr service, const QStringList &urls,
0110                        const QStringList &envs, const QByteArray &startup_id,
0111                        bool blind, const QDBusMessage &msg);
0112 
0113     void createArgs(KLaunchRequest *request, const KService::Ptr service,
0114                     const QList<QUrl> &url);
0115 
0116     void queueRequest(KLaunchRequest *);
0117 
0118     void send_service_startup_info(KLaunchRequest *request, KService::Ptr service, const QByteArray &startup_id,
0119                                    const QStringList &envs);
0120     void cancel_service_startup_info(KLaunchRequest *request, const QByteArray &startup_id,
0121                                      const QStringList &envs);
0122 
0123 public: // remote methods, called by KLauncherAdaptor
0124     /**
0125      * Starts a program.
0126      * 'envs' are environment variables that will be added
0127      *   to this program's environment before starting it
0128      * 'startup_id' is for application startup notification,
0129      * "" is the default, "0" for none
0130      */
0131     void exec_blind(const QString &name, const QStringList &arg_list, const QStringList &envs, const QString &startup_id);
0132     inline void exec_blind(const QString &name, const QStringList &arg_list)
0133     {
0134         exec_blind(name, arg_list, QStringList(), QStringLiteral("0"));
0135     }
0136 
0137     bool kdeinit_exec(const QString &app, const QStringList &args,
0138                       const QString &workdir, const QStringList &envs,
0139                       const QString &startup_id, bool wait, const QDBusMessage &msg);
0140 
0141     void reparseConfiguration();
0142     void setLaunchEnv(const QString &name, const QString &value);
0143 
0144     /**
0145      * Start a service by desktop name.
0146      *
0147      * 'serviceName' refers to a desktop file describing the service.
0148      * The service is looked up anywhere in the applications and services directories
0149      * (see KStandardDirs resource "xdgdata-apps" and "services").
0150      * E.g. it should have the form "korganizer".
0151      *
0152      * 'url', if not empty, will be passed to the service as
0153      * argument.
0154      *
0155      * 'envs' are environment variables that will be added
0156      *   to this program's environment before starting it
0157      *
0158      * 'startup_id' is for application startup notification,
0159      * "" is the default, "0" for none
0160      */
0161     bool start_service_by_desktop_name(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg);
0162 
0163     /**
0164      * Start a service by desktop path.
0165      *
0166      * 'serviceName' refers to a desktop file describing the service.
0167      * This may be an absolute path or a path relative to the applications
0168      * and/or services directories (see KStandardDirs)
0169      * E.g. it should have the form "korganizer.desktop" or
0170      * "/opt/kde/share/applications/korganizer.desktop".
0171      * Note that for absolute paths the restrictions of
0172      * KDesktopFile::isAuthorizedDesktopFile() are obeyed for security.
0173      *
0174      * 'url', if not empty, will be passed to the service as
0175      * argument.
0176      *
0177      * 'envs' are environment variables that will be added
0178      *   to this program's environment before starting it
0179      *
0180      * 'startup_id' is for application startup notification,
0181      * "" is the default, "0" for none
0182      */
0183     bool start_service_by_desktop_path(const QString &serviceName, const QStringList &urls, const QStringList &envs, const QString &startup_id, bool blind, const QDBusMessage &msg);
0184 
0185     pid_t requestHoldSlave(const QString &url, const QString &app_socket);
0186 
0187     pid_t requestSlave(const QString &protocol, const QString &host,
0188                        const QString &app_socket, QString &error);
0189     /**
0190      * Return true of there is a slave held for @p url.
0191      * @since 4.7
0192      */
0193     bool checkForHeldSlave(const QString &url);
0194     void waitForSlave(int pid);
0195     void terminate_kdeinit();
0196 
0197 public Q_SLOTS:
0198     void slotDequeue();
0199     void slotKDEInitData(int);
0200     void slotNameOwnerChanged(const QString &name, const QString &oldOnwer, const QString &newOwner);
0201     void slotSlaveStatus(IdleSlave *);
0202     void acceptSlave();
0203     void slotSlaveGone();
0204     void idleTimeout();
0205 
0206 public:
0207     serviceResult requestResult; // accessed by the adaptor
0208 protected:
0209     QList<KLaunchRequest *> requestList; // Requests being handled
0210     QList<KLaunchRequest *> requestQueue; // Requests waiting to being handled
0211     KLaunchRequest *lastRequest;
0212     QList<SlaveWaitRequest *> mSlaveWaitRequest;
0213 #ifndef USE_KPROCESS_FOR_KIOSLAVES
0214     int kdeinitSocket;
0215     QSocketNotifier *kdeinitNotifier;
0216 #endif
0217     KIO::ConnectionServer mConnectionServer;
0218     QList<IdleSlave *> mSlaveList;
0219     QTimer mTimer;
0220     bool bProcessingQueue;
0221     QString mSlaveDebug;
0222     QString mSlaveValgrind;
0223     QString mSlaveValgrindSkin;
0224     KSlaveLauncherAdaptor *mSlaveLauncherAdaptor;
0225     bool dontBlockReading;
0226 #if HAVE_X11
0227     bool mIsX11;
0228 #endif
0229     void processRequestReturn(int status, const QByteArray &requestData);
0230 
0231 protected Q_SLOTS:
0232     void slotGotOutput();
0233     void slotFinished(int exitCode, QProcess::ExitStatus exitStatus);
0234 
0235 private:
0236 #if HAVE_XCB
0237     struct XCBConnection {
0238         XCBConnection() : conn(nullptr), screen(0) { }
0239 
0240         operator bool() const {
0241             return conn != nullptr;
0242         }
0243 
0244         xcb_connection_t *conn;
0245         int screen;
0246         QByteArray displayName;
0247     } mCached;
0248 
0249     XCBConnection getXCBConnection(const QByteArray &displyName);
0250 #endif
0251 };
0252 #endif