[PATCH] tty: Add a new file /proc/tty/consoles

From: Werner Fink
Date: Wed Oct 27 2010 - 07:25:26 EST


Add a new file /proc/tty/consoles to be able to
determine the registered system console lines.
If the reading process holds /dev/console open at
the regular standard input stream the active device
will be marked by an asterisk. Show possible
operations and also decode the used flags of the
of the listed console lines.

Signed-off-by: Werner Fink <werner@xxxxxxx>

diff --git a/Documentation/filesystems/proc.txt b/Documentation/filesystems/proc.txt
index 9fb6cbe..eeee8d9 100644
--- a/Documentation/filesystems/proc.txt
+++ b/Documentation/filesystems/proc.txt
@@ -1074,6 +1074,7 @@ Table 1-11: Files in /proc/tty
drivers list of drivers and their usage
ldiscs registered line disciplines
driver/serial usage statistic and status of single tty lines
+ consoles registered system console lines
..............................................................................

To see which tty's are currently in use, you can simply look into the file
@@ -1092,6 +1093,38 @@ To see which tty's are currently in use, you can simply look into the file
/dev/tty /dev/tty 5 0 system:/dev/tty
unknown /dev/tty 4 1-63 console

+To see which character device lines are currently used for the system console
+/dev/console, you may simply look into the file /proc/tty/consoles:
+
+ > cat /proc/tty/consoles
+ tty0 -WU (ECp) 4:7
+ ttyS0 -W- (Ep) 4:64
+
+The columns are:
+
+ device name of the device
+ operations R = can do read operations
+ W = can do write operations
+ U = can do unblank
+ flags E = it is enabled
+ C = it is prefered console
+ B = it is primary boot console
+ p = it is used for printk buffer
+ b = it is not a TTY but a Braille device
+ a = it is safe to use when cpu is offline
+ * = it is tty line of the reading process
+ + = it is controlling tty of the reading process
+ major:minor major and minor number of the device separated by a colon
+
+If the reading process holds /dev/console open at the regular standard input
+stream the active device will be marked by an asterisk:
+
+ > cat /proc/tty/consoles < /dev/console
+ tty0 -WU (ECp*) 4:7
+ ttyS0 -W- (Ep) 4:64
+ > tty
+ /dev/pts/3
+

1.8 Miscellaneous kernel statistics in /proc/stat
-------------------------------------------------
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index 83adcc8..5a6798c 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -12,7 +12,10 @@
#include <linux/proc_fs.h>
#include <linux/stat.h>
#include <linux/tty.h>
+#include <linux/tty_driver.h>
+#include <linux/console.h>
#include <linux/seq_file.h>
+#include <linux/fdtable.h>
#include <linux/bitops.h>

/*
@@ -137,6 +140,170 @@ static const struct file_operations proc_tty_drivers_operations = {
};

/*
+ * The device ID of file descriptor 0 of the current reading
+ * task if a character device...
+ */
+struct proc_tty_private {
+ dev_t tty_device;
+ unsigned int on_console:1;
+};
+
+/*
+ * This is the handler for /proc/tty/consoles
+ */
+static int show_console_dev(struct seq_file *m, void *v)
+{
+ struct console *con;
+ int index, len;
+ char flags[10];
+ dev_t dev = 0;
+
+ con = v;
+ if (!con)
+ return 0;
+
+ if (con->device) {
+ const struct tty_driver *driver;
+ driver = con->device(con, &index);
+ if (driver) {
+ dev = MKDEV(driver->major, driver->minor_start);
+ dev += index;
+ }
+ }
+
+ index = 0;
+ if (con->flags & CON_ENABLED)
+ flags[index++] = 'E';
+ if (con->flags & CON_CONSDEV)
+ flags[index++] = 'C';
+ if (con->flags & CON_BOOT)
+ flags[index++] = 'B';
+ if (con->flags & CON_PRINTBUFFER)
+ flags[index++] = 'p';
+ if (con->flags & CON_BRL)
+ flags[index++] = 'b';
+ if (con->flags & CON_ANYTIME)
+ flags[index++] = 'a';
+ if (m->private) {
+ const struct proc_tty_private *priv = m->private;
+ if (priv->on_console && (con->flags & CON_CONSDEV))
+ flags[index++] = '*';
+ if (dev && priv->tty_device == dev)
+ flags[index++] = '+';
+ }
+ flags[index] = 0;
+
+ seq_printf(m, "%s%d%n", con->name, con->index, &len);
+ len = 21 - len;
+ if (len < 1)
+ len = 1;
+ seq_printf(m, "%*c", len, ' ');
+ seq_printf(m, "%c%c%c (%s)%n", con->read ? 'R' : '-',
+ con->write ? 'W' : '-', con->unblank ? 'U' : '-',
+ flags, &len);
+ if (dev) {
+ len = 13 - len;
+ if (len < 1)
+ len = 1;
+ seq_printf(m, "%*c%4d:%d\n", len, ' ', MAJOR(dev), MINOR(dev));
+ }
+
+ return 0;
+}
+
+/*
+ * Determine terminal device of standard input of current task.
+ */
+static void current_console_device(struct proc_tty_private *priv)
+{
+ struct files_struct *files = get_files_struct(current);
+ const struct file *filp;
+ unsigned long flags;
+
+ if (!files)
+ return;
+
+ spin_lock(&files->file_lock);
+ filp = fcheck_files(files, 0);
+ if (filp) {
+ const struct inode *inode;
+ dget(filp->f_dentry);
+ inode = filp->f_dentry->d_inode;
+ if (inode->i_rdev == MKDEV(TTYAUX_MAJOR, 1))
+ priv->on_console = 1;
+ dput(filp->f_dentry);
+ }
+ spin_unlock(&files->file_lock);
+ put_files_struct(files);
+
+ if (lock_task_sighand(current, &flags)) {
+ struct signal_struct *sig = current->signal;
+ if (sig->tty)
+ priv->tty_device = tty_devnum(sig->tty);
+ unlock_task_sighand(current, &flags);
+ }
+}
+
+static void *c_start(struct seq_file *m, loff_t *pos)
+{
+ struct proc_tty_private *priv;
+ struct console *con;
+ loff_t off = 0;
+
+ m->private = NULL;
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (priv) {
+ current_console_device(priv);
+ m->private = priv;
+ }
+
+ acquire_console_sem();
+ for (con = console_drivers; con; con = con->next) {
+ if (off++ == *pos)
+ break;
+ }
+ return con;
+}
+
+static void *c_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ struct console *con = v;
+ con = con->next;
+ if (con)
+ ++*pos;
+ return con;
+}
+
+static void c_stop(struct seq_file *m, void *v)
+{
+ release_console_sem();
+ kfree(m->private);
+}
+
+static const struct seq_operations tty_consoles_op = {
+ .start = c_start,
+ .next = c_next,
+ .stop = c_stop,
+ .show = show_console_dev
+};
+
+/* iterator for consoles */
+/*
+ * Used for open /proc/tty/consoles.
+ */
+static int tty_consoles_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &tty_consoles_op);
+}
+
+static const struct file_operations proc_tty_consoles_operations = {
+ .open = tty_consoles_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/*
* This function is called by tty_register_driver() to handle
* registering the driver's /proc handler into /proc/tty/driver/<foo>
*/
@@ -186,4 +353,5 @@ void __init proc_tty_init(void)
proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops);
proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations);
+ proc_create("tty/consoles", 0, NULL, &proc_tty_consoles_operations);
}
--
1.6.0.2


--G4iJoqBmSsgzjUCe--
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/