74b6f1814795026a3f4acfa8a5c0427177dd9c51
[platform/core/dotnet/launcher.git] / NativeLauncher / installer-plugin / common.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 <pkgmgr-info.h>
18 #include <pkgmgr_installer_info.h>
19 #include <aul.h>
20
21 #include "log.h"
22 #include "utils.h"
23 #include "pkgmgr_parser_plugin_interface.h"
24
25 #include <wait.h>
26 #include <dirent.h>
27 #include <sys/stat.h>
28
29 #include <algorithm>
30 #include <string>
31
32 #include <pwd.h>
33 #include <grp.h>
34 #include <sys/stat.h>
35 #include <unistd.h>
36 #include <string.h>
37
38 #include "common.h"
39
40 #ifdef  LOG_TAG
41 #undef  LOG_TAG
42 #endif
43 #define LOG_TAG "NETCORE_INSTALLER_PLUGIN"
44
45 #ifndef DEVICE_API_DIR
46 #error "DEVICE_API_DIR is missed"
47 #endif
48
49 #ifndef RUNTIME_DIR
50 #error "RUNTIME_DIR is missed"
51 #endif
52
53 #ifndef CROSSGEN_PATH
54 #error "CROSSGEN_PATH is missed"
55 #endif
56
57 #define __XSTR(x) #x
58 #define __STR(x) __XSTR(x)
59 static const char* __DEVICE_API_DIR = __STR(DEVICE_API_DIR);
60 static const char* __RUNTIME_DIR = __STR(RUNTIME_DIR);
61 static const char* __CROSSGEN_PATH = __STR(CROSSGEN_PATH);
62 static const char* __JIT_PATH = __STR(RUNTIME_DIR)"/libclrjit.so";
63 #undef __STR
64 #undef __XSTR
65
66
67 static std::string replace(std::string &str, const std::string& from, const std::string& to)
68 {
69         size_t startPos = 0;
70         while ((startPos = str.find(from, startPos)) != std::string::npos) {
71                 str.replace(startPos, from.length(), to);
72                 startPos += to.length();
73         }
74         return str;
75 }
76
77 static void smack_(const char* dllPath, const char* label)
78 {
79         static const char* chsmack = "/usr/bin/chsmack";
80         pid_t pid = fork();
81         if (pid == -1)
82                 return;
83
84         if (pid > 0) {
85                 int status;
86                 waitpid(pid, &status, 0);
87                 if (WIFEXITED(status))
88                         return;
89         } else {
90                 const char* args[] = {
91                         chsmack,
92                         "-a", label,
93                         dllPath,
94                         nullptr
95                 };
96                 execv(chsmack, const_cast<char*const*>(args));
97
98                 exit(0);
99         }
100 }
101
102 static void crossgen(const char* dllPath, const char* appPath)
103 {
104         //pid_t parent = getpid();
105         pid_t pid = fork();
106         if (pid == -1)
107                 return;
108
109         if (pid > 0) {
110                 int status;
111                 waitpid(pid, &status, 0);
112                 if (WIFEXITED(status))
113                         return;
114         } else {
115                 // search dlls in the application directory first, to use application dlls
116                 // instead of system dlls when proceeding NI
117                 std::vector<std::string> tpaDir;
118                 if (appPath != NULL) {
119                         std::string path(appPath);
120                         std::string::size_type prevPos = 0, pos = 0;
121                         while ((pos = path.find(':', pos)) != std::string::npos) {
122                                 std::string substring(path.substr(prevPos, pos - prevPos));
123                                 tpaDir.push_back(substring);
124                                 prevPos = ++pos;
125                         }
126                         std::string substring(path.substr(prevPos, pos - prevPos));
127                         tpaDir.push_back(substring);
128                 }
129                 tpaDir.push_back(__RUNTIME_DIR);
130                 tpaDir.push_back(__DEVICE_API_DIR);
131
132                 // get reference API directory ([DEVICE_API_DIR]/ref)
133                 int len = strlen(__DEVICE_API_DIR);
134                 char* refAPIDir = (char*)calloc(len + 4, 1);
135                 if (!refAPIDir) {
136                         printf("fail to allocate memory for reference API directory\n");
137                         return;
138                 }
139                 snprintf(refAPIDir, len + 4, "%s%s", __DEVICE_API_DIR, "/ref");
140                 tpaDir.push_back(refAPIDir);
141
142                 std::string tpa;
143                 assembliesInDirectory(tpaDir, tpa);
144
145                 std::vector<const char*> argv = {
146                         __CROSSGEN_PATH,
147                         "/Trusted_Platform_Assemblies", tpa.c_str(),
148                         "/JITPath", __JIT_PATH,
149                         "/FragileNonVersionable"
150                 };
151                 if (appPath != nullptr) {
152                         argv.push_back("/App_Paths");
153                         argv.push_back(appPath);
154                 }
155                 argv.push_back(dllPath);
156                 argv.push_back(nullptr);
157
158                 printf("+ %s\n", dllPath);
159
160                 execv(__CROSSGEN_PATH, const_cast<char* const*>(argv.data()));
161                 exit(0);
162         }
163 }
164
165 static int getRootPath(const char *pkgId, std::string& rootPath)
166 {
167         int ret = 0;
168         char *path = 0;
169
170         uid_t uid = 0;
171
172         if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
173                 _ERR("Failed to get UID");
174                 return -1;
175         }
176
177         _INFO("user id is %d", uid);
178
179         pkgmgrinfo_pkginfo_h handle;
180         if (uid == 0) {
181                 ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId, &handle);
182                 if (ret != PMINFO_R_OK)
183                         return -1;
184         } else {
185                 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId, uid, &handle);
186                 if (ret != PMINFO_R_OK)
187                         return -1;
188         }
189
190         ret = pkgmgrinfo_pkginfo_get_root_path(handle, &path);
191         if (ret != PMINFO_R_OK) {
192                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
193                 return -1;
194         }
195         rootPath = path;
196         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
197
198         return 0;
199 }
200
201 static bool niExist(const std::string& path, std::string& ni)
202 {
203         // native image of System.Private.CoreLib.dll should have to overwrite
204         // original file to support new coreclr
205         if (path.find("System.Private.CoreLib.dll") != std::string::npos) {
206                 std::string coreLibBackup = path + ".Backup";
207                 if (!fileNotExist(coreLibBackup)) {
208                         ni = path;
209                         return true;
210                 }
211                 return false;
212         }
213
214         static const char* possibleExts[] = {
215                 ".ni.dll", ".NI.dll", ".NI.DLL", ".ni.DLL",
216                 ".ni.exe", ".NI.exe", ".NI.EXE", ".ni.EXE"
217         };
218         std::string fName = path.substr(0, path.size() - 4);
219
220         struct stat sb;
221
222         for (const char* ext : possibleExts) {
223                 std::string f = fName + ext;
224                 if (stat(f.c_str(), &sb) == 0) {
225                         ni = f;
226                         return true;
227                 }
228         }
229
230         return false;
231 }
232
233 static void createCoreLibNI()
234 {
235         std::string coreLib = concatPath(__RUNTIME_DIR, "System.Private.CoreLib.dll");
236         std::string niCoreLib = concatPath(__RUNTIME_DIR, "System.Private.CoreLib.ni.dll");
237         std::string coreLibBackup = concatPath(__RUNTIME_DIR, "System.Private.CoreLib.dll.Backup");
238
239         if (!niExist(coreLib, niCoreLib)) {
240                 crossgen(coreLib.c_str(), nullptr);
241                 if (!fileNotExist(niCoreLib)) {
242                         // change owner and groups for generated ni file.
243                         struct stat info;
244                         if (!stat(coreLib.c_str(), &info)) {
245                                 if (chown(niCoreLib.c_str(), info.st_uid, info.st_gid) == -1)
246                                         _ERR("Failed to change owner and group name");
247                         }
248                         smack_(niCoreLib.c_str(), "_");
249                         rename(coreLib.c_str(), coreLibBackup.c_str());
250                         rename(niCoreLib.c_str(), coreLib.c_str());
251                 }
252         }
253 }
254
255 void createNiPlatform()
256 {
257         createCoreLibNI();
258
259         const char* platformDirs[] = {__RUNTIME_DIR, __DEVICE_API_DIR, "/usr/bin"};
260
261         createNiUnderDirs(platformDirs, 3, [](const char* ni) {
262                 smack_(ni, "_");
263         });
264 }
265
266 void createNiSelect(const char* dllPath)
267 {
268         createCoreLibNI();
269
270         std::string niPath;
271         if (!fileNotExist(dllPath)) {
272                 if (!niExist(dllPath, niPath)) {
273                         crossgen(dllPath, nullptr);
274                         if (niExist(dllPath, niPath)) {
275                                 // change owner and groups for generated ni file.
276                                 struct stat info;
277                                 if (!stat(dllPath, &info)) {
278                                         if (chown(niPath.c_str(), info.st_uid, info.st_gid) == -1)
279                                                 _ERR("Failed to change owner and group name");
280                                 }
281                                 smack_(niPath.c_str(), "_");
282                         }
283                 }
284                 else
285                         printf("Already [%s] file is exist\n", niPath.c_str());
286         }
287 }
288
289 void createNiUnderDirs(const char* rootPaths[], int count, const char* ignores[], int igcount, afterCreate cb)
290 {
291         std::string appPaths;
292         for (int i = 0; i < count; i++) {
293                 appPaths += rootPaths[i];
294                 appPaths += ':';
295         }
296
297         if (appPaths.back() == ':')
298                 appPaths.pop_back();
299
300         auto convert = [&appPaths, ignores, igcount, &cb](const char* path, const char* name) {
301                 for (int i = 0; i < igcount; i++) {
302                         if (strcmp(path, ignores[i]) == 0)
303                                 return;
304                 }
305                 std::string ni;
306                 if (isManagedAssembly(path) && !isNativeImage(path) && !niExist(path, ni)) {
307                         crossgen(path, appPaths.c_str());
308                         if (niExist(path, ni)) {
309                                 // change owner and groups for generated ni file.
310                                 struct stat info;
311                                 if (!stat(path, &info)) {
312                                         if (chown(ni.c_str(), info.st_uid, info.st_gid) == -1)
313                                                 _ERR("Failed to change owner and group name");
314                                 }
315
316                                 if (cb != nullptr)
317                                         cb(ni.c_str());
318                         }
319                 }
320         };
321
322         for (int i = 0; i < count; i++)
323                 scanFilesInDir(rootPaths[i], convert, -1);
324 }
325 void createNiUnderDirs(const char* rootPaths[], int count, afterCreate cb)
326 {
327         createNiUnderDirs(rootPaths, count, nullptr, 0, cb);
328 }
329 void createNiUnderDirs(const char* rootPaths[], int count)
330 {
331         createNiUnderDirs(rootPaths, count, nullptr);
332 }
333
334 int createNiUnderPkgRoot(const char* pkgName)
335 {
336         std::string pkgRoot;
337         if (getRootPath(pkgName, pkgRoot) < 0)
338                 return 1;
339
340         std::string binDir = concatPath(pkgRoot, "bin");
341         std::string libDir = concatPath(pkgRoot, "lib");
342         _INFO("bindir : %s", binDir.c_str());
343         _INFO("libdir : %s", libDir.c_str());
344
345         const char* paths[] = {
346                 binDir.c_str(),
347                 libDir.c_str()
348         };
349
350         // change smack label for generated ni file.
351         std::string label = "User::Pkg::" + std::string(pkgName) + "::RO";
352         createNiUnderDirs(paths, 2, [label](const char* ni) {
353                         smack_(ni, label.c_str());
354         });
355
356         return 0;
357 }