The C-Unix Interface

[follow external pointer to pipes ]

Overview
This summary is largely extracted from "C through UNIX", K. E. Martin, 1992, W.C.Brown Publishers, and Chapter 10 of Glass.

  1. We have already seen the compiler cc with its options (including -g and - p), the debugger dbx and the lint and make packages, as well as a few other utilities for compiling and analyzing C programs.
  2. A more interesting question is the use of UNIX commands as _parts_ of C programs, which we explore here. It is now time to expand upon the various tools that can be used in the construction of a C program.
  3. These fall into three categories:
  4. Note that the converse is also true. Compiled C programs can be used as commands in a shell script or mixed with UNIX commands and operators on the command line.
UNIX C functions in the manual
Interfaces with the UNIX system
Handling errors
    1. errno is a global variable which specifies the return error code of a function call (remember that 0 means successful completion; -1 is more-or-less _program_error_; and the other codes indicate states of the file system or environment).
    2. To use errno, it should be declared with
                  extern int errno;
    1. After this declaration, a statement like the following will print its integer value.
                  printf("%d\n",errno);
    1. By adding the following to the header, one can access the symbolic error code (e.g., EROFS for attempting to write a read-only file), and use that in tests (on loops and conditionals), although printing will still print only the integer value.
                  #include< errno.h> 
    1. By also using the following library function, one can have an error message, prefixed by _s_ (typically the name of the function causing the error, or in which the call was made, or the line number).
                  void perror (char *s);
    1. The error message is located in an array
                  extern char *sys_errlist [];
    1. Note that if perror is used, errno does not need to be declared, and errno.h does not need to be included.
File manipulation
    1. access can determine whether a given file/directory exists, or can be read, executed (searched in case of a directory), or written by the program. The syntax is
                  int access (char * path; int amode);
                  chmod (myfile,00755);
                  FILE *popen (char *command; char *type);
Multiprocessing
    1. The UNIX C command system causes a subshell to be created in which the command argument to system is executed (during which ordinarily the program sleeps).
    2. The command execl (one of the exec commands --- see Glass, p 416) also takes a command, but also a list of arguments, but is equivalent to a return from main followed by execution of the command.
    3. Multiprocessing in C is enabled by the fork command, which takes no arguments.
      • The process which called fork is the _parent_, and the new process is its _child_.
      • fork returns a new process id to the parent, and 0 to the child.
      • getpid always returns the process id of the current process, getppid returns the process id of the parent (or 1 if the current process is the root process).
      • Nominally, the parent and the child run the same process, but in most applications subsequent commands use the return value, or the value obtained by getpid, to differentiate and have the two processes run different code, or use variants of exec to cause the child to execute another process instead.
      • Synchronization with children can be enforced through the wait command. The parent can kill the child using the kill command:
                     int kill (int pid; int sig); 
System information
C programs can use functional variants of command-line UNIX commands to determine system information; these can be used, among other purposes, to initialize random number generators.

                 char *getname (char *variable);
                 char *getlogin ();
                 long time ((long *) 0);    
                      /* “long” is an integer type             */
                      /* with more significant bits than “int” */
                 long time (long *tloc);
                 char *ctime (long *clock);
                 int stat (char *filename, struct stat *buffer);
                 int fstat (int file_id, struct stat *buffer);
                 int getdents (int file_id, struct direct * buf, 
                               int structSize);
                 int mknod (char *fileName, int type, int device)
Pipes and sockets
  1. There are two types of pipes: named and unnamed pipes.
  2. Unnamed pipes
                  int pipe (int fd [2]);