2 * main.c: The main entry point for the mono executable
4 * The main entry point does a few things:
6 * * It probes whether the executable has a bundle appended
7 * at the end, and if so, registers the various bundled
8 * resources with Mono and executes the contained bundle
10 * * Parses the MONO_ENV_OPTIONS variable to treat the
11 * contents of the variable as command line arguments for
14 * * Launches Mono, by calling mono_main.
18 #include <mono/metadata/assembly.h>
19 #include <mono/metadata/mono-config.h>
20 #include <mono/utils/mono-mmap.h>
21 #include <mono/utils/mono-dl.h>
30 # ifndef BUILDVER_INCLUDED
31 # include "buildver-boehm.h"
36 * If the MONO_ENV_OPTIONS environment variable is set, it uses this as a
37 * source of command line arguments that are passed to Mono before the
38 * command line arguments specified in the command line.
41 mono_main_with_options (int argc, char *argv [])
43 mono_parse_env_options (&argc, &argv);
45 return mono_main (argc, argv);
49 * The Mono executable can initialize itself from a payload attached
50 * at the end of the main program. The payload contains the
51 * main assembly, one or more managed assemblies, configuration
52 * files and other assets that are used instead of launching a
53 * program from the command line.
55 * The startup sequence probes for a magical signature at the end of
56 * the executable, if the 16 characters "xmonkeysloveplay" are found,
57 * the code expects the 64-bits just before it to contain an offset
58 * within the executable with a directory of assets.
60 * All pointers in the file format are encoded as little-endian values
62 * The format of the file is thus:
66 * lenght-16 Optional "xmonkeysloveplay", indicating that a
67 * bundled payload is contained in the executable.
68 * length-24 pointer to the directory in the file, address DIR
70 * DIR 32-bit value with the number of entries in the directory
71 * DIR+4 First directory entry.
73 * Each directory entry is made up of:
74 * 4-bytes uint32_t containing the size of a string (STR)
75 * STRING UTF8 encoded and \0 terminated string
76 * 8-bytes uint64_t offset in the file with the payload associated with STRING
77 * 4-bytes uint32_t size of the asset
79 * The following are the known directory entries, without the quotes:
80 * "assembly:NAME" An assembly with the name NAME, assembly is in the payload
81 * "config:NAME" A configuration file (usually file.dll.config) in the payload that is
82 * loaded as the config file for an assembly
83 * "systemconfig:" Treats as a Mono system configuration, payload contains the config file.
84 * "options:" The payload contains command line options to initialize Mono, as if you
85 had set them on MONO_ENV_OPTIONS
86 * "config_dir:DIR" Configures the MONO_PATH to point to point to DIR
87 * "machineconfig:" The payload contains the machine.config file to use at runtime
88 * "env:" Sets the environment variable to the value encoded in the payload
89 * payload contains: 1-byte lenght for the \0 terminated variable,
90 * followed by the value.
91 * "library:NAME" Bundled dynamic library NAME, payload contains the dynamic library
93 #define STREAM_INT(x) GUINT32_TO_LE((*(uint32_t*)x))
94 #define STREAM_LONG(x) GUINT64_TO_LE((*(uint64_t*)x))
97 * Loads a chunk of data from the file pointed to by the
98 * @fd starting at the file offset @offset for @size bytes
99 * and returns an allocated version of that string, or NULL
103 load_from_region (int fd, uint64_t offset, uint64_t size)
110 loc = lseek (fd, offset, SEEK_SET);
111 } while (loc == -1 && errno == EINTR);
114 buffer = g_malloc (size + 1);
119 status = read (fd, buffer, size);
120 } while (status == -1 && errno == EINTR);
128 /* Did we initialize the temporary directory for dynamic libraries */
129 static int bundle_save_library_initialized;
131 /* List of bundled libraries we unpacked */
132 static GSList *bundle_library_paths;
134 /* Directory where we unpacked dynamic libraries */
135 static char *bundled_dylibrary_directory;
138 delete_bundled_libraries ()
142 for (list = bundle_library_paths; list != NULL; list = list->next){
145 rmdir (bundled_dylibrary_directory);
149 bundle_save_library_initialize ()
151 bundle_save_library_initialized = 1;
152 char *path = g_build_filename (g_get_tmp_dir (), "mono-bundle-XXXXXX");
153 bundled_dylibrary_directory = g_mkdtemp (path);
155 if (bundled_dylibrary_directory == NULL)
157 atexit (delete_bundled_libraries);
161 save_library (int fd, uint64_t offset, uint64_t size, const char *destfname)
164 char *file, *buffer, *err;
165 if (!bundle_save_library_initialized)
166 bundle_save_library_initialize ();
168 file = g_build_filename (bundled_dylibrary_directory, destfname);
169 buffer = load_from_region (fd, offset, size);
170 g_file_set_contents (file, buffer, size, NULL);
171 lib = mono_dl_open (file, MONO_DL_LAZY, &err);
173 fprintf (stderr, "Error loading shared library: %s\n", file);
176 mono_loader_register_module (destfname, lib);
177 bundle_library_paths = g_slist_append (bundle_library_paths, file);
183 probe_embedded (const char *program, int *ref_argc, char **ref_argv [])
185 MonoBundledAssembly last = { NULL, 0, 0 };
186 char sigbuffer [16+sizeof (uint64_t)];
187 gboolean status = FALSE;
188 uint64_t directory_location;
189 off_t sigstart, baseline = 0;
190 uint64_t directory_size;
193 unsigned char *mapaddress = NULL;
194 void *maphandle = NULL;
196 char *entry_point = NULL;
200 int fd = open (program, O_RDONLY);
203 if ((sigstart = lseek (fd, -24, SEEK_END)) == -1)
205 if (read (fd, sigbuffer, sizeof (sigbuffer)) == -1)
207 if (memcmp (sigbuffer+sizeof(uint64_t), "xmonkeysloveplay", 16) != 0)
209 directory_location = GUINT64_FROM_LE ((*(uint64_t *) &sigbuffer [0]));
210 if (lseek (fd, directory_location, SEEK_SET) == -1)
212 directory_size = sigstart-directory_location;
213 directory = g_malloc (directory_size);
214 if (directory == NULL)
216 if (read (fd, directory, directory_size) == -1)
219 items = STREAM_INT (directory);
222 assemblies = g_array_new (0, 0, sizeof (MonoBundledAssembly*));
223 for (i = 0; i < items; i++){
225 int strsize = STREAM_INT (p);
226 uint64_t offset, item_size;
229 offset = STREAM_LONG(p);
231 item_size = STREAM_INT (p);
234 if (mapaddress == NULL){
235 mapaddress = mono_file_map (directory_location-offset, MONO_MMAP_READ | MONO_MMAP_PRIVATE, fd, offset, &maphandle);
236 if (mapaddress == NULL){
237 perror ("Error mapping file");
242 if (strncmp (kind, "assembly:", strlen ("assembly:")) == 0){
243 char *aname = kind + strlen ("assembly:");
244 MonoBundledAssembly mba = { aname, mapaddress + offset - baseline, item_size }, *ptr;
245 ptr = g_new (MonoBundledAssembly, 1);
246 memcpy (ptr, &mba, sizeof (MonoBundledAssembly));
247 g_array_append_val (assemblies, ptr);
248 if (entry_point == NULL)
250 } else if (strncmp (kind, "config:", strlen ("config:")) == 0){
251 char *config = kind + strlen ("config:");
252 char *aname = g_strdup (config);
253 aname [strlen(aname)-strlen(".config")] = 0;
254 mono_register_config_for_assembly (aname, load_from_region (fd, offset, item_size));
255 } else if (strncmp (kind, "systemconfig:", strlen ("systemconfig:")) == 0){
256 mono_config_parse_memory (load_from_region (fd, offset, item_size));
257 } else if (strncmp (kind, "options:", strlen ("options:")) == 0){
258 mono_parse_options_from (load_from_region (fd, offset, item_size), ref_argc, ref_argv);
259 } else if (strncmp (kind, "config_dir:", strlen ("config_dir:")) == 0){
260 mono_set_dirs (getenv ("MONO_PATH"), load_from_region (fd, offset, item_size));
261 } else if (strncmp (kind, "machineconfig:", strlen ("machineconfig:")) == 0) {
262 mono_register_machine_config (load_from_region (fd, offset, item_size));
263 } else if (strncmp (kind, "env:", strlen ("env:")) == 0){
264 char *data = load_from_region (fd, offset, item_size);
265 uint8_t count = *data++;
266 char *value = data + count + 1;
267 g_setenv (data, value, FALSE);
268 } else if (strncmp (kind, "library:", strlen ("library:")) == 0){
269 save_library (fd, offset, item_size, kind + strlen ("library:"));
271 fprintf (stderr, "Unknown stream on embedded package: %s\n", kind);
275 g_array_append_val (assemblies, last);
277 mono_register_bundled_assemblies ((const MonoBundledAssembly **) assemblies->data);
278 new_argv = g_new (char *, (*ref_argc)+1);
279 for (j = 0; j < *ref_argc; j++)
280 new_argv [j] = (*ref_argv)[j];
281 new_argv [j] = entry_point;
282 *ref_argv = new_argv;
297 #include <shellapi.h>
302 TCHAR szFileName[MAX_PATH];
309 argvw = CommandLineToArgvW (GetCommandLine (), &argc);
310 argv = g_new0 (gchar*, argc + 1);
311 for (i = 0; i < argc; i++)
312 argv [i] = g_utf16_to_utf8 (argvw [i], -1, NULL, NULL, NULL);
317 if ((count = GetModuleFileName (NULL, szFileName, MAX_PATH)) != 0){
318 char *entry = g_utf16_to_utf8 (szFileName, count, NULL, NULL, NULL);
319 probe_embedded (entry, &argc, &argv);
322 return mono_main_with_options (argc, argv);
328 main (int argc, char* argv[])
330 mono_build_date = build_date;
332 probe_embedded (argv [0], &argc, &argv);
333 return mono_main_with_options (argc, argv);