0.9.8.33:
[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 \f
186 int
187 main(int argc, char *argv[], char *envp[])
188 {
189 #ifdef LISP_FEATURE_WIN32
190     /* Exception handling support structure. Evil Win32 hack. */
191     struct lisp_exception_frame exception_frame;
192 #endif
193
194     /* the name of the core file we're to execute. Note that this is
195      * a malloc'ed string which should be freed eventually. */
196     char *core = 0;
197     char **sbcl_argv = 0;
198
199     /* other command line options */
200     boolean noinform = 0;
201     boolean end_runtime_options = 0;
202
203     lispobj initial_function;
204
205     interrupt_init();
206     block_blockable_signals();
207
208     setlocale(LC_ALL, "");
209
210     /* KLUDGE: os_vm_page_size is set by os_init(), and on some
211      * systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so
212      * it must follow os_init(). -- WHN 2000-01-26 */
213     os_init(argv, envp);
214     arch_init();
215     gc_init();
216     validate();
217
218     /* Parse our part of the command line (aka "runtime options"),
219      * stripping out those options that we handle. */
220     {
221         int argi = 1;
222         while (argi < argc) {
223             char *arg = argv[argi];
224             if (0 == strcmp(arg, "--noinform")) {
225                 noinform = 1;
226                 ++argi;
227             } else if (0 == strcmp(arg, "--core")) {
228                 if (core) {
229                     lose("more than one core file specified\n");
230                 } else {
231                     ++argi;
232                     if (argi >= argc) {
233                         lose("missing filename for --core argument\n");
234                     }
235                     core = copied_string(argv[argi]);
236                     ++argi;
237                 }
238             } else if (0 == strcmp(arg, "--help")) {
239                 /* I think this is the (or a) usual convention: upon
240                  * seeing "--help" we immediately print our help
241                  * string and exit, ignoring everything else. */
242                 print_help();
243                 exit(0);
244             } else if (0 == strcmp(arg, "--version")) {
245                 /* As in "--help" case, I think this is expected. */
246                 print_version();
247                 exit(0);
248             } else if (0 == strcmp(arg, "--end-runtime-options")) {
249                 end_runtime_options = 1;
250                 ++argi;
251                 break;
252             } else {
253                 /* This option was unrecognized as a runtime option,
254                  * so it must be a toplevel option or a user option,
255                  * so we must be past the end of the runtime option
256                  * section. */
257                 break;
258             }
259         }
260         /* This is where we strip out those options that we handle. We
261          * also take this opportunity to make sure that we don't find
262          * an out-of-place "--end-runtime-options" option. */
263         {
264             char *argi0 = argv[argi];
265             int argj = 1;
266             /* (argc - argi) for the arguments, one for the binary,
267                and one for the terminating NULL. */
268             sbcl_argv = successful_malloc((2 + argc - argi) * sizeof(char *));
269             sbcl_argv[0] = argv[0];
270             while (argi < argc) {
271                 char *arg = argv[argi++];
272                 /* If we encounter --end-runtime-options for the first
273                  * time after the point where we had to give up on
274                  * runtime options, then the point where we had to
275                  * give up on runtime options must've been a user
276                  * error. */
277                 if (!end_runtime_options &&
278                     0 == strcmp(arg, "--end-runtime-options")) {
279                     lose("bad runtime option \"%s\"\n", argi0);
280                 }
281                 sbcl_argv[argj++] = arg;
282             }
283             sbcl_argv[argj] = 0;
284         }
285     }
286
287     /* If no core file was specified, look for one. */
288     if (!core) {
289         char *sbcl_home = getenv("SBCL_HOME");
290         char *lookhere;
291         char *stem = "/sbcl.core";
292         if(!sbcl_home) sbcl_home = SBCL_HOME;
293         lookhere = (char *) calloc(strlen(sbcl_home) +
294                                    strlen(stem) +
295                                    1,
296                                    sizeof(char));
297         sprintf(lookhere, "%s%s", sbcl_home, stem);
298         core = copied_existing_filename_or_null(lookhere);
299         free(lookhere);
300         if (!core) {
301             lose("can't find core file\n");
302         }
303     }
304     /* Make sure that SBCL_HOME is set, no matter where the core was
305      * found */
306     if (!getenv("SBCL_HOME")) {
307         char *envstring, *copied_core, *dir;
308         char *stem = "SBCL_HOME=";
309         copied_core = copied_string(core);
310         dir = dirname(copied_core);
311         envstring = (char *) calloc(strlen(stem) +
312                                     strlen(dir) +
313                                     1,
314                                     sizeof(char));
315         sprintf(envstring, "%s%s", stem, dir);
316         putenv(envstring);
317         free(copied_core);
318     }
319
320     if (!noinform) {
321         print_banner();
322         fflush(stdout);
323     }
324
325 #if defined(SVR4) || defined(__linux__)
326     tzset();
327 #endif
328
329     define_var("nil", NIL, 1);
330     define_var("t", T, 1);
331
332     set_lossage_handler(monitor_or_something);
333
334     globals_init();
335
336     initial_function = load_core_file(core);
337     if (initial_function == NIL) {
338         lose("couldn't find initial function\n");
339     }
340     SHOW("freeing core");
341     free(core);
342
343     gc_initialize_pointers();
344
345     arch_install_interrupt_handlers();
346 #ifndef LISP_FEATURE_WIN32
347     os_install_interrupt_handlers();
348 #else
349 /*     wos_install_interrupt_handlers(handler); */
350     wos_install_interrupt_handlers(&exception_frame);
351 #endif
352
353     /* Convert remaining argv values to something that Lisp can grok. */
354     SHOW("setting POSIX-ARGV symbol value");
355     SetSymbolValue(POSIX_ARGV, alloc_base_string_list(sbcl_argv),0);
356     free(sbcl_argv);
357
358     FSHOW((stderr, "/funcalling initial_function=0x%lx\n",
359           (unsigned long)initial_function));
360 #ifdef LISP_FEATURE_WIN32
361     fprintf(stderr, "\n\
362 This is experimental prerelease support for the Windows platform: use\n\
363 at your own risk.  \"Your Kitten of Death awaits!\"\n");
364     fflush(stdout);
365     fflush(stderr);
366 #endif
367     create_initial_thread(initial_function);
368     lose("CATS.  CATS ARE NICE.\n");
369     return 0;
370 }