Remove useless check for ENOENT errno after socket(2) call.
[tem.git] / main.c
blob70c937fbfeea4e591cea81d7a6e6495b7fd72b8c
1 /* Copyright (C) 2020-2022 Sergey Sushilin <sergeysushilin@protonmail.com>
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of either:
6 * the GNU General Public License as published by
7 the Free Software Foundation; version 2.
9 * the GNU General Public License as published by
10 the Free Software Foundation; version 3.
12 or both in parallel, as here.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copies of the GNU General Public License,
20 version 2 and 3 along with this program;
21 if not, see <https://www.gnu.org/licenses/>. */
23 #define _GNU_SOURCE 1
24 #define _DEFAULT_SOURCE 1
25 #define _FORTIFY_SOURCE 3
27 #include <errno.h>
28 #include <error.h>
29 #include <fcntl.h>
30 #include <limits.h>
31 #include <paths.h>
32 #include <signal.h>
33 #include <stdbool.h>
34 #include <stddef.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sys/stat.h>
39 #include <sys/types.h>
40 #include <termios.h>
41 #include <unistd.h>
42 #include <sys/socket.h>
43 #include <sys/un.h>
45 #include "system.h"
46 #include "wrappers.h"
48 enum action
50 ACTION_DAEMON_START,
51 ACTION_DAEMON_STOP,
52 ACTION_DAEMON_RESTART,
53 ACTION_CLIENT_START,
54 ACTION_LOAD_FILE
57 /* Initialized in main(). */
58 static struct passwd *pw = NULL;
59 static uid_t uid = -1;
60 static char *emacs_directory_name = NULL;
61 static char *socket_name = NULL;
63 /* Here we do a simple check, whether socket exists,
64 but emacs daemon is not running. This can be when
65 emacs daemon and its watchdog was terminated without
66 allowing to clear up temporary files. */
67 static inline void
68 remove_socket_if_not_connectable (void)
70 /* Create new socket. */
71 int sock = socket (AF_LOCAL, SOCK_STREAM, 0);
73 if (sock < 0)
74 edie (errno, "socket(AF_LOCAL, SOCK_STREAM, 0)");
76 const size_t socket_name_length = strlen (socket_name);
77 struct sockaddr_un server;
79 if (socket_name_length >= sizeof (server.sun_path))
80 edie (0, "socket name is too long: %s", socket_name);
82 server.sun_family = AF_LOCAL;
83 memcpy (server.sun_path, socket_name, socket_name_length + 1);
85 if (connect (sock, &server, sizeof (server)) < 0 && errno != ENOENT)
86 xunlinkat (AT_FDCWD, socket_name);
87 else
88 shutdown (sock, SHUT_RDWR);
91 static inline __warn_unused_result bool
92 emacs_daemon_is_running (void)
94 struct stat sb;
96 if (unlikely (stat (socket_name, &sb) != 0))
98 if (unlikely (errno != ENOENT))
99 edie (errno, "stat(%s)", socket_name);
101 return false;
104 if (unlikely (!S_ISSOCK (sb.st_mode)))
105 edie (ENOTSOCK, "%s", socket_name);
107 /* There is a socket in our directory,
108 but this socket is not owned by us. */
109 if (unlikely (sb.st_uid != uid))
110 die (EXIT_FAILURE, "the socket does not belong to us");
112 return likely (faccessat (AT_FDCWD, socket_name, X_OK, AT_EACCESS) == 0);
115 static inline __returns_nonnull __warn_unused_result char *
116 get_alternate_editor (void)
118 char *alternate_editor = getenv ("ALTERNATE_EDITOR");
120 return alternate_editor != NULL ? alternate_editor : (char *) "emacs";
123 static inline __malloc __nonnull ((1, 3)) __returns_nonnull __warn_unused_result __force_inline char *
124 catenate (const char *string1, char delimer, const char *string2)
126 size_t length1 = strlen (string1), length2 = strlen (string2);
127 char *s = xmalloc (length1 + 1 + length2 + 1);
129 memcpy (&s[0], string1, length1);
130 s[length1] = delimer;
131 memcpy (&s[length1 + 1], string2, length2);
132 s[length1 + 1 + length2] = '\0';
133 return s;
136 static inline __malloc __returns_nonnull __warn_unused_result char **
137 get_required_environ (void)
139 /* Actually almost all may-be-used by emacs environ variables. */
140 const char *names[] =
142 "ALTERNATE_EDITOR",
143 "APPDATA",
144 "CMDPROXY",
145 "COLORTERM",
146 "COLUMNS",
147 "COMSPEC",
148 "DBUS_SESSION_BUS_ADDRESS",
149 "DISPLAY",
150 "EMACSCLIENT_TRAMP",
151 "EMACSCOLORS",
152 "EMACSDATA",
153 "EMACSLOADPATH",
154 "EMACSTEST",
155 "EMACS_SERVER_FILE",
156 "EMACS_SOCKET_NAME",
157 "HOME",
158 "INSIDE_EMACS",
159 "LANG",
160 "LC_ADDRESS",
161 "LC_ALL",
162 "LC_COLLATE",
163 "LC_CTYPE",
164 "LC_IDENTIFICATION",
165 "LC_MEASUREMENT",
166 "LC_MESSAGES",
167 "LC_MONETARY",
168 "LC_NAME",
169 "LC_NUMERIC",
170 "LC_PAPER",
171 "LC_TELEPHONE",
172 "LC_TIME",
173 "LINES",
174 "LISP_PRELOADED",
175 "LOGNAME",
176 "MAIL",
177 "NAME",
178 "PAGER",
179 "PATH",
180 "PWD",
181 "SHELL",
182 "SUSPEND",
183 "TEMP",
184 "TERM",
185 "TMP",
186 "TMPDIR",
187 "TZ",
188 "USER",
189 "USERNAME",
190 "WAYLAND_DISPLAY",
191 "XDG_CONFIG_HOME",
192 "XDG_RUNTIME_DIR",
194 size_t envn = 0;
195 char **envp = xmallocarray (countof (names) + 1, sizeof (char *));
197 for (size_t i = 0; i < countof (names); i++)
199 const char *name = names[i];
200 const char *value = getenv (name);
202 if (value != NULL)
203 envp[envn++] = catenate (name, '=', value);
206 envp[envn] = NULL;
207 return xreallocarray (envp, envn + 1, sizeof (char *));
210 /* Used when starting daemon to make sure
211 that we did not get in infinity waiting. */
212 static __noreturn void
213 sigaction_sigchld (int signo __unused,
214 siginfo_t *restrict info __unused,
215 void *restrict context __unused)
217 die (EXIT_FAILURE, "unexpected emacs daemon death");
220 static inline __nonnull ((3)) void
221 redirect_to_file (int descriptor, int directory_descriptor, const char *file, int flags, mode_t mode)
223 /* Redirect descriptor to file at 'directory_descriptor/file'. */
224 int fd = xopenat (directory_descriptor, file, flags, mode);
225 xdup2 (fd, descriptor);
226 xclose (fd);
229 static inline void
230 create_emacs_directory (void)
232 /* Access only for its user. */
233 xmkdir (emacs_directory_name, S_IRUSR | S_IWUSR | S_IXUSR);
236 static inline __warn_unused_result int
237 get_emacs_directory_descriptor (void)
239 /* Get socket directory descriptor. */
240 return xopen (emacs_directory_name, O_DIRECTORY | O_CLOEXEC, 0);
243 static inline void
244 initialize_daemon (void)
246 /* Change default directory to root. */
247 ignore_value (chdir ("/"));
249 create_emacs_directory ();
250 int emacs_directory_descriptor = get_emacs_directory_descriptor ();
252 /* Redirect stdin to /dev/null for emacs daemon. */
253 redirect_to_file (STDIN_FILENO, -1, _PATH_DEVNULL, O_RDONLY, 0);
255 /* Redirect stdout to /path/to/socket/log for emacs daemon. */
256 redirect_to_file (STDOUT_FILENO, emacs_directory_descriptor, "log",
257 O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
259 /* Redirect stderr to /path/to/socket/error for emacs daemon. */
260 redirect_to_file (STDERR_FILENO, emacs_directory_descriptor, "error",
261 O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR);
263 xclose (emacs_directory_descriptor);
266 static inline void
267 start_daemon (int argc, char **argv)
269 struct sigaction new_sighup_action = { 0 };
271 /* Actually, since we disconnect from controlling terminal, we will not
272 be able to catch such signal, but for daemon sake... */
273 sigemptyset (&new_sighup_action.sa_mask);
274 new_sighup_action.sa_handler = SIG_IGN;
275 sigaction (SIGHUP, &new_sighup_action, NULL);
277 /* Start daemon. */
278 pid_t daemonpid = xfork ();
280 if (daemonpid != 0)
282 if (program_exited_unsuccessfully (wait_program_termination (daemonpid)))
283 die (EXIT_FAILURE, "failed to start daemon");
285 return;
288 /* Become session leader. */
289 setsid ();
291 /* Start watchdog. */
292 pid_t watchdogpid = xfork ();
294 /* Initialize sigaction for SIGCHLD. */
295 struct sigaction new_sigchld_action = { 0 };
297 sigemptyset (&new_sigchld_action.sa_mask);
298 new_sigchld_action.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO;
299 new_sigchld_action.sa_sigaction = sigaction_sigchld;
301 /* Set up sigaction for SIGCHLD to find out if someone of our children
302 unexpectedly die. */
303 struct sigaction old_sigchld_action;
304 sigaction (SIGCHLD, &new_sigchld_action, &old_sigchld_action);
306 if (watchdogpid != 0)
308 /* NOTE: this will not degradate to a forever cycle since we set
309 SIGCHLD handler above to die if the daemon failed. */
310 while (!emacs_daemon_is_running ())
311 /* Magic value (40000 microseconds == 0.04 seconds) selected
312 experimentally for two purpuses:
314 1) to do not make user wait too long after daemon actually
315 started but we still sleeping,
316 2) to reduce count of faccessat() (in emacs_daemon_is_running()
317 function) and usleep() syscalls. */
318 usleep (40000);
320 /* There is nothing to do more. */
321 exit (EXIT_SUCCESS);
324 /* Restore default behaviour. */
325 sigaction (SIGCHLD, &old_sigchld_action, NULL);
327 initialize_daemon ();
329 /* Start emacs daemon. */
330 pid_t emacspid = xfork ();
332 if (emacspid != 0)
334 if (unlikely (program_exited_unsuccessfully (wait_program_termination (emacspid))))
335 die (EXIT_FAILURE, "emacs daemon failed");
337 exit (EXIT_SUCCESS);
340 int i = 1;
341 int c = 0;
342 char **v = xmallocarray (argc - 1 + 3, sizeof (*v));
344 v[c++] = "emacs";
345 v[c++] = catenate ("--fg-daemon", '=', socket_name);
347 while (i < argc)
348 v[c++] = argv[i++];
350 v[c] = NULL;
352 /* 'That's all, folks!' */
353 xexecvpe (v[0], v, get_required_environ ());
356 static struct termios attrs[3];
357 /* Sometimes emacsclient dies unexpectively and do not reset attributes
358 back, so handle this case by ourselves. */
359 static void
360 restore_attributes (void)
362 /* Restore std{in,out,err} attributes. */
363 xtcsetattr (STDIN_FILENO, TCSAFLUSH, &attrs[0]);
364 xtcsetattr (STDOUT_FILENO, TCSAFLUSH, &attrs[1]);
365 xtcsetattr (STDERR_FILENO, TCSAFLUSH, &attrs[2]);
368 static void
369 enstore_attributes (void)
371 /* Enstore std{in,out,err} attributes. */
372 xtcgetattr (STDIN_FILENO, &attrs[0]);
373 xtcgetattr (STDOUT_FILENO, &attrs[1]);
374 xtcgetattr (STDERR_FILENO, &attrs[2]);
376 xatexit (restore_attributes);
379 static inline int
380 start_client (int argc, char **argv)
382 pid_t pid = xfork ();
384 if (pid != 0)
385 return program_exited_successfully (wait_program_termination (pid)) ? EXIT_SUCCESS : EXIT_FAILURE;
387 int i = 1;
388 int c = 0;
389 char **v = xmallocarray (argc - 1 + 6, sizeof (*v));
391 v[c++] = "emacsclient";
392 v[c++] = "--tty";
393 v[c++] = "--quiet";
394 v[c++] = catenate ("--socket-name", '=', socket_name);
395 v[c++] = catenate ("--alternate-editor", '=', get_alternate_editor ());
397 /* Copy the rest arguments. */
398 while (i < argc)
399 v[c++] = argv[i++];
401 v[c] = NULL;
403 enstore_attributes ();
405 xexecvpe (v[0], v, get_required_environ ());
408 /* Called only on daemon stop. */
409 static inline void
410 cleanup_emacs_directory (void)
412 int emacs_directory_descriptor = get_emacs_directory_descriptor ();
414 xunlinkat (emacs_directory_descriptor, "log");
415 xunlinkat (emacs_directory_descriptor, "error");
416 xrmdir (emacs_directory_name);
417 xclose (emacs_directory_descriptor);
420 static void
421 stop_daemon (void)
423 pid_t pid = xfork ();
425 if (pid == 0)
427 char *v[5];
429 v[0] = "emacsclient";
430 v[1] = catenate ("--socket-name", '=', socket_name);
431 v[2] = "--eval";
432 v[3] = "(kill-emacs)";
433 v[4] = NULL;
435 xexecvpe (v[0], v, get_required_environ ());
438 if (unlikely (program_exited_unsuccessfully (wait_program_termination (pid))))
440 if (!emacs_daemon_is_running ())
441 cleanup_emacs_directory ();
443 die (EXIT_FAILURE, "failed to stop emacs daemon");
446 cleanup_emacs_directory ();
449 static inline void
450 restart_daemon (int argc, char **argv)
452 stop_daemon ();
453 start_daemon (argc, argv);
456 static inline void
457 load_file (int argc, char **argv)
459 pid_t pid = xfork ();
461 if (pid != 0)
463 if (unlikely (program_exited_unsuccessfully (wait_program_termination (pid))))
464 die (EXIT_FAILURE, "failed to load file in emacs daemon");
466 return;
469 int c = 0;
470 char **v = xmallocarray (argc - 1 + 4 + 1, sizeof (char *));
471 v[c++] = "emacsclient";
472 v[c++] = catenate ("--socket-name", '=', socket_name);
473 v[c++] = "--eval";
475 for (int i = 1; i < argc; i++)
477 const char load_command[] = "(load-file \"%s\")";
478 char *command = xmalloc (sizeof (load_command) - 2 - 1 + strlen (argv[i]) + 1);
480 xsprintf (command, load_command, argv[i]);
481 v[c++] = command;
484 v[c] = NULL;
486 xexecvpe (v[0], v, get_required_environ ());
489 static inline __noreturn void
490 usage (const char *argv0, int status)
492 fprintf (status == EXIT_SUCCESS ? stdout : stderr, "\
493 Usage: %s [OPTION] FILE...\n\
494 Tiny Emacs Manager.\n\
495 Every FILE can be either just a FILENAME or [+LINE[:COLUMN]] FILENAME.\n\
496 (Except when -load option specified).\n\
498 The following OPTIONS are accepted:\n\
499 -startd Start daemon, arguments passed to started daemon.\n\
500 -stopd Stop daemon, other arguments ignored.\n\
501 -restartd Restart daemon, arguments passed to started daemon.\n\
502 -load Load files specified by [FILE...].\n\
503 -help Print this usage information message.\n\
504 -version Print version.\n\
505 ", argv0);
507 exit (status);
510 static inline __noreturn void
511 version (void)
513 puts ("Tiny Emacs Manager 1.0");
514 exit (EXIT_SUCCESS);
517 static inline void
518 die_if_tty_is_not_connectable (void)
520 /* Do the same emacs does in init_tty() to check whether
521 we are able to connect to a tty. */
523 #if !defined(O_IGNORE_CTTY)
524 # define O_IGNORE_CTTY 0
525 #endif
527 const char *name = xttyname (STDIN_FILENO);
528 int fd = openat (AT_FDCWD, name, O_RDWR | O_NOCTTY | O_IGNORE_CTTY, 0);
530 if (fd < 0)
531 edie (errno, "%s", name);
532 else
533 xclose (fd);
536 static inline enum action
537 parse_options (int *restrict argcp, char ***restrict argvp)
539 int argc = *argcp;
540 char **argv = *argvp;
541 enum action action = ACTION_CLIENT_START;
542 char *arg = argv[1];
544 if (unlikely (arg[0] == '-' && arg[1] != '\0'))
546 arg++;
547 argc--;
548 argv++;
550 if (streq (arg, "help"))
551 usage ((*argvp)[0], EXIT_SUCCESS);
552 else if (streq (arg, "version"))
553 version ();
554 else if (streq (arg, "startd"))
555 action = ACTION_DAEMON_START;
556 else if (streq (arg, "stopd"))
557 action = ACTION_DAEMON_STOP;
558 else if (streq (arg, "restartd"))
559 action = ACTION_DAEMON_RESTART;
560 else if (streq (arg, "load"))
561 action = ACTION_LOAD_FILE;
562 else
564 fprintf (stderr, "unknown option %s\n", arg - 1);
565 usage ((*argvp)[0], EXIT_FAILURE);
569 *argcp = argc;
570 *argvp = argv;
571 return action;
574 static inline void
575 initialize_emacs_directory_name (void)
577 const char emacs_directory_name_format[] = "%s/.emacs-server";
579 emacs_directory_name = xmalloc (sizeof (emacs_directory_name_format) - 1 - 2 + strlen (pw->pw_dir) + 1);
580 xsprintf (emacs_directory_name, emacs_directory_name_format, pw->pw_dir);
583 static inline void
584 initialize_socket_name (void)
586 const char socket_name_format[] = "%s/.emacs-server/socket";
588 socket_name = xmalloc (sizeof (socket_name_format) - 1 - 2 + strlen (pw->pw_dir) + 1);
589 xsprintf (socket_name, socket_name_format, pw->pw_dir);
593 main (int argc, char **argv)
595 int status = EXIT_SUCCESS;
596 enum action action = ACTION_CLIENT_START;
598 die_if_tty_is_not_connectable ();
599 uid = xgetuid ();
600 pw = xgetpwuid (uid);
602 initialize_emacs_directory_name ();
603 initialize_socket_name ();
605 if (argc > 1)
606 action = parse_options (&argc, &argv);
608 remove_socket_if_not_connectable ();
610 if (unlikely (action != ACTION_DAEMON_START && !emacs_daemon_is_running ()))
612 /* Little feature to allow user do not specially care about 'e -startd'
613 when he just want to edit file by 'e filename'. */
614 if (action == ACTION_CLIENT_START)
615 start_daemon (0, NULL);
616 else
617 die (EXIT_FAILURE, "emacs daemon is not running");
620 switch (action)
622 case ACTION_DAEMON_START:
623 start_daemon (argc, argv);
624 break;
625 case ACTION_DAEMON_STOP:
626 stop_daemon ();
627 break;
628 case ACTION_DAEMON_RESTART:
629 restart_daemon (argc, argv);
630 break;
631 case ACTION_CLIENT_START:
632 status = start_client (argc, argv);
633 break;
634 case ACTION_LOAD_FILE:
635 if (argc < 1)
636 die (EXIT_FAILURE, "at least one file name to load required");
638 load_file (argc, argv);
639 break;
642 return status;