rtems-tools/rtemstoolkit/rld-process.cpp
Joel Sherrill 49fac039a1 Revert rld-process: Add named tempfile constructor
This patch reflected a temporary workaround which avoided regenerating
the temporary files for each symbol set. The need for redundant processing
is being eliminated in an upcoming patch series.

Hash: 420d7a13672991a1480d06ac02190f2976b9253b

From 420d7a13672991a1480d06ac02190f2976b9253b Mon Sep 17 00:00:00 2001
From: Alex White <alex.white@oarcorp.com>
Date: Wed, 3 Mar 2021 09:48:00 -0600
Subject: rld-process: Add named tempfile constructor

This adds a new tempfile constructor for creating a named tempfile
rather than generating the name.
2021-03-31 10:41:25 -05:00

576 lines
13 KiB
C++

/*
* Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include "config.h"
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
#ifndef WIFEXITED
#define WIFEXITED(S) (((S) & 0xff) == 0)
#endif
#ifndef WEXITSTATUS
#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
#endif
#ifndef WIFSIGNALED
#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
#endif
#ifndef WTERMSIG
#define WTERMSIG(S) ((S) & 0x7f)
#endif
#ifndef WIFSTOPPED
#define WIFSTOPPED WIFEXITED
#endif
#ifndef WSTOPSIG
#define WSTOPSIG WEXITSTATUS
#endif
#if __WIN32__
#define CREATE_MODE (S_IRUSR | S_IWUSR)
#define OPEN_FLAGS (O_BINARY)
#else
#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
#define OPEN_FLAGS (0)
#endif
#include <iostream>
#include "rld.h"
#include "rld-process.h"
#include <libiberty.h>
namespace rld
{
namespace process
{
/**
* Global keep of temporary files if true. Used to help debug a system.
*/
bool keep_temporary_files = false;
/**
* The temporary files.
*/
temporary_files temporaries;
temporary_files::temporary_files ()
{
}
temporary_files::~temporary_files ()
{
try
{
clean_up ();
}
catch (...)
{
}
}
const std::string
temporary_files::get (const std::string& suffix, bool keep)
{
char* temp = ::make_temp_file (suffix.c_str ());
if (!temp)
throw rld::error ("bad temp name", "temp-file");
const std::string name = rld::find_replace (temp,
RLD_PATH_SEPARATOR_STR RLD_PATH_SEPARATOR_STR,
RLD_PATH_SEPARATOR_STR);
tempfile_ref ref (name, keep);
tempfiles.push_back (ref);
::free (temp);
return name;
}
void
temporary_files::unlink (const tempfile_ref& ref)
{
if (!keep_temporary_files && !ref.keep)
rld::path::unlink (ref.name);
}
void
temporary_files::erase (const std::string& name)
{
for (tempfile_container::iterator tfi = tempfiles.begin ();
tfi != tempfiles.end ();
++tfi)
{
if ((*tfi).name == name)
{
unlink (*tfi);
tempfiles.erase (tfi);
break;
}
}
}
void
temporary_files::keep (const std::string& name)
{
for (tempfile_container::iterator tfi = tempfiles.begin ();
tfi != tempfiles.end ();
++tfi)
{
if ((*tfi).name == name)
{
(*tfi).keep = true;
break;
}
}
}
void
temporary_files::clean_up ()
{
for (tempfile_container::iterator tfi = tempfiles.begin ();
tfi != tempfiles.end ();
++tfi)
{
unlink (*tfi);
}
}
tempfile::tempfile (const std::string& suffix, bool _keep)
: suffix (suffix),
overridden (false),
fd (-1),
level (0)
{
_name = temporaries.get (suffix, _keep);
}
tempfile::~tempfile ()
{
try
{
close ();
temporaries.erase (_name);
}
catch (...)
{
}
}
void
tempfile::open (bool writable)
{
if (fd < 0)
{
bool ok = rld::path::check_file (_name);
int flags = writable ? O_RDWR : O_RDONLY;
int mode = writable ? CREATE_MODE : 0;
if (writable && overridden)
{
flags |= O_CREAT | O_TRUNC | O_APPEND;
}
else
{
if (!ok)
throw rld::error ("Not found.", "tempfile open:" + _name);
}
level = 0;
fd = ::open (_name.c_str (), flags, mode);
if (fd < 0)
throw rld::error (::strerror (errno), "tempfile open:" + _name);
}
}
void
tempfile::close ()
{
if (fd != -1)
{
::close (fd);
fd = -1;
level = 0;
}
}
void
tempfile::override (const std::string& name_)
{
if (fd >= 0)
throw rld::error ("Already open", "tempfile override");
rld::path::unlink (_name);
overridden = true;
_name = name_ + suffix;
}
void
tempfile::keep ()
{
temporaries.keep (_name);
}
const std::string&
tempfile::name () const
{
return _name;
}
size_t
tempfile::size ()
{
if (fd < 0)
return 0;
struct stat sb;
if (::stat (_name.c_str (), &sb) == 0)
return sb.st_size;
return 0;
}
void
tempfile::read (std::string& all)
{
all.clear ();
if (fd != -1)
{
if (level)
all.append (buf, level);
level = 0;
while (true)
{
int read = ::read (fd, buf, sizeof (buf) );
if (read < 0)
throw rld::error (::strerror (errno), "tempfile get read:" + _name);
else if (read == 0)
break;
else
all.append (buf, read);
}
}
}
void
tempfile::read_line (std::string& line)
{
line.clear ();
if (fd != -1)
{
bool reading = true;
while (reading)
{
if (level < (sizeof (buf) - 1))
{
::memset (buf + level, 0, sizeof (buf) - level);
int read = ::read (fd, buf + level, sizeof (buf) - level - 1);
if (read < 0)
throw rld::error (::strerror (errno), "tempfile read:" + _name);
else if (read == 0)
reading = false;
else
level += read;
}
if (level)
{
char* lf = ::strchr (buf, '\n');
int len = level;
if (lf)
{
len = lf - &buf[0] + 1;
reading = false;
}
line.append (buf, len);
level -= len;
if (level)
::memmove (buf, &buf[len], level + 1);
}
}
}
}
void
tempfile::write (const std::string& s)
{
const char* p = s.c_str ();
size_t l = s.length ();
while (l)
{
int written = ::write (fd, p, l);
if (written < 0)
throw rld::error (::strerror (errno), "tempfile write:" + _name);
if (written == 0)
break;
l -= written;
}
}
void
tempfile::write_line (const std::string& s)
{
write (s);
write (RLD_LINE_SEPARATOR);
}
void
tempfile::write_lines (const rld::strings& ss)
{
for (rld::strings::const_iterator ssi = ss.begin ();
ssi != ss.end ();
++ssi)
{
write_line (*ssi);
}
}
void
tempfile::output (std::ostream& out)
{
std::string prefix;
output (prefix, out);
}
void
tempfile::output (const std::string& prefix,
std::ostream& out,
bool line_numbers)
{
if (fd == -1)
{
std::string line;
int lc = 0;
open ();
while (true)
{
read_line (line);
++lc;
if (line.empty () && (level == 0))
break;
if (!prefix.empty ())
out << prefix << ": ";
if (line_numbers)
out << lc << ": ";
out << line << std::flush;
}
close ();
}
}
void
set_keep_temporary_files ()
{
keep_temporary_files = true;
}
void
temporaries_clean_up ()
{
temporaries.clean_up ();
}
void
args_append (arg_container& args, const std::string& str)
{
rld::strings ss;
rld::split (ss, str);
for (rld::strings::iterator ssi = ss.begin ();
ssi != ss.end ();
++ssi)
{
args.push_back (*ssi);
}
}
status
execute (const std::string& pname,
const std::string& command,
const std::string& outname,
const std::string& errname)
{
arg_container args;
parse_command_line (command, args);
return execute (pname, args, outname, errname);
}
status
execute (const std::string& pname,
const arg_container& args,
const std::string& outname,
const std::string& errname)
{
if (rld::verbose (RLD_VERBOSE_TRACE))
{
std::cout << "execute: ";
for (size_t a = 0; a < args.size (); ++a)
std::cout << args[a] << ' ';
std::cout << std::endl;
}
const char** cargs = new const char* [args.size () + 1];
for (size_t a = 0; a < args.size (); ++a)
cargs[a] = args[a].c_str ();
cargs[args.size ()] = 0;
int err = 0;
int s = 0;
const char* serr = pex_one (PEX_LAST | PEX_SEARCH,
args[0].c_str (),
(char* const*) cargs,
pname.c_str (),
outname.c_str (),
errname.c_str (),
&s,
&err);
delete [] cargs;
if (serr)
throw rld::error ("execute: " + args[0], serr);
else if (err)
throw rld::error ("execute: " + args[0], ::strerror (err));
status _status;
if (rld::verbose (RLD_VERBOSE_TRACE))
std::cout << "execute: status: ";
if (WIFEXITED (s))
{
_status.type = status::normal;
_status.code = WEXITSTATUS (s);
if (rld::verbose (RLD_VERBOSE_TRACE))
std::cout << _status.code << std::endl;
}
else if (WIFSIGNALED (s))
{
_status.type = status::signal;
_status.code = WTERMSIG (s);
if (rld::verbose (RLD_VERBOSE_TRACE))
std::cout << "signal: " << _status.code << std::endl;
}
else if (WIFSTOPPED (s))
{
_status.type = status::stopped;
_status.code = WSTOPSIG (s);
if (rld::verbose (RLD_VERBOSE_TRACE))
std::cout << "stopped: " << _status.code << std::endl;
}
else
throw rld::error ("execute: " + args[0], "unknown status returned");
return _status;
}
/*
* The code is based on this C file:
* http://cybertiggyr.com/pcm/src/parse.c
*/
void
parse_command_line (const std::string& command, arg_container& args)
{
enum pstate
{
pstate_discard_space,
pstate_accumulate_quoted,
pstate_accumulate_raw
};
args.clear ();
const char quote = '"';
const char escape = '\\';
pstate state = pstate_discard_space;
size_t start = 0;
size_t i = 0;
while (i < command.size ())
{
switch (state)
{
case pstate_discard_space:
if (command[i] == quote)
{
++i;
start = i;
state = pstate_accumulate_quoted;
}
else if (::isspace (command[i]))
{
++i;
}
else /* includes escape */
{
start = i;
state = pstate_accumulate_raw;
}
break;
case pstate_accumulate_quoted:
if (command[i] == quote)
{
args.push_back (command.substr (start, i - 1));
++i;
state = pstate_discard_space;
}
else if ((command[i] == escape) && (command[i + 1] == quote))
{
i += 2;
}
else /* includes space */
{
++i;
}
break;
case pstate_accumulate_raw:
if (command[i] == quote)
{
throw rld::error ("quote in token", "command parse");
}
else if ((command[i] == escape) && (command[i + 1] == quote))
{
i += 2;
}
else if (::isspace (command[i]))
{
args.push_back (command.substr (start, i - 1));
++i;
state = pstate_discard_space;
}
else
{
++i;
}
break;
}
}
}
}
}