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