diff options
author | Lennart Poettering <lennart@poettering.net> | 2011-02-17 16:29:04 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2011-02-17 16:29:04 +0100 |
commit | fc116c6a19877275eabb085cf03f0df23b17c0e9 (patch) | |
tree | f230c08a0ef01803a582141210798447bb8ce719 | |
parent | 4ff21d85822b521ed6741ef88cb4aaa384539dec (diff) |
util: beef up logic to find ctty name
-rw-r--r-- | src/tty-ask-password-agent.c | 31 | ||||
-rw-r--r-- | src/util.c | 109 | ||||
-rw-r--r-- | src/util.h | 7 | ||||
-rw-r--r-- | src/utmp-wtmp.c | 2 |
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" |