Merge pull request #3422 from xmcclure/tarjan-doublefan
[mono.git] / mono / mini / main.c
1 #include <config.h>
2 #include <fcntl.h>
3 #include <mono/metadata/assembly.h>
4 #include <mono/metadata/mono-config.h>
5 #include <mono/utils/mono-mmap.h>
6 #include "mini.h"
7
8 #ifdef HAVE_UNISTD_H
9 #  include <unistd.h>
10 #endif
11 #ifdef HOST_WIN32
12 #  include <io.h>
13 #else
14 #  ifndef BUILDVER_INCLUDED
15 #    include "buildver-boehm.h"
16 #  endif
17 #endif
18
19 /*
20  * If the MONO_ENV_OPTIONS environment variable is set, it uses this as a
21  * source of command line arguments that are passed to Mono before the
22  * command line arguments specified in the command line.
23  */
24 static int
25 mono_main_with_options (int argc, char *argv [])
26 {
27         mono_parse_env_options (&argc, &argv);
28
29         return mono_main (argc, argv);
30 }
31
32 #define STREAM_INT(x) (*(uint32_t*)x)
33 #define STREAM_LONG(x) (*(uint64_t*)x)
34
35 static gboolean
36 probe_embedded (const char *program, int *ref_argc, char **ref_argv [])
37 {
38         MonoBundledAssembly last = { NULL, 0, 0 };
39         char sigbuffer [16+sizeof (uint64_t)];
40         gboolean status = FALSE;
41         uint64_t directory_location;
42         off_t sigstart, baseline = 0;
43         uint64_t directory_size;
44         char *directory, *p;
45         int items, i;
46         unsigned char *mapaddress = NULL;
47         void *maphandle = NULL;
48         GArray *assemblies;
49         char *entry_point = NULL;
50         char **new_argv;
51         int j;
52
53         int fd = open (program, O_RDONLY);
54         if (fd == -1)
55                 return FALSE;
56         if ((sigstart = lseek (fd, -24, SEEK_END)) == -1)
57                 goto doclose;
58         if (read (fd, sigbuffer, sizeof (sigbuffer)) == -1)
59                 goto doclose;
60         if (memcmp (sigbuffer+sizeof(uint64_t), "xmonkeysloveplay", 16) != 0)
61                 goto doclose;
62         directory_location = GUINT64_FROM_LE ((*(uint64_t *) &sigbuffer [0]));
63         if (lseek (fd, directory_location, SEEK_SET) == -1)
64                 goto doclose;
65         directory_size = sigstart-directory_location;
66         directory = g_malloc (directory_size);
67         if (directory == NULL)
68                 goto doclose;
69         if (read (fd, directory, directory_size) == -1)
70                 goto dofree;
71
72         items = STREAM_INT (directory);
73         p = directory+4;
74
75         assemblies = g_array_new (0, 0, sizeof (MonoBundledAssembly*));
76         for (i = 0; i < items; i++){
77                 char *kind;
78                 int strsize = STREAM_INT (p);
79                 uint64_t offset, item_size;
80                 kind = p+4;
81                 p += 4 + strsize;
82                 offset = STREAM_LONG(p);
83                 p += 8;
84                 item_size = STREAM_INT (p);
85                 p += 4;
86                 
87                 if (mapaddress == NULL){
88                         mapaddress = mono_file_map (directory_location-offset, MONO_MMAP_READ | MONO_MMAP_PRIVATE, fd, offset, &maphandle);
89                         if (mapaddress == NULL){
90                                 perror ("Error mapping file");
91                                 exit (1);
92                         }
93                         baseline = offset;
94                 }
95                 if (strncmp (kind, "assembly:", strlen ("assembly:")) == 0){
96                         char *aname = kind + strlen ("assembly:");
97                         MonoBundledAssembly mba = { aname, mapaddress + offset - baseline, item_size }, *ptr;
98                         ptr = g_new (MonoBundledAssembly, 1);
99                         memcpy (ptr, &mba, sizeof (MonoBundledAssembly));
100                         g_array_append_val  (assemblies, ptr);
101                         if (entry_point == NULL)
102                                 entry_point = aname;
103                 } else if (strncmp (kind, "config:", strlen ("config:")) == 0){
104                         char *config = kind + strlen ("config:");
105                         char *aname = g_strdup (config);
106                         aname [strlen(aname)-strlen(".config")] = 0;
107                         mono_register_config_for_assembly (aname, config);
108                 } else if (strncmp (kind, "systemconfig:", strlen ("systemconfig:")) == 0){
109                         mono_config_parse_memory (kind + strlen ("systemconfig:"));
110                 } else if (strncmp (kind, "options:", strlen ("options:")) == 0){
111                         mono_parse_options_from (kind + strlen("options:"), ref_argc, ref_argv);
112                 } else if (strncmp (kind, "config_dir:", strlen ("config_dir:")) == 0){
113                         mono_set_dirs (getenv ("MONO_PATH"), kind + strlen ("config_dir:"));
114                 } else if (strncmp (kind, "machineconfig:", strlen ("machineconfig:")) == 0) {
115                         mono_register_machine_config (kind + strlen ("machineconfig:"));
116                 } else {
117                         fprintf (stderr, "Unknown stream on embedded package: %s\n", kind);
118                         exit (1);
119                 }
120         }
121         g_array_append_val (assemblies, last);
122         
123         mono_register_bundled_assemblies ((const MonoBundledAssembly **) assemblies->data);
124         new_argv = g_new (char *, (*ref_argc)+1);
125         for (j = 0; j < *ref_argc; j++)
126                 new_argv [j] = (*ref_argv)[j];
127         new_argv [j] = entry_point;
128         *ref_argv = new_argv;
129         (*ref_argc)++;
130         
131         return TRUE;
132         
133 dofree:
134         g_free (directory);
135 doclose:
136         if (!status)
137                 close (fd);
138         return status;
139 }
140
141 #ifdef HOST_WIN32
142
143 #include <shellapi.h>
144
145 int
146 main (void)
147 {
148         TCHAR szFileName[MAX_PATH];
149         int argc;
150         gunichar2** argvw;
151         gchar** argv;
152         int i;
153         DWORD count;
154         
155         argvw = CommandLineToArgvW (GetCommandLine (), &argc);
156         argv = g_new0 (gchar*, argc + 1);
157         for (i = 0; i < argc; i++)
158                 argv [i] = g_utf16_to_utf8 (argvw [i], -1, NULL, NULL, NULL);
159         argv [argc] = NULL;
160
161         LocalFree (argvw);
162
163         if ((count = GetModuleFileName (NULL, szFileName, MAX_PATH)) != 0){
164                 char *entry = g_utf16_to_utf8 (szFileName, count, NULL, NULL, NULL);
165                 probe_embedded (entry, &argc, &argv);
166         }
167
168         return mono_main_with_options  (argc, argv);
169 }
170
171 #else
172
173 int
174 main (int argc, char* argv[])
175 {
176         mono_build_date = build_date;
177
178         probe_embedded (argv [0], &argc, &argv);
179         return mono_main_with_options (argc, argv);
180 }
181
182 #endif