]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
sulogin: agetty: use the plymouth local protocol instead the plymouth binary
authorWerner Fink <werner@suse.de>
Fri, 22 Apr 2016 10:16:04 +0000 (12:16 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 20 May 2016 09:21:10 +0000 (11:21 +0200)
for stopping plymouthd.  That do not depend on the existence of
the plymouth binary if it e.g. becomes uninstalled or an other
service is providing plymouthd facilities.

[kzak@redhat.com: - fix compiler warnings [-Wpointer-sign]
                  - use sizeof() for write_all()
                  - cast to char* for read_all]

Signed-off-by: Werner Fink <werner@suse.de>
Signed-off-by: Karel Zak <kzak@redhat.com>
include/plymouth-ctrl.h [new file with mode: 0644]
lib/Makemodule.am
lib/plymouth-ctrl.c [new file with mode: 0644]
login-utils/sulogin.c
term-utils/agetty.c

diff --git a/include/plymouth-ctrl.h b/include/plymouth-ctrl.h
new file mode 100644 (file)
index 0000000..e1df363
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * plymouth-ctrl.h     Header file for communcations with plymouthd
+ *
+ * Copyright (c) 2016 SUSE Linux GmbH, All rights reserved.
+ * Copyright (c) 2016 Werner Fink <werner@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *  
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+/*
+ * Taken from plymouth 0.9.0 src/ply-boot-protocol.h
+ */
+
+#ifndef UTIL_LINUX_PLYMOUTH_CTRL_H
+#define UTIL_LINUX_PLYMOUTH_CTRL_H
+
+#define PLYMOUTH_SOCKET_PATH   "\0/org/freedesktop/plymouthd"
+#define ANSWER_TYP             '\x2'
+#define ANSWER_ENQ             '\x5'
+#define ANSWER_ACK             '\x6'
+#define ANSWER_MLT             '\t'
+#define ANSWER_NCK             '\x15'
+
+#define MAGIC_PRG_STOP         'A'
+#define MAGIC_PRG_CONT         'a'
+#define MAGIC_UPDATE           'U'
+#define MAGIC_SYS_UPDATE       'u'
+#define MAGIC_SYS_INIT         'S'
+#define MAGIC_DEACTIVATE       'D'
+#define MAGIC_REACTIVATE       'r'
+#define MAGIC_SHOW_SPLASH      '$'
+#define MAGIC_HIDE_SPLASH      'H'
+#define MAGIC_CHMOD            'C'
+#define MAGIC_CHROOT           'R'
+#define MAGIC_ACTIVE_VT                'V'
+#define MAGIC_QUESTION         'W'
+#define MAGIC_SHOW_MSG         'M'
+#define MAGIC_HIDE_MSG         'm'
+#define MAGIC_KEYSTROKE                'K'
+#define MAGIC_KEYSTROKE_RM     'L'
+#define MAGIC_PING             'P'
+#define MAGIC_QUIT             'Q'
+#define MAGIC_CACHED_PWD       'c'
+#define MAGIC_ASK_PWD          '*'
+#define MAGIC_DETAILS          '!'
+
+#define PLYMOUTH_TERMIOS_FLAGS_DELAY   30
+extern int plymouth_command(int cmd, ...);
+
+#endif /* UTIL_LINUX_PLYMOUTH_CTRL_H */
index 092d54e7453063ff532c28704c64a4a0c5a84390..b2172db13eb600c21097343865fe89ff85d7f460 100644 (file)
@@ -16,6 +16,7 @@ libcommon_la_SOURCES = \
        lib/md5.c \
        lib/pager.c \
        lib/path.c \
+       lib/plymouth-ctrl.c \
        lib/randutils.c \
        lib/setproctitle.c \
        lib/strutils.c \
diff --git a/lib/plymouth-ctrl.c b/lib/plymouth-ctrl.c
new file mode 100644 (file)
index 0000000..2a1b2ce
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * plymouth-ctrl.c     Simply communcations with plymouthd
+ *                     to avoid forked sub processes and/or
+ *                     misssed plymouth send commands tool
+ *                     due a plymouthd replacment.
+ *
+ * Copyright (c) 2016 SUSE Linux GmbH, All rights reserved.
+ * Copyright (c) 2016 Werner Fink <werner@suse.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING); if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ *
+ * Author: Werner Fink <werner@suse.de>
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "all-io.h"
+#include "c.h"
+#include "nls.h"
+#include "plymouth-ctrl.h"
+
+static int can_read(int fd, const long timeout)
+{
+       struct pollfd fds = {
+               .fd = fd,
+               .events = POLLIN|POLLPRI,
+               .revents = 0,
+       };
+       int ret;
+
+       do {
+               ret = poll(&fds, 1, timeout);
+       } while ((ret < 0) && (errno == EINTR));
+
+       return (ret == 1) && (fds.revents & (POLLIN|POLLPRI));
+}
+
+static int open_un_socket_and_connect(void)
+{
+       struct sockaddr_un su = {               /* The abstract UNIX socket of plymouth */
+               .sun_family = AF_UNIX,
+               .sun_path = PLYMOUTH_SOCKET_PATH,
+       };
+       const int one = 1;
+       int fd, ret;
+
+       fd = socket(PF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+       if (fd < 0) {
+               warnx(_("can not open UNIX socket"));
+               goto err;
+       }
+
+       ret = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, (socklen_t)sizeof(one));
+       if (ret < 0) {
+               warnx(_("can not set option for UNIX socket"));
+               close(fd);
+               fd = -1;
+               goto err;
+       }
+
+       /*
+        * Please note that the PLYMOUTH_SOCKET_PATH has a
+        * leading NULL byte to mark it as an abstract socket
+        */
+       ret = connect(fd, &su, offsetof(struct sockaddr_un, sun_path) + 1 + strlen(su.sun_path+1));
+       if (ret < 0) {
+               if (errno != ECONNREFUSED)
+                       warnx(_("can not connect on UNIX socket"));
+               close(fd);
+               fd = -1;
+               goto err;
+       }
+err:
+       return fd;
+}
+
+int plymouth_command(int cmd, ...)
+{
+       uint8_t answer[2], command[2];
+       struct sigaction sp, op;
+       int fdsock = -1, ret = 0;
+
+       sigemptyset (&sp.sa_mask);
+       sp.sa_handler = SIG_IGN;
+       sp.sa_flags = SA_RESTART;
+       sigaction(SIGPIPE, &sp, &op);
+
+       /*
+        * The plymouthd does read at least two bytes.
+        */
+       command[1] = '\0';
+       switch (cmd) {
+       case MAGIC_PING:
+               fdsock = open_un_socket_and_connect();
+               if (fdsock >= 0) {
+                       command[0] = cmd;
+                       write_all(fdsock, command, sizeof(command));
+               }
+               break;
+       case MAGIC_QUIT:
+               fdsock = open_un_socket_and_connect();
+               if (fdsock >= 0) {
+                       command[0] = cmd;
+                       write_all(fdsock, command, sizeof(command));
+               }
+               break;
+       default:
+               warnx(_("the plymouth request %c is not implemented"), cmd);
+       case '?':
+               goto err;
+       }
+
+       answer[0] = '\0';
+       if (fdsock >= 0) {
+               if (can_read(fdsock, 1000))
+                       read_all(fdsock, (char *) &answer[0], sizeof(answer));
+               close(fdsock);
+       }
+       sigaction(SIGPIPE, &op, NULL);
+       ret = (answer[0] == ANSWER_ACK) ? 1 : 0;
+err:
+       return ret;
+}
+
index 601d38caf2419843fae8b2d207c5ed53b160df9a..8d6e65229fff65c42eed6e8e6f31ece21f38e62e 100644 (file)
@@ -58,6 +58,7 @@
 #include "closestream.h"
 #include "nls.h"
 #include "pathnames.h"
