0.9.10.39:
[sbcl.git] / src / runtime / runtime.c
1 /*
2  * main() entry point for a stand-alone SBCL image
3  */
4
5 /*
6  * This software is part of the SBCL system. See the README file for
7  * more information.
8  *
9  * This software is derived from the CMU CL system, which was
10  * written at Carnegie Mellon University and released into the
11  * public domain. The software is in the public domain and is
12  * provided with absolutely no warranty. See the COPYING and CREDITS
13  * files for more information.
14  */
15
16 #include "sbcl.h"
17
18 #include <stdio.h>
19 #include <string.h>
20 #ifndef LISP_FEATURE_WIN32
21 #include <libgen.h>
22 #endif
23 #include <sys/types.h>
24 #ifndef LISP_FEATURE_WIN32
25 #include <sys/wait.h>
26 #endif
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <sys/file.h>
30 #include <sys/param.h>
31 #include <sys/stat.h>
32 #include <signal.h>
33 #ifndef LISP_FEATURE_WIN32
34 #include <sched.h>
35 #endif
36 #include <errno.h>
37 #include <locale.h>
38
39 #if defined(SVR4) || defined(__linux__)
40 #include <time.h>
41 #endif
42
43 #include "signal.h"
44
45 #include "runtime.h"
46 #include "alloc.h"
47 #include "vars.h"
48 #include "globals.h"
49 #include "os.h"
50 #include "interrupt.h"
51 #include "arch.h"
52 #include "gc.h"
53 #include "interr.h"
54 #include "monitor.h"
55 #include "validate.h"
56 #include "core.h"
57 #include "save.h"
58 #include "lispregs.h"
59 #include "thread.h"
60
61 #include "genesis/static-symbols.h"
62 #include "genesis/symbol.h"
63
64
65 #ifdef irix
66 #include <string.h>
67 #include "interr.h"
68 #endif
69
70 #ifndef SBCL_HOME
71 #define SBCL_HOME "/usr/local/lib/sbcl/"
72 #endif
73
74 \f
75 /* SIGINT handler that invokes the monitor (for when Lisp isn't up to it) */
76 static void
77 sigint_handler(int signal, siginfo_t *info, void *void_context)
78 {
79     lose("\nSIGINT hit at 0x%08lX\n",
80          (unsigned long) *os_context_pc_addr(void_context));
81 }
82
83 /* (This is not static, because we want to be able to call it from
84  * Lisp land.) */
85 void
86 sigint_init(void)
87 {
88     SHOW("entering sigint_init()");
89     install_handler(SIGINT, sigint_handler);
90     SHOW("leaving sigint_init()");
91 }
92 \f
93 /*
94  * helper functions for dealing with command line args
95  */
96
97 void *
98 successful_malloc(size_t size)
99 {
100     void* result = malloc(size);
101     if (0 == result) {
102         lose("malloc failure\n");
103     } else {
104         return result;
105     }
106     return (void *) NULL; /* dummy value: return something ... */
107 }
108
109 char *
110 copied_string(char *string)
111 {
112     return strcpy(successful_malloc(1+strlen(string)), string);
113 }
114
115 char *
116 copied_existing_filename_or_null(char *filename)
117 {
118     struct stat filename_stat;
119     if (stat(filename, &filename_stat)) { /* if failure */
120         return 0;
121     } else {
122         return copied_string(filename);
123     }
124 }
125
126 /* Convert a null-terminated array of null-terminated strings (e.g.
127  * argv or envp) into a Lisp list of Lisp base-strings. */
128 static lispobj
129 alloc_base_string_list(char *array_ptr[])
130 {
131     if (*array_ptr) {
132         return alloc_cons(alloc_base_string(*array_ptr),
133                           alloc_base_string_list(1 + array_ptr));
134     } else {
135         return NIL;
136     }
137 }
138 \f
139 /* miscellaneous chattiness */
140
141 void
142 print_help()
143 {
144     puts(
145 "SBCL is a Common Lisp programming environment. Ordinarily you shouldn't\n\
146 need command line options when you invoke it interactively: you can just\n\
147 start it and work with the customary Lisp READ-EVAL-PRINT loop.\n\
148 \n\
149 One option idiom which is sometimes useful interactively (e.g. when\n\
150 exercising a test case for a bug report) is\n\
151   sbcl --sysinit /dev/null --userinit /dev/null\n\
152 to keep SBCL from reading any initialization files at startup. And some\n\
153 people like to suppress the default startup message:\n\
154   sbcl --noinform\n\
155 \n\
156 Other options can be useful when you're running SBCL noninteractively,\n\
157 e.g. from a script, or if you have a strange system configuration, so\n\
158 that SBCL can't by default find one of the files it needs. For\n\
159 information on such options, see the sbcl(1) man page.\n\
160 \n\
161 More information on SBCL can be found on its man page, or at\n\
162 <http://sbcl.sf.net/>.\n");
163 }
164
165 void
166 print_version()
167 {
168     printf("SBCL %s\n", SBCL_VERSION_STRING);
169 }
170
171 void
172 print_banner()
173 {
174     printf(
175 "This is SBCL %s, an implementation of ANSI Common Lisp.\n\
176 More information about SBCL is available at <http://www.sbcl.org/>.\n\
177 \n\
178 SBCL is free software, provided as is, with absolutely no warranty.\n\
179 It is mostly in the public domain; some portions are provided under\n\
180 BSD-style licenses.  See the CREDITS and COPYING files in the\n\
181 distribution for more information.\n\
182 ", SBCL_VERSION_STRING);
183 }
184
185 /* Look for a core file to load, first in the directory named by the
186  * SBCL_HOME environment variable, then in a hardcoded default
187  * location.  Returns a malloced copy of the core filename. */
188 char *
189 search_for_core ()
190 {
191     char *sbcl_home = getenv("SBCL_HOME");
192     char *lookhere;
193     char *stem = "/sbcl.core";
194     char *core;
195
196     if(!sbcl_home) sbcl_home = SBCL_HOME;
197     lookhere = (char *) calloc(strlen(sbcl_home) +
198                                strlen(stem) +
199                                1,
200                                sizeof(char));
201     sprintf(lookhere, "%s%s", sbcl_home, stem);
202     core = copied_existing_filename_or_null(lookhere);
203     free(lookhere);
204     if (!core) {
205         lose("can't find core file\n");
206     }
207
208     return core;
209 }
210
211  \f
212 int
213 main(int argc, char *argv[], char *envp[])
214 {
215 #ifdef LISP_FEATURE_WIN32
216     /* Exception handling support structure. Evil Win32 hack. */
217     struct lisp_exception_frame exception_frame;
218 #endif
219
220     /* the name of the core file we're to execute. Note that this is
221      * a malloc'ed string which should be freed eventually. */
222     char *core = 0;
223     char **sbcl_argv = 0;
224     os_vm_offset_t embedded_core_offset = 0;
225
226     /* other command line options */
227     boolean noinform = 0;
228     boolean end_runtime_options = 0;
229
230     lispobj initial_function;
231
232     interrupt_init();
233     block_blockable_signals();
234
235     setlocale(LC_ALL, "");
236
237     /* KLUDGE: os_vm_page_size is set by os_init(), and on some
238      * systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so
239      * it must follow os_init(). -- WHN 2000-01-26 */
240     os_init(argv, envp);
241     arch_init();
242     gc_init();
243     validate();
244
245     /* Parse our part of the command line (aka "runtime options"),
246      * stripping out those options that we handle. */
247     {
248         int argi = 1;
249         while (argi < argc) {
250             char *arg = argv[argi];
251             if (0 == strcmp(arg, "--noinform")) {
252                 noinform = 1;
253                 ++argi;
254             } else if (0 == strcmp(arg, "--core")) {
255                 if (core) {
256                     lose("more than one core file specified\n");
257                 } else {
258                     ++argi;
259                     if (argi >= argc) {
260                         lose("missing filename for --core argument\n");
261                     }
262                     core = copied_string(argv[argi]);
263                     ++argi;
264                 }
265             } else if (0 == strcmp(arg, "--help")) {
266                 /* I think this is the (or a) usual convention: upon
267                  * seeing "--help" we immediately print our help
268                  * string and exit, ignoring everything else. */
269                 print_help();
270                 exit(0);
271             } else if (0 == strcmp(arg, "--version")) {
272                 /* As in "--help" case, I think this is expected. */
273                 print_version();
274                 exit(0);
275             } else if (0 == strcmp(arg, "--end-runtime-options")) {
276                 end_runtime_options = 1;
277                 ++argi;
278                 break;
279             } else {
280                 /* This option was unrecognized as a runtime option,
281                  * so it must be a toplevel option or a user option,
282                  * so we must be past the end of the runtime option
283                  * section. */
284                 break;
285             }
286         }
287         /* This is where we strip out those options that we handle. We
288          * also take this opportunity to make sure that we don't find
289          * an out-of-place "--end-runtime-options" option. */
290         {
291             char *argi0 = argv[argi];
292             int argj = 1;
293             /* (argc - argi) for the arguments, one for the binary,
294                and one for the terminating NULL. */
295             sbcl_argv = successful_malloc((2 + argc - argi) * sizeof(char *));
296             sbcl_argv[0] = argv[0];
297             while (argi < argc) {
298                 char *arg = argv[argi++];
299                 /* If we encounter --end-runtime-options for the first
300                  * time after the point where we had to give up on
301                  * runtime options, then the point where we had to
302                  * give up on runtime options must've been a user
303                  * error. */
304                 if (!end_runtime_options &&
305                     0 == strcmp(arg, "--end-runtime-options")) {
306                     lose("bad runtime option \"%s\"\n", argi0);
307                 }
308                 sbcl_argv[argj++] = arg;
309             }
310             sbcl_argv[argj] = 0;
311         }
312     }
313
314     /* If no core file was specified, look for one. */
315     if (!core) {
316        char *runtime_path = os_get_runtime_executable_path();
317
318        if (runtime_path) {
319           os_vm_offset_t offset = search_for_embedded_core(runtime_path);
320
321           if (offset != -1) {
322              embedded_core_offset = offset;
323              core = runtime_path;
324           } else {
325              free(runtime_path);
326              core = search_for_core();
327           }
328        } else {
329           core = search_for_core();
330        }
331     }
332
333     /* Make sure that SBCL_HOME is set, unless loading an embedded core. */
334     if (!getenv("SBCL_HOME") && embedded_core_offset == 0) {
335         char *envstring, *copied_core, *dir;
336         char *stem = "SBCL_HOME=";
337         copied_core = copied_string(core);
338         dir = dirname(copied_core);
339         envstring = (char *) calloc(strlen(stem) +
340                                     strlen(dir) +
341                                     1,
342                                     sizeof(char));
343         sprintf(envstring, "%s%s", stem, dir);
344         putenv(envstring);
345         free(copied_core);
346     }
347
348     if (!noinform) {
349         print_banner();
350         fflush(stdout);
351     }
352
353 #if defined(SVR4) || defined(__linux__)
354     tzset();
355 #endif
356
357     define_var("nil", NIL, 1);
358     define_var("t", T, 1);
359
360     set_lossage_handler(monitor_or_something);
361
362     globals_init();
363
364     initial_function = load_core_file(core, embedded_core_offset);
365     if (initial_function == NIL) {
366         lose("couldn't find initial function\n");
367     }
368
369     gc_initialize_pointers();
370
371     arch_install_interrupt_handlers();
372 #ifndef LISP_FEATURE_WIN32
373     os_install_interrupt_handlers();
374 #else
375 /*     wos_install_interrupt_handlers(handler); */
376     wos_install_interrupt_handlers(&exception_frame);
377 #endif
378
379     /* Pass core filename into Lisp */
380     SetSymbolValue(CORE_STRING, alloc_base_string(core),0);
381     SHOW("freeing core");
382     free(core);
383
384     /* Convert remaining argv values to something that Lisp can grok. */
385     SHOW("setting POSIX-ARGV symbol value");
386     SetSymbolValue(POSIX_ARGV, alloc_base_string_list(sbcl_argv),0);
387     free(sbcl_argv);
388
389     FSHOW((stderr, "/funcalling initial_function=0x%lx\n",
390           (unsigned long)initial_function));
391 #ifdef LISP_FEATURE_WIN32
392     fprintf(stderr, "\n\
393 This is experimental prerelease support for the Windows platform: use\n\
394 at your own risk.  \"Your Kitten of Death awaits!\"\n");
395     fflush(stdout);
396     fflush(stderr);
397 #endif
398     create_initial_thread(initial_function);
399     lose("CATS.  CATS ARE NICE.\n");
400     return 0;
401 }