output.cc revision 9550
12SN/A/* 213759Sgiacomo.gabrielli@arm.com * Copyright (c) 2005 The Regents of The University of Michigan 313759Sgiacomo.gabrielli@arm.com * All rights reserved. 413759Sgiacomo.gabrielli@arm.com * 513759Sgiacomo.gabrielli@arm.com * Redistribution and use in source and binary forms, with or without 613759Sgiacomo.gabrielli@arm.com * modification, are permitted provided that the following conditions are 713759Sgiacomo.gabrielli@arm.com * met: redistributions of source code must retain the above copyright 813759Sgiacomo.gabrielli@arm.com * notice, this list of conditions and the following disclaimer; 913759Sgiacomo.gabrielli@arm.com * redistributions in binary form must reproduce the above copyright 1013759Sgiacomo.gabrielli@arm.com * notice, this list of conditions and the following disclaimer in the 1113759Sgiacomo.gabrielli@arm.com * documentation and/or other materials provided with the distribution; 1213759Sgiacomo.gabrielli@arm.com * neither the name of the copyright holders nor the names of its 1313759Sgiacomo.gabrielli@arm.com * contributors may be used to endorse or promote products derived from 142188SN/A * this software without specific prior written permission. 152SN/A * 162SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272SN/A * 282SN/A * Authors: Nathan Binkert 292SN/A * Chris Emmons 302SN/A */ 312SN/A 322SN/A#include <sys/stat.h> 332SN/A#include <sys/types.h> 342SN/A#include <dirent.h> 352SN/A 362SN/A#include <cassert> 372SN/A#include <cerrno> 382SN/A#include <climits> 392665SN/A#include <cstdlib> 402665SN/A#include <fstream> 412665SN/A 422665SN/A#include <gzstream.hh> 432665SN/A 442SN/A#include "base/misc.hh" 452SN/A#include "base/output.hh" 4611793Sbrandon.potter@amd.com 4711793Sbrandon.potter@amd.comusing namespace std; 482SN/A 492SN/AOutputDirectory simout; 502465SN/A 513565Sgblack@eecs.umich.edu/** 525529Snate@binkert.org * @file This file manages creating / deleting output files for the simulator. 538777Sgblack@eecs.umich.edu */ 541917SN/AOutputDirectory::OutputDirectory() 551070SN/A{} 561917SN/A 572188SN/AOutputDirectory::~OutputDirectory() 588777Sgblack@eecs.umich.edu{ 598777Sgblack@eecs.umich.edu for (map_t::iterator i = files.begin(); i != files.end(); i++) { 601917SN/A if (i->second) 612290SN/A delete i->second; 628777Sgblack@eecs.umich.edu } 638706Sandreas.hansson@arm.com} 648799Sgblack@eecs.umich.edu 658809Sgblack@eecs.umich.edustd::ostream * 6610319SAndreas.Sandberg@ARM.comOutputDirectory::checkForStdio(const string &name) const 678793Sgblack@eecs.umich.edu{ 688777Sgblack@eecs.umich.edu if (name == "cerr" || name == "stderr") 691070SN/A return &cerr; 701917SN/A 712519SN/A if (name == "cout" || name == "stdout") 722SN/A return &cout; 732SN/A 742SN/A return NULL; 752SN/A} 768820Sgblack@eecs.umich.edu 7712406Sgabeblack@google.comostream * 7812406Sgabeblack@google.comOutputDirectory::openFile(const string &filename, 7910537Sandreas.hansson@arm.com ios_base::openmode mode) 8010537Sandreas.hansson@arm.com{ 8113759Sgiacomo.gabrielli@arm.com if (filename.find(".gz", filename.length()-3) < filename.length()) { 828766Sgblack@eecs.umich.edu ogzstream *file = new ogzstream(filename.c_str(), mode); 838766Sgblack@eecs.umich.edu if (!file->is_open()) 848766Sgblack@eecs.umich.edu fatal("Cannot open file %s", filename); 8511627Smichael.lebeane@amd.com assert(files.find(filename) == files.end()); 868766Sgblack@eecs.umich.edu files[filename] = file; 879377Sgblack@eecs.umich.edu return file; 882683Sktlim@umich.edu } else { 8912406Sgabeblack@google.com ofstream *file = new ofstream(filename.c_str(), mode); 909384SAndreas.Sandberg@arm.com if (!file->is_open()) 919384SAndreas.Sandberg@arm.com fatal("Cannot open file %s", filename); 9213759Sgiacomo.gabrielli@arm.com assert(files.find(filename) == files.end()); 932SN/A files[filename] = file; 942683Sktlim@umich.edu return file; 952190SN/A } 962680SN/A} 972290SN/A 986316Sgblack@eecs.umich.eduvoid 991917SN/AOutputDirectory::close(ostream *openStream) { 1008735Sandreas.hanson@arm.com map_t::iterator i; 1011982SN/A for (i = files.begin(); i != files.end(); i++) { 1021917SN/A if (i->second != openStream) 1032683Sktlim@umich.edu continue; 1042683Sktlim@umich.edu 1051917SN/A ofstream *fs = dynamic_cast<ofstream*>(i->second); 1061917SN/A if (fs) { 1071917SN/A fs->close(); 1081917SN/A delete i->second; 1091917SN/A break; 1101917SN/A } else { 1111917SN/A ogzstream *gfs = dynamic_cast<ogzstream*>(i->second); 1121917SN/A if (gfs) { 1132521SN/A gfs->close(); 1145482Snate@binkert.org delete i->second; 11512181Sgabeblack@google.com break; 1162SN/A } 1172862Sktlim@umich.edu } 1182683Sktlim@umich.edu } 1191070SN/A 1202680SN/A if (i == files.end()) 1211070SN/A fatal("Attempted to close an unregistred file stream"); 1221070SN/A 1231917SN/A files.erase(i); 1242683Sktlim@umich.edu} 125180SN/A 1269441SAndreas.Sandberg@ARM.comvoid 1279478Snilay@cs.wisc.eduOutputDirectory::setDirectory(const string &d) 128180SN/A{ 1299441SAndreas.Sandberg@ARM.com if (!dir.empty()) 1309441SAndreas.Sandberg@ARM.com panic("Output directory already set!\n"); 131180SN/A 1322864Sktlim@umich.edu dir = d; 1332864Sktlim@umich.edu 1342864Sktlim@umich.edu // guarantee that directory ends with a path separator 1352862Sktlim@umich.edu if (dir[dir.size() - 1] != PATH_SEPARATOR) 1362862Sktlim@umich.edu dir += PATH_SEPARATOR; 1372862Sktlim@umich.edu} 1382862Sktlim@umich.edu 1392862Sktlim@umich.educonst string & 1408793Sgblack@eecs.umich.eduOutputDirectory::directory() const 1418793Sgblack@eecs.umich.edu{ 1425714Shsul@eecs.umich.edu if (dir.empty()) 1435715Shsul@eecs.umich.edu panic("Output directory not set!"); 1445714Shsul@eecs.umich.edu 1452862Sktlim@umich.edu return dir; 1462862Sktlim@umich.edu} 1472862Sktlim@umich.edu 14810905Sandreas.sandberg@arm.comstring 149217SN/AOutputDirectory::resolve(const string &name) const 15010905Sandreas.sandberg@arm.com{ 15110905Sandreas.sandberg@arm.com return (name[0] != PATH_SEPARATOR) ? dir + name : name; 152217SN/A} 153217SN/A 154217SN/Aostream * 155217SN/AOutputDirectory::create(const string &name, bool binary) 15610905Sandreas.sandberg@arm.com{ 157217SN/A ostream *file = checkForStdio(name); 15810905Sandreas.sandberg@arm.com if (file) 15910905Sandreas.sandberg@arm.com return file; 160217SN/A 161217SN/A string filename = resolve(name); 1622683Sktlim@umich.edu ios_base::openmode mode = 1639461Snilay@cs.wisc.edu ios::trunc | (binary ? ios::binary : (ios::openmode)0); 1649461Snilay@cs.wisc.edu file = openFile(filename, mode); 1659461Snilay@cs.wisc.edu 1669461Snilay@cs.wisc.edu return file; 1679461Snilay@cs.wisc.edu} 1689461Snilay@cs.wisc.edu 1692683Sktlim@umich.eduostream * 1702683Sktlim@umich.eduOutputDirectory::find(const string &name) const 17111359Sandreas@sandberg.pp.se{ 17211359Sandreas@sandberg.pp.se ostream *file = checkForStdio(name); 17311359Sandreas@sandberg.pp.se if (file) 1742683Sktlim@umich.edu return file; 175217SN/A 176217SN/A const string filename = resolve(name); 17710407Smitch.hayenga@arm.com map_t::const_iterator i = files.find(filename); 1782SN/A if (i != files.end()) 1792680SN/A return (*i).second; 1802SN/A 1812SN/A return NULL; 1827823Ssteve.reinhardt@amd.com} 1832680SN/A 18410407Smitch.hayenga@arm.combool 185393SN/AOutputDirectory::isFile(const std::ostream *os) 186393SN/A{ 187393SN/A return os && os != &cerr && os != &cout; 1882683Sktlim@umich.edu} 189393SN/A 1902680SN/Abool 191393SN/AOutputDirectory::isFile(const string &name) const 192393SN/A{ 1937823Ssteve.reinhardt@amd.com // definitely a file if in our data structure 1947823Ssteve.reinhardt@amd.com if (find(name) != NULL) return true; 1952680SN/A 1968735Sandreas.hanson@arm.com struct stat st_buf; 1972SN/A int st = stat(name.c_str(), &st_buf); 1982SN/A return (st == 0) && S_ISREG(st_buf.st_mode); 199393SN/A} 200393SN/A 2012683Sktlim@umich.edustring 202393SN/AOutputDirectory::createSubdirectory(const string &name) const 2032680SN/A{ 204393SN/A const string new_dir = resolve(name); 205393SN/A if (new_dir.find(directory()) == string::npos) 2062680SN/A fatal("Attempting to create subdirectory not in m5 output dir\n"); 2078735Sandreas.hanson@arm.com 208393SN/A // if it already exists, that's ok; otherwise, fail if we couldn't create 209393SN/A if ((mkdir(new_dir.c_str(), 0755) != 0) && (errno != EEXIST)) 210393SN/A fatal("Failed to create new output subdirectory '%s'\n", new_dir); 211393SN/A 2122683Sktlim@umich.edu return name + PATH_SEPARATOR; 2132SN/A} 2148793Sgblack@eecs.umich.edu 2152341SN/Avoid 2162SN/AOutputDirectory::remove(const string &name, bool recursive) 217716SN/A{ 218716SN/A const string fname = resolve(name); 2192683Sktlim@umich.edu 2202190SN/A if (fname.find(directory()) == string::npos) 2212680SN/A fatal("Attempting to remove file/dir not in output dir\n"); 2222190SN/A 2232190SN/A if (isFile(fname)) { 22410319SAndreas.Sandberg@ARM.com // close and release file if we have it open 22510319SAndreas.Sandberg@ARM.com map_t::iterator itr = files.find(fname); 22610319SAndreas.Sandberg@ARM.com if (itr != files.end()) { 22710319SAndreas.Sandberg@ARM.com delete itr->second; 22810319SAndreas.Sandberg@ARM.com files.erase(itr); 22910319SAndreas.Sandberg@ARM.com } 23010319SAndreas.Sandberg@ARM.com 23110319SAndreas.Sandberg@ARM.com if (::remove(fname.c_str()) != 0) 23210319SAndreas.Sandberg@ARM.com fatal("Could not erase file '%s'\n", fname); 23310319SAndreas.Sandberg@ARM.com } else { 23410319SAndreas.Sandberg@ARM.com // assume 'name' is a directory 23510319SAndreas.Sandberg@ARM.com if (recursive) { 23610319SAndreas.Sandberg@ARM.com DIR *subdir = opendir(fname.c_str()); 23710319SAndreas.Sandberg@ARM.com 23810319SAndreas.Sandberg@ARM.com // silently ignore removal request for non-existent directory 239 if ((!subdir) && (errno == ENOENT)) 240 return; 241 242 // fail on other errors 243 if (!subdir) { 244 perror("opendir"); 245 fatal("Error opening directory for recursive removal '%s'\n", 246 fname); 247 } 248 249 struct dirent *de = readdir(subdir); 250 while (de != NULL) { 251 // ignore files starting with a '.'; user must delete those 252 // manually if they really want to 253 if (de->d_name[0] != '.') 254 remove(name + PATH_SEPARATOR + de->d_name, recursive); 255 256 de = readdir(subdir); 257 } 258 } 259 260 // try to force recognition that we deleted the files in the directory 261 sync(); 262 263 if (::remove(fname.c_str()) != 0) { 264 perror("Warning! 'remove' failed. Could not erase directory."); 265 } 266 } 267} 268