oprof_start_util.cpp revision cc2ee177dbb3befca43e36cfc56778b006c3d050
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 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} 342