Add odxprint, a replacement for FSHOW which can be configured at run-time
[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 #include <ctype.h>
21 #ifndef LISP_FEATURE_WIN32
22 #include <libgen.h>
23 #endif
24 #include <sys/types.h>
25 #ifndef LISP_FEATURE_WIN32
26 #include <sys/wait.h>
27 #endif
28 #include <stdlib.h>
29 #include <unistd.h>
30 #include <sys/file.h>
31 #include <sys/param.h>
32 #include <sys/stat.h>
33 #include <signal.h>
34 #ifndef LISP_FEATURE_WIN32
35 #include <sched.h>
36 #endif
37 #include <errno.h>
38 #include <locale.h>
39 #include <limits.h>
40
41 #if defined(SVR4) || defined(__linux__)
42 #include <time.h>
43 #endif
44
45 #include "signal.h"
46
47 #include "runtime.h"
48 #include "vars.h"
49 #include "globals.h"
50 #include "os.h"
51 #include "interr.h"
52 #include "alloc.h"
53 #include "interrupt.h"
54 #include "arch.h"
55 #include "gc.h"
56 #include "validate.h"
57 #include "core.h"
58 #include "save.h"
59 #include "lispregs.h"
60 #include "thread.h"
61
62 #include "genesis/static-symbols.h"
63 #include "genesis/symbol.h"
64
65
66 #ifdef irix
67 #include <string.h>
68 #include "interr.h"
69 #endif
70
71 #ifndef SBCL_HOME
72 #define SBCL_HOME SBCL_PREFIX"/lib/sbcl/"
73 #endif
74
75 #ifdef LISP_FEATURE_HPUX
76 extern void *return_from_lisp_stub;
77 #include "genesis/closure.h"
78 #include "genesis/simple-fun.h"
79 #endif
80
81 \f
82 /* SIGINT handler that invokes the monitor (for when Lisp isn't up to it) */
83 static void
84 sigint_handler(int signal, siginfo_t *info, os_context_t *context)
85 {
86     lose("\nSIGINT hit at 0x%08lX\n",
87          (unsigned long) *os_context_pc_addr(context));
88 }
89
90 /* (This is not static, because we want to be able to call it from
91  * Lisp land.) */
92 void
93 sigint_init(void)
94 {
95     SHOW("entering sigint_init()");
96     install_handler(SIGINT, sigint_handler);
97     SHOW("leaving sigint_init()");
98 }
99 \f
100 /*
101  * helper functions for dealing with command line args
102  */
103
104 void *
105 successful_malloc(size_t size)
106 {
107     void* result = malloc(size);
108     if (0 == result) {
109         lose("malloc failure\n");
110     } else {
111         return result;
112     }
113     return (void *) NULL; /* dummy value: return something ... */
114 }
115
116 char *
117 copied_string(char *string)
118 {
119     return strcpy(successful_malloc(1+strlen(string)), string);
120 }
121
122 char *
123 copied_existing_filename_or_null(char *filename)
124 {
125     struct stat filename_stat;
126     if (stat(filename, &filename_stat)) { /* if failure */
127         return 0;
128     } else {
129         return copied_string(filename);
130     }
131 }
132
133 #ifndef LISP_FEATURE_WIN32
134 char *
135 copied_realpath(const char *pathname)
136 {
137     char *messy, *tidy;
138     size_t len;
139
140     /* realpath() supposedly can't be counted on to always return
141      * an absolute path, so we prepend the cwd to relative paths */
142     messy = NULL;
143     if (pathname[0] != '/') {
144         messy = successful_malloc(PATH_MAX + 1);
145         if (getcwd(messy, PATH_MAX + 1) == NULL) {
146             free(messy);
147             return NULL;
148         }
149         len = strlen(messy);
150         snprintf(messy + len, PATH_MAX + 1 - len, "/%s", pathname);
151     }
152
153     tidy = successful_malloc(PATH_MAX + 1);
154     if (realpath((messy ? messy : pathname), tidy) == NULL) {
155         free(messy);
156         free(tidy);
157         return NULL;
158     }
159
160     return tidy;
161 }
162 #endif /* LISP_FEATURE_WIN32 */
163 \f
164 /* miscellaneous chattiness */
165
166 void
167 print_help()
168 {
169     puts(
170 "Usage: sbcl [runtime-options] [toplevel-options] [user-options]\n\
171 Common runtime options:\n\
172   --help                     Print this message and exit.\n\
173   --version                  Print version information and exit.\n\
174   --core <filename>          Use the specified core file instead of the default.\n\
175   --dynamic-space-size <MiB> Size of reserved dynamic space in megabytes.\n\
176   --control-stack-size <MiB> Size of reserved control stack in megabytes.\n\
177 \n\
178 Common toplevel options:\n\
179   --sysinit <filename>       System-wide init-file to use instead of default.\n\
180   --userinit <filename>      Per-user init-file to use instead of default.\n\
181   --no-sysinit               Inhibit processing of any system-wide init-file.\n\
182   --no-userinit              Inhibit processing of any per-user init-file.\n\
183   --disable-debugger         Invoke sb-ext:disable-debugger.\n\
184   --noprint                  Run a Read-Eval Loop without printing results.\n\
185   --script [<filename>]      Skip #! line, disable debugger, avoid verbosity.\n\
186   --quit                     Exit with code 0 after option processing.\n\
187   --non-interactive          Sets both --quit and --disable-debugger.\n\
188 Common toplevel options that are processed in order:\n\
189   --eval <form>              Form to eval when processing this option.\n\
190   --load <filename>          File to load when processing this option.\n\
191 \n\
192 User options are not processed by SBCL. All runtime options must\n\
193 appear before toplevel options, and all toplevel options must\n\
194 appear before user options.\n\
195 \n\
196 For more information please refer to the SBCL User Manual, which\n\
197 should be installed along with SBCL, and is also available from the\n\
198 website <http://www.sbcl.org/>.\n");
199 }
200
201 void
202 print_version()
203 {
204     printf("SBCL %s\n", SBCL_VERSION_STRING);
205 }
206
207 void
208 print_banner()
209 {
210     printf(
211 "This is SBCL %s, an implementation of ANSI Common Lisp.\n\
212 More information about SBCL is available at <http://www.sbcl.org/>.\n\
213 \n\
214 SBCL is free software, provided as is, with absolutely no warranty.\n\
215 It is mostly in the public domain; some portions are provided under\n\
216 BSD-style licenses.  See the CREDITS and COPYING files in the\n\
217 distribution for more information.\n\
218 ", SBCL_VERSION_STRING);
219 }
220
221 /* Look for a core file to load, first in the directory named by the
222  * SBCL_HOME environment variable, then in a hardcoded default
223  * location.  Returns a malloced copy of the core filename. */
224 char *
225 search_for_core ()
226 {
227     char *sbcl_home = getenv("SBCL_HOME");
228     char *lookhere;
229     char *stem = "/sbcl.core";
230     char *core;
231
232     if (!(sbcl_home && *sbcl_home)) sbcl_home = SBCL_HOME;
233     lookhere = (char *) calloc(strlen(sbcl_home) +
234                                strlen(stem) +
235                                1,
236                                sizeof(char));
237     sprintf(lookhere, "%s%s", sbcl_home, stem);
238     core = copied_existing_filename_or_null(lookhere);
239
240     if (!core) {
241         lose("can't find core file at %s\n", lookhere);
242     }
243
244     free(lookhere);
245
246     return core;
247 }
248
249 /* Try to find the path to an executable from argv[0], this is only
250  * used when os_get_runtime_executable_path() returns NULL */
251 #ifdef LISP_FEATURE_WIN32
252 char *
253 search_for_executable(const char *argv0)
254 {
255     return NULL;
256 }
257 #else /* LISP_FEATURE_WIN32 */
258 char *
259 search_for_executable(const char *argv0)
260 {
261     char *search, *start, *end, *buf;
262
263     /* If argv[0] contains a slash then it's probably an absolute path
264      * or relative to the current directory, so check if it exists. */
265     if (strchr(argv0, '/') != NULL && access(argv0, F_OK) == 0)
266         return copied_realpath(argv0);
267
268     /* Bail on an absolute path which doesn't exist */
269     if (argv0[0] == '/')
270         return NULL;
271
272     /* Otherwise check if argv[0] exists relative to any directory in PATH */
273     search = getenv("PATH");
274     if (search == NULL)
275         return NULL;
276     search = copied_string(search);
277     buf = successful_malloc(PATH_MAX + 1);
278     for (start = search; (end = strchr(start, ':')) != NULL; start = end + 1) {
279         *end = '\0';
280         snprintf(buf, PATH_MAX + 1, "%s/%s", start, argv0);
281         if (access(buf, F_OK) == 0) {
282             free(search);
283             search = copied_realpath(buf);
284             free(buf);
285             return search;
286         }
287     }
288
289     free(search);
290     free(buf);
291     return NULL;
292 }
293 #endif /* LISP_FEATURE_WIN32 */
294
295 unsigned long parse_size_arg(char *arg, char *arg_name)
296 {
297   char *tail, *power_name;
298   unsigned long power, res;
299
300   res = strtoul(arg, &tail, 0);
301
302   if (arg == tail) {
303     lose("%s argument is not a number: %s", arg_name, arg);
304   } else if (tail[0]) {
305     int i, size;
306     power_name = copied_string(tail);
307     size = strlen(power_name);
308     for (i=0; i<size; i++)
309       power_name[i] = toupper(power_name[i]);
310   } else {
311     power = 20;
312     power_name = NULL;
313   }
314   if (power_name) {
315     if ((0==strcmp("KB", power_name)) ||
316         (0==strcmp("KIB", power_name))) {
317       power = 10;
318     } else if ((0==strcmp("MB", power_name)) ||
319                (0==strcmp("MIB", power_name))) {
320       power = 20;
321     } else if ((0==strcmp("GB", power_name)) ||
322                (0==strcmp("GIB", power_name))) {
323       power = 30;
324     } else {
325       lose("%s argument has an unknown suffix: %s", arg_name, tail);
326     }
327     free(power_name);
328   }
329   if ((res <= 0) ||
330       (res > (ULONG_MAX >> power))) {
331     lose("%s argument is out of range: %s", arg_name, arg);
332   }
333   res <<= power;
334   return res;
335 }
336
337 char **posix_argv;
338 char *core_string;
339
340 struct runtime_options *runtime_options;
341
342 char *saved_runtime_path = NULL;
343 \f
344 int
345 main(int argc, char *argv[], char *envp[])
346 {
347 #ifdef LISP_FEATURE_WIN32
348     /* Exception handling support structure. Evil Win32 hack. */
349     struct lisp_exception_frame exception_frame;
350 #endif
351
352     /* the name of the core file we're to execute. Note that this is
353      * a malloc'ed string which should be freed eventually. */
354     char *core = 0;
355     char **sbcl_argv = 0;
356     os_vm_offset_t embedded_core_offset = 0;
357     char *runtime_path = 0;
358
359     /* other command line options */
360     boolean noinform = 0;
361     boolean end_runtime_options = 0;
362     boolean disable_lossage_handler_p = 0;
363
364     lispobj initial_function;
365     const char *sbcl_home = getenv("SBCL_HOME");
366
367     interrupt_init();
368     block_blockable_signals(0, 0);
369
370     setlocale(LC_ALL, "");
371
372     runtime_options = NULL;
373
374     /* Save the argv[0] derived runtime path in case
375      * os_get_runtime_executable_path(1) isn't able to get an
376      * externally-usable path later on. */
377     saved_runtime_path = search_for_executable(argv[0]);
378
379     /* Check early to see if this executable has an embedded core,
380      * which also populates runtime_options if the core has runtime
381      * options */
382     runtime_path = os_get_runtime_executable_path(0);
383     if (runtime_path || saved_runtime_path) {
384         os_vm_offset_t offset = search_for_embedded_core(
385             runtime_path ? runtime_path : saved_runtime_path);
386         if (offset != -1) {
387             embedded_core_offset = offset;
388             core = (runtime_path ? runtime_path :
389                     copied_string(saved_runtime_path));
390         } else {
391             if (runtime_path)
392                 free(runtime_path);
393         }
394     }
395
396
397     /* Parse our part of the command line (aka "runtime options"),
398      * stripping out those options that we handle. */
399     if (runtime_options != NULL) {
400         dynamic_space_size = runtime_options->dynamic_space_size;
401         thread_control_stack_size = runtime_options->thread_control_stack_size;
402         sbcl_argv = argv;
403     } else {
404         int argi = 1;
405
406         runtime_options = successful_malloc(sizeof(struct runtime_options));
407
408         while (argi < argc) {
409             char *arg = argv[argi];
410             if (0 == strcmp(arg, "--script")) {
411                 /* This is both a runtime and a toplevel option. As a
412                  * runtime option, it is equivalent to --noinform.
413                  * This exits, and does not increment argi, so that
414                  * TOPLEVEL-INIT sees the option. */
415                 noinform = 1;
416                 end_runtime_options = 1;
417                 disable_lossage_handler_p = 1;
418                 lose_on_corruption_p = 1;
419                 break;
420             } else if (0 == strcmp(arg, "--noinform")) {
421                 noinform = 1;
422                 ++argi;
423             } else if (0 == strcmp(arg, "--core")) {
424                 if (core) {
425                     lose("more than one core file specified\n");
426                 } else {
427                     ++argi;
428                     if (argi >= argc) {
429                         lose("missing filename for --core argument\n");
430                     }
431                     core = copied_string(argv[argi]);
432                     ++argi;
433                 }
434             } else if (0 == strcmp(arg, "--help")) {
435                 /* I think this is the (or a) usual convention: upon
436                  * seeing "--help" we immediately print our help
437                  * string and exit, ignoring everything else. */
438                 print_help();
439                 exit(0);
440             } else if (0 == strcmp(arg, "--version")) {
441                 /* As in "--help" case, I think this is expected. */
442                 print_version();
443                 exit(0);
444             } else if (0 == strcmp(arg, "--dynamic-space-size")) {
445                 ++argi;
446                 if (argi >= argc)
447                     lose("missing argument for --dynamic-space-size");
448                   dynamic_space_size = parse_size_arg(argv[argi++], "--dynamic-space-size");
449 #               ifdef MAX_DYNAMIC_SPACE_END
450                 if (!((DYNAMIC_SPACE_START <
451                        DYNAMIC_SPACE_START+dynamic_space_size) &&
452                       (DYNAMIC_SPACE_START+dynamic_space_size <=
453                        MAX_DYNAMIC_SPACE_END)))
454                   lose("--dynamic-space-size argument %s is too large, max %lu",
455                        argv[argi-1], MAX_DYNAMIC_SPACE_END-DYNAMIC_SPACE_START);
456 #               endif
457             } else if (0 == strcmp(arg, "--control-stack-size")) {
458                 ++argi;
459                 if (argi >= argc)
460                     lose("missing argument for --control-stack-size");
461                 errno = 0;
462                 thread_control_stack_size = parse_size_arg(argv[argi++], "--control-stack-size");
463             } else if (0 == strcmp(arg, "--debug-environment")) {
464                 int n = 0;
465                 printf("; Commandline arguments:\n");
466                 while (n < argc) {
467                     printf(";  %2d: \"%s\"\n", n, argv[n]);
468                     ++n;
469                 }
470                 n = 0;
471                 printf(";\n; Environment:\n");
472                 while (ENVIRON[n]) {
473                     printf(";  %2d: \"%s\"\n", n, ENVIRON[n]);
474                     ++n;
475                 }
476                 ++argi;
477             } else if (0 == strcmp(arg, "--disable-ldb")) {
478                 disable_lossage_handler_p = 1;
479                 ++argi;
480             } else if (0 == strcmp(arg, "--lose-on-corruption")) {
481                 lose_on_corruption_p = 1;
482                 ++argi;
483             } else if (0 == strcmp(arg, "--end-runtime-options")) {
484                 end_runtime_options = 1;
485                 ++argi;
486                 break;
487             } else if (0 == strcmp(arg, "--merge-core-pages")) {
488                 ++argi;
489                 merge_core_pages = 1;
490             } else if (0 == strcmp(arg, "--no-merge-core-pages")) {
491                 ++argi;
492                 merge_core_pages = 0;
493             } else if (0 == strcmp(arg, "--default-merge-core-pages")) {
494                 ++argi;
495                 merge_core_pages = -1;
496             } else {
497                 /* This option was unrecognized as a runtime option,
498                  * so it must be a toplevel option or a user option,
499                  * so we must be past the end of the runtime option
500                  * section. */
501                 break;
502             }
503         }
504         /* This is where we strip out those options that we handle. We
505          * also take this opportunity to make sure that we don't find
506          * an out-of-place "--end-runtime-options" option. */
507         {
508             char *argi0 = argv[argi];
509             int argj = 1;
510             /* (argc - argi) for the arguments, one for the binary,
511                and one for the terminating NULL. */
512             sbcl_argv = successful_malloc((2 + argc - argi) * sizeof(char *));
513             sbcl_argv[0] = argv[0];
514             while (argi < argc) {
515                 char *arg = argv[argi++];
516                 /* If we encounter --end-runtime-options for the first
517                  * time after the point where we had to give up on
518                  * runtime options, then the point where we had to
519                  * give up on runtime options must've been a user
520                  * error. */
521                 if (!end_runtime_options &&
522                     0 == strcmp(arg, "--end-runtime-options")) {
523                     lose("bad runtime option \"%s\"\n", argi0);
524                 }
525                 sbcl_argv[argj++] = arg;
526             }
527             sbcl_argv[argj] = 0;
528         }
529     }
530
531     /* Align down to multiple of page_table page size, and to the appropriate
532      * stack alignment. */
533     dynamic_space_size &= ~(PAGE_BYTES-1);
534 #ifdef LISP_FEATURE_GENCGC
535     dynamic_space_size &= ~(GENCGC_CARD_BYTES-1);
536 #endif
537     thread_control_stack_size &= ~(CONTROL_STACK_ALIGNMENT_BYTES-1);
538
539     /* Preserve the runtime options for possible future core saving */
540     runtime_options->dynamic_space_size = dynamic_space_size;
541     runtime_options->thread_control_stack_size = thread_control_stack_size;
542
543     /* KLUDGE: os_vm_page_size is set by os_init(), and on some
544      * systems (e.g. Alpha) arch_init() needs need os_vm_page_size, so
545      * it must follow os_init(). -- WHN 2000-01-26 */
546     os_init(argv, envp);
547     dyndebug_init(); /* after os_init: do not print output before execve */
548     arch_init();
549     gc_init();
550     validate();
551
552     /* If no core file was specified, look for one. */
553     if (!core) {
554         core = search_for_core();
555     }
556
557     /* Make sure that SBCL_HOME is set and not the empty string,
558        unless loading an embedded core. */
559     if (!(sbcl_home && *sbcl_home) && embedded_core_offset == 0) {
560         char *envstring, *copied_core, *dir;
561         char *stem = "SBCL_HOME=";
562         copied_core = copied_string(core);
563         dir = dirname(copied_core);
564         envstring = (char *) calloc(strlen(stem) +
565                                     strlen(dir) +
566                                     1,
567                                     sizeof(char));
568         sprintf(envstring, "%s%s", stem, dir);
569         putenv(envstring);
570         free(copied_core);
571     }
572
573     if (!noinform && embedded_core_offset == 0) {
574         print_banner();
575         fflush(stdout);
576     }
577
578     if (embedded_core_offset == 0) {
579         /* Here we make a last attempt at recognizing an embedded core,
580          * so that a file with an embedded core is a valid argument to
581          * --core.  We take care that any decisions on special behaviour
582          * (suppressed banner, embedded options) have already been made
583          * before we reach this block, so that there is no observable
584          * difference between "embedded" and "bare" images given to
585          * --core. */
586         os_vm_offset_t offset = search_for_embedded_core(core);
587         if (offset != -1)
588             embedded_core_offset = offset;
589     }
590
591 #if defined(SVR4) || defined(__linux__) || defined(__NetBSD__)
592     tzset();
593 #endif
594
595     define_var("nil", NIL, 1);
596     define_var("t", T, 1);
597
598     if (!disable_lossage_handler_p)
599         enable_lossage_handler();
600
601     globals_init();
602
603     initial_function = load_core_file(core, embedded_core_offset);
604     if (initial_function == NIL) {
605         lose("couldn't find initial function\n");
606     }
607 #ifdef LISP_FEATURE_HPUX
608     /* -1 = CLOSURE_FUN_OFFSET, 23 = SIMPLE_FUN_CODE_OFFSET, we are
609      * not in LANGUAGE_ASSEMBLY so we cant reach them. */
610     return_from_lisp_stub = (void *) ((char *)*((unsigned long *)
611                  ((char *)initial_function + -1)) + 23);
612 #endif
613
614     gc_initialize_pointers();
615
616     arch_install_interrupt_handlers();
617 #ifndef LISP_FEATURE_WIN32
618     os_install_interrupt_handlers();
619 #else
620 /*     wos_install_interrupt_handlers(handler); */
621     wos_install_interrupt_handlers(&exception_frame);
622 #endif
623
624     /* Pass core filename and the processed argv into Lisp. They'll
625      * need to be processed further there, to do locale conversion.
626      */
627     core_string = core;
628     posix_argv = sbcl_argv;
629
630     FSHOW((stderr, "/funcalling initial_function=0x%lx\n",
631           (unsigned long)initial_function));
632 #ifdef LISP_FEATURE_WIN32
633     fprintf(stderr, "\n\
634 This is experimental prerelease support for the Windows platform: use\n\
635 at your own risk.  \"Your Kitten of Death awaits!\"\n");
636     fflush(stdout);
637     fflush(stderr);
638 #endif
639     create_initial_thread(initial_function);
640     lose("CATS.  CATS ARE NICE.\n");
641     return 0;
642 }