0.7.12.24
[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 <stdio.h>
17 #include <string.h>
18 #include <sys/types.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <sys/file.h>
22 #include <sys/param.h>
23 #include <sys/stat.h>
24
25 #if defined(SVR4) || defined(__linux__)
26 #include <time.h>
27 #endif
28
29 #include "signal.h"
30
31 #include "runtime.h"
32 #include "sbcl.h"
33 #include "alloc.h"
34 #include "vars.h"
35 #include "globals.h"
36 #include "os.h"
37 #include "interrupt.h"
38 #include "arch.h"
39 #include "gc.h"
40 #include "interr.h"
41 #include "monitor.h"
42 #include "validate.h"
43 #include "core.h"
44 #include "save.h"
45 #include "lispregs.h"
46
47 #ifdef irix
48 #include <string.h>
49 #include "interr.h"
50 #endif
51 \f
52 /* SIGINT handler that invokes the monitor (for when Lisp isn't up to it) */
53 static void
54 sigint_handler(int signal, siginfo_t *info, void *void_context)
55 {
56     lose("\nSIGINT hit at 0x%08lX\n", 
57          (unsigned long) *os_context_pc_addr(void_context));
58 }
59
60 /* (This is not static, because we want to be able to call it from
61  * Lisp land.) */
62 void
63 sigint_init(void)
64 {
65     SHOW("entering sigint_init()");
66     install_handler(SIGINT, sigint_handler);
67     SHOW("leaving sigint_init()");
68 }
69 \f
70 /*
71  * helper functions for dealing with command line args
72  */
73
74 void *
75 successful_malloc(size_t size)
76 {
77     void* result = malloc(size);
78     if (0 == result) {
79         lose("malloc failure");
80     } else {
81         return result;
82     }
83     return (void *) NULL; /* dummy value: return something ... */
84 }
85
86 char *
87 copied_string(char *string)
88 {
89     return strcpy(successful_malloc(1+strlen(string)), string);
90 }
91
92 char *
93 copied_existing_filename_or_null(char *filename)
94 {
95     struct stat filename_stat;
96     if (stat(filename, &filename_stat)) { /* if failure */
97         return 0;
98     } else {
99         return copied_string(filename);
100     }
101 }
102
103 /* Convert a null-terminated array of null-terminated strings (e.g.
104  * argv or envp) into a Lisp list of Lisp strings. */
105 static lispobj
106 alloc_string_list(char *array_ptr[])
107 {
108     if (*array_ptr) {
109         return alloc_cons(alloc_string(*array_ptr),
110                           alloc_string_list(1 + array_ptr));
111     } else {
112         return NIL;
113     }
114 }
115 \f
116 /* miscellaneous chattiness */
117
118 void
119 print_help()
120 {
121     puts(
122 "SBCL is a Common Lisp programming environment. Ordinarily you shouldn't\n\
123 need command line options when you invoke it interactively: you can just\n\
124 start it and work with the customary Lisp READ-EVAL-PRINT loop.\n\
125 \n\
126 One option idiom which is sometimes useful interactively (e.g. when\n\
127 exercising a test case for a bug report) is\n\
128   sbcl --sysinit /dev/null --userinit /dev/null\n\
129 to keep SBCL from reading any initialization files at startup. And some\n\
130 people like to suppress the default startup message:\n\
131   sbcl --noinform\n\
132 \n\
133 Other options can be useful when you're running SBCL noninteractively,\n\
134 e.g. from a script, or if you have a strange system configuration, so\n\
135 that SBCL can't by default find one of the files it needs. For\n\
136 information on such options, see the sbcl(1) man page.\n\
137 \n\
138 More information on SBCL can be found on its man page, or at\n\
139 <http://sbcl.sf.net/>.\n");
140 }
141
142 void
143 print_version()
144 {
145     printf("SBCL %s\n", SBCL_VERSION_STRING);
146 }
147
148 void
149 print_banner()
150 {
151     printf(
152 "This is SBCL %s, an implementation of ANSI Common Lisp.\n\
153 \n\
154 SBCL is derived from the CMU CL system created at Carnegie Mellon University.\n\
155 Besides software and documentation originally created at Carnegie Mellon\n\
156 University, SBCL contains some software originally from the Massachusetts\n\
157 Institute of Technology, Symbolics Incorporated, and Xerox Corporation, and\n\
158 material contributed by volunteers since the release of CMU CL into the\n\
159 public domain. See the CREDITS file in the distribution for more information.\n\
160 \n\
161 SBCL is a free software system, provided as is, with absolutely no warranty.\n\
162 It is mostly in the public domain, but also includes some software copyrighted\n\
163   Massachusetts Institute of Technology, 1986;\n\
164   Symbolics, Inc., 1989, 1990, 1991, 1992; and\n\
165   Xerox Corporation, 1985, 1986, 1987, 1988, 1989, 1990\n\
166 used under BSD-style licenses allowing copying only under certain conditions.\n\
167 See the COPYING file in the distribution for more information.\n\
168 \n\
169 More information about SBCL is available at <http://sbcl.sourceforge.net/>.\n\
170 ", SBCL_VERSION_STRING);
171 }
172 \f
173 int
174 main(int argc, char *argv[], char *envp[])
175 {
176     /* the name of the core file we're to execute. Note that this is
177      * a malloc'ed string which should be freed eventually. */
178     char *core = 0;
179
180     /* other command line options */
181     boolean noinform = 0;
182     boolean end_runtime_options = 0;
183
184     lispobj initial_function;
185
186     /* KLUDGE: os_vm_page_size is set by os_init(), and on some
187      * systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so
188      * it must follow os_init(). -- WHN 2000-01-26 */
189     os_init();
190     arch_init();
191     gc_init();
192     validate();
193
194     /* Parse our part of the command line (aka "runtime options"),
195      * stripping out those options that we handle. */
196     {
197         int argi = 1;
198         while (argi < argc) {
199             char *arg = argv[argi];
200             if (0 == strcmp(arg, "--noinform")) {
201                 noinform = 1;
202                 ++argi;
203             } else if (0 == strcmp(arg, "--core")) {
204                 if (core) {
205                     lose("more than one core file specified");
206                 } else {
207                     ++argi;
208                     if (argi >= argc) {
209                         lose("missing filename for --core argument");
210                     }
211                     core = copied_string(argv[argi]);
212                     ++argi;
213                 }
214             } else if (0 == strcmp(arg, "--help")) {
215                 /* I think this is the (or a) usual convention: upon
216                  * seeing "--help" we immediately print our help
217                  * string and exit, ignoring everything else. */
218                 print_help();
219                 exit(0);
220             } else if (0 == strcmp(arg, "--version")) {
221                 /* As in "--help" case, I think this is expected. */
222                 print_version();
223                 exit(0);
224             } else if (0 == strcmp(arg, "--end-runtime-options")) {
225                 end_runtime_options = 1;
226                 ++argi;
227                 break;
228             } else {
229                 /* This option was unrecognized as a runtime option,
230                  * so it must be a toplevel option or a user option,
231                  * so we must be past the end of the runtime option
232                  * section. */
233                 break;
234             }
235         }
236         /* This is where we strip out those options that we handle. We
237          * also take this opportunity to make sure that we don't find
238          * an out-of-place "--end-runtime-options" option. */
239         {
240             char *argi0 = argv[argi];
241             int argj = 1;
242             while (argi < argc) {
243                 char *arg = argv[argi++];
244                 /* If we encounter --end-runtime-options for the first
245                  * time after the point where we had to give up on
246                  * runtime options, then the point where we had to
247                  * give up on runtime options must've been a user
248                  * error. */
249                 if (!end_runtime_options &&
250                     0 == strcmp(arg, "--end-runtime-options")) {
251                     lose("bad runtime option \"%s\"", argi0);
252                 }
253                 argv[argj++] = arg;
254             }
255             argv[argj] = 0;
256             argc = argj;
257         }
258     }
259
260     /* If no core file was specified, look for one. */
261     if (!core) {
262         char *sbcl_home = getenv("SBCL_HOME");
263         if (sbcl_home) {
264             char *lookhere;
265             char *stem = "/sbcl.core";
266             lookhere = (char *) calloc(strlen(sbcl_home) +
267                                        strlen(stem) +
268                                        1,
269                                        sizeof(char));
270             sprintf(lookhere, "%s%s", sbcl_home, stem);
271             core = copied_existing_filename_or_null(lookhere);
272             free(lookhere);
273         } else {
274             putenv("SBCL_HOME=/usr/local/lib/sbcl/");
275             core = copied_existing_filename_or_null("/usr/local/lib/sbcl/sbcl.core");
276             if (!core) {
277                 putenv("SBCL_HOME=/usr/lib/sbcl/");
278                 core =
279                     copied_existing_filename_or_null("/usr/lib/sbcl/sbcl.core");
280             }
281         }
282         if (!core) {
283             lose("can't find core file");
284         }
285     }
286
287     if (!noinform) {
288         print_banner();
289         fflush(stdout);
290     }
291
292 #ifdef MACH
293     mach_init();
294 #endif
295 #if defined(SVR4) || defined(__linux__)
296     tzset();
297 #endif
298
299     define_var("nil", NIL, 1);
300     define_var("t", T, 1);
301
302     set_lossage_handler(monitor_or_something);
303
304     globals_init();
305
306     initial_function = load_core_file(core);
307     if (initial_function == NIL) {
308         lose("couldn't find initial function");
309     }
310     SHOW("freeing core");
311     free(core);
312
313     gc_initialize_pointers();
314
315 #ifdef BINDING_STACK_POINTER
316     SetSymbolValue(BINDING_STACK_POINTER, BINDING_STACK_START);
317 #endif
318
319     interrupt_init();
320
321     arch_install_interrupt_handlers();
322     os_install_interrupt_handlers();
323
324 #ifdef PSEUDO_ATOMIC_ATOMIC
325     /* Turn on pseudo atomic for when we call into Lisp. */
326     SHOW("turning on pseudo atomic");
327     SetSymbolValue(PSEUDO_ATOMIC_ATOMIC, make_fixnum(1));
328     SetSymbolValue(PSEUDO_ATOMIC_INTERRUPTED, make_fixnum(0));
329 #endif
330
331     /* Convert remaining argv values to something that Lisp can grok. */
332     SHOW("setting POSIX-ARGV symbol value");
333     SetSymbolValue(POSIX_ARGV, alloc_string_list(argv));
334
335     /* Install a handler to pick off SIGINT until the Lisp system gets
336      * far enough along to install its own handler. */
337     sigint_init();
338
339     FSHOW((stderr, "/funcalling initial_function=0x%lx\n", initial_function));
340     funcall0(initial_function);
341
342     /* initial_function() is not supposed to return. */
343     lose("Lisp initial_function gave up control.");
344     return 0; /* dummy value: return something */
345 }
346