550 likes | 689 Views
This chapter delves into the relationship between devices and files in system programming. It covers essential concepts such as controlling file descriptors, managing permissions, and the significance of various file attributes. Readers will learn about system calls like open, read, write, and ioctl, as well as the differences between terminal and disk files. The chapter also addresses race conditions, terminal modes, and provides practical examples for manipulating file settings using C programming. This knowledge is foundational for developing robust, device-aware applications.
E N D
Device == File ? • Filenames • Properties • permission bits • system call • open, read, write, lseek, close, stat
Device == File ? • Example: tty (chapter 2) Last_modified owner group mode filename inode link mode owner group size Last_modified filename minor # : Device link major # : Device Driver * Directory(d), Symbolic Link(l), Character Device(c), Block Device(b)
Device == File ? • Device Files and Inodes
Device != File ? • Disk Files vs Terminal Files • Devices have their own attributes. • Connection attributes - we can control attributes in a different way.
Change settings -Disk • 3-steps for controlling filedesciptors #include <fcntl.h> int s; s = fcntl(fd, F_GETFL); //step1. get flags s |= O_SYNC; //step2. modify flags result = fcntl(fd,F_SETFL,s); //step3. set flags if(result == -1) perror(“setting SYNC”);
Change settings -Disk • If two people log in at the same time, how can this Race Condition be avoided? • Auto Append #include <fcntl.h> int s; s = fcntl(fd, F_GETFL); s |= O_APPEND; result = fcntl(fd,F_SETFL,s); if(result == -1) perror(“setting APPEND”);
Controlling File Descriptors • fd = open(file_name, flags) • fd = open(fn, O_WRONLY|O_APPEND|O_SYNC); • Flags • O_CREAT: Create the file if it does not exist. • O_TRUNC: If the file exists, truncate the file to length zero. • O_EXCL: This flag is intended to prevent wo processes from creating the same file. The second call returns -1.
Attribute of Terminal #include <stdio.h> main() { int c, n = 0; while((c = getchar()) != 'Q') printf("char %3d is %c code %d\n", n++, c, c); } • A simple example $ ./a.out hello char 0 is h code 104 char 1 is e code 101 char 2 is l code 108 char 3 is l code 108 char 4 is o code 111 char 5 is code 10 Q $
Change settings -Terminal • The stty command $sttyerase X #make ‘X’ the erase key $stty –echo #type invisibly $stty erase @ echo #multiple requests
Change settings -Terminal • 3-steps for changing terminl driver #include <termios.h> structtermiosattribs; tcgetattr(fd, &attribs); //step1. get attribs settings.c_lflag |= O_ECHO; //step2. modify attribs tcsetattr(fd, TCSANOW, &attribs); //step3. send attribs ☞ TCSANOW, TCSADRAIN, TCSAFLUSH
structtermios structtermios { tcflag_tc_iflag; /*input mode flags*/ tcflag_tc_oflag; /*output mode flags*/ tcflag_tc_cflag; /*control mode flags*/ tcflag_tc_lflag; /*local mode flags*/ cc_tc_cc[NCCS]; /*control charters*/ speed_tc_ispeed; /*input speed*/ speed_tc_ospeed; /*output speed*/ };
Example – change state #include <stdio.h> #include <termios.h> #define oops(s,x) { perror(s);exit(x);} main(int ac, char *av[]) { structtermios info; if(ac==1) exit(0); if(tcgetattr(0, &info) == -1) //get attribs oops(“tcgetattr”, 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); }
Other Devices? • System call: ioctl
Example #include <stdio.h> #include <sys/ioctl.h> int main() { structwinsizewbuf; if(ioctl(0, TIOCGWINSZ, &wbuf) != -1) printf("%d rows x %d cols\n", wbuf.ws_row, wbuf.ws_col); return 0; }
Software tools • Programs that see no difference between disk files and devices Ex) who, ls, sort, uniq, grep, tr, du, … • Read stdin or files, Write to stdout and stderr. • $ sort > outputfile • $ sort x > /dev/lp
Device-Specific Program • Programs that interact with specific devices Ex) scanner, camera, cd-rom, … • In this chapter, we make terminal-specific program. user-program !
User-Program • Consider how the keystrokes are handled and output is processed. • Common concerns of user program(a) immediate response to keys(b) limited input set(c) timeout on input(d) resistance to Ctrl-C
Modes of the terminal driver • Raw mode- Sends entire sequence of characters. • Canonical mode- Erase characters before sending the revised sequence to the reading process. - Processes edit anddelete.
Modes of the terminal driver • Example input Hello data DEL DELDELDEL world • RAW mode output Hello data DEL DELDELDEL world • Canonical mode output Hello world
Example #include <stdio.h> #include <ctype.h> int main( ) { int c; while((c = getchar( )) != EOF) { if(c == ‘z’) c = ‘a’; else if(islower(c)) c++; putchar(c); } } * In Canonical Mode * In Non-Canonical Mode $ stty-icannon $ ./a.out ???? $ sttyicannon $ ./a.out abxcd ???? efg <ctrl-C>
Writing a User Program #!/bin/sh while true do do_a_transaction if play_again # our target then continue fi break done Accept inputif “y” : return 0if “n” : return 1 y : loop backn : break • What play_again does is • Prompt User with Question • If “y”, return 0 • If “n”, return 1
First play_again #include <stdio.h> #include <termios.h> #define QUESTION "Do you want another transaction“ intget_response(char *q) { printf("%s (y/n)?", q); while(1) { switch(getchar()) { case 'y': case 'Y': return 0; case 'n': case 'N': case EOF: return 1; } } } int main() { int response; response = get_response(QUESTION); return response; }
Second play_again: immediate response int main() { int response; tty_mode(0); set_crmode(); response = get_response(QUESTION); tty_mode(1); return response; } intset_crmode() { structtermiosttystate; tcgetattr(0, &ttystate); ttystate.c_lflag &= ~ICANON; ttystate.c_cc[VMIN] = 1; tcsetattr(0, TCSANOW, &ttystate); } inttty_mode(int how) { static structtermiosoriginal_mode; if(how == 0) { tcgetattr(0, &original_mode); return 0; } return tcsetattr(0, TCSANOW, &original_mode); }
Non-blocking mode • Blocking • getchar() or read() wait for input • How to set non-blocking • Use O_NDELAY in open or fcntl • New play_again • Timeout feature. • Telling the terminal drive not to wait • No input found then sleep for few seconds and look again for input • After three tries give up
New play_again /* play_again.c purpose: Ask if you want another transaction Method : set tty into chr-by-chr, no-echo mode set tty into no-delay mode read char, return result Returns: 0=> yes, 1=> no, 2=> timeout Better : rest the terminal mode on interrupt */ #include <stdio.h> #include <termios.h> #include <fcntl.h> #include <string.h> #define ASK "Do you want another transaction“ #define TRIES 3 /* maximum tries*/ #define SLEEPTIME 2 /* time per try */ #define BEEP putchar('\a') /* alert user */
/* play_again.c continued */ main( ) { intresponse; tty_mode(0); /* save current mode*/ set_cr_noecho_mode(); /* set –icanon, echo */ set_nodelay_mode(); /* noinput => EOF */ /* get some answer */ response = get_response(ASK, TRIES); tty_mode(1); /* restore orig mode */ return response; }
/* purpose : ask a question and wait for y/n answer or maxtries * method : use getchsr and complain about non –y/n input * returns : 0=> yes, 1=> no, 2=> timeout */ get_response(char* question, int maxtries) { int input; printf ("%s (y/n)?", question); /* ask*/ fflush(stdout); /* force output */ while(1) { sleep(SLEEPTIME); /* wait a bit*/ input = tolower(get_ok_char()); /* get next char*/ if (input == 'y') return 0; if (input == 'n') return 1; if (maxtries-- == 0) /* out time? */ return 2; /* say no */ BEEP; } }
/* skip over ilegal chars and return y,Y,n,N or EOP */ get_ok_char( ) { intc; while ((c = getchar())!=EOF && strchr("yYnN",c) == NULL) ; return c; } /* how == 0 => save current mode, how ==> 1 restore mode */ /* this version handles termios and fcnt1 flags */ tty_mode(inthow) { static structtermiosoriginal_mode; static intoriginal_flags; if (how == 0) { tcgetattr(0, &original_mode); orginal_flags= fcntl(0, F_GETFL); } else { return tcsetattr(0, TCSANOW, &original_mode); fcnt1 (0, F_SETFL, orginal_flags); } }
set_nodelay_mode( ) { inttermflags; termflags= fcntl(0, F_GETFL); /* read current setting */ termflags |= O_NDELAY; /* flip on nodelay bit */ fcntl(0, F_SETFL, termflags); /* and install em */ } set_cr_noecho_mode( ) { structtermiosttystate; tcgetattr(0, &ttystate); /* read current settings */ ttystate.c_lflag &= ~ICANON; /* no buffering */ ttystate.c_lflag &= ~ECHO; /* no echo either */ ttystate.c_cc[VMIN] = 1; /* get 1 char at a time */ tcsetattr(0, TCSANOW, &ttystate); /* install settings */ }
Others methods to implement timeouts • What happens when Ctrl–C is pressed? $ make play_again3 cc play_again3.c -o play_again3 $ ./ play_again3 Do you want another transaction (y/n)? Press Ctrl-C now $ logout Connection to host closed bash$ • What is the problem of the sequence above? • Couldn’t restore ttys!
User-Program • Consider how the keystrokes are handle and output is processed. • Common concerns of user program(a) immediate response to keys(b) limited input set(c) timeout on input(d) resistance to Ctrl-C
Signals • What does Ctrl-C do?- Ctrl-C interrupts program It generates a signal ! • Signal is a kernel mechanism • Simple and powerful
What is signal ? • Signal : One-word message Ex) go, stop, out, green light • Each signal has a numerical code. • Interrupt signal is No. 2.
Where do signals come from? • User, Kernel, other process
List of signals /usr/include/signal.h
When a signal comes … • Process have 3 choices: • Accept- signal(SIGINT, SIG_DFL) • Ignore- signal(SIGINT, SIG_IGN) • Call a function
How to call a function signal(signum, functionname);