]> code.delx.au - gnu-emacs/blob - lib-src/emacsclient.c
Merged from miles@gnu.org--gnu-2005 (patch 469)
[gnu-emacs] / lib-src / emacsclient.c
1 /* Client process that communicates with GNU Emacs acting as server.
2 Copyright (C) 1986, 1987, 1994, 1999, 2000, 2001, 2003, 2004
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA. */
21
22
23 #define NO_SHORTNAMES
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28
29 #undef signal
30
31 #include <ctype.h>
32 #include <stdio.h>
33 #include <getopt.h>
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37
38 #ifdef VMS
39 # include "vms-pwd.h"
40 #else
41 # include <pwd.h>
42 #endif /* not VMS */
43
44 #include <signal.h>
45 #include <errno.h>
46
47 \f
48 char *getenv (), *getwd ();
49 char *(getcwd) ();
50
51 #ifndef VERSION
52 #define VERSION "unspecified"
53 #endif
54 \f
55 /* Name used to invoke this program. */
56 char *progname;
57
58 /* The first argument to main. */
59 int main_argc;
60
61 /* The second argument to main. */
62 char **main_argv;
63
64 /* Nonzero means don't wait for a response from Emacs. --no-wait. */
65 int nowait = 0;
66
67 /* Nonzero means args are expressions to be evaluated. --eval. */
68 int eval = 0;
69
70 /* Nonzero means open a new graphical frame. */
71 int window_system = 0;
72
73 /* The display on which Emacs should work. --display. */
74 char *display = NULL;
75
76 /* Nonzero means open a new Emacs frame on the current terminal. */
77 int tty = 0;
78
79 /* If non-NULL, the name of an editor to fallback to if the server
80 is not running. --alternate-editor. */
81 const char * alternate_editor = NULL;
82
83 /* If non-NULL, the filename of the UNIX socket. */
84 char *socket_name = NULL;
85
86 void print_help_and_exit ();
87
88 struct option longopts[] =
89 {
90 { "no-wait", no_argument, NULL, 'n' },
91 { "eval", no_argument, NULL, 'e' },
92 { "help", no_argument, NULL, 'H' },
93 { "version", no_argument, NULL, 'V' },
94 { "tty", no_argument, NULL, 't' },
95 { "current-frame", no_argument, NULL, 'c' },
96 { "alternate-editor", required_argument, NULL, 'a' },
97 { "socket-name", required_argument, NULL, 's' },
98 { "display", required_argument, NULL, 'd' },
99 { 0, 0, 0, 0 }
100 };
101
102 /* Decode the options from argv and argc.
103 The global variable `optind' will say how many arguments we used up. */
104
105 void
106 decode_options (argc, argv)
107 int argc;
108 char **argv;
109 {
110 alternate_editor = getenv ("ALTERNATE_EDITOR");
111 display = getenv ("DISPLAY");
112 if (display && strlen (display) == 0)
113 display = NULL;
114
115 if (display)
116 window_system = 1;
117 else
118 tty = 1;
119
120 while (1)
121 {
122 int opt = getopt_long (argc, argv,
123 "VHnea:s:d:tc", longopts, 0);
124
125 if (opt == EOF)
126 break;
127
128 switch (opt)
129 {
130 case 0:
131 /* If getopt returns 0, then it has already processed a
132 long-named option. We should do nothing. */
133 break;
134
135 case 'a':
136 alternate_editor = optarg;
137 break;
138
139 case 's':
140 socket_name = optarg;
141 break;
142
143 case 'd':
144 display = optarg;
145 break;
146
147 case 'n':
148 nowait = 1;
149 break;
150
151 case 'e':
152 eval = 1;
153 break;
154
155 case 'V':
156 printf ("emacsclient %s\n", VERSION);
157 exit (EXIT_SUCCESS);
158 break;
159
160 case 't':
161 tty = 1;
162 window_system = 0;
163 break;
164
165 case 'c':
166 window_system = 0;
167 tty = 0;
168 break;
169
170 case 'H':
171 print_help_and_exit ();
172 break;
173
174 default:
175 fprintf (stderr, "Try `%s --help' for more information\n", progname);
176 exit (EXIT_FAILURE);
177 break;
178 }
179 }
180
181 if (tty) {
182 nowait = 0;
183 display = 0;
184 }
185 }
186
187 void
188 print_help_and_exit ()
189 {
190 printf (
191 "Usage: %s [OPTIONS] FILE...\n\
192 Tell the Emacs server to visit the specified files.\n\
193 Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\
194 \n\
195 The following OPTIONS are accepted:\n\
196 -V, --version Just print a version info and return\n\
197 -H, --help Print this usage information message\n\
198 -t, --tty Open a new Emacs frame on the current terminal\n\
199 -c, --current-frame Do not create a new frame; use the current Emacs frame\n\
200 -n, --no-wait Don't wait for the server to return\n\
201 -e, --eval Evaluate the FILE arguments as ELisp expressions\n\
202 -d, --display=DISPLAY Visit the file in the given display\n\
203 -s, --socket-name=FILENAME\n\
204 Set the filename of the UNIX socket for communication\n\
205 -a, --alternate-editor=EDITOR\n\
206 Editor to fallback to if the server is not running\n\
207 \n\
208 Report bugs to bug-gnu-emacs@gnu.org.\n", progname);
209 exit (EXIT_SUCCESS);
210 }
211
212 /* Like malloc but get fatal error if memory is exhausted. */
213
214 long *
215 xmalloc (size)
216 unsigned int size;
217 {
218 long *result = (long *) malloc (size);
219 if (result == NULL)
220 {
221 perror ("malloc");
222 exit (EXIT_FAILURE);
223 }
224 return result;
225 }
226
227 /* Like strdup but get a fatal error if memory is exhausted. */
228
229 char *
230 xstrdup (const char *s)
231 {
232 char *result = strdup (s);
233 if (result == NULL)
234 {
235 perror ("strdup");
236 exit (EXIT_FAILURE);
237 }
238 return result;
239 }
240
241 /* In STR, insert a & before each &, each space, each newline, and
242 any initial -. Change spaces to underscores, too, so that the
243 return value never contains a space.
244
245 Does not change the string. Outputs the result to STREAM. */
246
247 void
248 quote_argument (str, stream)
249 char *str;
250 FILE *stream;
251 {
252 char *copy = (char *) xmalloc (strlen (str) * 2 + 1);
253 char *p, *q;
254
255 p = str;
256 q = copy;
257 while (*p)
258 {
259 if (*p == ' ')
260 {
261 *q++ = '&';
262 *q++ = '_';
263 p++;
264 }
265 else if (*p == '\n')
266 {
267 *q++ = '&';
268 *q++ = 'n';
269 p++;
270 }
271 else
272 {
273 if (*p == '&' || (*p == '-' && p == str))
274 *q++ = '&';
275 *q++ = *p++;
276 }
277 }
278 *q++ = 0;
279
280 fprintf (stream, "%s", copy);
281
282 free (copy);
283 }
284
285
286 /* The inverse of quote_argument. Removes quoting in string STR by
287 modifying the string in place. Returns STR. */
288
289 char *
290 unquote_argument (str)
291 char *str;
292 {
293 char *p, *q;
294
295 if (! str)
296 return str;
297
298 p = str;
299 q = str;
300 while (*p)
301 {
302 if (*p == '&')
303 {
304 p++;
305 if (*p == '&')
306 *p = '&';
307 else if (*p == '_')
308 *p = ' ';
309 else if (*p == 'n')
310 *p = '\n';
311 else if (*p == '-')
312 *p = '-';
313 }
314 *q++ = *p++;
315 }
316 *q = 0;
317 return str;
318 }
319
320 \f
321 /*
322 Try to run a different command, or --if no alternate editor is
323 defined-- exit with an errorcode.
324 */
325 void
326 fail (void)
327 {
328 if (alternate_editor)
329 {
330 int i = optind - 1;
331 execvp (alternate_editor, main_argv + i);
332 return;
333 }
334 else
335 {
336 exit (EXIT_FAILURE);
337 }
338 }
339
340 /* The process id of Emacs. */
341 int emacs_pid;
342
343 /* File handles for communicating with Emacs. */
344 FILE *out, *in;
345
346 /* A signal handler that passes the signal to the Emacs process.
347 Useful for SIGWINCH. */
348
349 SIGTYPE
350 pass_signal_to_emacs (int signalnum)
351 {
352 int old_errno = errno;
353
354 if (emacs_pid)
355 kill (emacs_pid, signalnum);
356
357 signal (signalnum, pass_signal_to_emacs);
358 errno = old_errno;
359 }
360
361 /* Signal handler for SIGCONT; notify the Emacs process that it can
362 now resume our tty frame. */
363
364 SIGTYPE
365 handle_sigcont (int signalnum)
366 {
367 int old_errno = errno;
368
369 if (tcgetpgrp (1) == getpgrp ())
370 {
371 /* We are in the foreground. */
372 fprintf (out, "-resume \n");
373 fflush (out);
374 fsync (fileno (out));
375 }
376 else
377 {
378 /* We are in the background; cancel the continue. */
379 kill (getpid (), SIGSTOP);
380 }
381 errno = old_errno;
382 }
383
384 /* Signal handler for SIGTSTP; notify the Emacs process that we are
385 going to sleep. Normally the suspend is initiated by Emacs via
386 server-handle-suspend-tty, but if the server gets out of sync with
387 reality, we may get a SIGTSTP on C-z. Handling this signal and
388 notifying Emacs about it should get things under control again. */
389
390 SIGTYPE
391 handle_sigtstp (int signalnum)
392 {
393 int old_errno = errno;
394 sigset_t set;
395
396 if (out)
397 {
398 fprintf (out, "-suspend \n");
399 fflush (out);
400 fsync (fileno (out));
401 }
402
403 /* Unblock this signal and call the default handler by temprarily
404 changing the handler and resignalling. */
405 sigprocmask (SIG_BLOCK, NULL, &set);
406 sigdelset (&set, signalnum);
407 signal (signalnum, SIG_DFL);
408 kill (getpid (), signalnum);
409 sigprocmask (SIG_SETMASK, &set, NULL); /* Let's the above signal through. */
410 signal (signalnum, handle_sigtstp);
411
412 errno = old_errno;
413 }
414
415 /* Set up signal handlers before opening a frame on the current tty. */
416
417 void
418 init_signals (void)
419 {
420 /* Set up signal handlers. */
421 signal (SIGWINCH, pass_signal_to_emacs);
422
423 /* Don't pass SIGINT and SIGQUIT to Emacs, because it has no way of
424 deciding which terminal the signal came from. C-g is now a
425 normal input event on secondary terminals. */
426 #if 0
427 signal (SIGINT, pass_signal_to_emacs);
428 signal (SIGQUIT, pass_signal_to_emacs);
429 #endif
430
431 signal (SIGCONT, handle_sigcont);
432 signal (SIGTSTP, handle_sigtstp);
433 signal (SIGTTOU, handle_sigtstp);
434 }
435
436 \f
437 #if !defined (HAVE_SOCKETS) || defined (NO_SOCKETS_IN_FILE_SYSTEM)
438
439 int
440 main (argc, argv)
441 int argc;
442 char **argv;
443 {
444 fprintf (stderr, "%s: Sorry, the Emacs server is supported only\n",
445 argv[0]);
446 fprintf (stderr, "on systems with Berkeley sockets.\n");
447
448 fail ();
449 }
450
451 #else /* HAVE_SOCKETS */
452
453 #include <sys/types.h>
454 #include <sys/socket.h>
455 #include <sys/un.h>
456 #include <sys/stat.h>
457 #include <errno.h>
458
459 extern char *strerror ();
460 extern int errno;
461
462 /* Three possibilities:
463 2 - can't be `stat'ed (sets errno)
464 1 - isn't owned by us
465 0 - success: none of the above */
466
467 static int
468 socket_status (socket_name)
469 char *socket_name;
470 {
471 struct stat statbfr;
472
473 if (stat (socket_name, &statbfr) == -1)
474 return 2;
475
476 if (statbfr.st_uid != geteuid ())
477 return 1;
478
479 return 0;
480 }
481
482 /* Returns 1 if PREFIX is a prefix of STRING. */
483 static int
484 strprefix (char *prefix, char *string)
485 {
486 int i;
487 if (! prefix)
488 return 1;
489
490 if (!string)
491 return 0;
492
493 for (i = 0; prefix[i]; i++)
494 if (!string[i] || string[i] != prefix[i])
495 return 0;
496 return 1;
497 }
498
499 int
500 main (argc, argv)
501 int argc;
502 char **argv;
503 {
504 int s, i, needlf = 0;
505 struct sockaddr_un server;
506 char *cwd, *str;
507 char string[BUFSIZ];
508
509 main_argc = argc;
510 main_argv = argv;
511 progname = argv[0];
512
513 /* Process options. */
514 decode_options (argc, argv);
515
516 if ((argc - optind < 1) && !eval && !tty && !window_system)
517 {
518 fprintf (stderr, "%s: file name or argument required\n", progname);
519 fprintf (stderr, "Try `%s --help' for more information\n", progname);
520 exit (EXIT_FAILURE);
521 }
522
523 /*
524 * Open up an AF_UNIX socket in this person's home directory
525 */
526
527 if ((s = socket (AF_UNIX, SOCK_STREAM, 0)) < 0)
528 {
529 fprintf (stderr, "%s: ", argv[0]);
530 perror ("socket");
531 fail ();
532 }
533
534 server.sun_family = AF_UNIX;
535
536 {
537 int sock_status = 0;
538 int default_sock = !socket_name;
539 int saved_errno = 0;
540
541 char *server_name = "server";
542
543 if (socket_name && !index (socket_name, '/') && !index (socket_name, '\\'))
544 { /* socket_name is a file name component. */
545 server_name = socket_name;
546 socket_name = NULL;
547 default_sock = 1; /* Try both UIDs. */
548 }
549
550 if (default_sock)
551 {
552 socket_name = alloca (100 + strlen (server_name));
553 sprintf (socket_name, "/tmp/emacs%d/%s",
554 (int) geteuid (), server_name);
555 }
556
557 if (strlen (socket_name) < sizeof (server.sun_path))
558 strcpy (server.sun_path, socket_name);
559 else
560 {
561 fprintf (stderr, "%s: socket-name %s too long",
562 argv[0], socket_name);
563 fail ();
564 }
565
566 /* See if the socket exists, and if it's owned by us. */
567 sock_status = socket_status (server.sun_path);
568 saved_errno = errno;
569 if (sock_status && default_sock)
570 {
571 /* Failing that, see if LOGNAME or USER exist and differ from
572 our euid. If so, look for a socket based on the UID
573 associated with the name. This is reminiscent of the logic
574 that init_editfns uses to set the global Vuser_full_name. */
575
576 char *user_name = (char *) getenv ("LOGNAME");
577
578 if (!user_name)
579 user_name = (char *) getenv ("USER");
580
581 if (user_name)
582 {
583 struct passwd *pw = getpwnam (user_name);
584
585 if (pw && (pw->pw_uid != geteuid ()))
586 {
587 /* We're running under su, apparently. */
588 socket_name = alloca (100 + strlen (server_name));
589 sprintf (socket_name, "/tmp/emacs%d/%s",
590 (int) pw->pw_uid, server_name);
591
592 if (strlen (socket_name) < sizeof (server.sun_path))
593 strcpy (server.sun_path, socket_name);
594 else
595 {
596 fprintf (stderr, "%s: socket-name %s too long",
597 argv[0], socket_name);
598 exit (EXIT_FAILURE);
599 }
600
601 sock_status = socket_status (server.sun_path);
602 saved_errno = errno;
603 }
604 else
605 errno = saved_errno;
606 }
607 }
608
609 switch (sock_status)
610 {
611 case 1:
612 /* There's a socket, but it isn't owned by us. This is OK if
613 we are root. */
614 if (0 != geteuid ())
615 {
616 fprintf (stderr, "%s: Invalid socket owner\n", argv[0]);
617 fail ();
618 }
619 break;
620
621 case 2:
622 /* `stat' failed */
623 if (saved_errno == ENOENT)
624 fprintf (stderr,
625 "%s: can't find socket; have you started the server?\n\
626 To start the server in Emacs, type \"M-x server-start\".\n",
627 argv[0]);
628 else
629 fprintf (stderr, "%s: can't stat %s: %s\n",
630 argv[0], server.sun_path, strerror (saved_errno));
631 fail ();
632 break;
633 }
634 }
635
636 if (connect (s, (struct sockaddr *) &server, strlen (server.sun_path) + 2)
637 < 0)
638 {
639 fprintf (stderr, "%s: ", argv[0]);
640 perror ("connect");
641 fail ();
642 }
643
644 /* We use the stream OUT to send our commands to the server. */
645 if ((out = fdopen (s, "r+")) == NULL)
646 {
647 fprintf (stderr, "%s: ", argv[0]);
648 perror ("fdopen");
649 fail ();
650 }
651
652 /* We use the stream IN to read the responses.
653 We used to use just one stream for both output and input
654 on the socket, but reversing direction works nonportably:
655 on some systems, the output appears as the first input;
656 on other systems it does not. */
657 if ((in = fdopen (s, "r+")) == NULL)
658 {
659 fprintf (stderr, "%s: ", argv[0]);
660 perror ("fdopen");
661 fail ();
662 }
663
664 #ifdef HAVE_GETCWD
665 cwd = getcwd (string, sizeof string);
666 #else
667 cwd = getwd (string);
668 #endif
669 if (cwd == 0)
670 {
671 /* getwd puts message in STRING if it fails. */
672
673 #ifdef HAVE_GETCWD
674 fprintf (stderr, "%s: %s (%s)\n", argv[0],
675 "cannot get current working directory", strerror (errno));
676 #else
677 fprintf (stderr, "%s: %s (%s)\n", argv[0], string, strerror (errno));
678 #endif
679 fail ();
680 }
681
682 /* First of all, send our version number for verification. */
683 fprintf (out, "-version %s ", VERSION);
684
685 /* Send over our environment. */
686 {
687 extern char **environ;
688 int i;
689 for (i = 0; environ[i]; i++)
690 {
691 char *name = xstrdup (environ[i]);
692 char *value = strchr (name, '=');
693 if (value && strlen (value) > 1)
694 {
695 *value++ = 0;
696 fprintf (out, "-env ");
697 quote_argument (name, out);
698 fprintf (out, " ");
699 quote_argument (value, out);
700 fprintf (out, " ");
701 fflush (out);
702 }
703 free (name);
704 }
705 }
706
707 retry:
708 if (nowait)
709 fprintf (out, "-nowait ");
710
711 if (display)
712 {
713 fprintf (out, "-display ");
714 quote_argument (display, out);
715 fprintf (out, " ");
716 }
717
718 if (tty)
719 {
720 char *tty_name = ttyname (fileno (stdin));
721 char *type = getenv ("TERM");
722
723 if (! tty_name)
724 {
725 fprintf (stderr, "%s: could not get terminal name\n", progname);
726 fail ();
727 }
728
729 if (! type)
730 {
731 fprintf (stderr, "%s: please set the TERM variable to your terminal type\n",
732 progname);
733 fail ();
734 }
735
736 if (! strcmp (type, "eterm"))
737 {
738 /* This causes nasty, MULTI_KBOARD-related input lockouts. */
739 fprintf (stderr, "%s: opening a frame in an Emacs term buffer"
740 " is not supported\n", progname);
741 fail ();
742 }
743
744 init_signals ();
745
746 fprintf (out, "-tty ");
747 quote_argument (tty_name, out);
748 fprintf (out, " ");
749 quote_argument (type, out);
750 fprintf (out, " ");
751 }
752
753 if (window_system)
754 fprintf (out, "-window-system ");
755
756 if ((argc - optind > 0))
757 {
758 for (i = optind; i < argc; i++)
759 {
760 int relative = 0;
761
762 if (eval)
763 {
764 /* Don't prepend any cwd or anything like that. */
765 fprintf (out, "-eval ");
766 quote_argument (argv[i], out);
767 fprintf (out, " ");
768 continue;
769 }
770
771 if (*argv[i] == '+')
772 {
773 char *p = argv[i] + 1;
774 while (isdigit ((unsigned char) *p) || *p == ':') p++;
775 if (*p == 0)
776 {
777 fprintf (out, "-position ");
778 quote_argument (argv[i], out);
779 fprintf (out, " ");
780 continue;
781 }
782 else
783 relative = 1;
784 }
785 else if (*argv[i] != '/')
786 relative = 1;
787
788 fprintf (out, "-file ");
789 if (relative)
790 {
791 quote_argument (cwd, out);
792 fprintf (out, "/");
793 }
794 quote_argument (argv[i], out);
795 fprintf (out, " ");
796 }
797 }
798 else
799 {
800 if (!tty && !window_system)
801 {
802 while ((str = fgets (string, BUFSIZ, stdin)))
803 {
804 if (eval)
805 fprintf (out, "-eval ");
806 else
807 fprintf (out, "-file ");
808 quote_argument (str, out);
809 }
810 fprintf (out, " ");
811 }
812 }
813
814 fprintf (out, "\n");
815 fflush (out);
816 fsync (fileno (out));
817
818 /* Wait for an answer. */
819 if (!eval && !tty && !nowait)
820 {
821 printf ("Waiting for Emacs...");
822 needlf = 2;
823 }
824 fflush (stdout);
825 fsync (1);
826
827 /* Now, wait for an answer and print any messages. */
828 while ((str = fgets (string, BUFSIZ, in)))
829 {
830 char *p = str + strlen (str) - 1;
831 while (p > str && *p == '\n')
832 *p-- = 0;
833
834 if (strprefix ("-good-version ", str))
835 {
836 /* -good-version: The versions match. */
837 }
838 else if (strprefix ("-emacs-pid ", str))
839 {
840 /* -emacs-pid PID: The process id of the Emacs process. */
841 emacs_pid = strtol (string + strlen ("-emacs-pid"), NULL, 10);
842 }
843 else if (strprefix ("-window-system-unsupported ", str))
844 {
845 /* -window-system-unsupported: Emacs was compiled without X
846 support. Try again on the terminal. */
847 window_system = 0;
848 nowait = 0;
849 tty = 1;
850 goto retry;
851 }
852 else if (strprefix ("-print ", str))
853 {
854 /* -print STRING: Print STRING on the terminal. */
855 str = unquote_argument (str + strlen ("-print "));
856 if (needlf)
857 printf ("\n");
858 printf ("%s", str);
859 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
860 }
861 else if (strprefix ("-error ", str))
862 {
863 /* -error DESCRIPTION: Signal an error on the terminal. */
864 str = unquote_argument (str + strlen ("-error "));
865 if (needlf)
866 printf ("\n");
867 printf ("*ERROR*: %s", str);
868 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
869 }
870 else if (strprefix ("-suspend ", str))
871 {
872 /* -suspend: Suspend this terminal, i.e., stop the process. */
873 if (needlf)
874 printf ("\n");
875 needlf = 0;
876 kill (0, SIGSTOP);
877 }
878 else
879 {
880 /* Unknown command. */
881 if (needlf)
882 printf ("\n");
883 printf ("*ERROR*: Unknown message: %s", str);
884 needlf = str[0] == '\0' ? needlf : str[strlen (str) - 1] != '\n';
885 }
886 }
887
888 if (needlf)
889 printf ("\n");
890 fflush (stdout);
891 fsync (1);
892
893 return EXIT_SUCCESS;
894 }
895
896 #endif /* HAVE_SOCKETS */
897 \f
898 #ifndef HAVE_STRERROR
899 char *
900 strerror (errnum)
901 int errnum;
902 {
903 extern char *sys_errlist[];
904 extern int sys_nerr;
905
906 if (errnum >= 0 && errnum < sys_nerr)
907 return sys_errlist[errnum];
908 return (char *) "Unknown error";
909 }
910
911 #endif /* ! HAVE_STRERROR */
912
913 /* arch-tag: f39bb9c4-73eb-477e-896d-50832e2ca9a7
914 (do not change this comment) */
915
916 /* emacsclient.c ends here */