/* Synchronous subprocess invocation for GNU Emacs.
-Copyright (C) 1985-1988, 1993-1995, 1999-2015 Free Software Foundation,
+Copyright (C) 1985-1988, 1993-1995, 1999-2016 Free Software Foundation,
Inc.
This file is part of GNU Emacs.
GNU Emacs is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
-the Free Software Foundation, either version 3 of the License, or
-(at your option) any later version.
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
GNU Emacs is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
#endif /* MSDOS */
#include "commands.h"
-#include "character.h"
#include "buffer.h"
-#include "ccl.h"
#include "coding.h"
-#include "composite.h"
#include <epaths.h>
#include "process.h"
#include "syssignal.h"
-#include "systty.h"
#include "syswait.h"
#include "blockinput.h"
#include "frame.h"
-#include "termhooks.h"
#ifdef MSDOS
#include "msdos.h"
static Lisp_Object call_process (ptrdiff_t, Lisp_Object *, int, ptrdiff_t);
\f
-
-#ifndef MSDOS
-/* Block SIGCHLD. */
-
-void
-block_child_signal (void)
-{
- sigset_t blocked;
- sigemptyset (&blocked);
- sigaddset (&blocked, SIGCHLD);
- pthread_sigmask (SIG_BLOCK, &blocked, 0);
-}
-
-/* Unblock SIGCHLD. */
-
-void
-unblock_child_signal (void)
-{
- pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
-}
-
-#endif /* !MSDOS */
-
/* Return the current buffer's working directory, or the home
directory if it's unreachable, as a string suitable for a system call.
Signal an error if the result would not be an accessible directory. */
encode_current_directory (void)
{
Lisp_Object dir;
- struct gcpro gcpro1;
dir = BVAR (current_buffer, directory);
- GCPRO1 (dir);
dir = Funhandled_file_name_directory (dir);
report_file_error ("Setting current directory",
BVAR (current_buffer, directory));
- /* Remove "/:" from dir. */
- if (! NILP (Fstring_match (build_string ("^/:"), dir, Qnil)))
- dir = Fsubstring (dir, make_number (2), Qnil);
+ /* Remove "/:" from DIR and encode it. */
+ dir = ENCODE_FILE (remove_slash_colon (dir));
- if (STRING_MULTIBYTE (dir))
- dir = ENCODE_FILE (dir);
+ if (! file_accessible_directory_p (dir))
+ report_file_error ("Setting current directory",
+ BVAR (current_buffer, directory));
- RETURN_UNGCPRO (dir);
+ return dir;
}
/* If P is reapable, record it as a deleted process and kill it.
record_kill_process (struct Lisp_Process *p, Lisp_Object tempfile)
{
#ifndef MSDOS
- block_child_signal ();
+ sigset_t oldset;
+ block_child_signal (&oldset);
if (p->alive)
{
kill (- p->pid, SIGKILL);
}
- unblock_child_signal ();
+ unblock_child_signal (&oldset);
#endif /* !MSDOS */
}
Insert output in DESTINATION before point; t means current buffer; nil for DESTINATION
means discard it; 0 means discard and don't wait; and `(:file FILE)', where
FILE is a file name string, means that it should be written to that file
- \(if the file already exists it is overwritten).
+ (if the file already exists it is overwritten).
DESTINATION can also have the form (REAL-BUFFER STDERR-FILE); in that case,
REAL-BUFFER says what to do with standard output, as above,
while STDERR-FILE says what to do with standard error in the child.
{
Lisp_Object infile, encoded_infile;
int filefd;
- struct gcpro gcpro1;
ptrdiff_t count = SPECPDL_INDEX ();
if (nargs >= 2 && ! NILP (args[1]))
else
infile = build_string (NULL_DEVICE);
- GCPRO1 (infile);
- encoded_infile = STRING_MULTIBYTE (infile) ? ENCODE_FILE (infile) : infile;
+ encoded_infile = ENCODE_FILE (infile);
filefd = emacs_open (SSDATA (encoded_infile), O_RDONLY, 0);
if (filefd < 0)
report_file_error ("Opening process input file", infile);
record_unwind_protect_int (close_file_unwind, filefd);
- UNGCPRO;
return unbind_to (count, call_process (nargs, args, filefd, -1));
}
char *tempfile = NULL;
int pid;
#else
+ sigset_t oldset;
pid_t pid;
#endif
int child_errno;
/* Make sure that the child will be able to chdir to the current
buffer's current directory, or its unhandled equivalent. We
can't just have the child check for an error when it does the
- chdir, since it's in a vfork.
-
- We have to GCPRO around this because Fexpand_file_name,
- Funhandled_file_name_directory, and Ffile_accessible_directory_p
- might call a file name handling function. The argument list is
- protected by the caller, so all we really have to worry about is
- buffer. */
- {
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ chdir, since it's in a vfork. */
+ current_dir = encode_current_directory ();
- current_dir = encode_current_directory ();
-
- GCPRO4 (buffer, current_dir, error_file, output_file);
-
- if (STRINGP (error_file) && STRING_MULTIBYTE (error_file))
- error_file = ENCODE_FILE (error_file);
- if (STRINGP (output_file) && STRING_MULTIBYTE (output_file))
- output_file = ENCODE_FILE (output_file);
- UNGCPRO;
- }
+ if (STRINGP (error_file))
+ error_file = ENCODE_FILE (error_file);
+ if (STRINGP (output_file))
+ output_file = ENCODE_FILE (output_file);
display_p = INTERACTIVE && nargs >= 4 && !NILP (args[3]);
/* Search for program; barf if not found. */
{
- struct gcpro gcpro1, gcpro2, gcpro3;
int ok;
- GCPRO3 (buffer, current_dir, error_file);
ok = openp (Vexec_path, args[0], Vexec_suffixes, &path,
make_number (X_OK), false);
- UNGCPRO;
if (ok < 0)
report_file_error ("Searching for program", args[0]);
}
- /* If program file name starts with /: for quoting a magic name,
- discard that. */
- if (SBYTES (path) > 2 && SREF (path, 0) == '/'
- && SREF (path, 1) == ':')
- path = Fsubstring (path, make_number (2), Qnil);
+ /* Remove "/:" from PATH. */
+ path = remove_slash_colon (path);
- new_argv = SAFE_ALLOCA ((nargs > 4 ? nargs - 2 : 2) * sizeof *new_argv);
-
- {
- struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
+ SAFE_NALLOCA (new_argv, 1, nargs < 4 ? 2 : nargs - 2);
- GCPRO4 (buffer, current_dir, path, error_file);
- if (nargs > 4)
- {
- ptrdiff_t i;
+ if (nargs > 4)
+ {
+ ptrdiff_t i;
- argument_coding.dst_multibyte = 0;
- for (i = 4; i < nargs; i++)
- {
- argument_coding.src_multibyte = STRING_MULTIBYTE (args[i]);
- if (CODING_REQUIRE_ENCODING (&argument_coding))
- /* We must encode this argument. */
- args[i] = encode_coding_string (&argument_coding, args[i], 1);
- }
- for (i = 4; i < nargs; i++)
- new_argv[i - 3] = SSDATA (args[i]);
- new_argv[i - 3] = 0;
- }
- else
- new_argv[1] = 0;
- if (STRING_MULTIBYTE (path))
- path = ENCODE_FILE (path);
- new_argv[0] = SSDATA (path);
- UNGCPRO;
- }
+ argument_coding.dst_multibyte = 0;
+ for (i = 4; i < nargs; i++)
+ {
+ argument_coding.src_multibyte = STRING_MULTIBYTE (args[i]);
+ if (CODING_REQUIRE_ENCODING (&argument_coding))
+ /* We must encode this argument. */
+ args[i] = encode_coding_string (&argument_coding, args[i], 1);
+ }
+ for (i = 4; i < nargs; i++)
+ new_argv[i - 3] = SSDATA (args[i]);
+ new_argv[i - 3] = 0;
+ }
+ else
+ new_argv[1] = 0;
+ path = ENCODE_FILE (path);
+ new_argv[0] = SSDATA (path);
discard_output = INTEGERP (buffer) || (NILP (buffer) && NILP (output_file));
{
/* Since CRLF is converted to LF within `decode_coding', we
can always open a file with binary mode. */
- callproc_fd[CALLPROC_PIPEREAD] = emacs_open (tempfile,
- O_RDONLY | O_BINARY, 0);
+ callproc_fd[CALLPROC_PIPEREAD] = emacs_open (tempfile, O_RDONLY, 0);
if (callproc_fd[CALLPROC_PIPEREAD] < 0)
{
int open_errno = errno;
#ifndef MSDOS
block_input ();
- block_child_signal ();
+ block_child_signal (&oldset);
#ifdef WINDOWSNT
pid = child_setup (filefd, fd_output, fd_error, new_argv, 0, current_dir);
int volatile fd_error_volatile = fd_error;
int volatile filefd_volatile = filefd;
ptrdiff_t volatile count_volatile = count;
+ ptrdiff_t volatile sa_avail_volatile = sa_avail;
ptrdiff_t volatile sa_count_volatile = sa_count;
char **volatile new_argv_volatile = new_argv;
int volatile callproc_fd_volatile[CALLPROC_FDS];
fd_error = fd_error_volatile;
filefd = filefd_volatile;
count = count_volatile;
+ sa_avail = sa_avail_volatile;
sa_count = sa_count_volatile;
new_argv = new_argv_volatile;
if (pid == 0)
{
- unblock_child_signal ();
+ unblock_child_signal (&oldset);
setsid ();
}
}
- unblock_child_signal ();
+ unblock_child_signal (&oldset);
unblock_input ();
if (pid < 0)
(process_coding.dst_pos_byte
+ process_coding.produced),
0);
- display_on_the_fly = 0;
+ display_on_the_fly = false;
process_coding = saved_coding;
carryover = nread;
/* Make the above condition always fail in the future. */
/* This variable might have been set to 0 for code
detection. In that case, set it back to 1 because
we should have already detected a coding system. */
- display_on_the_fly = 1;
+ display_on_the_fly = true;
}
- immediate_quit = 1;
+ immediate_quit = true;
QUIT;
}
give_up: ;
Lisp_Object *filename_string_ptr)
{
int fd;
- struct gcpro gcpro1;
Lisp_Object filename_string;
Lisp_Object val, start, end;
Lisp_Object tmpdir;
#endif
filename_string = Fcopy_sequence (ENCODE_FILE (pattern));
- GCPRO1 (filename_string);
tempfile = SSDATA (filename_string);
count = SPECPDL_INDEX ();
record_unwind_protect_nothing ();
- fd = mkostemp (tempfile, O_CLOEXEC);
+ fd = mkostemp (tempfile, O_BINARY | O_CLOEXEC);
if (fd < 0)
report_file_error ("Failed to open temporary file using pattern",
pattern);
specbind (intern ("coding-system-for-write"), val);
/* POSIX lets mk[s]temp use "."; don't invoke jka-compr if we
happen to get a ".Z" suffix. */
- specbind (intern ("file-name-handler-alist"), Qnil);
+ specbind (Qfile_name_handler_alist, Qnil);
write_region (start, end, filename_string, Qnil, Qlambda, Qnil, Qnil, fd);
unbind_to (count1, Qnil);
coding-system-for-read. */
*filename_string_ptr = filename_string;
- UNGCPRO;
return fd;
}
usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &rest ARGS) */)
(ptrdiff_t nargs, Lisp_Object *args)
{
- struct gcpro gcpro1;
Lisp_Object infile, val;
ptrdiff_t count = SPECPDL_INDEX ();
Lisp_Object start = args[0];
record_unwind_protect_int (close_file_unwind, fd);
}
- GCPRO1 (infile);
-
if (nargs > 3 && !NILP (args[3]))
Fdelete_region (start, end);
args[1] = infile;
val = call_process (nargs, args, fd, empty_input ? -1 : count);
- RETURN_UNGCPRO (unbind_to (count, val));
+ return unbind_to (count, val);
}
\f
-#ifndef WINDOWSNT
-static int relocate_fd (int fd, int minfd);
-#endif
-
static char **
add_env (char **env, char **new_env, char *string)
{
char *p = *ep, *q = string;
while (ok)
{
- if (*q != *p)
+ if (*p && *q != *p)
break;
if (*q == 0)
/* The string is a lone variable name; keep it for now, we
return new_env;
}
+#ifndef DOS_NT
+
+/* 'exec' failed inside a child running NAME, with error number ERR.
+ Possibly a vforked child needed to allocate a large vector on the
+ stack; such a child cannot fall back on malloc because that might
+ mess up the allocator's data structures in the parent.
+ Report the error and exit the child. */
+
+static _Noreturn void
+exec_failed (char const *name, int err)
+{
+ /* Avoid deadlock if the child's perror writes to a full pipe; the
+ pipe's reader is the parent, but with vfork the parent can't
+ run until the child exits. Truncate the diagnostic instead. */
+ fcntl (STDERR_FILENO, F_SETFL, O_NONBLOCK);
+
+ errno = err;
+ emacs_perror (name);
+ _exit (err == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
+}
+
+#else
+
+/* Do nothing. There is no need to fail, as DOS_NT platforms do not
+ fork and exec, and handle alloca exhaustion in a different way. */
+
+static void
+exec_failed (char const *name, int err)
+{
+}
+
+#endif
+
/* This is the last thing run in a newly forked inferior
either synchronous or asynchronous.
Copy descriptors IN, OUT and ERR as descriptors 0, 1 and 2.
int cpid;
HANDLE handles[3];
#else
- int exec_errno;
-
pid_t pid = getpid ();
#endif /* WINDOWSNT */
on that. */
pwd_var = xmalloc (i + 5);
#else
+ if (MAX_ALLOCA - 5 < i)
+ exec_failed (new_argv[0], ENOMEM);
pwd_var = alloca (i + 5);
#endif
temp = pwd_var + 4;
memcpy (pwd_var, "PWD=", 4);
- strcpy (temp, SSDATA (current_dir));
+ lispstpcpy (temp, current_dir);
#ifndef DOS_NT
/* We can't signal an Elisp error here; we're in a vfork. Since
}
/* new_length + 2 to include PWD and terminating 0. */
+ if (MAX_ALLOCA / sizeof *env - 2 < new_length)
+ exec_failed (new_argv[0], ENOMEM);
env = new_env = alloca ((new_length + 2) * sizeof *env);
/* If we have a PWD envvar, pass one down,
but with corrected value. */
if (STRINGP (display))
{
+ if (MAX_ALLOCA - sizeof "DISPLAY=" < SBYTES (display))
+ exec_failed (new_argv[0], ENOMEM);
char *vdata = alloca (sizeof "DISPLAY=" + SBYTES (display));
- strcpy (vdata, "DISPLAY=");
- strcat (vdata, SSDATA (display));
+ lispstpcpy (stpcpy (vdata, "DISPLAY="), display);
new_env = add_env (env, new_env, vdata);
}
#ifdef WINDOWSNT
prepare_standard_handles (in, out, err, handles);
- set_process_dir (SDATA (current_dir));
+ set_process_dir (SSDATA (current_dir));
/* Spawn the child. (See w32proc.c:sys_spawnve). */
cpid = spawnve (_P_NOWAIT, new_argv[0], new_argv, env);
reset_standard_handles (in, out, err, handles);
return cpid;
#else /* not WINDOWSNT */
- /* Make sure that in, out, and err are not actually already in
- descriptors zero, one, or two; this could happen if Emacs is
- started with its standard in, out, or error closed, as might
- happen under X. */
- {
- int oin = in, oout = out;
-
- /* We have to avoid relocating the same descriptor twice! */
-
- in = relocate_fd (in, 3);
-
- if (out == oin)
- out = in;
- else
- out = relocate_fd (out, 3);
-
- if (err == oin)
- err = in;
- else if (err == oout)
- err = out;
- else
- err = relocate_fd (err, 3);
- }
#ifndef MSDOS
/* Redirect file descriptors and clear the close-on-exec flag on the
redirected ones. IN, OUT, and ERR are close-on-exec so they
need not be closed explicitly. */
- dup2 (in, 0);
- dup2 (out, 1);
- dup2 (err, 2);
+ dup2 (in, STDIN_FILENO);
+ dup2 (out, STDOUT_FILENO);
+ dup2 (err, STDERR_FILENO);
setpgid (0, 0);
tcsetpgrp (0, pid);
- execve (new_argv[0], new_argv, env);
- exec_errno = errno;
-
- /* Avoid deadlock if the child's perror writes to a full pipe; the
- pipe's reader is the parent, but with vfork the parent can't
- run until the child exits. Truncate the diagnostic instead. */
- fcntl (STDERR_FILENO, F_SETFL, O_NONBLOCK);
-
- errno = exec_errno;
- emacs_perror (new_argv[0]);
- _exit (exec_errno == ENOENT ? EXIT_ENOENT : EXIT_CANNOT_INVOKE);
+ int errnum = emacs_exec_file (new_argv[0], new_argv, env);
+ exec_failed (new_argv[0], errnum);
#else /* MSDOS */
pid = run_msdos_command (new_argv, pwd_var + 4, in, out, err, env);
#endif /* not WINDOWSNT */
}
-#ifndef WINDOWSNT
-/* Move the file descriptor FD so that its number is not less than MINFD.
- If the file descriptor is moved at all, the original is closed on MSDOS,
- but not elsewhere as the caller will close it anyway. */
-static int
-relocate_fd (int fd, int minfd)
-{
- if (fd >= minfd)
- return fd;
- else
- {
- int new = fcntl (fd, F_DUPFD_CLOEXEC, minfd);
- if (new == -1)
- {
- emacs_perror ("while setting up child");
- _exit (EXIT_CANCELED);
- }
-#ifdef MSDOS
- emacs_close (fd);
-#endif
- return new;
- }
-}
-#endif /* not WINDOWSNT */
-
static bool
getenv_internal_1 (const char *var, ptrdiff_t varlen, char **value,
ptrdiff_t *valuelen, Lisp_Object env)
&& SBYTES (entry) >= varlen
#ifdef WINDOWSNT
/* NT environment variables are case insensitive. */
- && ! strnicmp (SDATA (entry), var, varlen)
+ && ! strnicmp (SSDATA (entry), var, varlen)
#else /* not WINDOWSNT */
&& ! memcmp (SDATA (entry), var, varlen)
#endif /* not WINDOWSNT */
Vprocess_environment))
return *value ? 1 : 0;
+ /* On Windows we make some modifications to Emacs' environment
+ without recording them in Vprocess_environment. */
+#ifdef WINDOWSNT
+ {
+ char* tmpval = getenv (var);
+ if (tmpval)
+ {
+ *value = tmpval;
+ *valuelen = strlen (tmpval);
+ return 1;
+ }
+ }
+#endif
+
/* For DISPLAY try to get the values from the frame or the initial env. */
if (strcmp (var, "DISPLAY") == 0)
{
}
/* A version of getenv that consults the Lisp environment lists,
- easily callable from C. */
+ easily callable from C. This is usually called from egetenv. */
char *
-egetenv (const char *var)
+egetenv_internal (const char *var, ptrdiff_t len)
{
char *value;
ptrdiff_t valuelen;
- if (getenv_internal (var, strlen (var), &value, &valuelen, Qnil))
+ if (getenv_internal (var, len, &value, &valuelen, Qnil))
return value;
else
return 0;
void
init_callproc (void)
{
- char *data_dir = egetenv ("EMACSDATA");
+ bool data_dir = egetenv ("EMACSDATA") != 0;
- register char * sh;
+ char *sh;
Lisp_Object tempdir;
#ifdef HAVE_NS
if (data_dir == 0)
- {
- const char *etc_dir = ns_etc_directory ();
- if (etc_dir)
- {
- data_dir = alloca (strlen (etc_dir) + 1);
- strcpy (data_dir, etc_dir);
- }
- }
+ data_dir = ns_etc_directory () != 0;
#endif
if (!NILP (Vinstallation_directory))
#ifdef HAVE_NS
const char *path_exec = ns_exec_path ();
#endif
+ /* Running uninstalled, so default to tem rather than PATH_EXEC. */
Vexec_path = decode_env_path ("EMACSPATH",
#ifdef HAVE_NS
path_exec ? path_exec :
#endif
- PATH_EXEC, 0);
- Vexec_path = Fcons (tem, Vexec_path);
+ SSDATA (tem), 0);
Vexec_path = nconc2 (decode_env_path ("PATH", "", 0), Vexec_path);
}
srcdir = Fexpand_file_name (build_string ("../src/"), lispdir);
- tem = Fexpand_file_name (build_string ("GNU"), Vdata_directory);
+ tem = Fexpand_file_name (build_string ("NEWS"), Vdata_directory);
tem1 = Ffile_exists_p (tem);
if (!NILP (Fequal (srcdir, Vinvocation_directory)) || NILP (tem1))
{
Lisp_Object newdir;
newdir = Fexpand_file_name (build_string ("../etc/"), lispdir);
- tem = Fexpand_file_name (build_string ("GNU"), newdir);
+ tem = Fexpand_file_name (build_string ("NEWS"), newdir);
tem1 = Ffile_exists_p (tem);
if (!NILP (tem1))
Vdata_directory = newdir;
#endif
{
tempdir = Fdirectory_file_name (Vexec_directory);
- if (! file_accessible_directory_p (SSDATA (tempdir)))
+ if (! file_accessible_directory_p (tempdir))
dir_warning ("arch-dependent data dir", Vexec_directory);
}
tempdir = Fdirectory_file_name (Vdata_directory);
- if (! file_accessible_directory_p (SSDATA (tempdir)))
+ if (! file_accessible_directory_p (tempdir))
dir_warning ("arch-independent data dir", Vdata_directory);
sh = getenv ("SHELL");
DEFVAR_LISP ("shell-file-name", Vshell_file_name,
doc: /* File name to load inferior shells from.
Initialized from the SHELL environment variable, or to a system-dependent
-default if SHELL is not set. */);
+default if SHELL is unset. See Info node `(elisp)Security Considerations'. */);
DEFVAR_LISP ("exec-path", Vexec_path,
doc: /* List of directories to search programs to run in subprocesses.
By default the last element of this list is `exec-directory'. The
last element is not always used, for example in shell completion
-(`shell-dynamic-complete-command'). */);
+\(`shell-dynamic-complete-command'). */);
DEFVAR_LISP ("exec-suffixes", Vexec_suffixes,
doc: /* List of suffixes to try to find executable file names.