util: beef up logic to find ctty name

This commit is contained in:
Lennart Poettering 2011-02-17 16:29:04 +01:00
parent 4ff21d8582
commit fc116c6a19
4 changed files with 132 additions and 17 deletions

View file

@ -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);

View file

@ -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;

View file

@ -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);

View file

@ -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"