blob: ded9cae24aeb08a7c9bb09bbe2e7a8505e31f647 [file] [log] [blame]
Upstreamcc2ee171970-01-12 13:46:40 +00001/**
2 * @file oprof_start_util.cpp
3 * Miscellaneous helpers for the GUI start
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author Philippe Elie
9 * @author John Levon
10 */
11
12#include <dirent.h>
13#include <unistd.h>
14#include <glob.h>
15
16#include <cerrno>
17#include <vector>
18#include <cmath>
19#include <sstream>
20#include <iostream>
21#include <fstream>
22
23#include <qfiledialog.h>
24#include <qmessagebox.h>
25
26#include "op_file.h"
27#include "file_manip.h"
28#include "child_reader.h"
29#include "op_libiberty.h"
30
31#include "oprof_start.h"
32#include "oprof_start_util.h"
33
34using namespace std;
35
36namespace {
37
38// return the ~ expansion suffixed with a '/'
39string const get_user_dir()
40{
41 static string user_dir;
42
43 if (user_dir.empty()) {
44 char * dir = getenv("HOME");
45 if (!dir) {
46 cerr << "Can't determine home directory !\n" << endl;
47 exit(EXIT_FAILURE);
48 }
49
50 user_dir = dir;
51
52 if (user_dir.length() && user_dir[user_dir.length() -1] != '/')
53 user_dir += '/';
54 }
55
56 return user_dir;
57}
58
59string daemon_pid;
60
61} // namespace anon
62
63daemon_status::daemon_status()
64 : running(false)
65{
66 int HZ;
67 if (!daemon_pid.empty()) {
68 string const exec =
69 op_realpath(string("/proc/") + daemon_pid + "/exe");
70 if (exec.empty())
71 daemon_pid.erase();
72 else
73 running = true;
74 }
75
76 if (daemon_pid.empty()) {
77 DIR * dir;
78 struct dirent * dirent;
79
80 if (!(dir = opendir("/proc"))) {
81 perror("oprofiled: /proc directory could not be opened. ");
82 exit(EXIT_FAILURE);
83 }
84
85 while ((dirent = readdir(dir))) {
86 string const exec =
87 op_realpath(string("/proc/")
88 + dirent->d_name + "/exe");
89 string const name = op_basename(exec);
90 if (name != "oprofiled")
91 continue;
92
93 daemon_pid = dirent->d_name;
94 running = true;
95 }
96
97 closedir(dir);
98 }
99
100 HZ = sysconf(_SC_CLK_TCK);
101 if (HZ == -1) {
102 perror("oprofiled: Unable to determine clock ticks per second. ");
103 exit(EXIT_FAILURE);
104 }
105
106 if (daemon_pid.empty())
107 return;
108
109 nr_interrupts = 0;
110
111 switch (op_get_interface()) {
112 case OP_INTERFACE_24:
113 {
114 ifstream ifs3("/proc/sys/dev/oprofile/nr_interrupts");
115 if (ifs3)
116 ifs3 >> nr_interrupts;
117 }
118 break;
119 case OP_INTERFACE_26:
120 {
121 static unsigned int old_sum_interrupts;
122 unsigned int sum_interrupts = 0;
123 glob_t file_names;
124
125 file_names.gl_offs = 0;
126 glob("/dev/oprofile/stats/cpu*/sample_received",
127 GLOB_DOOFFS, NULL, &file_names);
128
129 for (size_t i = 0; i < file_names.gl_pathc; ++i) {
130 ifstream ifs3(file_names.gl_pathv[i]);
131 if (ifs3) {
132 unsigned int file_interrupts;
133 ifs3 >> file_interrupts;
134 sum_interrupts += file_interrupts;
135 }
136 }
137 nr_interrupts = sum_interrupts - old_sum_interrupts;
138 old_sum_interrupts = sum_interrupts;
139 globfree(&file_names);
140 }
141 break;
142 default:
143 break;
144 }
145}
146
147
148/**
149 * get_user_filename - get absolute filename of file in user $HOME
150 * @param filename the relative filename
151 *
152 * Get the absolute path of a file in a user's home directory.
153 */
154string const get_user_filename(string const & filename)
155{
156 return get_user_dir() + "/" + filename;
157}
158
159
160/**
161 * check_and_create_config_dir - make sure config dir is accessible
162 *
163 * Returns %true if the dir is accessible.
164 */
165bool check_and_create_config_dir()
166{
167 string dir = get_user_filename(".oprofile");
168
169 char * name = xstrdup(dir.c_str());
170
171 if (create_dir(name)) {
172 ostringstream out;
173 out << "unable to create " << dir << " directory ";
174 out << "cause: " << strerror(errno);
175 QMessageBox::warning(0, 0, out.str().c_str());
176
177 free(name);
178
179 return false;
180 }
181
182 free(name);
183 return true;
184}
185
186
187/**
188 * format - re-format a string
189 * @param orig string to format
190 * @param maxlen width of line
191 *
192 * Re-formats a string to fit into a certain width,
193 * breaking lines at spaces between words.
194 *
195 * Returns the formatted string
196 */
197string const format(string const & orig, uint const maxlen)
198{
199 string text(orig);
200
201 istringstream ss(text);
202 vector<string> lines;
203
204 string oline;
205 string line;
206
207 while (getline(ss, oline)) {
208 if (line.size() + oline.size() < maxlen) {
209 lines.push_back(line + oline);
210 line.erase();
211 } else {
212 lines.push_back(line);
213 line.erase();
214 string s;
215 string word;
216 istringstream oss(oline);
217 while (oss >> word) {
218 if (line.size() + word.size() > maxlen) {
219 lines.push_back(line);
220 line.erase();
221 }
222 line += word + " ";
223 }
224 }
225 }
226
227 if (line.size())
228 lines.push_back(line);
229
230 string ret;
231
232 for(vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it)
233 ret += *it + "\n";
234
235 return ret;
236}
237
238
239/**
240 * do_exec_command - execute a command
241 * @param cmd command name
242 * @param args arguments to command
243 *
244 * Execute a command synchronously. An error message is shown
245 * if the command returns a non-zero status, which is also returned.
246 *
247 * The arguments are verified and will refuse to execute if they contain
248 * shell metacharacters.
249 */
250int do_exec_command(string const & cmd, vector<string> const & args)
251{
252 ostringstream err;
253 bool ok = true;
254
255 // verify arguments
256 for (vector<string>::const_iterator cit = args.begin();
257 cit != args.end(); ++cit) {
258 if (verify_argument(*cit))
259 continue;
260
261 QMessageBox::warning(0, 0,
262 string(
263 "Could not execute: Argument \"" + *cit +
264 "\" contains shell metacharacters.\n").c_str());
265 return EINVAL;
266 }
267
268 child_reader reader(cmd, args);
269 if (reader.error())
270 ok = false;
271
272 if (ok)
273 reader.get_data(cout, err);
274
275 int ret = reader.terminate_process();
276 if (ret) {
277 string error = reader.error_str() + "\n";
278 error += "Failed: \n" + err.str() + "\n";
279 string cmdline = cmd;
280 for (vector<string>::const_iterator cit = args.begin();
281 cit != args.end(); ++cit) {
282 cmdline += " " + *cit + " ";
283 }
284 error += "\n\nCommand was :\n\n" + cmdline + "\n";
285
286 QMessageBox::warning(0, 0, format(error, 50).c_str());
287 }
288
289 return ret;
290}
291
292
293/**
294 * do_open_file_or_dir - open file/directory
295 * @param base_dir directory to start at
296 * @param dir_only directory or filename to select
297 *
298 * Select a file or directory. The selection is returned;
299 * an empty string if the selection was cancelled.
300 */
301string const do_open_file_or_dir(string const & base_dir, bool dir_only)
302{
303 QString result;
304
305 if (dir_only) {
306 result = QFileDialog::getExistingDirectory(base_dir.c_str(), 0,
307 "open_file_or_dir", "Get directory name", true);
308 } else {
309 result = QFileDialog::getOpenFileName(base_dir.c_str(), 0, 0,
310 "open_file_or_dir", "Get filename");
311 }
312
313 if (result.isNull())
314 return string();
315 else
316 return result.latin1();
317}
318
319/**
320 * verify_argument - check string for potentially dangerous characters
321 *
322 * This function returns false if the string contains dangerous shell
323 * metacharacters.
324 *
325 * WWW Security FAQ dangerous chars:
326 *
327 * & ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r
328 *
329 * David Wheeler: ! #
330 *
331 * We allow '-' because we disallow whitespace. We allow ':' and '='
332 */
333bool verify_argument(string const & str)
334{
335 if (str.find_first_not_of(
336 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
337 "abcdefghijklmnopqrstuvwxyz0123456789_:=-+%,./")
338 != string::npos)
339 return false;
340 return true;
341}