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