+#include "plymouth-ctrl.h"
 #include "strutils.h"
 #include "ttyutils.h"
 #include "sulogin-consoles.h"
@@ -92,42 +93,6 @@ static int locked_account_password(const char *passwd)
        return 0;
 }
 
-#ifdef TIOCGLCKTRMIOS
-/*
- * For the case plymouth is found on this system
- */
-static int plymouth_command(const char* arg)
-{
-       const char *cmd = "/usr/bin/plymouth";
-       static int has_plymouth = 1;
-       pid_t pid;
-
-       if (!has_plymouth)
-               return 127;
-
-       pid = fork();
-       if (!pid) {
-               int fd = open("/dev/null", O_RDWR);
-               if (fd < 0)
-                       exit(127);
-               dup2(fd, 0);
-               dup2(fd, 1);
-               dup2(fd, 2);
-               if (fd > 2)
-                       close(fd);
-               execl(cmd, cmd, arg, (char *) NULL);
-               exit(127);
-       } else if (pid > 0) {
-               int status;
-               waitpid(pid, &status, 0);
-               if (status == 127)
-                       has_plymouth = 0;
-               return status;
-       }
-       return 1;
-}
-#endif
-
 /*
  * Fix the tty modes and set reasonable defaults.
  */
@@ -138,8 +103,9 @@ static void tcinit(struct console *con)
        struct termios lock;
        int fd = con->fd;
 #ifdef TIOCGLCKTRMIOS
