/* Synchronous subprocess invocation for GNU Emacs.
-Copyright (C) 1985-1988, 1993-1995, 1999-2014 Free Software Foundation,
+Copyright (C) 1985-1988, 1993-1995, 1999-2015 Free Software Foundation,
Inc.
This file is part of GNU Emacs.
dir = expand_and_dir_to_file (dir, Qnil);
+ if (NILP (Ffile_accessible_directory_p (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);
+
if (STRING_MULTIBYTE (dir))
dir = ENCODE_FILE (dir);
- if (! file_accessible_directory_p (SSDATA (dir)))
+ if (! file_accessible_directory_p (dir))
report_file_error ("Setting current directory",
BVAR (current_buffer, directory));
&& SREF (path, 1) == ':')
path = Fsubstring (path, make_number (2), Qnil);
- new_argv = SAFE_ALLOCA ((nargs > 4 ? nargs - 2 : 2) * sizeof *new_argv);
+ SAFE_NALLOCA (new_argv, 1, nargs < 4 ? 2 : nargs - 2);
{
struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
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;
(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: ;
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);
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);
}
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);
+ exec_failed (new_argv[0], errno);
#else /* MSDOS */
pid = run_msdos_command (new_argv, pwd_var + 4, in, out, err, env);
}
/* 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))
#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");