(main): Close daemon_pipe on exec.
[bpt/emacs.git] / src / emacs.c
index 88ec487..bd733da 100644 (file)
@@ -27,10 +27,6 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <sys/types.h>
 #include <sys/file.h>
 
-#ifdef VMS
-#include <ssdef.h>
-#endif
-
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -135,6 +131,9 @@ Lisp_Object Vinvocation_directory;
    nil means get them only from PATH_LOADSEARCH.  */
 Lisp_Object Vinstallation_directory;
 
+/* The values of `current-time' before and after Emacs initialization.  */
+Lisp_Object Vbefore_init_time, Vafter_init_time;
+
 /* Hook run by `kill-emacs' before it does really anything.  */
 Lisp_Object Vkill_emacs_hook;
 
@@ -213,8 +212,8 @@ static void *my_heap_start;
 /* The gap between BSS end and heap start as far as we can tell.  */
 static unsigned long heap_bss_diff;
 
-/* If the gap between BSS end and heap start is larger than this we try to
-   work around it, and if that fails, output a warning in dump-emacs.  */
+/* If the gap between BSS end and heap start is larger than this
+   output a warning in dump-emacs.  */
 #define MAX_HEAP_BSS_DIFF (1024*1024)
 
 
@@ -236,6 +235,13 @@ int noninteractive;
 
 int noninteractive1;
 
+/* Name for the server started by the daemon.*/
+static char *daemon_name;
+
+/* Pipe used to send exit notification to the daemon parent at
+   startup.  */
+int daemon_pipe[2];
+
 /* Save argv and argc.  */
 char **initial_argv;
 int initial_argc;
@@ -258,6 +264,7 @@ read the main documentation for these command-line arguments.\n\
 Initialization options:\n\
 \n\
 --batch                     do not do interactive display; implies -q\n\
+--daemon                    start a server in the background\n\
 --debug-init                enable Emacs Lisp debugger for init file\n\
 --display, -d DISPLAY       use X server DISPLAY\n\
 --multibyte, --no-unibyte   inhibit the effect of EMACS_UNIBYTE\n\
@@ -278,8 +285,8 @@ Initialization options:\n\
 Action options:\n\
 \n\
 FILE                    visit FILE using find-file\n\
-+LINE                  go to line LINE in next FILE\n\
-+LINE:COLUMN           go to line LINE, column COLUMN, in next FILE\n\
++LINE                   go to line LINE in next FILE\n\
++LINE:COLUMN            go to line LINE, column COLUMN, in next FILE\n\
 --directory, -L DIR     add DIR to variable load-path\n\
 --eval EXPR             evaluate Emacs Lisp expression EXPR\n\
 --execute EXPR          evaluate Emacs Lisp expression EXPR\n\
@@ -351,8 +358,8 @@ int fatal_error_in_progress;
 void (*fatal_error_signal_hook) P_ ((void));
 
 #ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
-/* When compiled with GTK and running under Gnome, or Carbon under Mac
-   OS X, multiple threads may be created.  Keep track of our main
+/* When compiled with GTK and running under Gnome,
+   multiple threads may be created.  Keep track of our main
    thread to make sure signals are delivered to it (see syssignal.h).  */
 
 pthread_t main_thread;
@@ -378,9 +385,6 @@ fatal_error_signal (sig)
       shut_down_emacs (sig, 0, Qnil);
     }
 
-#ifdef VMS
-  LIB$STOP (SS$_ABORT);
-#else
   /* Signal the same code; this time it will really be fatal.
      Remember that since we're in a signal handler, the signal we're
      going to send is probably blocked, so we have to unblock it if we
@@ -393,7 +397,6 @@ fatal_error_signal (sig)
     fatal_error_signal_hook ();
 
   kill (getpid (), fatal_error_code);
-#endif /* not VMS */
 }
 
 #ifdef SIGDANGER
@@ -591,14 +594,6 @@ DEFUN ("invocation-directory", Finvocation_directory, Sinvocation_directory,
 }
 
 \f
-#ifdef VMS
-#ifdef LINK_CRTL_SHARE
-#ifdef SHARABLE_LIB_BUG
-extern noshare char **environ;
-#endif /* SHARABLE_LIB_BUG */
-#endif /* LINK_CRTL_SHARE */
-#endif /* VMS */
-
 #ifdef HAVE_TZSET
 /* A valid but unlikely value for the TZ environment value.
    It is OK (though a bit slower) if the user actually chooses this value.  */
@@ -785,16 +780,7 @@ bug_reporting_address ()
 
 /* ARGSUSED */
 int
