1 / 160

Chapter 13 Systems Programming

Graham Glass and King Ables, UNIX for Programmers and Users , Third Edition, Pearson Prentice Hall, 2003. Chapter 13 Systems Programming. Systems Programming. UNIX System calls: C functions that provide access to the file system, processes, and error handling.

Download Presentation

Chapter 13 Systems Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Graham Glass and King Ables, UNIX for Programmers and Users, Third Edition, Pearson Prentice Hall, 2003. Chapter 13Systems Programming

  2. Systems Programming • UNIX System calls: C functions that provide access to the file system, processes, and error handling. • System Calls grouped into 3 main categories: • File Management (Fig. 13.1) • Process Management (Fig. 13.2)‏ • Error Handling (Fig. 13.3)‏

  3. Error Handling • Most system calls are capable of failing in some way. • Example: open a file may fail because file does not exist! • System call returns a value of -1 when it fails. • This value does not tell much about the cause of the failure.

  4. Each process has a global variable errno that holds the numeric code of the last system-call error. (Initially, it 0). “/usr/include/sys/errno.h” #define EPERM 1 /*Operation not permitted*/ #define ENOENT 2 /*No such file or directory*/ #define EIO 5 /* I/O error */ #define EMFILE 24 /* Too many open files */ #include <errno.h> Error Handling: errno

  5. Error Handling • function perror() describes the system-call error • void perror(char* str) • /* standard C function in stdio.h */ • Displays str followed by a description of the last system call error. • Error 0 is displayed if no error • errno should be manually reset to 0 after system call failure!

  6. errno = 2 Main: No such file or directory errno = 21 main: Is a directory errno = 29 main: Illegal seek main: Success Error Handling: perror() #include <stdio.h> #include <fcntl.h> #include <errno.h> void main() { int fd; fd = open ("nonexist.txt", O_RDONLY); if(fd == -1) { printf ("errno = %d\n", errno); perror("main"); } fd = open ("/", O_WRONLY); if(fd == -1) { printf ("errno = %d\n", errno); perror("main"); } fd = open ("nonexist.txt", O_RDONLY | O_CREAT, 0644); printf ("errno = %d\n", errno); perror("main"); errno = 0; perror("main"); }

  7. Unix files are organized by hierarchy of labels commonly known as directory structure. Regular files: sequence of bytes that generally corresponds to code or data. Directory files: stored in a special format and form the backbone of the file system (directory-specific system calls). Special files correspond to peripherals, such as printers, disks, pipes and sockets. Unix File System

  8. File Management • System Calls: open, fcntl, read, write, lseek, unlink, close • Typical sequence: • open • read/write • close

  9. Typical File I/O Sequence • int fd; • /* file descriptor 0: std. in, 1: std. out, 2: std error*/ • fd = open(fileName,...); • if (fd == -1) /* deal with error */ • fcntl(fd,...) /* set IO flags if necessary */ • read(fd,...) /* read from file */ • write(fd,...) /* write to file */ • lseek(fd,...) /* seek within file */ • close(fd); /* close file, freeing file descriptor */

  10. File Descriptors • Each descriptor has its own private set of properties • file pointer (stores offset within file; changes on read/write/lseek)‏ • flag indicating if the file descriptor should be closed or not when process execs • flag indicating if output to file should be appended to end of file or not • A pipe or a socket have additional properties

  11. File Descriptors • Can open file several times (with different descriptors)‏ • System calls open() and fcntl() both allow you to manipulate these flags. fd1 File fd2 fd3

  12. Opening a File: open()‏ • int open(char* fileName, int mode[, int perm]) • allows you to open an existing file or create a new file for r/w • fileName: absolute or relative path name • mode: bitwise or-ing of a r/w flag together with zero or more miscellaneous flags (next slide)‏ • permissions: supplied only when file is created (ex. 0600 octal)‏

  13. Mode Flags • r/w flags: O_RDONLY, O_WRONLY, O_RDWR • misc. flags: • O_APPEND : position file pointer at the end of file before each write • O_CREAT : if the file does not exist, create it and set the owner ID = process' effective UID (uses umask value to set permissions) • O_EXCL : if O_CREAT is set and file exists then open() fails • O_NONBLOCK: for named pipes • O_TRUNC: if file exists it is truncated to length 0

  14. Create a File #include <stdio.h> #include <fcntl.h> #include <errno.h> void main() { int tmpfd; char tmpName[32]; sprintf(tmpName, ".rev.%d", getpid()); tmpfd = open (tmpName, O_CREAT | O_RDWR, 0600); if(tmpfd == -1) { printf ("errno = %d\n", errno); perror("main"); } printf("create a file %s\n", tmpName); } create a file .rev.4024

  15. #include<fcntl.h> #include<stdio.h> #include<stdlib.h> void main(int argc,char *argv[]) { if (argc>1) { int fd = open (argv[1], O_RDONLY); if (fd == -1) { perror ("reverse: "); exit (1); } else printf("File %s opened \n", argv[1]); } } Opening an Existing File [c33225@snowball ~]$ ./fopen nonexist reverse: : No such file or directory [c33225@snowball ~]$ ./fopen power.h File power.h opened

  16. int creat(char* fileName, mode_t perm) <sys/stat.h> S_IRUSR: owner read permit S_IWUSR: owner write permit S_IXUSR: owner execute permit S_IRGRP: group read permit S_IWGRP: group write permit S_IROTH: others read permit S_IWOTH: owners write permit S_IXOTH: others execute permit open(“myfile”, O_CREAT, S_IRUSR | S_IXOTH) CREATING A FILE: CREAT()

  17. Read from a regular file: read()‏ • size_t read(intfd, void* buf, size_t count) • copies uptocount bytes from the file referenced by fd into buffer buf • the bytes are read from current position (file pointer) which is then updated accordingly

  18. Read from a regular file: read()‏ • it returns number of bytes copied • returns 0 if it attempts to copy after end of file • returns -1 if unsuccessful • Example: • charsRead = read(fd, buffer, BUFFER_SIZE); • if (charsRead == 0) break; • if (charsRead == -1) fatalError();

  19. int charsRead; char buffer [4096]; while (1) { charsRead = read (fd, buffer, 4096); if (charsRead == 0) { printf("reach the end of the file.\n"); break; /* EOF */ } if (charsRead == -1) { perror ("reverse: "); exit (1); } } Read Example [c33225@snowball ~]$ ./fread power.h File power.h opened reach the end of the file. [c33225@snowball ~]$ ./fread nonexist reverse: : No such file or directory

  20. Write to a regular file: write()‏ • ssize_t write(int fd, void *buf, size_t count)‏ • Copies upto count bytes from a buffer buf into the file referenced by fd • The bytes are written into current position (file pointer) which is then updated accordingly • If O_APPEND was set, file pointer is set to end of file before each write

  21. Write to a regular file:write()‏ • It returns number of bytes copied • You should check this return value • returns -1 if unsuccessful

  22. int charsRead, charsWritten; char buffer [4096]; while (1) { charsRead = read (fd, buffer, 4096); if (charsRead == 0) break; /* EOF */ if (charsRead == -1) { perror ("reverse: "); exit (1);} charsWritten=write(out,buffer,charsRead); if (charsWritten!=charsRead){ perror ("reverse: "); exit (1);} } } Write Example

  23. Moving the file pointer:lseek()‏ • off_tlseek(intfd, off_t offset, int mode) • Changes current file position in the file referenced by fd. • mode describes how to interpret the offset.

  24. Moving the file pointer:lseek() modes • mode = SEEK_SET • offset relative to start of file • mode = SEEK_CUR • offset relative to current position of file • mode = SEEK_END • offset relative to end of file

  25. Moving the file pointer:lseek()‏ • lseek fails if moved before start of file • returns new file position if successful • returns -1 if unsuccessful

  26. Assume, fd is a file descriptor, lines[] is an array that holds starting positions of each line in the file. for (i = 0; i <10; i++) { int charsRead; char buffer [4096]; lseek (fd, lines[i], SEEK_SET); charsRead = read (fd, buffer, lines[i+1] - lines[i]); write (1, buffer, charsRead); }

  27. Current Offset of lseek • To find out current position use: • currentOffset = lseek(fd, 0, SEEK_CUR); • If you move past the end of file and write there, Unix automatically extends the size of the file and treats intermediate area as NULLS (0)‏ • Unix does not allocate disk area for intermediate space!! • (see next example)‏

  28. [c33235@snowball ~]$ cat sparse.txt Sparsefile [c33235@snowball ~]$ cat normal.txt normalfile

  29. Closing a file: close()‏ • int close(intfd) • Frees fd; releases resources • When a process terminates, all fds are automatically closed • Still it is a good idea to close yourself • Returns • 0 if success • -1 if failure

  30. Deleting a file: unlink()‏ • int unlink(const char* fileName) • Removes the hard link from the fileName to its file • If fileName is the last hard link, file resources are deallocated. • Example: • unlink(tmpName);‏

  31. Reverse Example (reverse.c)‏ • Starting page 440 • % reverse -c fileName • Reverses all lines in fileName • The -c option reverses each line; • If fileName is missing, standard input is used

  32. Reverse Example Algorithm • Step 1: Parse Command Line (parseCommandLine, processOptions) • System Calls used: none • Step 2: If reading from standard input, create temp. file to store input; otherwise open file for input (pass1) • System Calls used: open()‏

  33. Reverse Example Algorithm • Step 3: Read from file in chunks storing starting offsets of each line in an array. If reading from std. input, write each chunk into temp. file. (pass1, trackLines) • System Calls used: read(), write()‏ • Step 4: Read input file again, but backward, copying each line to std. output; reverse the line if -c option (pass2, processLine, reverseLine) • System Calls used: lseek()‏

  34. Reverse Example Algorithm • Step 5: Close file; remove it if temp. file; (pass2) • System Calls used: close(), unlink()‏

  35. Listing of reverse.c #include <fcntl.h> /* For file mode definitions */ #include <stdio.h> #include <stdlib.h> /* Enumerator */ enum { FALSE, TRUE }; /* Standard false and true values */ enum { STDIN, STDOUT, STDERR }; /* Standard I/O channel indices */ /* #define Statements */ #define BUFFER_SIZE 4096 /* Copy buffer size */ #define NAME_SIZE 12 #define MAX_LINES 100000 /* Max lines in file */

  36. Listing of reverse.c /* Function Prototypes */ void parseCommandLine (int argc, char* argv[]); void processOptions (char* str); void usageError (); void pass1 (); void trackLines (char* buffer, int charsRead); void pass2 (); void processLine (int i); void reverseLine (char* buffer, int size); void fatalError ();

  37. Listing of reverse.c /* Globals */ char *fileName = NULL; /* Points to file name */ char tmpName [NAME_SIZE]; int charOption = FALSE; /* Set to true if -c option is used */ int standardInput = FALSE; /* Set to true if reading stdin */ int lineCount = 0; /* Total number of lines in input */ int lineStart [MAX_LINES]; /* Store offsets of each line */ int fileOffset = 0; /* Current position in input */ int fd; /* File descriptor of input */ /*****************************************************/

  38. Listing of reverse.c int main (int argc, char* argv[]) { parseCommandLine (argc,argv); /* Parse cmd line */ pass1 (); /* Perform first pass through input */ pass2 (); /* Perform second pass through input */ return (/* EXITSUCCESS */ 0); /* Done */ } /*****************************************************/

  39. Function parseCommandLine void parseCommandLine (int argc, char* argv[]) { /* Parse command line arguments */ int i; for (i= 1; i < argc; i++) { if(argv[i][0] == '-')‏ processOptions (argv[i]); else if (fileName == NULL)‏ fileName= argv[i]; else usageError (); /* An error occurred */ } standardInput = (fileName == NULL); }

  40. Function processOptions void processOptions (char* str) { /* Parse options */ int j; for (j= 1; str[j] != NULL; j++) { switch(str[j]) /* Switch on command line flag */ { case 'c': charOption = TRUE; break; default: usageError (); break; } } }

  41. Function usageError void usageError () { fprintf (stderr, "Usage: reverse -c [filename]\n"); exit (/* EXITFAILURE */ 1); }

  42. Function pass1 void pass1 () { /* Perform first scan through file */ int tmpfd, charsRead, charsWritten; char buffer [BUFFER_SIZE]; if (standardInput) /* Read from standard input */ { fd = STDIN; sprintf (tmpName, ".rev.%d",getpid ()); /* Random name */ /* Create temporary file to store copy of input */ tmpfd = open (tmpName, O_CREAT | O_RDWR, 0600); if (tmpfd == -1) fatalError (); } else /* Open named file for reading */ { fd = open (fileName, O_RDONLY); if (fd == -1) fatalError (); } lineStart[0] = 0; /* Offset of first line */ }

  43. Function pass1 Continued while (TRUE) /* Read all input */ { /* Fill buffer */ charsRead = read (fd, buffer, BUFFER_SIZE); if (charsRead == 0) break; /* EOF */ if (charsRead == -1) fatalError (); /* Error */ trackLines (buffer, charsRead); /* Process line */ /* Copy line to temporary file if reading stdin */ if (standardInput) { charsWritten = write (tmpfd, buffer, charsRead); if(charsWritten != charsRead) fatalError (); } } /* Store offset of trailing line, if present */ lineStart[lineCount + 1] = fileOffset; /* If reading standard input, prepare fd for pass2 */ if (standardInput) fd = tmpfd; }

  44. Function trackLines void trackLines (char* buffer, int charsRead) { /* Store offsets of each line start in buffer */ int i; for (i = 0; i < charsRead; i++) { ++fileOffset; /* Update current file position */ if (buffer[i] == '\n') lineStart[++lineCount] = fileOffset; } }

  45. Function pass2 void pass2 () { /* Scan input file again, displaying lines in reverse order */ int i; for (i = lineCount - 1; i >= 0; i--)‏ processLine (i); close (fd); /* Close input file */ if (standardInput) unlink (tmpName); /* Remove temp file that we made*/ }

  46. Function processLine void processLine (int i) { /* Read a line and display it */ int charsRead; char buffer [BUFFER_SIZE]; /* Find the line and read it */ lseek (fd, lineStart[i], SEEK_SET); charsRead = read (fd, buffer, lineStart[i+1] - lineStart[i]); /* Reverse line if -c option was selected */ if (charOption) reverseLine (buffer, charsRead); /* Write it to standard output */ write (1, buffer, charsRead); }

  47. Function reverseLine void reverseLine (char* buffer, int size) { /* Reverse all the characters in the buffer */ int start = 0, end = size - 1; char tmp; /* Leave trailing newline */ if (buffer[end] == '\n') --end; /* Swap characters in a pairwise fashion */ while (start < end) { tmp = buffer[start]; buffer[start] = buffer[end]; buffer[end] = tmp; ++start; /* Increment start index */ --end; /* Decrement end index */ } }

  48. Function fatalError void fatalError () { perror ("reverse: "); /* Describe error */ exit (1); }

  49. [c33225@snowball reverse]$ cat > test Christmas is coming, The days that grow shorter, Remind me of seasons I knew in the past. [c33225@snowball reverse]$ ./reverse test Remind me of seasons I knew in the past. The days that grow shorter, Christmas is coming, [c33225@snowball reverse]$ ./reverse -c test .tsap eht ni wenk I snosaes fo em dnimeR ,retrohs worg taht syad ehT ,gnimoc si samtsirhC [c33225@snowball reverse]$ cat test | ./reverse Remind me of seasons I knew in the past. The days that grow shorter, Christmas is coming,

  50. [c33225@snowball reverse]$ ./reverse hello world hi there hi there hello world [c33225@snowball reverse]$ ./reverse -c hi there hello world dlrow olleh ereht ih

More Related