### 12.1 Definitions for OS interface

This is the complete set of system definitions (primarily subroutines) required; the examples shown implement the minimal functionality required to allow `libc` to link, and fail gracefully where OS services are not available.

Graceful failure is permitted by returning an error code. A minor complication arises here: the C library must be compatible with development environments that supply fully functional versions of these subroutines. Such environments usually return error codes in a global `errno`. However, the Red Hat newlib C library provides a macro definition for `errno` in the header file `errno.h`, as part of its support for reentrant routines (see Reentrancy).

The bridge between these two interpretations of `errno` is straightforward: the C library routines with OS interface calls capture the `errno` values returned globally, and record them in the appropriate field of the reentrancy structure (so that you can query them using the `errno` macro from `errno.h`).

This mechanism becomes visible when you write stub routines for OS interfaces. You must include `errno.h`, then disable the macro, like this:

    #include <errno.h>
    #undef errno
    extern int errno;

The examples in this chapter include this treatment of `errno`.

`_exit`

  Exit a program without cleaning up files. If your system doesn’t provide this, it is best to avoid linking with subroutines that require it (`exit`, `system`).

`close`

  Close a file. Minimal implementation:

      int close(int file) {
        return -1;
      }

`environ`

  A pointer to a list of environment variables and their values. For a minimal environment, this empty list is adequate:

      char *__env[1] = { 0 };
      char **environ = __env;

`execve`

  Transfer control to a new process. Minimal implementation (for a system without processes):

      #include <errno.h>
      #undef errno
      extern int errno;
      int execve(char *name, char **argv, char **env) {
        errno = ENOMEM;
        return -1;
      }

`fork`

  Create a new process. Minimal implementation (for a system without processes):

      #include <errno.h>
      #undef errno
      extern int errno;
      int fork(void) {
        errno = EAGAIN;
        return -1;
      }

`fstat`

  Status of an open file. For consistency with other minimal implementations in these examples, all files are regarded as character special devices. The `sys/stat.h` header file required is distributed in the `include` subdirectory for this C library.

      #include <sys/stat.h>
      int fstat(int file, struct stat *st) {
        st->st_mode = S_IFCHR;
        return 0;
      }

`getpid`

  Process-ID; this is sometimes used to generate strings unlikely to conflict with other processes. Minimal implementation, for a system without processes:

      int getpid(void) {
        return 1;
      }

`isatty`

  Query whether output stream is a terminal. For consistency with the other minimal implementations, which only support output to `stdout`, this minimal implementation is suggested:

      int isatty(int file) {
        return 1;
      }

`kill`

  Send a signal. Minimal implementation:

      #include <errno.h>
      #undef errno
      extern int errno;
      int kill(int pid, int sig) {
        errno = EINVAL;
        return -1;
      }

`link`

  Establish a new name for an existing file. Minimal implementation:

      #include <errno.h>
      #undef errno
      extern int errno;
      int link(char *old, char *new) {
        errno = EMLINK;
        return -1;
      }

`lseek`

  Set position in a file. Minimal implementation:

      int lseek(int file, int ptr, int dir) {
        return 0;
      }

`open`

  Open a file. Minimal implementation:

      int open(const char *name, int flags, int mode) {
        return -1;
      }

`read`

  Read from a file. Minimal implementation:

      int read(int file, char *ptr, int len) {
        return 0;
      }

`sbrk`

  Increase program data space. As `malloc` and related functions depend on this, it is useful to have a working implementation. The following suffices for a standalone system; it exploits the symbol `_end` automatically defined by the GNU linker.

      caddr_t sbrk(int incr) {
        extern char _end;		/* Defined by the linker */
        static char *heap_end;
        char *prev_heap_end;

        if (heap_end == 0) {
          heap_end = &_end;
        }
        prev_heap_end = heap_end;
        if (heap_end + incr > stack_ptr) {
          write (1, "Heap and stack collision\n", 25);
          abort ();
        }

        heap_end += incr;
        return (caddr_t) prev_heap_end;
      }

`stat`

  Status of a file (by name). Minimal implementation:

      int stat(char *file, struct stat *st) {
        st->st_mode = S_IFCHR;
        return 0;
      }

`times`

  Timing information for current process. Minimal implementation:

      int times(struct tms *buf) {
        return -1;
      }

`unlink`

  Remove a file’s directory entry. Minimal implementation:

      #include <errno.h>
      #undef errno
      extern int errno;
      int unlink(char *name) {
        errno = ENOENT;
        return -1;
      }

`wait`

  Wait for a child process. Minimal implementation:

      #include <errno.h>
      #undef errno
      extern int errno;
      int wait(int *status) {
        errno = ECHILD;
        return -1;
      }

`write`

  Write to a file. `libc` subroutines will use this system routine for output to all files, including `stdout`—so if you need to generate any output, for example to a serial port for debugging, you should make your minimal `write` capable of doing this. The following minimal implementation is an incomplete example; it relies on a `outbyte` subroutine (not shown; typically, you must write this in assembler from examples provided by your hardware manufacturer) to actually perform the output.

      int write(int file, char *ptr, int len) {
        int todo;

        for (todo = 0; todo < len; todo++) {
          outbyte (*ptr++);
        }
        return len;
      }