File indexing completed on 2025-03-16 08:11:26
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