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
74namespace ns3 {
75
76NS_LOG_COMPONENT_DEFINE ("SystemPath");
77
78// unnamed namespace for internal linkage
79namespace {
87std::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
129namespace SystemPath {
130
141std::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
150std::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
241std::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
258std::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
276std::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
300std::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
313std::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
360void
361MakeDirectories (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
392bool
393Exists (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::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
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
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.