Fix 'restart-emacs' on MS-Windows

* src/w32.c (w32_reexec_emacs): New function, emulation of
'execvp' on Posix systems.
* src/w32.h (w32_reexec_emacs): Add prototype.
* src/emacs.c (main) [WINDOWSNT]: Save the original command line
and working directory.
(Fkill_emacs) [WINDOWSNT]: Call 'w32_reexec_emacs' instead of
'execvp'.  (Bug#17036)
This commit is contained in:
Eli Zaretskii 2022-04-17 17:20:03 +03:00
parent 56d5a40794
commit 5a63af876b
3 changed files with 58 additions and 0 deletions

View file

@ -159,6 +159,10 @@ Lisp_Object empty_unibyte_string, empty_multibyte_string;
#ifdef WINDOWSNT
/* Cache for externally loaded libraries. */
Lisp_Object Vlibrary_cache;
/* Original command line string as received from the OS. */
static char *initial_cmdline;
/* Original working directory when invoked. */
static const char *initial_wd;
#endif
struct gflags gflags;
@ -1319,6 +1323,7 @@ main (int argc, char **argv)
}
}
init_heap (use_dynamic_heap);
initial_cmdline = GetCommandLine ();
#endif
#if defined WINDOWSNT || defined HAVE_NTGUI
/* Set global variables used to detect Windows version. Do this as
@ -1465,6 +1470,9 @@ main (int argc, char **argv)
#endif
emacs_wd = emacs_get_current_dir_name ();
#ifdef WINDOWSNT
initial_wd = emacs_wd;
#endif
#ifdef HAVE_PDUMPER
if (dumped_with_pdumper_p ())
pdumper_record_wd (emacs_wd);
@ -2811,7 +2819,11 @@ killed. */
(on some systems) with no argv. */
if (initial_argc < 1)
error ("No command line arguments known; unable to re-execute Emacs");
#ifdef WINDOWSNT
if (w32_reexec_emacs (initial_cmdline, initial_wd) < 1)
#else
if (execvp (*initial_argv, initial_argv) < 1)
#endif
error ("Unable to re-execute Emacs");
}

View file

@ -10614,6 +10614,49 @@ realpath (const char *file_name, char *resolved_name)
return xstrdup (tgt);
}
/* A replacement for Posix execvp, used to restart Emacs. This is
needed because the low-level Windows API to start processes accepts
the command-line arguments as a single string, so we cannot safely
use the MSVCRT execvp emulation, because elements of argv[] that
have embedded blanks and tabs will not be passed correctly to the
restarted Emacs. */
int
w32_reexec_emacs (char *cmd_line, const char *wdir)
{
STARTUPINFO si;
SECURITY_ATTRIBUTES sec_attrs;
BOOL status;
PROCESS_INFORMATION proc_info;
GetStartupInfo (&si); /* Use the same startup info as the caller. */
sec_attrs.nLength = sizeof (sec_attrs);
sec_attrs.lpSecurityDescriptor = NULL;
sec_attrs.bInheritHandle = FALSE;
/* Make sure we are in the original directory, in case the command
line specifies the program as a relative file name. */
chdir (wdir);
status = CreateProcess (NULL, /* program */
cmd_line, /* command line */
&sec_attrs, /* process attributes */
NULL, /* thread attributes */
TRUE, /* inherit handles? */
NORMAL_PRIORITY_CLASS,
NULL, /* environment */
wdir, /* initial directory */
&si, /* startup info */
&proc_info);
if (status)
{
CloseHandle (proc_info.hThread);
CloseHandle (proc_info.hProcess);
exit (0);
}
errno = ENOEXEC;
return -1;
}
/*
globals_of_w32 is used to initialize those global variables that
must always be initialized on startup even when the global variable

View file

@ -244,6 +244,9 @@ extern int w32_init_random (void *, ptrdiff_t);
extern Lisp_Object w32_read_registry (HKEY, Lisp_Object, Lisp_Object);
/* Used instead of execvp to restart Emacs. */
extern int w32_reexec_emacs (char *, const char *);
#ifdef HAVE_GNUTLS
#include <gnutls/gnutls.h>