Search code examples
ctty

how to open /dev/console in C


I was reading wayland/weston code, the setting up tty part. I found it tries to acquire an available tty for doing KMS and start windows.

This is how it does:

    if (!wl->new_user) {
            wl->tty = STDIN_FILENO;
    } else if (tty) {
            t = ttyname(STDIN_FILENO);
            if (t && strcmp(t, tty) == 0)
                    wl->tty = STDIN_FILENO;
            else
                    wl->tty = open(tty, O_RDWR | O_NOCTTY);
    } else {
            int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
            char filename[16];

            if (tty0 < 0)
                    error(1, errno, "could not open tty0");

            if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
                    error(1, errno, "failed to find non-opened console"); 

            snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
            wl->tty = open(filename, O_RDWR | O_NOCTTY);
            close(tty0);
    }

in src/weston-launch.c.

It tries to open('/dev/tty0') and find a tty that available if no tty is specified.

But you can't do that, neither /dev/tty0 nor 'available tty' belongs to you. I tested with my simpler version. And of course I couldn't open /dev/tty0.

Do you guys know how this magic is done?


Solution

  • The actual available devices for a tty depend on the system. On most interactive Unix/Unix-like systems you will have a "tty" whose name can be found from the command-line program tty. For example:

    $ tty
    /dev/pts/2
    

    Likely, you also have a device named "tty", e.g.,

    $ ls -l /dev/tty
    lrwxrwxrwx   1 root     other         26 Feb  9  2014 /dev/tty -> ../devices/pseudo/sy@0:tty
    $ ls -lL /dev/tty
    crw-rw-rw-   1 root     tty       22,  0 Feb  9  2014 /dev/tty
    

    You cannot open just any tty device, because most of them are owned by root (or other users to which they have been assigned).

    For further discussion about the differences between /dev/console, /dev/tty and other tty-devices, see Cannot open /dev/console.

    According to the console_codes(4) manual page:

    VT_OPENQRY

    Returns the first available (non-opened) console. argp points to an int which is set to the number of the vt (1 <= *argp <= MAX_NR_CONSOLES).

    and for example on a Linux system I see this in /dev:

    crw-rw-rw-   1 root        5,  0 Mon 04:20:13   tty
    crw-------   1 root        4,  0 Mon 03:58:52   tty0
    crw-------   1 root        4,  1 Mon 04:00:41   tty1  
    crw-------   1 tom         4,  2 Mon 04:30:31   tty2
    crw-------   1 root        4,  3 Mon 04:00:41   tty3
    crw-------   1 root        4,  4 Mon 04:00:41   tty4
    crw-------   1 root        4,  5 Mon 04:00:41   tty5
    crw-------   1 root        4,  6 Mon 04:00:41   tty6
    crw-------   1 root        4,  7 Mon 03:58:52   tty7
    crw-------   1 root        4,  8 Mon 03:58:52   tty8
    crw-------   1 root        4,  9 Mon 03:58:52   tty9
    crw-------   1 root        4, 10 Mon 03:58:52   tty10  
    crw-------   1 root        4, 11 Mon 03:58:52   tty11
    

    All of those tty devices except one for which I have opened a console session are owned by root. To be able to log into one, a program such as getty acts to temporarily change its ownership. Doing a ps on my machine shows for example

    root      2977     1  0 04:00 tty1     00:00:00 /sbin/getty 38400 tty1          
    root      2978     1  0 04:00 tty2     00:00:00 /bin/login --                   
    root      2979     1  0 04:00 tty3     00:00:00 /sbin/getty 38400     tty3          
    root      2980     1  0 04:00 tty4     00:00:00 /sbin/getty 38400 tty4          
    root      2981     1  0 04:00 tty5     00:00:00 /sbin/getty 38400 tty5          
    root      2982     1  0 04:00 tty6     00:00:00 /sbin/getty 38400 tty6
    

    Note that getty is running as root. That gives it the privilege to change the ownership of the tty device as needed. That is, while the ioctl may identify an unused tty, you need elevated privileges to actually open it. Linux (like any other Unix-like system) does not have a way to provide ensure that one process has truly exclusive access to a terminal. So it uses the device ownership and permissions to ensure this access.