output.cc revision 10412
11388SN/A/* 21388SN/A * Copyright (c) 2005 The Regents of The University of Michigan 31388SN/A * All rights reserved. 41388SN/A * 51388SN/A * Redistribution and use in source and binary forms, with or without 61388SN/A * modification, are permitted provided that the following conditions are 71388SN/A * met: redistributions of source code must retain the above copyright 81388SN/A * notice, this list of conditions and the following disclaimer; 91388SN/A * redistributions in binary form must reproduce the above copyright 101388SN/A * notice, this list of conditions and the following disclaimer in the 111388SN/A * documentation and/or other materials provided with the distribution; 121388SN/A * neither the name of the copyright holders nor the names of its 131388SN/A * contributors may be used to endorse or promote products derived from 141388SN/A * this software without specific prior written permission. 151388SN/A * 161388SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 171388SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 181388SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 191388SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 201388SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 211388SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 221388SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 231388SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 241388SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 251388SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 261388SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272665Ssaidi@eecs.umich.edu * 282665Ssaidi@eecs.umich.edu * Authors: Nathan Binkert 298634Schris.emmons@arm.com * Chris Emmons 301388SN/A */ 311388SN/A 321388SN/A#include <sys/stat.h> 331388SN/A#include <sys/types.h> 348634Schris.emmons@arm.com#include <dirent.h> 351388SN/A 368634Schris.emmons@arm.com#include <cassert> 378229Snate@binkert.org#include <cerrno> 388229Snate@binkert.org#include <climits> 398229Snate@binkert.org#include <cstdlib> 401388SN/A#include <fstream> 411388SN/A 425749Scws3k@cs.virginia.edu#include <gzstream.hh> 435749Scws3k@cs.virginia.edu 441388SN/A#include "base/misc.hh" 451388SN/A#include "base/output.hh" 461388SN/A 471388SN/Ausing namespace std; 481388SN/A 491388SN/AOutputDirectory simout; 501388SN/A 511388SN/A/** 528634Schris.emmons@arm.com * @file This file manages creating / deleting output files for the simulator. 531388SN/A */ 541388SN/AOutputDirectory::OutputDirectory() 551388SN/A{} 561388SN/A 571388SN/AOutputDirectory::~OutputDirectory() 585749Scws3k@cs.virginia.edu{ 595749Scws3k@cs.virginia.edu for (map_t::iterator i = files.begin(); i != files.end(); i++) { 605749Scws3k@cs.virginia.edu if (i->second) 615749Scws3k@cs.virginia.edu delete i->second; 625749Scws3k@cs.virginia.edu } 635749Scws3k@cs.virginia.edu} 645749Scws3k@cs.virginia.edu 655749Scws3k@cs.virginia.edustd::ostream * 665749Scws3k@cs.virginia.eduOutputDirectory::checkForStdio(const string &name) const 675749Scws3k@cs.virginia.edu{ 685749Scws3k@cs.virginia.edu if (name == "cerr" || name == "stderr") 695749Scws3k@cs.virginia.edu return &cerr; 705749Scws3k@cs.virginia.edu 715749Scws3k@cs.virginia.edu if (name == "cout" || name == "stdout") 725749Scws3k@cs.virginia.edu return &cout; 735749Scws3k@cs.virginia.edu 745749Scws3k@cs.virginia.edu return NULL; 755749Scws3k@cs.virginia.edu} 765749Scws3k@cs.virginia.edu 775749Scws3k@cs.virginia.eduostream * 785749Scws3k@cs.virginia.eduOutputDirectory::openFile(const string &filename, 798634Schris.emmons@arm.com ios_base::openmode mode) 805749Scws3k@cs.virginia.edu{ 815749Scws3k@cs.virginia.edu if (filename.find(".gz", filename.length()-3) < filename.length()) { 825749Scws3k@cs.virginia.edu ogzstream *file = new ogzstream(filename.c_str(), mode); 835749Scws3k@cs.virginia.edu if (!file->is_open()) 845749Scws3k@cs.virginia.edu fatal("Cannot open file %s", filename); 858634Schris.emmons@arm.com assert(files.find(filename) == files.end()); 868634Schris.emmons@arm.com files[filename] = file; 875749Scws3k@cs.virginia.edu return file; 885749Scws3k@cs.virginia.edu } else { 895749Scws3k@cs.virginia.edu ofstream *file = new ofstream(filename.c_str(), mode); 905749Scws3k@cs.virginia.edu if (!file->is_open()) 915749Scws3k@cs.virginia.edu fatal("Cannot open file %s", filename); 928634Schris.emmons@arm.com assert(files.find(filename) == files.end()); 938634Schris.emmons@arm.com files[filename] = file; 945749Scws3k@cs.virginia.edu return file; 955749Scws3k@cs.virginia.edu } 965749Scws3k@cs.virginia.edu} 971388SN/A 981388SN/Avoid 998634Schris.emmons@arm.comOutputDirectory::close(ostream *openStream) { 1008634Schris.emmons@arm.com map_t::iterator i; 1018634Schris.emmons@arm.com for (i = files.begin(); i != files.end(); i++) { 1028634Schris.emmons@arm.com if (i->second != openStream) 1038634Schris.emmons@arm.com continue; 1048634Schris.emmons@arm.com 1058634Schris.emmons@arm.com ofstream *fs = dynamic_cast<ofstream*>(i->second); 1068634Schris.emmons@arm.com if (fs) { 1078634Schris.emmons@arm.com fs->close(); 1088634Schris.emmons@arm.com delete i->second; 1098634Schris.emmons@arm.com break; 1108634Schris.emmons@arm.com } else { 1118634Schris.emmons@arm.com ogzstream *gfs = dynamic_cast<ogzstream*>(i->second); 1128634Schris.emmons@arm.com if (gfs) { 1138634Schris.emmons@arm.com gfs->close(); 1148634Schris.emmons@arm.com delete i->second; 1158634Schris.emmons@arm.com break; 1168634Schris.emmons@arm.com } 1178634Schris.emmons@arm.com } 1188634Schris.emmons@arm.com } 1198634Schris.emmons@arm.com 1208634Schris.emmons@arm.com if (i == files.end()) 1218634Schris.emmons@arm.com fatal("Attempted to close an unregistred file stream"); 1228634Schris.emmons@arm.com 1238634Schris.emmons@arm.com files.erase(i); 1248634Schris.emmons@arm.com} 1258634Schris.emmons@arm.com 1268634Schris.emmons@arm.comvoid 1271388SN/AOutputDirectory::setDirectory(const string &d) 1281388SN/A{ 1291388SN/A if (!dir.empty()) 1301388SN/A panic("Output directory already set!\n"); 1311388SN/A 1321388SN/A dir = d; 1331388SN/A 1348634Schris.emmons@arm.com // guarantee that directory ends with a path separator 1358634Schris.emmons@arm.com if (dir[dir.size() - 1] != PATH_SEPARATOR) 1368634Schris.emmons@arm.com dir += PATH_SEPARATOR; 1371388SN/A} 1381388SN/A 1391388SN/Aconst string & 1405749Scws3k@cs.virginia.eduOutputDirectory::directory() const 1411388SN/A{ 1421388SN/A if (dir.empty()) 1431388SN/A panic("Output directory not set!"); 1441388SN/A 1451388SN/A return dir; 1461388SN/A} 1471388SN/A 1489398Sandreas.hansson@arm.comstring 1495749Scws3k@cs.virginia.eduOutputDirectory::resolve(const string &name) const 1501388SN/A{ 1518634Schris.emmons@arm.com return (name[0] != PATH_SEPARATOR) ? dir + name : name; 1521388SN/A} 1531388SN/A 1541388SN/Aostream * 1554840Ssaidi@eecs.umich.eduOutputDirectory::create(const string &name, bool binary) 1561388SN/A{ 1575749Scws3k@cs.virginia.edu ostream *file = checkForStdio(name); 1585749Scws3k@cs.virginia.edu if (file) 1595749Scws3k@cs.virginia.edu return file; 1601388SN/A 1615749Scws3k@cs.virginia.edu string filename = resolve(name); 1625749Scws3k@cs.virginia.edu ios_base::openmode mode = 1638989SAli.Saidi@ARM.com ios::trunc | (binary ? ios::binary : (ios::openmode)0); 1645749Scws3k@cs.virginia.edu file = openFile(filename, mode); 1651388SN/A 1661388SN/A return file; 1671388SN/A} 1681388SN/A 1691388SN/Aostream * 1708634Schris.emmons@arm.comOutputDirectory::find(const string &name) const 1711388SN/A{ 1725749Scws3k@cs.virginia.edu ostream *file = checkForStdio(name); 1735749Scws3k@cs.virginia.edu if (file) 1745749Scws3k@cs.virginia.edu return file; 1751388SN/A 1768634Schris.emmons@arm.com const string filename = resolve(name); 1778634Schris.emmons@arm.com map_t::const_iterator i = files.find(filename); 1781388SN/A if (i != files.end()) 1791388SN/A return (*i).second; 1801388SN/A 1818634Schris.emmons@arm.com return NULL; 1821388SN/A} 1831388SN/A 1841388SN/Abool 1851388SN/AOutputDirectory::isFile(const std::ostream *os) 1861388SN/A{ 1871388SN/A return os && os != &cerr && os != &cout; 1881388SN/A} 1898634Schris.emmons@arm.com 1908634Schris.emmons@arm.combool 1918634Schris.emmons@arm.comOutputDirectory::isFile(const string &name) const 1928634Schris.emmons@arm.com{ 1938634Schris.emmons@arm.com // definitely a file if in our data structure 1948634Schris.emmons@arm.com if (find(name) != NULL) return true; 1958634Schris.emmons@arm.com 1968634Schris.emmons@arm.com struct stat st_buf; 1978634Schris.emmons@arm.com int st = stat(name.c_str(), &st_buf); 1988634Schris.emmons@arm.com return (st == 0) && S_ISREG(st_buf.st_mode); 1998634Schris.emmons@arm.com} 2008634Schris.emmons@arm.com 2018634Schris.emmons@arm.comstring 2028634Schris.emmons@arm.comOutputDirectory::createSubdirectory(const string &name) const 2038634Schris.emmons@arm.com{ 2048634Schris.emmons@arm.com const string new_dir = resolve(name); 2058634Schris.emmons@arm.com if (new_dir.find(directory()) == string::npos) 2068634Schris.emmons@arm.com fatal("Attempting to create subdirectory not in m5 output dir\n"); 2078634Schris.emmons@arm.com 2088634Schris.emmons@arm.com // if it already exists, that's ok; otherwise, fail if we couldn't create 2098634Schris.emmons@arm.com if ((mkdir(new_dir.c_str(), 0755) != 0) && (errno != EEXIST)) 2108634Schris.emmons@arm.com fatal("Failed to create new output subdirectory '%s'\n", new_dir); 2118634Schris.emmons@arm.com 2128634Schris.emmons@arm.com return name + PATH_SEPARATOR; 2138634Schris.emmons@arm.com} 2148634Schris.emmons@arm.com 2158634Schris.emmons@arm.comvoid 2168634Schris.emmons@arm.comOutputDirectory::remove(const string &name, bool recursive) 2178634Schris.emmons@arm.com{ 2188634Schris.emmons@arm.com const string fname = resolve(name); 2198634Schris.emmons@arm.com 2208634Schris.emmons@arm.com if (fname.find(directory()) == string::npos) 2218634Schris.emmons@arm.com fatal("Attempting to remove file/dir not in output dir\n"); 2228634Schris.emmons@arm.com 2238634Schris.emmons@arm.com if (isFile(fname)) { 2248634Schris.emmons@arm.com // close and release file if we have it open 2258634Schris.emmons@arm.com map_t::iterator itr = files.find(fname); 2268634Schris.emmons@arm.com if (itr != files.end()) { 2278634Schris.emmons@arm.com delete itr->second; 2288634Schris.emmons@arm.com files.erase(itr); 2298634Schris.emmons@arm.com } 2308634Schris.emmons@arm.com 2318634Schris.emmons@arm.com if (::remove(fname.c_str()) != 0) 2328634Schris.emmons@arm.com fatal("Could not erase file '%s'\n", fname); 2338634Schris.emmons@arm.com } else { 2348634Schris.emmons@arm.com // assume 'name' is a directory 2358634Schris.emmons@arm.com if (recursive) { 2369550Sandreas.hansson@arm.com DIR *subdir = opendir(fname.c_str()); 2378634Schris.emmons@arm.com 2388634Schris.emmons@arm.com // silently ignore removal request for non-existent directory 2399550Sandreas.hansson@arm.com if ((!subdir) && (errno == ENOENT)) 2408634Schris.emmons@arm.com return; 2418634Schris.emmons@arm.com 2428634Schris.emmons@arm.com // fail on other errors 2439550Sandreas.hansson@arm.com if (!subdir) { 2448634Schris.emmons@arm.com perror("opendir"); 2458634Schris.emmons@arm.com fatal("Error opening directory for recursive removal '%s'\n", 2468634Schris.emmons@arm.com fname); 2478634Schris.emmons@arm.com } 2488634Schris.emmons@arm.com 2499550Sandreas.hansson@arm.com struct dirent *de = readdir(subdir); 2508634Schris.emmons@arm.com while (de != NULL) { 2518634Schris.emmons@arm.com // ignore files starting with a '.'; user must delete those 2528634Schris.emmons@arm.com // manually if they really want to 2538634Schris.emmons@arm.com if (de->d_name[0] != '.') 2548634Schris.emmons@arm.com remove(name + PATH_SEPARATOR + de->d_name, recursive); 2558634Schris.emmons@arm.com 2569550Sandreas.hansson@arm.com de = readdir(subdir); 2578634Schris.emmons@arm.com } 25810412Sandreas.hansson@arm.com 25910412Sandreas.hansson@arm.com closedir(subdir); 2608634Schris.emmons@arm.com } 2618634Schris.emmons@arm.com 2628634Schris.emmons@arm.com // try to force recognition that we deleted the files in the directory 2638634Schris.emmons@arm.com sync(); 2648634Schris.emmons@arm.com 2658634Schris.emmons@arm.com if (::remove(fname.c_str()) != 0) { 2668634Schris.emmons@arm.com perror("Warning! 'remove' failed. Could not erase directory."); 2678634Schris.emmons@arm.com } 2688634Schris.emmons@arm.com } 2698634Schris.emmons@arm.com} 270