X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/38732dbaa3d35a399ada5d60153ce789217977b6..0925c80cd3d8f9a973d699fc1dbdbe79cca62988:/lib-src/emacsclient.c diff --git a/lib-src/emacsclient.c b/lib-src/emacsclient.c index 81245bcd66..034d5c9faa 100644 --- a/lib-src/emacsclient.c +++ b/lib-src/emacsclient.c @@ -1,6 +1,6 @@ /* Client process that communicates with GNU Emacs acting as server. - Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001 - Free Software Foundation, Inc. + Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2002, 2003, 2004, + 2005 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -16,8 +16,8 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU Emacs; see the file COPYING. If not, write to -the Free Software Foundation, Inc., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #define NO_SHORTNAMES @@ -42,10 +42,7 @@ Boston, MA 02111-1307, USA. */ #endif /* not VMS */ char *getenv (), *getwd (); -char *getcwd (); - -/* This is defined with -D from the compilation command, - which extracts it from ../lisp/version.el. */ +char *(getcwd) (); #ifndef VERSION #define VERSION "unspecified" @@ -67,6 +64,9 @@ char *display = NULL; is not running. --alternate-editor. */ const char * alternate_editor = NULL; +/* If non-NULL, the filename of the UNIX socket. */ +char *socket_name = NULL; + void print_help_and_exit (); struct option longopts[] = @@ -76,6 +76,7 @@ struct option longopts[] = { "help", no_argument, NULL, 'H' }, { "version", no_argument, NULL, 'V' }, { "alternate-editor", required_argument, NULL, 'a' }, + { "socket-name", required_argument, NULL, 's' }, { "display", required_argument, NULL, 'd' }, { 0, 0, 0, 0 } }; @@ -88,16 +89,16 @@ decode_options (argc, argv) int argc; char **argv; { + alternate_editor = getenv ("ALTERNATE_EDITOR"); + while (1) { int opt = getopt_long (argc, argv, - "VHnea:d:", longopts, 0); + "VHnea:s:d:", longopts, 0); if (opt == EOF) break; - alternate_editor = getenv ("ALTERNATE_EDITOR"); - switch (opt) { case 0: @@ -109,6 +110,10 @@ decode_options (argc, argv) alternate_editor = optarg; break; + case 's': + socket_name = optarg; + break; + case 'd': display = optarg; break; @@ -122,13 +127,18 @@ decode_options (argc, argv) break; case 'V': - fprintf (stderr, "emacsclient %s\n", VERSION); - exit (1); + printf ("emacsclient %s\n", VERSION); + exit (EXIT_SUCCESS); break; case 'H': - default: print_help_and_exit (); + break; + + default: + fprintf (stderr, "Try `%s --help' for more information\n", progname); + exit (EXIT_FAILURE); + break; } } } @@ -136,30 +146,34 @@ decode_options (argc, argv) void print_help_and_exit () { - fprintf (stderr, - "Usage: %s [OPTIONS] FILE...\n\ + printf ( + "Usage: %s [OPTIONS] FILE...\n\ Tell the Emacs server to visit the specified files.\n\ Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\ +\n\ The following OPTIONS are accepted:\n\ -V, --version Just print a version info and return\n\ -H, --help Print this usage information message\n\ -n, --no-wait Don't wait for the server to return\n\ -e, --eval Evaluate the FILE arguments as ELisp expressions\n\ -d, --display=DISPLAY Visit the file in the given display\n\ +-s, --socket-name=FILENAME\n\ + Set the filename of the UNIX socket for communication\n\ -a, --alternate-editor=EDITOR\n\ Editor to fallback to if the server is not running\n\ +\n\ Report bugs to bug-gnu-emacs@gnu.org.\n", progname); - exit (1); + exit (EXIT_SUCCESS); } -/* Return a copy of NAME, inserting a & - before each &, each space, each newline, and any initial -. - Change spaces to underscores, too, so that the +/* In NAME, insert a & before each &, each space, each newline, and + any initial -. Change spaces to underscores, too, so that the return value never contains a space. */ -char * -quote_file_name (name) +void +quote_file_name (name, stream) char *name; + FILE *stream; { char *copy = (char *) malloc (strlen (name) * 2 + 1); char *p, *q; @@ -189,7 +203,9 @@ quote_file_name (name) } *q++ = 0; - return copy; + fprintf (stream, "%s", copy); + + free (copy); } /* Like malloc but get fatal error if memory is exhausted. */ @@ -202,7 +218,7 @@ xmalloc (size) if (result == NULL) { perror ("malloc"); - exit (1); + exit (EXIT_FAILURE); } return result; } @@ -224,7 +240,7 @@ fail (argc, argv) } else { - exit (1); + exit (EXIT_FAILURE); } } @@ -280,8 +296,6 @@ main (argc, argv) int argc; char **argv; { - char *system_name; - int system_name_length; int s, i, needlf = 0; FILE *out, *in; struct sockaddr_un server; @@ -293,8 +307,12 @@ main (argc, argv) /* Process options. */ decode_options (argc, argv); - if (argc - optind < 1) - print_help_and_exit (); + if ((argc - optind < 1) && !eval) + { + fprintf (stderr, "%s: file name or argument required\n", progname); + fprintf (stderr, "Try `%s --help' for more information\n", progname); + exit (EXIT_FAILURE); + } /* * Open up an AF_UNIX socket in this person's home directory @@ -310,37 +328,38 @@ main (argc, argv) server.sun_family = AF_UNIX; { - char *dot; - system_name_length = 32; + int sock_status = 0; + int default_sock = !socket_name; + int saved_errno; + char *server_name = "server"; + + if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\')) + { /* socket_name is a file name component. */ + server_name = socket_name; + socket_name = NULL; + default_sock = 1; /* Try both UIDs. */ + } - while (1) + if (default_sock) { - system_name = (char *) xmalloc (system_name_length + 1); - - /* system_name must be null-terminated string. */ - system_name[system_name_length] = '\0'; - - if (gethostname (system_name, system_name_length) == 0) - break; - - free (system_name); - system_name_length *= 2; + socket_name = alloca (100 + strlen (server_name)); + sprintf (socket_name, "/tmp/emacs%d/%s", + (int) geteuid (), server_name); } - /* We always use the non-dotted host name, for simplicity. */ - dot = index (system_name, '.'); - if (dot) - *dot = '\0'; - } - - { - int sock_status = 0; - - sprintf (server.sun_path, "/tmp/esrv%d-%s", (int) geteuid (), system_name); + if (strlen (socket_name) < sizeof (server.sun_path)) + strcpy (server.sun_path, socket_name); + else + { + fprintf (stderr, "%s: socket-name %s too long", + argv[0], socket_name); + exit (EXIT_FAILURE); + } /* See if the socket exists, and if it's owned by us. */ sock_status = socket_status (server.sun_path); - if (sock_status) + saved_errno = errno; + if (sock_status && default_sock) { /* Failing that, see if LOGNAME or USER exist and differ from our euid. If so, look for a socket based on the UID @@ -348,19 +367,35 @@ main (argc, argv) 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", - (int) pw->pw_uid, system_name); + socket_name = alloca (100 + strlen (server_name)); + sprintf (socket_name, "/tmp/emacs%d/%s", + (int) pw->pw_uid, server_name); + + if (strlen (socket_name) < sizeof (server.sun_path)) + strcpy (server.sun_path, socket_name); + else + { + fprintf (stderr, "%s: socket-name %s too long", + argv[0], socket_name); + exit (EXIT_FAILURE); + } + sock_status = socket_status (server.sun_path); + saved_errno = errno; } + else + errno = saved_errno; } } @@ -378,13 +413,14 @@ main (argc, argv) case 2: /* `stat' failed */ - if (errno == ENOENT) + if (saved_errno == ENOENT) fprintf (stderr, - "%s: can't find socket; have you started the server?\n", + "%s: can't find socket; have you started the server?\n\ +To start the server in Emacs, type \"M-x server-start\".\n", argv[0]); else fprintf (stderr, "%s: can't stat %s: %s\n", - argv[0], server.sun_path, strerror (errno)); + argv[0], server.sun_path, strerror (saved_errno)); fail (argc, argv); break; } @@ -426,13 +462,13 @@ main (argc, argv) if (cwd == 0) { /* getwd puts message in STRING if it fails. */ - fprintf (stderr, "%s: %s (%s)\n", argv[0], + #ifdef HAVE_GETCWD - "Cannot get current working directory", + fprintf (stderr, "%s: %s (%s)\n", argv[0], + "Cannot get current working directory", strerror (errno)); #else - string, + fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno)); #endif - strerror (errno)); fail (argc, argv); } @@ -443,30 +479,53 @@ main (argc, argv) fprintf (out, "-eval "); if (display) - fprintf (out, "-display %s ", quote_file_name (display)); + { + fprintf (out, "-display "); + quote_file_name (display, out); + fprintf (out, " "); + } - for (i = optind; i < argc; i++) + if ((argc - optind > 0)) { - if (eval) - ; /* Don't prepend any cwd or anything like that. */ - else if (*argv[i] == '+') + for (i = optind; i < argc; i++) { - char *p = argv[i] + 1; - while (isdigit ((unsigned char) *p) || *p == ':') p++; - if (*p != 0) - fprintf (out, "%s/", quote_file_name (cwd)); + if (eval) + ; /* Don't prepend any cwd or anything like that. */ + else if (*argv[i] == '+') + { + char *p = argv[i] + 1; + while (isdigit ((unsigned char) *p) || *p == ':') p++; + if (*p != 0) + { + quote_file_name (cwd, out); + fprintf (out, "/"); + } + } + else if (*argv[i] != '/') + { + quote_file_name (cwd, out); + fprintf (out, "/"); + } + + quote_file_name (argv[i], out); + fprintf (out, " "); } - else if (*argv[i] != '/') - fprintf (out, "%s/", quote_file_name (cwd)); - - fprintf (out, "%s ", quote_file_name (argv[i])); } + else + { + while ((str = fgets (string, BUFSIZ, stdin))) + { + quote_file_name (str, out); + } + fprintf (out, " "); + } + fprintf (out, "\n"); fflush (out); /* Maybe wait for an answer. */ if (nowait) - return 0; + return EXIT_SUCCESS; if (!eval) { @@ -488,7 +547,7 @@ main (argc, argv) printf ("\n"); fflush (stdout); - return 0; + return EXIT_SUCCESS; } #endif /* HAVE_SOCKETS */ @@ -507,3 +566,8 @@ strerror (errnum) } #endif /* ! HAVE_STRERROR */ + +/* arch-tag: f39bb9c4-73eb-477e-896d-50832e2ca9a7 + (do not change this comment) */ + +/* emacsclient.c ends here */