| /** |
| * @file oprof_start_util.cpp |
| * Miscellaneous helpers for the GUI start |
| * |
| * @remark Copyright 2002 OProfile authors |
| * @remark Read the file COPYING |
| * |
| * @author Philippe Elie |
| * @author John Levon |
| */ |
| |
| #include <dirent.h> |
| #include <unistd.h> |
| #include <glob.h> |
| |
| #include <cerrno> |
| #include <vector> |
| #include <cmath> |
| #include <sstream> |
| #include <iostream> |
| #include <fstream> |
| #include <cstdlib> |
| |
| #include <qfiledialog.h> |
| #include <qmessagebox.h> |
| |
| #include "op_file.h" |
| #include "file_manip.h" |
| #include "child_reader.h" |
| #include "op_libiberty.h" |
| |
| #include "oprof_start.h" |
| #include "oprof_start_util.h" |
| |
| using namespace std; |
| |
| namespace { |
| |
| // return the ~ expansion suffixed with a '/' |
| string const get_config_dir() |
| { |
| return "/root"; |
| } |
| |
| string daemon_pid; |
| |
| } // namespace anon |
| |
| daemon_status::daemon_status() |
| : running(false), |
| nr_interrupts(0) |
| { |
| int HZ; |
| if (!daemon_pid.empty()) { |
| string proc_filename = string("/proc/") + daemon_pid + "/exe"; |
| string const exec = op_realpath(proc_filename); |
| if (exec == proc_filename) |
| daemon_pid.erase(); |
| else |
| running = true; |
| } |
| |
| if (daemon_pid.empty()) { |
| DIR * dir; |
| struct dirent * dirent; |
| |
| if (!(dir = opendir("/proc"))) { |
| perror("oprofiled: /proc directory could not be opened. "); |
| exit(EXIT_FAILURE); |
| } |
| |
| while ((dirent = readdir(dir))) { |
| string const exec = |
| op_realpath(string("/proc/") |
| + dirent->d_name + "/exe"); |
| string const name = op_basename(exec); |
| if (name != "oprofiled") |
| continue; |
| |
| daemon_pid = dirent->d_name; |
| running = true; |
| } |
| |
| closedir(dir); |
| } |
| |
| HZ = sysconf(_SC_CLK_TCK); |
| if (HZ == -1) { |
| perror("oprofiled: Unable to determine clock ticks per second. "); |
| exit(EXIT_FAILURE); |
| } |
| |
| if (daemon_pid.empty()) |
| return; |
| |
| nr_interrupts = 0; |
| |
| switch (op_get_interface()) { |
| case OP_INTERFACE_24: |
| { |
| ifstream ifs3("/proc/sys/dev/oprofile/nr_interrupts"); |
| if (ifs3) |
| ifs3 >> nr_interrupts; |
| } |
| break; |
| case OP_INTERFACE_26: |
| { |
| static unsigned int old_sum_interrupts; |
| unsigned int sum_interrupts = 0; |
| glob_t file_names; |
| |
| file_names.gl_offs = 0; |
| glob("/dev/oprofile/stats/cpu*/sample_received", |
| GLOB_DOOFFS, NULL, &file_names); |
| |
| for (size_t i = 0; i < file_names.gl_pathc; ++i) { |
| ifstream ifs3(file_names.gl_pathv[i]); |
| if (ifs3) { |
| unsigned int file_interrupts; |
| ifs3 >> file_interrupts; |
| sum_interrupts += file_interrupts; |
| } |
| } |
| if (old_sum_interrupts > sum_interrupts) |
| // occur if we stop/restart daemon. |
| old_sum_interrupts = 0; |
| nr_interrupts = sum_interrupts - old_sum_interrupts; |
| old_sum_interrupts = sum_interrupts; |
| globfree(&file_names); |
| } |
| break; |
| default: |
| break; |
| } |
| } |
| |
| |
| /** |
| * get_config_filename - get absolute filename of file in user $HOME |
| * @param filename the relative filename |
| * |
| * Get the absolute path of a file in a user's home directory. |
| */ |
| string const get_config_filename(string const & filename) |
| { |
| return get_config_dir() + "/" + filename; |
| } |
| |
| |
| /** |
| * check_and_create_config_dir - make sure config dir is accessible |
| * |
| * Returns %true if the dir is accessible. |
| */ |
| bool check_and_create_config_dir() |
| { |
| string dir = get_config_filename(".oprofile"); |
| |
| char * name = xstrdup(dir.c_str()); |
| |
| if (create_dir(name)) { |
| ostringstream out; |
| out << "unable to create " << dir << " directory "; |
| out << "cause: " << strerror(errno); |
| QMessageBox::warning(0, 0, out.str().c_str()); |
| |
| free(name); |
| |
| return false; |
| } |
| |
| free(name); |
| return true; |
| } |
| |
| |
| /** |
| * format - re-format a string |
| * @param orig string to format |
| * @param maxlen width of line |
| * |
| * Re-formats a string to fit into a certain width, |
| * breaking lines at spaces between words. |
| * |
| * Returns the formatted string |
| */ |
| string const format(string const & orig, uint const maxlen) |
| { |
| string text(orig); |
| |
| istringstream ss(text); |
| vector<string> lines; |
| |
| string oline; |
| string line; |
| |
| while (getline(ss, oline)) { |
| if (line.size() + oline.size() < maxlen) { |
| lines.push_back(line + oline); |
| line.erase(); |
| } else { |
| lines.push_back(line); |
| line.erase(); |
| string s; |
| string word; |
| istringstream oss(oline); |
| while (oss >> word) { |
| if (line.size() + word.size() > maxlen) { |
| lines.push_back(line); |
| line.erase(); |
| } |
| line += word + " "; |
| } |
| } |
| } |
| |
| if (line.size()) |
| lines.push_back(line); |
| |
| string ret; |
| |
| for(vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it) |
| ret += *it + "\n"; |
| |
| return ret; |
| } |
| |
| |
| /** |
| * do_exec_command - execute a command |
| * @param cmd command name |
| * @param args arguments to command |
| * |
| * Execute a command synchronously. An error message is shown |
| * if the command returns a non-zero status, which is also returned. |
| * |
| * The arguments are verified and will refuse to execute if they contain |
| * shell metacharacters. |
| */ |
| int do_exec_command(string const & cmd, vector<string> const & args) |
| { |
| ostringstream err; |
| bool ok = true; |
| |
| // verify arguments |
| for (vector<string>::const_iterator cit = args.begin(); |
| cit != args.end(); ++cit) { |
| if (verify_argument(*cit)) |
| continue; |
| |
| QMessageBox::warning(0, 0, |
| string( |
| "Could not execute: Argument \"" + *cit + |
| "\" contains shell metacharacters.\n").c_str()); |
| return EINVAL; |
| } |
| |
| child_reader reader(cmd, args); |
| if (reader.error()) |
| ok = false; |
| |
| if (ok) |
| reader.get_data(cout, err); |
| |
| int ret = reader.terminate_process(); |
| if (ret) { |
| string error = reader.error_str() + "\n"; |
| error += "Failed: \n" + err.str() + "\n"; |
| string cmdline = cmd; |
| for (vector<string>::const_iterator cit = args.begin(); |
| cit != args.end(); ++cit) { |
| cmdline += " " + *cit + " "; |
| } |
| error += "\n\nCommand was :\n\n" + cmdline + "\n"; |
| |
| QMessageBox::warning(0, 0, format(error, 50).c_str()); |
| } |
| |
| return ret; |
| } |
| |
| |
| /** |
| * do_open_file_or_dir - open file/directory |
| * @param base_dir directory to start at |
| * @param dir_only directory or filename to select |
| * |
| * Select a file or directory. The selection is returned; |
| * an empty string if the selection was cancelled. |
| */ |
| string const do_open_file_or_dir(string const & base_dir, bool dir_only) |
| { |
| QString result; |
| |
| if (dir_only) { |
| result = QFileDialog::getExistingDirectory(base_dir.c_str(), 0, |
| "open_file_or_dir", "Get directory name", true); |
| } else { |
| result = QFileDialog::getOpenFileName(base_dir.c_str(), 0, 0, |
| "open_file_or_dir", "Get filename"); |
| } |
| |
| if (result.isNull()) |
| return string(); |
| else |
| return result.latin1(); |
| } |
| |
| /** |
| * verify_argument - check string for potentially dangerous characters |
| * |
| * This function returns false if the string contains dangerous shell |
| * metacharacters. |
| * |
| * WWW Security FAQ dangerous chars: |
| * |
| * & ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r |
| * |
| * David Wheeler: ! # |
| * |
| * We allow '-' because we disallow whitespace. We allow ':' and '=' |
| */ |
| bool verify_argument(string const & str) |
| { |
| if (str.find_first_not_of( |
| "ABCDEFGHIJKLMNOPQRSTUVWXYZ" |
| "abcdefghijklmnopqrstuvwxyz0123456789_:=-+%,./") |
| != string::npos) |
| return false; |
| return true; |
| } |