Book Image

Linux System Programming Techniques

By : Jack-Benny Persson
Book Image

Linux System Programming Techniques

By: Jack-Benny Persson

Overview of this book

Linux is the world's most popular open source operating system (OS). Linux System Programming Techniques will enable you to extend the Linux OS with your own system programs and communicate with other programs on the system. The book begins by exploring the Linux filesystem, its basic commands, built-in manual pages, the GNU compiler collection (GCC), and Linux system calls. You'll then discover how to handle errors in your programs and will learn to catch errors and print relevant information about them. The book takes you through multiple recipes on how to read and write files on the system, using both streams and file descriptors. As you advance, you'll delve into forking, creating zombie processes, and daemons, along with recipes on how to handle daemons using systemd. After this, you'll find out how to create shared libraries and start exploring different types of interprocess communication (IPC). In the later chapters, recipes on how to write programs using POSIX threads and how to debug your programs using the GNU debugger (GDB) and Valgrind will also be covered. By the end of this Linux book, you will be able to develop your own system programs for Linux, including daemons, tools, clients, and filters.
Table of Contents (14 chapters)

Reading environment variables

Another way to communicate with the shell—and to configure a program—is via environment variables. By default, there are a lot of environment variables already set. These variables contain information on just about anything regarding your user and your settings. Some examples include the username, which type of terminal you are using, the path variable we discussed in previous recipes, your preferred editor, your preferred locale and language, and more.

Knowing how to read these variables will make it much easier for you to adapt your programs to the user's environment.

In this recipe, we will write a program that reads environment variables, adapts its output, and prints some information about the user and the session.

Getting ready

For this recipe, we can use just about any shell. Other than a shell, we'll need the GCC compiler.

How to do it…

Follow these steps to write a program that reads environment variables:

  1. Save the following code into a file called env-var.c. You can also download the whole program from https://github.com/PacktPublishing/Linux-System-Programming-Techniques/blob/master/ch2/env-var.c. This program will read some common environment variables from your shell using the getenv() function. The strange-looking number sequences (\033[0;31) are used to color the output:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    int main(void)
    {
       /* Using getenv() to fetch env. variables */
       printf("Your username is %s\n", getenv("USER"));
       printf("Your home directory is %s\n", 
          getenv("HOME"));
       printf("Your preferred editor is %s\n", 
          getenv("EDITOR"));
       printf("Your shell is %s\n", getenv("SHELL"));
       /* Check if the current terminal support colors*/
       if ( strstr(getenv("TERM"), "256color")  )
       {
          /* Color the output with \033 + colorcode */
          printf("\033[0;31mYour \033[0;32mterminal "
             "\033[0;35msupport "
             "\033[0;33mcolors\033[0m\n");
       }
       else
       {
          printf("Your terminal doesn't support" 
             " colors\n");
       }
       return 0;
    }
  2. Compile the program using GCC:
    $> gcc env-var.c -o env-var
  3. Run the program. The information that will be printed for you will differ from mine. The last line will also be in color if your terminal supports it. If it doesn't, it will tell you that your terminal doesn't support colors:
    $> ./env-var 
    Your username is jake
    Your home directory is /home/jake
    Your preferred editor is vim
    Your shell is /bin/bash
    Your terminal support colors
  4. Let's investigate the environment variables we used by using echo. Make a note of the $TERM variable. The dollar sign ($) tells the shell that we want to print the TERM variable, not the word TERM:
    $> echo $USER
    jake
    $> echo $HOME
    /home/jake
    $> echo $EDITOR
    vim
    $> echo $SHELL
    /bin/bash
    $> echo $TERM
    screen-256color
  5. If we were to change the $TERM variable to a regular xterm, without color support, we would get a different output from the program:
    $> export TERM=xterm
    $> ./env-var 
    Your username is jake
    Your home directory is /home/jake
    Your preferred editor is vim
    Your shell is /bin/bash
    Your terminal doesn't support colors
  6. Before moving on, we should reset our terminal to the value it was before we changed it. This will probably be something else on your computer:
    $> export TERM=screen-256color
  7. It's also possible to set an environment variable temporarily for the duration of the program. We can do this by setting the variable and executing the program on the same line. Notice that when the program ends, the variable is still the same as it was previously. We just override the variable when the program executes:
    $> echo $TERM
    xterm-256color
    $> TERM=xterm ./env-var
    Your username is jake
    Your home directory is /home/jake
    Your preferred editor is vim
    Your shell is /bin/bash
    Your terminal doesn't support colors
    $> echo $TERM
    xterm-256colo
  8. We can also print a complete list of all the environment variables using the env command. The list will probably be several pages long. All of these variables can be accessed using the getenv() C function:
    $> env

How it works…

We use the getenv() function to get the values from the shell's environment variables. We print these variables to the screen.

Then, at the end of the program, we check if the current terminal has color support. This is usually denoted by something such as xterm-256color, screen-256color, and so on. We then use the strstr() function (from string.h) to check if the $TERM variable contains the 256color substring. If it does, the terminal has color support, and we print a colorized message on the screen. If it doesn't, however, we print that the terminal doesn't have color support, without using any colors.

All of these variables are the shell's environment variables and can be printed with the echo command; for example, echo $TERM. We can also set our own environment variables in the shell; for instance, export FULLNAME=Jack-Benny. Likewise, we can change existing ones by overwriting them, just as we did with the $TERM variable. We can also override them by setting them at runtime, like we did with TERM=xterm ./env-var.

Regular variables set with the FULLNAME=Jack-Benny syntax are only available to the current shell and are hence called local variables. When we set variables using the export command, they become global variables or environment variables, a more common name, available to both subshells and child processes.

There's more…

We can also change environment variables and create new ones in a C program by using the setenv() function. However, when we do so, those variables won't be available in the shell that started the program. The program we run is a child process of the shell, and hence it can't change the shell's variable; that is, its parent process. But any other programs started from inside our own program will be able to see those variables. We will discuss parent and child processes in more depth later in this book.

Here is a short example of how to use setenv(). The 1 in the third argument to setenv() means that we want to overwrite the variable if it already exists. If we change it to a 0, it prevents overwriting:

env-var-set.c

#define _POSIX_C_SOURCE 200112L
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    setenv("FULLNAME", "Jack-Benny", 1);
    printf("Your full name is %s\n", getenv("FULLNAME"));
    return 0;
}

If we compile and run the program and then try to read $FULLNAME from the shell, we'll notice that it doesn't exist:

$> gcc env-var-set.c -o env-var-set
$> ./env-var-set 
Your full name is Jack-Benny
$> echo $FULLNAME