aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPaul Eggert2016-04-04 09:36:30 -0700
committerPaul Eggert2016-04-04 09:44:19 -0700
commit6bccb19c9bef1189c8e853ff7cc16b889a3a57e3 (patch)
tree9555d6605362ec0c452b343d549d2af3c983415d /src
parenta11756ad0e2ee719266c0081150c20996cce8e0d (diff)
downloademacs-6bccb19c9bef1189c8e853ff7cc16b889a3a57e3.tar.gz
emacs-6bccb19c9bef1189c8e853ff7cc16b889a3a57e3.zip
Port redirect-debugging-output to non-GNU/Linux
Problem reported by Kylie McClain for musl in: http://lists.gnu.org/archive/html/emacs-devel/2016-03/msg01592.html * etc/DEBUG, etc/NEWS: Mention this. * src/callproc.c (child_setup) [!MSDOS]: * src/dispnew.c (init_display): * src/emacs.c (main, Fdaemon_initialized): * src/minibuf.c (read_minibuf_noninteractive): * src/regex.c (xmalloc, xrealloc): Prefer symbolic names like STDERR_FILENO to magic numbers like 2, to make file-descriptor manipulation easier to follow. * src/emacs.c (relocate_fd) [!WINDOWSNT]: Remove; no longer needed now that we make sure stdin, stdout and stderr are open. All uses removed. (main): Make sure standard FDs are OK. Prefer symbolic names like EXIT_FAILURE to magic numbers like 1. Use bool for boolean. * src/lisp.h (init_standard_fds): New decl. * src/print.c (WITH_REDIRECT_DEBUGGING_OUTPUT) [GNU_LINUX]: Remove; no longer needed. (Fredirect_debugging_output): Define on all platforms, not just GNU/Linux. Redirect file descriptor, not stream, so that the code works even if stderr is not an lvalue. Report an error if the file arg is neither a string nor nil. (syms_of_print): Always define redirect-debugging-output. * src/sysdep.c (force_open, init_standard_fds): New functions.
Diffstat (limited to 'src')
-rw-r--r--src/callproc.c58
-rw-r--r--src/dispnew.c2
-rw-r--r--src/emacs.c28
-rw-r--r--src/lisp.h1
-rw-r--r--src/minibuf.c12
-rw-r--r--src/print.c51
-rw-r--r--src/regex.c4
-rw-r--r--src/sysdep.c29
8 files changed, 81 insertions, 104 deletions
diff --git a/src/callproc.c b/src/callproc.c
index db602f538c9..8578556b695 100644
--- a/src/callproc.c
+++ b/src/callproc.c
@@ -1078,10 +1078,6 @@ usage: (call-process-region START END PROGRAM &optional DELETE BUFFER DISPLAY &r
1078 return unbind_to (count, val); 1078 return unbind_to (count, val);
1079} 1079}
1080 1080
1081#ifndef WINDOWSNT
1082static int relocate_fd (int fd, int minfd);
1083#endif
1084
1085static char ** 1081static char **
1086add_env (char **env, char **new_env, char *string) 1082add_env (char **env, char **new_env, char *string)
1087{ 1083{
@@ -1310,37 +1306,14 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
1310 return cpid; 1306 return cpid;
1311 1307
1312#else /* not WINDOWSNT */ 1308#else /* not WINDOWSNT */
1313 /* Make sure that in, out, and err are not actually already in
1314 descriptors zero, one, or two; this could happen if Emacs is
1315 started with its standard in, out, or error closed, as might
1316 happen under X. */
1317 {
1318 int oin = in, oout = out;
1319
1320 /* We have to avoid relocating the same descriptor twice! */
1321
1322 in = relocate_fd (in, 3);
1323
1324 if (out == oin)
1325 out = in;
1326 else
1327 out = relocate_fd (out, 3);
1328
1329 if (err == oin)
1330 err = in;
1331 else if (err == oout)
1332 err = out;
1333 else
1334 err = relocate_fd (err, 3);
1335 }
1336 1309
1337#ifndef MSDOS 1310#ifndef MSDOS
1338 /* Redirect file descriptors and clear the close-on-exec flag on the 1311 /* Redirect file descriptors and clear the close-on-exec flag on the
1339 redirected ones. IN, OUT, and ERR are close-on-exec so they 1312 redirected ones. IN, OUT, and ERR are close-on-exec so they
1340 need not be closed explicitly. */ 1313 need not be closed explicitly. */
1341 dup2 (in, 0); 1314 dup2 (in, STDIN_FILENO);
1342 dup2 (out, 1); 1315 dup2 (out, STDOUT_FILENO);
1343 dup2 (err, 2); 1316 dup2 (err, STDERR_FILENO);
1344 1317
1345 setpgid (0, 0); 1318 setpgid (0, 0);
1346 tcsetpgrp (0, pid); 1319 tcsetpgrp (0, pid);
@@ -1359,31 +1332,6 @@ child_setup (int in, int out, int err, char **new_argv, bool set_pgrp,
1359#endif /* not WINDOWSNT */ 1332#endif /* not WINDOWSNT */
1360} 1333}
1361 1334
1362#ifndef WINDOWSNT
1363/* Move the file descriptor FD so that its number is not less than MINFD.
1364 If the file descriptor is moved at all, the original is closed on MSDOS,
1365 but not elsewhere as the caller will close it anyway. */
1366static int
1367relocate_fd (int fd, int minfd)
1368{
1369 if (fd >= minfd)
1370 return fd;
1371 else
1372 {
1373 int new = fcntl (fd, F_DUPFD_CLOEXEC, minfd);
1374 if (new == -1)
1375 {
1376 emacs_perror ("while setting up child");
1377 _exit (EXIT_CANCELED);
1378 }
1379#ifdef MSDOS
1380 emacs_close (fd);
1381#endif
1382 return new;
1383 }
1384}
1385#endif /* not WINDOWSNT */
1386
1387static bool 1335static bool
1388getenv_internal_1 (const char *var, ptrdiff_t varlen, char **value, 1336getenv_internal_1 (const char *var, ptrdiff_t varlen, char **value,
1389 ptrdiff_t *valuelen, Lisp_Object env) 1337 ptrdiff_t *valuelen, Lisp_Object env)
diff --git a/src/dispnew.c b/src/dispnew.c
index 3a0532a693b..51caa5b10e7 100644
--- a/src/dispnew.c
+++ b/src/dispnew.c
@@ -6038,7 +6038,7 @@ init_display (void)
6038#endif 6038#endif
6039 6039
6040 /* If no window system has been specified, try to use the terminal. */ 6040 /* If no window system has been specified, try to use the terminal. */
6041 if (! isatty (0)) 6041 if (! isatty (STDIN_FILENO))
6042 fatal ("standard input is not a tty"); 6042 fatal ("standard input is not a tty");
6043 6043
6044#ifdef WINDOWSNT 6044#ifdef WINDOWSNT
diff --git a/src/emacs.c b/src/emacs.c
index 95d1905ae22..c21c9e3971c 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -721,6 +721,7 @@ main (int argc, char **argv)
721 unexec_init_emacs_zone (); 721 unexec_init_emacs_zone ();
722#endif 722#endif
723 723
724 init_standard_fds ();
724 atexit (close_output_streams); 725 atexit (close_output_streams);
725 726
726#ifdef HAVE_MODULES 727#ifdef HAVE_MODULES
@@ -899,24 +900,25 @@ main (int argc, char **argv)
899 char *term; 900 char *term;
900 if (argmatch (argv, argc, "-t", "--terminal", 4, &term, &skip_args)) 901 if (argmatch (argv, argc, "-t", "--terminal", 4, &term, &skip_args))
901 { 902 {
902 int result; 903 emacs_close (STDIN_FILENO);
903 emacs_close (0); 904 emacs_close (STDOUT_FILENO);
904 emacs_close (1); 905 int result = emacs_open (term, O_RDWR, 0);
905 result = emacs_open (term, O_RDWR, 0); 906 if (result != STDIN_FILENO
906 if (result < 0 || fcntl (0, F_DUPFD_CLOEXEC, 1) < 0) 907 || (fcntl (STDIN_FILENO, F_DUPFD_CLOEXEC, STDOUT_FILENO)
908 != STDOUT_FILENO))
907 { 909 {
908 char *errstring = strerror (errno); 910 char *errstring = strerror (errno);
909 fprintf (stderr, "%s: %s: %s\n", argv[0], term, errstring); 911 fprintf (stderr, "%s: %s: %s\n", argv[0], term, errstring);
910 exit (1); 912 exit (EXIT_FAILURE);
911 } 913 }
912 if (! isatty (0)) 914 if (! isatty (STDIN_FILENO))
913 { 915 {
914 fprintf (stderr, "%s: %s: not a tty\n", argv[0], term); 916 fprintf (stderr, "%s: %s: not a tty\n", argv[0], term);
915 exit (1); 917 exit (EXIT_FAILURE);
916 } 918 }
917 fprintf (stderr, "Using %s\n", term); 919 fprintf (stderr, "Using %s\n", term);
918#ifdef HAVE_WINDOW_SYSTEM 920#ifdef HAVE_WINDOW_SYSTEM
919 inhibit_window_system = 1; /* -t => -nw */ 921 inhibit_window_system = true; /* -t => -nw */
920#endif 922#endif
921 } 923 }
922 else 924 else
@@ -1209,7 +1211,7 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
1209 /* Started from GUI? */ 1211 /* Started from GUI? */
1210 /* FIXME: Do the right thing if getenv returns NULL, or if 1212 /* FIXME: Do the right thing if getenv returns NULL, or if
1211 chdir fails. */ 1213 chdir fails. */
1212 if (! inhibit_window_system && ! isatty (0) && ! ch_to_dir) 1214 if (! inhibit_window_system && ! isatty (STDIN_FILENO) && ! ch_to_dir)
1213 chdir (getenv ("HOME")); 1215 chdir (getenv ("HOME"));
1214 if (skip_args < argc) 1216 if (skip_args < argc)
1215 { 1217 {
@@ -2357,9 +2359,9 @@ from the parent process and its tty file descriptors. */)
2357 /* Get rid of stdin, stdout and stderr. */ 2359 /* Get rid of stdin, stdout and stderr. */
2358 nfd = emacs_open ("/dev/null", O_RDWR, 0); 2360 nfd = emacs_open ("/dev/null", O_RDWR, 0);
2359 err |= nfd < 0; 2361 err |= nfd < 0;
2360 err |= dup2 (nfd, 0) < 0; 2362 err |= dup2 (nfd, STDIN_FILENO) < 0;
2361 err |= dup2 (nfd, 1) < 0; 2363 err |= dup2 (nfd, STDOUT_FILENO) < 0;
2362 err |= dup2 (nfd, 2) < 0; 2364 err |= dup2 (nfd, STDERR_FILENO) < 0;
2363 err |= emacs_close (nfd) != 0; 2365 err |= emacs_close (nfd) != 0;
2364 2366
2365 /* Closing the pipe will notify the parent that it can exit. 2367 /* Closing the pipe will notify the parent that it can exit.
diff --git a/src/lisp.h b/src/lisp.h
index 7c8b452dd5f..65335fbc052 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4248,6 +4248,7 @@ struct tty_display_info;
4248struct terminal; 4248struct terminal;
4249 4249
4250/* Defined in sysdep.c. */ 4250/* Defined in sysdep.c. */
4251extern void init_standard_fds (void);
4251extern char *emacs_get_current_dir_name (void); 4252extern char *emacs_get_current_dir_name (void);
4252extern void stuff_char (char c); 4253extern void stuff_char (char c);
4253extern void init_foreground_group (void); 4254extern void init_foreground_group (void);
diff --git a/src/minibuf.c b/src/minibuf.c
index 238a04a8ad2..41814c2b54b 100644
--- a/src/minibuf.c
+++ b/src/minibuf.c
@@ -194,7 +194,7 @@ read_minibuf_noninteractive (Lisp_Object map, Lisp_Object initial,
194 int c; 194 int c;
195 unsigned char hide_char = 0; 195 unsigned char hide_char = 0;
196 struct emacs_tty etty; 196 struct emacs_tty etty;
197 bool etty_valid; 197 bool etty_valid IF_LINT (= false);
198 198
199 /* Check, whether we need to suppress echoing. */ 199 /* Check, whether we need to suppress echoing. */
200 if (CHARACTERP (Vread_hide_char)) 200 if (CHARACTERP (Vread_hide_char))
@@ -203,10 +203,10 @@ read_minibuf_noninteractive (Lisp_Object map, Lisp_Object initial,
203 /* Manipulate tty. */ 203 /* Manipulate tty. */
204 if (hide_char) 204 if (hide_char)
205 { 205 {
206 etty_valid = emacs_get_tty (fileno (stdin), &etty) == 0; 206 etty_valid = emacs_get_tty (STDIN_FILENO, &etty) == 0;
207 if (etty_valid) 207 if (etty_valid)
208 set_binary_mode (fileno (stdin), O_BINARY); 208 set_binary_mode (STDIN_FILENO, O_BINARY);
209 suppress_echo_on_tty (fileno (stdin)); 209 suppress_echo_on_tty (STDIN_FILENO);
210 } 210 }
211 211
212 fwrite (SDATA (prompt), 1, SBYTES (prompt), stdout); 212 fwrite (SDATA (prompt), 1, SBYTES (prompt), stdout);
@@ -240,8 +240,8 @@ read_minibuf_noninteractive (Lisp_Object map, Lisp_Object initial,
240 fprintf (stdout, "\n"); 240 fprintf (stdout, "\n");
241 if (etty_valid) 241 if (etty_valid)
242 { 242 {
243 emacs_set_tty (fileno (stdin), &etty, 0); 243 emacs_set_tty (STDIN_FILENO, &etty, 0);
244 set_binary_mode (fileno (stdin), O_TEXT); 244 set_binary_mode (STDIN_FILENO, O_TEXT);
245 } 245 }
246 } 246 }
247 247
diff --git a/src/print.c b/src/print.c
index 2b53d7580b1..db2918ff478 100644
--- a/src/print.c
+++ b/src/print.c
@@ -775,15 +775,6 @@ debug_output_compilation_hack (bool x)
775 print_output_debug_flag = x; 775 print_output_debug_flag = x;
776} 776}
777 777
778#if defined (GNU_LINUX)
779
780/* This functionality is not vitally important in general, so we rely on
781 non-portable ability to use stderr as lvalue. */
782
783#define WITH_REDIRECT_DEBUGGING_OUTPUT 1
784
785static FILE *initial_stderr_stream = NULL;
786
787DEFUN ("redirect-debugging-output", Fredirect_debugging_output, Sredirect_debugging_output, 778DEFUN ("redirect-debugging-output", Fredirect_debugging_output, Sredirect_debugging_output,
788 1, 2, 779 1, 2,
789 "FDebug output file: \nP", 780 "FDebug output file: \nP",
@@ -793,30 +784,38 @@ Optional arg APPEND non-nil (interactively, with prefix arg) means
793append to existing target file. */) 784append to existing target file. */)
794 (Lisp_Object file, Lisp_Object append) 785 (Lisp_Object file, Lisp_Object append)
795{ 786{
796 if (initial_stderr_stream != NULL) 787 /* If equal to STDERR_FILENO, stderr has not been duplicated and is OK as-is.
797 { 788 Otherwise, this is a close-on-exec duplicate of the original stderr. */
798 block_input (); 789 static int stderr_dup = STDERR_FILENO;
799 fclose (stderr); 790 int fd = stderr_dup;
800 unblock_input ();
801 }
802 stderr = initial_stderr_stream;
803 initial_stderr_stream = NULL;
804 791
805 if (STRINGP (file)) 792 if (! NILP (file))
806 { 793 {
807 file = Fexpand_file_name (file, Qnil); 794 file = Fexpand_file_name (file, Qnil);
808 initial_stderr_stream = stderr; 795
809 stderr = emacs_fopen (SSDATA (file), NILP (append) ? "w" : "a"); 796 if (stderr_dup == STDERR_FILENO)
810 if (stderr == NULL)
811 { 797 {
812 stderr = initial_stderr_stream; 798 int n = fcntl (STDERR_FILENO, F_DUPFD_CLOEXEC, STDERR_FILENO + 1);
813 initial_stderr_stream = NULL; 799 if (n < 0)
814 report_file_error ("Cannot open debugging output stream", file); 800 report_file_error ("dup", file);
801 stderr_dup = n;
815 } 802 }
803
804 fd = emacs_open (SSDATA (ENCODE_FILE (file)),
805 (O_WRONLY | O_CREAT
806 | (! NILP (append) ? O_APPEND : O_TRUNC)),
807 0666);
808 if (fd < 0)
809 report_file_error ("Cannot open debugging output stream", file);
816 } 810 }
811
812 fflush (stderr);
813 if (dup2 (fd, STDERR_FILENO) < 0)
814 report_file_error ("dup2", file);
815 if (fd != stderr_dup)
816 emacs_close (fd);
817 return Qnil; 817 return Qnil;
818} 818}
819#endif /* GNU_LINUX */
820 819
821 820
822/* This is the interface for debugging printing. */ 821/* This is the interface for debugging printing. */
@@ -2305,9 +2304,7 @@ priorities. */);
2305 defsubr (&Sprint); 2304 defsubr (&Sprint);
2306 defsubr (&Sterpri); 2305 defsubr (&Sterpri);
2307 defsubr (&Swrite_char); 2306 defsubr (&Swrite_char);
2308#ifdef WITH_REDIRECT_DEBUGGING_OUTPUT
2309 defsubr (&Sredirect_debugging_output); 2307 defsubr (&Sredirect_debugging_output);
2310#endif
2311 2308
2312 DEFSYM (Qprint_escape_newlines, "print-escape-newlines"); 2309 DEFSYM (Qprint_escape_newlines, "print-escape-newlines");
2313 DEFSYM (Qprint_escape_multibyte, "print-escape-multibyte"); 2310 DEFSYM (Qprint_escape_multibyte, "print-escape-multibyte");
diff --git a/src/regex.c b/src/regex.c
index d5c58aeaf8b..af379367be6 100644
--- a/src/regex.c
+++ b/src/regex.c
@@ -215,7 +215,7 @@ xmalloc (size_t size)
215 void *val = malloc (size); 215 void *val = malloc (size);
216 if (!val && size) 216 if (!val && size)
217 { 217 {
218 write (2, "virtual memory exhausted\n", 25); 218 write (STDERR_FILENO, "virtual memory exhausted\n", 25);
219 exit (1); 219 exit (1);
220 } 220 }
221 return val; 221 return val;
@@ -233,7 +233,7 @@ xrealloc (void *block, size_t size)
233 val = realloc (block, size); 233 val = realloc (block, size);
234 if (!val && size) 234 if (!val && size)
235 { 235 {
236 write (2, "virtual memory exhausted\n", 25); 236 write (STDERR_FILENO, "virtual memory exhausted\n", 25);
237 exit (1); 237 exit (1);
238 } 238 }
239 return val; 239 return val;
diff --git a/src/sysdep.c b/src/sysdep.c
index 6154c1325d8..67c9bd90df7 100644
--- a/src/sysdep.c
+++ b/src/sysdep.c
@@ -130,6 +130,35 @@ static const int baud_convert[] =
130 1800, 2400, 4800, 9600, 19200, 38400 130 1800, 2400, 4800, 9600, 19200, 38400
131 }; 131 };
132 132
133/* If FD is not already open, arrange for it to be open with FLAGS. */
134static void
135force_open (int fd, int flags)
136{
137 if (dup2 (fd, fd) < 0 && errno == EBADF)
138 {
139 int n = open (NULL_DEVICE, flags);
140 if (n < 0 || (fd != n && (dup2 (n, fd) < 0 || emacs_close (n) != 0)))
141 {
142 emacs_perror (NULL_DEVICE);
143 exit (EXIT_FAILURE);
144 }
145 }
146}
147
148/* Make sure stdin, stdout, and stderr are open to something, so that
149 their file descriptors are not hijacked by later system calls. */
150void
151init_standard_fds (void)
152{
153 /* Open stdin for *writing*, and stdout and stderr for *reading*.
154 That way, any attempt to do normal I/O will result in an error,
155 just as if the files were closed, and the file descriptors will
156 not be reused by later opens. */
157 force_open (STDIN_FILENO, O_WRONLY);
158 force_open (STDOUT_FILENO, O_RDONLY);
159 force_open (STDERR_FILENO, O_RDONLY);
160}
161
133/* Return the current working directory. The result should be freed 162/* Return the current working directory. The result should be freed
134 with 'free'. Return NULL on errors. */ 163 with 'free'. Return NULL on errors. */
135char * 164char *