/**
* @file oparchive.cpp
* Implement oparchive utility
*
* @remark Copyright 2003, 2004 OProfile authors
* @remark Read the file COPYING
*
* @author Will Cohen
* @author John Levon
* @author Philippe Elie
*/
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <errno.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "op_file.h"
#include "op_bfd.h"
#include "op_config.h"
#include "oparchive_options.h"
#include "file_manip.h"
#include "cverb.h"
#include "image_errors.h"
#include "string_manip.h"
#include "locate_images.h"
using namespace std;
namespace {
void copy_one_file(image_error err, string const & source, string const & dest)
{
if (!op_file_readable(source))
return;
if (options::list_files) {
cout << source << endl;
return;
}
if (!copy_file(source, dest) && err == image_ok) {
cerr << "can't copy from " << source << " to " << dest
<< " cause: " << strerror(errno) << endl;
}
}
void copy_stats(string const & session_samples_dir,
string const & archive_path)
{
DIR * dir;
struct dirent * dirent;
string stats_path;
stats_path = session_samples_dir + "stats/";
if (!(dir = opendir(stats_path.c_str()))) {
return;
}
string sample_base_dir = session_samples_dir.substr(archive_path.size());
string archive_stats = options::outdirectory + sample_base_dir + "stats/";
string archive_stats_path = archive_stats + "event_lost_overflow";
if (!options::list_files &&
create_path(archive_stats_path.c_str())) {
cerr << "Unable to create directory for "
<< archive_stats << "." << endl;
exit (EXIT_FAILURE);
}
copy_one_file(image_ok, stats_path + "/event_lost_overflow", archive_stats_path);
while ((dirent = readdir(dir))) {
int cpu_nr;
string path;
if (sscanf(dirent->d_name, "cpu%d", &cpu_nr) != 1)
continue;
path = string(dirent->d_name) + "/" + "sample_lost_overflow";
archive_stats_path = archive_stats + path;
if (!options::list_files &&
create_path(archive_stats_path.c_str())) {
cerr << "Unable to create directory for "
<< archive_stats_path << "." << endl;
exit (EXIT_FAILURE);
}
copy_one_file(image_ok, stats_path + path, archive_stats_path);
}
closedir(dir);
}
int oparchive(options::spec const & spec)
{
handle_options(spec);
string archive_path = classes.extra_found_images.get_archive_path();
/* Check to see if directory can be created */
if (!options::list_files && create_path(options::outdirectory.c_str())) {
cerr << "Unable to create directory for "
<< options::outdirectory << "." << endl;
exit (EXIT_FAILURE);
}
/* copy over each of the executables and the debuginfo files */
list<inverted_profile> iprofiles = invert_profiles(classes);
report_image_errors(iprofiles, classes.extra_found_images);
list<inverted_profile>::iterator it = iprofiles.begin();
list<inverted_profile>::iterator const end = iprofiles.end();
cverb << vdebug << "(exe_names)" << endl << endl;
for (; it != end; ++it) {
string exe_name = it->image;
image_error error;
string real_exe_name =
classes.extra_found_images.find_image_path(it->image,
error, true);
if (error == image_ok)
exe_name = classes.extra_found_images.strip_path_prefix(real_exe_name);
// output name must be identical to the original name, when
// using this archive the used fixup will be identical e.g.:
// oparchive -p /lib/modules/2.6.42/kernel -o tmp;
// opreport -p /lib/modules/2.6.42/kernel { archive:tmp }
string exe_archive_file = options::outdirectory + exe_name;
// FIXME: hacky
if (it->error == image_not_found && is_prefix(exe_name, "anon "))
continue;
cverb << vdebug << real_exe_name << endl;
/* Create directory for executable file. */
if (!options::list_files &&
create_path(exe_archive_file.c_str())) {
cerr << "Unable to create directory for "
<< exe_archive_file << "." << endl;
exit (EXIT_FAILURE);
}
/* Copy actual executable files */
copy_one_file(it->error, real_exe_name, exe_archive_file);
/* If there are any debuginfo files, copy them over.
* Need to copy the debug info file to somewhere we'll
* find it - executable location + "/.debug"
* to avoid overwriting files with the same name. The
* /usr/lib/debug search path is not going to work.
*/
bfd * ibfd = open_bfd(real_exe_name);
if (ibfd) {
string dirname = op_dirname(real_exe_name);
string debug_filename;
if (find_separate_debug_file(ibfd, real_exe_name,
debug_filename, classes.extra_found_images)) {
/* found something copy it over */
string dest_debug_dir = options::outdirectory +
dirname + "/.debug/";
if (!options::list_files &&
create_dir(dest_debug_dir.c_str())) {
cerr << "Unable to create directory: "
<< dest_debug_dir << "." << endl;
exit (EXIT_FAILURE);
}
string dest_debug = dest_debug_dir +
op_basename(debug_filename);
copy_one_file(image_ok, debug_filename, dest_debug);
}
bfd_close(ibfd);
}
}
/* copy over each of the sample files */
list<string>::iterator sit = sample_files.begin();
list<string>::iterator const send = sample_files.end();
string a_sample_file = *sit;
int offset = a_sample_file.find('{');
string base_samples_dir = a_sample_file.substr(0, offset);
copy_stats(base_samples_dir, archive_path);
cverb << vdebug << "(sample_names)" << endl << endl;
for (; sit != send; ++sit) {
string sample_name = *sit;
/* Get rid of the the archive_path from the name */
string sample_base = sample_name.substr(archive_path.size());
string sample_archive_file = options::outdirectory + sample_base;
cverb << vdebug << sample_name << endl;
cverb << vdebug << " destp " << sample_archive_file << endl;
if (!options::list_files &&
create_path(sample_archive_file.c_str())) {
cerr << "Unable to create directory for "
<< sample_archive_file << "." << endl;
exit (EXIT_FAILURE);
}
/* Copy over actual sample file. */
copy_one_file(image_ok, sample_name, sample_archive_file);
}
/* copy over the <session-dir>/abi file if it exists */
string abi_name = string(op_session_dir) + "/abi";
copy_one_file(image_ok, archive_path + abi_name,
options::outdirectory + abi_name);
/* copy over the <session-dir>/samples/oprofiled.log file */
string log_name = string(op_samples_dir) + "/oprofiled.log";
copy_one_file(image_ok, archive_path + log_name,
options::outdirectory + log_name);
return 0;
}
} // anonymous namespace
int main(int argc, char const * argv[])
{
return run_pp_tool(argc, argv, oparchive);
}