1 #ifndef WIN32
2 # include <unistd.h>
3 #else
4 # include <io.h>
5 # include <windows.h>
6 #endif
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <stdlib.h>
11 #include <errno.h>
12 #include "scheme.h"
13 #include "rktio.h"
14 
15 #ifdef WIN32
16 # define RACKET_API_EXTERN __declspec(dllexport)
17 #else
18 # define RACKET_API_EXTERN extern
19 #endif
20 #define BOOT_EXTERN RACKET_API_EXTERN
21 #include "boot.h"
22 #include "api.h"
23 
24 #define RACKET_AS_BOOT
25 
26 #if defined(_MSC_VER) || defined(__MINGW32__)
27 # define BOOT_O_BINARY O_BINARY
28 #endif
29 
30 #ifndef BOOT_O_BINARY
31 # define BOOT_O_BINARY 0
32 #endif
33 
34 #ifdef WIN32
boot_open(const char * path,int flags)35 int boot_open(const char *path, int flags) {
36   int sz = MultiByteToWideChar(CP_UTF8, 0, path, -1, NULL, 0);
37   wchar_t *w_path = malloc(sz * sizeof(wchar_t));
38 
39   MultiByteToWideChar(CP_UTF8, 0, path, -1, w_path, sz);
40 
41   {
42     int r = _wopen(w_path, flags);
43 
44     free(w_path);
45     return r;
46   }
47 }
48 #else
49 # define boot_open open
50 #endif
51 
Sbytevector(char * s)52 static ptr Sbytevector(char *s)
53 {
54   iptr len = strlen(s);
55   ptr bv;
56   bv = Smake_bytevector(len, 0);
57   memcpy(Sbytevector_data(bv), s, len);
58   return bv;
59 }
60 
parse_coldirs(char * s)61 static ptr parse_coldirs(char *s)
62 {
63   iptr len = strlen(s);
64 
65   if (!len || !s[len+1]) {
66     /* empty string or only one string */
67     return Sbytevector(s);
68   }
69 
70   /* multiple collects paths; put into a reversed list */
71   {
72     ptr rev = Snil;
73     iptr delta = 0;
74 
75     while (s[delta]) {
76       len = strlen(s + delta);
77       rev = Scons(Sbytevector(s+delta), rev);
78       delta += len + 1;
79     }
80 
81     return rev;
82   }
83 }
84 
run_cross_server(char ** argv)85 static void run_cross_server(char **argv)
86 {
87   ptr c, a;
88   const char *target_machine = argv[1];
89   const char *cross_server_patch_file = argv[2];
90   const char *cross_server_library_file = argv[3];
91 
92   c = Stop_level_value(Sstring_to_symbol("load")); /* original `load` */
93   a = Sstring(cross_server_patch_file);
94   (void)Scall1(c, a);
95 
96   c = Stop_level_value(Sstring_to_symbol("load")); /* this is the patched `load` */
97   a = Sstring(cross_server_library_file);
98   (void)Scall1(c, a);
99   c = Stop_level_value(Sstring_to_symbol("serve-cross-compile"));
100 
101   a = Sstring(target_machine);
102   (void)Scall1(c, a);
103 }
104 
init_foreign()105 static void init_foreign()
106 {
107 # include "rktio.inc"
108 }
109 
racket_boot(racket_boot_arguments_t * ba)110 void racket_boot(racket_boot_arguments_t *ba)
111 {
112   int cross_server = 0;
113 
114 #ifdef WIN32
115   if (ba->dll_dir)
116     rktio_set_dll_path((wchar_t *)ba->dll_dir);
117   if (ba->dll_open)
118     rktio_set_dll_procs(ba->dll_open, ba->dll_find_object, ba->dll_close);
119 #endif
120 
121   Sscheme_register_signal_registerer(rktio_will_modify_os_signal_handler);
122 
123   Sscheme_init(NULL);
124 
125   if ((ba->argc == 4) && !strcmp(ba->argv[0], "--cross-server"))
126     cross_server = 1;
127 
128   /* Open boot files, but reuse file descriptors when possible */
129   {
130     int fd1, fd2, close_fd1 = 0, close_fd2 = 0;
131 
132     if ((ba->boot2_offset == 0)
133         || ((ba->boot1_path != ba->boot2_path)
134             && strcmp(ba->boot1_path, ba->boot2_path)))
135       close_fd1 = 1;
136 # ifdef RACKET_AS_BOOT
137     if ((ba->boot3_offset == 0)
138         || ((ba->boot2_path != ba->boot3_path)
139             && strcmp(ba->boot2_path, ba->boot3_path)))
140       close_fd2 = 1;
141 #else
142     close_fd2 = 1;
143 #endif
144 
145     fd1 = boot_open(ba->boot1_path, O_RDONLY | BOOT_O_BINARY);
146     Sregister_boot_file_fd_region("petite", fd1, ba->boot1_offset, ba->boot1_len, close_fd1);
147 
148     if (!close_fd1)
149       fd2 = fd1;
150     else
151       fd2 = boot_open(ba->boot2_path, O_RDONLY | BOOT_O_BINARY);
152     Sregister_boot_file_fd_region("scheme", fd2, ba->boot2_offset, ba->boot2_len, close_fd2);
153 
154 # ifdef RACKET_AS_BOOT
155     if (!cross_server) {
156       int fd3;
157 
158       if (!close_fd2)
159         fd3 = fd2;
160       else
161         fd3 = boot_open(ba->boot3_path, O_RDONLY | BOOT_O_BINARY);
162       Sregister_boot_file_fd_region("racket", fd3, ba->boot3_offset, ba->boot3_len, 1);
163     }
164 # endif
165   }
166 
167   Sbuild_heap(NULL, init_foreign);
168 
169   if (cross_server) {
170     /* Don't run Racket as usual. Instead, load the patch
171        file and run `serve-cross-compile` */
172     run_cross_server(ba->argv);
173     exit(0);
174   }
175 
176   {
177     ptr l = Snil;
178     int i;
179     char segment_offset_s[32], wm_is_gracket_s[32];
180 
181     if (ba->argv) {
182       for (i = ba->argc; i--; ) {
183         l = Scons(Sbytevector(ba->argv[i]), l);
184       }
185     } else {
186       l = Scons(Sbytevector("-n"), l);
187     }
188     l = Scons(Sbytevector(ba->gracket_guid_or_x11_args ? ba->gracket_guid_or_x11_args : ""), l);
189     sprintf(wm_is_gracket_s, "%d", ba->wm_is_gracket_or_x11_arg_count);
190     l = Scons(Sbytevector(wm_is_gracket_s), l);
191     l = Scons(Sbytevector(ba->is_gui ? "true" : "false"), l);
192     l = Scons(Sbytevector(ba->cs_compiled_subdir ? "true" : "false"), l);
193     sprintf(segment_offset_s, "%ld", ba->segment_offset);
194     l = Scons(Sbytevector(segment_offset_s), l);
195     l = Scons(Sbytevector(ba->k_file ? (char *)ba->k_file : (char *)ba->exec_file), l);
196     l = Scons(Sbytevector(ba->config_dir ? (char *)ba->config_dir : "etc"), l);
197     l = Scons(parse_coldirs(ba->collects_dir ? (char *)ba->collects_dir : ""), l);
198     l = Scons(Sbytevector(ba->run_file ? (char *)ba->run_file : (char *)ba->exec_file), l);
199     l = Scons(Sbytevector((char *)ba->exec_file), l);
200     l = Scons(Sbytevector(ba->exit_after ? "false" : "true"), l);
201 
202 #ifdef RACKET_AS_BOOT
203     {
204       ptr c, start, apply;
205       c = Stop_level_value(Sstring_to_symbol("scheme-start"));
206       start = Scall0(c);
207       apply = Stop_level_value(Sstring_to_symbol("apply"));
208       Scall2(apply, start, l);
209     }
210 #else
211     Sset_top_level_value(Sstring_to_symbol("bytes-command-line-arguments"), l);
212 #endif
213   }
214 
215 #ifndef RACKET_AS_BOOT
216   {
217     ptr c, p;
218     int f3;
219 
220     fd3 = open(ba->boot3_path, O_RDONLY | BOOT_O_BINARY);
221     if (boot3_offset) lseek(fd3, ba->boot3_offset, SEEK_SET);
222     c = Stop_level_value(Sstring_to_symbol("open-fd-input-port"));
223     p = Scall1(c, Sfixnum(fd3));
224     Slock_object(p);
225     c = Stop_level_value(Sstring_to_symbol("port-file-compressed!"));
226     Scall1(c, p);
227     Sunlock_object(p);
228     c = Stop_level_value(Sstring_to_symbol("load-compiled-from-port"));
229     Scall1(c, p);
230   }
231 #endif
232 }
233 
234 /* **************************************** */
235 
236 enum {
237   EMBEDDED_ENTRY_APPLY,
238   EMBEDDED_ENTRY_PRIMITIVE_LOOKUP,
239   EMBEDDED_ENTRY_EVAL,
240   EMBEDDED_ENTRY_DYNAMIC_REQUIRE,
241   EMBEDDED_ENTRY_NAMESPACE_REQUIRE,
242   EMBEDDED_ENTRY_EMBEDDED_LOAD
243 };
244 
get_embedded_entry(int index)245 static ptr get_embedded_entry(int index)
246 {
247   ptr vec;
248 
249   vec = Stop_level_value(Sstring_to_symbol("embedded-racket-entry-info"));
250   return Svector_ref(vec, index);
251 }
252 
racket_apply(ptr proc,ptr arg_list)253 ptr racket_apply(ptr proc, ptr arg_list)
254 {
255   ptr app = get_embedded_entry(EMBEDDED_ENTRY_APPLY);
256 
257   return Scall2(app, proc, arg_list);
258 }
259 
racket_primitive(const char * name)260 ptr racket_primitive(const char *name)
261 {
262   ptr prim_lookup = get_embedded_entry(EMBEDDED_ENTRY_PRIMITIVE_LOOKUP);
263 
264   return Scall1(prim_lookup, Sstring_to_symbol(name));
265 }
266 
racket_eval(ptr s_expr)267 ptr racket_eval(ptr s_expr)
268 {
269   ptr eval = get_embedded_entry(EMBEDDED_ENTRY_EVAL);
270 
271   return racket_apply(eval, Scons(s_expr, Snil));
272 }
273 
racket_dynamic_require(ptr module_path,ptr sym_or_false)274 ptr racket_dynamic_require(ptr module_path, ptr sym_or_false)
275 {
276   ptr dy_req = get_embedded_entry(EMBEDDED_ENTRY_DYNAMIC_REQUIRE);
277 
278   return racket_apply(dy_req, Scons(module_path, Scons(sym_or_false, Snil)));
279 }
280 
racket_namespace_require(ptr module_path)281 void racket_namespace_require(ptr module_path)
282 {
283   ptr ns_req = get_embedded_entry(EMBEDDED_ENTRY_NAMESPACE_REQUIRE);
284 
285   (void)racket_apply(ns_req, Scons(module_path, Snil));
286 }
287 
embedded_load(ptr path,ptr start,ptr end,ptr bstr,int as_predefined)288 static void embedded_load(ptr path, ptr start, ptr end, ptr bstr, int as_predefined)
289 {
290   ptr load = get_embedded_entry(EMBEDDED_ENTRY_EMBEDDED_LOAD);
291   ptr pre = (as_predefined ? Strue : Sfalse);
292 
293   (void)racket_apply(load, Scons(path, Scons(start, Scons(end, Scons(bstr, Scons(pre, Snil))))));
294 }
295 
racket_embedded_load_bytes(const char * code,uptr len,int as_predefined)296 void racket_embedded_load_bytes(const char *code, uptr len, int as_predefined)
297 {
298   ptr bstr = Smake_bytevector(len, 0);
299   memcpy(Sbytevector_data(bstr), code, len);
300 
301   embedded_load(Sfalse, Sfalse, Sfalse, bstr, as_predefined);
302 }
303 
racket_embedded_load_file(const char * path,int as_predefined)304 void racket_embedded_load_file(const char *path, int as_predefined)
305 {
306   embedded_load(Sbytevector((char *)path), Sfixnum(0), Sfalse, Sfalse, as_predefined);
307 }
308 
racket_embedded_load_file_region(const char * path,uptr start,uptr end,int as_predefined)309 void racket_embedded_load_file_region(const char *path, uptr start, uptr end, int as_predefined)
310 {
311   embedded_load(Sbytevector((char *)path), Sfixnum(start), Sfixnum(end), Sfalse, as_predefined);
312 }
313 
racket_cpointer_address(ptr cptr)314 void *racket_cpointer_address(ptr cptr) {
315   void *p;
316   iptr offset;
317   p = racket_cpointer_base_address(cptr);
318   offset = racket_cpointer_offset(cptr);
319   return (char *)p + offset;
320 }
321 
racket_cpointer_base_address(ptr cptr)322 void *racket_cpointer_base_address(ptr cptr) {
323   if (Srecordp(cptr)) {
324     cptr = Srecord_uniform_ref(cptr, 0);
325 
326     if (Sbytevectorp(cptr))
327       return &Sbytevector_u8_ref(cptr, 0);
328     else if (Svectorp(cptr))
329       return &Svector_ref(cptr, 0);
330     else if (Sfixnump(cptr) || Sbignump(cptr))
331       return TO_VOIDP(Sinteger_value(cptr));
332   }
333 
334   return NULL;
335 }
336 
racket_cpointer_offset(ptr cptr)337 iptr racket_cpointer_offset(ptr cptr) {
338   if (Srecordp(cptr)) {
339     if (Srecord_type_parent(Srecord_type(cptr)) != Sfalse) {
340       /* assume that it's a cpointer+offset */
341       return Sinteger_value(Srecord_uniform_ref(cptr, 2));
342     }
343   }
344 
345   return 0;
346 }
347