linux tty设备号,linux tty设备

/dev/console是什么

如果系统中存在多个tty设备,想象一下,这时内核启动的log应该打印在哪里,这时内核会从tty中选择一个最合适的作为console,当然内核启动参数中也可以明确的去指定那个tty作为内核的console,/dev/console主要是暴露给用户空间使用的,主要用于系统管理员在改终端上登陆用。

/dev/tty又是什么

The file /dev/tty is a character file with major number 5 and minor number 0, usually of mode 0666 and owner.group root.tty. It is a synonym for the controlling terminal of a process, if any.

/dev/tty can represent different controlling terminals, without being a link, because the driver which implements it determines what the calling process’ controlling terminal is, if any.

如果当前进程有控制终端(Controlling Terminal)的话,那么/dev/tty就是当前进程的控制终端的设备特殊文件。

下面从内核源码的角度来分析一下具体的实现:

//./drivers/tty/tty_io.c

int __init tty_init(void)

{

cdev_init(&tty_cdev, &tty_fops);

if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||

register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)

panic("Couldn't register /dev/tty driver\n");

device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");

cdev_init(&console_cdev, &console_fops);

if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||

register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)

panic("Couldn't register /dev/console driver\n");

consdev = device_create_with_groups(tty_class, NULL,

MKDEV(TTYAUX_MAJOR, 1), NULL,

cons_dev_groups, "console");

if (IS_ERR(consdev))

consdev = NULL;

#ifdef CONFIG_VT

vty_init(&console_fops);

#endif

return 0;

}

static const struct file_operations tty_fops = {

.llseek = no_llseek,

.read = tty_read,

.write = tty_write,

.poll = tty_poll,

.unlocked_ioctl = tty_ioctl,

.compat_ioctl = tty_compat_ioctl,

.open = tty_open,

.release = tty_release,

.fasync = tty_fasync,

};

static const struct file_operations console_fops = {

.llseek = no_llseek,

.read = tty_read,

.write = redirected_tty_write,

.poll = tty_poll,

.unlocked_ioctl = tty_ioctl,

.compat_ioctl = tty_compat_ioctl,

.open = tty_open,

.release = tty_release,

.fasync = tty_fasync,

};

可以看出它们的打开函数都是tty_open,下面详细分析一下tty_open()这个函数的实现:

static int tty_open(struct inode *inode, struct file *filp)

{

dev_t device = inode->i_rdev; //得到设备号

...

tty = tty_open_current_tty(device, filp);

if (!tty)

tty = tty_open_by_driver(device, inode, filp);

...

tty_add_file(tty, filp);

...

}

/**

* tty_open_current_tty - get locked tty of current task

* @device: device number

* @filp: file pointer to tty

* @return: locked tty of the current task iff @device is /dev/tty

*

* Performs a re-open of the current task's controlling tty.

*

* We cannot return driver and index like for the other nodes because

* devpts will not work then. It expects inodes to be from devpts FS.

*/

static struct tty_struct *tty_open_current_tty(dev_t device, struct file *filp)

{

struct tty_struct *tty;

int retval;

if (device != MKDEV(TTYAUX_MAJOR, 0)) //判断打开的是否是/dev/tty

return NULL;

tty = get_current_tty();

if (!tty)

return ERR_PTR(-ENXIO);

filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */

/* noctty = 1; */

tty_lock(tty);

tty_kref_put(tty); /* safe to drop the kref now */

retval = tty_reopen(tty);

if (retval < 0) {

tty_unlock(tty);

tty = ERR_PTR(retval);

}

return tty;

}

struct tty_struct *get_current_tty(void)

{

struct tty_struct *tty;

unsigned long flags;

spin_lock_irqsave(&current->sighand->siglock, flags);

tty = tty_kref_get(current->signal->tty); //这个就是当前调用进程的控制终端

spin_unlock_irqrestore(&current->sighand->siglock, flags);

return tty;

}

/* Associate a new file with the tty structure */

void tty_add_file(struct tty_struct *tty, struct file *file)

{

struct tty_file_private *priv = file->private_data;

priv->tty = tty; //将关联的tty放在file的私有数据中保存,这样在后面的tty_read中就能调用对应的tty去执行真正的read动作

priv->file = file;

spin_lock(&tty->files_lock);

list_add(&priv->list, &tty->tty_files);

spin_unlock(&tty->files_lock);

}

可以看出/dev/tty打开的就是当前进程的控制终端,所以不同的session通过

echo hello > /dev/tty

总是能在当前控制终端中显示出来

下面来分析/dev/console的打开过程:

static struct tty_struct *tty_open_by_driver(dev_t device, struct inode *inode,

struct file *filp)

{

...

mutex_lock(&tty_mutex);

driver = tty_lookup_driver(device, filp, &index);

if (IS_ERR(driver)) {

mutex_unlock(&tty_mutex);

return ERR_CAST(driver);

}

/* check whether we're reopening an existing tty */

tty = tty_driver_lookup_tty(driver, filp, index);

if (IS_ERR(tty)) {

mutex_unlock(&tty_mutex);

goto out;

}

...

}

static struct tty_driver *tty_lookup_driver(dev_t device, struct file *filp,

int *index)

{

...

switch (device) {

case MKDEV(TTYAUX_MAJOR, 1): {

struct tty_driver *console_driver = console_device(index);

if (console_driver) {

driver = tty_driver_kref_get(console_driver);

if (driver) {

/* Don't let /dev/console block */

filp->f_flags |= O_NONBLOCK;

break;

}

}

return ERR_PTR(-ENODEV);

}

}

...

}

/*

* Return the console tty driver structure and its associated index

*/

struct tty_driver *console_device(int *index)

{

struct console *c;

struct tty_driver *driver = NULL;

console_lock();

for_each_console(c) {

if (!c->device)

continue;

driver = c->device(c, index);

if (driver)

break;

}

console_unlock();

return driver;

}

这个函数实际就是返回当前console使用的tty对应的驱动

这里只是分析了个大概,重点是为了说明上面的理解,所有中间略去了很多细节,感兴趣的可以对着代码详细分析。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值