diff options
| author | Daniel Colascione | 2019-06-24 06:20:07 -0700 |
|---|---|---|
| committer | Daniel Colascione | 2019-06-24 06:53:30 -0700 |
| commit | 65d45def8d71e50d111adf1141011a5d30a27447 (patch) | |
| tree | a0550807d637618b3561b344b9070586865c3d90 /src | |
| parent | 157fced053601c993734c61078c42d7905389828 (diff) | |
| download | emacs-65d45def8d71e50d111adf1141011a5d30a27447.tar.gz emacs-65d45def8d71e50d111adf1141011a5d30a27447.zip | |
Fix pdumper executable-finding code
* src/emacs.c:
(load_pdump_find_executable): New function.
(load_pdump): Use it.
Diffstat (limited to 'src')
| -rw-r--r-- | src/emacs.c | 162 |
1 files changed, 137 insertions, 25 deletions
diff --git a/src/emacs.c b/src/emacs.c index 6463c1be1b7..a26eacbe786 100644 --- a/src/emacs.c +++ b/src/emacs.c | |||
| @@ -26,6 +26,7 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 26 | #include <stdlib.h> | 26 | #include <stdlib.h> |
| 27 | 27 | ||
| 28 | #include <sys/file.h> | 28 | #include <sys/file.h> |
| 29 | #include <sys/stat.h> | ||
| 29 | #include <unistd.h> | 30 | #include <unistd.h> |
| 30 | 31 | ||
| 31 | #include <close-stream.h> | 32 | #include <close-stream.h> |
| @@ -704,11 +705,101 @@ dump_error_to_string (enum pdumper_load_result result) | |||
| 704 | } | 705 | } |
| 705 | } | 706 | } |
| 706 | 707 | ||
| 708 | /* Find a path (absolute or relative) to the Emacs executable. | ||
| 709 | Called early in initialization by portable dump loading code, so we | ||
| 710 | can't use lisp and associated machinery. On success, *EXENAME is | ||
| 711 | set to a heap-allocated string giving a path to the Emacs | ||
| 712 | executable or to NULL if we can't determine the path immediately. | ||
| 713 | */ | ||
| 714 | static enum pdumper_load_result | ||
| 715 | load_pdump_find_executable (const char* argv0, char **exename) | ||
| 716 | { | ||
| 717 | enum pdumper_load_result result; | ||
| 718 | char *candidate = NULL; | ||
| 719 | |||
| 720 | /* If the executable name contains a slash, we have some kind of | ||
| 721 | path already, so just copy it. */ | ||
| 722 | eassert (argv0); | ||
| 723 | if (strchr (argv0, DIRECTORY_SEP)) | ||
| 724 | { | ||
| 725 | result = PDUMPER_LOAD_OOM; | ||
| 726 | char *ret = strdup (argv0); | ||
| 727 | if (!ret) | ||
| 728 | goto out; | ||
| 729 | result = PDUMPER_LOAD_SUCCESS; | ||
| 730 | *exename = ret; | ||
| 731 | goto out; | ||
| 732 | } | ||
| 733 | size_t argv0_length = strlen (argv0); | ||
| 734 | |||
| 735 | const char *path = getenv ("PATH"); | ||
| 736 | if (!path) | ||
| 737 | { | ||
| 738 | /* Default PATH is implementation-defined, so we don't know how | ||
| 739 | to conduct the search. */ | ||
| 740 | result = PDUMPER_LOAD_SUCCESS; | ||
| 741 | *exename = NULL; | ||
| 742 | goto out; | ||
| 743 | } | ||
| 744 | |||
| 745 | /* Actually try each concatenation of a path element and the | ||
| 746 | executable basename. */ | ||
| 747 | const char path_sep[] = { SEPCHAR, '\0' }; | ||
| 748 | do | ||
| 749 | { | ||
| 750 | size_t path_part_length = strcspn (path, path_sep); | ||
| 751 | const char *path_part = path; | ||
| 752 | path += path_part_length; | ||
| 753 | if (path_part_length == 0) | ||
| 754 | { | ||
| 755 | path_part = "."; | ||
| 756 | path_part_length = 1; | ||
| 757 | } | ||
| 758 | size_t candidate_length = path_part_length + 1 + argv0_length; | ||
| 759 | { | ||
| 760 | char *new_candidate = realloc (candidate, candidate_length + 1); | ||
| 761 | if (!new_candidate) | ||
| 762 | { | ||
| 763 | result = PDUMPER_LOAD_OOM; | ||
| 764 | goto out; | ||
| 765 | } | ||
| 766 | candidate = new_candidate; | ||
| 767 | } | ||
| 768 | memcpy (candidate + 0, path_part, path_part_length); | ||
| 769 | candidate[path_part_length] = DIRECTORY_SEP; | ||
| 770 | memcpy (candidate + path_part_length + 1, argv0, argv0_length + 1); | ||
| 771 | struct stat st; | ||
| 772 | if (!access (candidate, X_OK) && | ||
| 773 | !stat (candidate, &st) && | ||
| 774 | S_ISREG (st.st_mode)) | ||
| 775 | { | ||
| 776 | *exename = candidate; | ||
| 777 | candidate = NULL; | ||
| 778 | break; | ||
| 779 | } | ||
| 780 | } while ((path++)[0] != '\0'); | ||
| 781 | |||
| 782 | result = PDUMPER_LOAD_SUCCESS; | ||
| 783 | |||
| 784 | out: | ||
| 785 | free (candidate); | ||
| 786 | return result; | ||
| 787 | } | ||
| 788 | |||
| 707 | static enum pdumper_load_result | 789 | static enum pdumper_load_result |
| 708 | load_pdump (int argc, char **argv) | 790 | load_pdump (int argc, char **argv) |
| 709 | { | 791 | { |
| 710 | const char *const suffix = ".pdmp"; | 792 | const char *const suffix = ".pdmp"; |
| 711 | enum pdumper_load_result result; | 793 | enum pdumper_load_result result; |
| 794 | char *exename = NULL; | ||
| 795 | char *real_exename = NULL; | ||
| 796 | const char* strip_suffix = | ||
| 797 | #ifdef DOS_NT | ||
| 798 | ".exe" | ||
| 799 | #else | ||
| 800 | NULL | ||
| 801 | #endif | ||
| 802 | ; | ||
| 712 | 803 | ||
| 713 | /* TODO: maybe more thoroughly scrub process environment in order to | 804 | /* TODO: maybe more thoroughly scrub process environment in order to |
| 714 | make this use case (loading a pdumper image in an unexeced emacs) | 805 | make this use case (loading a pdumper image in an unexeced emacs) |
| @@ -744,31 +835,50 @@ load_pdump (int argc, char **argv) | |||
| 744 | } | 835 | } |
| 745 | 836 | ||
| 746 | /* Look for a dump file in the same directory as the executable; it | 837 | /* Look for a dump file in the same directory as the executable; it |
| 747 | should have the same basename. If the directory name is, however, | 838 | should have the same basename. Take care to search PATH to find |
| 748 | a symbolic link, resolve the symbolic symbolic link first. */ | 839 | the executable if needed. We're too early in init to use Lisp, |
| 749 | 840 | so we can't use decode_env_path. We're working in whatever | |
| 750 | char* argv0 = realpath (argv[0], NULL); | 841 | encoding the system natively uses for filesystem access, so |
| 751 | if (!argv0) | 842 | there's no need for character set conversion. */ |
| 752 | fatal ("could not resolve realpath of \"%s\": %s", | 843 | result = load_pdump_find_executable (argv[0], &exename); |
| 753 | argv0, strerror (errno)); | 844 | if (result != PDUMPER_LOAD_SUCCESS) |
| 754 | |||
| 755 | dump_file = alloca (strlen (argv0) + strlen (suffix) + 1); | ||
| 756 | #ifdef DOS_NT | ||
| 757 | /* Remove the .exe extension if present. */ | ||
| 758 | size_t argv0_len = strlen (argv0); | ||
| 759 | if (argv0_len >= 4 && c_strcasecmp (argv0 + argv0_len - 4, ".exe") == 0) | ||
| 760 | sprintf (dump_file, "%.*s%s", (int)(argv0_len - 4), argv0, suffix); | ||
| 761 | else | ||
| 762 | #endif | ||
| 763 | sprintf (dump_file, "%s%s", argv0, suffix); | ||
| 764 | |||
| 765 | result = pdumper_load (dump_file); | ||
| 766 | if (result == PDUMPER_LOAD_SUCCESS) | ||
| 767 | goto out; | 845 | goto out; |
| 768 | 846 | ||
| 769 | if (result != PDUMPER_LOAD_FILE_NOT_FOUND) | 847 | /* If we couldn't find our executable, go straight to looking for |
| 770 | fatal ("could not load dump file \"%s\": %s", | 848 | the dump in the hardcoded location. */ |
| 771 | dump_file, dump_error_to_string (result)); | 849 | if (exename) |
| 850 | { | ||
| 851 | real_exename = realpath (exename, NULL); | ||
| 852 | if (!real_exename) | ||
| 853 | fatal ("could not resolve realpath of \"%s\": %s", | ||
| 854 | exename, strerror (errno)); | ||
| 855 | size_t real_exename_length = strlen (real_exename); | ||
| 856 | if (strip_suffix) | ||
| 857 | { | ||
| 858 | size_t strip_suffix_length = strlen (strip_suffix); | ||
| 859 | if (real_exename_length >= strip_suffix_length) | ||
| 860 | { | ||
| 861 | size_t prefix_length = | ||
| 862 | real_exename_length - strip_suffix_length; | ||
| 863 | if (!memcmp (&real_exename[prefix_length], | ||
| 864 | strip_suffix, | ||
| 865 | strip_suffix_length)) | ||
| 866 | real_exename_length = prefix_length; | ||
| 867 | } | ||
| 868 | } | ||
| 869 | dump_file = alloca (real_exename_length + strlen (suffix) + 1); | ||
| 870 | memcpy (dump_file, real_exename, real_exename_length); | ||
| 871 | memcpy (dump_file + real_exename_length, | ||
| 872 | suffix, | ||
| 873 | strlen (suffix) + 1); | ||
| 874 | result = pdumper_load (dump_file); | ||
| 875 | if (result == PDUMPER_LOAD_SUCCESS) | ||
| 876 | goto out; | ||
| 877 | |||
| 878 | if (result != PDUMPER_LOAD_FILE_NOT_FOUND) | ||
| 879 | fatal ("could not load dump file \"%s\": %s", | ||
| 880 | dump_file, dump_error_to_string (result)); | ||
| 881 | } | ||
| 772 | 882 | ||
| 773 | #ifdef WINDOWSNT | 883 | #ifdef WINDOWSNT |
| 774 | /* On MS-Windows, PATH_EXEC normally starts with a literal | 884 | /* On MS-Windows, PATH_EXEC normally starts with a literal |
| @@ -798,12 +908,12 @@ load_pdump (int argc, char **argv) | |||
| 798 | file in PATH_EXEC, and have several Emacs configurations in | 908 | file in PATH_EXEC, and have several Emacs configurations in |
| 799 | the same versioned libexec subdirectory. */ | 909 | the same versioned libexec subdirectory. */ |
| 800 | char *p, *last_sep = NULL; | 910 | char *p, *last_sep = NULL; |
| 801 | for (p = argv0; *p; p++) | 911 | for (p = argv[0]; *p; p++) |
| 802 | { | 912 | { |
| 803 | if (IS_DIRECTORY_SEP (*p)) | 913 | if (IS_DIRECTORY_SEP (*p)) |
| 804 | last_sep = p; | 914 | last_sep = p; |
| 805 | } | 915 | } |
| 806 | argv0_base = last_sep ? last_sep + 1 : argv0; | 916 | argv0_base = last_sep ? last_sep + 1 : argv[0]; |
| 807 | dump_file = alloca (strlen (path_exec) | 917 | dump_file = alloca (strlen (path_exec) |
| 808 | + 1 | 918 | + 1 |
| 809 | + strlen (argv0_base) | 919 | + strlen (argv0_base) |
| @@ -831,6 +941,8 @@ load_pdump (int argc, char **argv) | |||
| 831 | } | 941 | } |
| 832 | 942 | ||
| 833 | out: | 943 | out: |
| 944 | free (exename); | ||
| 945 | free (real_exename); | ||
| 834 | return result; | 946 | return result; |
| 835 | } | 947 | } |
| 836 | #endif /* HAVE_PDUMPER */ | 948 | #endif /* HAVE_PDUMPER */ |