ns-3 Direct Code Execution
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
elf-dependencies.cc
Go to the documentation of this file.
1 #include "elf-dependencies.h"
2 #include "elf-ldd.h"
3 #include "ns3/log.h"
4 #include "ns3/assert.h"
5 #include <string.h>
6 #include <errno.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <sys/wait.h>
10 #include <unistd.h>
11 #include <algorithm>
12 #include <stdio.h>
13 #include <sstream>
14 #include <unistd.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 
19 namespace ns3 {
20 
21 NS_LOG_COMPONENT_DEFINE ("ElfDependencies");
22 
23 ElfDependencies::ElfDependencies (std::string filename)
24 {
25  std::string fullname;
26  bool found;
27  found = SearchFile (filename, &fullname);
28  NS_ASSERT (found);
29  if (getenv ("OLDDEP"))
30  {
31  m_deps = GatherDependencies (fullname);
32  std::reverse (m_deps.begin (), m_deps.end ());
33  struct Dependency dependency;
34  dependency.required = filename;
35  dependency.found = fullname;
36  m_deps.push_back (dependency);
37  }
38  else
39  {
40  m_deps = NewGather (filename, fullname);
41  struct Dependency dependency;
42  dependency.required = filename;
43  dependency.found = fullname;
44  m_deps.push_back (dependency);
45  }
46 }
47 
48 std::vector<struct ElfDependencies::Dependency>
49 ElfDependencies::NewGather (std::string sName, std::string fullname) const
50 {
51  std::vector<struct Dependency> res;
52  ElfLdd tool (sName, fullname);
53  std::vector<struct Dependency> tm = tool.GetDeps ();
54 
55  for (Iterator i = tool.Begin ();
56  i != tool.End (); ++i)
57  {
58  std::string depname = (*i).required;
59 
60  if (depname == "linux-gate.so.1"
61  || depname == "ld-linux.so.2"
62  || depname == "ld-linux-x86-64.so.2"
63  || depname == "/lib/ld-linux.so.2"
64  || depname == "/lib64/ld-linux-x86-64.so.2"
65  || depname == "/usr/lib/debug/ld-linux-x86-64.so.2"
66  || depname == "linux-vdso.so.1")
67  {
68  // IGNORE
69  }
70  else
71  {
72  res.push_back (*i);
73  }
74  }
75  return res;
76 }
77 
78 std::vector<struct ElfDependencies::Dependency>
79 ElfDependencies::GatherDependencies (std::string fullname) const
80 {
81  NS_LOG_FUNCTION (this << fullname);
82  /* We gather the dependencies for the input file using the 'ldd' program.
83  * To do this, we do a standard fork+exec and forward the output of ldd
84  * to the parent through a pipe which is then parsed in the parent.
85  */
86  std::vector<struct Dependency> dependencies;
87 
88  std::ostringstream tmpFile;
89  tmpFile << "/tmp/deps_" << getpid ();
90  std::ostringstream lddCmd;
91  lddCmd << "/usr/bin/ldd "
92  << fullname
93  << " > " << tmpFile.str ();
94  int ret = system (lddCmd.str ().c_str ());
95  if (ret == -1)
96  {
97  NS_LOG_ERROR (lddCmd << " failed");
98  return dependencies;
99  }
100 
101  int depsFd = open (tmpFile.str ().c_str (), O_RDONLY);
102  if (depsFd == -1)
103  {
104  NS_LOG_ERROR (tmpFile.str () << " doesn't exist");
105  return dependencies;
106  }
107 
108  std::string lddOutput;
109  uint8_t c;
110  ssize_t bytesRead = ::read (depsFd, &c, 1);
111  while (bytesRead == 1)
112  {
113  lddOutput.push_back (c);
114  bytesRead = ::read (depsFd, &c, 1);
115  }
116  close (depsFd);
117  NS_LOG_DEBUG ("line=" << lddOutput << ", " << (int)lddOutput[0]);
118 
119  std::string::size_type cur = 0;
120  while (true)
121  {
122  std::string::size_type dep_start = lddOutput.find_first_not_of (" \t", cur);
123  std::string::size_type next_line = lddOutput.find ("\n", cur);
124  std::string::size_type dep_end = lddOutput.find (" ", dep_start);
125  std::string::size_type full_start = lddOutput.find_first_of (">", dep_end);
126 
127  full_start = lddOutput.find_first_not_of (" \t", full_start + 1);
128  std::string::size_type full_end = lddOutput.find_first_of (" \n", full_start);
129  NS_LOG_DEBUG ("dep_start=" << (int)dep_start << " dep_end=" << (int)dep_end
130  << " full_start=" << (int)full_start << " full_end=" << (int)full_end
131  << " next_line=" << (int)next_line << " cur=" << (int)cur);
132  if (dep_start != std::string::npos
133  && full_start != std::string::npos
134  && next_line != std::string::npos
135  && dep_start < next_line
136  && dep_end < next_line
137  && full_start <= next_line
138  && full_start > dep_start)
139  {
140  std::string depname = lddOutput.substr (dep_start, dep_end - dep_start);
141  std::string fulldepname = lddOutput.substr (full_start, full_end - (full_start));
142  NS_LOG_DEBUG (depname << "->" << fulldepname);
143  if (depname == "linux-gate.so.1"
144  || depname == "ld-linux.so.2"
145  || depname == "ld-linux-x86-64.so.2"
146  || depname == "/lib/ld-linux.so.2"
147  || depname == "/lib64/ld-linux-x86-64.so.2"
148  || depname == "/usr/lib/debug/ld-linux-x86-64.so.2"
149  || depname == "linux-vdso.so.1")
150  {
151  goto next;
152  }
153  else
154  {
155  struct Dependency dependency;
156  dependency.required = depname;
157  dependency.found = fulldepname;
158  dependencies.push_back (dependency);
159  }
160  }
161  else
162  {
163  if (next_line == std::string::npos)
164  {
165  break;
166  }
167  else
168  {
169  full_start = next_line - 1;
170  }
171  }
172 next:
173  cur = lddOutput.find_first_of ("\n", full_start);
174  if (cur != std::string::npos)
175  {
176  cur++;
177  }
178  else
179  {
180  break;
181  }
182  }
183 
184  return dependencies;
185 }
186 
187 
188 std::list<std::string>
189 ElfDependencies::Split (std::string input, std::string sep) const
190 {
191  NS_LOG_FUNCTION (this << input << sep);
192  std::list<std::string> retval;
193  std::string::size_type cur = 0, next;
194  while (true)
195  {
196  next = input.find (sep, cur);
197  if (next == cur)
198  {
199  cur++;
200  continue;
201  }
202  else if (next == std::string::npos)
203  {
204  if (input.size () != cur)
205  {
206  retval.push_back (input.substr (cur, input.size () - cur));
207  }
208  break;
209  }
210  retval.push_back (input.substr (cur, next - cur));
211  cur = next + 1;
212  }
213  return retval;
214 }
215 
216 std::list<std::string>
218 {
219  NS_LOG_FUNCTION (this);
220  std::list<std::string> directories;
221  char *ldLibraryPath = getenv ("LD_LIBRARY_PATH");
222  if (ldLibraryPath != 0)
223  {
224  std::list<std::string> tmp = Split (ldLibraryPath, ":");
225  directories.insert (directories.end (),
226  tmp.begin (),
227  tmp.end ());
228  }
229  char *path = getenv ("PATH");
230  if (path != 0)
231  {
232  std::list<std::string> tmp = Split (path, ":");
233  directories.insert (directories.end (),
234  tmp.begin (),
235  tmp.end ());
236  }
237  directories.push_back ("/lib");
238  directories.push_back ("/usr/lib");
239  directories.push_back (".");
240  return directories;
241 }
242 
243 bool
244 ElfDependencies::Exists (std::string filename) const
245 {
246  //NS_LOG_FUNCTION (this << filename);
247  struct stat st;
248  int retval = ::stat (filename.c_str (), &st);
249  return retval == 0;
250 }
251 
252 bool
253 ElfDependencies::SearchFile (std::string filename, std::string *fullname) const
254 {
255  NS_LOG_FUNCTION (this << filename);
256  if (Exists (filename))
257  {
258  *fullname = filename;
259  NS_LOG_DEBUG ("Found: " << filename << " as " << *fullname);
260  return true;
261  }
262  std::list<std::string> dirs = GetSearchDirectories ();
263  for (std::list<std::string>::const_iterator i = dirs.begin (); i != dirs.end (); i++)
264  {
265  if (Exists (*i + "/" + filename))
266  {
267  *fullname = *i + "/" + filename;
268  NS_LOG_DEBUG ("Found: " << filename << " as " << *fullname);
269  return true;
270  }
271  }
272  return false;
273 }
274 
275 
278 {
279  return m_deps.begin ();
280 }
281 
284 {
285  return m_deps.end ();
286 }
287 
288 
289 } // namespace ns3