summaryrefslogtreecommitdiff
path: root/src/shared/util.c
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2012-06-26 12:16:18 +0200
committerLennart Poettering <lennart@poettering.net>2012-06-26 12:21:43 +0200
commitaf6da548aa14c57da7f17b3a1f2211efdb811d19 (patch)
treee118258cb9795ee0b80b656c9aca121cf7bc8b3e /src/shared/util.c
parent0c7f15b3a95c3596a4756de5c44eb1fdcd0034fc (diff)
core: make systemd.confirm_spawn=1 actually work
This adds a timeout if the TTY cannot be acquired and makes sure we always output the question to the console, never to the TTY of the respective service.
Diffstat (limited to 'src/shared/util.c')
-rw-r--r--src/shared/util.c58
1 files changed, 48 insertions, 10 deletions
diff --git a/src/shared/util.c b/src/shared/util.c
index 67ec5ae747..041a63bb4b 100644
--- a/src/shared/util.c
+++ b/src/shared/util.c
@@ -2305,12 +2305,14 @@ int open_terminal(const char *name, int mode) {
*/
for (;;) {
- if ((fd = open(name, mode)) >= 0)
+ fd = open(name, mode);
+ if (fd >= 0)
break;
if (errno != EIO)
return -errno;
+ /* Max 1s in total */
if (c >= 20)
return -errno;
@@ -2321,7 +2323,8 @@ int open_terminal(const char *name, int mode) {
if (fd < 0)
return -errno;
- if ((r = isatty(fd)) < 0) {
+ r = isatty(fd);
+ if (r < 0) {
close_nointr_nofail(fd);
return -errno;
}
@@ -2373,8 +2376,15 @@ int flush_fd(int fd) {
}
}
-int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocstty_eperm) {
+int acquire_terminal(
+ const char *name,
+ bool fail,
+ bool force,
+ bool ignore_tiocstty_eperm,
+ usec_t timeout) {
+
int fd = -1, notify = -1, r, wd = -1;
+ usec_t ts = 0;
assert(name);
@@ -2391,27 +2401,35 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst
* on the same tty as an untrusted user this should not be a
* problem. (Which he probably should not do anyway.) */
+ if (timeout != (usec_t) -1)
+ ts = now(CLOCK_MONOTONIC);
+
if (!fail && !force) {
- if ((notify = inotify_init1(IN_CLOEXEC)) < 0) {
+ notify = inotify_init1(IN_CLOEXEC | (timeout != (usec_t) -1 ? IN_NONBLOCK : 0));
+ if (notify < 0) {
r = -errno;
goto fail;
}
- if ((wd = inotify_add_watch(notify, name, IN_CLOSE)) < 0) {
+ wd = inotify_add_watch(notify, name, IN_CLOSE);
+ if (wd < 0) {
r = -errno;
goto fail;
}
}
for (;;) {
- if (notify >= 0)
- if ((r = flush_fd(notify)) < 0)
+ if (notify >= 0) {
+ r = flush_fd(notify);
+ if (r < 0)
goto fail;
+ }
/* We pass here O_NOCTTY only so that we can check the return
* value TIOCSCTTY and have a reliable way to figure out if we
* successfully became the controlling process of the tty */
- if ((fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC)) < 0)
+ fd = open_terminal(name, O_RDWR|O_NOCTTY|O_CLOEXEC);
+ if (fd < 0)
return fd;
/* First, try to get the tty */
@@ -2440,9 +2458,29 @@ int acquire_terminal(const char *name, bool fail, bool force, bool ignore_tiocst
ssize_t l;
struct inotify_event *e;
- if ((l = read(notify, inotify_buffer, sizeof(inotify_buffer))) < 0) {
+ if (timeout != (usec_t) -1) {
+ usec_t n;
+
+ n = now(CLOCK_MONOTONIC);
+ if (ts + timeout < n) {
+ r = -ETIMEDOUT;
+ goto fail;
+ }
+
+ r = fd_wait_for_event(fd, POLLIN, ts + timeout - n);
+ if (r < 0)
+ goto fail;
+
+ if (r == 0) {
+ r = -ETIMEDOUT;
+ goto fail;
+ }
+ }
+
+ l = read(notify, inotify_buffer, sizeof(inotify_buffer));
+ if (l < 0) {
- if (errno == EINTR)
+ if (errno == EINTR || errno == EAGAIN)
continue;
r = -errno;