File indexing completed on 2024-05-19 05:28:17

0001 /*
0002     SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 
0006     This program is distributed in the hope that it will be useful,
0007     but WITHOUT ANY WARRANTY; without even the implied warranty of
0008     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0009     GNU General Public License for more details.
0010 
0011     You should have received a copy of the GNU General Public License
0012     along with this program; if not, write to the Free Software
0013     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0014     02110-1301  USA.
0015 */
0016 
0017 #ifndef PROCESSINFO_H
0018 #define PROCESSINFO_H
0019 
0020 // Qt
0021 #include <QtCore/QFile>
0022 #include <QtCore/QMap>
0023 #include <QtCore/QString>
0024 #include <QtCore/QVector>
0025 
0026 // std
0027 #include <memory>
0028 
0029 namespace Konsole
0030 {
0031 /**
0032  * Takes a snapshot of the state of a process and provides access to
0033  * information such as the process name, parent process,
0034  * the foreground process in the controlling terminal,
0035  * the arguments with which the process was started and the
0036  * environment.
0037  *
0038  * To create a new snapshot, construct a new ProcessInfo instance,
0039  * using ProcessInfo::newInstance(),
0040  * passing the process identifier of the process you are interested in.
0041  *
0042  * After creating a new instance, call the update() method to take a
0043  * snapshot of the current state of the process.
0044  *
0045  * Before calling any additional methods, check that the process state
0046  * was read successfully using the isValid() method.
0047  *
0048  * Each accessor method which provides information about the process state ( such as pid(),
0049  * currentDir(), name() ) takes a pointer to a boolean as an argument.  If the information
0050  * requested was read successfully then the boolean is set to true, otherwise it is set
0051  * to false, in which case the return value from the function should be ignored.
0052  * If this boolean is set to false, it may indicate an error reading the process information,
0053  * or it may indicate that the information is not available on the current platform.
0054  *
0055  * eg.
0056  *
0057  * @code
0058  *   ProcessInfo* info = ProcessInfo::newInstance(pid);
0059  *   info->update();
0060  *
0061  *   if ( info->isValid() )
0062  *   {
0063  *      bool ok;
0064  *
0065  *      QString name = info->name(&ok);
0066  *      if ( ok ) qDebug() << "process name - " << name;
0067  *      int parentPid = info->parentPid(&ok);
0068  *      if ( ok ) qDebug() << "parent process - " << parentPid;
0069  *      int foregroundPid = info->foregroundPid(&ok);
0070  *      if ( ok ) qDebug() << "foreground process - " << foregroundPid;
0071  *   }
0072  * @endcode
0073  */
0074 class ProcessInfo
0075 {
0076 public:
0077     /**
0078      * Constructs a new instance of a suitable ProcessInfo sub-class for
0079      * the current platform which provides information about a given process.
0080      *
0081      * @param pid The pid of the process to examine
0082      * @param readEnvironment Specifies whether environment bindings should
0083      * be read.  If this is false, then environment() calls will
0084      * always fail.  This is an optimization to avoid the overhead
0085      * of reading the (potentially large) environment data when it
0086      * is not required.
0087      */
0088     static std::unique_ptr<ProcessInfo> newInstance(int pid, bool readEnvironment = false);
0089 
0090     virtual ~ProcessInfo()
0091     {
0092     }
0093 
0094     /**
0095      * Updates the information about the process.  This must
0096      * be called before attempting to use any of the accessor methods.
0097      */
0098     void update();
0099 
0100     /** Returns true if the process state was read successfully. */
0101     bool isValid() const;
0102     /**
0103      * Returns the process id.
0104      *
0105      * @param ok Set to true if the process id was read successfully or false otherwise
0106      */
0107     int pid(bool *ok) const;
0108     /**
0109      * Returns the id of the parent process id was read successfully or false otherwise
0110      *
0111      * @param ok Set to true if the parent process id
0112      */
0113     int parentPid(bool *ok) const;
0114 
0115     /**
0116      * Returns the id of the current foreground process
0117      *
0118      * NOTE:  Using the foregroundProcessGroup() method of the Pty
0119      * instance associated with the terminal of interest is preferred
0120      * over using this method.
0121      *
0122      * @param ok Set to true if the foreground process id was read successfully or false otherwise
0123      */
0124     int foregroundPid(bool *ok) const;
0125 
0126     /* Returns the user id of the process */
0127     int userId(bool *ok) const;
0128 
0129     /** Returns the user's name of the process */
0130     QString userName() const;
0131 
0132     /** Returns the user's home directory of the process */
0133     QString userHomeDir() const;
0134 
0135     /** Returns the local host */
0136     static QString localHost();
0137 
0138     /** Returns the name of the current process */
0139     QString name(bool *ok) const;
0140 
0141     /**
0142      * Returns the command-line arguments which the process
0143      * was started with.
0144      *
0145      * The first argument is the name used to launch the process.
0146      *
0147      * @param ok Set to true if the arguments were read successfully or false otherwise.
0148      */
0149     QVector<QString> arguments(bool *ok) const;
0150     /**
0151      * Returns the environment bindings which the process
0152      * was started with.
0153      * In the returned map, the key is the name of the environment variable,
0154      * and the value is the corresponding value.
0155      *
0156      * @param ok Set to true if the environment bindings were read successfully or false otherwise
0157      */
0158     QMap<QString, QString> environment(bool *ok) const;
0159 
0160     /**
0161      * Returns the current working directory of the process
0162      *
0163      * @param ok Set to true if the current working directory was read successfully or false otherwise
0164      */
0165     QString currentDir(bool *ok) const;
0166 
0167     /**
0168      * Returns the current working directory of the process (or its parent)
0169      */
0170     QString validCurrentDir() const;
0171 
0172     /** Forces the user home directory to be calculated */
0173     void setUserHomeDir();
0174 
0175     /**
0176      * Parses an input string, looking for markers beginning with a '%'
0177      * character and returns a string with the markers replaced
0178      * with information from this process description.
0179      * <br>
0180      * The markers recognized are:
0181      * <ul>
0182      * <li> %u - Name of the user which owns the process. </li>
0183      * <li> %n - Replaced with the name of the process.   </li>
0184      * <li> %d - Replaced with the last part of the path name of the
0185      *      process' current working directory.
0186      *
0187      *      (eg. if the current directory is '/home/bob' then
0188      *      'bob' would be returned)
0189      * </li>
0190      * <li> %D - Replaced with the current working directory of the process. </li>
0191      * </ul>
0192      */
0193     QString format(const QString &text) const;
0194 
0195     /**
0196      * This enum describes the errors which can occur when trying to read
0197      * a process's information.
0198      */
0199     enum Error {
0200         /** No error occurred. */
0201         NoError,
0202         /** The nature of the error is unknown. */
0203         UnknownError,
0204         /** Konsole does not have permission to obtain the process information. */
0205         PermissionsError
0206     };
0207 
0208     /**
0209      * Returns the last error which occurred.
0210      */
0211     Error error() const;
0212 
0213     enum Field { PROCESS_ID = 1, PARENT_PID = 2, FOREGROUND_PID = 4, ARGUMENTS = 8, ENVIRONMENT = 16, NAME = 32, CURRENT_DIR = 64, UID = 128 };
0214     Q_DECLARE_FLAGS(Fields, Field)
0215 
0216 protected:
0217     /**
0218      * Constructs a new process instance.  You should not call the constructor
0219      * of ProcessInfo or its subclasses directly.  Instead use the
0220      * static ProcessInfo::newInstance() method which will return
0221      * a suitable ProcessInfo instance for the current platform.
0222      */
0223     explicit ProcessInfo(int pid, bool readEnvironment = false);
0224 
0225     /**
0226      * This is called on construction to read the process state
0227      * Subclasses should reimplement this function to provide
0228      * platform-specific process state reading functionality.
0229      *
0230      * When called, readProcessInfo() should attempt to read all
0231      * of the necessary state information.  If the attempt is successful,
0232      * it should set the process id using setPid(), and update
0233      * the other relevant information using setParentPid(), setName(),
0234      * setArguments() etc.
0235      *
0236      * Calls to isValid() will return true only if the process id
0237      * has been set using setPid()
0238      *
0239      * @param pid The process id of the process to read
0240      * @param readEnvironment Specifies whether the environment bindings
0241      *                        for the process should be read
0242      */
0243     virtual bool readProcessInfo(int pid, bool readEnvironment) = 0;
0244 
0245     /* Read the user name */
0246     virtual void readUserName(void) = 0;
0247 
0248     /** Sets the process id associated with this ProcessInfo instance */
0249     void setPid(int pid);
0250     /** Sets the parent process id as returned by parentPid() */
0251     void setParentPid(int pid);
0252     /** Sets the foreground process id as returned by foregroundPid() */
0253     void setForegroundPid(int pid);
0254     /** Sets the user id associated with this ProcessInfo instance */
0255     void setUserId(int uid);
0256     /** Sets the user name of the process as set by readUserName() */
0257     void setUserName(const QString &name);
0258     /** Sets the name of the process as returned by name() */
0259     void setName(const QString &name);
0260     /** Sets the current working directory for the process */
0261     void setCurrentDir(const QString &dir);
0262 
0263     /** Sets the error */
0264     void setError(Error error);
0265 
0266     /** Convenience method.  Sets the error based on a QFile error code. */
0267     void setFileError(QFile::FileError error);
0268 
0269     /**
0270      * Adds a commandline argument for the process, as returned
0271      * by arguments()
0272      */
0273     void addArgument(const QString &argument);
0274 
0275     /**
0276      * clear the commandline arguments for the process, as returned
0277      * by arguments()
0278      */
0279     void clearArguments();
0280 
0281     /**
0282      * Adds an environment binding for the process, as returned by
0283      * environment()
0284      *
0285      * @param name The name of the environment variable, eg. "PATH"
0286      * @param value The value of the environment variable, eg. "/bin"
0287      */
0288     void addEnvironmentBinding(const QString &name, const QString &value);
0289 
0290 private:
0291     // takes a full directory path and returns a
0292     // shortened version suitable for display in
0293     // space-constrained UI elements (eg. tabs)
0294     QString formatShortDir(const QString &dirPath) const;
0295 
0296     Fields _fields;
0297 
0298     bool _enableEnvironmentRead; // specifies whether to read the environment
0299     // bindings when update() is called
0300     int _pid;
0301     int _parentPid;
0302     int _foregroundPid;
0303     int _userId;
0304 
0305     Error _lastError;
0306 
0307     QString _name;
0308     QString _userName;
0309     QString _userHomeDir;
0310     QString _currentDir;
0311 
0312     QVector<QString> _arguments;
0313     QMap<QString, QString> _environment;
0314 
0315     static QSet<QString> commonDirNames();
0316     static QSet<QString> _commonDirNames;
0317 };
0318 Q_DECLARE_OPERATORS_FOR_FLAGS(ProcessInfo::Fields)
0319 
0320 /**
0321  * Implementation of ProcessInfo which does nothing.
0322  * Used on platforms where a suitable ProcessInfo subclass is not
0323  * available.
0324  *
0325  * isValid() will always return false for instances of NullProcessInfo
0326  */
0327 class NullProcessInfo : public ProcessInfo
0328 {
0329 public:
0330     /**
0331      * Constructs a new NullProcessInfo instance.
0332      * See ProcessInfo::newInstance()
0333      */
0334     explicit NullProcessInfo(int pid, bool readEnvironment = false);
0335 
0336 protected:
0337     bool readProcessInfo(int pid, bool readEnvironment) override;
0338     void readUserName(void) override;
0339 };
0340 
0341 #if !defined(Q_OS_WIN)
0342 /**
0343  * Implementation of ProcessInfo for Unix platforms which uses
0344  * the /proc filesystem
0345  */
0346 class UnixProcessInfo : public ProcessInfo
0347 {
0348 public:
0349     /**
0350      * Constructs a new instance of UnixProcessInfo.
0351      * See ProcessInfo::newInstance()
0352      */
0353     explicit UnixProcessInfo(int pid, bool readEnvironment = false);
0354 
0355 protected:
0356     /**
0357      * Implementation of ProcessInfo::readProcessInfo(); calls the
0358      * four private methods below in turn.
0359      */
0360     bool readProcessInfo(int pid, bool readEnvironment) override;
0361 
0362     void readUserName(void) override;
0363 
0364 private:
0365     /**
0366      * Read the standard process information -- PID, parent PID, foreground PID.
0367      * @param pid process ID to use
0368      * @return true on success
0369      */
0370     virtual bool readProcInfo(int pid) = 0;
0371 
0372     /**
0373      * Read the environment of the process. Sets _environment.
0374      * @param pid process ID to use
0375      * @return true on success
0376      */
0377     virtual bool readEnvironment(int pid) = 0;
0378 
0379     /**
0380      * Determine what arguments were passed to the process. Sets _arguments.
0381      * @param pid process ID to use
0382      * @return true on success
0383      */
0384     virtual bool readArguments(int pid) = 0;
0385 
0386     /**
0387      * Determine the current directory of the process.
0388      * @param pid process ID to use
0389      * @return true on success
0390      */
0391     virtual bool readCurrentDir(int pid) = 0;
0392 };
0393 #endif
0394 
0395 /**
0396  * Lightweight class which provides additional information about SSH processes.
0397  */
0398 class SSHProcessInfo
0399 {
0400 public:
0401     /**
0402      * Constructs a new SSHProcessInfo instance which provides additional
0403      * information about the specified SSH process.
0404      *
0405      * @param process A ProcessInfo instance for a SSH process.
0406      */
0407     explicit SSHProcessInfo(const ProcessInfo &process);
0408 
0409     /**
0410      * Returns the user name which the user initially logged into on
0411      * the remote computer.
0412      */
0413     QString userName() const;
0414 
0415     /**
0416      * Returns the host which the user has connected to.
0417      */
0418     QString host() const;
0419 
0420     /**
0421      * Returns the port on host which the user has connected to.
0422      */
0423     QString port() const;
0424 
0425     /**
0426      * Returns the command which the user specified to execute on the
0427      * remote computer when starting the SSH process.
0428      */
0429     QString command() const;
0430 
0431     /**
0432      * Operates in the same way as ProcessInfo::format(), except
0433      * that the set of markers understood is different:
0434      *
0435      * %u - Replaced with user name which the user initially logged
0436      *      into on the remote computer.
0437      * %h - Replaced with the first part of the host name which
0438      *      is connected to.
0439      * %H - Replaced with the full host name of the computer which
0440      *      is connected to.
0441      * %c - Replaced with the command which the user specified
0442      *      to execute when starting the SSH process.
0443      */
0444     QString format(const QString &input) const;
0445 
0446 private:
0447     const ProcessInfo &_process;
0448     QString _user;
0449     QString _host;
0450     QString _port;
0451     QString _command;
0452 };
0453 }
0454 #endif // PROCESSINFO_H