Fixed the segmentation fault in dotnettool (#437)
[platform/core/dotnet/launcher.git] / NativeLauncher / tool / dotnettool.cc
index bb8ba55..4343b49 100644 (file)
 #include "utils.h"
 #include "ni_common.h"
 #include "tac_common.h"
+#include "profile_common.h"
+#include "privilege_common.h"
+#include "multi_target_resolver.h"
+#include "log.h"
 
 #include <vector>
+#include <cstring>
+#include <string.h>
 #include <stdlib.h>
 #include <sys/time.h>
+#include <app_common.h>
 
 void DisplayUsage() {
-       fprintf(stdout,
+       _SOUT(
                "\n"
                "Dotnet Tool Version: 1.0\n"
                "\n"
@@ -32,6 +39,7 @@ void DisplayUsage() {
                "       --ni-system               - Create NI under System DLLs\n"
                "       --ni-dll                  - Create NI for DLL\n"
                "       --ni-pkg                  - Create NI for package\n"
+               "                                   (If package is installed under RO area, NI files are generated under RW area)\n"
                "       --ni-dir                  - Create NI for directory\n"
                "       --ni-reset-system         - Remove System NI files\n"
                "       --ni-reset-pkg            - Remove App NI files\n"
@@ -41,14 +49,33 @@ void DisplayUsage() {
                "       --tac-restore-db          - Restore TAC Database\n"
                "       --tac-disable-pkg         - Disable TAC for package\n"
                "       --tac-enable-pkg          - Enable TAC for package\n"
-               "       --ibc-dir                 - Specify a directory containing IBC files\n"
+               "       --resolve-all-app         - Remove unused multi-targeting files of all apps\n"
+               "                                   (this option is used for FOTA script or test)\n"
+               "       --rm-app-profile          - Remove application profile of given packages for all users\n"
+               "                                   (this option should be run as root)\n"
+               "       --rm-all-app-profile      - Remove application profile of all packages for all users\n"
+               "                                   (this option should be run as root)\n"
+               "       --check-all-app-privilege - Chcek application privilege of all package\n"
+               "                                   (this option should be run as root)\n"
                "\n"
                "Options:\n"
-               "       --r2r                     - Generate a Ready-To-Run image (disable: /FragileNonVersionable)\n"
-               "       --compatibility           - Compatibility mode for older versions of crossgen\n"
-               "                                   (replaces /r with /Trusted_Platform_Assemblies)\n"
+               "       --mibc                    - Specify Mibc files. Sepatated with ':'.\n"
                "       --verbose                 - Display verbose information\n"
-               "       --instrument              - Generate an instrumented image for profiling (enable: /Tuning)\n"
+               "       --inputbubble             - Compile input assemblies into one bubble with the assemblies described at --inputbubbleref option\n"
+               "                                   Note!: If you do not have an accurate understanding of Bubble, do not use this option.\n"
+               "                                          All assemblies in the bubble must be guaranteed to be compiled to the native image before execution.\n"
+               "                                          If an uncompiled assembly is included in the bubble during execution, an unknown error may occur.\n"
+               "                                          If --inputbubbleref option doesnot be set, only input files are included to bubble. \n"
+               "       --inputbubbleref          - Input bubble reference file(s) to be added to bubble (used with --inputbubble option)\n"
+               "       --ref                     - Reference file(s) for compilation\n"
+               "                                   (system paths are set automatically.)\n"
+               "       --no-pipeline             - Compile the dlls individually\n"
+               "       --print-cmd               - Print command and options\n"
+               "       --skip-ro-app             - Skip re-generate NI for apps installed RO area\n"
+               "                                   (This option works with --ni-regen-all-app only)\n"
+               "       --rm-origin-after-ni      - Remove original dll after creating native image\n"
+               "                                   Note!: App ATOC options(--ni-pkg, --ni-regen-all-app, --tac-regen-all) cannot be used with --rm-origin-after-ni option.\n"
+               "                                   (Use only for assemblies that will not be AOTed again afterward.)"
                "\n"
                "Usage: dotnettool [options] [command] [arguments]\n"
                "\n"
@@ -59,10 +86,12 @@ void DisplayUsage() {
                "   # dotnettool --ni-dll /usr/bin/Tizen.Runtime.dll\n"
                "3. Create native image under the package's bin and lib directory\n"
                "   # dotnettool --ni-pkg org.tizen.FormsGallery\n"
-               "4. Regenerate native images for all installed .net packages with ready-to-run option\n"
-               "   # dotnettool --r2r --ni-regen-all-app\n"
-               "5. Create native image for dll based on the IBC data\n"
-               "   # dotnettool --ibc-dir /tmp/ibcdata/ --ni-dll /usr/bin/Tizen.Runtime.dll\n"
+               "4. Regenerate native images for all installed .net packages\n"
+               "   # dotnettool --ni-regen-all-app\n"
+               "5. Create native image for dll based on the Mibc data\n"
+               "   # dotnettool --mibc /tmp/ibcdata/in.mibc --ni-dll /usr/bin/Tizen.Runtime.dll\n"
+               "6. Remove profile for package\n"
+               "   # dotnettool --rm-app-profile org.tizen.FormsGallery\n"
                "\n");
 }
 
@@ -82,45 +111,95 @@ int main(int argc, char* argv[])
                return -1;
        }
 
-       //sh-3.2# dotnettool --[r2r|compatibility|instrument|verbose]
-       DWORD flags = 0;
+       NIOption* opt = getNIOption();
+       if (opt == nullptr) {
+               _SERR("Fail to create option structure.");
+               return -1;
+       }
+
        std::vector<std::string> args;
-       for (char** it = argv; it != argv+argc; it++) {
-               if (!strncmp(*it, "-?", 2) || !strncmp(*it, "-h", 2) || !strncmp(*it, "--help", 6)) {
+       for (int i = 0; i < argc; ++i) {
+               std::string arg = argv[i];
+
+               if ((arg == "-?") || (arg == "-h") || (arg == "--h")) {
                        DisplayUsage();
                        return 0;
-               } else if (!strncmp(*it, "--r2r", 5)) {
-                       flags |= NI_FLAGS_ENABLER2R;
-               } else if (!strncmp(*it, "--compatibility", 15)) {
-                       flags |= NI_FLAGS_COMPATIBILITY;
-               } else if (!strncmp(*it, "--instrument", 12)) {
-                       flags |= NI_FLAGS_INSTRUMENT;
-               } else if (!strncmp(*it, "--verbose", 9)) {
-                       flags |= NI_FLAGS_VERBOSE;
-               } else {
-                       args.push_back(*it);
-               }
-       }
+               } else if (arg == "--verbose") {
+                       opt->flags |= NI_FLAGS_VERBOSE;
+               } else if (arg == "--inputbubble") {
+                       opt->flags |= NI_FLAGS_INPUT_BUBBLE;
+               } else if (arg == "--no-pipeline") {
+                       opt->flags |= NI_FLAGS_NO_PIPELINE;
+               } else if (arg == "--print-cmd") {
+                       opt->flags |= NI_FLAGS_PRINT_CMD;
+               } else if (arg == "--skip-ro-app") {
+                       opt->flags |= NI_FLAGS_SKIP_RO_APP;
+               }  else if (arg == "--rm-origin-after-ni") {
+                       opt->flags |= NI_FLAGS_RM_ORIGIN_AFTER_NI;
+               } else if (arg == "--mibc") {
+                       ++i;
+                       if (i >= argc) {
+                               _SOUT("File path containing Mibc files should be followed for --mibc option");
+                               DisplayUsage();
+                               return 0;
+                       }
 
-       //sh-3.2# dotnettool --ibc-dir [ibcDirectory]
-       for (auto it = args.begin(); it != args.end(); ) {
-               if (*it == "--ibc-dir") {
-                       it = args.erase(it);
+                       opt->flags |= NI_FLAGS_MIBC;
 
-                       std::string ibcFilePath = std::string(*it);
-                       if (!isDirectory(ibcFilePath)) {
-                               fprintf(stderr, "IBC path is missing or not exist\n");
-                               return -1;
+                       std::vector<std::string> paths;
+                       splitPath(std::string(argv[i]), paths);
+                       for (const auto &path : paths) {
+                               if (!isFile(path) || isDirectory(path)) {
+                                       _SERR("Mibc file path is missing or does not exist");
+                                       return -1;
+                               }
+                               opt->mibcPath.push_back(path);
+                       }
+               } else if (arg == "--inputbubbleref") {
+                       ++i;
+                       if (i >= argc) {
+                               _SOUT("Path for references should be followed for --inputbubbleref option");
+                               DisplayUsage();
+                               return 0;
                        }
 
-                       setenv("COMPlus_IBCFileDir", const_cast<char *>(ibcFilePath.c_str()), 1);
-                       setenv("COMPlus_UseIBCFile", const_cast<char *>("1"), 1);
-                       it = args.erase(it);
+                       opt->flags |= NI_FLAGS_INPUT_BUBBLE_REF;
+
+                       std::vector<std::string> files;
+                       splitPath(std::string(argv[i]), files);
+                       for (const auto &f : files) {
+                               opt->inputBubbleRefFiles.push_back(f);
+                       }
+               } else if (arg == "--ref") {
+                       ++i;
+                       if (i >= argc) {
+                               _SOUT("Path for references should be followed for --ref option");
+                               DisplayUsage();
+                               return 0;
+                       }
+
+                       std::vector<std::string> files;
+                       splitPath(std::string(argv[i]), files);
+                       for (const auto &f : files) {
+                               opt->refFiles.push_back(f);
+                       }
                } else {
-                       ++it;
+                       args.push_back(arg);
                }
        }
 
+       if (args.size() == 0) {
+               _SERR("The command is missing");
+               DisplayUsage();
+               return -1;
+       }
+
+       if (opt->flags & NI_FLAGS_INPUT_BUBBLE_REF && !(opt->flags & NI_FLAGS_INPUT_BUBBLE)) {
+               _SERR("--inputbubbleref option should be used with --inputbubble option");
+               DisplayUsage();
+               return -1;
+       }
+
        if (initNICommon() != NI_ERROR_NONE) {
                return -1;
        }
@@ -129,39 +208,59 @@ int main(int argc, char* argv[])
        std::string cmd = std::string(*it);
        it = args.erase(it);
 
-       //sh-3.2# dotnettool --ni-system
+       //sh-3.2# dotnettool --ni-system [AssemblyDirectory] [AssemblyDirectory] ...
        if (cmd == "--ni-system") {
-               int ret = createNIPlatform(flags);
+               std::string inputs;
+               while (it != args.end()) {
+                       const std::string dir = std::string(*it);
+                       inputs = inputs + ":" + dir;
+                       it = args.erase(it);
+               }
+               int ret = createNIPlatform(inputs, opt);
                if (ret != NI_ERROR_NONE) {
-                       fprintf(stderr, "Failed to generate system NI\n");
+                       _SERR("Failed to generate system NI");
                }
        }
        //sh-3.2# dotnettool --ni-dll [assemblyPath] [assemblyPath] ...
        else if (cmd == "--ni-dll") {
                if (args.size() < 1) {
-                       fprintf(stderr, "DLL path is missing\n");
+                       _SERR("DLL path is missing");
                }
+               std::vector<std::string> inputs;
                while (it != args.end()) {
                        std::string dll = std::string(*it);
-                       int ret = createNIDll(dll, flags);
-                       if (ret != NI_ERROR_NONE) {
-                               fprintf(stderr, "Failed to generate NI file [%s]\n", dll.c_str());
-                               break;
+                       inputs.push_back(dll);
+                       opt->refFiles.push_back(dll);
+                       if (opt->flags & NI_FLAGS_INPUT_BUBBLE) {
+                               opt->inputBubbleRefFiles.push_back(dll);
                        }
                        it = args.erase(it);
                }
+
+               for (auto &dll : inputs) {
+                       int ret = createNIDll(dll, opt);
+                       if (ret != NI_ERROR_NONE && ret != NI_ERROR_ALREADY_EXIST) {
+                               _SERR("Failed to generate NI file [%s]", dll.c_str());
+                               break;
+                       }
+               }
        }
        //sh-3.2# dotnettool --ni-pkg [pkgId] [pkgId] ...
        else if (cmd == "--ni-pkg") {
+               if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
+                       _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
+                       DisplayUsage();
+                       return -1;
+               }
+
                if (args.size() < 1) {
-                       fprintf(stderr, "Package name is missing\n");
+                       _SERR("Package name is missing");
                }
                while (it != args.end()) {
                        std::string pkg = std::string(*it);
-                       // if there is AOTed dlls under package root, that is skiped.
-                       int ret = createNIUnderPkgRoot(pkg, flags);
+                       int ret = createNIUnderPkgRoot(pkg, opt);
                        if (ret != NI_ERROR_NONE) {
-                               fprintf(stderr, "Failed to generate NI file [%s]\n", pkg.c_str());
+                               _SERR("Failed to generate app NI [%s]", pkg.c_str());
                                break;
                        }
                        it = args.erase(it);
@@ -170,17 +269,19 @@ int main(int argc, char* argv[])
        //sh-3.2# dotnettool --ni-dir [AssemblyDirectory] [AssemblyDirectory] ...
        else if (cmd == "--ni-dir") {
                if (args.size() < 1) {
-                       fprintf(stderr, "Directory path is missing\n");
+                       _SERR("Directory path is missing");
                }
+               std::string dir;
                while (it != args.end()) {
-                       const std::string dir = std::string(*it);
-                       int ret = createNIUnderDirs(dir, flags);
-                       if (ret != NI_ERROR_NONE) {
-                               fprintf(stderr, "Failed to generate NI directory\n");
-                               break;
+                       if (!dir.empty()) {
+                               dir += std::string(":");
                        }
+                       dir += std::string(*it);
                        it = args.erase(it);
                }
+               if (createNIUnderDirs(dir, opt) != NI_ERROR_NONE) {
+                       _SERR("Failed to generate NI directory");
+               }
        }
        //sh-3.2# dotnettool --ni-reset-system
        else if (cmd == "--ni-reset-system") {
@@ -189,13 +290,13 @@ int main(int argc, char* argv[])
        //sh-3.2# dotnettool --ni-reset-pkg [pkgId] [pkgId] ...
        else if (cmd == "--ni-reset-pkg") {
                if (args.size() < 1) {
-                       fprintf(stderr, "Package name is missing\n");
+                       _SERR("Package name is missing");
                }
                while (it != args.end()) {
                        std::string pkg = std::string(*it);
                        int ret = removeNIUnderPkgRoot(pkg);
                        if (ret != NI_ERROR_NONE) {
-                               fprintf(stderr, "Failed to remove dlls for given package [%s]\n", pkg.c_str());
+                               _SERR("Failed to remove dlls for given package [%s]", pkg.c_str());
                                break;
                        }
                        it = args.erase(it);
@@ -204,7 +305,7 @@ int main(int argc, char* argv[])
        //sh-3.2# dotnettool --ni-reset-dir [AssemblyDirectory] [AssemblyDirectory] ...
        else if (cmd == "--ni-reset-dir") {
                if (args.size() < 1) {
-                       fprintf(stderr, "Directory path is missing\n");
+                       _SERR("Directory path is missing");
                }
                while (it != args.end()) {
                        const std::string dir = std::string(*it);
@@ -214,39 +315,51 @@ int main(int argc, char* argv[])
        }
        //sh-3.2# dotnettool --ni-regen-all-app
        else if (cmd == "--ni-regen-all-app") {
-               int ret = regenerateAppNI(flags);
+               if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
+                       _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
+                       DisplayUsage();
+                       return -1;
+               }
+
+               int ret = regenerateAppNI(opt);
                if (ret != NI_ERROR_NONE) {
-                       fprintf(stderr, "Failed to regenerate all app NI\n");
+                       _SERR("Failed to regenerate all app NI");
                }
        }
        //sh-3.2# dotnettool --tac-regen-all
        else if (cmd == "--tac-regen-all") {
-               int ret = regenerateTACNI(flags);
+               if (opt->flags & NI_FLAGS_RM_ORIGIN_AFTER_NI) {
+                       _SERR("App AOTC options cannot be used with --rm-origin-after-ni option");
+                       DisplayUsage();
+                       return -1;
+               }
+
+               int ret = regenerateTACNI(opt);
                if (ret != NI_ERROR_NONE) {
-                       fprintf(stderr, "Failed to regenerate all TAC\n");
+                       _SERR("Failed to regenerate all TAC");
                }
        }
        //sh-3.2# dotnettool --tac-restore-db
        else if (cmd == "--tac-restore-db") {
                int ret = tac_restoreDB();
                if (ret != TAC_ERROR_NONE) {
-                       fprintf(stderr, "Failed to restore TAC db\n");
+                       _SERR("Failed to restore TAC db");
                }
                ret = tlc_restoreDB();
                if (ret != TAC_ERROR_NONE) {
-                       fprintf(stderr, "Failed to restore TLC db\n");
+                       _SERR("Failed to restore TLC db");
                }
        }
        //sh-3.2# dotnettool --tac-enable-pkg [pkgId] [pkgId] ...
        else if (cmd == "--tac-enable-pkg") {
                if (args.size() < 1) {
-                       fprintf(stderr, "Package name is missing\n");
+                       _SERR("Package name is missing");
                }
                while (it != args.end()) {
                        std::string pkg = std::string(*it);
                        int ret = enableTACPackage(pkg);
                        if (ret != TAC_ERROR_NONE) {
-                               fprintf(stderr, "Failed to enable tac [%s]\n", pkg.c_str());
+                               _SERR("Failed to enable tac [%s]", pkg.c_str());
                                break;
                        }
                        it = args.erase(it);
@@ -255,20 +368,48 @@ int main(int argc, char* argv[])
        //sh-3.2# dotnettool --tac-disable-pkg [pkgId] [pkgId] ...
        else if (cmd == "--tac-disable-pkg") {
                if (args.size() < 1) {
-                       fprintf(stderr, "Package name is missing\n");
+                       _SERR("Package name is missing");
                }
                while (it != args.end()) {
                        std::string pkg = std::string(*it);
                        int ret = disableTACPackage(pkg);
                        if (ret != TAC_ERROR_NONE) {
-                               fprintf(stderr, "Failed to disable tac [%s]\n", pkg.c_str());
+                               _SERR("Failed to disable tac [%s]", pkg.c_str());
                                break;
                        }
                        it = args.erase(it);
                }
        }
+       //sh-3.2# dotnettool --resolve-all-app
+       else if (cmd == "--resolve-all-app") {
+               int ret = resolveAllApps();
+               if (ret != 0) {
+                       _SERR("Failed to remove unused multi-targeting files");
+               }
+       }
+       //sh-3.2# dotnettool --rm-app-profile [pkgId] [pkgId] ...
+       else if (cmd == "--rm-app-profile") {
+               if (args.size() < 1) {
+                       _SERR("Package name is missing");
+               }
+               while (it != args.end()) {
+                       std::string pkg = std::string(*it);
+                       if (removeAppProfileData(pkg) != PROFILE_ERROR_NONE) {
+                               _SERR("Failed to remove [%s] profile data", pkg.c_str());
+                       }
+                       it = args.erase(it);
+               }
+       }
+       //sh-3.2# dotnettool --rm-all-app-profile
+       else if (cmd == "--rm-all-app-profile") {
+               removeAllAppProfileData();
+       }
+       //sh-3.2# dotnettool --check-all-app-privilege
+       else if (cmd == "--check-all-app-privilege") {
+               checkAllAppPrivilege();
+       }
        else {
-               fprintf(stderr, "Unknown option [%s]\n", cmd.c_str());
+               _SERR("Unknown option [%s]", cmd.c_str());
                DisplayUsage();
        }
 
@@ -276,7 +417,7 @@ int main(int argc, char* argv[])
 
        gettimeofday(&tv, NULL);
        endtime = tv.tv_sec * 1000l + tv.tv_usec / 1000l;
-       fprintf(stdout, "\nSpend time for dotnettool is [%d]ms\n", (int)(endtime - starttime));
+       _SOUT("\nSpend time for dotnettool is [%d]ms", (int)(endtime - starttime));
 
        return 0;
 }