1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #include "SysUtils.hpp"
10 #include <sstream>
11 #include <fstream>
12 #include <sys/stat.h>
13 #include "Probe/Assertion.h"
14 
15 using namespace std;
16 
17 #ifndef S_ISDIR
18 #define S_ISDIR(flags) (((flags)&S_IFDIR)==S_IFDIR)
19 #endif
20 
21 namespace IGC
22 {
23     namespace SysUtils
24     {
25         //implementation details
26         namespace
27         {
28             template <typename T>
MakeStrImpl(ostream & ss,T const & t)29             inline void MakeStrImpl(ostream& ss, T const& t)
30             {
31                 ss << t;
32             }
33 
34             template <typename T1, typename... T>
MakeStrImpl(ostream & ss,T1 const & t1,T const &...args)35             inline void MakeStrImpl(ostream& ss, T1 const& t1, T const&... args)
36             {
37                 MakeStrImpl(ss << t1, args...);
38             }
39         }
40 
41         //makes single string from args, using stringstream
42         template <typename... T>
MakeStr(T const &...args)43         string MakeStr(T const&... args)
44         {
45             if (sizeof...(args) == 0) // MakeStr() == ""
46                 return "";
47 
48             stringstream ss;
49             MakeStrImpl(ss, args...); //see functions above
50             return ss.str();
51         }
52 
GetProcessName()53         string GetProcessName()
54         {
55             string ret;
56 
57 #if defined (__linux__)
58             ifstream in(MakeStr("/proc/", getpid(), "/cmdline"), ios::in);
59             IGC_ASSERT_MESSAGE(in.is_open(), "Can not open cmdline pseudo file for current process");
60 
61             //in cmdline arguments are separated with \0
62             getline(in, ret, '\0');
63             IGC_ASSERT_MESSAGE(in.good(), "Error reading from cmdline pseudo file");
64 
65 #elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
66       defined(__OpenBSD__) || defined(__sun)
67             // KERN_PROC_ARGS returns similar value to /proc/<pid>/cmdline but as
68             // neither invocation path nor arguments are used just ask libc
69             ret = getprogname();
70 #elif defined(_WIN64) || defined(_WIN32)
71             ret.resize(MAX_PATH);
72             DWORD size = ::GetModuleFileNameA(NULL, &ret[0], ret.size());
73             IGC_ASSERT_MESSAGE(size < ret.size(), "Windows path can have MAX_PATH characters max");
74             ret.resize(size);
75 #else
76             ret = "unknownProcess";
77 #endif
78 
79             auto pos = ret.rfind('/');
80             if (pos != ret.npos)
81                 ret = ret.substr(pos + 1);
82             return ret;
83         }
84 
CreateDir(string basedir,bool addprocessdir,bool addpid,string * full_path)85         bool CreateDir(string basedir, bool addprocessdir, bool addpid, string* full_path)
86         {
87             UnifyDirSeparators(basedir);
88 
89             if (addprocessdir)
90             {
91                 if (!basedir.empty() && basedir.back() != '/')
92                     basedir.push_back('/');
93 
94                 basedir += GetProcessName();
95 
96                 if (addpid)
97                     basedir += MakeStr("_", GetProcessId());
98             }
99 
100             if (basedir.empty())
101             {
102                 if (full_path != nullptr)
103                     *full_path = "";
104                 return true;
105             }
106 
107             if (basedir.back() != '/')
108                 basedir.push_back('/');
109 
110             struct stat statbuf;
111 
112 #ifdef _WIN32
113             auto pos = basedir.find('/', (basedir.size() > 2 && basedir[1] == ':') ? 3 : 0); //on windows, ignore drive letter
114 #else
115             auto pos = basedir.find('/', (basedir[0] == '/' ? 1 : 0)); //on linux, ignore root /
116 #endif
117 
118             while (pos != basedir.npos)
119             {
120                 basedir[pos] = 0;
121 
122                 if (stat(basedir.data(), &statbuf) != 0) //dir doesnt exist
123                 {
124                     if (!CreateSingleDir(basedir.data())) //couldn't create
125                         return false;
126                 }
127                 else if (!S_ISDIR(statbuf.st_mode)) //exists but isnt dir
128                     return false;
129 
130                 basedir[pos] = '/';
131                 pos = basedir.find('/', pos + 1);
132             }
133 
134             if (full_path != nullptr)
135                 *full_path = basedir;
136 
137             return true;
138         }
139     }
140 }
141