1

I wrote an executable that checks the presence of combinations of xattr tags. I want to use that executable on all the files of a directory, that means I want to execute it on every files I find in that directory and every files of the directories there are in it... etc.

My xattr executable and the program I use to recursively navigate in the dirs look like this:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/xattr.h>
#include <string.h>
#include <errno.h>


int main(int argc, char const *argv[]){
    char argNormaux[4096] = {0};
    char argNeg[4096] = {0};
    char argEt[4096] = {0};
    int nbArgsNormaux = 0;

    if (argc > 2){
        for (int i = 2; i < argc; i++){
            const char *arg = argv[i];
            if (strstr(argv[i],"et") != NULL){
                // printf("%d. Et trouvé. Argument=%s\n", i, argv[i]);
                strcat(argEt, argv[i]);
            }
            else if (strstr(argv[i], "!") != NULL){
                // printf("%d. Négation trouvée. Argument=%s\n", i, argv[i]);
                strcat(argNeg, argv[i]);
            }
            else {
                // printf("%d. Argument trouvé=%s\n", i, argv[i]);
                strcat(argNormaux, argv[i]);
                nbArgsNormaux++;
            }
        }
        // printf("nbArgsNormaux=%d\n", nbArgsNormaux);
        // printf("Liste des arguments normaux: %s\n", argNormaux);
        // printf("Liste des négations: %s\n", argNeg);
        // printf("Liste des et: %s\n", argEt);

        const char *path = argv[1];
        printf("path=%s\n", path);
        // printf("Tags du fichier %s\n", path);
        char buf[4096];
        int rc;
        rc = listxattr(path, buf, sizeof(buf));
        if (rc < 0){
            perror("listxattr");
        }
        else {
            if (strlen(buf) == 0){
                printf("Il n'y a aucun tag sur ce fichier.\n");
                return 1;
            }
            int tagsNormauxCheck = 0;
            int tagsNegCheck = 0;
            char *token = buf;
            while(*token){
                char tagBuf[4096];
                if (strlen(token) == 2){
                    if (strcmp(token, "\0\0\0")) break;
                }
                rc = getxattr(path, token, &tagBuf, sizeof(tagBuf));
                if (rc < 0){
                    perror("getxattr");
                }
                else {
                    if (strstr(argNormaux, tagBuf) != NULL) {
                        // printf("tagbuf=%s\n", tagBuf);
                        // printf("Check NULL\n");
                        tagsNormauxCheck++;
                    }
                    if (strstr(argNeg, tagBuf) != NULL) {
                        tagsNegCheck = 1;
                        break;
                    }
                }
                memset(&tagBuf, 0, sizeof(tagBuf));
                token = strchr(token, '\0');
                token++;
            }
            // printf("Normaux=%d, NegCheck=%d\n", tagsNormauxCheck, tagsNegCheck);
            if (tagsNormauxCheck == nbArgsNormaux && tagsNegCheck == 0){
                printf("Le fichier %s possède la combinaison des tags donnés.", path);
                return 1;
            }
        }
    }
    else {
        printf("Pas assez d'arguments.\n");
        return 0;
    }
    return 0;
}
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <sys/types.h>
#include <unistd.h>

void listFilesRecursively(char *basePath, int argc, char const *argv[]){
    char path[4096];
    struct dirent *dp;
    DIR *dir = opendir(basePath);

    // Unable to open directory stream
    if (!dir) return;

    char const *cpArgv[argc+2];
    for (int i = 1; i < argc; i++){
        cpArgv[i] = argv[i];
    }
    cpArgv[argc+2] = NULL;
    while ((dp = readdir(dir)) != NULL){
        if (strcmp(dp->d_name, ".") != 0 && strcmp(dp->d_name, "..") != 0){
            if (dp->d_type == DT_REG){
                cpArgv[0] = "./logic";
                cpArgv[1] = path;
                strcpy(cpArgv[1], basePath);
                strcat(cpArgv[1], "/");
                strcat(cpArgv[1], dp->d_name);
                printf("%s\n", dp->d_name);
                for (int i = 0; i < argc; i++){
                    printf("cpArgv[%d]=%s\n",i, cpArgv[i]);
                }

            }
            if (fork() == 0){
                execv("./logic",cpArgv);
            }
            // Construct new path from our base path
            strcpy(path, basePath);
            strcat(path, "/");
            strcat(path, dp->d_name);

            listFilesRecursively(path, argc, cpArgv);
        }
    }

    closedir(dir);
}

int main(int argc, char const *argv[]){
    if (argc > 1){
        listFilesRecursively(argv[1], argc, argv);
    }
    else {
        printf("Pas assez d'arguments, test.\n");
    }
    return 0;
}

The xattr program works perfectly fine when used alone, from the terminal. The program used to get all the files recursively in a directory works perfectly fine when used without the fork and exec. However, when I use them, The program is showing duplicates, the xattr program is executed but not finding the tags, like it's just executed, but not finishing, and some files are not showed...

This an example of the output I can have:

dir2fichierUN.txt
cpArgv[0]=./logic
cpArgv[1]=testDir/dir2/dir2fichierUN.txt
cpArgv[2]=essai1
fichier1.txt
cpArgv[0]=./logic
cpArgv[1]=testDir/fichier1.txt
cpArgv[2]=essai1
fichier2.txt
cpArgv[0]=./logic
cpArgv[1]=testDir/fichier2.txt
cpArgv[2]=essai1
fichier1.txt
cpArgv[0]=./logic
cpArgv[1]=testDir/fichier1.txt
cpArgv[2]=essai1
fichier1.txt
fichier2.txt
cpArgv[0]=./logic
cpArgv[1]=testDir/fichier2.txt
cpArgv[2]=essai1
cpArgv[0]=./logic
cpArgv[1]=testDir/fichier1.txt
cpArgv[2]=essai1
fichier2.txt
cpArgv[0]=./logic
cpArgv[1]=testDir/fichier2.txt
cpArgv[2]=essai1
path=testDir/fichier1.txt
path=testDir/fichier2.txt
path=testDir/fichier1.txt
path=testDir/fichier2.txt
path=testDir/fichier1.txt
path=testDir/fichier2.txt
path=testDir/fichier1.txt
path=testDir/fichier2.txt

The program seems to be hanging in my terminal...

What I'm trying to achieve here is to be able to execute my xattr program on every file there are in the directory the first the second program is called. I have troubles making it work with fork and execv.

Could you help me please?

Thanks.

VDS-Atomic
  • 115
  • 1
  • 11

1 Answers1

1

You don't need to handle the recursion yourself, you could just handle files given as command line arguments and use find to apply your command recursively to all files in a hierarchy:

find . -type f -exec logic args '{}' \;

If your logic program is not available from the $PATH variable, replace its name with its path in the find argument list. args are the arguments you want to pass to your program before the filename.

chqrlie
  • 131,814
  • 10
  • 121
  • 189
  • Yea I could make something work with existing commands, but I'm trying to make it work with a C program! – VDS-Atomic May 10 '20 at 08:55
  • And after a bit of testing, it seems to only apply `logic` on directories, and not files, or maybe it's the way my `logic` executable works. I want it to be executed on every file existing in a directory and its subdirectories and so on. – VDS-Atomic May 10 '20 at 09:12