diff --git a/chapter_8.unix_interface/8_2.fopen_fields/Makefile b/chapter_8.unix_interface/8_2.fopen_fields/Makefile
new file mode 100644
index 0000000..e407b12
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/Makefile
@@ -0,0 +1,3 @@
+BINARY=fopen_fields
+
+include ../../Exercise.mk
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/knr_io.c b/chapter_8.unix_interface/8_2.fopen_fields/knr_io.c
new file mode 100644
index 0000000..b0f63e5
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/knr_io.c
@@ -0,0 +1,86 @@
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <fcntl.h>
+# include "knr_io.h"
+
+KNR_FILE knr_iob[KNR_OPEN_MAX] = {    /* stdin, stdout, stderr */
+  { 0, (char *) 0, (char *) 0, 0, 1, 0, 0, 0, 0 },
+  { 0, (char *) 0, (char *) 0, 1, 0, 1, 0, 0, 0 },
+  { 0, (char *) 0, (char *) 0, 2, 0, 1, 1, 0, 0 }
+};
+
+/* knr_fopen:  open file, return KNR_FILE* on success, KNR_NULL on error */
+KNR_FILE *knr_fopen (char *name, char *mode)
+{
+  int fd;
+  KNR_FILE *fp;
+
+  if (*mode != 'r' && *mode != 'w' && *mode != 'a')
+    return KNR_NULL;
+  for (fp = knr_iob; fp < knr_iob + KNR_OPEN_MAX; fp++)
+    if (fp->f_read == 0 && fp->f_write == 0)
+      break;              /* found free slot */
+  if (fp >= knr_iob + KNR_OPEN_MAX)   /* no free slots */
+    return KNR_NULL;
+
+  if (*mode == 'w')
+    fd = creat(name, KNR_PERMS);
+  else if (*mode == 'a') {
+    if ((fd = open(name, O_WRONLY, 0)) == -1)
+      fd = creat(name, KNR_PERMS);
+    lseek(fd, 0L, 2);
+  } else
+    fd = open(name, O_RDONLY, 0);
+  if (fd == -1)           /* couldn't access name */
+    return KNR_NULL;
+  fp->fd = fd;
+  fp->cnt = 0;
+  fp->base = KNR_NULL;
+  if (*mode == 'r')
+    fp->f_read = 1;
+  else
+    fp->f_write = 1;
+  return fp;
+}
+
+/* knr_fillbuf:  allocate and fill input buffer */
+int knr_fillbuf (KNR_FILE *fp)
+{
+  int bufsize;
+
+  if (fp->f_read == 0 || fp->f_eof == 1 || fp->f_err == 1)
+    return KNR_EOF;
+  bufsize = fp->f_unbuf==1 ? 1 : KNR_BUFSIZ;
+  if (fp->base == KNR_NULL)         /* no buffer yet */
+    if ((fp->base = (char*) malloc(bufsize)) == NULL)
+      return KNR_EOF;                   /* can't get buffer */
+  fp->ptr = fp->base;
+  fp->cnt = read(fp->fd, fp->ptr, bufsize);
+  if (--fp->cnt < 0) {
+    if (fp->cnt == -1)
+      fp->f_eof = 1;
+    else
+      fp->f_err = 1;
+    fp->cnt = 0;
+    return KNR_EOF;
+  }
+  return (unsigned char) *fp->ptr++;
+}
+
+/* knr_flushbuf:  flush buffer (TODO LATER) */
+int knr_flushbuf (int, KNR_FILE *)
+{
+  return 0;
+}
+
+/* knr_fclose:  close a stream, return 0 on success, KNR_EOF on error */
+int knr_fclose (KNR_FILE *fp)
+{
+  int r;
+  
+  if ((r = close(fp->fd)) == -1)
+    return KNR_EOF;
+  fp->f_read = fp->f_write = fp->f_unbuf = fp->f_eof = fp->f_err = 0;
+  return 0;
+}
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/knr_io.h b/chapter_8.unix_interface/8_2.fopen_fields/knr_io.h
new file mode 100644
index 0000000..7af0e82
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/knr_io.h
@@ -0,0 +1,47 @@
+# ifndef KNR_IO_H
+# define KNR_IO_H
+
+# define KNR_PERMS 0666 /* RW for owner, group, others */
+
+# define KNR_NULL     0
+# define KNR_EOF      (-1)
+# define KNR_BUFSIZ   1024
+# define KNR_OPEN_MAX 20 /* max #files open at once */
+
+typedef struct knr_iobuf {
+  int   cnt;   /* characters left */
+  char *ptr;   /* next character position */
+  char *base;  /* location of buffer */
+  int   fd;    /* file descriptor */
+  /* mode of file access: */
+  int   f_read;  /* file open for reading */   
+  int   f_write; /* file open for writing */
+  int   f_unbuf; /* file is unbuffered */
+  int   f_eof;   /* EOF has occurred on this file */
+  int   f_err;   /* error occurred on this file */
+} KNR_FILE;
+extern KNR_FILE knr_iob[KNR_OPEN_MAX];
+
+# define knr_stdin   (&knr_iob[0])
+# define knr_stdout  (&knr_iob[1])
+# define knr_stderr  (&knr_iob[2])
+
+/* knr_fopen:  open file, return KNR_FILE* on success, KNR_NULL on error */
+KNR_FILE *knr_fopen (char *name, char *mode);
+/* knr_fillbuf:  allocate and fill input buffer */
+int knr_fillbuf (KNR_FILE *fp);
+/* knr_flushbuf:  flush buffer */
+int knr_flushbuf (int, KNR_FILE *);
+/* knr_fclose:  close a stream, return 0 on success, KNR_EOF on error */
+int knr_fclose (KNR_FILE *fp);
+
+# define knr_feof(p)    ((p)->flag & KNR_EOF) != 0)
+# define knr_ferror(p)  ((p)->flag & KNR_ERR) != 0)
+# define knr_fileno(p)  ((p)->fd)
+
+# define knr_getc(p)    (--(p)->cnt >= 0 ? (unsigned char) *(p)->ptr++ : knr_fillbuf(p))
+# define knr_putc(x,p)  (--(p)->cnt >= 0 ? *(p)->ptr++ = (x)           : knr_flushbuf((x),p))
+# define knr_getchar()  knr_getc(knr_stdin)
+# define knr_putchar(x) knr_putc((x), knr_stdout)
+
+# endif
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/main.c b/chapter_8.unix_interface/8_2.fopen_fields/main.c
new file mode 100644
index 0000000..0eb05c7
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/main.c
@@ -0,0 +1,24 @@
+# include <stdio.h>
+# include <error.h>
+# include "knr_io.h"
+
+
+int main (int argc, char *argv[])
+{
+  KNR_FILE *fp;
+  int c;
+  
+  if (argc == 1)
+    printf("Usage: %s <file1> <...fileN>\n", argv[0]);
+  else
+    while (--argc > 0) {
+      if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL)
+        error(1, 0, "Can't open file %s.", *argv);
+      while ((c = knr_getc(fp)) != KNR_EOF)
+        putchar(c);
+      if (knr_fclose(fp) != 0)
+        error(2, 0, "Can't close file %s.", *argv);
+    }
+
+  return 0;
+}
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/0_usage_info.tin b/chapter_8.unix_interface/8_2.fopen_fields/tests/0_usage_info.tin
new file mode 100644
index 0000000..e69de29
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/0_usage_info.tout b/chapter_8.unix_interface/8_2.fopen_fields/tests/0_usage_info.tout
new file mode 100644
index 0000000..d984692
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/0_usage_info.tout
@@ -0,0 +1 @@
+Usage: ./fopen_fields <file1> <...fileN>
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.targs b/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.targs
new file mode 100644
index 0000000..c4414a8
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.targs
@@ -0,0 +1 @@
+no_such_file.txt
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.terr b/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.terr
new file mode 100644
index 0000000..2bf23e9
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.terr
@@ -0,0 +1 @@
+./fopen_fields: Can't open file no_such_file.txt.
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.tin b/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.tin
new file mode 100644
index 0000000..e69de29
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.tout b/chapter_8.unix_interface/8_2.fopen_fields/tests/1_err_file_open.tout
new file mode 100644
index 0000000..e69de29
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/2_file.c b/chapter_8.unix_interface/8_2.fopen_fields/tests/2_file.c
new file mode 100644
index 0000000..0eb05c7
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/2_file.c
@@ -0,0 +1,24 @@
+# include <stdio.h>
+# include <error.h>
+# include "knr_io.h"
+
+
+int main (int argc, char *argv[])
+{
+  KNR_FILE *fp;
+  int c;
+  
+  if (argc == 1)
+    printf("Usage: %s <file1> <...fileN>\n", argv[0]);
+  else
+    while (--argc > 0) {
+      if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL)
+        error(1, 0, "Can't open file %s.", *argv);
+      while ((c = knr_getc(fp)) != KNR_EOF)
+        putchar(c);
+      if (knr_fclose(fp) != 0)
+        error(2, 0, "Can't close file %s.", *argv);
+    }
+
+  return 0;
+}
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/2_one.targs b/chapter_8.unix_interface/8_2.fopen_fields/tests/2_one.targs
new file mode 100644
index 0000000..edff2ec
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/2_one.targs
@@ -0,0 +1 @@
+tests/2_file.c
\ No newline at end of file
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/2_one.tin b/chapter_8.unix_interface/8_2.fopen_fields/tests/2_one.tin
new file mode 100644
index 0000000..e69de29
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/2_one.tout b/chapter_8.unix_interface/8_2.fopen_fields/tests/2_one.tout
new file mode 100644
index 0000000..0eb05c7
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/2_one.tout
@@ -0,0 +1,24 @@
+# include <stdio.h>
+# include <error.h>
+# include "knr_io.h"
+
+
+int main (int argc, char *argv[])
+{
+  KNR_FILE *fp;
+  int c;
+  
+  if (argc == 1)
+    printf("Usage: %s <file1> <...fileN>\n", argv[0]);
+  else
+    while (--argc > 0) {
+      if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL)
+        error(1, 0, "Can't open file %s.", *argv);
+      while ((c = knr_getc(fp)) != KNR_EOF)
+        putchar(c);
+      if (knr_fclose(fp) != 0)
+        error(2, 0, "Can't close file %s.", *argv);
+    }
+
+  return 0;
+}
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/3_file0.c b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_file0.c
new file mode 100644
index 0000000..0eb05c7
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_file0.c
@@ -0,0 +1,24 @@
+# include <stdio.h>
+# include <error.h>
+# include "knr_io.h"
+
+
+int main (int argc, char *argv[])
+{
+  KNR_FILE *fp;
+  int c;
+  
+  if (argc == 1)
+    printf("Usage: %s <file1> <...fileN>\n", argv[0]);
+  else
+    while (--argc > 0) {
+      if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL)
+        error(1, 0, "Can't open file %s.", *argv);
+      while ((c = knr_getc(fp)) != KNR_EOF)
+        putchar(c);
+      if (knr_fclose(fp) != 0)
+        error(2, 0, "Can't close file %s.", *argv);
+    }
+
+  return 0;
+}
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/3_file1.c b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_file1.c
new file mode 100644
index 0000000..b0f63e5
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_file1.c
@@ -0,0 +1,86 @@
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <fcntl.h>
+# include "knr_io.h"
+
+KNR_FILE knr_iob[KNR_OPEN_MAX] = {    /* stdin, stdout, stderr */
+  { 0, (char *) 0, (char *) 0, 0, 1, 0, 0, 0, 0 },
+  { 0, (char *) 0, (char *) 0, 1, 0, 1, 0, 0, 0 },
+  { 0, (char *) 0, (char *) 0, 2, 0, 1, 1, 0, 0 }
+};
+
+/* knr_fopen:  open file, return KNR_FILE* on success, KNR_NULL on error */
+KNR_FILE *knr_fopen (char *name, char *mode)
+{
+  int fd;
+  KNR_FILE *fp;
+
+  if (*mode != 'r' && *mode != 'w' && *mode != 'a')
+    return KNR_NULL;
+  for (fp = knr_iob; fp < knr_iob + KNR_OPEN_MAX; fp++)
+    if (fp->f_read == 0 && fp->f_write == 0)
+      break;              /* found free slot */
+  if (fp >= knr_iob + KNR_OPEN_MAX)   /* no free slots */
+    return KNR_NULL;
+
+  if (*mode == 'w')
+    fd = creat(name, KNR_PERMS);
+  else if (*mode == 'a') {
+    if ((fd = open(name, O_WRONLY, 0)) == -1)
+      fd = creat(name, KNR_PERMS);
+    lseek(fd, 0L, 2);
+  } else
+    fd = open(name, O_RDONLY, 0);
+  if (fd == -1)           /* couldn't access name */
+    return KNR_NULL;
+  fp->fd = fd;
+  fp->cnt = 0;
+  fp->base = KNR_NULL;
+  if (*mode == 'r')
+    fp->f_read = 1;
+  else
+    fp->f_write = 1;
+  return fp;
+}
+
+/* knr_fillbuf:  allocate and fill input buffer */
+int knr_fillbuf (KNR_FILE *fp)
+{
+  int bufsize;
+
+  if (fp->f_read == 0 || fp->f_eof == 1 || fp->f_err == 1)
+    return KNR_EOF;
+  bufsize = fp->f_unbuf==1 ? 1 : KNR_BUFSIZ;
+  if (fp->base == KNR_NULL)         /* no buffer yet */
+    if ((fp->base = (char*) malloc(bufsize)) == NULL)
+      return KNR_EOF;                   /* can't get buffer */
+  fp->ptr = fp->base;
+  fp->cnt = read(fp->fd, fp->ptr, bufsize);
+  if (--fp->cnt < 0) {
+    if (fp->cnt == -1)
+      fp->f_eof = 1;
+    else
+      fp->f_err = 1;
+    fp->cnt = 0;
+    return KNR_EOF;
+  }
+  return (unsigned char) *fp->ptr++;
+}
+
+/* knr_flushbuf:  flush buffer (TODO LATER) */
+int knr_flushbuf (int, KNR_FILE *)
+{
+  return 0;
+}
+
+/* knr_fclose:  close a stream, return 0 on success, KNR_EOF on error */
+int knr_fclose (KNR_FILE *fp)
+{
+  int r;
+  
+  if ((r = close(fp->fd)) == -1)
+    return KNR_EOF;
+  fp->f_read = fp->f_write = fp->f_unbuf = fp->f_eof = fp->f_err = 0;
+  return 0;
+}
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/3_file2.mk b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_file2.mk
new file mode 100644
index 0000000..e407b12
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_file2.mk
@@ -0,0 +1,3 @@
+BINARY=fopen_fields
+
+include ../../Exercise.mk
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/3_many.targs b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_many.targs
new file mode 100644
index 0000000..a97ba8f
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_many.targs
@@ -0,0 +1 @@
+tests/3_file0.c tests/3_file1.c tests/3_file2.mk
\ No newline at end of file
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/3_many.tin b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_many.tin
new file mode 100644
index 0000000..e69de29
diff --git a/chapter_8.unix_interface/8_2.fopen_fields/tests/3_many.tout b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_many.tout
new file mode 100644
index 0000000..c7158b5
--- /dev/null
+++ b/chapter_8.unix_interface/8_2.fopen_fields/tests/3_many.tout
@@ -0,0 +1,113 @@
+# include <stdio.h>
+# include <error.h>
+# include "knr_io.h"
+
+
+int main (int argc, char *argv[])
+{
+  KNR_FILE *fp;
+  int c;
+  
+  if (argc == 1)
+    printf("Usage: %s <file1> <...fileN>\n", argv[0]);
+  else
+    while (--argc > 0) {
+      if ((fp = knr_fopen(*++argv, "r")) == KNR_NULL)
+        error(1, 0, "Can't open file %s.", *argv);
+      while ((c = knr_getc(fp)) != KNR_EOF)
+        putchar(c);
+      if (knr_fclose(fp) != 0)
+        error(2, 0, "Can't close file %s.", *argv);
+    }
+
+  return 0;
+}
+# include <stdio.h>
+# include <stdlib.h>
+# include <unistd.h>
+# include <fcntl.h>
+# include "knr_io.h"
+
+KNR_FILE knr_iob[KNR_OPEN_MAX] = {    /* stdin, stdout, stderr */
+  { 0, (char *) 0, (char *) 0, 0, 1, 0, 0, 0, 0 },
+  { 0, (char *) 0, (char *) 0, 1, 0, 1, 0, 0, 0 },
+  { 0, (char *) 0, (char *) 0, 2, 0, 1, 1, 0, 0 }
+};
+
+/* knr_fopen:  open file, return KNR_FILE* on success, KNR_NULL on error */
+KNR_FILE *knr_fopen (char *name, char *mode)
+{
+  int fd;
+  KNR_FILE *fp;
+
+  if (*mode != 'r' && *mode != 'w' && *mode != 'a')
+    return KNR_NULL;
+  for (fp = knr_iob; fp < knr_iob + KNR_OPEN_MAX; fp++)
+    if (fp->f_read == 0 && fp->f_write == 0)
+      break;              /* found free slot */
+  if (fp >= knr_iob + KNR_OPEN_MAX)   /* no free slots */
+    return KNR_NULL;
+
+  if (*mode == 'w')
+    fd = creat(name, KNR_PERMS);
+  else if (*mode == 'a') {
+    if ((fd = open(name, O_WRONLY, 0)) == -1)
+      fd = creat(name, KNR_PERMS);
+    lseek(fd, 0L, 2);
+  } else
+    fd = open(name, O_RDONLY, 0);
+  if (fd == -1)           /* couldn't access name */
+    return KNR_NULL;
+  fp->fd = fd;
+  fp->cnt = 0;
+  fp->base = KNR_NULL;
+  if (*mode == 'r')
+    fp->f_read = 1;
+  else
+    fp->f_write = 1;
+  return fp;
+}
+
+/* knr_fillbuf:  allocate and fill input buffer */
+int knr_fillbuf (KNR_FILE *fp)
+{
+  int bufsize;
+
+  if (fp->f_read == 0 || fp->f_eof == 1 || fp->f_err == 1)
+    return KNR_EOF;
+  bufsize = fp->f_unbuf==1 ? 1 : KNR_BUFSIZ;
+  if (fp->base == KNR_NULL)         /* no buffer yet */
+    if ((fp->base = (char*) malloc(bufsize)) == NULL)
+      return KNR_EOF;                   /* can't get buffer */
+  fp->ptr = fp->base;
+  fp->cnt = read(fp->fd, fp->ptr, bufsize);
+  if (--fp->cnt < 0) {
+    if (fp->cnt == -1)
+      fp->f_eof = 1;
+    else
+      fp->f_err = 1;
+    fp->cnt = 0;
+    return KNR_EOF;
+  }
+  return (unsigned char) *fp->ptr++;
+}
+
+/* knr_flushbuf:  flush buffer (TODO LATER) */
+int knr_flushbuf (int, KNR_FILE *)
+{
+  return 0;
+}
+
+/* knr_fclose:  close a stream, return 0 on success, KNR_EOF on error */
+int knr_fclose (KNR_FILE *fp)
+{
+  int r;
+  
+  if ((r = close(fp->fd)) == -1)
+    return KNR_EOF;
+  fp->f_read = fp->f_write = fp->f_unbuf = fp->f_eof = fp->f_err = 0;
+  return 0;
+}
+BINARY=fopen_fields
+
+include ../../Exercise.mk