add missing else
[platform/core/dotnet/launcher.git] / NativeLauncher / installer-plugin / ni_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 #include <sys/smack.h>
40
41 #include "ni_common.h"
42 #include "path_manager.h"
43 #include "plugin_manager.h"
44
45 #ifdef  LOG_TAG
46 #undef  LOG_TAG
47 #endif
48 #define LOG_TAG "NETCORE_INSTALLER_PLUGIN"
49
50 #ifndef CROSSGEN_PATH
51 #error "CROSSGEN_PATH is missed"
52 #endif
53
54 #define __XSTR(x) #x
55 #define __STR(x) __XSTR(x)
56 static const char* __CROSSGEN_PATH = __STR(CROSSGEN_PATH);
57 #undef __STR
58 #undef __XSTR
59
60 static int __interval = 0;
61 static std::string __tpa;
62
63 static void waitInterval()
64 {
65         // by the recommand, ignore small value for performance.
66         if (__interval > 10000) {
67                 fprintf(stderr, "sleep %d usec\n", __interval);
68                 usleep(__interval);
69         }
70 }
71
72 static bool niExist(const std::string& path, std::string& ni)
73 {
74         static std::string possibleExts[] = {
75                 ".ni.dll", ".NI.dll", ".NI.DLL", ".ni.DLL",
76                 ".ni.exe", ".NI.exe", ".NI.EXE", ".ni.EXE"
77         };
78         std::string fName = path.substr(0, path.size() - 4);
79
80         struct stat sb;
81
82         for (std::string ext : possibleExts) {
83                 std::string f = fName + ext;
84                 if (stat(f.c_str(), &sb) == 0) {
85                         ni = f;
86                         return true;
87                 }
88         }
89
90         // native image of System.Private.CoreLib.dll should have to overwrite
91         // original file to support new coreclr
92         if (path.find("System.Private.CoreLib.dll") != std::string::npos) {
93                 std::string coreLibBackup = path + ".Backup";
94                 if (isFileExist(coreLibBackup)) {
95                         ni = path;
96                         return true;
97                 }
98         }
99
100         return false;
101 }
102
103 static void updateNiFileInfo(const std::string& path)
104 {
105         char* label = NULL;
106         std::string niPath;
107
108         if (niExist(path, niPath)) {
109                 // change smack label
110                 if (smack_getlabel(path.c_str(), &label, SMACK_LABEL_ACCESS) == 0) {
111                         if (smack_setlabel(niPath.c_str(), label, SMACK_LABEL_ACCESS) < 0) {
112                                 fprintf(stderr, "Fail to set smack label\n");
113                         }
114                         free(label);
115                 }
116
117                 // change owner and groups for generated ni file.
118                 struct stat info;
119                 if (!stat(path.c_str(), &info)) {
120                         if (chown(niPath.c_str(), info.st_uid, info.st_gid) == -1)
121                                 fprintf(stderr, "Failed to change owner and group name\n");
122                 }
123         }
124 }
125
126 static void crossgen(const std::string& dllPath, const std::string& appPath, bool enableR2R)
127 {
128         std::string absDllPath = absolutePath(dllPath);
129
130         pid_t pid = fork();
131         if (pid == -1)
132                 return;
133
134         if (pid > 0) {
135                 int status;
136                 waitpid(pid, &status, 0);
137                 if (WIFEXITED(status)) {
138                         updateNiFileInfo(absDllPath);
139                         return;
140                 }
141         } else {
142                 std::string jitPath = getRuntimeDir() + "/libclrjit.so";
143                 std::vector<const char*> argv = {
144                         __CROSSGEN_PATH,
145                         "/nologo",
146                         "/Trusted_Platform_Assemblies", __tpa.c_str(),
147                         "/JITPath", jitPath.c_str()
148                 };
149
150                 if (!enableR2R) {
151                         argv.push_back("/FragileNonVersionable");
152                 }
153
154                 argv.push_back("/App_Paths");
155                 std::string absAppPath;
156                 if (!appPath.empty()) {
157                         absAppPath = appPath;
158                 } else {
159                         absAppPath = baseName(absDllPath);
160                 }
161                 argv.push_back(absAppPath.c_str());
162
163                 argv.push_back(absDllPath.c_str());
164                 argv.push_back(nullptr);
165
166                 fprintf(stderr, "+ %s (%s)\n", absDllPath.c_str(), enableR2R ? "R2R" : "FNV");
167
168                 execv(__CROSSGEN_PATH, const_cast<char* const*>(argv.data()));
169                 exit(0);
170         }
171 }
172
173 static int getRootPath(std::string pkgId, std::string& rootPath)
174 {
175         int ret = 0;
176         char *path = 0;
177
178         uid_t uid = 0;
179
180         if (pkgmgr_installer_info_get_target_uid(&uid) < 0) {
181                 _ERR("Failed to get UID");
182                 return -1;
183         }
184
185         pkgmgrinfo_pkginfo_h handle;
186         if (uid == 0) {
187                 ret = pkgmgrinfo_pkginfo_get_pkginfo(pkgId.c_str(), &handle);
188                 if (ret != PMINFO_R_OK)
189                         return -1;
190         } else {
191                 ret = pkgmgrinfo_pkginfo_get_usr_pkginfo(pkgId.c_str(), uid, &handle);
192                 if (ret != PMINFO_R_OK)
193                         return -1;
194         }
195
196         ret = pkgmgrinfo_pkginfo_get_root_path(handle, &path);
197         if (ret != PMINFO_R_OK) {
198                 pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
199                 return -1;
200         }
201         rootPath = path;
202         pkgmgrinfo_pkginfo_destroy_pkginfo(handle);
203
204         return 0;
205 }
206
207
208 static int appAotCb(pkgmgrinfo_appinfo_h handle, void *userData)
209 {
210         char *pkgId = NULL;
211         int ret = 0;
212
213         ret = pkgmgrinfo_appinfo_get_pkgid(handle, &pkgId);
214         if (ret != PMINFO_R_OK) {
215                 fprintf(stderr, "Failed to get pkgid\n");
216                 return -1;
217         }
218
219         if (removeNiUnderPkgRoot(pkgId) != 0) {
220                 fprintf(stderr, "Failed to remove previous dlls from [%s]\n", pkgId);
221                 return -1;
222         }
223
224         // Regenerate ni files with R2R mode forcibiliy. (there is no way to now which option is used)
225         if (createNiUnderPkgRoot(pkgId, true) != 0) {
226                 fprintf(stderr, "Failed to get root path from [%s]\n", pkgId);
227                 return -1;
228         } else {
229                 fprintf(stderr, "Complete make application to native image\n");
230         }
231
232         return 0;
233 }
234
235 static void createCoreLibNI(bool enableR2R)
236 {
237         std::string coreLib = concatPath(getRuntimeDir(), "System.Private.CoreLib.dll");
238         std::string niCoreLib = concatPath(getRuntimeDir(), "System.Private.CoreLib.ni.dll");
239         std::string coreLibBackup = concatPath(getRuntimeDir(), "System.Private.CoreLib.dll.Backup");
240
241         if (!niExist(coreLib, niCoreLib)) {
242                 crossgen(coreLib, std::string(), enableR2R);
243                 if (isFileExist(niCoreLib)) {
244                         if (rename(coreLib.c_str(), coreLibBackup.c_str())) {
245                                 fprintf(stderr, "Failed to rename System.Private.CoreLib.dll\n");
246                         }
247                         if (rename(niCoreLib.c_str(), coreLib.c_str())) {
248                                 fprintf(stderr, "Failed to rename System.Private.CoreLib.ni.dll\n");
249                         }
250                 } else {
251                         fprintf(stderr, "Failed to create native image for %s\n", coreLib.c_str());
252                 }
253         }
254 }
255
256 int initNICommon(NiCommonOption* option)
257 {
258         // get interval value
259         const char* intervalFile = "/usr/share/dotnet.tizen/lib/crossgen_interval.txt";
260         std::ifstream inFile(intervalFile);
261         if (inFile) {
262                 fprintf(stderr, "crossgen_interval.txt is found\n");
263                 inFile >> __interval;
264         }
265
266         if (initializePluginManager("normal")) {
267                 fprintf(stderr, "Fail to initialize plugin manager\n");
268                 return -1;
269         }
270         if (initializePathManager(option->runtimeDir, option->tizenFXDir, option->extraDirs)) {
271                 fprintf(stderr, "Fail to initialize path manager\n");
272                 return -1;
273         }
274
275         __tpa = getTPA();
276
277         return 0;
278 }
279
280 void finalizeNICommon()
281 {
282         __interval = 0;
283
284         finalizePluginManager();
285         finalizePathManager();
286
287         __tpa.clear();
288 }
289
290
291 void createNiPlatform(bool enableR2R)
292 {
293         const std::string platformDirs[] = {getRuntimeDir(), getTizenFXDir()};
294
295         createNiUnderDirs(platformDirs, 2, enableR2R);
296 }
297
298 void createNiDll(const std::string& dllPath, bool enableR2R)
299 {
300         createCoreLibNI(enableR2R);
301
302         if (!isFileExist(dllPath)) {
303                 fprintf(stderr, "Failed to find dll : %s\n", dllPath.c_str());
304                 return;
305         }
306
307         std::string niPath;
308         if (niExist(dllPath, niPath)) {
309                 fprintf(stderr, "Already [%s] file is exist\n", niPath.c_str());
310                 return;
311         }
312
313         crossgen(dllPath, std::string(), enableR2R);
314         if (!niExist(dllPath, niPath)) {
315                 fprintf(stderr, "Failed to create native image for %s\n", dllPath.c_str());
316         }
317 }
318
319 void createNiUnderDirs(const std::string rootPaths[], int count, const std::string ignores[], int igcount, afterCreate cb, bool enableR2R)
320 {
321         createCoreLibNI(enableR2R);
322
323         std::string appPaths;
324         for (int i = 0; i < count; i++) {
325                 appPaths += rootPaths[i];
326                 appPaths += ':';
327         }
328
329         if (appPaths.back() == ':')
330                 appPaths.pop_back();
331
332         auto convert = [&appPaths, ignores, igcount, &cb, enableR2R](const std::string& path, const char* name) {
333                 for (int i = 0; i < igcount; i++) {
334                         if (path == ignores[i])
335                                 return;
336                 }
337                 std::string niPath;
338                 if (isManagedAssembly(path)) {
339                         if (niExist(path, niPath)) {
340                                 fprintf(stderr, "Already [%s] file is exist\n", niPath.c_str());
341                                 return;
342                         }
343                         crossgen(path, appPaths.c_str(), enableR2R);
344                         if (niExist(path, niPath)) {
345                                 if (cb != nullptr)
346                                         cb(niPath.c_str());
347                         } else {
348                                 fprintf(stderr, "Failed to create native image for %s\n", path.c_str());
349                         }
350                         waitInterval();
351                 }
352         };
353
354         for (int i = 0; i < count; i++)
355                 scanFilesInDir(rootPaths[i], convert, 1);
356 }
357 void createNiUnderDirs(const std::string rootPaths[], int count, afterCreate cb, bool enableR2R)
358 {
359         createNiUnderDirs(rootPaths, count, nullptr, 0, cb, enableR2R);
360 }
361 void createNiUnderDirs(const std::string rootPaths[], int count, bool enableR2R)
362 {
363         createNiUnderDirs(rootPaths, count, nullptr, enableR2R);
364 }
365
366 int createNiUnderPkgRoot(const std::string& pkgName, bool enableR2R)
367 {
368         std::string pkgRoot;
369         if (getRootPath(pkgName, pkgRoot) < 0)
370                 return -1;
371
372         std::string binDir = concatPath(pkgRoot, "bin");
373         std::string libDir = concatPath(pkgRoot, "lib");
374         std::string paths[] = {binDir, libDir};
375
376         createNiUnderDirs(paths, 2, enableR2R);
377
378         return 0;
379 }
380
381 int createNiDllUnderPkgRoot(const std::string& pkgName, const std::string& dllPath, bool enableR2R)
382 {
383         std::string pkgRoot;
384         if (getRootPath(pkgName, pkgRoot) < 0)
385                 return -1;
386
387         std::string binDir = concatPath(pkgRoot, "bin");
388         std::string libDir = concatPath(pkgRoot, "lib");
389         std::string appPaths = binDir + ":" + libDir;
390
391         if (!isFileExist(dllPath)) {
392                 fprintf(stderr, "Failed to find dll : %s\n", dllPath.c_str());
393                 return -1;
394         }
395
396         std::string niPath;
397         if (niExist(dllPath, niPath)) {
398                 fprintf(stderr, "Already [%s] file is exist\n", niPath.c_str());
399                 return -1;
400         }
401
402         crossgen(dllPath, appPaths, enableR2R);
403         if (!niExist(dllPath, niPath)) {
404                 fprintf(stderr, "Failed to create native image for %s\n", dllPath.c_str());
405                 return -1;
406         }
407
408         return 0;
409 }
410
411 void removeNiPlatform()
412 {
413         std::string coreLib = concatPath(getRuntimeDir(), "System.Private.CoreLib.dll");
414         std::string coreLibBackup = concatPath(getRuntimeDir(), "System.Private.CoreLib.dll.Backup");
415
416         if (!isFileExist(coreLibBackup)) {
417                 return;
418         }
419
420         if (remove(coreLib.c_str())) {
421                 fprintf(stderr, "Failed to remove System.Private.CoreLib native image file\n");
422         }
423
424         if (rename(coreLibBackup.c_str(), coreLib.c_str())) {
425                 fprintf(stderr, "Failed to rename System.Private.CoreLib.Backup to origin\n");
426         }
427
428         const std::string platformDirs[] = {getRuntimeDir(), getTizenFXDir()};
429
430         removeNiUnderDirs(platformDirs, 2);
431 }
432
433 void removeNiUnderDirs(const std::string rootPaths[], int count)
434 {
435         auto convert = [](const std::string& path, std::string name) {
436                 std::string ni;
437                 if (isNativeImage(path)) {
438                         if (remove(path.c_str())) {
439                                 fprintf(stderr, "Failed to remove %s\n", path.c_str());
440                         }
441                 }
442         };
443
444         for (int i = 0; i < count; i++)
445                 scanFilesInDir(rootPaths[i], convert, -1);
446 }
447
448 int removeNiUnderPkgRoot(const std::string& pkgName)
449 {
450         std::string pkgRoot;
451         if (getRootPath(pkgName, pkgRoot) < 0)
452                 return -1;
453
454         std::string binDir = concatPath(pkgRoot, "bin");
455         std::string libDir = concatPath(pkgRoot, "lib");
456         std::string paths[] = {binDir, libDir};
457
458         removeNiUnderDirs(paths, 2);
459
460         return 0;
461 }
462
463 int regenerateAppNI()
464 {
465         int ret = 0;
466         pkgmgrinfo_appinfo_metadata_filter_h handle;
467
468         ret = pkgmgrinfo_appinfo_metadata_filter_create(&handle);
469         if (ret != PMINFO_R_OK)
470                 return -1;
471
472         ret = pkgmgrinfo_appinfo_metadata_filter_add(handle, "http://tizen.org/metadata/prefer_dotnet_aot", "true");
473         if (ret != PMINFO_R_OK) {
474                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
475                 return -1;
476         }
477
478         ret = pkgmgrinfo_appinfo_metadata_filter_foreach(handle, appAotCb, NULL);
479         if (ret != PMINFO_R_OK) {
480                 fprintf(stderr, "Failed pkgmgrinfo_appinfo_metadata_filter_foreach\n");
481                 pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
482                 return -1;
483         }
484
485         fprintf(stderr, "Success pkgmgrinfo_appinfo_metadata_filter_foreach\n");
486
487         pkgmgrinfo_appinfo_metadata_filter_destroy(handle);
488         return 0;
489 }
490