Vidalia  0.3.1
procutil.cpp
Go to the documentation of this file.
1 /*
2 ** This file is part of Vidalia, and is subject to the license terms in the
3 ** LICENSE file, found in the top level directory of this distribution. If you
4 ** did not receive the LICENSE file with this file, you may obtain it from the
5 ** Vidalia source package distributed by the Vidalia Project at
6 ** http://www.torproject.org/projects/vidalia.html. No part of Vidalia,
7 ** including this file, may be copied, modified, propagated, or distributed
8 ** except according to the terms described in the LICENSE file.
9 */
10 
11 /*
12 ** \file procutil.cpp
13 ** \brief Process information and pidfile functions
14 */
15 
16 #include "procutil.h"
17 #include "stringutil.h"
18 
19 #include <QDir>
20 #include <QFile>
21 #include <QFileInfo>
22 #include <QTextStream>
23 #include <QApplication>
24 #include <QProcess>
25 
26 #if !defined(Q_OS_WIN)
27 #include <signal.h>
28 #endif
29 
30 
31 /** Returns the PID of the current process. */
32 qint64
34 {
35 #if defined(Q_OS_WIN)
36  return (qint64)GetCurrentProcessId();
37 #else
38  return (qint64)getpid();
39 #endif
40 }
41 
42 /** Returns true if a process with the given PID is running. */
43 bool
44 is_process_running(qint64 pid)
45 {
46 #if defined(Q_OS_WIN)
47  QHash<qint64, QString> procList = win32_process_list();
48  if (procList.contains(pid)) {
49  /* A process with this ID exists. Check if it's the same as this process. */
50  QString exeFile = procList.value(pid);
51  QString thisExe = QFileInfo(QApplication::applicationFilePath()).fileName();
52  return (exeFile.toLower() == thisExe.toLower());
53  }
54  return false;
55 #else
56  /* Send the "null" signal to check if a process exists */
57  if (kill((pid_t)pid, 0) < 0) {
58  return (errno != ESRCH);
59  }
60  return true;
61 #endif
62 }
63 
64 /** Writes the given file to disk containing the current process's PID. */
65 bool
66 write_pidfile(const QString &pidFileName, QString *errmsg)
67 {
68  /* Make sure the directory exists */
69  QDir pidFileDir = QFileInfo(pidFileName).absoluteDir();
70  if (!pidFileDir.exists()) {
71  pidFileDir.mkpath(QDir::convertSeparators(pidFileDir.absolutePath()));
72  }
73 
74  /* Try to open (and create if it doesn't exist) the pidfile */
75  QFile pidfile(pidFileName);
76  if (!pidfile.open(QIODevice::WriteOnly | QIODevice::Text)) {
77  return err(errmsg, pidfile.errorString());
78  }
79 
80  /* Write our current PID to it */
81  QTextStream pidstream(&pidfile);
82  pidstream << get_pid();
83  return true;
84 }
85 
86 /** Reads the given pidfile and returns the value contained in it. If the file
87  * does not exist 0 is returned. Returns -1 if an error occurs. */
88 qint64
89 read_pidfile(const QString &pidFileName, QString *errmsg)
90 {
91  qint64 pid;
92 
93  /* Open the pidfile, if it exists */
94  QFile pidfile(pidFileName);
95  if (!pidfile.exists()) {
96  return 0;
97  }
98  if (!pidfile.open(QIODevice::ReadOnly | QIODevice::Text)) {
99  if (errmsg) {
100  *errmsg = pidfile.errorString();
101  }
102  return -1;
103  }
104 
105  /* Read the PID in from the file */
106  QTextStream pidstream(&pidfile);
107  pidstream >> pid;
108  return pid;
109 }
110 
111 QHash<qint64, QString>
112 process_list(quint16 port)
113 {
114  return universal_process_list(port);
115 }
116 
117 bool
118 process_kill(qint64 pid)
119 {
120 #if defined(Q_OS_WIN32)
121  HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE,
122  static_cast<DWORD>(pid));
123  if (hProcess == NULL)
124  return false;
125 
126  BOOL ret = TerminateProcess(hProcess, 0);
127  CloseHandle(hProcess);
128 
129  return (ret != FALSE);
130 #else
131  if(!kill(pid, 15))
132  return true;
133  return false;
134 #endif
135 }
136 
137 QHash<qint64, QString>
139 {
140  QHash<qint64, QString> pl;
141 
142  QProcess ps;
143  QStringList args;
144 #if defined(Q_OS_LINUX)
145  args << "-npl";
146 #else
147  args << "-no";
148 #endif
149 
150  ps.start("netstat", args, QIODevice::ReadOnly);
151  while(!ps.waitForFinished());
152 
153  QString flt = QString("127.0.0.1:%1").arg(port);
154  QStringList lines = QString(ps.readAllStandardOutput()).split("\n");
155  QStringList filtered = lines.filter(flt);
156 
157 #if defined(Q_OS_WIN)
158  filtered = filtered.filter("LISTENING");
159 #endif
160 
161  if(filtered.length() == 0)
162  return QHash<qint64, QString>();
163 
164  qint64 pid = 0;
165  QString proc = "";
166 #if defined(Q_OS_LINUX)
167  foreach(QString line, lines) {
168  QStringList items = line.trimmed().split(" ");
169  if(items.length() < 1)
170  continue;
171  items = items.last().trimmed().split("/");
172  if(items.length() < 2)
173  continue;
174 
175  pid = items[0].toLong();
176  proc = items[1];
177 
178  pl.insert(pid, proc);
179  }
180 #else
181  pid = filtered[0].split(" ").last().trimmed().toLong();
182  proc = "tor";
183  pl.insert(pid, proc);
184 #endif
185 
186  return pl;
187 }