Accessing and Controlling UNIX Devices
Prof. Brian D. Davison
Computer Science & Engineering, Lehigh University
Announcements
- Reminder: project 6 due Thursday
- Wednesday's class will be in the PL122 lab
- Today's schedule
- Return homework #6; range 8-10, mean 9.4
- Accessing and Controlling UNIX Devices
UNIX Devices
- UNIX treats devices much like files
- Devices have filenames (ls /dev)
- Devices contain information and have properties
- You can read and write bytes to a device
- Use same system calls (e.g., open(), read(), write(), lseek(), close(), stat()).
- Not all devices support all file operations (e.g., write(), lseek(), etc.)
- Some special devices exist: /dev/null, /dev/zero, etc.
Example: UNIX Terminals
- The UNIX terminal is a sample device that acts much like a file.
- Terminal emulation is still used by telnet, ssh, xterm, since hardwired terminals are rarely used today.
- Use tty to tell the name of the current terminal device.
- Try cat /etc/motd > terminal-device-name
- Or any other command... to read or write to the device
Devices have properties
- Just like files, devices have properties (but not always the same)
- We can see these properties (stored in the inode) using ls -l
- Type of file (c=character, b=block) different
- Owner, modification time, permissions the same (wouldn't want others to be able to read from your keyboard)
- Not really files, but provide connections to the device
- No size, but have major and minor device numbers, which specify which driver handles the file, and a parameter to the driver
Devices are different from files
- After open()ing, files and devices are accessed via file descriptors.
- Settings for the fd are stored in the kernel
- For files, the use of buffering is such a setting
- For device like a terminal, we have baud rates, parity, echo mode, buffering, cr/lf translation
- Many of these attributes can be controlled by the programmer.
Controlling file descriptor attributes
Terminals are rather different from files
- Connections to ttys have additional attributes for a human interface
- In the naive model, output of a program is sent directly to be viewed by the user, and input by the user is sent directly to the program
- The naive model is false. There is processing between the user and the program.
- You press return/enter (ascii 13), process sees newline (ascii 10)
- Program prints newline, terminal sees cr+nl
- The program sees no input until you press enter
- The terminal driver handles
- Translation
- Buffering
- Editing
- Echo
- Wrapping
Viewing and changing terminal settings
- Use stty -a to see all terminal settings
- Many settings, e.g.:
- -olcuc -- don't convert from lower case to upper case
- onclr -- add newline to a carriage return (for output)
- echo -- show keys pressed (without requiring program to do it explicitly)
- stty can allow the shell to control some settings
- A program can (and often needs to) control the terminal settings
Controlling changing terminal settings
- Many user programs (e.g., editors) need to control what happens in response to user input
- What settings are available? See stty man page, header files
- Working with settings:
#include <termios.h>
struct termios settings;
tcgetattr(fd, &settings);
//test, set or clear bits
tcsetattr(fd, how, &settings);
- Bit processing:
- test a bit: if (flagset & MASK)
- set a bit: flagset != MASK;
- clear a bit: flagset &= ~MASK;
Sample code: echostate.c
/* echostate.c
* reports current state of echo bit in tty driver for fd 0
* shows how to read attributes from driver and test a bit
*/
#include <stdio.h>
#include <termios.h>
main()
{
struct termios info;
int rv;
rv = tcgetattr( 0, &info ); /* read values from driver */
if ( rv == -1 ){
perror( "tcgetattr");
exit(1);
}
if ( info.c_lflag & ECHO )
printf(" echo is on , since its bit is 1\n");
else
printf(" echo if OFF, since its bit is 0\n");
}
Sample code: setecho.c
/* setecho.c
* usage: setecho [y|n]
* shows: how to read, change, reset tty attributes
*/
#include <stdio.h>
#include <termios.h>
#define oops(s,x) { perror(s); exit(x); }
main(int ac, char *av[])
{
struct termios info;
if ( ac == 1 )
exit(0);
if ( tcgetattr(0,&info) == -1 ) /* get attribs */
oops("tcgettattr", 1);
if ( av[1][0] == 'y' )
info.c_lflag |= ECHO ; /* turn on bit */
else
info.c_lflag &= ~ECHO ; /* turn off bit */
if ( tcsetattr(0,TCSANOW,&info) == -1 ) /* set attribs */
oops("tcsetattr",2);
}