1/*
2 Copyright 2007-2008 by Robert Knight <robertknight@gmail.com>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301 USA.
18*/
19
20#ifndef PROCESSINFO_H
21#define PROCESSINFO_H
22
23// Qt
24#include <QtCore/QFile>
25#include <QtCore/QMap>
26#include <QtCore/QString>
27#include <QtCore/QVector>
28
29namespace Konsole
30{
31/**
32 * Takes a snapshot of the state of a process and provides access to
33 * information such as the process name, parent process,
34 * the foreground process in the controlling terminal,
35 * the arguments with which the process was started and the
36 * environment.
37 *
38 * To create a new snapshot, construct a new ProcessInfo instance,
39 * using ProcessInfo::newInstance(),
40 * passing the process identifier of the process you are interested in.
41 *
42 * After creating a new instance, call the update() method to take a
43 * snapshot of the current state of the process.
44 *
45 * Before calling any additional methods, check that the process state
46 * was read successfully using the isValid() method.
47 *
48 * Each accessor method which provides information about the process state ( such as pid(),
49 * currentDir(), name() ) takes a pointer to a boolean as an argument. If the information
50 * requested was read successfully then the boolean is set to true, otherwise it is set
51 * to false, in which case the return value from the function should be ignored.
52 * If this boolean is set to false, it may indicate an error reading the process information,
53 * or it may indicate that the information is not available on the current platform.
54 *
55 * eg.
56 *
57 * @code
58 * ProcessInfo* info = ProcessInfo::newInstance(pid);
59 * info->update();
60 *
61 * if ( info->isValid() )
62 * {
63 * bool ok;
64 *
65 * QString name = info->name(&ok);
66 * if ( ok ) kDebug() << "process name - " << name;
67 * int parentPid = info->parentPid(&ok);
68 * if ( ok ) kDebug() << "parent process - " << parentPid;
69 * int foregroundPid = info->foregroundPid(&ok);
70 * if ( ok ) kDebug() << "foreground process - " << foregroundPid;
71 * }
72 * @endcode
73 */
74class ProcessInfo
75{
76public:
77 /**
78 * Constructs a new instance of a suitable ProcessInfo sub-class for
79 * the current platform which provides information about a given process.
80 *
81 * @param pid The pid of the process to examine
82 * @param readEnvironment Specifies whether environment bindings should
83 * be read. If this is false, then environment() calls will
84 * always fail. This is an optimization to avoid the overhead
85 * of reading the (potentially large) environment data when it
86 * is not required.
87 */
88 static ProcessInfo* newInstance(int pid, bool readEnvironment = false);
89
90 virtual ~ProcessInfo() {}
91
92 /**
93 * Updates the information about the process. This must
94 * be called before attempting to use any of the accessor methods.
95 */
96 void update();
97
98 /** Returns true if the process state was read successfully. */
99 bool isValid() const;
100 /**
101 * Returns the process id.
102 *
103 * @param ok Set to true if the process id was read successfully or false otherwise
104 */
105 int pid(bool* ok) const;
106 /**
107 * Returns the id of the parent process id was read successfully or false otherwise
108 *
109 * @param ok Set to true if the parent process id
110 */
111 int parentPid(bool* ok) const;
112
113 /**
114 * Returns the id of the current foreground process
115 *
116 * NOTE: Using the foregroundProcessGroup() method of the Pty
117 * instance associated with the terminal of interest is preferred
118 * over using this method.
119 *
120 * @param ok Set to true if the foreground process id was read successfully or false otherwise
121 */
122 int foregroundPid(bool* ok) const;
123
124 /* Returns the user id of the process */
125 int userId(bool* ok) const;
126
127 /** Returns the user's name of the process */
128 QString userName() const;
129
130 /** Returns the user's home directory of the process */
131 QString userHomeDir() const;
132
133 /** Returns the local host */
134 static QString localHost();
135
136 /** Returns the name of the current process */
137 QString name(bool* ok) const;
138
139 /**
140 * Returns the command-line arguments which the process
141 * was started with.
142 *
143 * The first argument is the name used to launch the process.
144 *
145 * @param ok Set to true if the arguments were read successfully or false otherwise.
146 */
147 QVector<QString> arguments(bool* ok) const;
148 /**
149 * Returns the environment bindings which the process
150 * was started with.
151 * In the returned map, the key is the name of the environment variable,
152 * and the value is the corresponding value.
153 *
154 * @param ok Set to true if the environment bindings were read successfully or false otherwise
155 */
156 QMap<QString, QString> environment(bool* ok) const;
157
158 /**
159 * Returns the current working directory of the process
160 *
161 * @param ok Set to true if the current working directory was read successfully or false otherwise
162 */
163 QString currentDir(bool* ok) const;
164
165 /**
166 * Returns the current working directory of the process (or its parent)
167 */
168 QString validCurrentDir() const;
169
170 /** Forces the user home directory to be calculated */
171 void setUserHomeDir();
172
173 /**
174 * Parses an input string, looking for markers beginning with a '%'
175 * character and returns a string with the markers replaced
176 * with information from this process description.
177 * <br>
178 * The markers recognized are:
179 * <ul>
180 * <li> %u - Name of the user which owns the process. </li>
181 * <li> %n - Replaced with the name of the process. </li>
182 * <li> %d - Replaced with the last part of the path name of the
183 * process' current working directory.
184 *
185 * (eg. if the current directory is '/home/bob' then
186 * 'bob' would be returned)
187 * </li>
188 * <li> %D - Replaced with the current working directory of the process. </li>
189 * </ul>
190 */
191 QString format(const QString& text) const;
192
193 /**
194 * This enum describes the errors which can occur when trying to read
195 * a process's information.
196 */
197 enum Error {
198 /** No error occurred. */
199 NoError,
200 /** The nature of the error is unknown. */
201 UnknownError,
202 /** Konsole does not have permission to obtain the process information. */
203 PermissionsError
204 };
205
206 /**
207 * Returns the last error which occurred.
208 */
209 Error error() const;
210
211protected:
212 /**
213 * Constructs a new process instance. You should not call the constructor
214 * of ProcessInfo or its subclasses directly. Instead use the
215 * static ProcessInfo::newInstance() method which will return
216 * a suitable ProcessInfo instance for the current platform.
217 */
218 explicit ProcessInfo(int pid , bool readEnvironment = false);
219
220 /**
221 * This is called on construction to read the process state
222 * Subclasses should reimplement this function to provide
223 * platform-specific process state reading functionality.
224 *
225 * When called, readProcessInfo() should attempt to read all
226 * of the necessary state information. If the attempt is successful,
227 * it should set the process id using setPid(), and update
228 * the other relevant information using setParentPid(), setName(),
229 * setArguments() etc.
230 *
231 * Calls to isValid() will return true only if the process id
232 * has been set using setPid()
233 *
234 * @param pid The process id of the process to read
235 * @param readEnvironment Specifies whether the environment bindings
236 * for the process should be read
237 */
238 virtual bool readProcessInfo(int pid , bool readEnvironment) = 0;
239
240 /* Read the user name */
241 virtual void readUserName(void) = 0;
242
243 /** Sets the process id associated with this ProcessInfo instance */
244 void setPid(int pid);
245 /** Sets the parent process id as returned by parentPid() */
246 void setParentPid(int pid);
247 /** Sets the foreground process id as returned by foregroundPid() */
248 void setForegroundPid(int pid);
249 /** Sets the user id associated with this ProcessInfo instance */
250 void setUserId(int uid);
251 /** Sets the user name of the process as set by readUserName() */
252 void setUserName(const QString& name);
253 /** Sets the name of the process as returned by name() */
254 void setName(const QString& name);
255 /** Sets the current working directory for the process */
256 void setCurrentDir(const QString& dir);
257
258 /** Sets the error */
259 void setError(Error error);
260
261 /** Convenience method. Sets the error based on a QFile error code. */
262 void setFileError(QFile::FileError error);
263
264 /**
265 * Adds a commandline argument for the process, as returned
266 * by arguments()
267 */
268 void addArgument(const QString& argument);
269
270 /**
271 * clear the commandline arguments for the process, as returned
272 * by arguments()
273 */
274 void clearArguments();
275
276 /**
277 * Adds an environment binding for the process, as returned by
278 * environment()
279 *
280 * @param name The name of the environment variable, eg. "PATH"
281 * @param value The value of the environment variable, eg. "/bin"
282 */
283 void addEnvironmentBinding(const QString& name , const QString& value);
284
285private:
286 // takes a full directory path and returns a
287 // shortened version suitable for display in
288 // space-constrained UI elements (eg. tabs)
289 QString formatShortDir(const QString& dirPath) const;
290
291 // valid bits for _fields variable, ensure that
292 // _fields is changed to an int if more than 8 fields are added
293 enum FIELD_BITS {
294 PROCESS_ID = 1,
295 PARENT_PID = 2,
296 FOREGROUND_PID = 4,
297 ARGUMENTS = 8,
298 ENVIRONMENT = 16,
299 NAME = 32,
300 CURRENT_DIR = 64,
301 UID = 128
302 };
303
304 char _fields; // a bitmap indicating which fields are valid
305 // used to set the "ok" parameters for the public
306 // accessor functions
307
308 bool _enableEnvironmentRead; // specifies whether to read the environment
309 // bindings when update() is called
310 int _pid;
311 int _parentPid;
312 int _foregroundPid;
313 int _userId;
314
315 Error _lastError;
316
317 QString _name;
318 QString _userName;
319 QString _userHomeDir;
320 QString _currentDir;
321
322 QVector<QString> _arguments;
323 QMap<QString, QString> _environment;
324
325 static QSet<QString> commonDirNames();
326 static QSet<QString> _commonDirNames;
327};
328
329/**
330 * Implementation of ProcessInfo which does nothing.
331 * Used on platforms where a suitable ProcessInfo subclass is not
332 * available.
333 *
334 * isValid() will always return false for instances of NullProcessInfo
335 */
336class NullProcessInfo : public ProcessInfo
337{
338public:
339 /**
340 * Constructs a new NullProcessInfo instance.
341 * See ProcessInfo::newInstance()
342 */
343 explicit NullProcessInfo(int pid, bool readEnvironment = false);
344protected:
345 virtual bool readProcessInfo(int pid, bool readEnvironment);
346 virtual void readUserName(void);
347};
348
349#if !defined(Q_OS_WIN)
350/**
351 * Implementation of ProcessInfo for Unix platforms which uses
352 * the /proc filesystem
353 */
354class UnixProcessInfo : public ProcessInfo
355{
356public:
357 /**
358 * Constructs a new instance of UnixProcessInfo.
359 * See ProcessInfo::newInstance()
360 */
361 explicit UnixProcessInfo(int pid, bool readEnvironment = false);
362
363protected:
364 /**
365 * Implementation of ProcessInfo::readProcessInfo(); calls the
366 * four private methods below in turn.
367 */
368 virtual bool readProcessInfo(int pid , bool readEnvironment);
369
370 virtual void readUserName(void);
371
372private:
373 /**
374 * Read the standard process information -- PID, parent PID, foreground PID.
375 * @param pid process ID to use
376 * @return true on success
377 */
378 virtual bool readProcInfo(int pid) = 0;
379
380 /**
381 * Read the environment of the process. Sets _environment.
382 * @param pid process ID to use
383 * @return true on success
384 */
385 virtual bool readEnvironment(int pid) = 0;
386
387 /**
388 * Determine what arguments were passed to the process. Sets _arguments.
389 * @param pid process ID to use
390 * @return true on success
391 */
392 virtual bool readArguments(int pid) = 0;
393
394 /**
395 * Determine the current directory of the process.
396 * @param pid process ID to use
397 * @return true on success
398 */
399 virtual bool readCurrentDir(int pid) = 0;
400};
401#endif
402
403/**
404 * Lightweight class which provides additional information about SSH processes.
405 */
406class SSHProcessInfo
407{
408public:
409 /**
410 * Constructs a new SSHProcessInfo instance which provides additional
411 * information about the specified SSH process.
412 *
413 * @param process A ProcessInfo instance for a SSH process.
414 */
415 explicit SSHProcessInfo(const ProcessInfo& process);
416
417 /**
418 * Returns the user name which the user initially logged into on
419 * the remote computer.
420 */
421 QString userName() const;
422
423 /**
424 * Returns the host which the user has connected to.
425 */
426 QString host() const;
427
428 /**
429 * Returns the port on host which the user has connected to.
430 */
431 QString port() const;
432
433 /**
434 * Returns the command which the user specified to execute on the
435 * remote computer when starting the SSH process.
436 */
437 QString command() const;
438
439 /**
440 * Operates in the same way as ProcessInfo::format(), except
441 * that the set of markers understood is different:
442 *
443 * %u - Replaced with user name which the user initially logged
444 * into on the remote computer.
445 * %h - Replaced with the first part of the host name which
446 * is connected to.
447 * %H - Replaced with the full host name of the computer which
448 * is connected to.
449 * %c - Replaced with the command which the user specified
450 * to execute when starting the SSH process.
451 */
452 QString format(const QString& input) const;
453
454private:
455 const ProcessInfo& _process;
456 QString _user;
457 QString _host;
458 QString _port;
459 QString _command;
460};
461}
462#endif //PROCESSINFO_H
463