output.cc revision 11259
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> 3510810Sbr@bsdpad.com#include <unistd.h> 361388SN/A 378634Schris.emmons@arm.com#include <cassert> 388229Snate@binkert.org#include <cerrno> 398229Snate@binkert.org#include <climits> 408229Snate@binkert.org#include <cstdlib> 411388SN/A#include <fstream> 421388SN/A 435749Scws3k@cs.virginia.edu#include <gzstream.hh> 445749Scws3k@cs.virginia.edu 451388SN/A#include "base/misc.hh" 461388SN/A#include "base/output.hh" 471388SN/A 481388SN/Ausing namespace std; 491388SN/A 501388SN/AOutputDirectory simout; 511388SN/A 521388SN/A/** 538634Schris.emmons@arm.com * @file This file manages creating / deleting output files for the simulator. 541388SN/A */ 551388SN/AOutputDirectory::OutputDirectory() 561388SN/A{} 571388SN/A 581388SN/AOutputDirectory::~OutputDirectory() 595749Scws3k@cs.virginia.edu{ 605749Scws3k@cs.virginia.edu for (map_t::iterator i = files.begin(); i != files.end(); i++) { 615749Scws3k@cs.virginia.edu if (i->second) 625749Scws3k@cs.virginia.edu delete i->second; 635749Scws3k@cs.virginia.edu } 645749Scws3k@cs.virginia.edu} 655749Scws3k@cs.virginia.edu 665749Scws3k@cs.virginia.edustd::ostream * 675749Scws3k@cs.virginia.eduOutputDirectory::checkForStdio(const string &name) const 685749Scws3k@cs.virginia.edu{ 695749Scws3k@cs.virginia.edu if (name == "cerr" || name == "stderr") 705749Scws3k@cs.virginia.edu return &cerr; 715749Scws3k@cs.virginia.edu 725749Scws3k@cs.virginia.edu if (name == "cout" || name == "stdout") 735749Scws3k@cs.virginia.edu return &cout; 745749Scws3k@cs.virginia.edu 755749Scws3k@cs.virginia.edu return NULL; 765749Scws3k@cs.virginia.edu} 775749Scws3k@cs.virginia.edu 785749Scws3k@cs.virginia.eduostream * 795749Scws3k@cs.virginia.eduOutputDirectory::openFile(const string &filename, 8011259Ssascha.bischoff@ARM.com ios_base::openmode mode, bool no_gz) 815749Scws3k@cs.virginia.edu{ 8211259Ssascha.bischoff@ARM.com bool gz = !no_gz; 8311259Ssascha.bischoff@ARM.com gz = gz && filename.find(".gz", filename.length()-3) < filename.length(); 8411259Ssascha.bischoff@ARM.com if (gz) { 855749Scws3k@cs.virginia.edu ogzstream *file = new ogzstream(filename.c_str(), mode); 865749Scws3k@cs.virginia.edu if (!file->is_open()) 875749Scws3k@cs.virginia.edu fatal("Cannot open file %s", filename); 888634Schris.emmons@arm.com assert(files.find(filename) == files.end()); 898634Schris.emmons@arm.com files[filename] = file; 905749Scws3k@cs.virginia.edu return file; 915749Scws3k@cs.virginia.edu } else { 925749Scws3k@cs.virginia.edu ofstream *file = new ofstream(filename.c_str(), mode); 935749Scws3k@cs.virginia.edu if (!file->is_open()) 945749Scws3k@cs.virginia.edu fatal("Cannot open file %s", filename); 958634Schris.emmons@arm.com assert(files.find(filename) == files.end()); 968634Schris.emmons@arm.com files[filename] = file; 975749Scws3k@cs.virginia.edu return file; 985749Scws3k@cs.virginia.edu } 995749Scws3k@cs.virginia.edu} 1001388SN/A 1011388SN/Avoid 1028634Schris.emmons@arm.comOutputDirectory::close(ostream *openStream) { 1038634Schris.emmons@arm.com map_t::iterator i; 1048634Schris.emmons@arm.com for (i = files.begin(); i != files.end(); i++) { 1058634Schris.emmons@arm.com if (i->second != openStream) 1068634Schris.emmons@arm.com continue; 1078634Schris.emmons@arm.com 1088634Schris.emmons@arm.com ofstream *fs = dynamic_cast<ofstream*>(i->second); 1098634Schris.emmons@arm.com if (fs) { 1108634Schris.emmons@arm.com fs->close(); 1118634Schris.emmons@arm.com delete i->second; 1128634Schris.emmons@arm.com break; 1138634Schris.emmons@arm.com } else { 1148634Schris.emmons@arm.com ogzstream *gfs = dynamic_cast<ogzstream*>(i->second); 1158634Schris.emmons@arm.com if (gfs) { 1168634Schris.emmons@arm.com gfs->close(); 1178634Schris.emmons@arm.com delete i->second; 1188634Schris.emmons@arm.com break; 1198634Schris.emmons@arm.com } 1208634Schris.emmons@arm.com } 1218634Schris.emmons@arm.com } 1228634Schris.emmons@arm.com 1238634Schris.emmons@arm.com if (i == files.end()) 1248634Schris.emmons@arm.com fatal("Attempted to close an unregistred file stream"); 1258634Schris.emmons@arm.com 1268634Schris.emmons@arm.com files.erase(i); 1278634Schris.emmons@arm.com} 1288634Schris.emmons@arm.com 1298634Schris.emmons@arm.comvoid 1301388SN/AOutputDirectory::setDirectory(const string &d) 1311388SN/A{ 1321388SN/A if (!dir.empty()) 1331388SN/A panic("Output directory already set!\n"); 1341388SN/A 1351388SN/A dir = d; 1361388SN/A 1378634Schris.emmons@arm.com // guarantee that directory ends with a path separator 1388634Schris.emmons@arm.com if (dir[dir.size() - 1] != PATH_SEPARATOR) 1398634Schris.emmons@arm.com dir += PATH_SEPARATOR; 1401388SN/A} 1411388SN/A 1421388SN/Aconst string & 1435749Scws3k@cs.virginia.eduOutputDirectory::directory() const 1441388SN/A{ 1451388SN/A if (dir.empty()) 1461388SN/A panic("Output directory not set!"); 1471388SN/A 1481388SN/A return dir; 1491388SN/A} 1501388SN/A 1519398Sandreas.hansson@arm.comstring 1525749Scws3k@cs.virginia.eduOutputDirectory::resolve(const string &name) const 1531388SN/A{ 1548634Schris.emmons@arm.com return (name[0] != PATH_SEPARATOR) ? dir + name : name; 1551388SN/A} 1561388SN/A 1571388SN/Aostream * 15811259Ssascha.bischoff@ARM.comOutputDirectory::create(const string &name, bool binary, bool no_gz) 1591388SN/A{ 1605749Scws3k@cs.virginia.edu ostream *file = checkForStdio(name); 1615749Scws3k@cs.virginia.edu if (file) 1625749Scws3k@cs.virginia.edu return file; 1631388SN/A 1645749Scws3k@cs.virginia.edu string filename = resolve(name); 1655749Scws3k@cs.virginia.edu ios_base::openmode mode = 1668989SAli.Saidi@ARM.com ios::trunc | (binary ? ios::binary : (ios::openmode)0); 16711259Ssascha.bischoff@ARM.com file = openFile(filename, mode, no_gz); 1681388SN/A 1691388SN/A return file; 1701388SN/A} 1711388SN/A 1721388SN/Aostream * 1738634Schris.emmons@arm.comOutputDirectory::find(const string &name) const 1741388SN/A{ 1755749Scws3k@cs.virginia.edu ostream *file = checkForStdio(name); 1765749Scws3k@cs.virginia.edu if (file) 1775749Scws3k@cs.virginia.edu return file; 1781388SN/A 1798634Schris.emmons@arm.com const string filename = resolve(name); 1808634Schris.emmons@arm.com map_t::const_iterator i = files.find(filename); 1811388SN/A if (i != files.end()) 1821388SN/A return (*i).second; 1831388SN/A 1848634Schris.emmons@arm.com return NULL; 1851388SN/A} 1861388SN/A 1871388SN/Abool 1881388SN/AOutputDirectory::isFile(const std::ostream *os) 1891388SN/A{ 1901388SN/A return os && os != &cerr && os != &cout; 1911388SN/A} 1928634Schris.emmons@arm.com 1938634Schris.emmons@arm.combool 1948634Schris.emmons@arm.comOutputDirectory::isFile(const string &name) const 1958634Schris.emmons@arm.com{ 1968634Schris.emmons@arm.com // definitely a file if in our data structure 1978634Schris.emmons@arm.com if (find(name) != NULL) return true; 1988634Schris.emmons@arm.com 1998634Schris.emmons@arm.com struct stat st_buf; 2008634Schris.emmons@arm.com int st = stat(name.c_str(), &st_buf); 2018634Schris.emmons@arm.com return (st == 0) && S_ISREG(st_buf.st_mode); 2028634Schris.emmons@arm.com} 2038634Schris.emmons@arm.com 2048634Schris.emmons@arm.comstring 2058634Schris.emmons@arm.comOutputDirectory::createSubdirectory(const string &name) const 2068634Schris.emmons@arm.com{ 2078634Schris.emmons@arm.com const string new_dir = resolve(name); 2088634Schris.emmons@arm.com if (new_dir.find(directory()) == string::npos) 2098634Schris.emmons@arm.com fatal("Attempting to create subdirectory not in m5 output dir\n"); 2108634Schris.emmons@arm.com 2118634Schris.emmons@arm.com // if it already exists, that's ok; otherwise, fail if we couldn't create 2128634Schris.emmons@arm.com if ((mkdir(new_dir.c_str(), 0755) != 0) && (errno != EEXIST)) 2138634Schris.emmons@arm.com fatal("Failed to create new output subdirectory '%s'\n", new_dir); 2148634Schris.emmons@arm.com 2158634Schris.emmons@arm.com return name + PATH_SEPARATOR; 2168634Schris.emmons@arm.com} 2178634Schris.emmons@arm.com 2188634Schris.emmons@arm.comvoid 2198634Schris.emmons@arm.comOutputDirectory::remove(const string &name, bool recursive) 2208634Schris.emmons@arm.com{ 2218634Schris.emmons@arm.com const string fname = resolve(name); 2228634Schris.emmons@arm.com 2238634Schris.emmons@arm.com if (fname.find(directory()) == string::npos) 2248634Schris.emmons@arm.com fatal("Attempting to remove file/dir not in output dir\n"); 2258634Schris.emmons@arm.com 2268634Schris.emmons@arm.com if (isFile(fname)) { 2278634Schris.emmons@arm.com // close and release file if we have it open 2288634Schris.emmons@arm.com map_t::iterator itr = files.find(fname); 2298634Schris.emmons@arm.com if (itr != files.end()) { 2308634Schris.emmons@arm.com delete itr->second; 2318634Schris.emmons@arm.com files.erase(itr); 2328634Schris.emmons@arm.com } 2338634Schris.emmons@arm.com 2348634Schris.emmons@arm.com if (::remove(fname.c_str()) != 0) 2358634Schris.emmons@arm.com fatal("Could not erase file '%s'\n", fname); 2368634Schris.emmons@arm.com } else { 2378634Schris.emmons@arm.com // assume 'name' is a directory 2388634Schris.emmons@arm.com if (recursive) { 2399550Sandreas.hansson@arm.com DIR *subdir = opendir(fname.c_str()); 2408634Schris.emmons@arm.com 2418634Schris.emmons@arm.com // silently ignore removal request for non-existent directory 2429550Sandreas.hansson@arm.com if ((!subdir) && (errno == ENOENT)) 2438634Schris.emmons@arm.com return; 2448634Schris.emmons@arm.com 2458634Schris.emmons@arm.com // fail on other errors 2469550Sandreas.hansson@arm.com if (!subdir) { 2478634Schris.emmons@arm.com perror("opendir"); 2488634Schris.emmons@arm.com fatal("Error opening directory for recursive removal '%s'\n", 2498634Schris.emmons@arm.com fname); 2508634Schris.emmons@arm.com } 2518634Schris.emmons@arm.com 2529550Sandreas.hansson@arm.com struct dirent *de = readdir(subdir); 2538634Schris.emmons@arm.com while (de != NULL) { 2548634Schris.emmons@arm.com // ignore files starting with a '.'; user must delete those 2558634Schris.emmons@arm.com // manually if they really want to 2568634Schris.emmons@arm.com if (de->d_name[0] != '.') 2578634Schris.emmons@arm.com remove(name + PATH_SEPARATOR + de->d_name, recursive); 2588634Schris.emmons@arm.com 2599550Sandreas.hansson@arm.com de = readdir(subdir); 2608634Schris.emmons@arm.com } 26110412Sandreas.hansson@arm.com 26210412Sandreas.hansson@arm.com closedir(subdir); 2638634Schris.emmons@arm.com } 2648634Schris.emmons@arm.com 2658634Schris.emmons@arm.com // try to force recognition that we deleted the files in the directory 2668634Schris.emmons@arm.com sync(); 2678634Schris.emmons@arm.com 2688634Schris.emmons@arm.com if (::remove(fname.c_str()) != 0) { 2698634Schris.emmons@arm.com perror("Warning! 'remove' failed. Could not erase directory."); 2708634Schris.emmons@arm.com } 2718634Schris.emmons@arm.com } 2728634Schris.emmons@arm.com} 273