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