18cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
28cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @file oprof_start_util.cpp
38cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Miscellaneous helpers for the GUI start
48cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
58cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Copyright 2002 OProfile authors
68cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @remark Read the file COPYING
78cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
88cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author Philippe Elie
98cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @author John Levon
108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <dirent.h>
138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <unistd.h>
148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <glob.h>
158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cerrno>
178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <vector>
188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cmath>
198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <sstream>
208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <iostream>
218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <fstream>
228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <cstdlib>
238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <qfiledialog.h>
258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include <qmessagebox.h>
268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_file.h"
288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "file_manip.h"
298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "child_reader.h"
308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "op_libiberty.h"
318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "oprof_start.h"
338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd#include "oprof_start_util.h"
348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddusing namespace std;
368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddnamespace {
388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd// return the ~ expansion suffixed with a '/'
408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstring const get_config_dir()
418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return "/root";
438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstring daemon_pid;
468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd} // namespace anon
488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodddaemon_status::daemon_status()
508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	: running(false),
518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	  nr_interrupts(0)
528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int HZ;
548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (!daemon_pid.empty()) {
558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		string proc_filename = string("/proc/") + daemon_pid + "/exe";
568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		string const exec = op_realpath(proc_filename);
578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (exec == proc_filename)
588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			daemon_pid.erase();
598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		else
608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			running = true;
618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (daemon_pid.empty()) {
648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		DIR * dir;
658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		struct dirent * dirent;
668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (!(dir = opendir("/proc"))) {
688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			perror("oprofiled: /proc directory could not be opened. ");
698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			exit(EXIT_FAILURE);
708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		}
718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		while ((dirent = readdir(dir))) {
738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			string const exec =
748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				op_realpath(string("/proc/")
758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				               + dirent->d_name + "/exe");
768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			string const name = op_basename(exec);
778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			if (name != "oprofiled")
788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				continue;
798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			daemon_pid = dirent->d_name;
818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			running = true;
828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		}
838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		closedir(dir);
858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	HZ = sysconf(_SC_CLK_TCK);
888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (HZ == -1) {
898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		perror("oprofiled: Unable to determine clock ticks per second. ");
908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		exit(EXIT_FAILURE);
918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (daemon_pid.empty())
948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return;
958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	nr_interrupts = 0;
978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	switch (op_get_interface()) {
998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	case OP_INTERFACE_24:
1008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		{
1018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			ifstream ifs3("/proc/sys/dev/oprofile/nr_interrupts");
1028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			if (ifs3)
1038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				ifs3 >> nr_interrupts;
1048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		}
1058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		break;
1068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	case OP_INTERFACE_26:
1078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		{
1088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			static unsigned int old_sum_interrupts;
1098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			unsigned int sum_interrupts = 0;
1108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			glob_t file_names;
1118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			file_names.gl_offs = 0;
1138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			glob("/dev/oprofile/stats/cpu*/sample_received",
1148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			     GLOB_DOOFFS, NULL, &file_names);
1158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			for (size_t i = 0; i < file_names.gl_pathc; ++i) {
1178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				ifstream ifs3(file_names.gl_pathv[i]);
1188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				if (ifs3) {
1198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd					unsigned int file_interrupts;
1208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd					ifs3 >> file_interrupts;
1218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd					sum_interrupts += file_interrupts;
1228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				}
1238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			}
1248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			if (old_sum_interrupts > sum_interrupts)
1258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				// occur if we stop/restart daemon.
1268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				old_sum_interrupts = 0;
1278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			nr_interrupts = sum_interrupts - old_sum_interrupts;
1288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			old_sum_interrupts = sum_interrupts;
1298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			globfree(&file_names);
1308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		}
1318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		break;
1328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	default:
1338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		break;
1348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
1398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * get_config_filename - get absolute filename of file in user $HOME
1408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @param filename  the relative filename
1418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
1428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Get the absolute path of a file in a user's home directory.
1438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
1448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstring const get_config_filename(string const & filename)
1458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return get_config_dir() + "/" + filename;
1478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
1518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * check_and_create_config_dir - make sure config dir is accessible
1528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
1538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Returns %true if the dir is accessible.
1548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
1558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddbool check_and_create_config_dir()
1568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	string dir = get_config_filename(".oprofile");
1588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	char * name = xstrdup(dir.c_str());
1608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (create_dir(name)) {
1628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		ostringstream out;
1638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		out << "unable to create " << dir << " directory ";
1648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		out << "cause: " << strerror(errno);
1658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		QMessageBox::warning(0, 0, out.str().c_str());
1668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		free(name);
1688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return false;
1708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
1718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	free(name);
1738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return true;
1748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
1758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
1788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * format - re-format a string
1798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @param orig  string to format
1808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @param maxlen  width of line
1818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
1828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Re-formats a string to fit into a certain width,
1838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * breaking lines at spaces between words.
1848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
1858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Returns the formatted string
1868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
1878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstring const format(string const & orig, uint const maxlen)
1888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
1898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	string text(orig);
1908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	istringstream ss(text);
1928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	vector<string> lines;
1938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	string oline;
1958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	string line;
1968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
1978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	while (getline(ss, oline)) {
1988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (line.size() + oline.size() < maxlen) {
1998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			lines.push_back(line + oline);
2008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			line.erase();
2018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		} else {
2028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			lines.push_back(line);
2038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			line.erase();
2048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			string s;
2058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			string word;
2068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			istringstream oss(oline);
2078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			while (oss >> word) {
2088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				if (line.size() + word.size() > maxlen) {
2098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd					lines.push_back(line);
2108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd					line.erase();
2118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				}
2128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd				line += word + " ";
2138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			}
2148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		}
2158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
2168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (line.size())
2188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		lines.push_back(line);
2198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	string ret;
2218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	for(vector<string>::const_iterator it = lines.begin(); it != lines.end(); ++it)
2238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		ret += *it + "\n";
2248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return ret;
2268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
2308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * do_exec_command - execute a command
2318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @param cmd  command name
2328cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @param args  arguments to command
2338cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
2348cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Execute a command synchronously. An error message is shown
2358cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * if the command returns a non-zero status, which is also returned.
2368cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
2378cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * The arguments are verified and will refuse to execute if they contain
2388cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * shell metacharacters.
2398cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
2408cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddint do_exec_command(string const & cmd, vector<string> const & args)
2418cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2428cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	ostringstream err;
2438cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	bool ok = true;
2448cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2458cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	// verify arguments
2468cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	for (vector<string>::const_iterator cit = args.begin();
2478cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		cit != args.end(); ++cit) {
2488cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		if (verify_argument(*cit))
2498cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			continue;
2508cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2518cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		QMessageBox::warning(0, 0,
2528cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			string(
2538cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			"Could not execute: Argument \"" + *cit +
2548cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			"\" contains shell metacharacters.\n").c_str());
2558cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return EINVAL;
2568cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
2578cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2588cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	child_reader reader(cmd, args);
2598cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (reader.error())
2608cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		ok = false;
2618cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2628cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ok)
2638cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		reader.get_data(cout, err);
2648cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2658cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	int ret = reader.terminate_process();
2668cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (ret) {
2678cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		string error = reader.error_str() + "\n";
2688cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		error += "Failed: \n" + err.str() + "\n";
2698cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		string cmdline = cmd;
2708cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		for (vector<string>::const_iterator cit = args.begin();
2718cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		     cit != args.end(); ++cit) {
2728cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			cmdline += " " + *cit + " ";
2738cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		}
2748cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		error += "\n\nCommand was :\n\n" + cmdline + "\n";
2758cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2768cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		QMessageBox::warning(0, 0, format(error, 50).c_str());
2778cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
2788cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2798cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return ret;
2808cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
2818cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2828cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2838cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
2848cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * do_open_file_or_dir - open file/directory
2858cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @param base_dir  directory to start at
2868cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * @param dir_only  directory or filename to select
2878cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
2888cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * Select a file or directory. The selection is returned;
2898cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * an empty string if the selection was cancelled.
2908cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
2918cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddstring const do_open_file_or_dir(string const & base_dir, bool dir_only)
2928cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
2938cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	QString result;
2948cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
2958cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (dir_only) {
2968cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		result = QFileDialog::getExistingDirectory(base_dir.c_str(), 0,
2978cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			"open_file_or_dir", "Get directory name", true);
2988cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	} else {
2998cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		result = QFileDialog::getOpenFileName(base_dir.c_str(), 0, 0,
3008cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd			"open_file_or_dir", "Get filename");
3018cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	}
3028cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3038cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (result.isNull())
3048cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return string();
3058cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	else
3068cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return result.latin1();
3078cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
3088cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd
3098cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd/**
3108cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * verify_argument - check string for potentially dangerous characters
3118cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
3128cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * This function returns false if the string contains dangerous shell
3138cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * metacharacters.
3148cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
3158cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * WWW Security FAQ dangerous chars:
3168cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
3178cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * & ; ` ' \ " | * ? ~ < > ^ ( ) [ ] { } $ \n \r
3188cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
3198cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * David Wheeler: ! #
3208cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd *
3218cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd * We allow '-' because we disallow whitespace. We allow ':' and '='
3228cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd */
3238cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Doddbool verify_argument(string const & str)
3248cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd{
3258cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	if (str.find_first_not_of(
3268cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
3278cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		"abcdefghijklmnopqrstuvwxyz0123456789_:=-+%,./")
3288cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		!= string::npos)
3298cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd		return false;
3308cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd	return true;
3318cfa702f803c5ef6a2b062a489a1b2cf66b45b5eMike Dodd}
332