diff options
| author | Paul Eggert | 2012-11-28 14:33:35 -0800 |
|---|---|---|
| committer | Paul Eggert | 2012-11-28 14:33:35 -0800 |
| commit | 60aeceb8c41fffee197d43e7eae2b46d9e3fcc74 (patch) | |
| tree | e29f8adf206ac107b41ea6769d17589381da78fe /src/callproc.c | |
| parent | e7c8fcc44eff6dbc6ccb6ebc7f6389233ee516ab (diff) | |
| download | emacs-60aeceb8c41fffee197d43e7eae2b46d9e3fcc74.tar.gz emacs-60aeceb8c41fffee197d43e7eae2b46d9e3fcc74.zip | |
* callproc.c (Fcall_process): Fix vfork portability problems.
Do not assume that fd[0], count, filefd, and save_environ survive
vfork. Fix bug whereby wrong errno value could be reported for
pipe failure. Some minor cleanups, too, as follows. Move buf and
bufsize to the context where they're needed. Change new_argv to
be of type char **, as this is more convenient and avoids casts.
(CALLPROC_BUFFER_SIZE_MIN, CALLPROC_BUFFER_SIZE_MAX):
Now local constants, not macros.
Diffstat (limited to 'src/callproc.c')
| -rw-r--r-- | src/callproc.c | 86 |
1 files changed, 48 insertions, 38 deletions
diff --git a/src/callproc.c b/src/callproc.c index c9a504746b3..bba1c043b4c 100644 --- a/src/callproc.c +++ b/src/callproc.c | |||
| @@ -183,16 +183,11 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 183 | { | 183 | { |
| 184 | Lisp_Object infile, buffer, current_dir, path, cleanup_info_tail; | 184 | Lisp_Object infile, buffer, current_dir, path, cleanup_info_tail; |
| 185 | bool display_p; | 185 | bool display_p; |
| 186 | int fd[2]; | 186 | int fd0, fd1, filefd; |
| 187 | int filefd; | ||
| 188 | #define CALLPROC_BUFFER_SIZE_MIN (16 * 1024) | ||
| 189 | #define CALLPROC_BUFFER_SIZE_MAX (4 * CALLPROC_BUFFER_SIZE_MIN) | ||
| 190 | char buf[CALLPROC_BUFFER_SIZE_MAX]; | ||
| 191 | int bufsize = CALLPROC_BUFFER_SIZE_MIN; | ||
| 192 | ptrdiff_t count = SPECPDL_INDEX (); | 187 | ptrdiff_t count = SPECPDL_INDEX (); |
| 193 | USE_SAFE_ALLOCA; | 188 | USE_SAFE_ALLOCA; |
| 194 | 189 | ||
| 195 | register const unsigned char **new_argv; | 190 | char **new_argv; |
| 196 | /* File to use for stderr in the child. | 191 | /* File to use for stderr in the child. |
| 197 | t means use same as standard output. */ | 192 | t means use same as standard output. */ |
| 198 | Lisp_Object error_file; | 193 | Lisp_Object error_file; |
| @@ -432,12 +427,12 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 432 | } | 427 | } |
| 433 | UNGCPRO; | 428 | UNGCPRO; |
| 434 | for (i = 4; i < nargs; i++) | 429 | for (i = 4; i < nargs; i++) |
| 435 | new_argv[i - 3] = SDATA (args[i]); | 430 | new_argv[i - 3] = SSDATA (args[i]); |
| 436 | new_argv[i - 3] = 0; | 431 | new_argv[i - 3] = 0; |
| 437 | } | 432 | } |
| 438 | else | 433 | else |
| 439 | new_argv[1] = 0; | 434 | new_argv[1] = 0; |
| 440 | new_argv[0] = SDATA (path); | 435 | new_argv[0] = SSDATA (path); |
| 441 | 436 | ||
| 442 | #ifdef MSDOS /* MW, July 1993 */ | 437 | #ifdef MSDOS /* MW, July 1993 */ |
| 443 | 438 | ||
| @@ -466,29 +461,35 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 466 | } | 461 | } |
| 467 | else | 462 | else |
| 468 | outfilefd = fd_output; | 463 | outfilefd = fd_output; |
| 469 | fd[0] = filefd; | 464 | fd0 = filefd; |
| 470 | fd[1] = outfilefd; | 465 | fd1 = outfilefd; |
| 471 | #endif /* MSDOS */ | 466 | #endif /* MSDOS */ |
| 472 | 467 | ||
| 473 | if (INTEGERP (buffer)) | 468 | if (INTEGERP (buffer)) |
| 474 | fd[1] = emacs_open (NULL_DEVICE, O_WRONLY, 0), fd[0] = -1; | 469 | { |
| 470 | fd0 = -1; | ||
| 471 | fd1 = emacs_open (NULL_DEVICE, O_WRONLY, 0); | ||
| 472 | } | ||
| 475 | else | 473 | else |
| 476 | { | 474 | { |
| 477 | #ifndef MSDOS | 475 | #ifndef MSDOS |
| 478 | errno = 0; | 476 | int fd[2]; |
| 479 | if (pipe (fd) == -1) | 477 | if (pipe (fd) == -1) |
| 480 | { | 478 | { |
| 479 | int pipe_errno = errno; | ||
| 481 | emacs_close (filefd); | 480 | emacs_close (filefd); |
| 481 | errno = pipe_errno; | ||
| 482 | report_file_error ("Creating process pipe", Qnil); | 482 | report_file_error ("Creating process pipe", Qnil); |
| 483 | } | 483 | } |
| 484 | fd0 = fd[0]; | ||
| 485 | fd1 = fd[1]; | ||
| 484 | #endif | 486 | #endif |
| 485 | } | 487 | } |
| 486 | 488 | ||
| 487 | { | 489 | { |
| 488 | /* child_setup must clobber environ in systems with true vfork. | 490 | /* child_setup must clobber environ in systems with true vfork. |
| 489 | Protect it from permanent change. */ | 491 | Protect it from permanent change. */ |
| 490 | register char **save_environ = environ; | 492 | char **save_environ = environ; |
| 491 | register int fd1 = fd[1]; | ||
| 492 | int fd_error = fd1; | 493 | int fd_error = fd1; |
| 493 | 494 | ||
| 494 | if (fd_output >= 0) | 495 | if (fd_output >= 0) |
| @@ -520,8 +521,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 520 | if (fd_error < 0) | 521 | if (fd_error < 0) |
| 521 | { | 522 | { |
| 522 | emacs_close (filefd); | 523 | emacs_close (filefd); |
| 523 | if (fd[0] != filefd) | 524 | if (fd0 != filefd) |
| 524 | emacs_close (fd[0]); | 525 | emacs_close (fd0); |
| 525 | if (fd1 >= 0) | 526 | if (fd1 >= 0) |
| 526 | emacs_close (fd1); | 527 | emacs_close (fd1); |
| 527 | #ifdef MSDOS | 528 | #ifdef MSDOS |
| @@ -538,8 +539,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 538 | /* Note that on MSDOS `child_setup' actually returns the child process | 539 | /* Note that on MSDOS `child_setup' actually returns the child process |
| 539 | exit status, not its PID, so we assign it to `synch_process_retcode' | 540 | exit status, not its PID, so we assign it to `synch_process_retcode' |
| 540 | below. */ | 541 | below. */ |
| 541 | pid = child_setup (filefd, outfilefd, fd_error, (char **) new_argv, | 542 | pid = child_setup (filefd, outfilefd, fd_error, new_argv, 0, current_dir); |
| 542 | 0, current_dir); | ||
| 543 | 543 | ||
| 544 | /* Record that the synchronous process exited and note its | 544 | /* Record that the synchronous process exited and note its |
| 545 | termination status. */ | 545 | termination status. */ |
| @@ -559,8 +559,8 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 559 | { | 559 | { |
| 560 | /* Since CRLF is converted to LF within `decode_coding', we | 560 | /* Since CRLF is converted to LF within `decode_coding', we |
| 561 | can always open a file with binary mode. */ | 561 | can always open a file with binary mode. */ |
| 562 | fd[0] = emacs_open (tempfile, O_RDONLY | O_BINARY, 0); | 562 | fd0 = emacs_open (tempfile, O_RDONLY | O_BINARY, 0); |
| 563 | if (fd[0] < 0) | 563 | if (fd0 < 0) |
| 564 | { | 564 | { |
| 565 | unlink (tempfile); | 565 | unlink (tempfile); |
| 566 | emacs_close (filefd); | 566 | emacs_close (filefd); |
| @@ -569,11 +569,10 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 569 | } | 569 | } |
| 570 | } | 570 | } |
| 571 | else | 571 | else |
| 572 | fd[0] = -1; /* We are not going to read from tempfile. */ | 572 | fd0 = -1; /* We are not going to read from tempfile. */ |
| 573 | #else /* not MSDOS */ | 573 | #else /* not MSDOS */ |
| 574 | #ifdef WINDOWSNT | 574 | #ifdef WINDOWSNT |
| 575 | pid = child_setup (filefd, fd1, fd_error, (char **) new_argv, | 575 | pid = child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); |
| 576 | 0, current_dir); | ||
| 577 | #else /* not WINDOWSNT */ | 576 | #else /* not WINDOWSNT */ |
| 578 | 577 | ||
| 579 | block_input (); | 578 | block_input (); |
| @@ -586,11 +585,15 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 586 | bool volatile display_p_volatile = display_p; | 585 | bool volatile display_p_volatile = display_p; |
| 587 | bool volatile output_to_buffer_volatile = output_to_buffer; | 586 | bool volatile output_to_buffer_volatile = output_to_buffer; |
| 588 | bool volatile sa_must_free_volatile = sa_must_free; | 587 | bool volatile sa_must_free_volatile = sa_must_free; |
| 588 | int volatile fd0_volatile = fd0; | ||
| 589 | int volatile fd1_volatile = fd1; | 589 | int volatile fd1_volatile = fd1; |
| 590 | int volatile fd_error_volatile = fd_error; | 590 | int volatile fd_error_volatile = fd_error; |
| 591 | int volatile fd_output_volatile = fd_output; | 591 | int volatile fd_output_volatile = fd_output; |
| 592 | int volatile filefd_volatile = filefd; | ||
| 593 | ptrdiff_t volatile count_volatile = count; | ||
| 592 | ptrdiff_t volatile sa_count_volatile = sa_count; | 594 | ptrdiff_t volatile sa_count_volatile = sa_count; |
| 593 | unsigned char const **volatile new_argv_volatile = new_argv; | 595 | char **volatile new_argv_volatile = new_argv; |
| 596 | char **volatile new_save_environ = save_environ; | ||
| 594 | 597 | ||
| 595 | pid = vfork (); | 598 | pid = vfork (); |
| 596 | 599 | ||
| @@ -598,27 +601,30 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 598 | coding_systems = coding_systems_volatile; | 601 | coding_systems = coding_systems_volatile; |
| 599 | current_dir = current_dir_volatile; | 602 | current_dir = current_dir_volatile; |
| 600 | display_p = display_p_volatile; | 603 | display_p = display_p_volatile; |
| 604 | output_to_buffer = output_to_buffer_volatile; | ||
| 605 | sa_must_free = sa_must_free_volatile; | ||
| 606 | fd0 = fd0_volatile; | ||
| 601 | fd1 = fd1_volatile; | 607 | fd1 = fd1_volatile; |
| 602 | fd_error = fd_error_volatile; | 608 | fd_error = fd_error_volatile; |
| 603 | fd_output = fd_output_volatile; | 609 | fd_output = fd_output_volatile; |
| 604 | output_to_buffer = output_to_buffer_volatile; | 610 | filefd = filefd_volatile; |
| 605 | sa_must_free = sa_must_free_volatile; | 611 | count = count_volatile; |
| 606 | sa_count = sa_count_volatile; | 612 | sa_count = sa_count_volatile; |
| 607 | new_argv = new_argv_volatile; | 613 | new_argv = new_argv_volatile; |
| 614 | save_environ = new_save_environ; | ||
| 608 | } | 615 | } |
| 609 | 616 | ||
| 610 | if (pid == 0) | 617 | if (pid == 0) |
| 611 | { | 618 | { |
| 612 | if (fd[0] >= 0) | 619 | if (fd0 >= 0) |
| 613 | emacs_close (fd[0]); | 620 | emacs_close (fd0); |
| 614 | 621 | ||
| 615 | setsid (); | 622 | setsid (); |
| 616 | 623 | ||
| 617 | /* Emacs ignores SIGPIPE, but the child should not. */ | 624 | /* Emacs ignores SIGPIPE, but the child should not. */ |
| 618 | signal (SIGPIPE, SIG_DFL); | 625 | signal (SIGPIPE, SIG_DFL); |
| 619 | 626 | ||
| 620 | child_setup (filefd, fd1, fd_error, (char **) new_argv, | 627 | child_setup (filefd, fd1, fd_error, new_argv, 0, current_dir); |
| 621 | 0, current_dir); | ||
| 622 | } | 628 | } |
| 623 | 629 | ||
| 624 | unblock_input (); | 630 | unblock_input (); |
| @@ -632,7 +638,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 632 | 638 | ||
| 633 | environ = save_environ; | 639 | environ = save_environ; |
| 634 | 640 | ||
| 635 | /* Close most of our fd's, but not fd[0] | 641 | /* Close most of our file descriptors, but not fd0 |
| 636 | since we will use that to read input from. */ | 642 | since we will use that to read input from. */ |
| 637 | emacs_close (filefd); | 643 | emacs_close (filefd); |
| 638 | if (fd_output >= 0) | 644 | if (fd_output >= 0) |
| @@ -643,15 +649,15 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 643 | 649 | ||
| 644 | if (pid < 0) | 650 | if (pid < 0) |
| 645 | { | 651 | { |
| 646 | if (fd[0] >= 0) | 652 | if (fd0 >= 0) |
| 647 | emacs_close (fd[0]); | 653 | emacs_close (fd0); |
| 648 | report_file_error ("Doing vfork", Qnil); | 654 | report_file_error ("Doing vfork", Qnil); |
| 649 | } | 655 | } |
| 650 | 656 | ||
| 651 | if (INTEGERP (buffer)) | 657 | if (INTEGERP (buffer)) |
| 652 | { | 658 | { |
| 653 | if (fd[0] >= 0) | 659 | if (fd0 >= 0) |
| 654 | emacs_close (fd[0]); | 660 | emacs_close (fd0); |
| 655 | return Qnil; | 661 | return Qnil; |
| 656 | } | 662 | } |
| 657 | 663 | ||
| @@ -666,7 +672,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 666 | #endif /* not MSDOS */ | 672 | #endif /* not MSDOS */ |
| 667 | record_unwind_protect (call_process_cleanup, | 673 | record_unwind_protect (call_process_cleanup, |
| 668 | Fcons (Fcurrent_buffer (), | 674 | Fcons (Fcurrent_buffer (), |
| 669 | Fcons (INTEGER_TO_CONS (fd[0]), | 675 | Fcons (INTEGER_TO_CONS (fd0), |
| 670 | cleanup_info_tail))); | 676 | cleanup_info_tail))); |
| 671 | 677 | ||
| 672 | if (BUFFERP (buffer)) | 678 | if (BUFFERP (buffer)) |
| @@ -723,6 +729,10 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 723 | 729 | ||
| 724 | if (output_to_buffer) | 730 | if (output_to_buffer) |
| 725 | { | 731 | { |
| 732 | enum { CALLPROC_BUFFER_SIZE_MIN = 16 * 1024 }; | ||
| 733 | enum { CALLPROC_BUFFER_SIZE_MAX = 4 * CALLPROC_BUFFER_SIZE_MIN }; | ||
| 734 | char buf[CALLPROC_BUFFER_SIZE_MAX]; | ||
| 735 | int bufsize = CALLPROC_BUFFER_SIZE_MIN; | ||
| 726 | int nread; | 736 | int nread; |
| 727 | bool first = 1; | 737 | bool first = 1; |
| 728 | EMACS_INT total_read = 0; | 738 | EMACS_INT total_read = 0; |
| @@ -739,7 +749,7 @@ usage: (call-process PROGRAM &optional INFILE BUFFER DISPLAY &rest ARGS) */) | |||
| 739 | nread = carryover; | 749 | nread = carryover; |
| 740 | while (nread < bufsize - 1024) | 750 | while (nread < bufsize - 1024) |
| 741 | { | 751 | { |
| 742 | int this_read = emacs_read (fd[0], buf + nread, | 752 | int this_read = emacs_read (fd0, buf + nread, |
| 743 | bufsize - nread); | 753 | bufsize - nread); |
| 744 | 754 | ||
| 745 | if (this_read < 0) | 755 | if (this_read < 0) |