简体   繁体   中英

Running BASH command via C program

I'm trying to run BASH commands via a C program, but i'm struggling with the function execv. I don't really know how to write the first parameter of that function. I tried with the strcat function to append the string "/bin/" with the 1st element of the argv tab, which is the command i write when I run my program, but it just doesn't work. I get a "Segmentation fault". Instead of using the strcat function I tried with strdup, but I don't know how to use it right.

Any help would be appreciated. My program is below.

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

int main(int argc, char *argv[], char *envp[]){

char *tab[] = {argv[1],NULL};

if(execve(strcat("/bin/",argv[1]), tab, envp)==-1)
{
    perror("execve");
    return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

To run a shell command from a C program, you should use system(3) . If you want to get its stdout (or give its stdin, but not both) use popen(3) (don't forget to pclose such a stream).

The shell used (by system and popen ) is not exactly bash but the standard POSIX /bin/sh (quite similar to bash with some restrictions).

To build that shell command (but beware of code injections in it) you can use common string functions such as snprintf and asprintf .

Notice that execve(2) does not return when it is successful, and it does not run a command thru a shell, but directly an executable program. Actually Unix shells (such as bash or /bin/sh ) are using fork(2) , execve(2) , waitpid(2) very often and are implementing globbing . BTW system & popen are also using fork and execve on /bin/sh -c .

strcat("/bin/",argv[1])

is horribly wrong, the first argument to strcat is the overwritten destination buffer (so cannot be a string literal), and you don't check against buffer overflow .

You might want to code:

char progbuf[80];
int ln = snprintf(progbuf, sizeof(progbuf), "/bin/%s", argv[1]);

and you should check later that ln<(int)sizeof(progbuf)

BTW, your program, when you'll improve it, is not using Bash; it is directly executing some command.


I tried with strdup, but I don't know how to use it right.

Before using any function, you need to carefully read its documentation, for example strdup(3) (or type man strdup in a terminal).

regarding:

if(execve(strcat("/bin/",argv[1]), tab, envp)==-1)  

This will not work ,

  1. the literal "/bin/" is in read only memory, so cannot be changed (need a char buffer large enough to hold the full string, similar to `char string[100] = "/bin/";

Suggest:

#include <stdio.h>      // perror()
#include <stdlib.h>     // exit(), EXIT_FAILURE
#include <sys/types.h>
#include <sys/wait.h>   // waitpid()

#include <unistd.h>     // fork(), execvp()
#include <string.h>     // strlen(), strcpy(), strcat()

int main( int argc, char *argv[], char *env[] )
{
    (void)argc;

    char *tab[] = { argv[1], NULL };

    char string[strlen(argv[1]) + strlen( "/bin/" ) +1 ];
    strcpy( string, "/bin/" );
    strcat( string, argv[1] );

    int status;

    pid_t pid = fork();
    switch( pid )
    {
        case -1:   // fork failed
            perror( "fork failed" );
            exit( EXIT_FAILURE );
            break;

        case 0:    // child process
            execve( string, tab, env );   // does not return unless an error
            perror("execve failed");
            exit( EXIT_FAILURE );
            break;

        default:
            waitpid( pid, &status, 0 );
            break;
    }

}

Caveat: the proposed code just hides the parameter: argc rather than properly checking it to assure the command line does contain a parameter.

Caveat: the parameter to main: env[] is not portable and should not be used. Suggest using :

extern char *environ[];

Melpomene is right- you can't use strcat like that. In C, you can't return strings. What you do is pass a memory address (pointer) as the first argument in strcat , and then strcat modifies the memory pointed to by it so that it also contains the second argument of strcat . This is a process you will repeat over and over again in C, so you should understand it. Also, that strcat doesn't look safe, I bet there is a strcatn function or something like that.

I finally got to find a way to do what I wanted at the first place. Thanks to all of you guys for your help & advices ! Here's the solution !

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

int main(int argc, char *argv[], char *envp[]){

char *tab[] = {argv[1],argv[2],NULL};

char test[20] = "/bin/";

if(execve(strcat(test,argv[1]), tab, envp)==-1)
{
    perror("execve");
    return EXIT_FAILURE;
}

return EXIT_SUCCESS;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM