X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/a5522abbca2235771384949dfa87c8efc68831b2..63750fd4ed4ff8bb9b3ff8868d4e36e3422adb21:/src/sysdep.c diff --git a/src/sysdep.c b/src/sysdep.c index 30a55f1140..16541735f0 100644 --- a/src/sysdep.c +++ b/src/sysdep.c @@ -1,13 +1,13 @@ /* Interfaces to system-dependent kernel and library entries. - Copyright (C) 1985-1988, 1993-1995, 1999-2015 Free Software + 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 @@ -19,14 +19,6 @@ along with GNU Emacs. If not, see . */ #include -/* If HYBRID_GET_CURRENT_DIR_NAME is defined in conf_post.h, then we - need the following before including unistd.h, in order to pick up - the right prototype for gget_current_dir_name. */ -#ifdef HYBRID_GET_CURRENT_DIR_NAME -#undef get_current_dir_name -#define get_current_dir_name gget_current_dir_name -#endif - #include #include "sysstdio.h" #ifdef HAVE_PWD_H @@ -40,6 +32,7 @@ along with GNU Emacs. If not, see . */ #include #include "lisp.h" +#include "sheap.h" #include "sysselect.h" #include "blockinput.h" @@ -93,20 +86,27 @@ along with GNU Emacs. If not, see . */ #include "keyboard.h" #include "frame.h" -#include "window.h" #include "termhooks.h" #include "termchar.h" #include "termopts.h" -#include "dispextern.h" #include "process.h" -#include "cm.h" /* for reset_sys_modes */ +#include "cm.h" + +#include "gnutls.h" +/* MS-Windows loads GnuTLS at run time, if available; we don't want to + do that during startup just to call gnutls_rnd. */ +#if 0x020c00 <= GNUTLS_VERSION_NUMBER && !defined WINDOWSNT +# include +#else +# define emacs_gnutls_global_init() Qnil +# define gnutls_rnd(level, data, len) (-1) +#endif #ifdef WINDOWSNT #include /* In process.h which conflicts with the local copy. */ #define _P_WAIT 0 int _cdecl _spawnlp (int, const char *, const char *, ...); -int _cdecl _getpid (void); /* The following is needed for O_CLOEXEC, F_SETFD, FD_CLOEXEC, and several prototypes of functions called below. */ #include @@ -129,14 +129,92 @@ static const int baud_convert[] = 1800, 2400, 4800, 9600, 19200, 38400 }; -#if !defined HAVE_GET_CURRENT_DIR_NAME || defined BROKEN_GET_CURRENT_DIR_NAME \ - || (defined HYBRID_GET_CURRENT_DIR_NAME) -/* Return the current working directory. Returns NULL on errors. - Any other returned value must be freed with free. This is used - only when get_current_dir_name is not defined on the system. */ +#ifdef HAVE_PERSONALITY_ADDR_NO_RANDOMIZE +# include + +/* Disable address randomization in the current process. Return true + if addresses were randomized but this has been disabled, false + otherwise. */ +bool +disable_address_randomization (void) +{ + bool disabled = false; + int pers = personality (0xffffffff); + disabled = (! (pers & ADDR_NO_RANDOMIZE) + && 0 <= personality (pers | ADDR_NO_RANDOMIZE)); + return disabled; +} +#endif + +/* Execute the program in FILE, with argument vector ARGV and environ + ENVP. Return an error number if unsuccessful. This is like execve + except it reenables ASLR in the executed program if necessary, and + on error it returns an error number rather than -1. */ +int +emacs_exec_file (char const *file, char *const *argv, char *const *envp) +{ +#ifdef HAVE_PERSONALITY_ADDR_NO_RANDOMIZE + int pers = getenv ("EMACS_HEAP_EXEC") ? personality (0xffffffff) : -1; + bool change_personality = 0 <= pers && pers & ADDR_NO_RANDOMIZE; + if (change_personality) + personality (pers & ~ADDR_NO_RANDOMIZE); +#endif + + execve (file, argv, envp); + int err = errno; + +#ifdef HAVE_PERSONALITY_ADDR_NO_RANDOMIZE + if (change_personality) + personality (pers); +#endif + + return err; +} + +/* If FD is not already open, arrange for it to be open with FLAGS. */ +static void +force_open (int fd, int flags) +{ + if (dup2 (fd, fd) < 0 && errno == EBADF) + { + int n = open (NULL_DEVICE, flags); + if (n < 0 || (fd != n && (dup2 (n, fd) < 0 || emacs_close (n) != 0))) + { + emacs_perror (NULL_DEVICE); + exit (EXIT_FAILURE); + } + } +} + +/* Make sure stdin, stdout, and stderr are open to something, so that + their file descriptors are not hijacked by later system calls. */ +void +init_standard_fds (void) +{ + /* Open stdin for *writing*, and stdout and stderr for *reading*. + That way, any attempt to do normal I/O will result in an error, + just as if the files were closed, and the file descriptors will + not be reused by later opens. */ + force_open (STDIN_FILENO, O_WRONLY); + force_open (STDOUT_FILENO, O_RDONLY); + force_open (STDERR_FILENO, O_RDONLY); +} + +/* Return the current working directory. The result should be freed + with 'free'. Return NULL on errors. */ char * -get_current_dir_name (void) +emacs_get_current_dir_name (void) { +# if HAVE_GET_CURRENT_DIR_NAME && !BROKEN_GET_CURRENT_DIR_NAME +# ifdef HYBRID_MALLOC + bool use_libc = bss_sbrk_did_unexec; +# else + bool use_libc = true; +# endif + if (use_libc) + return get_current_dir_name (); +# endif + char *buf; char *pwd = getenv ("PWD"); struct stat dotstat, pwdstat; @@ -184,7 +262,6 @@ get_current_dir_name (void) } return buf; } -#endif /* Discard pending input on all input descriptors. */ @@ -471,15 +548,16 @@ void sys_subshell (void) { #ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */ - int st; #ifdef MSDOS + int st; char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */ #else char oldwd[MAX_UTF8_PATH]; -#endif +#endif /* MSDOS */ +#else /* !DOS_NT */ + int status; #endif pid_t pid; - int status; struct save_signal saved_handlers[5]; char *str = SSDATA (encode_current_directory ()); @@ -659,14 +737,6 @@ unrequest_sigio (void) interrupts_deferred = 1; #endif } - -void -ignore_sigio (void) -{ -#ifdef USABLE_SIGIO - signal (SIGIO, SIG_IGN); -#endif -} #ifndef MSDOS /* Block SIGCHLD. */ @@ -910,7 +980,9 @@ void init_sys_modes (struct tty_display_info *tty_out) { struct emacs_tty tty; +#ifndef DOS_NT Lisp_Object terminal; +#endif Vtty_erase_char = Qnil; @@ -1409,6 +1481,12 @@ setup_pty (int fd) void init_system_name (void) { + if (!build_details) + { + /* Set system-name to nil so that the build is deterministic. */ + Vsystem_name = Qnil; + return; + } char *hostname_alloc = NULL; char *hostname; #ifndef HAVE_GETHOSTNAME @@ -1620,7 +1698,7 @@ handle_arith_signal (int sig) xsignal0 (Qarith_error); } -#ifdef HAVE_STACK_OVERFLOW_HANDLING +#if defined HAVE_STACK_OVERFLOW_HANDLING && !defined WINDOWSNT /* Alternate stack used by SIGSEGV handler below. */ @@ -1632,6 +1710,9 @@ static unsigned char sigsegv_stack[SIGSTKSZ]; static bool stack_overflow (siginfo_t *siginfo) { + if (!attempt_stack_overflow_recovery) + return false; + /* In theory, a more-accurate heuristic can be obtained by using GNU/Linux pthread_getattr_np along with POSIX pthread_attr_getstack and pthread_attr_getguardsize to find the location and size of the @@ -1716,7 +1797,7 @@ init_sigsegv (void) return sigaction (SIGSEGV, &sa, NULL) < 0 ? 0 : 1; } -#else /* not HAVE_STACK_OVERFLOW_HANDLING */ +#else /* not HAVE_STACK_OVERFLOW_HANDLING or WINDOWSNT */ static bool init_sigsegv (void) @@ -1724,7 +1805,7 @@ init_sigsegv (void) return 0; } -#endif /* HAVE_STACK_OVERFLOW_HANDLING */ +#endif /* HAVE_STACK_OVERFLOW_HANDLING && !WINDOWSNT */ static void deliver_arith_signal (int sig) @@ -2078,36 +2159,56 @@ init_signals (bool dumping) # endif /* !HAVE_RANDOM */ #endif /* !RAND_BITS */ +#ifdef HAVE_RANDOM +typedef unsigned int random_seed; +static void set_random_seed (random_seed arg) { srandom (arg); } +#elif defined HAVE_LRAND48 +/* Although srand48 uses a long seed, this is unsigned long to avoid + undefined behavior on signed integer overflow in init_random. */ +typedef unsigned long int random_seed; +static void set_random_seed (random_seed arg) { srand48 (arg); } +#else +typedef unsigned int random_seed; +static void set_random_seed (random_seed arg) { srand (arg); } +#endif + void seed_random (void *seed, ptrdiff_t seed_size) { -#if defined HAVE_RANDOM || ! defined HAVE_LRAND48 - unsigned int arg = 0; -#else - long int arg = 0; -#endif + random_seed arg = 0; unsigned char *argp = (unsigned char *) &arg; unsigned char *seedp = seed; - ptrdiff_t i; - for (i = 0; i < seed_size; i++) + for (ptrdiff_t i = 0; i < seed_size; i++) argp[i % sizeof arg] ^= seedp[i]; -#ifdef HAVE_RANDOM - srandom (arg); -#else -# ifdef HAVE_LRAND48 - srand48 (arg); -# else - srand (arg); -# endif -#endif + set_random_seed (arg); } void init_random (void) { - struct timespec t = current_timespec (); - uintmax_t v = getpid () ^ t.tv_sec ^ t.tv_nsec; - seed_random (&v, sizeof v); + random_seed v; + if (! (EQ (emacs_gnutls_global_init (), Qt) + && gnutls_rnd (GNUTLS_RND_NONCE, &v, sizeof v) == 0)) + { + bool success = false; +#ifndef WINDOWSNT + int fd = emacs_open ("/dev/urandom", O_RDONLY, 0); + if (0 <= fd) + { + success = emacs_read (fd, &v, sizeof v) == sizeof v; + emacs_close (fd); + } +#else + success = w32_init_random (&v, sizeof v) == 0; +#endif + if (! success) + { + /* Fall back to current time value + PID. */ + struct timespec t = current_timespec (); + v = getpid () ^ t.tv_sec ^ t.tv_nsec; + } + } + set_random_seed (v); } /* @@ -2271,7 +2372,6 @@ emacs_fopen (char const *file, char const *mode) switch (*m++) { case '+': omode = O_RDWR; break; - case 'b': bflag = O_BINARY; break; case 't': bflag = O_TEXT; break; default: /* Ignore. */ break; } @@ -2440,7 +2540,7 @@ void emacs_perror (char const *message) { int err = errno; - char const *error_string = strerror (err); + char const *error_string = emacs_strerror (err); char const *command = (initial_argv && initial_argv[0] ? initial_argv[0] : "emacs"); /* Write it out all at once, if it's short; this is less likely to @@ -2727,10 +2827,8 @@ Lisp_Object list_system_processes (void) { Lisp_Object procdir, match, proclist, next; - struct gcpro gcpro1, gcpro2; - register Lisp_Object tail; + Lisp_Object tail; - GCPRO2 (procdir, match); /* For every process on the system, there's a directory in the "/proc" pseudo-directory whose name is the numeric ID of that process. */ @@ -2745,7 +2843,6 @@ list_system_processes (void) next = XCDR (tail); XSETCAR (tail, Fstring_to_number (XCAR (tail), Qnil)); } - UNGCPRO; /* directory_files_internal returns the files in reverse order; undo that. */ @@ -2767,7 +2864,6 @@ list_system_processes (void) struct kinfo_proc *procs; size_t i; - struct gcpro gcpro1; Lisp_Object proclist = Qnil; if (sysctl (mib, 3, NULL, &len, NULL, 0) != 0) @@ -2780,7 +2876,6 @@ list_system_processes (void) return proclist; } - GCPRO1 (proclist); len /= sizeof (struct kinfo_proc); for (i = 0; i < len; i++) { @@ -2790,7 +2885,6 @@ list_system_processes (void) proclist = Fcons (make_fixnum_or_float (procs[i].ki_pid), proclist); #endif } - UNGCPRO; xfree (procs); @@ -2999,9 +3093,8 @@ system_process_attributes (Lisp_Object pid) struct timespec tnow, tstart, tboot, telapsed, us_time; double pcpu, pmem; Lisp_Object attrs = Qnil; - Lisp_Object cmd_str, decoded_cmd; + Lisp_Object decoded_cmd; ptrdiff_t count; - struct gcpro gcpro1, gcpro2; CHECK_NUMBER_OR_FLOAT (pid); CONS_TO_INTEGER (pid, pid_t, proc_id); @@ -3009,8 +3102,6 @@ system_process_attributes (Lisp_Object pid) if (stat (procfn, &st) < 0) return attrs; - GCPRO2 (attrs, decoded_cmd); - /* euid egid */ uid = st.st_uid; attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs); @@ -3059,7 +3150,7 @@ system_process_attributes (Lisp_Object pid) else q = NULL; /* Command name is encoded in locale-coding-system; decode it. */ - cmd_str = make_unibyte_string (cmd, cmdsize); + AUTO_STRING_WITH_LEN (cmd_str, cmd, cmdsize); decoded_cmd = code_convert_string_norecord (cmd_str, Vlocale_coding_system, 0); attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs); @@ -3192,14 +3283,13 @@ system_process_attributes (Lisp_Object pid) sprintf (cmdline, "[%.*s]", cmdsize, cmd); } /* Command line is encoded in locale-coding-system; decode it. */ - cmd_str = make_unibyte_string (q, nread); + AUTO_STRING_WITH_LEN (cmd_str, q, nread); decoded_cmd = code_convert_string_norecord (cmd_str, Vlocale_coding_system, 0); unbind_to (count, Qnil); attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); } - UNGCPRO; return attrs; } @@ -3238,7 +3328,6 @@ system_process_attributes (Lisp_Object pid) gid_t gid; Lisp_Object attrs = Qnil; Lisp_Object decoded_cmd; - struct gcpro gcpro1, gcpro2; ptrdiff_t count; CHECK_NUMBER_OR_FLOAT (pid); @@ -3247,8 +3336,6 @@ system_process_attributes (Lisp_Object pid) if (stat (procfn, &st) < 0) return attrs; - GCPRO2 (attrs, decoded_cmd); - /* euid egid */ uid = st.st_uid; attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs); @@ -3331,17 +3418,16 @@ system_process_attributes (Lisp_Object pid) make_float (100.0 / 0x8000 * pinfo.pr_pctmem)), attrs); - decoded_cmd = (code_convert_string_norecord - (build_unibyte_string (pinfo.pr_fname), - Vlocale_coding_system, 0)); + AUTO_STRING (fname, pinfo.pr_fname); + decoded_cmd = code_convert_string_norecord (fname, + Vlocale_coding_system, 0); attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs); - decoded_cmd = (code_convert_string_norecord - (build_unibyte_string (pinfo.pr_psargs), - Vlocale_coding_system, 0)); + AUTO_STRING (psargs, pinfo.pr_psargs); + decoded_cmd = code_convert_string_norecord (psargs, + Vlocale_coding_system, 0); attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs); } unbind_to (count, Qnil); - UNGCPRO; return attrs; } @@ -3377,7 +3463,6 @@ system_process_attributes (Lisp_Object pid) struct kinfo_proc proc; size_t proclen = sizeof proc; - struct gcpro gcpro1, gcpro2; Lisp_Object attrs = Qnil; Lisp_Object decoded_comm; @@ -3388,8 +3473,6 @@ system_process_attributes (Lisp_Object pid) if (sysctl (mib, 4, &proc, &proclen, NULL, 0) != 0) return attrs; - GCPRO2 (attrs, decoded_comm); - attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (proc.ki_uid)), attrs); block_input (); @@ -3406,9 +3489,8 @@ system_process_attributes (Lisp_Object pid) if (gr) attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs); - decoded_comm = (code_convert_string_norecord - (build_unibyte_string (proc.ki_comm), - Vlocale_coding_system, 0)); + AUTO_STRING (comm, proc.ki_comm); + decoded_comm = code_convert_string_norecord (comm, Vlocale_coding_system, 0); attrs = Fcons (Fcons (Qcomm, decoded_comm), attrs); { @@ -3519,15 +3601,153 @@ system_process_attributes (Lisp_Object pid) args[i] = ' '; } - decoded_comm = - (code_convert_string_norecord - (build_unibyte_string (args), - Vlocale_coding_system, 0)); + AUTO_STRING (comm, args); + decoded_comm = code_convert_string_norecord (comm, + Vlocale_coding_system, 0); attrs = Fcons (Fcons (Qargs, decoded_comm), attrs); } - UNGCPRO; + return attrs; +} + +#elif defined DARWIN_OS + +static struct timespec +timeval_to_timespec (struct timeval t) +{ + return make_timespec (t.tv_sec, t.tv_usec * 1000); +} + +static Lisp_Object +make_lisp_timeval (struct timeval t) +{ + return make_lisp_time (timeval_to_timespec (t)); +} + +Lisp_Object +system_process_attributes (Lisp_Object pid) +{ + int proc_id; + int pagesize = getpagesize (); + unsigned long npages; + int fscale; + struct passwd *pw; + struct group *gr; + char *ttyname; + size_t len; + char args[MAXPATHLEN]; + struct timeval starttime; + struct timespec t, now; + struct rusage *rusage; + dev_t tdev; + uid_t uid; + gid_t gid; + + int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID}; + struct kinfo_proc proc; + size_t proclen = sizeof proc; + + Lisp_Object attrs = Qnil; + Lisp_Object decoded_comm; + + CHECK_NUMBER_OR_FLOAT (pid); + CONS_TO_INTEGER (pid, int, proc_id); + mib[3] = proc_id; + + if (sysctl (mib, 4, &proc, &proclen, NULL, 0) != 0) + return attrs; + + uid = proc.kp_eproc.e_ucred.cr_uid; + attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs); + + block_input (); + pw = getpwuid (uid); + unblock_input (); + if (pw) + attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs); + + gid = proc.kp_eproc.e_pcred.p_svgid; + attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid)), attrs); + + block_input (); + gr = getgrgid (gid); + unblock_input (); + if (gr) + attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs); + + decoded_comm = (code_convert_string_norecord + (build_unibyte_string (proc.kp_proc.p_comm), + Vlocale_coding_system, 0)); + + attrs = Fcons (Fcons (Qcomm, decoded_comm), attrs); + { + char state[2] = {'\0', '\0'}; + switch (proc.kp_proc.p_stat) + { + case SRUN: + state[0] = 'R'; + break; + + case SSLEEP: + state[0] = 'S'; + break; + + case SZOMB: + state[0] = 'Z'; + break; + + case SSTOP: + state[0] = 'T'; + break; + + case SIDL: + state[0] = 'I'; + break; + } + attrs = Fcons (Fcons (Qstate, build_string (state)), attrs); + } + + attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (proc.kp_eproc.e_ppid)), + attrs); + attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (proc.kp_eproc.e_pgid)), + attrs); + + tdev = proc.kp_eproc.e_tdev; + block_input (); + ttyname = tdev == NODEV ? NULL : devname (tdev, S_IFCHR); + unblock_input (); + if (ttyname) + attrs = Fcons (Fcons (Qtty, build_string (ttyname)), attrs); + + attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (proc.kp_eproc.e_tpgid)), + attrs); + + rusage = proc.kp_proc.p_ru; + if (rusage) + { + attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (rusage->ru_minflt)), + attrs); + attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (rusage->ru_majflt)), + attrs); + + attrs = Fcons (Fcons (Qutime, make_lisp_timeval (rusage->ru_utime)), + attrs); + attrs = Fcons (Fcons (Qstime, make_lisp_timeval (rusage->ru_stime)), + attrs); + t = timespec_add (timeval_to_timespec (rusage->ru_utime), + timeval_to_timespec (rusage->ru_stime)); + attrs = Fcons (Fcons (Qtime, make_lisp_time (t)), attrs); + } + + starttime = proc.kp_proc.p_starttime; + attrs = Fcons (Fcons (Qnice, make_number (proc.kp_proc.p_nice)), attrs); + attrs = Fcons (Fcons (Qstart, make_lisp_timeval (starttime)), attrs); + + now = current_timespec (); + t = timespec_sub (now, timeval_to_timespec (starttime)); + attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs); + return attrs; } @@ -3687,7 +3907,7 @@ str_collate (Lisp_Object s1, Lisp_Object s2, locale_t loc = newlocale (LC_COLLATE_MASK | LC_CTYPE_MASK, SSDATA (locale), 0); if (!loc) - error ("Invalid locale %s: %s", SSDATA (locale), strerror (errno)); + error ("Invalid locale %s: %s", SSDATA (locale), emacs_strerror (errno)); if (! NILP (ignore_case)) for (int i = 1; i < 3; i++) @@ -3718,10 +3938,10 @@ str_collate (Lisp_Object s1, Lisp_Object s2, } # ifndef HAVE_NEWLOCALE if (err) - error ("Invalid locale or string for collation: %s", strerror (err)); + error ("Invalid locale or string for collation: %s", emacs_strerror (err)); # else if (err) - error ("Invalid string for collation: %s", strerror (err)); + error ("Invalid string for collation: %s", emacs_strerror (err)); # endif SAFE_FREE (); @@ -3739,7 +3959,7 @@ str_collate (Lisp_Object s1, Lisp_Object s2, int res, err = errno; errno = 0; - res = w32_compare_strings (SDATA (s1), SDATA (s2), loc, !NILP (ignore_case)); + res = w32_compare_strings (SSDATA (s1), SSDATA (s2), loc, !NILP (ignore_case)); if (errno) error ("Invalid string for collation: %s", strerror (errno));