bug-fix : support plugin path for tpa
[platform/core/dotnet/launcher.git] / NativeLauncher / util / utils.cc
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <stdio.h>
18 #include <dirent.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 #include <limits.h>
22 #include <strings.h>
23 #include <pthread.h>
24
25 #include <cstdlib>
26 #include <cstring>
27 #include <algorithm>
28 #include <unordered_map>
29 #include <vector>
30 #include <iterator>
31 #include <sstream>
32 #include <map>
33
34 #include "utils.h"
35 #include "path_manager.h"
36 #include "log.h"
37
38 static pthread_t loggingThread;
39
40 static bool iCompare(const std::string& a, int aOffset, const std::string& b, int bOffset, int length)
41 {
42         return static_cast<int>(a.length()) - length >= aOffset &&
43                 static_cast<int>(b.length()) - length >= bOffset &&
44                 std::equal(b.begin() + bOffset, b.begin() + bOffset + length, a.begin() + aOffset,
45                         [](unsigned char a, unsigned char b)
46                         { return std::tolower(a) == std::tolower(b); });
47 }
48
49 bool isManagedAssembly(const std::string& fileName)
50 {
51         return (iCompare(fileName, fileName.size()-4, ".dll", 0, 4) ||
52                         iCompare(fileName, fileName.size()-4, ".exe", 0, 4)) &&
53                         !isNativeImage(fileName);
54 }
55
56 bool isNativeImage(const std::string& fileName)
57 {
58         return iCompare(fileName, fileName.size()-7, ".ni", 0, 3);
59 }
60
61 std::string readSelfPath()
62 {
63         char buff[PATH_MAX];
64         ssize_t len = ::readlink("/proc/self/exe", buff, sizeof(buff)-1);
65         if (len != -1) {
66                 buff[len] = '\0';
67                 return std::string(buff);
68         }
69
70         return "";
71 }
72
73 std::string concatPath(const std::string& path1, const std::string& path2)
74 {
75         std::string path(path1);
76         if (path.back() == PATH_SEPARATOR) {
77                 path.append(path2);
78         } else {
79                 path += PATH_SEPARATOR;
80                 path.append(path2);
81         }
82
83         return path;
84 }
85
86 void splitPath(const std::string& path, std::vector<std::string>& out)
87 {
88         std::istringstream ss(path);
89         std::string token;
90
91         while (std::getline(ss, token, ':')) {
92                 out.push_back(token);
93         }
94 }
95
96 std::string absolutePath(const std::string& path)
97 {
98         std::string absPath;
99         char realPath[PATH_MAX];
100         if (realpath(path.c_str(), realPath) != nullptr && realPath[0] != '\0')
101                 absPath.assign(realPath);
102
103         return absPath;
104 }
105
106 std::string baseName(const std::string& path)
107 {
108         auto pos = path.find_last_of(PATH_SEPARATOR);
109         if (pos != std::string::npos)
110                 return path.substr(0, pos);
111         else
112                 return std::string(".");
113         return path;
114 }
115
116 bool isFileExist(const std::string& path)
117 {
118         struct stat sb;
119         return stat(path.c_str(), &sb) == 0;
120 }
121
122 std::string stripNiDLL(const std::string& path)
123 {
124         std::string niPath(path);
125         if (path.size() < 5) return niPath;
126         if (!strncasecmp(path.c_str() + path.size() - 4, ".dll", 4))
127                 niPath = path.substr(0, path.size()-4);
128         else if (!strncasecmp(path.c_str() + path.size() - 4, ".exe", 4))
129                 niPath = path.substr(0, path.size()-4);
130
131         if (!strncasecmp(niPath.c_str() + niPath.size() - 3, ".ni", 3))
132                 return niPath.substr(0, niPath.size()-3);
133
134         return niPath;
135 }
136
137 void assembliesInDirectory(const std::vector<std::string>& directories, std::string& tpaList)
138 {
139         std::map<std::string, std::string> assemblyList;
140         std::map<std::string, std::string> tmpList;
141
142         auto reader = [&assemblyList, &tmpList] (const std::string& path, const char* name) {
143                 if (isManagedAssembly(path) || isNativeImage(path)) {
144                         std::string dllName = stripNiDLL(name);
145                         std::pair<std::map<std::string, std::string>::iterator, bool> ret;
146                         ret = tmpList.insert(std::pair<std::string, std::string>(dllName, path));
147                         if (ret.second == false) {
148                                 if (isNativeImage(path))
149                                         tmpList[dllName] = path;
150                         }
151                 }
152         };
153
154         for (auto directory : directories) {
155                 scanFilesInDir(directory.c_str(), reader, 1);
156                 // merge scaned dll list to tpa list.
157                 // if the dll is already exist in the list, that is skipped.
158                 assemblyList.insert(tmpList.begin(), tmpList.end());
159         }
160
161         std::map<std::string, std::string>::iterator it;
162         for (it = assemblyList.begin(); it != assemblyList.end(); it++)
163                 tpaList += it->second + ':';
164
165         if (tpaList.back() == ':')
166                 tpaList.pop_back();
167 }
168
169 void scanFilesInDir(const std::string& directory, FileReader reader, unsigned int depth)
170 {
171         DIR *dir;
172         struct dirent* entry;
173         bool isDir;
174
175         dir = opendir(directory.c_str());
176
177         if (dir == nullptr)
178                 return;
179
180         std::vector<std::string> innerDirectories;
181
182         while ((entry = readdir(dir)) != nullptr) {
183                 isDir = false;
184                 std::string path = concatPath(directory, entry->d_name);
185                 switch (entry->d_type) {
186                         case DT_REG: break;
187                         case DT_DIR:
188                                 isDir = true;
189                                 break;
190                         case DT_LNK:
191                         case DT_UNKNOWN:
192                                 struct stat sb;
193                                 if (stat(path.c_str(), &sb) == -1)
194                                         continue;
195
196                                 if (S_ISREG(sb.st_mode) || S_ISDIR(sb.st_mode))
197                                         break;
198                         default:
199                                 continue;
200                 }
201                 if (!isDir)
202                         reader(path, entry->d_name);
203                 else if (depth > 1 && strcmp(entry->d_name, ".") && strcmp(entry->d_name, ".."))
204                         innerDirectories.push_back(path);
205         }
206
207         if (depth != 0)
208                 for (auto& d : innerDirectories)
209                         scanFilesInDir(d.c_str(), reader, depth-1);
210
211         closedir(dir);
212 }
213
214 static int __pfd[2];
215
216 static void *stdlog(void*)
217 {
218     ssize_t readSize;
219     char buf[1024];
220
221     while ((readSize = read(__pfd[0], buf, sizeof buf - 1)) > 0) {
222         if (buf[readSize - 1] == '\n') {
223             --readSize;
224         }
225
226         buf[readSize] = 0;
227
228         _LOGX("%s", buf);
229     }
230
231         close(__pfd[0]);
232
233     return 0;
234 }
235
236 int runLoggingThread()
237 {
238     if (setvbuf(stdout, NULL, _IOLBF, 0) < 0) {
239                 _DBG("fail to make stdout line-buffered");
240                 return -1;
241     }
242
243     if (setvbuf(stderr, NULL, _IONBF, 0) < 0) {
244                 _DBG("make stderr unbuffered");
245                 return -1;
246         }
247
248     /* create the pipe and redirect stdout and stderr */
249     if (pipe(__pfd) < 0) {
250                 _DBG("fail to create pipe for logging");
251                 return -1;
252     }
253
254     // stdout
255     if (dup2(__pfd[1], 1) == -1) {
256                 _DBG("fail to duplicate fd to stdout");
257                 return -1;
258     }
259
260     // stderr
261     if (dup2(__pfd[1], 2) == -1) {
262                 _DBG("fail to duplicate fd to stderr");
263                 return -1;
264         }
265
266         close(__pfd[1]);
267
268     /* spawn the logging thread */
269     if (pthread_create(&loggingThread, 0, stdlog, 0) != 0) {
270                 _DBG("fail to create pthread");
271         return -1;
272     }
273
274     if (pthread_detach(loggingThread) != 0) {
275                 _DBG("fail to detach pthread");
276                 return -1;
277         }
278
279     return 0;
280 }
281