A Discrete-Event Network Simulator
API
system-path.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2008 INRIA
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License version 2 as
7  * published by the Free Software Foundation;
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 #include "system-path.h"
21 #include "fatal-error.h"
22 #include "assert.h"
23 #include "log.h"
24 #include "ns3/core-config.h"
25 
26 #include <algorithm>
27 #include <cstdlib> // getenv
28 #include <cerrno>
29 #include <cstring> // strlen
30 #include <tuple>
31 
32 #if defined (HAVE_DIRENT_H) && defined (HAVE_SYS_TYPES_H)
34 #define HAVE_OPENDIR
35 #include <sys/types.h>
36 #include <dirent.h>
37 #endif
38 #if defined (HAVE_SYS_STAT_H) && defined (HAVE_SYS_TYPES_H)
40 #define HAVE_MKDIR_H
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #endif
44 #include <sstream>
45 #ifdef __APPLE__
46 #include <mach-o/dyld.h>
47 #endif /* __APPLE__ */
48 
49 #ifdef __FreeBSD__
50 #include <sys/types.h>
51 #include <sys/sysctl.h>
52 #endif
53 
54 #ifdef __linux__
55 #include <unistd.h>
56 #endif
57 
62 #if defined (__win32__)
63 #define SYSTEM_PATH_SEP "\\"
64 #else
65 #define SYSTEM_PATH_SEP "/"
66 #endif
67 
74 namespace ns3 {
75 
76 NS_LOG_COMPONENT_DEFINE ("SystemPath");
77 
78 // unnamed namespace for internal linkage
79 namespace {
87 std::tuple<std::list<std::string>, bool> ReadFilesNoThrow (std::string path)
88 {
89  NS_LOG_FUNCTION (path);
90  std::list<std::string> files;
91 
92 #if defined HAVE_OPENDIR
93  DIR *dp = opendir (path.c_str ());
94  if (dp == NULL)
95  {
96  return std::make_tuple (files, true);
97  }
98  struct dirent *de = readdir (dp);
99  while (de != 0)
100  {
101  files.push_back (de->d_name);
102  de = readdir (dp);
103  }
104  closedir (dp);
105 #elif defined (HAVE_FIND_FIRST_FILE)
107  HANDLE hFind;
108  WIN32_FIND_DATA fileData;
109 
110  hFind = FindFirstFile (path.c_str (), &FindFileData);
111  if (hFind == INVALID_HANDLE_VALUE)
112  {
113  return std::make_tuple (files, true);
114  }
115  do
116  {
117  files.push_back (fileData.cFileName);
118  }
119  while (FindNextFile (hFind, &fileData));
120  FindClose (hFind);
121 #else
122 #error "No support for reading a directory on this platform"
123 #endif
124  return std::make_tuple (files, false);
125 }
126 
127 } // unnamed namespace
128 
129 namespace SystemPath {
130 
141 std::string Dirname (std::string path)
142 {
143  NS_LOG_FUNCTION (path);
144  std::list<std::string> elements = Split (path);
145  std::list<std::string>::const_iterator last = elements.end ();
146  last--;
147  return Join (elements.begin (), last);
148 }
149 
150 std::string FindSelfDirectory (void)
151 {
162  std::string filename;
163 #if defined(__linux__)
164  {
165  ssize_t size = 1024;
166  char *buffer = (char*)malloc (size);
167  memset (buffer, 0, size);
168  int status;
169  while (true)
170  {
171  status = readlink ("/proc/self/exe", buffer, size);
172  if (status != 1 || (status == -1 && errno != ENAMETOOLONG))
173  {
174  break;
175  }
176  size *= 2;
177  free (buffer);
178  buffer = (char*)malloc (size);
179  memset (buffer, 0, size);
180  }
181  if (status == -1)
182  {
183  NS_FATAL_ERROR ("Oops, could not find self directory.");
184  }
185  filename = buffer;
186  free (buffer);
187  }
188 #elif defined (__win32__)
189  {
193  DWORD size = 1024;
194  LPTSTR lpFilename = (LPTSTR) malloc (sizeof(TCHAR) * size);
195  DWORD status = GetModuleFilename (0, lpFilename, size);
196  while (status == size)
197  {
198  size = size * 2;
199  free (lpFilename);
200  lpFilename = (LPTSTR) malloc (sizeof(TCHAR) * size);
201  status = GetModuleFilename (0, lpFilename, size);
202  }
203  NS_ASSERT (status != 0);
204  filename = lpFilename;
205  free (lpFilename);
206  }
207 #elif defined (__APPLE__)
208  {
209  uint32_t bufsize = 1024;
210  char *buffer = (char *) malloc (bufsize);
211  NS_ASSERT (buffer != 0);
212  int status = _NSGetExecutablePath (buffer, &bufsize);
213  if (status == -1)
214  {
215  free (buffer);
216  buffer = (char *) malloc (bufsize);
217  status = _NSGetExecutablePath (buffer, &bufsize);
218  }
219  NS_ASSERT (status == 0);
220  filename = buffer;
221  free (buffer);
222  }
223 #elif defined (__FreeBSD__)
224  {
225  int mib[4];
226  std::size_t bufSize = 1024;
227  char *buf = (char *) malloc (bufSize);
228 
229  mib[0] = CTL_KERN;
230  mib[1] = KERN_PROC;
231  mib[2] = KERN_PROC_PATHNAME;
232  mib[3] = -1;
233 
234  sysctl (mib, 4, buf, &bufSize, NULL, 0);
235  filename = buf;
236  }
237 #endif
238  return Dirname (filename);
239 }
240 
241 std::string Append (std::string left, std::string right)
242 {
243  // removing trailing separators from 'left'
244  NS_LOG_FUNCTION (left << right);
245  while (true)
246  {
247  std::string::size_type lastSep = left.rfind (SYSTEM_PATH_SEP);
248  if (lastSep != left.size () - 1)
249  {
250  break;
251  }
252  left = left.substr (0, left.size () - 1);
253  }
254  std::string retval = left + SYSTEM_PATH_SEP + right;
255  return retval;
256 }
257 
258 std::list<std::string> Split (std::string path)
259 {
260  NS_LOG_FUNCTION (path);
261  std::list<std::string> retval;
262  std::string::size_type current = 0, next = 0;
263  next = path.find (SYSTEM_PATH_SEP, current);
264  while (next != std::string::npos)
265  {
266  std::string item = path.substr (current, next - current);
267  retval.push_back (item);
268  current = next + 1;
269  next = path.find (SYSTEM_PATH_SEP, current);
270  }
271  std::string item = path.substr (current, next - current);
272  retval.push_back (item);
273  return retval;
274 }
275 
276 std::string Join (std::list<std::string>::const_iterator begin,
277  std::list<std::string>::const_iterator end)
278 {
279  NS_LOG_FUNCTION (*begin << *end);
280  std::string retval = "";
281  for (std::list<std::string>::const_iterator i = begin; i != end; i++)
282  {
283  if (*i == "")
284  {
285  // skip empty strings in the path list
286  continue;
287  }
288  else if (i == begin)
289  {
290  retval = *i;
291  }
292  else
293  {
294  retval = retval + SYSTEM_PATH_SEP + *i;
295  }
296  }
297  return retval;
298 }
299 
300 std::list<std::string> ReadFiles (std::string path)
301 {
302  NS_LOG_FUNCTION (path);
303  bool err;
304  std::list<std::string> files;
305  std::tie (files, err) = ReadFilesNoThrow (path);
306  if (err)
307  {
308  NS_FATAL_ERROR ("Could not open directory=" << path);
309  }
310  return files;
311 }
312 
313 std::string
315 {
317  char *path = NULL;
318 
319  path = std::getenv ("TMP");
320  if (path == NULL || std::strlen (path) == 0)
321  {
322  path = std::getenv ("TEMP");
323  if (path == NULL || std::strlen (path) == 0)
324  {
325  path = const_cast<char *> ("/tmp");
326  }
327  }
328 
329  //
330  // Just in case the user wants to go back and find the output, we give
331  // a hint as to which dir we created by including a time hint.
332  //
333  time_t now = time (NULL);
334  struct tm *tm_now = localtime (&now);
335  //
336  // But we also randomize the name in case there are multiple users doing
337  // this at the same time
338  //
339  srand (time (0));
340  long int n = rand ();
341 
342  //
343  // The final path to the directory is going to look something like
344  //
345  // /tmp/ns3.14.30.29.32767
346  //
347  // The first segment comes from one of the temporary directory env
348  // variables or /tmp if not found. The directory name starts with an
349  // identifier telling folks who is making all of the temp directories
350  // and then the local time (in this case 14.30.29 -- which is 2:30 and
351  // 29 seconds PM).
352  //
353  std::ostringstream oss;
354  oss << path << SYSTEM_PATH_SEP << "ns-3." << tm_now->tm_hour << "."
355  << tm_now->tm_min << "." << tm_now->tm_sec << "." << n;
356 
357  return oss.str ();
358 }
359 
360 void
361 MakeDirectories (std::string path)
362 {
363  NS_LOG_FUNCTION (path);
364 
365  // Make sure all directories on the path exist
366  std::list<std::string> elements = Split (path);
367  auto i = elements.begin ();
368  while (i != elements.end ())
369  {
370  if (*i == "")
371  {
372  NS_LOG_LOGIC ("skipping empty directory name");
373  ++i;
374  continue;
375  }
376  NS_LOG_LOGIC ("creating directory " << *i);
377  ++i; // Now points to one past the directory we want to create
378  std::string tmp = Join (elements.begin (), i);
379  bool makeDirErr = false;
380 
381 #if defined(HAVE_MKDIR_H)
382  makeDirErr = mkdir (tmp.c_str (), S_IRWXU);
383 #endif
384 
385  if (makeDirErr)
386  {
387  NS_LOG_ERROR ("failed creating directory " << tmp);
388  }
389  }
390 }
391 
392 bool
393 Exists (const std::string path)
394 {
395  NS_LOG_FUNCTION (path);
396 
397  bool err;
398  auto dirpath = Dirname (path);
399  std::list<std::string> files;
400  tie (files, err) = ReadFilesNoThrow (dirpath);
401  if (err)
402  {
403  // Directory doesn't exist
404  NS_LOG_LOGIC ("directory doesn't exist: " << dirpath);
405  return false;
406  }
407  NS_LOG_LOGIC ("directory exists: " << dirpath);
408 
409  // Check if the file itself exists
410  auto tokens = Split (path);
411  std::string file = tokens.back ();
412 
413  if (file == "")
414  {
415  // Last component was a directory, not a file name
416  // We already checked that the directory exists,
417  // so return true
418  NS_LOG_LOGIC ("directory path exists: " << path);
419  return true;
420  }
421 
422  files = ReadFiles (dirpath);
423 
424  auto it = std::find (files.begin (), files.end (), file);
425  if (it == files.end ())
426  {
427  // File itself doesn't exist
428  NS_LOG_LOGIC ("file itself doesn't exist: " << file);
429  return false;
430  }
431 
432  NS_LOG_LOGIC ("file itself exists: " << file);
433  return true;
434 
435 } // Exists()
436 
437 
438 } // namespace SystemPath
439 
440 } // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
NS_FATAL_x macro definitions.
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:67
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:165
#define NS_LOG_ERROR(msg)
Use NS_LOG to output a message of level LOG_ERROR.
Definition: log.h:257
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:205
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:289
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
std::list< std::string > ReadFiles(std::string path)
Get the list of files located in a file system directory.
Definition: system-path.cc:300
std::string MakeTemporaryDirectoryName(void)
Get the name of a temporary directory.
Definition: system-path.cc:314
bool Exists(const std::string path)
Check if a path exists.
Definition: system-path.cc:393
std::tuple< std::list< std::string >, bool > ReadFilesNoThrow(std::string path)
Get the list of files located in a file system directory with error.
Definition: system-path.cc:87
std::list< std::string > Split(std::string path)
Split a file system path into directories according to the local path separator.
Definition: system-path.cc:258
std::string Dirname(std::string path)
Get the directory path for a file.
Definition: system-path.cc:141
void MakeDirectories(std::string path)
Create all the directories leading to path.
Definition: system-path.cc:361
std::string Append(std::string left, std::string right)
Join two file system path elements.
Definition: system-path.cc:241
std::string Join(std::list< std::string >::const_iterator begin, std::list< std::string >::const_iterator end)
Join a list of file system path directories into a single file system path.
Definition: system-path.cc:276
std::string FindSelfDirectory(void)
Get the file system path to the current executable.
Definition: system-path.cc:150
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
#define SYSTEM_PATH_SEP
System-specific path separator used between directory names.
Definition: system-path.cc:65
ns3::SystemPath declarations.