26

The user will read a line and i will retain the first word as a command for execvp.

Lets say he will type "cat file.txt" ... command will be cat . But i am not sure how to use this execvp(), i read some tutorials but still didn't get it.

#include <stdio.h>
#include <stdlib.h>

int main()
{
    char *buf;
    char command[32];
    char name[32];
    char *pointer;
    char line[80];
    printf(">");

    while((buf = readline(""))!=NULL){   
        if (strcmp(buf,"exit")==0)
        break;

        if(buf[0]!=NULL)
        add_history(buf);

        pointer = strtok(buf, " ");
        if(pointer != NULL){
            strcpy(command, pointer);
        }

        pid_t pid;

        int  status;

        if ((pid = fork()) < 0) {     
            printf("*** ERROR: forking child process failed\n");
            exit(1);
        }
        else if (pid == 0) {          
            if (execvp(command, buf) < 0) {     
                printf("*** ERROR: exec failed\n");
                exit(1);
            }
        }
        else                                  
        while (wait(&status) != pid)       
            ;
        free(buf);
        printf(">");
    }///end While
    return 0;
}
Joe
  • 41,484
  • 20
  • 104
  • 125
Axl
  • 273
  • 1
  • 3
  • 7

2 Answers2

60

The first argument is the file you wish to execute, and the second argument is an array of null-terminated strings that represent the appropriate arguments to the file as specified in the man page.

For example:

char *cmd = "ls";
char *argv[3];
argv[0] = "ls";
argv[1] = "-la";
argv[2] = NULL;

execvp(cmd, argv); //This will run "ls -la" as if it were a command
Ricky Mutschlechner
  • 4,291
  • 2
  • 31
  • 36
  • 2
    This code kinda works, but how i make that *argv contain the rest of the line, after cmd ? let's saying im splitting it in tokens like this : pointer = strtok(buf, " "); if(pointer != NULL){ strcpy(command, pointer); } pointer = strtok(NULL, " "); if(pointer != NULL){ strcpy(name, pointer); } Can i do char*argv[3] = {name,"\0"};execvp(command, name); ? – Axl Dec 18 '14 at 08:34
  • 1
    @Axl not sure what you're asking. Is it a separate question? – Ricky Mutschlechner Dec 18 '14 at 08:37
  • 5
    @Axl I think I see now - you're trying to make a shell, I assume? Just write a function that splits the string AFTER you take it all in as user input. So if the user inputs "ls -la", write a function that takes that, splits the string by space, and then sets cmd = split[0], argv[0] = split[0], argv[1] = split[2], and argv[3] = NULL appropriately. Does that help? – Ricky Mutschlechner Dec 18 '14 at 08:38
  • No, its in my code , but i didnt posted it because i thought it wasn't important.I am separating "buf" in tokens , first part is the command and the next on is the argument . My question is : Can't i add in your *argv just the token for the argument, so i don't need to store manually every posible argument in argv ? – Axl Dec 18 '14 at 08:39
  • 1
    Just a minor typo fix for char array pointer initialization: line 1 should be : char *cmd = "ls"; – Aditya Gaykar Oct 07 '15 at 09:26
  • I know this is a rather old post, but I still don't know how I would handle this when I would like to start the second program in the one I am currently running with execvp. For this, I have 2 separate paths for the programs. fe Project3\x64\Debug\Project3.exe and Project4\x64\Debug\Project4.exe – Andreas Feb 06 '19 at 13:55
  • @Andreas `execvp()` will replace your currently running program with the new one. You'd want to set `cmd` and `argv[0]` to `Project4\x64\Debug\Project4.exe` (if you were running Project3) and then any arguments that might be needed as well. Hopefully this helps you. – Ricky Mutschlechner Feb 06 '19 at 23:19
  • @Andreas most importantly, you will NOT want to fork. You can JUST call execvp or any of the variants and that will do what you want. – Ricky Mutschlechner Feb 06 '19 at 23:34
  • Technically it works, but, there's a warning. Why? `warning: incompatible pointer types passing 'char *' to parameter of type 'char *const *'; take the address with & [-Wincompatible-pointer-types] execvp("ls",argv);` Compiler indicates you should be using & to dereferencethe argv pointer. What even is a `char *const *`? – Ryan Oct 12 '19 at 04:04
-1

In cpp, you need to pay special attention to string types when using execvp:

#include <iostream>
#include <string>
#include <cstring>
#include <stdio.h>
#include <unistd.h>
using namespace std;

const size_t MAX_ARGC = 15; // 1 command + # of arguments
char* argv[MAX_ARGC + 1]; // Needs +1 because of the null terminator at the end
// c_str() converts string to const char*, strdup converts const char* to char*
argv[0] = strdup(command.c_str());

// start filling up the arguments after the first command
size_t arg_i = 1;
while (cin && arg_i < MAX_ARGC) {
    string arg;
    cin >> arg;
    if (arg.empty()) {
        argv[arg_i] = nullptr;
        break;
    } else {
        argv[arg_i] = strdup(arg.c_str());
    }
    ++arg_i;
}

// Run the command with arguments
if (execvp(command.c_str(), argv) == -1) {
    // Print error if command not found
    cerr << "command '" << command << "' not found\n";
}

Reference: execlp、execvp用法與範例

AlienKevin
  • 2,691
  • 2
  • 17
  • 19