Search code examples
carchiveexecv

How do I tar compress without parent and root files in one line for execv()


This question's been asked a million times on this site with various different solutions, but non of them seems to work for my case.

So far the most promising one is tar -cvf testetest.tar -C folder1 * where folder1 includes:

Folder1
    >txt1.txt
    >folder2
        >txt2.txt

running the code above in the terminal creates testtest.tar which includes along with a bunch of error msgs:

txt1.txt
folder2
    >txt2.txt

However when ran in a function via execv like so:

pid_t archive = fork();
    switch(archive)
    {
        case -1 :
        {
            printf("fork() failed\n");
            break;
        }
        case 0 :
        {
            if( strcmp(getFileExtension(finalArchiveName), "tar") == 0)
            {
                char* args[] = {"/usr/bin/tar","-cvf", finalArchiveName, "-C", "dest", "*", NULL};
                int error = execv("/usr/bin/tar", args);    
                if(error == -1){
                    perror("Error when archiving");
                    exit(EXIT_FAILURE);
                }
                else{
                    exit(EXIT_SUCCESS);
                }
                break;
            }
//... (not including the whole function, only the part i feel is relevant to the question)

it returns with /usr/bin/tar: *: Cannot stat: No such file or directory

Another line I've tired is to replace the * with . however that ends up including the root directory


Solution

  • The shell replaces the * with a list of filenames, as you can see by typing echo * in a shell. But there's no shell in a call to execv, unless you specifically execute a shell:

    char* args[] = {"sh", "-c", "tar /usr/bin/tar -cvf testetest.tar -C dest *", NULL};
    int error = execv("/bin/sh", args);
    

    In such a case, system() is often a simpler alternative.

    If you want to create a list of file names to pass as arguments to a command-line utility, take a look at glob().