• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • applications API Reference
  • KDE Home
  • Contact Us
 

Konsole

  • kde-4.14
  • applications
  • konsole
  • src
ProcessInfo.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2007-2008 by Robert Knight <robertknight@gmail.countm>
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 // Config
21 #include <config-konsole.h>
22 
23 // Own
24 #include "ProcessInfo.h"
25 
26 // Unix
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <unistd.h>
31 #include <pwd.h>
32 #include <sys/param.h>
33 
34 // Qt
35 #include <QtCore/QDir>
36 #include <QtCore/QFileInfo>
37 #include <QtCore/QTextStream>
38 #include <QtCore/QStringList>
39 #include <QtNetwork/QHostInfo>
40 
41 // KDE
42 #include <KConfigGroup>
43 #include <KGlobal>
44 #include <KSharedConfig>
45 #include <KUser>
46 #include <KDebug>
47 
48 #if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) || defined(Q_OS_MAC)
49 #include <sys/sysctl.h>
50 #endif
51 
52 #if defined(Q_OS_MAC)
53 #include <libproc.h>
54 #include <kde_file.h>
55 #endif
56 
57 #if defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
58 #include <sys/types.h>
59 #include <sys/user.h>
60 #include <sys/syslimits.h>
61 # if defined(Q_OS_FREEBSD)
62 # include <libutil.h>
63 # endif
64 #endif
65 
66 using namespace Konsole;
67 
68 ProcessInfo::ProcessInfo(int aPid , bool enableEnvironmentRead)
69  : _fields(ARGUMENTS | ENVIRONMENT) // arguments and environments
70  // are currently always valid,
71  // they just return an empty
72  // vector / map respectively
73  // if no arguments
74  // or environment bindings
75  // have been explicitly set
76  , _enableEnvironmentRead(enableEnvironmentRead)
77  , _pid(aPid)
78  , _parentPid(0)
79  , _foregroundPid(0)
80  , _userId(0)
81  , _lastError(NoError)
82  , _userName(QString())
83  , _userHomeDir(QString())
84 {
85 }
86 
87 ProcessInfo::Error ProcessInfo::error() const
88 {
89  return _lastError;
90 }
91 void ProcessInfo::setError(Error error)
92 {
93  _lastError = error;
94 }
95 
96 void ProcessInfo::update()
97 {
98  readProcessInfo(_pid, _enableEnvironmentRead);
99 }
100 
101 QString ProcessInfo::validCurrentDir() const
102 {
103  bool ok = false;
104 
105  // read current dir, if an error occurs try the parent as the next
106  // best option
107  int currentPid = parentPid(&ok);
108  QString dir = currentDir(&ok);
109  while (!ok && currentPid != 0) {
110  ProcessInfo* current = ProcessInfo::newInstance(currentPid);
111  current->update();
112  currentPid = current->parentPid(&ok);
113  dir = current->currentDir(&ok);
114  delete current;
115  }
116 
117  return dir;
118 }
119 
120 QString ProcessInfo::format(const QString& input) const
121 {
122  bool ok = false;
123 
124  QString output(input);
125 
126  // search for and replace known marker
127  output.replace("%u", userName());
128  output.replace("%h", localHost());
129  output.replace("%n", name(&ok));
130 
131  QString dir = validCurrentDir();
132  if (output.contains("%D")) {
133  QString homeDir = userHomeDir();
134  QString tempDir = dir;
135  // Change User's Home Dir w/ ~ only at the beginning
136  if (tempDir.startsWith(homeDir)) {
137  tempDir.remove(0, homeDir.length());
138  tempDir.prepend('~');
139  }
140  output.replace("%D", tempDir);
141  }
142  output.replace("%d", formatShortDir(dir));
143 
144  return output;
145 }
146 
147 QSet<QString> ProcessInfo::_commonDirNames;
148 
149 QSet<QString> ProcessInfo::commonDirNames()
150 {
151  static bool forTheFirstTime = true;
152 
153  if (forTheFirstTime) {
154  const KSharedConfigPtr& config = KGlobal::config();
155  const KConfigGroup& configGroup = config->group("ProcessInfo");
156  _commonDirNames = QSet<QString>::fromList(configGroup.readEntry("CommonDirNames", QStringList()));
157 
158  forTheFirstTime = false;
159  }
160 
161  return _commonDirNames;
162 }
163 
164 QString ProcessInfo::formatShortDir(const QString& input) const
165 {
166  QString result;
167 
168  const QStringList& parts = input.split(QDir::separator());
169 
170  QSet<QString> dirNamesToShorten = commonDirNames();
171 
172  QListIterator<QString> iter(parts);
173  iter.toBack();
174 
175  // go backwards through the list of the path's parts
176  // adding abbreviations of common directory names
177  // and stopping when we reach a dir name which is not
178  // in the commonDirNames set
179  while (iter.hasPrevious()) {
180  const QString& part = iter.previous();
181 
182  if (dirNamesToShorten.contains(part)) {
183  result.prepend(QDir::separator() + part[0]);
184  } else {
185  result.prepend(part);
186  break;
187  }
188  }
189 
190  return result;
191 }
192 
193 QVector<QString> ProcessInfo::arguments(bool* ok) const
194 {
195  *ok = _fields & ARGUMENTS;
196 
197  return _arguments;
198 }
199 
200 QMap<QString, QString> ProcessInfo::environment(bool* ok) const
201 {
202  *ok = _fields & ENVIRONMENT;
203 
204  return _environment;
205 }
206 
207 bool ProcessInfo::isValid() const
208 {
209  return _fields & PROCESS_ID;
210 }
211 
212 int ProcessInfo::pid(bool* ok) const
213 {
214  *ok = _fields & PROCESS_ID;
215 
216  return _pid;
217 }
218 
219 int ProcessInfo::parentPid(bool* ok) const
220 {
221  *ok = _fields & PARENT_PID;
222 
223  return _parentPid;
224 }
225 
226 int ProcessInfo::foregroundPid(bool* ok) const
227 {
228  *ok = _fields & FOREGROUND_PID;
229 
230  return _foregroundPid;
231 }
232 
233 QString ProcessInfo::name(bool* ok) const
234 {
235  *ok = _fields & NAME;
236 
237  return _name;
238 }
239 
240 int ProcessInfo::userId(bool* ok) const
241 {
242  *ok = _fields & UID;
243 
244  return _userId;
245 }
246 
247 QString ProcessInfo::userName() const
248 {
249  return _userName;
250 }
251 
252 QString ProcessInfo::userHomeDir() const
253 {
254  return _userHomeDir;
255 }
256 
257 QString ProcessInfo::localHost()
258 {
259  return QHostInfo::localHostName();
260 }
261 
262 void ProcessInfo::setPid(int aPid)
263 {
264  _pid = aPid;
265  _fields |= PROCESS_ID;
266 }
267 
268 void ProcessInfo::setUserId(int uid)
269 {
270  _userId = uid;
271  _fields |= UID;
272 }
273 
274 void ProcessInfo::setUserName(const QString& name)
275 {
276  _userName = name;
277  setUserHomeDir();
278 }
279 
280 void ProcessInfo::setUserHomeDir()
281 {
282  const QString& usersName = userName();
283  if (!usersName.isEmpty())
284  _userHomeDir = KUser(usersName).homeDir();
285  else
286  _userHomeDir = QDir::homePath();
287 }
288 
289 void ProcessInfo::setParentPid(int aPid)
290 {
291  _parentPid = aPid;
292  _fields |= PARENT_PID;
293 }
294 void ProcessInfo::setForegroundPid(int aPid)
295 {
296  _foregroundPid = aPid;
297  _fields |= FOREGROUND_PID;
298 }
299 
300 QString ProcessInfo::currentDir(bool* ok) const
301 {
302  if (ok)
303  *ok = _fields & CURRENT_DIR;
304 
305  return _currentDir;
306 }
307 void ProcessInfo::setCurrentDir(const QString& dir)
308 {
309  _fields |= CURRENT_DIR;
310  _currentDir = dir;
311 }
312 
313 void ProcessInfo::setName(const QString& name)
314 {
315  _name = name;
316  _fields |= NAME;
317 }
318 void ProcessInfo::addArgument(const QString& argument)
319 {
320  _arguments << argument;
321 }
322 
323 void ProcessInfo::clearArguments()
324 {
325  _arguments.clear();
326 }
327 
328 void ProcessInfo::addEnvironmentBinding(const QString& name , const QString& value)
329 {
330  _environment.insert(name, value);
331 }
332 
333 void ProcessInfo::setFileError(QFile::FileError error)
334 {
335  switch (error) {
336  case QFile::PermissionsError:
337  setError(ProcessInfo::PermissionsError);
338  break;
339  case QFile::NoError:
340  setError(ProcessInfo::NoError);
341  break;
342  default:
343  setError(ProcessInfo::UnknownError);
344  }
345 }
346 
347 //
348 // ProcessInfo::newInstance() is way at the bottom so it can see all of the
349 // implementations of the UnixProcessInfo abstract class.
350 //
351 
352 NullProcessInfo::NullProcessInfo(int aPid, bool enableEnvironmentRead)
353  : ProcessInfo(aPid, enableEnvironmentRead)
354 {
355 }
356 
357 bool NullProcessInfo::readProcessInfo(int /*pid*/ , bool /*enableEnvironmentRead*/)
358 {
359  return false;
360 }
361 
362 void NullProcessInfo::readUserName()
363 {
364 }
365 
366 #if !defined(Q_OS_WIN)
367 UnixProcessInfo::UnixProcessInfo(int aPid, bool enableEnvironmentRead)
368  : ProcessInfo(aPid, enableEnvironmentRead)
369 {
370 }
371 
372 bool UnixProcessInfo::readProcessInfo(int aPid , bool enableEnvironmentRead)
373 {
374  // prevent _arguments from growing longer and longer each time this
375  // method is called.
376  clearArguments();
377 
378  bool ok = readProcInfo(aPid);
379  if (ok) {
380  ok |= readArguments(aPid);
381  ok |= readCurrentDir(aPid);
382  if (enableEnvironmentRead) {
383  ok |= readEnvironment(aPid);
384  }
385  }
386  return ok;
387 }
388 
389 void UnixProcessInfo::readUserName()
390 {
391  bool ok = false;
392  const int uid = userId(&ok);
393  if (!ok) return;
394 
395  struct passwd passwdStruct;
396  struct passwd* getpwResult;
397  char* getpwBuffer;
398  long getpwBufferSize;
399  int getpwStatus;
400 
401  getpwBufferSize = sysconf(_SC_GETPW_R_SIZE_MAX);
402  if (getpwBufferSize == -1)
403  getpwBufferSize = 16384;
404 
405  getpwBuffer = new char[getpwBufferSize];
406  if (getpwBuffer == NULL)
407  return;
408  getpwStatus = getpwuid_r(uid, &passwdStruct, getpwBuffer, getpwBufferSize, &getpwResult);
409  if ((getpwStatus == 0) && (getpwResult != NULL)) {
410  setUserName(QString(passwdStruct.pw_name));
411  } else {
412  setUserName(QString());
413  kWarning() << "getpwuid_r returned error : " << getpwStatus;
414  }
415  delete [] getpwBuffer;
416 }
417 #endif
418 
419 #if defined(Q_OS_LINUX)
420 class LinuxProcessInfo : public UnixProcessInfo
421 {
422 public:
423  LinuxProcessInfo(int aPid, bool env) :
424  UnixProcessInfo(aPid, env) {
425  }
426 
427 private:
428  virtual bool readProcInfo(int aPid) {
429  // indicies of various fields within the process status file which
430  // contain various information about the process
431  const int PARENT_PID_FIELD = 3;
432  const int PROCESS_NAME_FIELD = 1;
433  const int GROUP_PROCESS_FIELD = 7;
434 
435  QString parentPidString;
436  QString processNameString;
437  QString foregroundPidString;
438  QString uidLine;
439  QString uidString;
440  QStringList uidStrings;
441 
442  // For user id read process status file ( /proc/<pid>/status )
443  // Can not use getuid() due to it does not work for 'su'
444  QFile statusInfo(QString("/proc/%1/status").arg(aPid));
445  if (statusInfo.open(QIODevice::ReadOnly)) {
446  QTextStream stream(&statusInfo);
447  QString statusLine;
448  do {
449  statusLine = stream.readLine(0);
450  if (statusLine.startsWith(QLatin1String("Uid:")))
451  uidLine = statusLine;
452  } while (!statusLine.isNull() && uidLine.isNull());
453 
454  uidStrings << uidLine.split('\t', QString::SkipEmptyParts);
455  // Must be 5 entries: 'Uid: %d %d %d %d' and
456  // uid string must be less than 5 chars (uint)
457  if (uidStrings.size() == 5)
458  uidString = uidStrings[1];
459  if (uidString.size() > 5)
460  uidString.clear();
461 
462  bool ok = false;
463  const int uid = uidString.toInt(&ok);
464  if (ok)
465  setUserId(uid);
466  readUserName();
467  } else {
468  setFileError(statusInfo.error());
469  return false;
470  }
471 
472  // read process status file ( /proc/<pid/stat )
473  //
474  // the expected file format is a list of fields separated by spaces, using
475  // parenthesies to escape fields such as the process name which may itself contain
476  // spaces:
477  //
478  // FIELD FIELD (FIELD WITH SPACES) FIELD FIELD
479  //
480  QFile processInfo(QString("/proc/%1/stat").arg(aPid));
481  if (processInfo.open(QIODevice::ReadOnly)) {
482  QTextStream stream(&processInfo);
483  const QString& data = stream.readAll();
484 
485  int stack = 0;
486  int field = 0;
487  int pos = 0;
488 
489  while (pos < data.count()) {
490  QChar c = data[pos];
491 
492  if (c == '(') {
493  stack++;
494  } else if (c == ')') {
495  stack--;
496  } else if (stack == 0 && c == ' ') {
497  field++;
498  } else {
499  switch (field) {
500  case PARENT_PID_FIELD:
501  parentPidString.append(c);
502  break;
503  case PROCESS_NAME_FIELD:
504  processNameString.append(c);
505  break;
506  case GROUP_PROCESS_FIELD:
507  foregroundPidString.append(c);
508  break;
509  }
510  }
511 
512  pos++;
513  }
514  } else {
515  setFileError(processInfo.error());
516  return false;
517  }
518 
519  // check that data was read successfully
520  bool ok = false;
521  const int foregroundPid = foregroundPidString.toInt(&ok);
522  if (ok)
523  setForegroundPid(foregroundPid);
524 
525  const int parentPid = parentPidString.toInt(&ok);
526  if (ok)
527  setParentPid(parentPid);
528 
529  if (!processNameString.isEmpty())
530  setName(processNameString);
531 
532  // update object state
533  setPid(aPid);
534 
535  return ok;
536  }
537 
538  virtual bool readArguments(int aPid) {
539  // read command-line arguments file found at /proc/<pid>/cmdline
540  // the expected format is a list of strings delimited by null characters,
541  // and ending in a double null character pair.
542 
543  QFile argumentsFile(QString("/proc/%1/cmdline").arg(aPid));
544  if (argumentsFile.open(QIODevice::ReadOnly)) {
545  QTextStream stream(&argumentsFile);
546  const QString& data = stream.readAll();
547 
548  const QStringList& argList = data.split(QChar('\0'));
549 
550  foreach(const QString & entry , argList) {
551  if (!entry.isEmpty())
552  addArgument(entry);
553  }
554  } else {
555  setFileError(argumentsFile.error());
556  }
557 
558  return true;
559  }
560 
561  virtual bool readCurrentDir(int aPid) {
562  char path_buffer[MAXPATHLEN + 1];
563  path_buffer[MAXPATHLEN] = 0;
564  QByteArray procCwd = QFile::encodeName(QString("/proc/%1/cwd").arg(aPid));
565  const int length = readlink(procCwd.constData(), path_buffer, MAXPATHLEN);
566  if (length == -1) {
567  setError(UnknownError);
568  return false;
569  }
570 
571  path_buffer[length] = '\0';
572  QString path = QFile::decodeName(path_buffer);
573 
574  setCurrentDir(path);
575  return true;
576  }
577 
578  virtual bool readEnvironment(int aPid) {
579  // read environment bindings file found at /proc/<pid>/environ
580  // the expected format is a list of KEY=VALUE strings delimited by null
581  // characters and ending in a double null character pair.
582 
583  QFile environmentFile(QString("/proc/%1/environ").arg(aPid));
584  if (environmentFile.open(QIODevice::ReadOnly)) {
585  QTextStream stream(&environmentFile);
586  const QString& data = stream.readAll();
587 
588  const QStringList& bindingList = data.split(QChar('\0'));
589 
590  foreach(const QString & entry , bindingList) {
591  QString name;
592  QString value;
593 
594  const int splitPos = entry.indexOf('=');
595 
596  if (splitPos != -1) {
597  name = entry.mid(0, splitPos);
598  value = entry.mid(splitPos + 1, -1);
599 
600  addEnvironmentBinding(name, value);
601  }
602  }
603  } else {
604  setFileError(environmentFile.error());
605  }
606 
607  return true;
608  }
609 };
610 
611 #elif defined(Q_OS_FREEBSD)
612 class FreeBSDProcessInfo : public UnixProcessInfo
613 {
614 public:
615  FreeBSDProcessInfo(int aPid, bool readEnvironment) :
616  UnixProcessInfo(aPid, readEnvironment) {
617  }
618 
619 private:
620  virtual bool readProcInfo(int aPid) {
621  int managementInfoBase[4];
622  size_t mibLength;
623  struct kinfo_proc* kInfoProc;
624 
625  managementInfoBase[0] = CTL_KERN;
626  managementInfoBase[1] = KERN_PROC;
627  managementInfoBase[2] = KERN_PROC_PID;
628  managementInfoBase[3] = aPid;
629 
630  if (sysctl(managementInfoBase, 4, NULL, &mibLength, NULL, 0) == -1)
631  return false;
632 
633  kInfoProc = new struct kinfo_proc [mibLength];
634 
635  if (sysctl(managementInfoBase, 4, kInfoProc, &mibLength, NULL, 0) == -1) {
636  delete [] kInfoProc;
637  return false;
638  }
639 
640 #if defined(HAVE_OS_DRAGONFLYBSD)
641  setName(kInfoProc->kp_comm);
642  setPid(kInfoProc->kp_pid);
643  setParentPid(kInfoProc->kp_ppid);
644  setForegroundPid(kInfoProc->kp_pgid);
645  setUserId(kInfoProc->kp_uid);
646 #else
647  setName(kInfoProc->ki_comm);
648  setPid(kInfoProc->ki_pid);
649  setParentPid(kInfoProc->ki_ppid);
650  setForegroundPid(kInfoProc->ki_pgid);
651  setUserId(kInfoProc->ki_uid);
652 #endif
653 
654  readUserName();
655 
656  delete [] kInfoProc;
657  return true;
658  }
659 
660  virtual bool readArguments(int aPid) {
661  char args[ARG_MAX];
662  int managementInfoBase[4];
663  size_t len;
664 
665  managementInfoBase[0] = CTL_KERN;
666  managementInfoBase[1] = KERN_PROC;
667  managementInfoBase[2] = KERN_PROC_PID;
668  managementInfoBase[3] = aPid;
669 
670  len = sizeof(args);
671  if (sysctl(managementInfoBase, 4, args, &len, NULL, 0) == -1)
672  return false;
673 
674  const QStringList& argumentList = QString(args).split(QChar('\0'));
675 
676  for (QStringList::const_iterator it = argumentList.begin(); it != argumentList.end(); ++it) {
677  addArgument(*it);
678  }
679 
680  return true;
681  }
682 
683  virtual bool readEnvironment(int aPid) {
684  Q_UNUSED(aPid);
685  // Not supported in FreeBSD?
686  return false;
687  }
688 
689  virtual bool readCurrentDir(int aPid) {
690 #if defined(HAVE_OS_DRAGONFLYBSD)
691  char buf[PATH_MAX];
692  int managementInfoBase[4];
693  size_t len;
694 
695  managementInfoBase[0] = CTL_KERN;
696  managementInfoBase[1] = KERN_PROC;
697  managementInfoBase[2] = KERN_PROC_CWD;
698  managementInfoBase[3] = aPid;
699 
700  len = sizeof(buf);
701  if (sysctl(managementInfoBase, 4, buf, &len, NULL, 0) == -1)
702  return false;
703 
704  setCurrentDir(buf);
705 
706  return true;
707 #else
708  int numrecords;
709  struct kinfo_file* info = 0;
710 
711  info = kinfo_getfile(aPid, &numrecords);
712 
713  if (!info)
714  return false;
715 
716  for (int i = 0; i < numrecords; ++i) {
717  if (info[i].kf_fd == KF_FD_TYPE_CWD) {
718  setCurrentDir(info[i].kf_path);
719 
720  free(info);
721  return true;
722  }
723  }
724 
725  free(info);
726  return false;
727 #endif
728  }
729 };
730 
731 #elif defined(Q_OS_OPENBSD)
732 class OpenBSDProcessInfo : public UnixProcessInfo
733 {
734 public:
735  OpenBSDProcessInfo(int aPid, bool readEnvironment) :
736  UnixProcessInfo(aPid, readEnvironment) {
737  }
738 
739 private:
740  virtual bool readProcInfo(int aPid) {
741  int managementInfoBase[6];
742  size_t mibLength;
743  struct kinfo_proc* kInfoProc;
744 
745  managementInfoBase[0] = CTL_KERN;
746  managementInfoBase[1] = KERN_PROC;
747  managementInfoBase[2] = KERN_PROC_PID;
748  managementInfoBase[3] = aPid;
749  managementInfoBase[4] = sizeof(struct kinfo_proc);
750  managementInfoBase[5] = 1;
751 
752  if (::sysctl(managementInfoBase, 6, NULL, &mibLength, NULL, 0) == -1) {
753  kWarning() << "first sysctl() call failed with code" << errno;
754  return false;
755  }
756 
757  kInfoProc = (struct kinfo_proc*)malloc(mibLength);
758 
759  if (::sysctl(managementInfoBase, 6, kInfoProc, &mibLength, NULL, 0) == -1) {
760  kWarning() << "second sysctl() call failed with code" << errno;
761  free(kInfoProc);
762  return false;
763  }
764 
765  setName(kInfoProc->p_comm);
766  setPid(kInfoProc->p_pid);
767  setParentPid(kInfoProc->p_ppid);
768  setForegroundPid(kInfoProc->p_tpgid);
769  setUserId(kInfoProc->p_uid);
770  setUserName(kInfoProc->p_login);
771 
772  free(kInfoProc);
773  return true;
774  }
775 
776  char** readProcArgs(int aPid, int whatMib) {
777  void* buf = NULL;
778  void* nbuf;
779  size_t len = 4096;
780  int rc = -1;
781  int managementInfoBase[4];
782 
783  managementInfoBase[0] = CTL_KERN;
784  managementInfoBase[1] = KERN_PROC_ARGS;
785  managementInfoBase[2] = aPid;
786  managementInfoBase[3] = whatMib;
787 
788  do {
789  len *= 2;
790  nbuf = realloc(buf, len);
791  if (nbuf == NULL) {
792  break;
793  }
794 
795  buf = nbuf;
796  rc = ::sysctl(managementInfoBase, 4, buf, &len, NULL, 0);
797  kWarning() << "sysctl() call failed with code" << errno;
798  } while (rc == -1 && errno == ENOMEM);
799 
800  if (nbuf == NULL || rc == -1) {
801  free(buf);
802  return NULL;
803  }
804 
805  return (char**)buf;
806  }
807 
808  virtual bool readArguments(int aPid) {
809  char** argv;
810 
811  argv = readProcArgs(aPid, KERN_PROC_ARGV);
812  if (argv == NULL) {
813  return false;
814  }
815 
816  for (char** p = argv; *p != NULL; p++) {
817  addArgument(QString(*p));
818  }
819  free(argv);
820  return true;
821  }
822 
823  virtual bool readEnvironment(int aPid) {
824  char** envp;
825  char* eqsign;
826 
827  envp = readProcArgs(aPid, KERN_PROC_ENV);
828  if (envp == NULL) {
829  return false;
830  }
831 
832  for (char **p = envp; *p != NULL; p++) {
833  eqsign = strchr(*p, '=');
834  if (eqsign == NULL || eqsign[1] == '\0') {
835  continue;
836  }
837  *eqsign = '\0';
838  addEnvironmentBinding(QString((const char *)p),
839  QString((const char *)eqsign + 1));
840  }
841  free(envp);
842  return true;
843  }
844 
845  virtual bool readCurrentDir(int aPid) {
846  char buf[PATH_MAX];
847  int managementInfoBase[3];
848  size_t len;
849 
850  managementInfoBase[0] = CTL_KERN;
851  managementInfoBase[1] = KERN_PROC_CWD;
852  managementInfoBase[2] = aPid;
853 
854  len = sizeof(buf);
855  if (::sysctl(managementInfoBase, 3, buf, &len, NULL, 0) == -1) {
856  kWarning() << "sysctl() call failed with code" << errno;
857  return false;
858  }
859 
860  setCurrentDir(buf);
861  return true;
862  }
863 };
864 
865 #elif defined(Q_OS_MAC)
866 class MacProcessInfo : public UnixProcessInfo
867 {
868 public:
869  MacProcessInfo(int aPid, bool env) :
870  UnixProcessInfo(aPid, env) {
871  }
872 
873 private:
874  virtual bool readProcInfo(int aPid) {
875  int managementInfoBase[4];
876  size_t mibLength;
877  struct kinfo_proc* kInfoProc;
878  KDE_struct_stat statInfo;
879 
880  // Find the tty device of 'pid' (Example: /dev/ttys001)
881  managementInfoBase[0] = CTL_KERN;
882  managementInfoBase[1] = KERN_PROC;
883  managementInfoBase[2] = KERN_PROC_PID;
884  managementInfoBase[3] = aPid;
885 
886  if (sysctl(managementInfoBase, 4, NULL, &mibLength, NULL, 0) == -1) {
887  return false;
888  } else {
889  kInfoProc = new struct kinfo_proc [mibLength];
890  if (sysctl(managementInfoBase, 4, kInfoProc, &mibLength, NULL, 0) == -1) {
891  delete [] kInfoProc;
892  return false;
893  } else {
894  const QString deviceNumber = QString(devname(((&kInfoProc->kp_eproc)->e_tdev), S_IFCHR));
895  const QString fullDeviceName = QString("/dev/") + deviceNumber.rightJustified(3, '0');
896  delete [] kInfoProc;
897 
898  const QByteArray deviceName = fullDeviceName.toLatin1();
899  const char* ttyName = deviceName.data();
900 
901  if (KDE::stat(ttyName, &statInfo) != 0)
902  return false;
903 
904  // Find all processes attached to ttyName
905  managementInfoBase[0] = CTL_KERN;
906  managementInfoBase[1] = KERN_PROC;
907  managementInfoBase[2] = KERN_PROC_TTY;
908  managementInfoBase[3] = statInfo.st_rdev;
909 
910  mibLength = 0;
911  if (sysctl(managementInfoBase, sizeof(managementInfoBase) / sizeof(int), NULL, &mibLength, NULL, 0) == -1)
912  return false;
913 
914  kInfoProc = new struct kinfo_proc [mibLength];
915  if (sysctl(managementInfoBase, sizeof(managementInfoBase) / sizeof(int), kInfoProc, &mibLength, NULL, 0) == -1)
916  return false;
917 
918  // The foreground program is the first one
919  setName(QString(kInfoProc->kp_proc.p_comm));
920 
921  delete [] kInfoProc;
922  }
923  setPid(aPid);
924  }
925  return true;
926  }
927 
928  virtual bool readArguments(int aPid) {
929  Q_UNUSED(aPid);
930  return false;
931  }
932  virtual bool readCurrentDir(int aPid) {
933  struct proc_vnodepathinfo vpi;
934  const int nb = proc_pidinfo(aPid, PROC_PIDVNODEPATHINFO, 0, &vpi, sizeof(vpi));
935  if (nb == sizeof(vpi)) {
936  setCurrentDir(QString(vpi.pvi_cdir.vip_path));
937  return true;
938  }
939  return false;
940  }
941  virtual bool readEnvironment(int aPid) {
942  Q_UNUSED(aPid);
943  return false;
944  }
945 };
946 
947 #elif defined(Q_OS_SOLARIS)
948 // The procfs structure definition requires off_t to be
949 // 32 bits, which only applies if FILE_OFFSET_BITS=32.
950 // Futz around here to get it to compile regardless,
951 // although some of the structure sizes might be wrong.
952 // Fortunately, the structures we actually use don't use
953 // off_t, and we're safe.
954 #if defined(_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS==64)
955 #undef _FILE_OFFSET_BITS
956 #endif
957 #include <procfs.h>
958 
959 class SolarisProcessInfo : public UnixProcessInfo
960 {
961 public:
962  SolarisProcessInfo(int aPid, bool readEnvironment)
963  : UnixProcessInfo(aPid, readEnvironment) {
964  }
965 private:
966  virtual bool readProcInfo(int aPid) {
967  QFile psinfo(QString("/proc/%1/psinfo").arg(aPid));
968  if (psinfo.open(QIODevice::ReadOnly)) {
969  struct psinfo info;
970  if (psinfo.read((char *)&info, sizeof(info)) != sizeof(info)) {
971  return false;
972  }
973 
974  setParentPid(info.pr_ppid);
975  setForegroundPid(info.pr_pgid);
976  setName(info.pr_fname);
977  setPid(aPid);
978 
979  // Bogus, because we're treating the arguments as one single string
980  info.pr_psargs[PRARGSZ - 1] = 0;
981  addArgument(info.pr_psargs);
982  }
983  return true;
984  }
985 
986  virtual bool readArguments(int /*pid*/) {
987  // Handled in readProcInfo()
988  return false;
989  }
990 
991  virtual bool readEnvironment(int /*pid*/) {
992  // Not supported in Solaris
993  return false;
994  }
995 
996  // FIXME: This will have the same issues as BKO 251351; the Linux
997  // version uses readlink.
998  virtual bool readCurrentDir(int aPid) {
999  QFileInfo info(QString("/proc/%1/path/cwd").arg(aPid));
1000  const bool readable = info.isReadable();
1001 
1002  if (readable && info.isSymLink()) {
1003  setCurrentDir(info.symLinkTarget());
1004  return true;
1005  } else {
1006  if (!readable)
1007  setError(PermissionsError);
1008  else
1009  setError(UnknownError);
1010 
1011  return false;
1012  }
1013  }
1014 };
1015 #endif
1016 
1017 SSHProcessInfo::SSHProcessInfo(const ProcessInfo& process)
1018  : _process(process)
1019 {
1020  bool ok = false;
1021 
1022  // check that this is a SSH process
1023  const QString& name = _process.name(&ok);
1024 
1025  if (!ok || name != "ssh") {
1026  if (!ok)
1027  kWarning() << "Could not read process info";
1028  else
1029  kWarning() << "Process is not a SSH process";
1030 
1031  return;
1032  }
1033 
1034  // read arguments
1035  const QVector<QString>& args = _process.arguments(&ok);
1036 
1037  // SSH options
1038  // these are taken from the SSH manual ( accessed via 'man ssh' )
1039 
1040  // options which take no arguments
1041  static const QString noArgumentOptions("1246AaCfgKkMNnqsTtVvXxYy");
1042  // options which take one argument
1043  static const QString singleArgumentOptions("bcDeFIiLlmOopRSWw");
1044 
1045  if (ok) {
1046  // find the username, host and command arguments
1047  //
1048  // the username/host is assumed to be the first argument
1049  // which is not an option
1050  // ( ie. does not start with a dash '-' character )
1051  // or an argument to a previous option.
1052  //
1053  // the command, if specified, is assumed to be the argument following
1054  // the username and host
1055  //
1056  // note that we skip the argument at index 0 because that is the
1057  // program name ( expected to be 'ssh' in this case )
1058  for (int i = 1 ; i < args.count() ; i++) {
1059  // If this one is an option ...
1060  // Most options together with its argument will be skipped.
1061  if (args[i].startsWith('-')) {
1062  const QChar optionChar = (args[i].length() > 1) ? args[i][1] : '\0';
1063  // for example: -p2222 or -p 2222 ?
1064  const bool optionArgumentCombined = args[i].length() > 2;
1065 
1066  if (noArgumentOptions.contains(optionChar)) {
1067  continue;
1068  } else if (singleArgumentOptions.contains(optionChar)) {
1069  QString argument;
1070  if (optionArgumentCombined) {
1071  argument = args[i].mid(2);
1072  } else {
1073  // Verify correct # arguments are given
1074  if ((i + 1) < args.count()) {
1075  argument = args[i + 1];
1076  }
1077  i++;
1078  }
1079 
1080  // support using `-l user` to specify username.
1081  if (optionChar == 'l')
1082  _user = argument;
1083  // support using `-p port` to specify port.
1084  else if (optionChar == 'p')
1085  _port = argument;
1086 
1087  continue;
1088  }
1089  }
1090 
1091  // check whether the host has been found yet
1092  // if not, this must be the username/host argument
1093  if (_host.isEmpty()) {
1094  // check to see if only a hostname is specified, or whether
1095  // both a username and host are specified ( in which case they
1096  // are separated by an '@' character: username@host )
1097 
1098  const int separatorPosition = args[i].indexOf('@');
1099  if (separatorPosition != -1) {
1100  // username and host specified
1101  _user = args[i].left(separatorPosition);
1102  _host = args[i].mid(separatorPosition + 1);
1103  } else {
1104  // just the host specified
1105  _host = args[i];
1106  }
1107  } else {
1108  // host has already been found, this must be the command argument
1109  _command = args[i];
1110  }
1111  }
1112  } else {
1113  kWarning() << "Could not read arguments";
1114 
1115  return;
1116  }
1117 }
1118 
1119 QString SSHProcessInfo::userName() const
1120 {
1121  return _user;
1122 }
1123 QString SSHProcessInfo::host() const
1124 {
1125  return _host;
1126 }
1127 QString SSHProcessInfo::port() const
1128 {
1129  return _port;
1130 }
1131 QString SSHProcessInfo::command() const
1132 {
1133  return _command;
1134 }
1135 QString SSHProcessInfo::format(const QString& input) const
1136 {
1137  QString output(input);
1138 
1139  // test whether host is an ip address
1140  // in which case 'short host' and 'full host'
1141  // markers in the input string are replaced with
1142  // the full address
1143  bool isIpAddress = false;
1144 
1145  struct in_addr address;
1146  if (inet_aton(_host.toLocal8Bit().constData(), &address) != 0)
1147  isIpAddress = true;
1148  else
1149  isIpAddress = false;
1150 
1151  // search for and replace known markers
1152  output.replace("%u", _user);
1153 
1154  if (isIpAddress)
1155  output.replace("%h", _host);
1156  else
1157  output.replace("%h", _host.left(_host.indexOf('.')));
1158 
1159  output.replace("%H", _host);
1160  output.replace("%c", _command);
1161 
1162  return output;
1163 }
1164 
1165 ProcessInfo* ProcessInfo::newInstance(int aPid, bool enableEnvironmentRead)
1166 {
1167 #if defined(Q_OS_LINUX)
1168  return new LinuxProcessInfo(aPid, enableEnvironmentRead);
1169 #elif defined(Q_OS_SOLARIS)
1170  return new SolarisProcessInfo(aPid, enableEnvironmentRead);
1171 #elif defined(Q_OS_MAC)
1172  return new MacProcessInfo(aPid, enableEnvironmentRead);
1173 #elif defined(Q_OS_FREEBSD)
1174  return new FreeBSDProcessInfo(aPid, enableEnvironmentRead);
1175 #elif defined(Q_OS_OPENBSD)
1176  return new OpenBSDProcessInfo(aPid, enableEnvironmentRead);
1177 #else
1178  return new NullProcessInfo(aPid, enableEnvironmentRead);
1179 #endif
1180 }
1181 
QString::indexOf
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const
QString::append
QString & append(QChar ch)
Konsole::ProcessInfo::userHomeDir
QString userHomeDir() const
Returns the user's home directory of the process.
Definition: ProcessInfo.cpp:252
Konsole::ProcessInfo::environment
QMap< QString, QString > environment(bool *ok) const
Returns the environment bindings which the process was started with.
Definition: ProcessInfo.cpp:200
QByteArray
Konsole::ProcessInfo::currentDir
QString currentDir(bool *ok) const
Returns the current working directory of the process.
Definition: ProcessInfo.cpp:300
Konsole::ProcessInfo::setError
void setError(Error error)
Sets the error.
Definition: ProcessInfo.cpp:91
QVector::indexOf
int indexOf(const T &value, int from) const
QChar
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
Konsole::ProcessInfo::setUserName
void setUserName(const QString &name)
Sets the user name of the process as set by readUserName()
Definition: ProcessInfo.cpp:274
QString::prepend
QString & prepend(QChar ch)
Konsole::ProcessInfo::NoError
No error occurred.
Definition: ProcessInfo.h:199
QMap< QString, QString >
QString::size
int size() const
Konsole::NullProcessInfo::readProcessInfo
virtual bool readProcessInfo(int pid, bool readEnvironment)
This is called on construction to read the process state Subclasses should reimplement this function ...
Definition: ProcessInfo.cpp:357
Konsole::ProcessInfo::setCurrentDir
void setCurrentDir(const QString &dir)
Sets the current working directory for the process.
Definition: ProcessInfo.cpp:307
Konsole::ProcessInfo::foregroundPid
int foregroundPid(bool *ok) const
Returns the id of the current foreground process.
Definition: ProcessInfo.cpp:226
Konsole::ProcessInfo::localHost
static QString localHost()
Returns the local host.
Definition: ProcessInfo.cpp:257
Konsole::ProcessInfo::setPid
void setPid(int pid)
Sets the process id associated with this ProcessInfo instance.
Definition: ProcessInfo.cpp:262
QString::remove
QString & remove(int position, int n)
QDir::homePath
QString homePath()
QDir::separator
QChar separator()
QList::const_iterator
ProcessInfo.h
QFile
Konsole::ProcessInfo::newInstance
static ProcessInfo * newInstance(int pid, bool readEnvironment=false)
Constructs a new instance of a suitable ProcessInfo sub-class for the current platform which provides...
Definition: ProcessInfo.cpp:1165
QTextStream
QList::size
int size() const
Konsole::ProcessInfo::pid
int pid(bool *ok) const
Returns the process id.
Definition: ProcessInfo.cpp:212
Konsole::ProcessInfo::update
void update()
Updates the information about the process.
Definition: ProcessInfo.cpp:96
QString::isNull
bool isNull() const
Konsole::NullProcessInfo::NullProcessInfo
NullProcessInfo(int pid, bool readEnvironment=false)
Constructs a new NullProcessInfo instance.
Definition: ProcessInfo.cpp:352
Konsole::ProcessInfo::ProcessInfo
ProcessInfo(int pid, bool readEnvironment=false)
Constructs a new process instance.
Definition: ProcessInfo.cpp:68
Konsole::SSHProcessInfo::userName
QString userName() const
Returns the user name which the user initially logged into on the remote computer.
Definition: ProcessInfo.cpp:1119
QString::clear
void clear()
Konsole::ProcessInfo::setName
void setName(const QString &name)
Sets the name of the process as returned by name()
Definition: ProcessInfo.cpp:313
QVector::clear
void clear()
Konsole::ProcessInfo::setUserHomeDir
void setUserHomeDir()
Forces the user home directory to be calculated.
Definition: ProcessInfo.cpp:280
Konsole::ProcessInfo::name
QString name(bool *ok) const
Returns the name of the current process.
Definition: ProcessInfo.cpp:233
Konsole::SSHProcessInfo::command
QString command() const
Returns the command which the user specified to execute on the remote computer when starting the SSH ...
Definition: ProcessInfo.cpp:1131
Konsole::UnixProcessInfo
Implementation of ProcessInfo for Unix platforms which uses the /proc filesystem. ...
Definition: ProcessInfo.h:354
QString::rightJustified
QString rightJustified(int width, QChar fill, bool truncate) const
Konsole::ProcessInfo::addEnvironmentBinding
void addEnvironmentBinding(const QString &name, const QString &value)
Adds an environment binding for the process, as returned by environment()
Definition: ProcessInfo.cpp:328
QString::toInt
int toInt(bool *ok, int base) const
Konsole::ProcessInfo
Takes a snapshot of the state of a process and provides access to information such as the process nam...
Definition: ProcessInfo.h:74
QString::isEmpty
bool isEmpty() const
QByteArray::constData
const char * constData() const
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
Konsole::ProcessInfo::format
QString format(const QString &text) const
Parses an input string, looking for markers beginning with a '' character and returns a string with t...
Definition: ProcessInfo.cpp:120
Konsole::UnixProcessInfo::UnixProcessInfo
UnixProcessInfo(int pid, bool readEnvironment=false)
Constructs a new instance of UnixProcessInfo.
Definition: ProcessInfo.cpp:367
Konsole::ProcessInfo::setUserId
void setUserId(int uid)
Sets the user id associated with this ProcessInfo instance.
Definition: ProcessInfo.cpp:268
Konsole::ProcessInfo::userName
QString userName() const
Returns the user's name of the process.
Definition: ProcessInfo.cpp:247
Konsole::UnixProcessInfo::readProcessInfo
virtual bool readProcessInfo(int pid, bool readEnvironment)
Implementation of ProcessInfo::readProcessInfo(); calls the four private methods below in turn...
Definition: ProcessInfo.cpp:372
QVector::mid
QVector< T > mid(int pos, int length) const
QSet< QString >
Konsole::SSHProcessInfo::host
QString host() const
Returns the host which the user has connected to.
Definition: ProcessInfo.cpp:1123
Konsole::ProcessInfo::setForegroundPid
void setForegroundPid(int pid)
Sets the foreground process id as returned by foregroundPid()
Definition: ProcessInfo.cpp:294
QString
Konsole::ProcessInfo::Error
Error
This enum describes the errors which can occur when trying to read a process's information.
Definition: ProcessInfo.h:197
QStringList
QFileInfo
QList::end
iterator end()
QString::toLocal8Bit
QByteArray toLocal8Bit() const
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
Konsole::ProcessInfo::validCurrentDir
QString validCurrentDir() const
Returns the current working directory of the process (or its parent)
Definition: ProcessInfo.cpp:101
QSet::contains
bool contains(const T &value) const
Konsole::ProcessInfo::isValid
bool isValid() const
Returns true if the process state was read successfully.
Definition: ProcessInfo.cpp:207
Konsole::ProcessInfo::UnknownError
The nature of the error is unknown.
Definition: ProcessInfo.h:201
Konsole::UnixProcessInfo::readUserName
virtual void readUserName(void)
Definition: ProcessInfo.cpp:389
QString::replace
QString & replace(int position, int n, QChar after)
Konsole::SSHProcessInfo::SSHProcessInfo
SSHProcessInfo(const ProcessInfo &process)
Constructs a new SSHProcessInfo instance which provides additional information about the specified SS...
Definition: ProcessInfo.cpp:1017
QString::toLatin1
QByteArray toLatin1() const
QString::mid
QString mid(int position, int n) const
QVector< QString >
QLatin1String
Konsole::NullProcessInfo
Implementation of ProcessInfo which does nothing.
Definition: ProcessInfo.h:336
Konsole::SSHProcessInfo::format
QString format(const QString &input) const
Operates in the same way as ProcessInfo::format(), except that the set of markers understood is diffe...
Definition: ProcessInfo.cpp:1135
QString::count
int count() const
Konsole::ProcessInfo::parentPid
int parentPid(bool *ok) const
Returns the id of the parent process id was read successfully or false otherwise. ...
Definition: ProcessInfo.cpp:219
Konsole::ProcessInfo::arguments
QVector< QString > arguments(bool *ok) const
Returns the command-line arguments which the process was started with.
Definition: ProcessInfo.cpp:193
QVector::count
int count(const T &value) const
QSet::fromList
QSet< T > fromList(const QList< T > &list)
QString::length
int length() const
QByteArray::data
char * data()
QString::left
QString left(int n) const
QHostInfo::localHostName
QString localHostName()
Konsole::ProcessInfo::addArgument
void addArgument(const QString &argument)
Adds a commandline argument for the process, as returned by arguments()
Definition: ProcessInfo.cpp:318
Konsole::ProcessInfo::PermissionsError
Konsole does not have permission to obtain the process information.
Definition: ProcessInfo.h:203
QMap::insert
iterator insert(const Key &key, const T &value)
QListIterator
Konsole::ProcessInfo::setFileError
void setFileError(QFile::FileError error)
Convenience method.
Definition: ProcessInfo.cpp:333
Konsole::ProcessInfo::error
Error error() const
Returns the last error which occurred.
Definition: ProcessInfo.cpp:87
Konsole::ProcessInfo::setParentPid
void setParentPid(int pid)
Sets the parent process id as returned by parentPid()
Definition: ProcessInfo.cpp:289
Konsole::NullProcessInfo::readUserName
virtual void readUserName(void)
Definition: ProcessInfo.cpp:362
Konsole::ProcessInfo::clearArguments
void clearArguments()
clear the commandline arguments for the process, as returned by arguments()
Definition: ProcessInfo.cpp:323
Konsole::ProcessInfo::readProcessInfo
virtual bool readProcessInfo(int pid, bool readEnvironment)=0
This is called on construction to read the process state Subclasses should reimplement this function ...
QList::begin
iterator begin()
QFile::encodeName
QByteArray encodeName(const QString &fileName)
QFile::decodeName
QString decodeName(const QByteArray &localFileName)
Konsole::ProcessInfo::userId
int userId(bool *ok) const
Definition: ProcessInfo.cpp:240
Konsole::SSHProcessInfo::port
QString port() const
Returns the port on host which the user has connected to.
Definition: ProcessInfo.cpp:1127
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat May 9 2020 03:56:27 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Konsole

Skip menu "Konsole"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

applications API Reference

Skip menu "applications API Reference"
  •   kate
  •       kate
  •   KTextEditor
  •   Kate
  • Konsole

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal