1 /* Fully extensible Emacs, running on Unix, intended for GNU.
2    Copyright (C) 1985, 1986, 1987, 1990 Free Software Foundation, Inc.
3 
4 This file is part of GNU Emacs.
5 
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 1, or (at your option)
9 any later version.
10 
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING.  If not, write to
18 the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
19 
20 
21 #include <signal.h>
22 #include <errno.h>
23 
24 #include "config.h"
25 #include <stdio.h>
26 #undef NULL
27 #include "lisp.h"
28 #include "commands.h"
29 
30 #include <sys/types.h>
31 #include <sys/file.h>
32 
33 #ifdef VMS
34 #include <ssdef.h>
35 #endif
36 
37 #ifdef USG5
38 #include <fcntl.h>
39 #endif
40 
41 #ifdef BSD
42 #include <sys/ioctl.h>
43 #endif
44 
45 #ifdef APOLLO
46 #ifndef APOLLO_SR10
47 #include <default_acl.h>
48 #endif
49 #endif
50 
51 #ifndef O_RDWR
52 #define O_RDWR 2
53 #endif
54 
55 #define PRIO_PROCESS 0
56 
57 /* Command line args from shell, as list of strings */
58 Lisp_Object Vcommand_line_args;
59 
60 /* Hook run by `kill-emacs' before it does really anything.  */
61 Lisp_Object Vkill_emacs_hook;
62 
63 /* Set nonzero after Emacs has started up the first time.
64   Prevents reinitialization of the Lisp world and keymaps
65   on subsequent starts.  */
66 int initialized;
67 
68 /* Variable whose value is symbol giving operating system type */
69 Lisp_Object Vsystem_type;
70 
71 /* If non-zero, emacs should not attempt to use an window-specific code,
72    but instead should use the virtual terminal under which it was started */
73 int inhibit_window_system;
74 
75 #ifdef HAVE_X_WINDOWS
76 /* If -d option is used, this variable points to the name of
77    the display to use.  */
78 char *alternate_display;
79 char **xargv;
80 int xargc;
81 #endif /* HAVE_X_WINDOWS */
82 
83 #ifdef USG_SHARED_LIBRARIES
84 /* If nonzero, this is the place to put the end of the writable segment
85    at startup.  */
86 
87 unsigned int bss_end = 0;
88 #endif
89 
90 /* Nonzero means running Emacs without interactive terminal.  */
91 
92 int noninteractive;
93 
94 /* Value of Lisp variable `noninteractive'.
95    Normally same as C variable `noninteractive'
96    but nothing terrible happens if user sets this one.  */
97 
98 int noninteractive1;
99 
100 /* Signal code for the fatal signal that was received */
101 int fatal_error_code;
102 
103 /* Nonzero if handling a fatal error already */
104 int fatal_error_in_progress;
105 
106 /* Handle bus errors, illegal instruction, etc. */
107 fatal_error_signal (sig)
108      int sig;
109 {
110 #ifdef BSD
111   int tpgrp;
112 #endif /* BSD */
113 
114   fatal_error_code = sig;
115   signal (sig, SIG_DFL);
116 
117   /* If fatal error occurs in code below, avoid infinite recursion.  */
118   if (fatal_error_in_progress)
119     kill (getpid (), fatal_error_code);
120 
121   fatal_error_in_progress = 1;
122 
123   /* If we are controlling the terminal, reset terminal modes */
124 #ifdef BSD
125   if (ioctl(0, TIOCGPGRP, &tpgrp) == 0
126       && tpgrp == getpgrp (0))
127 #endif /* BSD */
128     {
129       reset_sys_modes ();
130       if (sig != SIGTERM)
131 	fprintf (stderr, "Fatal error (%d).", sig);
132     }
133 
134   /* Clean up */
135 #ifdef subprocesses
136   kill_buffer_processes (Qnil);
137 #endif
138   Fdo_auto_save (Qt);
139 
140 #ifdef CLASH_DETECTION
141   unlock_all_files ();
142 #endif /* CLASH_DETECTION */
143 
144 #ifdef VMS
145   kill_vms_processes ();
146   LIB$STOP (SS$_ABORT);
147 #else
148   /* Signal the same code; this time it will really be fatal.  */
149   kill (getpid (), fatal_error_code);
150 #endif /* not VMS */
151 }
152 
153 /* Code for dealing with Lisp access to the Unix command line */
154 
155 static
156 init_cmdargs (argc, argv, skip_args)
157      int argc;
158      char **argv;
159      int skip_args;
160 {
161   register int i;
162 
163   Vcommand_line_args = Qnil;
164 
165   for (i = argc - 1; i >= 0; i--)
166     {
167       if (i == 0 || i > skip_args)
168 	Vcommand_line_args
169 	  = Fcons (build_string (argv[i]), Vcommand_line_args);
170     }
171 }
172 
173 #ifdef VMS
174 #ifdef LINK_CRTL_SHARE
175 #ifdef SHAREABLE_LIB_BUG
176 extern noshare char **environ;
177 #endif /* SHAREABLE_LIB_BUG */
178 #endif /* LINK_CRTL_SHARE */
179 #endif /* VMS */
180 
181 /* We don't include crtbegin.o and crtend.o in the link,
182    so these functions and variables might be missed.
183    Provide dummy definitions to avoid error.
184    (We don't have any real constructors or destructors.)  */
185 #ifdef __GNUC__
186 #ifndef ORDINARY_LINK
187 __do_clobal_ctors ()
188 {}
189 __do_clobal_ctors_aux ()
190 {}
191 __do_global_dtors ()
192 {}
193 char * __CTOR_LIST__[2] = { (char *) (-1), 0 };
194 char * __DTOR_LIST__[2] = { (char *) (-1), 0 };
195 __main ()
196 {}
197 #endif /* not ORDINARY_LINK */
198 #endif /* __GNUC__ */
199 
200 /* ARGSUSED */
201 main (argc, argv, envp)
202      int argc;
203      char **argv;
204      char **envp;
205 {
206   int skip_args = 0;
207   extern int errno;
208   extern void malloc_warning ();
209 
210 /* Map in shared memory, if we are using that.  */
211 #ifdef HAVE_SHM
212   if (argc > 1 && !strcmp (argv[1], "-nl"))
213     {
214       map_in_data (0);
215       /* The shared momory was just restored, which clobbered this.  */
216       skip_args = 1;
217     }
218   else
219     {
220       map_in_data (1);
221       /* The shared momory was just restored, which clobbered this.  */
222       skip_args = 0;
223     }
224 #endif
225 
226 #ifdef VMS
227   /* If -map specified, map the data file in */
228   if (argc > 2 && ! strcmp (argv[1], "-map"))
229     {
230       skip_args = 2;
231       mapin_data (argv[2]);
232     }
233 
234 #ifdef LINK_CRTL_SHARE
235 #ifdef SHAREABLE_LIB_BUG
236   /* Bletcherous shared libraries! */
237   if (!stdin)
238     stdin = fdopen (0, "r");
239   if (!stdout)
240     stdout = fdopen (1, "w");
241   if (!stderr)
242     stderr = fdopen (2, "w");
243   if (!environ)
244     environ = envp;
245 #endif /* SHAREABLE_LIB_BUG */
246 #endif /* LINK_CRTL_SHARE */
247 #endif /* VMS */
248 
249 #ifdef USG_SHARED_LIBRARIES
250   if (bss_end)
251     brk (bss_end);
252 #endif
253 
254   clearerr (stdin);
255 
256 #ifdef APOLLO
257 #ifndef APOLLO_SR10
258   /* If USE_DOMAIN_ACLS environment variable exists,
259      use ACLs rather than UNIX modes. */
260   if (egetenv ("USE_DOMAIN_ACLS"))
261     default_acl (USE_DEFACL);
262 #endif
263 #endif /* APOLLO */
264 
265 #ifndef SYSTEM_MALLOC
266   /* Arrange for warnings when nearly out of space.  */
267   malloc_init (0, malloc_warning);
268 #endif
269 
270 #ifdef HIGHPRI
271   setpriority (PRIO_PROCESS, getpid (), HIGHPRI);
272   setuid (getuid ());
273 #endif HIGHPRI
274 
275   inhibit_window_system = 0;
276 
277 #ifdef HAVE_X_WINDOWS
278   xargv = argv;
279   xargc = argc;
280 #endif
281 
282 /* Handle the -t switch, which specifies filename to use as terminal */
283   if (skip_args + 2 < argc && !strcmp (argv[skip_args + 1], "-t"))
284     {
285       skip_args += 2;
286       close (0);
287       close (1);
288       open (argv[skip_args], O_RDWR, 2 );
289       dup (0);
290       fprintf (stderr, "Using %s\n", argv[skip_args]);
291 #ifdef HAVE_X_WINDOWS
292       inhibit_window_system = 1;	/* -t => -nw */
293 #endif
294     }
295 #ifdef HAVE_X_WINDOWS
296 /* Handle the -d switch, which means use a different display for X */
297   if (skip_args + 2 < argc && (!strcmp (argv[skip_args + 1], "-d") ||
298 			       !strcmp (argv[skip_args + 1], "-display")))
299     {
300       skip_args += 2;
301       alternate_display = argv[skip_args];
302     }
303   else
304     alternate_display = 0;
305 #endif	/* HAVE_X_WINDOWS */
306 
307   if (skip_args + 1 < argc
308       && (!strcmp (argv[skip_args + 1], "-nw")))
309     {
310       skip_args += 1;
311       inhibit_window_system = 1;
312     }
313 
314 /* Handle the -batch switch, which means don't do interactive display.  */
315   noninteractive = 0;
316   if (skip_args + 1 < argc && !strcmp (argv[skip_args + 1], "-batch"))
317     {
318       skip_args += 1;
319       noninteractive = 1;
320     }
321 
322   if (
323 #ifndef CANNOT_DUMP
324       ! noninteractive || initialized
325 #else
326       1
327 #endif
328       )
329     {
330       /* Don't catch these signals in batch mode if not initialized.
331 	 On some machines, this sets static data that would make
332 	 signal fail to work right when the dumped Emacs is run.  */
333       signal (SIGHUP, fatal_error_signal);
334       signal (SIGQUIT, fatal_error_signal);
335       signal (SIGILL, fatal_error_signal);
336       signal (SIGTRAP, fatal_error_signal);
337       signal (SIGIOT, fatal_error_signal);
338 #ifdef SIGEMT
339       signal (SIGEMT, fatal_error_signal);
340 #endif
341       signal (SIGFPE, fatal_error_signal);
342       signal (SIGBUS, fatal_error_signal);
343       signal (SIGSEGV, fatal_error_signal);
344       signal (SIGSYS, fatal_error_signal);
345       signal (SIGTERM, fatal_error_signal);
346 #ifdef SIGXCPU
347       signal (SIGXCPU, fatal_error_signal);
348 #endif
349 #ifdef SIGXFSZ
350       signal (SIGXFSZ, fatal_error_signal);
351 #endif SIGXFSZ
352 
353 #ifdef AIX
354       signal (SIGDANGER, fatal_error_signal);
355       signal (20, fatal_error_signal);
356       signal (21, fatal_error_signal);
357       signal (22, fatal_error_signal);
358       signal (23, fatal_error_signal);
359       signal (24, fatal_error_signal);
360       signal (SIGAIO, fatal_error_signal);
361       signal (SIGPTY, fatal_error_signal);
362       signal (SIGIOINT, fatal_error_signal);
363       signal (SIGGRANT, fatal_error_signal);
364       signal (SIGRETRACT, fatal_error_signal);
365       signal (SIGSOUND, fatal_error_signal);
366       signal (SIGMSG, fatal_error_signal);
367 #endif /* AIX */
368     }
369 
370   noninteractive1 = noninteractive;
371 
372 /* Perform basic initializations (not merely interning symbols) */
373 
374   if (!initialized)
375     {
376       init_alloc_once ();
377       init_obarray ();
378       init_eval_once ();
379       init_syntax_once ();	/* Create standard syntax table.  */
380 		      /* Must be done before init_buffer */
381       init_buffer_once ();	/* Create buffer table and some buffers */
382       init_minibuf_once ();	/* Create list of minibuffers */
383 			      /* Must precede init_window_once */
384       init_window_once ();	/* Init the window system */
385     }
386 
387   init_alloc ();
388 #ifdef MAINTAIN_ENVIRONMENT
389   init_environ ();
390 #endif
391   init_eval ();
392   init_data ();
393   init_read ();
394 
395   init_cmdargs (argc, argv, skip_args);	/* Create list Vcommand_line_args */
396   init_buffer ();	/* Init default directory of main buffer */
397   if (!noninteractive)
398     {
399 #ifdef VMS
400       init_vms_input ();/* init_display calls get_screen_size, that needs this */
401 #endif /* VMS */
402       init_display ();	/* Determine terminal type.  init_sys_modes uses results */
403     }
404   init_keyboard ();	/* This too must precede init_sys_modes */
405   init_callproc ();	/* And this too. */
406   init_sys_modes ();	/* Init system terminal modes (RAW or CBREAK, etc.) */
407   init_xdisp ();
408   init_macros ();
409   init_editfns ();
410 #ifdef VMS
411   init_vmsfns ();
412 #endif /* VMS */
413 #ifdef subprocesses
414   init_process ();
415 #endif /* subprocesses */
416 
417 /* Intern the names of all standard functions and variables; define standard keys */
418 
419   if (!initialized)
420     {
421       /* The basic levels of Lisp must come first */
422       /* And data must come first of all
423 	 for the sake of symbols like error-message */
424       syms_of_data ();
425       syms_of_alloc ();
426 #ifdef MAINTAIN_ENVIRONMENT
427       syms_of_environ ();
428 #endif MAINTAIN_ENVIRONMENT
429       syms_of_read ();
430       syms_of_print ();
431       syms_of_eval ();
432       syms_of_fns ();
433 
434       syms_of_abbrev ();
435       syms_of_buffer ();
436       syms_of_bytecode ();
437       syms_of_callint ();
438       syms_of_casefiddle ();
439       syms_of_callproc ();
440       syms_of_cmds ();
441 #ifndef NO_DIR_LIBRARY
442       syms_of_dired ();
443 #endif /* not NO_DIR_LIBRARY */
444       syms_of_display ();
445       syms_of_doc ();
446       syms_of_editfns ();
447       syms_of_emacs ();
448       syms_of_fileio ();
449 #ifdef CLASH_DETECTION
450       syms_of_filelock ();
451 #endif /* CLASH_DETECTION */
452       syms_of_indent ();
453       syms_of_keyboard ();
454       syms_of_keymap ();
455       syms_of_macros ();
456       syms_of_marker ();
457       syms_of_minibuf ();
458       syms_of_mocklisp ();
459 #ifdef subprocesses
460       syms_of_process ();
461 #endif /* subprocesses */
462       syms_of_search ();
463       syms_of_syntax ();
464       syms_of_undo ();
465       syms_of_window ();
466       syms_of_xdisp ();
467 #ifdef HAVE_X_WINDOWS
468       syms_of_xfns ();
469 #ifdef HAVE_X_MENU
470       syms_of_xmenu ();
471 #endif /* HAVE_X_MENU */
472 #endif /* HAVE_X_WINDOWS */
473 
474 #ifdef SYMS_SYSTEM
475       SYMS_SYSTEM;
476 #endif
477 
478 #ifdef SYMS_MACHINE
479       SYMS_MACHINE;
480 #endif
481 
482       keys_of_casefiddle ();
483       keys_of_cmds ();
484       keys_of_buffer ();
485       keys_of_keyboard ();
486       keys_of_keymap ();
487       keys_of_macros ();
488       keys_of_minibuf ();
489       keys_of_window ();
490     }
491 
492   if (!initialized)
493     {
494       /* Handle -l loadup-and-dump, args passed by Makefile. */
495       if (argc > 2 + skip_args && !strcmp (argv[1 + skip_args], "-l"))
496 	Vtop_level = Fcons (intern ("load"),
497 			    Fcons (build_string (argv[2 + skip_args]), Qnil));
498 #ifdef CANNOT_DUMP
499       /* Unless next switch is -nl, load "loadup.el" first thing.  */
500       if (!(argc > 1 + skip_args && !strcmp (argv[1 + skip_args], "-nl")))
501 	Vtop_level = Fcons (intern ("load"),
502 			    Fcons (build_string ("loadup.el"), Qnil));
503 #endif /* CANNOT_DUMP */
504     }
505 
506   initialized = 1;
507 
508   /* Enter editor command loop.  This never returns.  */
509   Frecursive_edit ();
510   /* NOTREACHED */
511 }
512 
513 DEFUN ("kill-emacs", Fkill_emacs, Skill_emacs, 0, 1, "P",
514   "Exit the Emacs job and kill it.  ARG means no query.\n\
515 If emacs is running noninteractively and ARG is an integer,\n\
516 return ARG as the exit program code.")
517   (arg)
518      Lisp_Object arg;
519 {
520   Lisp_Object answer;
521   int i;
522   struct gcpro gcpro1;
523 
524   GCPRO1 (arg);
525 
526   if (!NULL (Vkill_emacs_hook))
527     call0 (Vkill_emacs_hook);
528 
529   if (feof (stdin))
530     arg = Qt;
531 
532 #ifdef subprocesses
533   kill_buffer_processes (Qnil);
534 #endif /* subprocesses */
535 
536 #ifdef VMS
537   kill_vms_processes ();
538 #endif /* VMS */
539 
540   Fdo_auto_save (Qt);
541 
542 #ifdef CLASH_DETECTION
543   unlock_all_files ();
544 #endif /* CLASH_DETECTION */
545 
546   fflush (stdout);
547   reset_sys_modes ();
548   UNGCPRO;
549 
550 /* Is it really necessary to do this deassign
551    when we are going to exit anyway?  */
552 /* #ifdef VMS
553   stop_vms_input ();
554  #endif  */
555   stuff_buffered_input (arg);
556 #ifdef SIGIO
557   /* There is a tendency for a SIGIO signal to arrive within exit,
558      and cause a SIGHUP because the input descriptor is already closed.  */
559   unrequest_sigio ();
560   signal (SIGIO, SIG_IGN);
561 #endif
562   exit ((XTYPE (arg) == Lisp_Int) ? XINT (arg)
563 #ifdef VMS
564 	: 1
565 #else
566 	: 0
567 #endif
568 	);
569   /* NOTREACHED */
570 }
571 
572 #ifndef CANNOT_DUMP
573 /* Nothing like this can be implemented on an Apollo.
574    What a loss!  */
575 
576 #ifdef HAVE_SHM
577 
578 DEFUN ("dump-emacs-data", Fdump_emacs_data, Sdump_emacs_data, 1, 1, 0,
579   "Dump current state of Emacs into data file FILENAME.\n\
580 This function exists on systems that use HAVE_SHM.")
581   (intoname)
582      Lisp_Object intoname;
583 {
584   extern int my_edata;
585   Lisp_Object tem;
586   extern void malloc_warning ();
587 
588   CHECK_STRING (intoname, 0);
589   intoname = Fexpand_file_name (intoname, Qnil);
590 
591   tem = Vpurify_flag;
592   Vpurify_flag = Qnil;
593 
594   fflush (stdout);
595   /* Tell malloc where start of impure now is */
596   /* Also arrange for warnings when nearly out of space.  */
597 #ifndef SYSTEM_MALLOC
598   malloc_init (&my_edata, malloc_warning);
599 #endif
600   map_out_data (XSTRING (intoname)->data);
601 
602   Vpurify_flag = tem;
603 
604   return Qnil;
605 }
606 
607 #else /* not HAVE_SHM */
608 
609 DEFUN ("dump-emacs", Fdump_emacs, Sdump_emacs, 2, 2, 0,
610   "Dump current state of Emacs into executable file FILENAME.\n\
611 Take symbols from SYMFILE (presumably the file you executed to run Emacs).")
612   (intoname, symname)
613      Lisp_Object intoname, symname;
614 {
615   extern int my_edata;
616   Lisp_Object tem;
617   extern void malloc_warning ();
618 
619   CHECK_STRING (intoname, 0);
620   intoname = Fexpand_file_name (intoname, Qnil);
621   if (!NULL (symname))
622     {
623       CHECK_STRING (symname, 0);
624       if (XSTRING (symname)->size)
625 	symname = Fexpand_file_name (symname, Qnil);
626     }
627 
628   tem = Vpurify_flag;
629   Vpurify_flag = Qnil;
630 
631   fflush (stdout);
632 #ifdef VMS
633   mapout_data (XSTRING (intoname)->data);
634 #else
635   /* Tell malloc where start of impure now is */
636   /* Also arrange for warnings when nearly out of space.  */
637 #ifndef SYSTEM_MALLOC
638   malloc_init (&my_edata, malloc_warning);
639 #endif
640   unexec (XSTRING (intoname)->data,
641 	  !NULL (symname) ? XSTRING (symname)->data : 0, &my_edata, 0, 0);
642 #endif /* not VMS */
643 
644   Vpurify_flag = tem;
645 
646   return Qnil;
647 }
648 
649 #endif /* not HAVE_SHM */
650 
651 #endif /* not CANNOT_DUMP */
652 
653 #ifdef VMS
654 #define SEPCHAR ','
655 #else
656 #define SEPCHAR ':'
657 #endif
658 
659 Lisp_Object
660 decode_env_path (evarname, defalt)
661      char *evarname, *defalt;
662 {
663   register char *path, *p;
664   extern char *index ();
665 
666   Lisp_Object lpath;
667 
668   path = (char *) egetenv (evarname);
669   if (!path)
670     path = defalt;
671   lpath = Qnil;
672   while (1)
673     {
674       p = index (path, SEPCHAR);
675       if (!p) p = path + strlen (path);
676       lpath = Fcons (p - path ? make_string (path, p - path) : Qnil,
677 		     lpath);
678       if (*p)
679 	path = p + 1;
680       else
681 	break;
682     }
683   return Fnreverse (lpath);
684 }
685 
686 syms_of_emacs ()
687 {
688 #ifndef CANNOT_DUMP
689 #ifdef HAVE_SHM
690   defsubr (&Sdump_emacs_data);
691 #else
692   defsubr (&Sdump_emacs);
693 #endif
694 #endif /* not CANNOT_DUMP */
695 
696   defsubr (&Skill_emacs);
697 
698   DEFVAR_LISP ("command-line-args", &Vcommand_line_args,
699     "Args passed by shell to Emacs, as a list of strings.");
700 
701   DEFVAR_LISP ("system-type", &Vsystem_type,
702     "Symbol indicating type of operating system you are using.");
703   Vsystem_type = intern (SYSTEM_TYPE);
704 
705   DEFVAR_BOOL ("noninteractive", &noninteractive1,
706     "Non-nil means Emacs is running without interactive terminal.");
707 
708   Vkill_emacs_hook = Qnil;
709 
710   DEFVAR_LISP ("kill-emacs-hook", &Vkill_emacs_hook,
711     "Function called, if non-nil, whenever kill-emacs is called.");
712 }
713