Merge pull request #5479 from marek-safar/cecil-bump
[mono.git] / mono / mini / main.c
index 8d2f5bd17121d78ef98c4fba3c8e1f427d4b86da..bd4f6674dfbc0d82273461ef9aabab9b56689604 100644 (file)
@@ -1,8 +1,25 @@
+/**
+ * \file
+ * The main entry point for the mono executable
+ *
+ * The main entry point does a few things:
+ * 
+ *   * It probes whether the executable has a bundle appended
+ *     at the end, and if so, registers the various bundled
+ *     resources with Mono and executes the contained bundle
+ *
+ *   * Parses the MONO_ENV_OPTIONS variable to treat the
+ *     contents of the variable as command line arguments for
+ *     the mono runtime
+ *
+ *   * Launches Mono, by calling mono_main.
+ */
 #include <config.h>
 #include <fcntl.h>
 #include <mono/metadata/assembly.h>
 #include <mono/metadata/mono-config.h>
 #include <mono/utils/mono-mmap.h>
+#include <mono/utils/mono-dl.h>
 #include "mini.h"
 
 #ifdef HAVE_UNISTD_H
@@ -29,6 +46,51 @@ mono_main_with_options (int argc, char *argv [])
        return mono_main (argc, argv);
 }
 
+/*
+ * The Mono executable can initialize itself from a payload attached
+ * at the end of the main program.   The payload contains the
+ * main assembly, one or more managed assemblies, configuration
+ * files and other assets that are used instead of launching a
+ * program from the command line.
+ *
+ * The startup sequence probes for a magical signature at the end of
+ * the executable, if the 16 characters "xmonkeysloveplay" are found,
+ * the code expects the 64-bits just before it to contain an offset
+ * within the executable with a directory of assets.
+ *
+ * All pointers in the file format are encoded as little-endian values
+ *
+ * The format of the file is thus:
+ *
+ * Location        Content
+ * --------        -------
+ * lenght-16       Optional "xmonkeysloveplay", indicating that a
+ *                 bundled payload is contained in the executable.
+ * length-24       pointer to the directory in the file, address DIR
+ *
+ * DIR             32-bit value with the number of entries in the directory
+ * DIR+4           First directory entry.
+ *
+ * Each directory entry is made up of:
+ * 4-bytes         uint32_t containing the size of a string (STR)
+ * STRING          UTF8 encoded and \0 terminated string
+ * 8-bytes         uint64_t offset in the file with the payload associated with STRING
+ * 4-bytes         uint32_t size of the asset
+ *
+ * The following are the known directory entries, without the quotes:
+ * "assembly:NAME"  An assembly with the name NAME, assembly is in the payload
+ * "config:NAME"    A configuration file (usually file.dll.config) in the payload that is
+ *                  loaded as the config file for an assembly
+ * "systemconfig:"  Treats as a Mono system configuration, payload contains the config file.
+ * "options:"       The payload contains command line options to initialize Mono, as if you 
+                    had set them on MONO_ENV_OPTIONS
+ * "config_dir:DIR" Configures the MONO_PATH to point to point to DIR
+ * "machineconfig:" The payload contains the machine.config file to use at runtime
+ * "env:"           Sets the environment variable to the value encoded in the payload
+ *                  payload contains: 1-byte lenght for the \0 terminated variable,
+ *                  followed by the value.
+ * "library:NAME"   Bundled dynamic library NAME, payload contains the dynamic library
+ */
 #define STREAM_INT(x) GUINT32_TO_LE((*(uint32_t*)x))
 #define STREAM_LONG(x) GUINT64_TO_LE((*(uint64_t*)x))
 
@@ -64,6 +126,64 @@ load_from_region (int fd, uint64_t offset, uint64_t size)
        return buffer;
 }
 
+/* Did we initialize the temporary directory for dynamic libraries */
+static int bundle_save_library_initialized;
+
+/* List of bundled libraries we unpacked */
+static GSList *bundle_library_paths;
+
+/* Directory where we unpacked dynamic libraries */
+static char *bundled_dylibrary_directory;
+
+static void
+delete_bundled_libraries (void)
+{
+       GSList *list;
+
+       for (list = bundle_library_paths; list != NULL; list = list->next){
+               unlink (list->data);
+       }
+       rmdir (bundled_dylibrary_directory);
+}
+
+static void
+bundle_save_library_initialize (void)
+{
+       bundle_save_library_initialized = 1;
+       char *path = g_build_filename (g_get_tmp_dir (), "mono-bundle-XXXXXX", NULL);
+       bundled_dylibrary_directory = g_mkdtemp (path);
+       g_free (path);
+       if (bundled_dylibrary_directory == NULL)
+               return;
+       atexit (delete_bundled_libraries);
+}
+
+static void
+save_library (int fd, uint64_t offset, uint64_t size, const char *destfname)
+{
+       MonoDl *lib;
+       char *file, *buffer, *err, *internal_path;
+       if (!bundle_save_library_initialized)
+               bundle_save_library_initialize ();
+       
+       file = g_build_filename (bundled_dylibrary_directory, destfname, NULL);
+       buffer = load_from_region (fd, offset, size);
+       g_file_set_contents (file, buffer, size, NULL);
+
+       lib = mono_dl_open (file, MONO_DL_LAZY, &err);
+       if (lib == NULL){
+               fprintf (stderr, "Error loading shared library: %s %s\n", file, err);
+               exit (1);
+       }
+       // Register the name with "." as this is how it will be found when embedded
+       internal_path = g_build_filename (".", destfname, NULL);
+       mono_loader_register_module (internal_path, lib);
+       g_free (internal_path);
+       bundle_library_paths = g_slist_append (bundle_library_paths, file);
+       
+       g_free (buffer);
+}
+
 static gboolean
 probe_embedded (const char *program, int *ref_argc, char **ref_argv [])
 {
@@ -150,18 +270,21 @@ probe_embedded (const char *program, int *ref_argc, char **ref_argv [])
                        uint8_t count = *data++;
                        char *value = data + count + 1;
                        g_setenv (data, value, FALSE);
+               } else if (strncmp (kind, "library:", strlen ("library:")) == 0){
+                       save_library (fd, offset, item_size, kind + strlen ("library:"));
                } else {
                        fprintf (stderr, "Unknown stream on embedded package: %s\n", kind);
                        exit (1);
                }
        }
        g_array_append_val (assemblies, last);
-       
+
        mono_register_bundled_assemblies ((const MonoBundledAssembly **) assemblies->data);
        new_argv = g_new (char *, (*ref_argc)+1);
-       for (j = 0; j < *ref_argc; j++)
-               new_argv [j] = (*ref_argv)[j];
-       new_argv [j] = entry_point;
+       new_argv [0] = (*ref_argv)[0];
+       new_argv [1] = entry_point;
+       for (j = 1; j < *ref_argc; j++)
+               new_argv [j+1] = (*ref_argv)[j];
        *ref_argv = new_argv;
        (*ref_argc)++;