summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2011-02-17 16:29:04 +0100
committerLennart Poettering <lennart@poettering.net>2011-02-17 16:29:04 +0100
commitfc116c6a19877275eabb085cf03f0df23b17c0e9 (patch)
treef230c08a0ef01803a582141210798447bb8ce719 /src
parent4ff21d85822b521ed6741ef88cb4aaa384539dec (diff)
util: beef up logic to find ctty name
Diffstat (limited to 'src')
-rw-r--r--src/tty-ask-password-agent.c31
-rw-r--r--src/util.c109
-rw-r--r--src/util.h7
-rw-r--r--src/utmp-wtmp.c2
4 files changed, 132 insertions, 17 deletions
diff --git a/src/tty-ask-password-agent.c b/src/tty-ask-password-agent.c
index 00496e7119..655bfb9ff5 100644
--- a/src/tty-ask-password-agent.c
+++ b/src/tty-ask-password-agent.c
@@ -353,13 +353,13 @@ finish:
static int wall_tty_block(void) {
char *p;
- const char *t;
- int fd;
+ int fd, r;
+ dev_t devnr;
- if (!(t = ttyname(STDIN_FILENO)))
- return -errno;
+ if ((r = get_ctty_devnr(&devnr)) < 0)
+ return -r;
- if (asprintf(&p, "/dev/.systemd/ask-password-block/%s", file_name_from_path(t)) < 0)
+ if (asprintf(&p, "/dev/.systemd/ask-password-block/%u:%u", major(devnr), minor(devnr)) < 0)
return -ENOMEM;
mkdir_parents(p, 0700);
@@ -375,8 +375,25 @@ static int wall_tty_block(void) {
}
static bool wall_tty_match(const char *path) {
- int fd;
+ int fd, k;
char *p;
+ struct stat st;
+
+ if (path_is_absolute(path))
+ k = lstat(path, &st);
+ else {
+ if (asprintf(&p, "/dev/%s", path) < 0)
+ return true;
+
+ k = lstat(p, &st);
+ free(p);
+ }
+
+ if (k < 0)
+ return true;
+
+ if (!S_ISCHR(st.st_mode))
+ return true;
/* We use named pipes to ensure that wall messages suggesting
* password entry are not printed over password prompts
@@ -386,7 +403,7 @@ static bool wall_tty_match(const char *path) {
* advantage that the block will automatically go away if the
* process dies. */
- if (asprintf(&p, "/dev/.systemd/ask-password-block/%s", file_name_from_path(path)) < 0)
+ if (asprintf(&p, "/dev/.systemd/ask-password-block/%u:%u", major(st.st_rdev), minor(st.st_rdev)) < 0)
return true;
fd = open(p, O_WRONLY|O_CLOEXEC|O_NONBLOCK|O_NOCTTY);
diff --git a/src/util.c b/src/util.c
index 16e4ab289a..92268b69a9 100644
--- a/src/util.c
+++ b/src/util.c
@@ -2749,28 +2749,121 @@ char* getlogname_malloc(void) {
return name;
}
-int getttyname_malloc(char **r) {
- char path[PATH_MAX], *p, *c;
+int getttyname_malloc(int fd, char **r) {
+ char path[PATH_MAX], *c;
int k;
assert(r);
- if ((k = ttyname_r(STDIN_FILENO, path, sizeof(path))) != 0)
+ if ((k = ttyname_r(fd, path, sizeof(path))) != 0)
return -k;
char_array_0(path);
- p = path;
- if (startswith(path, "/dev/"))
- p += 5;
-
- if (!(c = strdup(p)))
+ if (!(c = strdup(startswith(path, "/dev/") ? path + 5 : path)))
return -ENOMEM;
*r = c;
return 0;
}
+int getttyname_harder(int fd, char **r) {
+ int k;
+ char *s;
+
+ if ((k = getttyname_malloc(fd, &s)) < 0)
+ return k;
+
+ if (streq(s, "tty")) {
+ free(s);
+ return get_ctty(r);
+ }
+
+ *r = s;
+ return 0;
+}
+
+int get_ctty_devnr(dev_t *d) {
+ int k;
+ char line[256], *p;
+ unsigned long ttynr;
+ FILE *f;
+
+ if (!(f = fopen("/proc/self/stat", "r")))
+ return -errno;
+
+ if (!(fgets(line, sizeof(line), f))) {
+ k = -errno;
+ fclose(f);
+ return k;
+ }
+
+ fclose(f);
+
+ if (!(p = strrchr(line, ')')))
+ return -EIO;
+
+ p++;
+
+ if (sscanf(p, " "
+ "%*c " /* state */
+ "%*d " /* ppid */
+ "%*d " /* pgrp */
+ "%*d " /* session */
+ "%lu ", /* ttynr */
+ &ttynr) != 1)
+ return -EIO;
+
+ *d = (dev_t) ttynr;
+ return 0;
+}
+
+int get_ctty(char **r) {
+ int k;
+ char fn[128], *s, *b, *p;
+ dev_t devnr;
+
+ assert(r);
+
+ if ((k = get_ctty_devnr(&devnr)) < 0)
+ return k;
+
+ snprintf(fn, sizeof(fn), "/dev/char/%u:%u", major(devnr), minor(devnr));
+ char_array_0(fn);
+
+ if ((k = readlink_malloc(fn, &s)) < 0) {
+
+ if (k != -ENOENT)
+ return k;
+
+ /* Probably something like the ptys which have no
+ * symlink in /dev/char. Let's return something
+ * vaguely useful. */
+
+ if (!(b = strdup(fn + 5)))
+ return -ENOMEM;
+
+ *r = b;
+ return 0;
+ }
+
+ if (startswith(s, "/dev/"))
+ p = s + 5;
+ else if (startswith(s, "../"))
+ p = s + 3;
+ else
+ p = s;
+
+ b = strdup(p);
+ free(s);
+
+ if (!b)
+ return -ENOMEM;
+
+ *r = b;
+ return 0;
+}
+
static int rm_rf_children(int fd, bool only_dirs) {
DIR *d;
int ret = 0;
diff --git a/src/util.h b/src/util.h
index 3898b89ff1..80f1a38b57 100644
--- a/src/util.h
+++ b/src/util.h
@@ -331,7 +331,12 @@ void sigset_add_many(sigset_t *ss, ...);
char* gethostname_malloc(void);
char* getlogname_malloc(void);
-int getttyname_malloc(char **r);
+
+int getttyname_malloc(int fd, char **r);
+int getttyname_harder(int fd, char **r);
+
+int get_ctty_devnr(dev_t *d);
+int get_ctty(char **r);
int chmod_and_chown(const char *path, mode_t mode, uid_t uid, gid_t gid);
diff --git a/src/utmp-wtmp.c b/src/utmp-wtmp.c
index 83da640bf3..b03a3e70af 100644
--- a/src/utmp-wtmp.c
+++ b/src/utmp-wtmp.c
@@ -370,7 +370,7 @@ int utmp_wall(const char *message, bool (*match_tty)(const char *tty)) {
goto finish;
}
- getttyname_malloc(&tty);
+ getttyname_harder(STDIN_FILENO, &tty);
if (asprintf(&text,
"\a\r\n"