A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
system-path.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2008 INRIA
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
7 */
8#include "system-path.h"
9
10#include "assert.h"
12#include "fatal-error.h"
13#include "log.h"
14#include "string.h"
15
16#include <algorithm>
17#include <ctime>
18#include <filesystem>
19#include <regex>
20#include <sstream>
21#include <tuple>
22
23#ifdef __APPLE__
24#include <mach-o/dyld.h>
25#endif /* __APPLE__ */
26
27#ifdef __FreeBSD__
28#include <sys/sysctl.h>
29#include <sys/types.h>
30#endif
31
32#ifdef __linux__
33#include <cstring>
34#include <unistd.h>
35#endif
36
37#ifdef __WIN32__
38#define WIN32_LEAN_AND_MEAN
39#include <regex>
40#include <windows.h>
41#endif
42
43/**
44 * System-specific path separator used between directory names.
45 */
46#if defined(__WIN32__)
47constexpr auto SYSTEM_PATH_SEP = "\\";
48#else
49constexpr auto SYSTEM_PATH_SEP = "/";
50#endif
51
52/**
53 * @file
54 * @ingroup systempath
55 * ns3::SystemPath implementation.
56 */
57
58namespace ns3
59{
60
61NS_LOG_COMPONENT_DEFINE("SystemPath");
62
63// unnamed namespace for internal linkage
64namespace
65{
66/**
67 * @ingroup systempath
68 * Get the list of files located in a file system directory with error.
69 *
70 * @param [in] path A path which identifies a directory
71 * @return Tuple with a list of the filenames which are located in the input directory or error flag
72 * \c true if directory doesn't exist.
73 */
74std::tuple<std::list<std::string>, bool>
75ReadFilesNoThrow(std::string path)
76{
77 NS_LOG_FUNCTION(path);
78 std::list<std::string> files;
79 if (!std::filesystem::exists(path))
80 {
81 return std::make_tuple(files, true);
82 }
83 for (auto& it : std::filesystem::directory_iterator(path))
84 {
85 if (!std::filesystem::is_directory(it.path()))
86 {
87 files.push_back(it.path().filename().string());
88 }
89 }
90 return std::make_tuple(files, false);
91}
92
93} // unnamed namespace
94
95namespace SystemPath
96{
97
98/**
99 * @ingroup systempath
100 * @brief Get the directory path for a file.
101 *
102 * This is an internal function (by virtue of not being
103 * declared in a \c .h file); the public API is FindSelfDirectory().
104 *
105 * @param [in] path The full path to a file.
106 * @returns The full path to the containing directory.
107 */
108std::string
109Dirname(std::string path)
110{
111 NS_LOG_FUNCTION(path);
112 std::list<std::string> elements = Split(path);
113 auto last = elements.end();
114 last--;
115 return Join(elements.begin(), last);
116}
117
118std::string
120{
121 /**
122 * This function returns the path to the running $PREFIX.
123 * Mac OS X: _NSGetExecutablePath() (man 3 dyld)
124 * Linux: readlink /proc/self/exe
125 * Solaris: getexecname()
126 * FreeBSD: sysctl CTL_KERN KERN_PROC KERN_PROC_PATHNAME -1
127 * BSD with procfs: readlink /proc/curproc/file
128 * Windows: GetModuleFileName() with hModule = NULL
129 */
131 std::string filename;
132#if defined(__linux__)
133 {
134 ssize_t size = 1024;
135 char* buffer = (char*)malloc(size);
136 memset(buffer, 0, size);
137 int status;
138 while (true)
139 {
140 status = readlink("/proc/self/exe", buffer, size);
141 if (status != 1 || (status == -1 && errno != ENAMETOOLONG))
142 {
143 break;
144 }
145 size *= 2;
146 free(buffer);
147 buffer = (char*)malloc(size);
148 memset(buffer, 0, size);
149 }
150 if (status == -1)
151 {
152 NS_FATAL_ERROR("Oops, could not find self directory.");
153 }
154 filename = buffer;
155 free(buffer);
156 }
157#elif defined(__WIN32__)
158 {
159 // LPTSTR = char *
160 DWORD size = 1024;
161 auto lpFilename = (LPTSTR)malloc(sizeof(TCHAR) * size);
162 DWORD status = GetModuleFileName(nullptr, lpFilename, size);
163 while (status == size)
164 {
165 size = size * 2;
166 free(lpFilename);
167 lpFilename = (LPTSTR)malloc(sizeof(TCHAR) * size);
168 status = GetModuleFileName(nullptr, lpFilename, size);
169 }
170 NS_ASSERT(status != 0);
171 filename = lpFilename;
172 free(lpFilename);
173 }
174#elif defined(__APPLE__)
175 {
176 uint32_t bufsize = 1024;
177 char* buffer = (char*)malloc(bufsize);
178 NS_ASSERT(buffer);
179 int status = _NSGetExecutablePath(buffer, &bufsize);
180 if (status == -1)
181 {
182 free(buffer);
183 buffer = (char*)malloc(bufsize);
184 status = _NSGetExecutablePath(buffer, &bufsize);
185 }
186 NS_ASSERT(status == 0);
187 filename = buffer;
188 free(buffer);
189 }
190#elif defined(__FreeBSD__)
191 {
192 int mib[4];
193 std::size_t bufSize = 1024;
194 char* buf = (char*)malloc(bufSize);
195
196 mib[0] = CTL_KERN;
197 mib[1] = KERN_PROC;
198 mib[2] = KERN_PROC_PATHNAME;
199 mib[3] = -1;
200
201 sysctl(mib, 4, buf, &bufSize, nullptr, 0);
202 filename = buf;
203 }
204#endif
205 return filename;
206}
207
208std::string
210{
211 return Dirname(FindSelf());
212}
213
214std::string
215Append(std::string left, std::string right)
216{
217 // removing trailing separators from 'left'
218 NS_LOG_FUNCTION(left << right);
219 while (true)
220 {
221 std::string::size_type lastSep = left.rfind(SYSTEM_PATH_SEP);
222 if (lastSep != left.size() - 1)
223 {
224 break;
225 }
226 left = left.substr(0, left.size() - 1);
227 }
228 std::string retval = left + SYSTEM_PATH_SEP + right;
229 return retval;
230}
231
232std::list<std::string>
233Split(std::string path)
234{
235 NS_LOG_FUNCTION(path);
236 std::vector<std::string> items = SplitString(path, SYSTEM_PATH_SEP);
237 std::list<std::string> retval(items.begin(), items.end());
238 return retval;
239}
240
241std::string
242Join(std::list<std::string>::const_iterator begin, std::list<std::string>::const_iterator end)
243{
244 NS_LOG_FUNCTION(*begin << *end);
245 std::string retval = "";
246 for (auto i = begin; i != end; i++)
247 {
248 if ((*i).empty())
249 {
250 // skip empty strings in the path list
251 continue;
252 }
253 else if (i == begin)
254 {
255 retval = *i;
256 }
257 else
258 {
259 retval = retval + SYSTEM_PATH_SEP + *i;
260 }
261 }
262 return retval;
263}
264
265std::list<std::string>
266ReadFiles(std::string path)
267{
268 NS_LOG_FUNCTION(path);
269 bool err;
270 std::list<std::string> files;
271 std::tie(files, err) = ReadFilesNoThrow(path);
272 if (err)
273 {
274 NS_FATAL_ERROR("Could not open directory=" << path);
275 }
276 return files;
277}
278
279std::string
281{
283 auto [found, path] = EnvironmentVariable::Get("TMP");
284 if (!found)
285 {
286 std::tie(found, path) = EnvironmentVariable::Get("TEMP");
287 if (!found)
288 {
289 path = "/tmp";
290 }
291 }
292
293 //
294 // Just in case the user wants to go back and find the output, we give
295 // a hint as to which dir we created by including a time hint.
296 //
297 time_t now = time(nullptr);
298 struct tm* tm_now = localtime(&now);
299 //
300 // But we also randomize the name in case there are multiple users doing
301 // this at the same time
302 //
303 srand(time(nullptr));
304 long int n = rand();
305
306 //
307 // The final path to the directory is going to look something like
308 //
309 // /tmp/ns3.14.30.29.32767
310 //
311 // The first segment comes from one of the temporary directory env
312 // variables or /tmp if not found. The directory name starts with an
313 // identifier telling folks who is making all of the temp directories
314 // and then the local time (in this case 14.30.29 -- which is 2:30 and
315 // 29 seconds PM).
316 //
317 std::ostringstream oss;
318 oss << path << SYSTEM_PATH_SEP << "ns-3." << tm_now->tm_hour << "." << tm_now->tm_min << "."
319 << tm_now->tm_sec << "." << n;
320
321 return oss.str();
322}
323
324void
325MakeDirectories(std::string path)
326{
327 NS_LOG_FUNCTION(path);
328
329 std::error_code ec;
330 if (!std::filesystem::exists(path))
331 {
332 std::filesystem::create_directories(path, ec);
333 }
334
335 if (ec.value())
336 {
337 NS_FATAL_ERROR("failed creating directory " << path);
338 }
339}
340
341bool
342Exists(const std::string path)
343{
344 NS_LOG_FUNCTION(path);
345
346 bool err;
347 auto dirpath = Dirname(path);
348 std::list<std::string> files;
349 tie(files, err) = ReadFilesNoThrow(dirpath);
350 if (err)
351 {
352 // Directory doesn't exist
353 NS_LOG_LOGIC("directory doesn't exist: " << dirpath);
354 return false;
355 }
356 NS_LOG_LOGIC("directory exists: " << dirpath);
357
358 // Check if the file itself exists
359 auto tokens = Split(path);
360 const std::string& file = tokens.back();
361
362 if (file.empty())
363 {
364 // Last component was a directory, not a file name
365 // We already checked that the directory exists,
366 // so return true
367 NS_LOG_LOGIC("directory path exists: " << path);
368 return true;
369 }
370
371 files = ReadFiles(dirpath);
372
373 auto it = std::find(files.begin(), files.end(), file);
374 if (it == files.end())
375 {
376 // File itself doesn't exist
377 NS_LOG_LOGIC("file itself doesn't exist: " << file);
378 return false;
379 }
380
381 NS_LOG_LOGIC("file itself exists: " << file);
382 return true;
383}
384
385std::string
386CreateValidSystemPath(const std::string path)
387{
388 // Windows and its file systems, e.g. NTFS and (ex)FAT(12|16|32),
389 // do not like paths with empty spaces or special symbols.
390 // Some of these symbols are allowed in test names, checked in TestCase::AddTestCase.
391 // We replace them with underlines to ensure they work on Windows.
392 std::regex incompatible_characters(" |:[^\\\\]|<|>|\\*");
393 std::string valid_path;
394 std::regex_replace(std::back_inserter(valid_path),
395 path.begin(),
396 path.end(),
397 incompatible_characters,
398 "_");
399 return valid_path;
400}
401
402} // namespace SystemPath
403
404} // 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:55
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition log.h:274
#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.
bool Exists(const std::string path)
Check if a path exists.
std::list< std::string > Split(std::string path)
Split a file system path into directories according to the local path separator.
std::string Dirname(std::string path)
Get the directory path for a file.
std::string FindSelf()
Get the file system path to the current executable.
void MakeDirectories(std::string path)
Create all the directories leading to path.
std::string MakeTemporaryDirectoryName()
Get the name of a temporary directory.
std::string Append(std::string left, std::string right)
Join two file system path elements.
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.
std::string CreateValidSystemPath(const std::string path)
Replace incompatible characters in a path, to get a path compatible with different file systems.
std::tuple< std::list< std::string >, bool > ReadFilesNoThrow(std::string path)
Get the list of files located in a file system directory with error.
std::string FindSelfDirectory()
Get the file system path to the current executable.
Debug message logging.
Namespace for various file and directory path functions.
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:23
ns3::StringValue attribute value declarations.
constexpr auto SYSTEM_PATH_SEP
System-specific path separator used between directory names.
ns3::SystemPath declarations.