aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKarel Klíc2010-04-20 20:02:58 -0700
committerGlenn Morris2010-04-20 20:02:58 -0700
commit574c05e219476912db3105fa164accd9ba12b35f (patch)
tree2e161de168846db96263030f147e3062722cd335 /src
parenta1d830c700ecca2964223ea30ccb7eb9a6747a4d (diff)
downloademacs-574c05e219476912db3105fa164accd9ba12b35f.tar.gz
emacs-574c05e219476912db3105fa164accd9ba12b35f.zip
Add SELinux support.
* configure.in: New option: --with(out)-selinux, on by default. Set HAVE_LIBSELINUX if we find libselinux, and substitute LIBSELINUX_LIBS in Makefiles. * src/Makefile.in (LIBSELINUX_LIBS): New. (LIBES): Add $LIBSELINUX_LIBS. * src/eval.c, lisp.h (call7): New function. * src/fileio.c [HAVE_LIBSELINUX]: Include selinux headers. (Ffile_selinux_context, Fset_file_selinux_context): New functions. (Fcopy_file): New parameter preserve-selinux-context. (Frename_file): Preserve selinux context when renaming by copy-file. * lisp/files.el (backup-buffer): Handle SELinux context, and return it if a backup was made by renaming. (backup-buffer-copy): Set SELinux context to the target file. (basic-save-buffer): Set SELinux context of the newly written file. (basic-save-buffer-1): Now it also returns any SELinux context. (basic-save-buffer-2): Set SELinux context of the newly created file, and return it. * lisp/net/tramp.el (tramp-file-name-for-operation): Add file-selinux-context.
Diffstat (limited to 'src')
-rw-r--r--src/ChangeLog11
-rw-r--r--src/Makefile.in6
-rw-r--r--src/eval.c27
-rw-r--r--src/fileio.c186
-rw-r--r--src/lisp.h1
5 files changed, 223 insertions, 8 deletions
diff --git a/src/ChangeLog b/src/ChangeLog
index a211e1f66fd..2da967958cd 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,14 @@
12010-04-21 Karel Klíč <kklic@redhat.com>
2
3 * Makefile.in (LIBSELINUX_LIBS): New.
4 (LIBES): Add $LIBSELINUX_LIBS.
5 * eval.c, lisp.h (call7): New function.
6 * fileio.c [HAVE_LIBSELINUX]: Include selinux headers.
7 (Ffile_selinux_context, Fset_file_selinux_context):
8 New functions.
9 (Fcopy_file): New parameter preserve-selinux-context.
10 (Frename_file): Preserve selinux context when renaming by copy-file.
11
12010-04-21 Juanma Barranquero <lekktu@gmail.com> 122010-04-21 Juanma Barranquero <lekktu@gmail.com>
2 Eli Zaretskii <eliz@gnu.org> 13 Eli Zaretskii <eliz@gnu.org>
3 14
diff --git a/src/Makefile.in b/src/Makefile.in
index 0862aa94725..913ac5a847e 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -243,6 +243,10 @@ shared=no
243DBUS_OBJ = dbusbind.o 243DBUS_OBJ = dbusbind.o
244#endif 244#endif
245 245
246#ifdef HAVE_LIBSELINUX
247LIBSELINUX_LIBS = @LIBSELINUX_LIBS@
248#endif
249
246/* DO NOT use -R. There is a special hack described in lastfile.c 250/* DO NOT use -R. There is a special hack described in lastfile.c
247 which is used instead. Some initialized data areas are modified 251 which is used instead. Some initialized data areas are modified
248 at initial startup, then labeled as part of the text area when 252 at initial startup, then labeled as part of the text area when
@@ -824,7 +828,7 @@ SOME_MACHINE_LISP = ../lisp/mouse.elc \
824 828
825LIBES = $(LOADLIBES) $(LIBS) $(LIBX) $(LIBSOUND) $(RSVG_LIBS) $(DBUS_LIBS) \ 829LIBES = $(LOADLIBES) $(LIBS) $(LIBX) $(LIBSOUND) $(RSVG_LIBS) $(DBUS_LIBS) \
826 @LIBGPM@ @LIBRESOLV@ LIBS_SYSTEM LIBS_MACHINE LIBS_TERMCAP \ 830 @LIBGPM@ @LIBRESOLV@ LIBS_SYSTEM LIBS_MACHINE LIBS_TERMCAP \
827 $(GETLOADAVG_LIBS) ${GCONF_LIBS} \ 831 $(GETLOADAVG_LIBS) ${GCONF_LIBS} ${LIBSELINUX_LIBS} \
828 @FREETYPE_LIBS@ @FONTCONFIG_LIBS@ @LIBOTF_LIBS@ @M17N_FLT_LIBS@ \ 832 @FREETYPE_LIBS@ @FONTCONFIG_LIBS@ @LIBOTF_LIBS@ @M17N_FLT_LIBS@ \
829 $(GNULIB_VAR) LIB_MATH LIB_STANDARD $(GNULIB_VAR) 833 $(GNULIB_VAR) LIB_MATH LIB_STANDARD $(GNULIB_VAR)
830 834
diff --git a/src/eval.c b/src/eval.c
index cb1d435cb8b..501ffd452cb 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -2952,6 +2952,33 @@ call6 (fn, arg1, arg2, arg3, arg4, arg5, arg6)
2952#endif /* not NO_ARG_ARRAY */ 2952#endif /* not NO_ARG_ARRAY */
2953} 2953}
2954 2954
2955/* Call function fn with 7 arguments arg1, arg2, arg3, arg4, arg5, arg6, arg7 */
2956/* ARGSUSED */
2957Lisp_Object
2958call7 (fn, arg1, arg2, arg3, arg4, arg5, arg6, arg7)
2959 Lisp_Object fn, arg1, arg2, arg3, arg4, arg5, arg6, arg7;
2960{
2961 struct gcpro gcpro1;
2962#ifdef NO_ARG_ARRAY
2963 Lisp_Object args[8];
2964 args[0] = fn;
2965 args[1] = arg1;
2966 args[2] = arg2;
2967 args[3] = arg3;
2968 args[4] = arg4;
2969 args[5] = arg5;
2970 args[6] = arg6;
2971 args[7] = arg7;
2972 GCPRO1 (args[0]);
2973 gcpro1.nvars = 8;
2974 RETURN_UNGCPRO (Ffuncall (8, args));
2975#else /* not NO_ARG_ARRAY */
2976 GCPRO1 (fn);
2977 gcpro1.nvars = 8;
2978 RETURN_UNGCPRO (Ffuncall (8, &fn));
2979#endif /* not NO_ARG_ARRAY */
2980}
2981
2955/* The caller should GCPRO all the elements of ARGS. */ 2982/* The caller should GCPRO all the elements of ARGS. */
2956 2983
2957DEFUN ("funcall", Ffuncall, Sfuncall, 1, MANY, 0, 2984DEFUN ("funcall", Ffuncall, Sfuncall, 1, MANY, 0,
diff --git a/src/fileio.c b/src/fileio.c
index e9440adabe0..4bfbae91844 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -53,6 +53,11 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
53#include <ctype.h> 53#include <ctype.h>
54#include <errno.h> 54#include <errno.h>
55 55
56#ifdef HAVE_LIBSELINUX
57#include <selinux/selinux.h>
58#include <selinux/context.h>
59#endif
60
56#include "lisp.h" 61#include "lisp.h"
57#include "intervals.h" 62#include "intervals.h"
58#include "buffer.h" 63#include "buffer.h"
@@ -331,6 +336,8 @@ Lisp_Object Qfile_accessible_directory_p;
331Lisp_Object Qfile_modes; 336Lisp_Object Qfile_modes;
332Lisp_Object Qset_file_modes; 337Lisp_Object Qset_file_modes;
333Lisp_Object Qset_file_times; 338Lisp_Object Qset_file_times;
339Lisp_Object Qfile_selinux_context;
340Lisp_Object Qset_file_selinux_context;
334Lisp_Object Qfile_newer_than_file_p; 341Lisp_Object Qfile_newer_than_file_p;
335Lisp_Object Qinsert_file_contents; 342Lisp_Object Qinsert_file_contents;
336Lisp_Object Qwrite_region; 343Lisp_Object Qwrite_region;
@@ -1894,7 +1901,7 @@ barf_or_query_if_file_exists (absname, querystring, interactive, statptr, quick)
1894 return; 1901 return;
1895} 1902}
1896 1903
1897DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 5, 1904DEFUN ("copy-file", Fcopy_file, Scopy_file, 2, 6,
1898 "fCopy file: \nGCopy %s to file: \np\nP", 1905 "fCopy file: \nGCopy %s to file: \np\nP",
1899 doc: /* Copy FILE to NEWNAME. Both args must be strings. 1906 doc: /* Copy FILE to NEWNAME. Both args must be strings.
1900If NEWNAME names a directory, copy FILE there. 1907If NEWNAME names a directory, copy FILE there.
@@ -1916,10 +1923,13 @@ last-modified time as the old one. (This works on only some systems.)
1916A prefix arg makes KEEP-TIME non-nil. 1923A prefix arg makes KEEP-TIME non-nil.
1917 1924
1918If PRESERVE-UID-GID is non-nil, we try to transfer the 1925If PRESERVE-UID-GID is non-nil, we try to transfer the
1919uid and gid of FILE to NEWNAME. */) 1926uid and gid of FILE to NEWNAME.
1920 (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid) 1927
1928If PRESERVE-SELINUX-CONTEXT is non-nil and SELinux is enabled
1929on the system, we copy the SELinux context of FILE to NEWNAME. */)
1930 (file, newname, ok_if_already_exists, keep_time, preserve_uid_gid, preserve_selinux_context)
1921 Lisp_Object file, newname, ok_if_already_exists, keep_time; 1931 Lisp_Object file, newname, ok_if_already_exists, keep_time;
1922 Lisp_Object preserve_uid_gid; 1932 Lisp_Object preserve_uid_gid, preserve_selinux_context;
1923{ 1933{
1924 int ifd, ofd, n; 1934 int ifd, ofd, n;
1925 char buf[16 * 1024]; 1935 char buf[16 * 1024];
@@ -1929,6 +1939,10 @@ uid and gid of FILE to NEWNAME. */)
1929 int count = SPECPDL_INDEX (); 1939 int count = SPECPDL_INDEX ();
1930 int input_file_statable_p; 1940 int input_file_statable_p;
1931 Lisp_Object encoded_file, encoded_newname; 1941 Lisp_Object encoded_file, encoded_newname;
1942#if HAVE_LIBSELINUX
1943 security_context_t con;
1944 int fail, conlength = 0;
1945#endif
1932 1946
1933 encoded_file = encoded_newname = Qnil; 1947 encoded_file = encoded_newname = Qnil;
1934 GCPRO4 (file, newname, encoded_file, encoded_newname); 1948 GCPRO4 (file, newname, encoded_file, encoded_newname);
@@ -1949,8 +1963,9 @@ uid and gid of FILE to NEWNAME. */)
1949 if (NILP (handler)) 1963 if (NILP (handler))
1950 handler = Ffind_file_name_handler (newname, Qcopy_file); 1964 handler = Ffind_file_name_handler (newname, Qcopy_file);
1951 if (!NILP (handler)) 1965 if (!NILP (handler))
1952 RETURN_UNGCPRO (call6 (handler, Qcopy_file, file, newname, 1966 RETURN_UNGCPRO (call7 (handler, Qcopy_file, file, newname,
1953 ok_if_already_exists, keep_time, preserve_uid_gid)); 1967 ok_if_already_exists, keep_time, preserve_uid_gid,
1968 preserve_selinux_context));
1954 1969
1955 encoded_file = ENCODE_FILE (file); 1970 encoded_file = ENCODE_FILE (file);
1956 encoded_newname = ENCODE_FILE (newname); 1971 encoded_newname = ENCODE_FILE (newname);
@@ -2004,6 +2019,15 @@ uid and gid of FILE to NEWNAME. */)
2004 copyable by us. */ 2019 copyable by us. */
2005 input_file_statable_p = (fstat (ifd, &st) >= 0); 2020 input_file_statable_p = (fstat (ifd, &st) >= 0);
2006 2021
2022#if HAVE_LIBSELINUX
2023 if (!NILP (preserve_selinux_context) && is_selinux_enabled ())
2024 {
2025 conlength = fgetfilecon (ifd, &con);
2026 if (conlength == -1)
2027 report_file_error ("Doing fgetfilecon", Fcons (file, Qnil));
2028 }
2029#endif
2030
2007 if (out_st.st_mode != 0 2031 if (out_st.st_mode != 0
2008 && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino) 2032 && st.st_dev == out_st.st_dev && st.st_ino == out_st.st_ino)
2009 { 2033 {
@@ -2061,6 +2085,18 @@ uid and gid of FILE to NEWNAME. */)
2061 } 2085 }
2062#endif /* not MSDOS */ 2086#endif /* not MSDOS */
2063 2087
2088#if HAVE_LIBSELINUX
2089 if (conlength > 0)
2090 {
2091 /* Set the modified context back to the file. */
2092 fail = fsetfilecon (ofd, con);
2093 if (fail)
2094 report_file_error ("Doing fsetfilecon", Fcons (newname, Qnil));
2095
2096 freecon (con);
2097 }
2098#endif
2099
2064 /* Closing the output clobbers the file times on some systems. */ 2100 /* Closing the output clobbers the file times on some systems. */
2065 if (emacs_close (ofd) < 0) 2101 if (emacs_close (ofd) < 0)
2066 report_file_error ("I/O error", Fcons (newname, Qnil)); 2102 report_file_error ("I/O error", Fcons (newname, Qnil));
@@ -2287,7 +2323,7 @@ This is what happens in interactive use with M-x. */)
2287 have copy-file prompt again. */ 2323 have copy-file prompt again. */
2288 Fcopy_file (file, newname, 2324 Fcopy_file (file, newname,
2289 NILP (ok_if_already_exists) ? Qnil : Qt, 2325 NILP (ok_if_already_exists) ? Qnil : Qt,
2290 Qt, Qt); 2326 Qt, Qt, Qt);
2291 2327
2292 count = SPECPDL_INDEX (); 2328 count = SPECPDL_INDEX ();
2293 specbind (Qdelete_by_moving_to_trash, Qnil); 2329 specbind (Qdelete_by_moving_to_trash, Qnil);
@@ -2844,6 +2880,136 @@ See `file-symlink-p' to distinguish symlinks. */)
2844#endif 2880#endif
2845} 2881}
2846 2882
2883DEFUN ("file-selinux-context", Ffile_selinux_context,
2884 Sfile_selinux_context, 1, 1, 0,
2885 doc: /* Return SELinux context of file named FILENAME,
2886as a list ("user", "role", "type", "range"). Return (nil, nil, nil, nil)
2887if file does not exist, is not accessible, or SELinux is disabled */)
2888 (filename)
2889 Lisp_Object filename;
2890{
2891 Lisp_Object absname;
2892 Lisp_Object values[4];
2893 Lisp_Object handler;
2894#if HAVE_LIBSELINUX
2895 security_context_t con;
2896 int conlength;
2897 context_t context;
2898#endif
2899
2900 absname = expand_and_dir_to_file (filename, current_buffer->directory);
2901
2902 /* If the file name has special constructs in it,
2903 call the corresponding file handler. */
2904 handler = Ffind_file_name_handler (absname, Qfile_selinux_context);
2905 if (!NILP (handler))
2906 return call2 (handler, Qfile_selinux_context, absname);
2907
2908 absname = ENCODE_FILE (absname);
2909
2910 values[0] = Qnil;
2911 values[1] = Qnil;
2912 values[2] = Qnil;
2913 values[3] = Qnil;
2914#if HAVE_LIBSELINUX
2915 if (is_selinux_enabled ())
2916 {
2917 conlength = lgetfilecon (SDATA (absname), &con);
2918 if (conlength > 0)
2919 {
2920 context = context_new (con);
2921 values[0] = build_string (context_user_get (context));
2922 values[1] = build_string (context_role_get (context));
2923 values[2] = build_string (context_type_get (context));
2924 values[3] = build_string (context_range_get (context));
2925 context_free (context);
2926 }
2927 if (con)
2928 freecon (con);
2929 }
2930#endif
2931
2932 return Flist (sizeof(values) / sizeof(values[0]), values);
2933}
2934
2935DEFUN ("set-file-selinux-context", Fset_file_selinux_context,
2936 Sset_file_selinux_context, 2, 2, 0,
2937 doc: /* Set SELinux context of file named FILENAME to CONTEXT
2938as a list ("user", "role", "type", "range"). Has no effect if SELinux
2939is disabled. */)
2940 (filename, context)
2941 Lisp_Object filename, context;
2942{
2943 Lisp_Object absname, encoded_absname;
2944 Lisp_Object handler;
2945 Lisp_Object user = CAR_SAFE (context);
2946 Lisp_Object role = CAR_SAFE (CDR_SAFE (context));
2947 Lisp_Object type = CAR_SAFE (CDR_SAFE (CDR_SAFE (context)));
2948 Lisp_Object range = CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (context))));
2949#if HAVE_LIBSELINUX
2950 security_context_t con;
2951 int fail, conlength;
2952 context_t parsed_con;
2953#endif
2954
2955 absname = Fexpand_file_name (filename, current_buffer->directory);
2956
2957 /* If the file name has special constructs in it,
2958 call the corresponding file handler. */
2959 handler = Ffind_file_name_handler (absname, Qset_file_selinux_context);
2960 if (!NILP (handler))
2961 return call3 (handler, Qset_file_selinux_context, absname, context);
2962
2963 encoded_absname = ENCODE_FILE (absname);
2964
2965#if HAVE_LIBSELINUX
2966 if (is_selinux_enabled ())
2967 {
2968 /* Get current file context. */
2969 conlength = lgetfilecon (SDATA (encoded_absname), &con);
2970 if (conlength > 0)
2971 {
2972 parsed_con = context_new (con);
2973 /* Change the parts defined in the parameter.*/
2974 if (STRINGP (user))
2975 {
2976 if (context_user_set (parsed_con, SDATA (user)))
2977 error ("Doing context_user_set");
2978 }
2979 if (STRINGP (role))
2980 {
2981 if (context_role_set (parsed_con, SDATA (role)))
2982 error ("Doing context_role_set");
2983 }
2984 if (STRINGP (type))
2985 {
2986 if (context_type_set (parsed_con, SDATA (type)))
2987 error ("Doing context_type_set");
2988 }
2989 if (STRINGP (range))
2990 {
2991 if (context_range_set (parsed_con, SDATA (range)))
2992 error ("Doing context_range_set");
2993 }
2994
2995 /* Set the modified context back to the file. */
2996 fail = lsetfilecon (SDATA (encoded_absname), context_str (parsed_con));
2997 if (fail)
2998 report_file_error ("Doing lsetfilecon", Fcons (absname, Qnil));
2999
3000 context_free (parsed_con);
3001 }
3002 else
3003 report_file_error("Doing lgetfilecon", Fcons (absname, Qnil));
3004
3005 if (con)
3006 freecon (con);
3007 }
3008#endif
3009
3010 return Qnil;
3011}
3012
2847DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0, 3013DEFUN ("file-modes", Ffile_modes, Sfile_modes, 1, 1, 0,
2848 doc: /* Return mode bits of file named FILENAME, as an integer. 3014 doc: /* Return mode bits of file named FILENAME, as an integer.
2849Return nil, if file does not exist or is not accessible. */) 3015Return nil, if file does not exist or is not accessible. */)
@@ -5505,6 +5671,8 @@ syms_of_fileio ()
5505 Qfile_modes = intern_c_string ("file-modes"); 5671 Qfile_modes = intern_c_string ("file-modes");
5506 Qset_file_modes = intern_c_string ("set-file-modes"); 5672 Qset_file_modes = intern_c_string ("set-file-modes");
5507 Qset_file_times = intern_c_string ("set-file-times"); 5673 Qset_file_times = intern_c_string ("set-file-times");
5674 Qfile_selinux_context = intern_c_string("file-selinux-context");
5675 Qset_file_selinux_context = intern_c_string("set-file-selinux-context");
5508 Qfile_newer_than_file_p = intern_c_string ("file-newer-than-file-p"); 5676 Qfile_newer_than_file_p = intern_c_string ("file-newer-than-file-p");
5509 Qinsert_file_contents = intern_c_string ("insert-file-contents"); 5677 Qinsert_file_contents = intern_c_string ("insert-file-contents");
5510 Qwrite_region = intern_c_string ("write-region"); 5678 Qwrite_region = intern_c_string ("write-region");
@@ -5540,6 +5708,8 @@ syms_of_fileio ()
5540 staticpro (&Qfile_modes); 5708 staticpro (&Qfile_modes);
5541 staticpro (&Qset_file_modes); 5709 staticpro (&Qset_file_modes);
5542 staticpro (&Qset_file_times); 5710 staticpro (&Qset_file_times);
5711 staticpro (&Qfile_selinux_context);
5712 staticpro (&Qset_file_selinux_context);
5543 staticpro (&Qfile_newer_than_file_p); 5713 staticpro (&Qfile_newer_than_file_p);
5544 staticpro (&Qinsert_file_contents); 5714 staticpro (&Qinsert_file_contents);
5545 staticpro (&Qwrite_region); 5715 staticpro (&Qwrite_region);
@@ -5773,6 +5943,8 @@ When non-nil, the function `move-file-to-trash' will be used by
5773 defsubr (&Sfile_modes); 5943 defsubr (&Sfile_modes);
5774 defsubr (&Sset_file_modes); 5944 defsubr (&Sset_file_modes);
5775 defsubr (&Sset_file_times); 5945 defsubr (&Sset_file_times);
5946 defsubr (&Sfile_selinux_context);
5947 defsubr (&Sset_file_selinux_context);
5776 defsubr (&Sset_default_file_modes); 5948 defsubr (&Sset_default_file_modes);
5777 defsubr (&Sdefault_file_modes); 5949 defsubr (&Sdefault_file_modes);
5778 defsubr (&Sfile_newer_than_file_p); 5950 defsubr (&Sfile_newer_than_file_p);
diff --git a/src/lisp.h b/src/lisp.h
index d7e88e7c8b8..357fc6fada3 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -2897,6 +2897,7 @@ extern Lisp_Object call3 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object
2897extern Lisp_Object call4 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); 2897extern Lisp_Object call4 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object));
2898extern Lisp_Object call5 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); 2898extern Lisp_Object call5 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object));
2899extern Lisp_Object call6 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object)); 2899extern Lisp_Object call6 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object));
2900extern Lisp_Object call7 P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object));
2900EXFUN (Fdo_auto_save, 2); 2901EXFUN (Fdo_auto_save, 2);
2901extern Lisp_Object apply_lambda P_ ((Lisp_Object, Lisp_Object, int)); 2902extern Lisp_Object apply_lambda P_ ((Lisp_Object, Lisp_Object, int));
2902extern Lisp_Object internal_catch P_ ((Lisp_Object, Lisp_Object (*) (Lisp_Object), Lisp_Object)); 2903extern Lisp_Object internal_catch P_ ((Lisp_Object, Lisp_Object (*) (Lisp_Object), Lisp_Object));