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