Named Pipes in Linux C

The mkfifo() function is used to create a named piped in the filesystem. The pipe() system call creates an anonymous pipe that can only be used by related processes. A named pipe, in contrast, can be used by any process, since the pipes are visible in the filesystem.

The mkfifo() call takes two arguments, the first being the pathname of the named pipe that we wish to create, and the second represents the read/write permissions for this pipe. The mkfifo() call returns 0 on success or -1 on error.

#include <stdio.h>
#include <sys/stat.h>

int main(void){

    //read, write, execute permissions for owner.
    printf("S_IRWXU = %d\n", S_IRWXU);

    int returnValue;

    //should return 0, if we are running this program
    //for the first time.
    returnValue = mkfifo("FIFOpipe", S_IRWXU);

    printf("The mkfifo() call returned %d\n", returnValue);

    return 0;


}

If we run this program twice (or more) the return value will be -1, as the named pipe will have already been created. We can see the error mkfifo() has encountered via errno, which is defined in the errno.h header file.

#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>

int main(void){

    mode_t theMode = S_IRWXU;

    int returnValue = mkfifo("FIFOpipe", theMode);

    if(returnValue < 0){
        printf("mkfifo() failed.\n");
        printf("errno = %d\n", errno);
        if(errno==EEXIST){
            printf("That file already exists.\n");
            printf("(or we passed in a symbolic link, which we did not.)\n");
        }
    }

    return 0;

}

The mode_t permissions are delineated in the sys/stat.h header file.

To remove a FIFO, we can use the unlink() function which is included in the unistd.h header file.

#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
//note: unistd.h included
//so we can call unlink() to delete the FIFO

int main(void){

    //S_IRWXU is the same value as 
    //'OR'-ing S_IRUSR, S_IWUSR, S_IXUSR
    //(i.e. all permissions for file creator)
    mode_t theMode = S_IRWXU;
    int returnValue;

    printf("S_IRUSR = %d\n", S_IRUSR);
    printf("S_IWUSR = %d\n", S_IWUSR);
    printf("S_IXUSR = %d\n", S_IXUSR);

    printf("S_IRUSR | S_IWUSR | S_IXUSR = %d\n", S_IRUSR | S_IWUSR | S_IXUSR);
    printf("S_IRWXU = %d\n", S_IRWXU);

    returnValue = mkfifo("AnotherPipe", S_IRWXU);
    if(returnValue==0){
        printf("FIFO created successfully.\n");
        printf("Now let's delete it!\n");
        returnValue = unlink("AnotherPipe");
        if(returnValue==0){
            printf("FIFO deleted.\n");
        }
    }


    return 0;
}

Once a named pipe has been created, we can read and write to it just as with any other file.

Advertisements

Review of Arrays in C

An array is a set number of data items that are all of the same type. Each of these data items is referred to as an element. There are a fixed number of elements in the array, and each element is of the same type, this is as opposed to a structure, which can contain data members of differing types.

We declare an array by placing the type name, followed by the name of the array, and then a number place in brackets. The number indicates the size of the array.

#include <stdio.h>

int main(void){

    long lNums[10];
    char chChars[10];

    printf("a char is %lu byte.\n", sizeof(char));
    printf("our char array is %lu bytes in size.\n", sizeof(chChars));
    printf("there are %lu elements in the chChars array.\n", sizeof(chChars) / sizeof(char));

    printf("a long int is %lu bytes.\n", sizeof(long));
    printf("our long array is %lu bytes in size.\n", sizeof(lNums));
    printf("our long array has %lu elementsin.\n", sizeof(lNums) / sizeof(long));
    return 0;
}

The number in the fixed brackets is called the dimension, it specifies the number of elements we want to store in the array. Each element in the array is accessed by the same name, the name of the array, in addition to the array element’s number.  This number is what is known as an index value. An index value is an integer placed in the square brackets after the array name.

It’s very important to remember that array elements are indexed from 0, not 1. That means the first element is at offset 0, the second element is at offset 1, etc. This is actually conceptually clearer in pointer notation than in array index notation, but array notation is way less of a pain to use, especially when working with multidimensional arrays.

#include <stdio.h>

int main(void){

    int iArray[5];

    iArray[0] = 8;
    iArray[1] = 16;
    iArray[2] = 32;
    iArray[3] = 64;
    iArray[4] = 128;
    //no more elements left! we've used
    //them all up.
    //let's print them out
    
    int *iPtrArray = iArray;
    printf("%d\n", *(iPtrArray+0));
    printf("%d\n", *(iPtrArray+1));
    printf("%d\n", *(iPtrArray+2));
    printf("%d\n", *(iPtrArray+3));
           printf("%d\n", *(iPtrArray+4));

    printf("%d\n", iArray[0]);
    printf("%d\n", iArray[1]);
    printf("%d\n", iArray[2]);
    printf("%d\n", iArray[3]);
    printf("%d\n", iArray[4]);

    return 0;    
    
}

To access a value of an element in an array, we can also place an expression in the square brackets following the array name. As long as the expression resolves to an integer value that falls within the bounds of the array, we are fine.

#include <stdio.h>

int main(void){

    double dNums[5];

    int i = 0;

    dNums[i] = 16.16;
    dNums[++i] = 10.16;
    dNums[i+1] = 88.103;
    dNums[++i + 1] = 104.102;
    dNums[i + 2] = 13.1723;

    for(i = 0; i < 5; i++){
        printf("%f\n", dNums[i]);
    }

    return 0;

}

Remember, when we use an expression to specify the array element the only constraints are that it must produce an integer result and the result must be a legal index value for the array.

For our next program, let’s use an array to store a set of scores that we wish to average.

#include <stdio.h>

int main(void){

    int iScores[10];

    int iCount = 10;

    int iSum = 0;

    double dAvg = 0;

    int i;

    printf("Please enter the scores.\n");
    for(i = 0; i < iCount; i++){
        printf("Score %d of %d:\t", i + 1, iCount);
        scanf("%d ", &iScores[i]);
        iSum += iScores[i];
    }

    dAvg = (double)iSum / iCount;

    for(i = 0; i < iCount; i++){
        printf("%d\t", iScores[i]);
    }
    printf("\nAverage: %f\n", dAvg);
    
    return 0;

}

In the above program, we declare an array of ten integers and then a couple of numbers that we will use for the program. We then will prompt for input using a for loop, and then output the data using another for loop. We use scanf() to accept input from standard input; although in production code we should never use scanf(), it’s fine for our purposes here.

Note that with the for loop we start the count at 0, rather than 1, and use a non-inclusive comparison (< instead of <=). This makes it so we can use the iterator variable for providing the index value for the array.