Next: Reentrant Syscalls, Up: Syscalls

### 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;
                }