source: rtems-tools/rtemstoolkit/rld-process.cpp

Last change on this file was 49fac03, checked in by Joel Sherrill <joel@…>, on 03/31/21 at 15:41:25

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@…>
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.

  • Property mode set to 100644
File size: 13.0 KB
Line 
1/*
2 * Copyright (c) 2011, Chris Johns <chrisj@rtems.org>
3 *
4 * Permission to use, copy, modify, and/or distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15 */
16
17#include "config.h"
18
19#include <ctype.h>
20#include <errno.h>
21#include <fcntl.h>
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25#include <sys/stat.h>
26#include <unistd.h>
27
28#ifdef HAVE_SYS_WAIT_H
29#include <sys/wait.h>
30#endif
31
32#ifndef WIFEXITED
33#define WIFEXITED(S) (((S) & 0xff) == 0)
34#endif
35#ifndef WEXITSTATUS
36#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
37#endif
38#ifndef WIFSIGNALED
39#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
40#endif
41#ifndef WTERMSIG
42#define WTERMSIG(S) ((S) & 0x7f)
43#endif
44#ifndef WIFSTOPPED
45#define WIFSTOPPED WIFEXITED
46#endif
47#ifndef WSTOPSIG
48#define WSTOPSIG WEXITSTATUS
49#endif
50
51#if __WIN32__
52#define CREATE_MODE (S_IRUSR | S_IWUSR)
53#define OPEN_FLAGS  (O_BINARY)
54#else
55#define CREATE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
56#define OPEN_FLAGS  (0)
57#endif
58
59#include <iostream>
60
61#include "rld.h"
62#include "rld-process.h"
63
64#include <libiberty.h>
65
66namespace rld
67{
68  namespace process
69  {
70    /**
71     * Global keep of temporary files if true. Used to help debug a system.
72     */
73    bool keep_temporary_files = false;
74
75    /**
76     * The temporary files.
77     */
78    temporary_files temporaries;
79
80    temporary_files::temporary_files ()
81    {
82    }
83
84    temporary_files::~temporary_files ()
85    {
86      try
87      {
88        clean_up ();
89      }
90      catch (...)
91      {
92      }
93    }
94
95    const std::string
96    temporary_files::get (const std::string& suffix, bool keep)
97    {
98      char* temp = ::make_temp_file (suffix.c_str ());
99
100      if (!temp)
101        throw rld::error ("bad temp name", "temp-file");
102
103      const std::string name = rld::find_replace (temp,
104                                                  RLD_PATH_SEPARATOR_STR RLD_PATH_SEPARATOR_STR,
105                                                  RLD_PATH_SEPARATOR_STR);
106      tempfile_ref ref (name, keep);
107      tempfiles.push_back (ref);
108
109      ::free (temp);
110
111      return name;
112    }
113
114    void
115    temporary_files::unlink (const tempfile_ref& ref)
116    {
117      if (!keep_temporary_files && !ref.keep)
118        rld::path::unlink (ref.name);
119    }
120
121    void
122    temporary_files::erase (const std::string& name)
123    {
124      for (tempfile_container::iterator tfi = tempfiles.begin ();
125           tfi != tempfiles.end ();
126           ++tfi)
127      {
128        if ((*tfi).name == name)
129        {
130          unlink (*tfi);
131          tempfiles.erase (tfi);
132          break;
133        }
134      }
135    }
136
137    void
138    temporary_files::keep (const std::string& name)
139    {
140      for (tempfile_container::iterator tfi = tempfiles.begin ();
141           tfi != tempfiles.end ();
142           ++tfi)
143      {
144        if ((*tfi).name == name)
145        {
146          (*tfi).keep = true;
147          break;
148        }
149      }
150    }
151
152    void
153    temporary_files::clean_up ()
154    {
155      for (tempfile_container::iterator tfi = tempfiles.begin ();
156           tfi != tempfiles.end ();
157           ++tfi)
158      {
159        unlink (*tfi);
160      }
161    }
162
163    tempfile::tempfile (const std::string& suffix, bool _keep)
164      : suffix (suffix),
165        overridden (false),
166        fd (-1),
167        level (0)
168    {
169      _name = temporaries.get (suffix, _keep);
170    }
171
172    tempfile::~tempfile ()
173    {
174      try
175      {
176        close ();
177        temporaries.erase (_name);
178      }
179      catch (...)
180      {
181      }
182    }
183
184    void
185    tempfile::open (bool writable)
186    {
187      if (fd < 0)
188      {
189        bool ok = rld::path::check_file (_name);
190        int  flags = writable ? O_RDWR : O_RDONLY;
191        int  mode = writable ? CREATE_MODE : 0;
192
193        if (writable && overridden)
194        {
195          flags |= O_CREAT | O_TRUNC | O_APPEND;
196        }
197        else
198        {
199          if (!ok)
200            throw rld::error ("Not found.", "tempfile open:" + _name);
201        }
202
203        level = 0;
204        fd = ::open (_name.c_str (), flags, mode);
205        if (fd < 0)
206          throw rld::error (::strerror (errno), "tempfile open:" + _name);
207      }
208    }
209
210    void
211    tempfile::close ()
212    {
213      if (fd != -1)
214      {
215        ::close (fd);
216        fd = -1;
217        level = 0;
218      }
219    }
220
221    void
222    tempfile::override (const std::string& name_)
223    {
224      if (fd >= 0)
225        throw rld::error ("Already open", "tempfile override");
226      rld::path::unlink (_name);
227      overridden = true;
228      _name = name_ + suffix;
229    }
230
231    void
232    tempfile::keep ()
233    {
234      temporaries.keep (_name);
235    }
236
237    const std::string&
238    tempfile::name () const
239    {
240      return _name;
241    }
242
243    size_t
244    tempfile::size ()
245    {
246      if (fd < 0)
247        return 0;
248
249      struct stat sb;
250      if (::stat (_name.c_str (), &sb) == 0)
251        return sb.st_size;
252
253      return 0;
254    }
255
256    void
257    tempfile::read (std::string& all)
258    {
259      all.clear ();
260      if (fd != -1)
261      {
262        if (level)
263          all.append (buf, level);
264        level = 0;
265        while (true)
266        {
267          int read = ::read (fd, buf, sizeof (buf) );
268          if (read < 0)
269            throw rld::error (::strerror (errno), "tempfile get read:" + _name);
270          else if (read == 0)
271            break;
272          else
273            all.append (buf, read);
274        }
275      }
276    }
277
278    void
279    tempfile::read_line (std::string& line)
280    {
281      line.clear ();
282      if (fd != -1)
283      {
284        bool reading = true;
285        while (reading)
286        {
287          if (level < (sizeof (buf) - 1))
288          {
289            ::memset (buf + level, 0, sizeof (buf) - level);
290            int read = ::read (fd, buf + level, sizeof (buf) - level - 1);
291            if (read < 0)
292              throw rld::error (::strerror (errno), "tempfile read:" + _name);
293            else if (read == 0)
294              reading = false;
295            else
296              level += read;
297          }
298          if (level)
299          {
300            char* lf = ::strchr (buf, '\n');
301            int   len = level;
302            if (lf)
303            {
304              len = lf - &buf[0] + 1;
305              reading = false;
306            }
307            line.append (buf, len);
308            level -= len;
309            if (level)
310              ::memmove (buf, &buf[len], level + 1);
311          }
312        }
313      }
314    }
315
316    void
317    tempfile::write (const std::string& s)
318    {
319      const char* p = s.c_str ();
320      size_t      l = s.length ();
321      while (l)
322      {
323        int written = ::write (fd, p, l);
324        if (written < 0)
325            throw rld::error (::strerror (errno), "tempfile write:" + _name);
326        if (written == 0)
327          break;
328        l -= written;
329      }
330    }
331
332    void
333    tempfile::write_line (const std::string& s)
334    {
335      write (s);
336      write (RLD_LINE_SEPARATOR);
337    }
338
339    void
340    tempfile::write_lines (const rld::strings& ss)
341    {
342      for (rld::strings::const_iterator ssi = ss.begin ();
343           ssi != ss.end ();
344           ++ssi)
345      {
346        write_line (*ssi);
347      }
348    }
349
350    void
351    tempfile::output (std::ostream& out)
352    {
353      std::string prefix;
354      output (prefix, out);
355    }
356
357    void
358    tempfile::output (const std::string& prefix,
359                      std::ostream&      out,
360                      bool               line_numbers)
361    {
362      if (fd == -1)
363      {
364        std::string line;
365        int         lc = 0;
366        open ();
367        while (true)
368        {
369          read_line (line);
370          ++lc;
371          if (line.empty () && (level == 0))
372            break;
373          if (!prefix.empty ())
374            out << prefix << ": ";
375          if (line_numbers)
376            out << lc << ": ";
377          out << line << std::flush;
378        }
379        close ();
380      }
381    }
382
383    void
384    set_keep_temporary_files ()
385    {
386      keep_temporary_files = true;
387    }
388
389    void
390    temporaries_clean_up ()
391    {
392      temporaries.clean_up ();
393    }
394
395    void
396    args_append (arg_container& args, const std::string& str)
397    {
398      rld::strings ss;
399      rld::split (ss, str);
400      for (rld::strings::iterator ssi = ss.begin ();
401           ssi != ss.end ();
402           ++ssi)
403      {
404        args.push_back (*ssi);
405      }
406    }
407
408    status
409    execute (const std::string& pname,
410             const std::string& command,
411             const std::string& outname,
412             const std::string& errname)
413    {
414      arg_container args;
415      parse_command_line (command, args);
416      return execute (pname, args, outname, errname);
417    }
418
419    status
420    execute (const std::string&   pname,
421             const arg_container& args,
422             const std::string&   outname,
423             const std::string&   errname)
424    {
425      if (rld::verbose (RLD_VERBOSE_TRACE))
426      {
427        std::cout << "execute: ";
428        for (size_t a = 0; a < args.size (); ++a)
429          std::cout << args[a] << ' ';
430        std::cout << std::endl;
431      }
432
433      const char** cargs = new const char* [args.size () + 1];
434
435      for (size_t a = 0; a < args.size (); ++a)
436        cargs[a] = args[a].c_str ();
437      cargs[args.size ()] = 0;
438
439      int err = 0;
440      int s = 0;
441
442      const char* serr = pex_one (PEX_LAST | PEX_SEARCH,
443                                  args[0].c_str (),
444                                  (char* const*) cargs,
445                                  pname.c_str (),
446                                  outname.c_str (),
447                                  errname.c_str (),
448                                  &s,
449                                  &err);
450
451      delete [] cargs;
452
453      if (serr)
454        throw rld::error ("execute: " + args[0], serr);
455      else if (err)
456        throw rld::error ("execute: " + args[0], ::strerror (err));
457
458      status _status;
459
460      if (rld::verbose (RLD_VERBOSE_TRACE))
461        std::cout << "execute: status: ";
462
463      if (WIFEXITED (s))
464      {
465        _status.type = status::normal;
466        _status.code = WEXITSTATUS (s);
467        if (rld::verbose (RLD_VERBOSE_TRACE))
468          std::cout << _status.code << std::endl;
469      }
470      else if (WIFSIGNALED (s))
471      {
472        _status.type = status::signal;
473        _status.code = WTERMSIG (s);
474        if (rld::verbose (RLD_VERBOSE_TRACE))
475          std::cout << "signal: " << _status.code << std::endl;
476      }
477      else if (WIFSTOPPED (s))
478      {
479        _status.type = status::stopped;
480        _status.code = WSTOPSIG (s);
481        if (rld::verbose (RLD_VERBOSE_TRACE))
482          std::cout << "stopped: " << _status.code << std::endl;
483      }
484      else
485        throw rld::error ("execute: " + args[0], "unknown status returned");
486
487      return _status;
488    }
489
490    /*
491     * The code is based on this C file:
492     *  http://cybertiggyr.com/pcm/src/parse.c
493     */
494    void
495    parse_command_line (const std::string& command, arg_container& args)
496    {
497      enum pstate
498      {
499        pstate_discard_space,
500        pstate_accumulate_quoted,
501        pstate_accumulate_raw
502      };
503
504      args.clear ();
505
506      const char quote = '"';
507      const char escape = '\\';
508      pstate     state = pstate_discard_space;
509      size_t     start = 0;
510      size_t     i = 0;
511
512      while (i < command.size ())
513      {
514        switch (state)
515        {
516          case pstate_discard_space:
517            if (command[i] == quote)
518            {
519              ++i;
520              start = i;
521              state = pstate_accumulate_quoted;
522            }
523            else if (::isspace (command[i]))
524            {
525              ++i;
526            }
527            else /* includes escape */
528            {
529              start = i;
530              state = pstate_accumulate_raw;
531            }
532            break;
533
534          case pstate_accumulate_quoted:
535            if (command[i] == quote)
536            {
537              args.push_back (command.substr (start, i - 1));
538              ++i;
539              state = pstate_discard_space;
540            }
541            else if ((command[i] == escape) && (command[i + 1] == quote))
542            {
543              i += 2;
544            }
545            else /* includes space */
546            {
547              ++i;
548            }
549            break;
550
551          case pstate_accumulate_raw:
552            if (command[i] == quote)
553            {
554              throw rld::error ("quote in token", "command parse");
555            }
556            else if ((command[i] == escape) && (command[i + 1] == quote))
557            {
558              i += 2;
559            }
560            else if (::isspace (command[i]))
561            {
562              args.push_back (command.substr (start, i - 1));
563              ++i;
564              state = pstate_discard_space;
565            }
566            else
567            {
568              ++i;
569            }
570            break;
571        }
572      }
573    }
574  }
575}
Note: See TracBrowser for help on using the repository browser.