-1

How can you run execvp with a "*.c". I can get it to work with a full name but not a wildcard. Any help would be greatly appreciated. This is what I have so far.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(void) {
    printf("running\n");    
    char* args[] = { "find", "-name", "one.c",  NULL};
    char * envp[] ={NULL};

    int pid = fork();

    switch(pid){
        case -1:
            perror("fork() failed");
            exit(1); 
        case 0: // child
            execvp(args[0], args);
            printf("after the exec\n"); 
        default: // parent 
            //wait(NULL);
            if(wait(NULL) == -1){
                perror("wait() failed"); 
            }
    }

    return 0; 
}
melpomene
  • 84,125
  • 8
  • 85
  • 148
code kid
  • 374
  • 1
  • 6
  • 22

2 Answers2

0

This is by design. Wildcard processing can be expensive because it requires to browse a folder. It is normally active by default in the shell, but not in API functions. One notable exception is system because it actually pass a command to the shell:

The system() function hands the argument string to the command inter- preter sh(1)

The exec... family functions do not do that and assume that the path is a real path and do not special processing for wildcard characters. Simply, the exec[lv]p take all folder from the PATH environment variable and try to find a file with the exact name in one of them.

You must use the glob function for wildcard processing. BTW, the shell programs use it...

Serge Ballesta
  • 143,923
  • 11
  • 122
  • 252
  • That doesn't make sense in the context of `find -name "*.c"`. `find` does its own wildcard processing. You can't pass it a list of names in the current directory; what would that mean? – melpomene Jun 01 '18 at 15:37
  • @melpomene : The shell interprets wildcards, unless you explicitely ask it not to do by *quoting* them... – Serge Ballesta Jun 01 '18 at 17:48
  • Yes, I know. Look at the command OP is trying to run. Wildcard expansion is exactly not what's needed here because we're trying to use `find`'s built in wildcard processing. – melpomene Jun 01 '18 at 18:04
0

You must do your own wildcard expansion. When you use the exec() family of functions, you are passing arguments almost directly to the new program.

If you want the replacing program to replace wildcards for you, you may well want to use a shell to do that (as system() does), but be careful, as you'll need to correctly quote for the shell.

Example:

char shell[] = "/bin/sh\0-c\0ls *.c";
char *args[] = { shell, shell+8, shell + 11, 0 };

execv("ls", args);

Note also that string literals are const char*, so shouldn't be used to populate a char*[].


However, in the case of find, you probably don't want to expand the wildcard. Here, there's no need to do anything special - just pass *.c as one of the arguments. The find command (specifically the -name argument) requires a pattern, not a list of filenames, so there's no expansion to do:

char shell[] = "/usr/bin/find\0.\0-name\0*.c";
char *args[] = { shell, shell+14, shell + 16, shell+22, 0 };

execv("find", args);
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • That doesn't make sense in the context of `find -name "*.c"`. `find` does its own wildcard processing. You can't pass it a list of names in the current directory; what would that mean? – melpomene Jun 01 '18 at 15:37
  • That's why I showed `ls` instead. I couldn't understand why anyone would want to expand a wildcard for `find -name` - the usual issue in a shell is forgetting to quote it to *prevent* expansion! I've voted to close the question as unclear. – Toby Speight Jun 01 '18 at 15:39