X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/4ee9629e2beb7a870ab30509d547b6845ef645cf..ef53d75e82b52e5948807e3af892fb3f3e8f98cc:/lib-src/emacsclient.c diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index 11946ff2ec..03fe66598c 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -1,5 +1,5 @@ /* Client process that communicates with GNU Emacs acting as server. - Copyright (C) 1986, 1987, 1994, 1999 Free Software Foundation, Inc. + Copyright (C) 1986, 1987, 1994, 1999, 2000 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -29,6 +29,12 @@ Boston, MA 02111-1307, USA. */ #include #endif +#ifdef VMS +# include "vms-pwd.h" +#else +# include +#endif /* not VMS */ + char *getenv (), *getwd (); char *getcwd (); @@ -52,9 +58,13 @@ struct option longopts[] = { "no-wait", no_argument, NULL, 'n' }, { "help", no_argument, NULL, 'H' }, { "version", no_argument, NULL, 'V' }, + { "alternate-editor",required_argument, NULL, 'a' }, { 0 } }; + +const char * alternate_editor = NULL; + /* Decode the options from argv and argc. The global variable `optind' will say how many arguments we used up. */ @@ -66,18 +76,24 @@ decode_options (argc, argv) while (1) { int opt = getopt_long (argc, argv, - "VHn", longopts, 0); + "VHna:", longopts, 0); if (opt == EOF) break; + alternate_editor = getenv ("ALTERNATE_EDITOR"); + switch (opt) { case 0: /* If getopt returns 0, then it has already processed a long-named option. We should do nothing. */ break; - + + case 'a': + alternate_editor = optarg; + break; + case 'n': nowait = 1; break; @@ -98,7 +114,7 @@ void print_help_and_exit () { fprintf (stderr, - "Usage: %s [-n] [--no-wait] [+LINENUMBER] FILENAME\n", + "Usage: %s [-a ALTERNATE-EDITOR] [-n] [--no-wait] [+LINENUMBER] FILENAME\n", progname); fprintf (stderr, "Or %s --version\n", @@ -139,6 +155,7 @@ quote_file_name (name) } *q++ = 0; + return copy; } @@ -156,6 +173,28 @@ xmalloc (size) } return result; } + +/* + Try to run a different command, or --if no alternate editor is + defined-- exit with an errorcode. +*/ +fail (argc, argv) + int argc; + char **argv; +{ + if (alternate_editor) + { + int i = optind -1 ; + execvp (alternate_editor, argv + i); + } + else + { + exit (1); + } +} + + + #if !defined (HAVE_SOCKETS) && !defined (HAVE_SYSVIPC) @@ -166,7 +205,8 @@ main (argc, argv) fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n", argv[0]); fprintf (stderr, "on systems with Berkeley sockets or System V IPC.\n"); - exit (1); + + fail (argc, argv); } #else /* HAVE_SOCKETS or HAVE_SYSVIPC */ @@ -183,6 +223,26 @@ main (argc, argv) extern char *strerror (); extern int errno; +/* Three possibilities: + 2 - can't be `stat'ed (sets errno) + 1 - isn't owned by us + 0 - success: none of the above */ + +static int +socket_status (socket_name) + char *socket_name; +{ + struct stat statbfr; + + if (stat (socket_name, &statbfr) == -1) + return 2; + + if (statbfr.st_uid != geteuid ()) + return 1; + + return 0; +} + int main (argc, argv) int argc; @@ -193,7 +253,10 @@ main (argc, argv) int s, i; FILE *out, *in; struct sockaddr_un server; - char *homedir, *cwd, *str; +#ifdef SERVER_HOME_DIR + char *homedir; +#endif + char *cwd, *str; char string[BUFSIZ]; progname = argv[0]; @@ -212,8 +275,9 @@ main (argc, argv) { fprintf (stderr, "%s: ", argv[0]); perror ("socket"); - exit (1); + fail (argc, argv); } + server.sun_family = AF_UNIX; { @@ -236,32 +300,66 @@ main (argc, argv) #ifndef SERVER_HOME_DIR { - struct stat statbfr; + int sock_status = 0; sprintf (server.sun_path, "/tmp/esrv%d-%s", geteuid (), system_name); - if (stat (server.sun_path, &statbfr) == -1) + /* See if the socket exists, and if it's owned by us. */ + sock_status = socket_status (server.sun_path); + if (sock_status) { - if (errno == ENOENT) - fprintf (stderr, - "%s: can't find socket; have you started the server?\n", - argv[0]); - else - fprintf (stderr, "%s: can't stat %s: %s\n", - argv[0], server.sun_path, strerror (errno)); - exit (1); - } - if (statbfr.st_uid != geteuid ()) - { - fprintf (stderr, "%s: Invalid socket owner\n", argv[0]); - exit (1); + /* Failing that, see if LOGNAME or USER exist and differ from + our euid. If so, look for a socket based on the UID + associated with the name. This is reminiscent of the logic + that init_editfns uses to set the global Vuser_full_name. */ + + char *user_name = (char *) getenv ("LOGNAME"); + if (!user_name) + user_name = (char *) getenv ("USER"); + + if (user_name) + { + struct passwd *pw = getpwnam (user_name); + if (pw && (pw->pw_uid != geteuid ())) + { + /* We're running under su, apparently. */ + sprintf (server.sun_path, "/tmp/esrv%d-%s", + pw->pw_uid, system_name); + sock_status = socket_status (server.sun_path); + } + } } + + switch (sock_status) + { + case 1: + /* There's a socket, but it isn't owned by us. This is OK if + we are root. */ + if (0 != geteuid ()) + { + fprintf (stderr, "%s: Invalid socket owner\n", argv[0]); + fail (argc, argv); + } + break; + + case 2: + /* `stat' failed */ + if (errno == ENOENT) + fprintf (stderr, + "%s: can't find socket; have you started the server?\n", + argv[0]); + else + fprintf (stderr, "%s: can't stat %s: %s\n", + argv[0], server.sun_path, strerror (errno)); + fail (argc, argv); + break; + } } #else if ((homedir = getenv ("HOME")) == NULL) { fprintf (stderr, "%s: No home directory\n", argv[0]); - exit (1); + fail (argc, argv); } strcpy (server.sun_path, homedir); strcat (server.sun_path, "/.emacs-server-"); @@ -273,7 +371,7 @@ main (argc, argv) { fprintf (stderr, "%s: ", argv[0]); perror ("connect"); - exit (1); + fail (argc, argv); } /* We use the stream OUT to send our command to the server. */ @@ -281,7 +379,7 @@ main (argc, argv) { fprintf (stderr, "%s: ", argv[0]); perror ("fdopen"); - exit (1); + fail (argc, argv); } /* We use the stream IN to read the response. @@ -293,7 +391,7 @@ main (argc, argv) { fprintf (stderr, "%s: ", argv[0]); perror ("fdopen"); - exit (1); + fail (argc, argv); } #ifdef BSD_SYSTEM @@ -311,7 +409,7 @@ main (argc, argv) "Cannot get current working directory", #endif strerror (errno)); - exit (1); + fail (argc, argv); } if (nowait) @@ -442,7 +540,7 @@ main (argc, argv) fprintf (stderr, "%s: Cannot get current working directory: %s\n", argv[0], strerror (errno)); #endif - exit (1); + fail (argc, argv); } msgp->mtext[0] = 0; @@ -498,7 +596,7 @@ main (argc, argv) if (strlen (msgp->mtext) >= 512) { fprintf (stderr, "%s: args too long for msgsnd\n", progname); - exit (1); + fail (argc, argv); } #endif msgp->mtype = 1; @@ -506,7 +604,7 @@ main (argc, argv) { fprintf (stderr, "%s: ", progname); perror ("msgsnd"); - exit (1); + fail (argc, argv); } /* Maybe wait for an answer. */