diff options
Diffstat (limited to 'term-utils/write.c')
-rw-r--r-- | term-utils/write.c | 81 |
1 files changed, 38 insertions, 43 deletions
diff --git a/term-utils/write.c b/term-utils/write.c index 1b476473f..be91218cf 100644 --- a/term-utils/write.c +++ b/term-utils/write.c @@ -64,6 +64,7 @@ #include "closestream.h" #include "nls.h" #include "strutils.h" +#include "ttyutils.h" #include "xalloc.h" static sig_atomic_t signal_received = 0; @@ -71,9 +72,11 @@ static sig_atomic_t signal_received = 0; struct write_control { uid_t src_uid; const char *src_login; - char *src_tty; + const char *src_tty_path; + const char *src_tty_name; const char *dst_login; - char dst_tty[PATH_MAX]; + char *dst_tty_path; + const char *dst_tty_name; }; static void __attribute__((__noreturn__)) usage(FILE *out) @@ -98,24 +101,20 @@ static void __attribute__((__noreturn__)) usage(FILE *out) * check_tty - check that a terminal exists, and get the message bit * and the access time */ -static int check_tty(char *tty, int *tty_writeable, time_t *tty_atime, int showerror) +static int check_tty(const char *tty, int *tty_writeable, time_t *tty_atime, int showerror) { struct stat s; - char path[PATH_MAX]; - if (sizeof(path) < strlen(tty) + 6) - return 1; - sprintf(path, "/dev/%s", tty); - if (stat(path, &s) < 0) { + if (stat(tty, &s) < 0) { if (showerror) - warn("%s", path); + warn("%s", tty); return 1; } if (getuid() == 0) /* root can always write */ *tty_writeable = 1; else { if (getegid() != s.st_gid) { - warnx(_("effective gid does not match group of %s"), path); + warnx(_("effective gid does not match group of %s"), tty); return 1; } *tty_writeable = s.st_mode & S_IWGRP; @@ -139,7 +138,7 @@ static int check_utmp(const struct write_control *ctl) while ((u = getutent())) { if (strncmp(ctl->dst_login, u->ut_user, sizeof(u->ut_user)) == 0 && - strncmp(ctl->dst_tty, u->ut_line, sizeof(u->ut_line)) == 0) { + strncmp(ctl->dst_tty_name, u->ut_line, sizeof(u->ut_line)) == 0) { res = 0; break; } @@ -165,6 +164,7 @@ static void search_utmp(struct write_control *ctl) struct utmp *u; time_t best_atime = 0, tty_atime; int num_ttys = 0, valid_ttys = 0, tty_writeable = 0, user_is_me = 0; + char path[UT_LINESIZE + 6]; utmpname(_PATH_UTMP); setutent(); @@ -173,13 +173,14 @@ static void search_utmp(struct write_control *ctl) if (strncmp(ctl->dst_login, u->ut_user, sizeof(u->ut_user)) != 0) continue; num_ttys++; - if (check_tty(u->ut_line, &tty_writeable, &tty_atime, 0)) + sprintf(path, "/dev/%s", u->ut_line); + if (check_tty(path, &tty_writeable, &tty_atime, 0)) /* bad term? skip */ continue; if (ctl->src_uid && !tty_writeable) /* skip ttys with msgs off */ continue; - if (strcmp(u->ut_line, ctl->src_tty) == 0) { + if (strcmp(u->ut_line, ctl->src_tty_name) == 0) { user_is_me = 1; /* don't write to yourself */ continue; @@ -190,8 +191,9 @@ static void search_utmp(struct write_control *ctl) valid_ttys++; if (best_atime < tty_atime) { best_atime = tty_atime; - xstrncpy(ctl->dst_tty, u->ut_line, - sizeof(ctl->dst_tty)); + free(ctl->dst_tty_path); + ctl->dst_tty_path = xstrdup(path); + ctl->dst_tty_name = ctl->dst_tty_path + 5; } } @@ -201,14 +203,17 @@ static void search_utmp(struct write_control *ctl) if (valid_ttys == 0) { if (user_is_me) { /* ok, so write to yourself! */ - xstrncpy(ctl->dst_tty, ctl->src_tty, sizeof(ctl->dst_tty)); + if (!ctl->src_tty_path) + errx(EXIT_FAILURE, _("can't find your tty's name")); + ctl->dst_tty_path = xstrdup(ctl->src_tty_path); + ctl->dst_tty_name = ctl->dst_tty_path + 5; return; } errx(EXIT_FAILURE, _("%s has messages disabled"), ctl->dst_login); } if (1 < valid_ttys) warnx(_("%s is logged in more than once; writing to %s"), - ctl->dst_login, ctl->dst_tty); + ctl->dst_login, ctl->dst_tty_name); } /* @@ -243,7 +248,7 @@ static void do_write(const struct write_control *ctl) struct passwd *pwd; time_t now; struct tm *tm; - char path[PATH_MAX], *host, line[512]; + char *host, line[512]; struct sigaction sigact; /* Determine our login name(s) before the we reopen() stdout */ @@ -254,11 +259,8 @@ static void do_write(const struct write_control *ctl) if ((login = getlogin()) == NULL) login = pwuid; - if (sizeof(path) < strlen(ctl->dst_tty) + 6) - errx(EXIT_FAILURE, _("tty path %s too long"), ctl->dst_tty); - snprintf(path, sizeof(path), "/dev/%s", ctl->dst_tty); - if ((freopen(path, "w", stdout)) == NULL) - err(EXIT_FAILURE, "%s", path); + if ((freopen(ctl->dst_tty_path, "w", stdout)) == NULL) + err(EXIT_FAILURE, "%s", ctl->dst_tty_path); sigact.sa_handler = signal_handler; sigemptyset(&sigact.sa_mask); @@ -277,10 +279,10 @@ static void do_write(const struct write_control *ctl) printf("\r\n\a\a\a"); if (strcmp(login, pwuid)) printf(_("Message from %s@%s (as %s) on %s at %s ..."), - login, host, pwuid, ctl->src_tty, timestamp); + login, host, pwuid, ctl->src_tty_name, timestamp); else printf(_("Message from %s@%s on %s at %s ..."), - login, host, ctl->src_tty, timestamp); + login, host, ctl->src_tty_name, timestamp); free(host); printf("\r\n"); @@ -329,25 +331,16 @@ int main(int argc, char **argv) else src_fd = -1; - if (src_fd != -1) { - if (!(ctl.src_tty = ttyname(src_fd))) - errx(EXIT_FAILURE, - _("can't find your tty's name")); - /* - * We may have /dev/ttyN but also /dev/pts/xx. Below, - * check_tty() will put "/dev/" in front, so remove that - * part. - */ - if (!strncmp(ctl.src_tty, "/dev/", 5)) - ctl.src_tty += 5; - if (check_tty(ctl.src_tty, &tty_writeable, NULL, 1)) + if (src_fd != -1 && + get_terminal_name(src_fd, &ctl.src_tty_path, &ctl.src_tty_name, NULL) == 0) { + if (check_tty(ctl.src_tty_path, &tty_writeable, NULL, 1)) exit(EXIT_FAILURE); if (!tty_writeable) errx(EXIT_FAILURE, _("you have write permission turned off")); tty_writeable = 0; } else - ctl.src_tty = "<no tty>"; + ctl.src_tty_name = "<no tty>"; ctl.src_uid = getuid(); @@ -361,23 +354,25 @@ int main(int argc, char **argv) case 3: ctl.dst_login = argv[1]; if (!strncmp(argv[2], "/dev/", 5)) - xstrncpy(ctl.dst_tty, argv[2] + 5, sizeof(ctl.dst_tty)); + ctl.dst_tty_path = xstrdup(argv[2]); else - xstrncpy(ctl.dst_tty, argv[2], sizeof(ctl.dst_tty)); + xasprintf(&ctl.dst_tty_path, "/dev/%s", argv[2]); + ctl.dst_tty_name = ctl.dst_tty_path + 5; if (check_utmp(&ctl)) errx(EXIT_FAILURE, _("%s is not logged in on %s"), - ctl.dst_login, ctl.dst_tty); - if (check_tty(ctl.dst_tty, &tty_writeable, NULL, 1)) + ctl.dst_login, ctl.dst_tty_name); + if (check_tty(ctl.dst_tty_path, &tty_writeable, NULL, 1)) exit(EXIT_FAILURE); if (ctl.src_uid && !tty_writeable) errx(EXIT_FAILURE, _("%s has messages disabled on %s"), - ctl.dst_login, ctl.dst_tty); + ctl.dst_login, ctl.dst_tty_name); do_write(&ctl); break; default: usage(stderr); } + free(ctl.dst_tty_path); return EXIT_SUCCESS; } |