1

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;
}
5
  • 2
    So basically you're just asking how to concatenate two strings in C? Have you tried reading a C tutorial? Commented Oct 8, 2017 at 13:34
  • I'm not asking how to concatenate, if this was all about concatenation the function strcat would have been enough. But it's not. So i'm asking for help about another way to use the execv function to make my program work. Commented Oct 8, 2017 at 13:52
  • 4
    If that's not what you're asking, then it's what you should have been asking. Clearly you don't understand either what strcat does or how C strings work. (Passing a string literal as the first argument of strcat never makes sense.) Commented Oct 8, 2017 at 13:54
  • yeah actually i don't understand both. I do a lot of programming in java, so I always struggle with strings when it comes to C language. Commented Oct 8, 2017 at 14:08
  • Compile with all warnings and debug info : gcc -Wall -Wextra -gand use the debugger gdb Commented Oct 8, 2017 at 14:34

4 Answers 4

1

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[];
Sign up to request clarification or add additional context in comments.

Comments

1

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).

Comments

0

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.

1 Comment

There is strncat, but it's error prone because its n argument specifies how many bytes to read (at most) from the second argument, not how big the target buffer is.
0

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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.