A Discrete-Event Network Simulator
QKDNetSim v2.0 (NS-3 v3.41) @ (+)
API
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
system-path.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2008 INRIA
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
18  */
19 #include "system-path.h"
20 
21 #include "assert.h"
22 #include "environment-variable.h"
23 #include "fatal-error.h"
24 #include "log.h"
25 #include "string.h"
26 
27 #include <algorithm>
28 #include <ctime>
29 #include <regex>
30 #include <sstream>
31 #include <tuple>
32 
33 // Some compilers such as GCC < 8 (Ubuntu 18.04
34 // ships with GCC 7) do not ship with the
35 // std::filesystem header, but with the
36 // std::experimental::filesystem header.
37 // Since Clang reuses these headers and the libstdc++
38 // from GCC, we need to either use the experimental
39 // version or require a more up-to-date GCC.
40 // we use the "fs" namespace to prevent collisions
41 // with musl libc.
42 #ifdef __has_include
43 #if __has_include(<filesystem>)
44 #include <filesystem>
45 namespace fs = std::filesystem;
46 #elif __has_include(<experimental/filesystem>)
47 #include <experimental/filesystem>
48 namespace fs = std::experimental::filesystem;
49 #else
50 #error "No support for filesystem library"
51 #endif
52 #endif
53 
54 #ifdef __APPLE__
55 #include <mach-o/dyld.h>
56 #endif /* __APPLE__ */
57 
58 #ifdef __FreeBSD__
59 #include <sys/sysctl.h>
60 #include <sys/types.h>
61 #endif
62 
63 #ifdef __linux__
64 #include <cstring>
65 #include <unistd.h>
66 #endif
67 
68 #ifdef __WIN32__
69 #define WIN32_LEAN_AND_MEAN
70 #include <regex>
71 #include <windows.h>
72 #endif
73 
77 #if defined(__WIN32__)
78 constexpr auto SYSTEM_PATH_SEP = "\\";
79 #else
80 constexpr auto SYSTEM_PATH_SEP = "/";
81 #endif
82 
89 namespace ns3
90 {
91 
92 NS_LOG_COMPONENT_DEFINE("SystemPath");
93 
94 // unnamed namespace for internal linkage
95 namespace
96 {
105 std::tuple<std::list<std::string>, bool>
106 ReadFilesNoThrow(std::string path)
107 {
108  NS_LOG_FUNCTION(path);
109  std::list<std::string> files;
110  if (!fs::exists(path))
111  {
112  return std::make_tuple(files, true);
113  }
114  for (auto& it : fs::directory_iterator(path))
115  {
116  if (!fs::is_directory(it.path()))
117  {
118  files.push_back(it.path().filename().string());
119  }
120  }
121  return std::make_tuple(files, false);
122 }
123 
124 } // unnamed namespace
125 
126 namespace SystemPath
127 {
128 
139 std::string
140 Dirname(std::string path)
141 {
142  NS_LOG_FUNCTION(path);
143  std::list<std::string> elements = Split(path);
144  auto last = elements.end();
145  last--;
146  return Join(elements.begin(), last);
147 }
148 
149 std::string
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  {
190  // LPTSTR = char *
191  DWORD size = 1024;
192  LPTSTR lpFilename = (LPTSTR)malloc(sizeof(TCHAR) * size);
193  DWORD status = GetModuleFileName(nullptr, lpFilename, size);
194  while (status == size)
195  {
196  size = size * 2;
197  free(lpFilename);
198  lpFilename = (LPTSTR)malloc(sizeof(TCHAR) * size);
199  status = GetModuleFileName(nullptr, lpFilename, size);
200  }
201  NS_ASSERT(status != 0);
202  filename = lpFilename;
203  free(lpFilename);
204  }
205 #elif defined(__APPLE__)
206  {
207  uint32_t bufsize = 1024;
208  char* buffer = (char*)malloc(bufsize);
209  NS_ASSERT(buffer);
210  int status = _NSGetExecutablePath(buffer, &bufsize);
211  if (status == -1)
212  {
213  free(buffer);
214  buffer = (char*)malloc(bufsize);
215  status = _NSGetExecutablePath(buffer, &bufsize);
216  }
217  NS_ASSERT(status == 0);
218  filename = buffer;
219  free(buffer);
220  }
221 #elif defined(__FreeBSD__)
222  {
223  int mib[4];
224  std::size_t bufSize = 1024;
225  char* buf = (char*)malloc(bufSize);
226 
227  mib[0] = CTL_KERN;
228  mib[1] = KERN_PROC;
229  mib[2] = KERN_PROC_PATHNAME;
230  mib[3] = -1;
231 
232  sysctl(mib, 4, buf, &bufSize, nullptr, 0);
233  filename = buf;
234  }
235 #endif
236  return Dirname(filename);
237 }
238 
239 std::string
240 Append(std::string left, std::string right)
241 {
242  // removing trailing separators from 'left'
243  NS_LOG_FUNCTION(left << right);
244  while (true)
245  {
246  std::string::size_type lastSep = left.rfind(SYSTEM_PATH_SEP);
247  if (lastSep != left.size() - 1)
248  {
249  break;
250  }
251  left = left.substr(0, left.size() - 1);
252  }
253  std::string retval = left + SYSTEM_PATH_SEP + right;
254  return retval;
255 }
256 
257 std::list<std::string>
258 Split(std::string path)
259 {
260  NS_LOG_FUNCTION(path);
261  std::vector<std::string> items = SplitString(path, SYSTEM_PATH_SEP);
262  std::list<std::string> retval(items.begin(), items.end());
263  return retval;
264 }
265 
266 std::string
267 Join(std::list<std::string>::const_iterator begin, std::list<std::string>::const_iterator end)
268 {
269  NS_LOG_FUNCTION(*begin << *end);
270  std::string retval = "";
271  for (auto i = begin; i != end; i++)
272  {
273  if ((*i).empty())
274  {
275  // skip empty strings in the path list
276  continue;
277  }
278  else if (i == begin)
279  {
280  retval = *i;
281  }
282  else
283  {
284  retval = retval + SYSTEM_PATH_SEP + *i;
285  }
286  }
287  return retval;
288 }
289 
290 std::list<std::string>
291 ReadFiles(std::string path)
292 {
293  NS_LOG_FUNCTION(path);
294  bool err;
295  std::list<std::string> files;
296  std::tie(files, err) = ReadFilesNoThrow(path);
297  if (err)
298  {
299  NS_FATAL_ERROR("Could not open directory=" << path);
300  }
301  return files;
302 }
303 
304 std::string
306 {
308  auto [found, path] = EnvironmentVariable::Get("TMP");
309  if (!found)
310  {
311  std::tie(found, path) = EnvironmentVariable::Get("TEMP");
312  if (!found)
313  {
314  path = "/tmp";
315  }
316  }
317 
318  //
319  // Just in case the user wants to go back and find the output, we give
320  // a hint as to which dir we created by including a time hint.
321  //
322  time_t now = time(nullptr);
323  struct tm* tm_now = localtime(&now);
324  //
325  // But we also randomize the name in case there are multiple users doing
326  // this at the same time
327  //
328  srand(time(nullptr));
329  long int n = rand();
330 
331  //
332  // The final path to the directory is going to look something like
333  //
334  // /tmp/ns3.14.30.29.32767
335  //
336  // The first segment comes from one of the temporary directory env
337  // variables or /tmp if not found. The directory name starts with an
338  // identifier telling folks who is making all of the temp directories
339  // and then the local time (in this case 14.30.29 -- which is 2:30 and
340  // 29 seconds PM).
341  //
342  std::ostringstream oss;
343  oss << path << SYSTEM_PATH_SEP << "ns-3." << tm_now->tm_hour << "." << tm_now->tm_min << "."
344  << tm_now->tm_sec << "." << n;
345 
346  return oss.str();
347 }
348 
349 void
350 MakeDirectories(std::string path)
351 {
352  NS_LOG_FUNCTION(path);
353 
354  std::error_code ec;
355  if (!fs::exists(path))
356  {
357  fs::create_directories(path, ec);
358  }
359 
360  if (ec.value())
361  {
362  NS_FATAL_ERROR("failed creating directory " << path);
363  }
364 }
365 
366 bool
367 Exists(const std::string path)
368 {
369  NS_LOG_FUNCTION(path);
370 
371  bool err;
372  auto dirpath = Dirname(path);
373  std::list<std::string> files;
374  tie(files, err) = ReadFilesNoThrow(dirpath);
375  if (err)
376  {
377  // Directory doesn't exist
378  NS_LOG_LOGIC("directory doesn't exist: " << dirpath);
379  return false;
380  }
381  NS_LOG_LOGIC("directory exists: " << dirpath);
382 
383  // Check if the file itself exists
384  auto tokens = Split(path);
385  std::string file = tokens.back();
386 
387  if (file.empty())
388  {
389  // Last component was a directory, not a file name
390  // We already checked that the directory exists,
391  // so return true
392  NS_LOG_LOGIC("directory path exists: " << path);
393  return true;
394  }
395 
396  files = ReadFiles(dirpath);
397 
398  auto it = std::find(files.begin(), files.end(), file);
399  if (it == files.end())
400  {
401  // File itself doesn't exist
402  NS_LOG_LOGIC("file itself doesn't exist: " << file);
403  return false;
404  }
405 
406  NS_LOG_LOGIC("file itself exists: " << file);
407  return true;
408 
409 } // Exists()
410 
411 std::string
412 CreateValidSystemPath(const std::string path)
413 {
414  // Windows and its file systems, e.g. NTFS and (ex)FAT(12|16|32),
415  // do not like paths with empty spaces or special symbols.
416  // Some of these symbols are allowed in test names, checked in TestCase::AddTestCase.
417  // We replace them with underlines to ensure they work on Windows.
418  std::regex incompatible_characters(" |:[^\\\\]|<|>|\\*");
419  std::string valid_path;
420  std::regex_replace(std::back_inserter(valid_path),
421  path.begin(),
422  path.end(),
423  incompatible_characters,
424  "_");
425  return valid_path;
426 } // CreateValidSystemPath
427 
428 } // namespace SystemPath
429 
430 } // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
static KeyFoundType Get(const std::string &envvar, const std::string &key="", const std::string &delim=";")
Get the value corresponding to a key from an environment variable.
Class Environment declaration.
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:66
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:282
#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:291
bool Exists(const std::string path)
Check if a path exists.
Definition: system-path.cc:367
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:106
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:140
void MakeDirectories(std::string path)
Create all the directories leading to path.
Definition: system-path.cc:350
std::string MakeTemporaryDirectoryName()
Get the name of a temporary directory.
Definition: system-path.cc:305
std::string Append(std::string left, std::string right)
Join two file system path elements.
Definition: system-path.cc:240
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:267
std::string CreateValidSystemPath(const std::string path)
Replace incompatible characters in a path, to get a path compatible with different file systems.
Definition: system-path.cc:412
std::string FindSelfDirectory()
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.
StringVector SplitString(const std::string &str, const std::string &delim)
Split a string on a delimiter.
Definition: string.cc:34
ns3::StringValue attribute value declarations.
constexpr auto SYSTEM_PATH_SEP
System-specific path separator used between directory names.
Definition: system-path.cc:80
ns3::SystemPath declarations.