-main (argc, argv
-#ifdef VMS
-, envp
-#endif
-)
-     int argc;
-     char **argv;
-#ifdef VMS
-     char **envp;
-#endif
+main (int argc, char **argv)
 {
 #if GC_MARK_STACK
   Lisp_Object dummy;
@@ -810,6 +796,7 @@ main (argc, argv
 #endif
   int no_loadup = 0;
   char *junk = 0;
+  char *dname_arg = 0;
 
 #if GC_MARK_STACK
   extern Lisp_Object *stack_base;
@@ -827,7 +814,8 @@ main (argc, argv
       heap_bss_diff = (char *)my_heap_start - max (my_endbss, my_endbss_static);
     }
 
-#if defined(GNU_LINUX) && __GNU_LIBRARY__ - 0 < 6
+#ifdef LINUX_SBRK_BUG
+  /* This is only used GNU/LINUX running on alpha when using libc5 */
   __sbrk (1);
 #endif
 
@@ -836,7 +824,8 @@ main (argc, argv
     run_time_remap (argv[0]);
 #endif
 
-#if defined (MAC_OSX) || defined (NS_IMPL_COCOA)
+/* If using unexmacosx.c (set by s/darwin.h), we must do this. */
+#ifdef DARWIN_OS
   if (!initialized)
     unexec_init_emacs_zone ();
 #endif
@@ -877,29 +866,24 @@ main (argc, argv
     }
 
 #ifdef HAVE_PERSONALITY_LINUX32
-  /* See if there is a gap between the end of BSS and the heap.
-     In that case, set personality and exec ourself again.  */
   if (!initialized
       && (strcmp (argv[argc-1], "dump") == 0
           || strcmp (argv[argc-1], "bootstrap") == 0)
-      && heap_bss_diff > MAX_HEAP_BSS_DIFF)
+      && ! getenv ("EMACS_HEAP_EXEC"))
     {
-      if (! getenv ("EMACS_HEAP_EXEC"))
-        {
-          /* Set this so we only do this once.  */
-          putenv("EMACS_HEAP_EXEC=true");
+      /* Set this so we only do this once.  */
+      putenv("EMACS_HEAP_EXEC=true");
 
-         /* A flag to turn off address randomization which is introduced
-          in linux kernel shipped with fedora core 4 */
+      /* A flag to turn off address randomization which is introduced
+         in linux kernel shipped with fedora core 4 */
 #define ADD_NO_RANDOMIZE 0x0040000
-         personality (PER_LINUX32 | ADD_NO_RANDOMIZE);
+      personality (PER_LINUX32 | ADD_NO_RANDOMIZE);
 #undef  ADD_NO_RANDOMIZE
 
-          execvp (argv[0], argv);
+      execvp (argv[0], argv);
 
-          /* If the exec fails, try to dump anyway.  */
-          perror ("execvp");
-        }
+      /* If the exec fails, try to dump anyway.  */
+      perror ("execvp");
     }
 #endif /* HAVE_PERSONALITY_LINUX32 */
 
@@ -920,42 +904,6 @@ main (argc, argv
     }
 #endif
 
-#ifdef MAC_OSX
-  /* Skip process serial number passed in the form -psn_x_y as
-     command-line argument.  The WindowServer adds this option when
-     Emacs is invoked from the Finder or by the `open' command.  In
-     these cases, the working directory becomes `/', so we change it
-     to the user's home directory.  */
-  if (argc > skip_args + 1 && strncmp (argv[skip_args+1], "-psn_", 5) == 0)
-    {
-      chdir (getenv ("HOME"));
-      skip_args++;
-    }
-#endif /* MAC_OSX */
-
-#ifdef VMS
-  /* If -map specified, map the data file in.  */
-  {
-    char *file;
-    if (argmatch (argv, argc, "-map", "--map-data", 3, &file, &skip_args))
-      mapin_data (file);
-  }
-
-#ifdef LINK_CRTL_SHARE
-#ifdef SHARABLE_LIB_BUG
-  /* Bletcherous shared libraries!  */
-  if (!stdin)
-    stdin = fdopen (0, "r");
-  if (!stdout)
-    stdout = fdopen (1, "w");
-  if (!stderr)
-    stderr = fdopen (2, "w");
-  if (!environ)
-    environ = envp;
-#endif /* SHARABLE_LIB_BUG */
-#endif /* LINK_CRTL_SHARE */
-#endif /* VMS */
-
 #if defined (HAVE_SETRLIMIT) && defined (RLIMIT_STACK)
   /* Extend the stack space available.
      Don't do that if dumping, since some systems (e.g. DJGPP)
@@ -1127,6 +1075,87 @@ main (argc, argv
       exit (0);
     }
 
+  if (argmatch (argv, argc, "-daemon", "--daemon", 5, NULL, &skip_args)
+      || argmatch (argv, argc, "-daemon", "--daemon", 5, &dname_arg, &skip_args))
+    {
+#ifndef DOS_NT
+      pid_t f;
+
+      /* Start as a daemon: fork a new child process which will run the
+        rest of the initialization code, then exit.
+
+        Detaching a daemon requires the following steps:
+        - fork
+        - setsid
+        - exit the parent
+        - close the tty file-descriptors
+
+        We only want to do the last 2 steps once the daemon is ready to
+        serve requests, i.e. after loading .emacs (initialization).
+        OTOH initialization may start subprocesses (e.g. ispell) and these
+        should be run from the proper process (the one that will end up
+        running as daemon) and with the proper "session id" in order for
+        them to keep working after detaching, so fork and setsid need to be
+        performed before initialization.
+
+        We want to avoid exiting before the server socket is ready, so
+        use a pipe for synchronization.  The parent waits for the child
+        to close its end of the pipe (using `daemon-initialized')
+        before exiting.  */
+      if (pipe (daemon_pipe) == -1)
+       {
+         fprintf (stderr, "Cannot pipe!\n");
+         exit (1);
+       }
+
+      f = fork ();
+      if (f > 0)
+       {
+         int retval;
+         char buf[1];
+
+         /* Close unused writing end of the pipe.  */
+         close (daemon_pipe[1]);
+
+         /* Just wait for the child to close its end of the pipe.  */
+         do
+           {
+             retval = read (daemon_pipe[0], &buf, 1);
+           }
+         while (retval == -1 && errno == EINTR);
+
+         if (retval < 0)
+           {
+             fprintf (stderr, "Error reading status from child\n");
+             exit (1);
+           }
+
+         close (daemon_pipe[0]);
+         exit (0);
+       }
+      if (f < 0)
+       {
+         fprintf (stderr, "Cannot fork!\n");
+         exit (1);
+       }
+
+      if (dname_arg)
+               daemon_name = xstrdup (dname_arg);
+      /* Close unused reading end of the pipe.  */
+      close (daemon_pipe[0]);
+      /* Make sure that the used end of the pipe is closed on exec, so
+        that it is not accessible to programs started from .emacs.  */
+      fcntl (daemon_pipe[1], F_SETFD, FD_CLOEXEC);
+
+#ifdef HAVE_SETSID
+      setsid();
+#endif
+#else /* DOS_NT */
+      fprintf (stderr, "This platform does not support the -daemon flag.\n");
+      exit (1);
+#endif /* DOS_NT */
+    }
+
   if (! noninteractive)
     {
 #ifdef BSD_PGRPS
@@ -1283,27 +1312,6 @@ main (argc, argv
         CANNOT_DUMP is defined.  */
       syms_of_keyboard ();
 
-#ifdef MAC_OS8
-      /* init_window_once calls make_terminal_frame which on Mac OS
-         creates a full-fledge output_mac type frame.  This does not
-         work correctly before syms_of_textprop, syms_of_macfns,
-         syms_of_ccl, syms_of_fontset, syms_of_xterm, syms_of_search,
-         syms_of_frame, mac_term_init, and init_keyboard have already
-         been called.  */
-      syms_of_textprop ();
-      syms_of_macfns ();
-      syms_of_ccl ();
-      syms_of_fontset ();
-      syms_of_macterm ();
-      syms_of_macmenu ();
-      syms_of_macselect ();
-      syms_of_search ();
-      syms_of_frame ();
-
-      init_atimer ();
-      mac_term_init (build_string ("Mac"), NULL, NULL);
-      init_keyboard ();
-#endif
       /* Called before syms_of_fileio, because it sets up Qerror_condition.  */
       syms_of_data ();
       syms_of_fileio ();
@@ -1415,11 +1423,12 @@ main (argc, argv
           if (!strncmp(argv[skip_args], "-psn", 4))
             {
               skip_args += 1;
+              chdir (getenv ("HOME"));
             }
-          else
+          else if (skip_args+1 < argc && !strncmp(argv[skip_args+1], "-psn", 4))
             {
-              if (skip_args+1 < argc && !strncmp(argv[skip_args+1], "-psn", 4))
-                  skip_args += 2;
+              skip_args += 2;
+              chdir (getenv ("HOME"));
             }
         }
 #endif
@@ -1507,11 +1516,6 @@ main (argc, argv
   init_ntproc ();      /* must precede init_editfns.  */
 #endif
 
-#if defined (MAC_OSX) && defined (HAVE_CARBON)
-  if (initialized)
-    init_mac_osx_environment ();
-#endif
-
 #ifdef HAVE_NS
 #ifndef CANNOT_DUMP
   if (initialized)
@@ -1557,7 +1561,6 @@ main (argc, argv
       /* The basic levels of Lisp must come first.  */
       /* And data must come first of all
         for the sake of symbols like error-message.  */
-      /* Called before init_window_once for Mac OS Classic.  */
       syms_of_data ();
       syms_of_chartab ();
       syms_of_lread ();
@@ -1604,9 +1607,6 @@ main (argc, argv
 #endif
       syms_of_textprop ();
       syms_of_composite ();
-#ifdef VMS
-      syms_of_vmsproc ();
-#endif /* VMS */
 #ifdef WINDOWSNT
       syms_of_ntproc ();
 #endif /* WINDOWSNT */
@@ -1640,13 +1640,9 @@ main (argc, argv
       syms_of_fontset ();
 #endif /* HAVE_NTGUI */
 
-#if defined (MAC_OSX) && defined (HAVE_CARBON)
-      syms_of_macterm ();
-      syms_of_macfns ();
-      syms_of_macmenu ();
-      syms_of_macselect ();
-      syms_of_fontset ();
-#endif /* MAC_OSX && HAVE_CARBON */
+#ifdef MSDOS
+      syms_of_xmenu ();
+#endif /* MSDOS */
 
 #ifdef HAVE_NS
       syms_of_nsterm ();
@@ -1691,16 +1687,8 @@ main (argc, argv
   init_editfns (); /* init_process uses Voperating_system_release. */
   init_process (); /* init_display uses add_keyboard_wait_descriptor. */
   init_keyboard ();    /* This too must precede init_sys_modes.  */
-#ifdef VMS
-  init_vmsproc ();     /* And this too.  */
-#endif /* VMS */
   if (!noninteractive)
-    {
-#ifdef VMS
-      init_vms_input ();/* init_display calls get_tty_size, that needs this.  */
-#endif /* VMS */
-      init_display (); /* Determine terminal type.  Calls init_sys_modes.  */
-    }
+    init_display ();   /* Determine terminal type.  Calls init_sys_modes.  */
   init_fns ();
   init_xdisp ();
 #ifdef HAVE_WINDOW_SYSTEM
@@ -1709,9 +1697,6 @@ main (argc, argv
 #endif /* HAVE_WINDOW_SYSTEM */
   init_macros ();
   init_floatfns ();
-#ifdef VMS
-  init_vmsfns ();
-#endif /* VMS */
 #ifdef HAVE_SOUND
   init_sound ();
 #endif
@@ -1816,15 +1801,13 @@ struct standard_args standard_args[] =
   { "-version", "--version", 150, 0 },
 #ifdef HAVE_SHM
   { "-nl", "--no-shared-memory", 140, 0 },
-#endif
-#ifdef VMS
-  { "-map", "--map-data", 130, 0 },
 #endif
   { "-t", "--terminal", 120, 1 },
   { "-nw", "--no-window-system", 110, 0 },
   { "-nw", "--no-windows", 110, 0 },
   { "-batch", "--batch", 100, 0 },
   { "-script", "--script", 100, 1 },
+  { "-daemon", "--daemon", 99, 0 },
   { "-help", "--help", 90, 0 },
   { "-no-unibyte", "--no-unibyte", 83, 0 },
   { "-multibyte", "--multibyte", 82, 0 },
@@ -2098,12 +2081,6 @@ all of which are called before Emacs is actually killed.  */)
 
   UNGCPRO;
 
-/* Is it really necessary to do this deassign
-   when we are going to exit anyway?  */
-/* #ifdef VMS
-  stop_vms_input ();
- #endif  */
-
   shut_down_emacs (0, 0, STRINGP (arg) ? arg : Qnil);
 
   /* If we have an auto-save list file,
@@ -2171,10 +2148,6 @@ shut_down_emacs (sig, no_x, stuff)
   unlock_all_files ();
 #endif
 
-#ifdef VMS
-  kill_vms_processes ();
-#endif
-
 #if 0 /* This triggers a bug in XCloseDisplay and is not needed.  */
 #ifdef HAVE_X_WINDOWS
   /* It's not safe to call intern here.  Maybe we are crashing.  */
@@ -2311,9 +2284,6 @@ You must run Emacs in batch mode in order to dump it.  */)
 #endif
 
   fflush (stdout);
-#ifdef VMS
-  mapout_data (SDATA (filename));
-#else
   /* Tell malloc where start of impure now is.  */
   /* Also arrange for warnings when nearly out of space.  */
 #ifndef SYSTEM_MALLOC
@@ -2344,7 +2314,6 @@ You must run Emacs in batch mode in order to dump it.  */)
 #ifdef DOUG_LEA_MALLOC
   free (malloc_state_ptr);
 #endif
-#endif /* not VMS */
 
   Vpurify_flag = tem;
 
@@ -2470,6 +2439,58 @@ decode_env_path (evarname, defalt)
   return Fnreverse (lpath);
 }
 
+DEFUN ("daemonp", Fdaemonp, Sdaemonp, 0, 0, 0,
+       doc: /* Return non-nil if the current emacs process is a daemon.
+If the daemon was given a name argument, return that name. */)
+  ()
+{
+  if (IS_DAEMON)
+    if (daemon_name)
+      return build_string (daemon_name);
+    else
+      return Qt;
+  else
+    return Qnil;
+}
+
+DEFUN ("daemon-initialized", Fdaemon_initialized, Sdaemon_initialized, 0, 0, 0,
+       doc: /* Mark the Emacs daemon as being initialized.
+This finishes the daemonization process by doing the other half of detaching
+from the parent process and its tty file descriptors.  */)
+  ()
+{
+  int nfd;
+
+  if (!IS_DAEMON)
+    error ("This function can only be called if emacs is run as a daemon");
+
+  if (daemon_pipe[1] < 0)
+    error ("The daemon has already been initialized");
+
+  if (NILP (Vafter_init_time))
+    error ("This function can only be called after loading the init files");
+
+  /* Get rid of stdin, stdout and stderr.  */
+  nfd = open ("/dev/null", O_RDWR);
+  dup2 (nfd, 0);
+  dup2 (nfd, 1);
+  dup2 (nfd, 2);
+  close (nfd);
+
+  /* Closing the pipe will notify the parent that it can exit.
+     FIXME: In case some other process inherited the pipe, closing it here
+     won't notify the parent because it's still open elsewhere, so we
+     additionally send a byte, just to make sure the parent really exits.
+     Instead, we should probably close the pipe in start-process and
+     call-process to make sure the pipe is never inherited by
+     subprocesses.  */
+  write (daemon_pipe[1], "\n", 1);
+  close (daemon_pipe[1]);
+  /* Set it to an invalid value so we know we've already run this function.  */
+  daemon_pipe[1] = -1;
+  return Qt;
+}
+
 void
 syms_of_emacs ()
 {
@@ -2488,6 +2509,8 @@ syms_of_emacs ()
 
   defsubr (&Sinvocation_name);
   defsubr (&Sinvocation_directory);
+  defsubr (&Sdaemonp);
+  defsubr (&Sdaemon_initialized);
 
   DEFVAR_LISP ("command-line-args", &Vcommand_line_args,
               doc: /* Args passed by shell to Emacs, as a list of strings.
@@ -2502,7 +2525,6 @@ Special values:
   `ms-dos'      compiled as an MS-DOS application.
   `windows-nt'  compiled as a native W32 application.
   `cygwin'      compiled using the Cygwin library.
-  `vax-vms'     compiled for a (Open)VMS system.
 Anything else indicates some sort of Unix system.  */);
   Vsystem_type = intern (SYSTEM_TYPE);
 
@@ -2577,6 +2599,18 @@ was found.  */);
   DEFVAR_LISP ("previous-system-time-locale", &Vprevious_system_time_locale,
               doc: /* Most recently used system locale for time.  */);
   Vprevious_system_time_locale = Qnil;
+
+  DEFVAR_LISP ("before-init-time", &Vbefore_init_time,
+              doc: /* Value of `current-time' before Emacs begins initialization.  */);
+  Vbefore_init_time = Qnil;
+
+  DEFVAR_LISP ("after-init-time", &Vafter_init_time,
+              doc: /* Value of `current-time' after loading the init files.
+This is nil during initialization.  */);
+  Vafter_init_time = Qnil;
+
+  /* Make sure IS_DAEMON starts up as false.  */
+  daemon_pipe[1] = 0;
 }
 
 /* arch-tag: 7bfd356a-c720-4612-8ab6-aa4222931c2e