0

I try to do some homework exercise about creating a process with execv in linux. I need to take an input string from the user, and check if there is a program with same name on the machine. I need to try to execute the given program string with the PATH variable directories I have to use the execv function ONLY to execute the program. The input seperated by space when the first word is the file of the program and the other words are the arguments. And they also ask me to validate that the environment has passed to the execv. How do i check that? I found out that I need to use the environ variable and fill it

I Have tried this so far:

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

#define MYCOMMAND_LEN   1000
#define MYNUM_OF_PARAMS 500

extern char **environ;

int main()
{
    int i = 0, j, pid, stat, amountOfLib;
    char command[MYCOMMAND_LEN];
    char *params[MYNUM_OF_PARAMS];
    char *path, *lastStr;
    char *libs[100];
    int numberOflib = 0, numOfParams;
    char *commandPath;

    //cut path
    path = getenv("PATH");
    lastStr = strtok(path, ":");
    libs[0] = (char*)malloc(sizeof(char)*strlen(lastStr) + 1);
    strcpy(libs[0], lastStr);
    i = 1;
    while (lastStr = strtok(NULL, ":")) {
        libs[i] = (char*)malloc(sizeof(char)*strlen(lastStr) + 1);
        strcpy(libs[i], lastStr);
        i++;
        numberOflib = i;
    }
    numberOflib = i;


    puts("Please Enter Command: ");
    gets(commandPath);

    //loop until leave {
    while (strcmp(command, "leave") != 0) {

        //cut command
        lastStr = strtok(command, " ");
        params[0] = (char*)malloc(sizeof(char)*(strlen(lastStr) + 1));
        strcpy(params[0], lastStr);
        i = 1;
        while ((lastStr = strtok(NULL, " ")) != NULL)
        {
            params[i] = (char*)malloc(sizeof(char)*(strlen(lastStr) + 1));
            strcpy(params[i], lastStr);
            i++;
        }
        params[i] = NULL;
        numOfParams = i;

        //check if first is relative
        if ((pid = fork()) == 0) {
            if (params[0][0] == '/' ||
                (strlen(params[0]) >= 2 &&
                    params[0][0] == '.' &&
                    params[0][1] == '/'
                    ) ||
                    (strlen(params[0]) >= 3 &&
                        params[0][0] == '.' &&
                        params[0][1] == '.' &&
                        params[0][2] == '/'
                        )
                ) execv(params[0], params);
            // if command like "man ls"
            else {
                for (i = 0; i < amountOfLib; i++) {
                    commandPath = libs[i];
                    strcat(commandPath, "/");
                    strcat(commandPath, params[0]);

                    for (j = 0; j < numOfParams; j++) {
                         environ[j] = params[j]; //last environ also get the null
                    }

                    execv(commandPath, NULL);
                }
                puts("command not found in PATH");
                exit(1);
            }
        } else {
            wait(&stat);
        }
        puts("Please Enter Command: ");
        gets(commandPath);
    }
    //}

}

some inputs like 'ls' reply that the argv vector is empty.

  • Since `strtok()` chops up a string, you should not use it on the value returned by `getenv()` — you are chopping up the environment variable PATH that the child process will receive. Make a copy and chop the copy. Note that `PATH=:/bin::/usr/bin` has the current directory `.` implicitly specified 3 times — before the first colon, between the adjacent colons, and after the last colon. You should check that the memory allocations are successful. – Jonathan Leffler Apr 24 '19 at 14:51
  • See [Why `gets()` is so dangerous it should never be used](https://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used). – Jonathan Leffler Apr 24 '19 at 14:51
  • You only use a path-based search for the command if there is no `/` anywhere in it. It doesn't have to start with `./` or `../` to be a relative path (though if it does, it _is_ a relative path). For example, `subdir/program` is a relative path and the command should not be searched for using `$PATH`. – Jonathan Leffler Apr 24 '19 at 14:54
  • If you use `execv()`, the environment is automatically inherited. You can demonstrate that by running `env` (type it as the command name). It will print out the environment it receives. Or you can run a program of your own devising to print the environment — it's not hard, and there are several ways to do it. – Jonathan Leffler Apr 24 '19 at 14:56
  • The sequence `commandPath = libs[i]; strcat(commandPath, "/"); strcat(commandPath, params[0]);` is not going to work well. You have not allocated space for the command name, and you mangle the elements of `libs`. You need to allocate separate space for the command path. You are leaking memory; you don't free the parameters from the previous command when you go back for the next command. – Jonathan Leffler Apr 24 '19 at 15:01
  • thank you for the answer. I'll change the mistakes. What about the environ variable how should I use it. do I need to allocate memory for those strings. what data should be in the environment (program name/filename/arguments) ? I Mean what should I expect to see when i execute `env` – itzik ben shitrit Apr 24 '19 at 15:10
  • Unless you've got to add to the environment, you won't need to mess with `environ`. If you do need to add to the environment, use `setenv()` — not `putenv()` unless you're desparate — and still don't need `environ`. When you run `env` at the command line with no arguments, it prints out the environment it was given by your shell. Similarly inside your shell-like program — if you type `env` and that runs `env`, then you should see the environment that your program is giving its children. Further, usually if you run `env` several times , you should see the same output — else you have bugs. – Jonathan Leffler Apr 24 '19 at 17:09

0 Answers0