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 | |
29 | namespace 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 | */ |
74 | class ProcessInfo |
75 | { |
76 | public: |
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 | |
211 | protected: |
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 | |
285 | private: |
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 | */ |
336 | class NullProcessInfo : public ProcessInfo |
337 | { |
338 | public: |
339 | /** |
340 | * Constructs a new NullProcessInfo instance. |
341 | * See ProcessInfo::newInstance() |
342 | */ |
343 | explicit NullProcessInfo(int pid, bool readEnvironment = false); |
344 | protected: |
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 | */ |
354 | class UnixProcessInfo : public ProcessInfo |
355 | { |
356 | public: |
357 | /** |
358 | * Constructs a new instance of UnixProcessInfo. |
359 | * See ProcessInfo::newInstance() |
360 | */ |
361 | explicit UnixProcessInfo(int pid, bool readEnvironment = false); |
362 | |
363 | protected: |
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 | |
372 | private: |
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 | */ |
406 | class SSHProcessInfo |
407 | { |
408 | public: |
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 | |
454 | private: |
455 | const ProcessInfo& _process; |
456 | QString _user; |
457 | QString _host; |
458 | QString _port; |
459 | QString _command; |
460 | }; |
461 | } |
462 | #endif //PROCESSINFO_H |
463 | |