X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/290d7ac277986bd118e594a8100b3f40e4492cb1..970d21e8e6aa7e5bafd3f025f66d694b5ae06ba5:/src/callproc.c diff --git a/src/callproc.c b/src/callproc.c index a2c52e5b5b..271743021b 100644 --- a/src/callproc.c +++ b/src/callproc.c @@ -105,29 +105,6 @@ enum static Lisp_Object call_process (ptrdiff_t, Lisp_Object *, int, ptrdiff_t); - -#ifndef MSDOS -/* Block SIGCHLD. */ - -void -block_child_signal (sigset_t *oldset) -{ - sigset_t blocked; - sigemptyset (&blocked); - sigaddset (&blocked, SIGCHLD); - pthread_sigmask (SIG_BLOCK, &blocked, oldset); -} - -/* Unblock SIGCHLD. */ - -void -unblock_child_signal (sigset_t const *oldset) -{ - pthread_sigmask (SIG_SETMASK, oldset, 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. */ @@ -152,7 +129,7 @@ encode_current_directory (void) 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)); @@ -489,7 +466,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, && 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; @@ -828,8 +805,10 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, /* Now NREAD is the total amount of data in the buffer. */ immediate_quit = 0; - if (NILP (BVAR (current_buffer, enable_multibyte_characters)) - && ! CODING_MAY_REQUIRE_DECODING (&process_coding)) + if (!nread) + ; + else if (NILP (BVAR (current_buffer, enable_multibyte_characters)) + && ! CODING_MAY_REQUIRE_DECODING (&process_coding)) insert_1_both (buf, nread, nread, 0, 1, 0); else { /* We have to decode the input. */ @@ -837,6 +816,7 @@ call_process (ptrdiff_t nargs, Lisp_Object *args, int filefd, ptrdiff_t count1 = SPECPDL_INDEX (); XSETBUFFER (curbuf, current_buffer); + /* FIXME: Call signal_after_change! */ prepare_to_modify_buffer (PT, PT, NULL); /* We cannot allow after-change-functions be run during decoding, because that might modify the @@ -1002,7 +982,7 @@ create_temp_file (ptrdiff_t nargs, Lisp_Object *args, 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); @@ -1171,6 +1151,25 @@ add_env (char **env, char **new_env, char *string) return new_env; } +#ifndef DOS_NT + +/* 'exec' failed inside a child running NAME, with error number ERR. + 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); +} +#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. @@ -1194,8 +1193,6 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, int cpid; HANDLE handles[3]; #else - int exec_errno; - pid_t pid = getpid (); #endif /* WINDOWSNT */ @@ -1216,6 +1213,13 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, on that. */ pwd_var = xmalloc (i + 5); #else + /* WINDOWSNT doesn't define exec_failed, and doesn't need this + test, since a directory name cannot be longer than 260 + characters, i.e. 260 * 4 = 1040 UTF-8 bytes. */ +#ifndef WINDOWSNT + if (MAX_ALLOCA - 5 < i) + exec_failed (new_argv[0], ENOMEM); +#endif pwd_var = alloca (i + 5); #endif temp = pwd_var + 4; @@ -1282,6 +1286,10 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, } /* new_length + 2 to include PWD and terminating 0. */ +#ifndef WINDOWSNT + if (MAX_ALLOCA / sizeof *env - 2 < new_length) + exec_failed (new_argv[0], ENOMEM); +#endif env = new_env = alloca ((new_length + 2) * sizeof *env); /* If we have a PWD envvar, pass one down, but with corrected value. */ @@ -1290,7 +1298,14 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, if (STRINGP (display)) { - char *vdata = alloca (sizeof "DISPLAY=" + SBYTES (display)); + char *vdata; + + /* WINDOWSNT doesn't have $DISPLAY. */ +#ifndef WINDOWSNT + if (MAX_ALLOCA - sizeof "DISPLAY=" < SBYTES (display)) + exec_failed (new_argv[0], ENOMEM); +#endif + vdata = alloca (sizeof "DISPLAY=" + SBYTES (display)); strcpy (vdata, "DISPLAY="); strcat (vdata, SSDATA (display)); new_env = add_env (env, new_env, vdata); @@ -1365,16 +1380,7 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp, 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); @@ -1508,14 +1514,14 @@ If optional parameter ENV is a list, then search this list instead of } /* 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; @@ -1563,20 +1569,13 @@ init_callproc_1 (void) 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)) @@ -1645,12 +1644,12 @@ init_callproc (void) #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");