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", NULL
);
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
, *internal_path
;
165 if (!bundle_save_library_initialized
)
166 bundle_save_library_initialize ();
168 file
= g_build_filename (bundled_dylibrary_directory
, destfname
, NULL
);
169 buffer
= load_from_region (fd
, offset
, size
);
170 g_file_set_contents (file
, buffer
, size
, NULL
);
172 lib
= mono_dl_open (file
, MONO_DL_LAZY
, &err
);
174 fprintf (stderr
, "Error loading shared library: %s %s\n", file
, err
);
177 // Register the name with "." as this is how it will be found when embedded
178 internal_path
= g_build_filename (".", destfname
, NULL
);
179 mono_loader_register_module (internal_path
, lib
);
180 g_free (internal_path
);
181 bundle_library_paths
= g_slist_append (bundle_library_paths
, file
);
187 probe_embedded (const char *program
, int *ref_argc
, char **ref_argv
[])
189 MonoBundledAssembly last
= { NULL
, 0, 0 };
190 char sigbuffer
[16+sizeof (uint64_t)];
191 gboolean status
= FALSE
;
192 uint64_t directory_location
;
193 off_t sigstart
, baseline
= 0;
194 uint64_t directory_size
;
197 unsigned char *mapaddress
= NULL
;
198 void *maphandle
= NULL
;
200 char *entry_point
= NULL
;
204 int fd
= open (program
, O_RDONLY
);
207 if ((sigstart
= lseek (fd
, -24, SEEK_END
)) == -1)
209 if (read (fd
, sigbuffer
, sizeof (sigbuffer
)) == -1)
211 if (memcmp (sigbuffer
+sizeof(uint64_t), "xmonkeysloveplay", 16) != 0)
213 directory_location
= GUINT64_FROM_LE ((*(uint64_t *) &sigbuffer
[0]));
214 if (lseek (fd
, directory_location
, SEEK_SET
) == -1)
216 directory_size
= sigstart
-directory_location
;
217 directory
= g_malloc (directory_size
);
218 if (directory
== NULL
)
220 if (read (fd
, directory
, directory_size
) == -1)
223 items
= STREAM_INT (directory
);
226 assemblies
= g_array_new (0, 0, sizeof (MonoBundledAssembly
*));
227 for (i
= 0; i
< items
; i
++){
229 int strsize
= STREAM_INT (p
);
230 uint64_t offset
, item_size
;
233 offset
= STREAM_LONG(p
);
235 item_size
= STREAM_INT (p
);
238 if (mapaddress
== NULL
){
239 mapaddress
= mono_file_map (directory_location
-offset
, MONO_MMAP_READ
| MONO_MMAP_PRIVATE
, fd
, offset
, &maphandle
);
240 if (mapaddress
== NULL
){
241 perror ("Error mapping file");
246 if (strncmp (kind
, "assembly:", strlen ("assembly:")) == 0){
247 char *aname
= kind
+ strlen ("assembly:");
248 MonoBundledAssembly mba
= { aname
, mapaddress
+ offset
- baseline
, item_size
}, *ptr
;
249 ptr
= g_new (MonoBundledAssembly
, 1);
250 memcpy (ptr
, &mba
, sizeof (MonoBundledAssembly
));
251 g_array_append_val (assemblies
, ptr
);
252 if (entry_point
== NULL
)
254 } else if (strncmp (kind
, "config:", strlen ("config:")) == 0){
255 char *config
= kind
+ strlen ("config:");
256 char *aname
= g_strdup (config
);
257 aname
[strlen(aname
)-strlen(".config")] = 0;
258 mono_register_config_for_assembly (aname
, load_from_region (fd
, offset
, item_size
));
259 } else if (strncmp (kind
, "systemconfig:", strlen ("systemconfig:")) == 0){
260 mono_config_parse_memory (load_from_region (fd
, offset
, item_size
));
261 } else if (strncmp (kind
, "options:", strlen ("options:")) == 0){
262 mono_parse_options_from (load_from_region (fd
, offset
, item_size
), ref_argc
, ref_argv
);
263 } else if (strncmp (kind
, "config_dir:", strlen ("config_dir:")) == 0){
264 mono_set_dirs (getenv ("MONO_PATH"), load_from_region (fd
, offset
, item_size
));
265 } else if (strncmp (kind
, "machineconfig:", strlen ("machineconfig:")) == 0) {
266 mono_register_machine_config (load_from_region (fd
, offset
, item_size
));
267 } else if (strncmp (kind
, "env:", strlen ("env:")) == 0){
268 char *data
= load_from_region (fd
, offset
, item_size
);
269 uint8_t count
= *data
++;
270 char *value
= data
+ count
+ 1;
271 g_setenv (data
, value
, FALSE
);
272 } else if (strncmp (kind
, "library:", strlen ("library:")) == 0){
273 save_library (fd
, offset
, item_size
, kind
+ strlen ("library:"));
275 fprintf (stderr
, "Unknown stream on embedded package: %s\n", kind
);
279 g_array_append_val (assemblies
, last
);
281 mono_register_bundled_assemblies ((const MonoBundledAssembly
**) assemblies
->data
);
282 new_argv
= g_new (char *, (*ref_argc
)+1);
283 new_argv
[0] = (*ref_argv
)[0];
284 new_argv
[1] = entry_point
;
285 for (j
= 1; j
< *ref_argc
; j
++)
286 new_argv
[j
+1] = (*ref_argv
)[j
];
287 *ref_argv
= new_argv
;
302 #include <shellapi.h>
307 TCHAR szFileName
[MAX_PATH
];
314 argvw
= CommandLineToArgvW (GetCommandLine (), &argc
);
315 argv
= g_new0 (gchar
*, argc
+ 1);
316 for (i
= 0; i
< argc
; i
++)
317 argv
[i
] = g_utf16_to_utf8 (argvw
[i
], -1, NULL
, NULL
, NULL
);
322 if ((count
= GetModuleFileName (NULL
, szFileName
, MAX_PATH
)) != 0){
323 char *entry
= g_utf16_to_utf8 (szFileName
, count
, NULL
, NULL
, NULL
);
324 probe_embedded (entry
, &argc
, &argv
);
327 return mono_main_with_options (argc
, argv
);
333 main (int argc
, char* argv
[])
335 mono_build_date
= build_date
;
337 probe_embedded (argv
[0], &argc
, &argv
);
338 return mono_main_with_options (argc
, argv
);