EXPORT_SYMBOL(start_tty);
+/* We limit tty time update visibility to every 8 seconds or so. */
+static void tty_update_time(struct timespec *time)
+{
+ unsigned long sec = get_seconds();
+ if (abs(sec - time->tv_sec) & ~7)
+ time->tv_sec = sec;
+}
+
/**
* tty_read - read method for tty device files
* @file: pointer to tty file
else
i = -EIO;
tty_ldisc_deref(ld);
+
if (i > 0)
- inode->i_atime = current_fs_time(inode->i_sb);
+ tty_update_time(&inode->i_atime);
+
return i;
}
cond_resched();
}
if (written) {
- struct inode *inode = file->f_path.dentry->d_inode;
- inode->i_mtime = current_fs_time(inode->i_sb);
+ struct inode *inode = file->f_path.dentry->d_inode;
+ tty_update_time(&inode->i_mtime);
ret = written;
}
out:
struct file *p = NULL;
spin_lock(&redirect_lock);
- if (redirect) {
- get_file(redirect);
- p = redirect;
- }
+ if (redirect)
+ p = get_file(redirect);
spin_unlock(&redirect_lock);
if (p) {
*
* Locking: None
*/
-static void tty_line_name(struct tty_driver *driver, int index, char *p)
+static ssize_t tty_line_name(struct tty_driver *driver, int index, char *p)
{
- sprintf(p, "%s%d", driver->name, index + driver->name_base);
+ return sprintf(p, "%s%d", driver->name, index + driver->name_base);
}
/**
int devpts;
int idx;
char buf[64];
+ long timeout = 0;
if (tty_paranoia_check(tty, inode, "tty_release_dev"))
return 0;
"active!\n", tty_name(tty, buf));
tty_unlock();
mutex_unlock(&tty_mutex);
- schedule();
+ schedule_timeout_killable(timeout);
+ if (timeout < 120 * HZ)
+ timeout = 2 * timeout + 1;
+ else
+ timeout = MAX_SCHEDULE_TIMEOUT;
}
/*
if (!noctty &&
current->signal->leader &&
!current->signal->tty &&
- tty->session == NULL)
- __proc_set_tty(current, tty);
+ tty->session == NULL) {
+ /*
+ * Don't let a process that only has write access to the tty
+ * obtain the privileges associated with having a tty as
+ * controlling terminal (being able to reopen it with full
+ * access through /dev/tty, being able to perform pushback).
+ * Many distributions set the group of all ttys to "tty" and
+ * grant write-only access to all terminals for setgid tty
+ * binaries, which should not imply full privileges on all ttys.
+ *
+ * This could theoretically break old code that performs open()
+ * on a write-only file descriptor. In that case, it might be
+ * necessary to also permit this if
+ * inode_permission(inode, MAY_READ) == 0.
+ */
+ if (filp->f_mode & FMODE_READ)
+ __proc_set_tty(current, tty);
+ }
spin_unlock_irq(¤t->sighand->siglock);
tty_unlock();
mutex_unlock(&tty_mutex);
spin_unlock(&redirect_lock);
return -EBUSY;
}
- get_file(file);
- redirect = file;
+ redirect = get_file(file);
spin_unlock(&redirect_lock);
return 0;
}
* Takes ->siglock() when updating signal->tty
*/
-static int tiocsctty(struct tty_struct *tty, int arg)
+static int tiocsctty(struct tty_struct *tty, struct file *file, int arg)
{
int ret = 0;
if (current->signal->leader && (task_session(current) == tty->session))
goto unlock;
}
}
+
+ /* See the comment in tty_open(). */
+ if ((file->f_mode & FMODE_READ) == 0 && !capable(CAP_SYS_ADMIN)) {
+ ret = -EPERM;
+ goto unlock;
+ }
+
proc_set_tty(current, tty);
unlock:
mutex_unlock(&tty_mutex);
return ret;
}
+/**
+ * tiocgetd - get line discipline
+ * @tty: tty device
+ * @p: pointer to user data
+ *
+ * Retrieves the line discipline id directly from the ldisc.
+ *
+ * Locking: waits for ldisc reference (in case the line discipline
+ * is changing or the tty is being hungup)
+ */
+
+static int tiocgetd(struct tty_struct *tty, int __user *p)
+{
+ struct tty_ldisc *ld;
+ int ret;
+
+ ld = tty_ldisc_ref_wait(tty);
+ ret = put_user(ld->ops->num, p);
+ tty_ldisc_deref(ld);
+ return ret;
+}
+
/**
* send_break - performed time break
* @tty: device to break on
no_tty();
return 0;
case TIOCSCTTY:
- return tiocsctty(tty, arg);
+ return tiocsctty(tty, file, arg);
case TIOCGPGRP:
return tiocgpgrp(tty, real_tty, p);
case TIOCSPGRP:
case TIOCGSID:
return tiocgsid(tty, real_tty, p);
case TIOCGETD:
- return put_user(tty->ldisc->ops->num, (int __user *)p);
+ return tiocgetd(tty, p);
case TIOCSETD:
return tiocsetd(tty, p);
case TIOCVHANGUP:
if (i >= ARRAY_SIZE(cs))
break;
}
- while (i--)
- count += sprintf(buf + count, "%s%d%c",
- cs[i]->name, cs[i]->index, i ? ' ':'\n');
+ while (i--) {
+ int index = cs[i]->index;
+ struct tty_driver *drv = cs[i]->device(cs[i], &index);
+
+ /* don't resolve tty0 as some programs depend on it */
+ if (drv && (cs[i]->index > 0 || drv->major != TTY_MAJOR))
+ count += tty_line_name(drv, index, buf + count);
+ else
+ count += sprintf(buf + count, "%s%d",
+ cs[i]->name, cs[i]->index);
+
+ count += sprintf(buf + count, "%c", i ? ' ':'\n');
+ }
console_unlock();
return count;