aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorDaniel Colascione2019-06-24 06:20:07 -0700
committerDaniel Colascione2019-06-24 06:53:30 -0700
commit65d45def8d71e50d111adf1141011a5d30a27447 (patch)
treea0550807d637618b3561b344b9070586865c3d90 /src
parent157fced053601c993734c61078c42d7905389828 (diff)
downloademacs-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.c162
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 */
714static enum pdumper_load_result
715load_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
707static enum pdumper_load_result 789static enum pdumper_load_result
708load_pdump (int argc, char **argv) 790load_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 */