source: rtems-tools/linkers/rld-process.cpp @ fe19d06

4.104.115
Last change on this file since fe19d06 was ec24a37, checked in by Chris Johns <chrisj@…>, on 05/06/12 at 22:47:11

Add to git.

  • Property mode set to 100644
File size: 10.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
27#ifdef HAVE_SYS_WAIT_H
28#include <sys/wait.h>
29#endif
30
31#ifndef WIFEXITED
32#define WIFEXITED(S) (((S) & 0xff) == 0)
33#endif
34#ifndef WEXITSTATUS
35#define WEXITSTATUS(S) (((S) & 0xff00) >> 8)
36#endif
37#ifndef WIFSIGNALED
38#define WIFSIGNALED(S) (((S) & 0xff) != 0 && ((S) & 0xff) != 0x7f)
39#endif
40#ifndef WTERMSIG
41#define WTERMSIG(S) ((S) & 0x7f)
42#endif
43#ifndef WIFSTOPPED
44#define WIFSTOPPED WIFEXITED
45#endif
46#ifndef WSTOPSIG
47#define WSTOPSIG WEXITSTATUS
48#endif
49
50#include <iostream>
51
52#include "rld.h"
53#include "rld-process.h"
54
55#include <libiberty.h>
56
57namespace rld
58{
59  namespace process
60  {
61    temporary_files::temporary_files ()
62    {
63    }
64
65    temporary_files::~temporary_files ()
66    {
67      clean_up ();
68    }
69   
70    const std::string
71    temporary_files::get ()
72    {
73      char* temp = ::make_temp_file ("rldXXXXXX");
74
75      if (!temp)
76        throw rld::error ("bad temp name", "pex");
77
78      std::string name = temp;
79
80      tempfiles.push_back (name);
81
82      return name;
83    }
84
85    void
86    temporary_files::unlink (const std::string& name)
87    {
88      struct stat sb;
89      if ((::stat (name.c_str (), &sb) >= 0) && S_ISREG (sb.st_mode))
90      {
91        if (::unlink (name.c_str ()) < 0)
92        {
93          std::cerr << "error: unlinking temp file: " << name << std::endl;
94          ::exit (100);
95        }
96      }
97    }
98
99    void
100    temporary_files::erase (const std::string& name)
101    {
102      for (tempfile_container::iterator tfi = tempfiles.begin ();
103           tfi != tempfiles.end ();
104           ++tfi)
105      {
106        if (*tfi == name)
107        {
108          unlink (name);
109          tempfiles.erase (tfi);
110          break;
111        }
112      }
113    }
114
115    void
116    temporary_files::clean_up ()
117    {
118      for (tempfile_container::iterator tfi = tempfiles.begin ();
119           tfi != tempfiles.end ();
120           ++tfi)
121      {
122        unlink (*tfi);
123      }
124    }
125
126    tempfile::tempfile ()
127      : fd (-1),
128        level (0)
129    {
130      _name = temporaries.get ();
131    }
132
133    tempfile::~tempfile ()
134    {
135      close ();
136      temporaries.erase (_name);
137    }
138
139    void
140    tempfile::open ()
141    {
142      if ((fd < 0) && rld::files::check_file (_name))
143      {
144        level = 0;
145        fd = ::open (_name.c_str (), O_RDONLY);
146        if (fd < 0)
147          throw rld::error (::strerror (errno), "tempfile open:" + _name);
148      }
149    }
150
151    void
152    tempfile::close ()
153    {
154      if (fd != -1)
155      {
156        ::close (fd);
157        fd = -1;
158        level = 0;
159      }
160    }
161
162    const std::string&
163    tempfile::name () const
164    {
165      return _name;
166    }
167
168    size_t
169    tempfile::size ()
170    {
171      if (fd < 0)
172        return 0;
173
174      struct stat sb;
175      if (::stat (_name.c_str (), &sb) == 0)
176        return sb.st_size;
177     
178      return 0;
179    }
180
181    void
182    tempfile::get (std::string& all)
183    {
184      all.clear ();
185      if (fd != -1)
186      {
187        if (level)
188          all.append (buf, level);
189        level = 0;
190        while (true)
191        {
192          int read = ::read (fd, buf, sizeof (buf) );
193          if (read < 0)
194            throw rld::error (::strerror (errno), "tempfile get read:" + _name);
195          else if (read == 0)
196            break;
197          else
198            all.append (buf, read);
199        }
200      }
201    }
202
203    void
204    tempfile::getline (std::string& line)
205    {
206      line.clear ();
207      if (fd != -1)
208      {
209        if (level)
210          line.append (buf, level);
211        level = 0;
212        while (true)
213        {
214          int read = ::read (fd, buf, sizeof (buf));
215          if (read < 0)
216            throw rld::error (::strerror (errno), "tempfile read:" + _name);
217          else if (read == 0)
218            break;
219          else
220          {
221            char* lf = ::strchr (buf, '\n');
222            if (lf)
223            {
224              int len = lf - &buf[0] + 1;
225              line.append (buf, len);
226              level = read - len;
227              if (level)
228                ::memmove (buf, &buf[len], level);
229              break;
230            }
231            line.append (buf, read);
232          }
233        }
234      }
235    }
236
237    void
238    tempfile::output (std::ostream& out)
239    {
240      std::string prefix;
241      output (prefix, out);
242    }
243
244    void
245    tempfile::output (const std::string& prefix,
246                      std::ostream&      out,
247                      bool               line_numbers)
248    {
249      if (fd == -1)
250      {
251        std::string line;
252        int         lc = 0;
253        open ();
254        while (true)
255        {
256          getline (line);
257          ++lc;
258          if (line.empty ())
259            break;
260          if (!prefix.empty ())
261            out << prefix << ':';
262          if (line_numbers)
263            out << lc << ':';
264          out << line;
265        }
266        close ();
267      }
268    }
269
270    status
271    execute (const std::string& pname,
272             const std::string& command,
273             const std::string& outname,
274             const std::string& errname)
275    {
276      arg_container args;
277      parse_command_line (command, args);
278      return execute (pname, args, outname, errname);
279    }
280
281    status
282    execute (const std::string&   pname,
283             const arg_container& args,
284             const std::string&   outname,
285             const std::string&   errname)
286    {
287      if (rld::verbose () >= RLD_VERBOSE_TRACE)
288      {
289        std::cout << "execute: ";
290        for (size_t a = 0; a < args.size (); ++a)
291          std::cout << args[a] << ' ';
292        std::cout << std::endl;
293      }
294
295      const char** cargs = new const char* [args.size () + 1];
296
297      for (size_t a = 0; a < args.size (); ++a)
298        cargs[a] = args[a].c_str ();
299      cargs[args.size ()] = 0;
300
301      int err = 0;
302      int s = 0;
303
304      const char* serr = pex_one (PEX_LAST | PEX_SEARCH,
305                                  args[0].c_str (),
306                                  (char* const*) cargs,
307                                  pname.c_str (),
308                                  outname.c_str (),
309                                  errname.c_str (),
310                                  &s,
311                                  &err);
312
313      delete [] cargs;
314
315      if (serr)
316        throw rld::error ("execute: " + args[0], serr);
317      else if (err)
318        throw rld::error ("execute: " + args[0], ::strerror (err));
319
320      status _status;
321
322      if (rld::verbose () >= RLD_VERBOSE_TRACE)
323        std::cout << "execute: status: ";
324
325      if (WIFEXITED (s))
326      {
327        _status.type = status::normal;
328        _status.code = WEXITSTATUS (s);
329        if (rld::verbose () >= RLD_VERBOSE_TRACE)
330          std::cout << _status.code << std::endl;
331      }
332      else if (WIFSIGNALED (s))
333      {
334        _status.type = status::signal;
335        _status.code = WTERMSIG (s);
336        if (rld::verbose () >= RLD_VERBOSE_TRACE)
337          std::cout << "signal: " << _status.code << std::endl;
338      }
339      else if (WIFSTOPPED (s))
340      {
341        _status.type = status::stopped;
342        _status.code = WSTOPSIG (s);
343        if (rld::verbose () >= RLD_VERBOSE_TRACE)
344          std::cout << "stopped: " << _status.code << std::endl;
345      }
346      else
347        throw rld::error ("execute: " + args[0], "unknown status returned");
348         
349      return _status;
350    }
351
352    /*
353     * The code is based on this C file:
354     *  http://cybertiggyr.com/pcm/src/parse.c
355     */
356    void
357    parse_command_line (const std::string& command, arg_container& args)
358    {
359      enum pstate
360      {
361        pstate_discard_space,
362        pstate_accumulate_quoted,
363        pstate_accumulate_raw
364      };
365
366      args.clear ();
367     
368      const char quote = '"';
369      const char escape = '\\';
370      pstate     state = pstate_discard_space;
371      size_t     start = 0;
372      size_t     i = 0;
373
374      while (i < command.size ())
375      {
376        switch (state)
377        {
378          case pstate_discard_space:
379            if (command[i] == quote)
380            {
381              ++i;
382              start = i;
383              state = pstate_accumulate_quoted;
384            }
385            else if (::isspace (command[i]))
386            {
387              ++i;
388            }
389            else /* includes escape */
390            {
391              start = i;
392              state = pstate_accumulate_raw;
393            }
394            break;
395
396          case pstate_accumulate_quoted:
397            if (command[i] == quote)
398            {
399              args.push_back (command.substr (start, i - 1));
400              ++i;
401              state = pstate_discard_space;
402            }
403            else if ((command[i] == escape) && (command[i + 1] == quote))
404            {
405              i += 2;
406            }
407            else /* includes space */
408            {
409              ++i;
410            }
411            break;
412
413          case pstate_accumulate_raw:
414            if (command[i] == quote)
415            {
416              throw rld::error ("quote in token", "command parse");
417            }
418            else if ((command[i] == escape) && (command[i + 1] == quote))
419            {
420              i += 2;
421            }
422            else if (::isspace (command[i]))
423            {
424              args.push_back (command.substr (start, i - 1));
425              ++i;
426              state = pstate_discard_space;
427            }
428            else
429            {
430              ++i;
431            }
432            break;
433        }
434      }
435    }
436  }
437}
Note: See TracBrowser for help on using the repository browser.