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