-       int i = (plymouth_command("--ping")) ? 20 : 0;
-
+       int i = (plymouth_command(MAGIC_PING)) ? PLYMOUTH_TERMIOS_FLAGS_DELAY : 0;
+       if (i)
+               plymouth_command(MAGIC_QUIT);
        while (i-- > 0) {
                /*
                 * With plymouth the termios flags become changed after this
@@ -150,8 +116,6 @@ static void tcinit(struct console *con)
                        break;
                if (!lock.c_iflag && !lock.c_oflag && !lock.c_cflag && !lock.c_lflag)
                        break;
-               if (i == 15 && plymouth_command("quit") != 0)
-                       break;
                sleep(1);
        }
        memset(&lock, 0, sizeof(struct termios));
index 6d610c608916fb97e942b2276e86ccca32479348..ab82fdbc8dee6036a42acac290b25fee4f042e79 100644 (file)
@@ -41,6 +41,7 @@
 #include "all-io.h"
 #include "nls.h"
 #include "pathnames.h"
+#include "plymouth-ctrl.h"
 #include "c.h"
 #include "widechar.h"
 #include "ttyutils.h"
@@ -138,9 +139,6 @@ static int inotify_fd = AGETTY_RELOAD_FDNONE;
 static int netlink_fd = AGETTY_RELOAD_FDNONE;
 #endif
 
-#define AGETTY_PLYMOUTH                "/usr/bin/plymouth"
-#define AGETTY_PLYMOUTH_FDFILE "/dev/null"
-
 /*
  * When multiple baud rates are specified on the command line, the first one
  * we will try is the first one specified.
@@ -309,7 +307,6 @@ static void log_warn (const char *, ...)
 static ssize_t append(char *dest, size_t len, const char  *sep, const char *src);
 static void check_username (const char* nm);
 static void login_options_to_argv(char *argv[], int *argc, char *str, char *username);
-static int plymouth_command(const char* arg);
 static void reload_agettys(void);
 
 /* Fake hostname for ut_host specified on command line. */
@@ -1180,8 +1177,9 @@ static void termio_init(struct options *op, struct termios *tp)
        struct winsize ws;
        struct termios lock;
 #ifdef TIOCGLCKTRMIOS
-       int i =  (plymouth_command("--ping") == 0) ? 30 : 0;
-
+       int i =  (plymouth_command(MAGIC_PING) == 0) ? PLYMOUTH_TERMIOS_FLAGS_DELAY : 0;
+       if (i)
+               plymouth_command(MAGIC_QUIT);
        while (i-- > 0) {
                /*
                 * Even with TTYReset=no it seems with systemd or plymouth
@@ -1194,8 +1192,6 @@ static void termio_init(struct options *op, struct termios *tp)
                if (!lock.c_iflag && !lock.c_oflag && !lock.c_cflag && !lock.c_lflag)
                        break;
                debug("termios locked\n");
-               if (i == 15 && plymouth_command("quit") != 0)
-                       break;
                sleep(1);
        }
        memset(&lock, 0, sizeof(struct termios));
@@ -1725,7 +1721,9 @@ static void print_issue_file(struct options *op, struct termios *tp)
 /* Show login prompt, optionally preceded by /etc/issue contents. */
 static void do_prompt(struct options *op, struct termios *tp)
 {
+#ifdef AGETTY_RELOAD
 again:
+#endif
        print_issue_file(op, tp);
 
        if (op->flags & F_LOGINPAUSE) {
@@ -2596,40 +2594,6 @@ err:
        log_err(_("checkname failed: %m"));
 }
 
-/*
- * For the case plymouth is found on this system
- */
-static int plymouth_command(const char* arg)
-{
-       static int has_plymouth = 1;
-       pid_t pid;
-
-       if (!has_plymouth)
-               return 127;
-
-       pid = fork();
-       if (!pid) {
-               int fd = open(AGETTY_PLYMOUTH_FDFILE, O_RDWR);
-
-               if (fd < 0)
-                       err(EXIT_FAILURE,_("cannot open %s"),
-                                       AGETTY_PLYMOUTH_FDFILE);
-               dup2(fd, 0);
-               dup2(fd, 1);
-               dup2(fd, 2);
-               close(fd);
-               execl(AGETTY_PLYMOUTH, AGETTY_PLYMOUTH, arg, (char *) NULL);
-               exit(127);
-       } else if (pid > 0) {
-               int status;
-               waitpid(pid, &status, 0);
-               if (status == 127)
-                       has_plymouth = 0;
-               return status;
-       }
-       return 1;
-}
-
 static void reload_agettys(void)
 {
 #ifdef AGETTY_RELOAD