Mr eskimo
Mr eskimo

Reputation: 41

Problem with directories in C

I'm making a program for Linux in C that recieves a directory as an argument, then for each file in that directory and each of it's sub-directories, calls a program called monfile. Here's the code:

#include <stdio.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <fcntl.h>

#define DIR_ARG 1
#define DUR_ARG 2
#define SEC_ARG 3
#define LOG_ARG 4
#define OP1_ARG 5
#define OP2_ARG 6

int main(int argc, char** argv)
{
    // Teste aos argumentos
    if (argc < 5) {
        printf("Erro! Argumentos insuficientes!\n");
        return -1;
    }

    // Declaração de variáveis
    DIR *dir;
    struct dirent *dentry;
    struct stat stat_entry;

    int fork_result;


    // Testa se o directório passado como argumento é válido
    if ((dir = opendir( argv[DIR_ARG])) == NULL)
    {
        perror(argv[DIR_ARG]);
        exit(2);
    }

    chdir(argv[DIR_ARG]);
    // Ciclo de propagação
    while ((dentry = readdir(dir)) != NULL) {

        stat(dentry->d_name, &stat_entry);
        // Se for ficheiro regular
        if (S_ISREG(stat_entry.st_mode)) {
            fork_result = fork();
            if (fork_result == -1) {
                printf("file fork error!\n");
                exit(1);
            }
            if (fork_result == 0) {
                execlp("monfile", "monfile", argv[SEC_ARG], dentry->d_name, filedes, (char *)NULL);
                printf("Erro no exec!\n");
                exit(1);
            }
        }
        // Se for directório vai criar um novo processo e passar dir para esse directório 
        if (S_ISDIR (stat_entry.st_mode)) {
            fork_result = fork();
            if (fork_result == -1) {
                printf ("dir fork error!\n");
                exit(1);
            }
            if (fork_result == 0) {
                chdir(dentry->d_name);
                dir = opendir (dentry->d_name);
            }
        }
    }



    return 0;
}

Now, the result of this was...a ton of exec error messages and then a bunch of fork error messages, even though I was just calling this for a directory with a file and a sub-directory. This brought me 2 questions: a) How was the cicle doing so many iterations? b) What was wrong with the exec, seeing how monfile is built and in the same folder as mondir?

So, I decided to figure out what directory the program was looking at by adding

printf("%s\n", dentry->d_name);

at the beggining of the cicle, and it was somehow scanning every directory, even though it was called like this: mondir Subfolder1 ...(other args), being Subfolder1 in the same directory as mondir. What am I doing wrong here, both with the directory problem and the exec problem?

Upvotes: 1

Views: 687

Answers (3)

Jonathan Leffler
Jonathan Leffler

Reputation: 754890

Your code is not handling sub-directories very well. You stop processing the current directory (but leak a DIR pointer in the process since you do not do closedir() on the old one before overwriting with the new one) and then chdir() into the new directory.

You also don't avoid directory entries . and ..; you probably do not want to process them, but readdir() will faithfully return them as the first two entries in each directory. This accounts for the flood of processes.

You should look up the POSIX function nftw() and use that - or not try handling directories until after your code is working.

Upvotes: 1

Douglas Leeder
Douglas Leeder

Reputation: 53320

readdir will return "." and ".." so you code will walk up the directory tree, as well as repeating every directory forever - fork/exec bombing your machine.

Also, as mentioned, find -exec would seem a reasonable alternative?

Upvotes: 1

geekosaur
geekosaur

Reputation: 61459

You're tripping over a very common mistake: the names returned by readdir() don't have the source directory name prepended, so you have to put it there yourself.

Upvotes: 0

Related Questions