Question

I'm writing a program to take user input from the command line (linux/unix commands), and execute them within my program.

My steps so far:

  1. Ask user for number of commands input
  2. Fork() to create child process
  3. Output Child PID and Parent PID
  4. Allow user to input each command, read each input into an index of argv
  5. Use execv to run each command inside of argv

The main issue is that when it executes, it merely does the "bin/ls/" in the execv command.

Here is a sample output from running my program:

Enter number of commands: 2
Child's PID is 3487. Parent's PID is 3485
Enter a UNIX command: ls
Enter a UNIX command: -al

LIST OF FILES AS IF TYPING "LS" ON THE CMD LINE

Process Complete.


And here is my source code:

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

void main(int argc, char *argv[20])
{
        int pid;
        int num = 0;

        printf("Enter number of commands: ");
        scanf("%d", &argc);

        pid = fork();

        if(pid == 0)
        {
                printf("Child's PID is %d. Parent's PID is %d\n", (int)getpid(), (int)getppid());

                for(num=0; num < argc; num++)
                {
                        printf("Enter a UNIX command: ");
                        scanf("%s", argv[num]);
                }

                argv[num+1] = 0;

                execv("bin/ls/", argv);
        }
        else
        {
                wait(pid);
                printf("Process Complete.\n");
                exit(0);
        }
}
Was it helpful?

Solution

Firstly you are defining char* argv[20] in main which is not a good idea. If you ever pass in more than 20 arguments you will exceed the bounds of the array.

Secondly, you are attempting to read a string with scanf("%s", argv[num]) into an address space that is not initialized as far as I can tell.

The argv[] array of "strings" is initialized by the OS when your program is invoked and if you don't pass any arguments to your program you will not have any "strings", meaning that you will be writing to random memory which you might not own.

If you really want to load your commands the way you are doing it now please try the following:

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

void main(int argc, char *argv[])
{
    int pid;
    int num = 0;
    int argc2 = 0;
    char* argv2[20]; // argv2 will point inside of buffer for convenience.
    char* buffer[2000]; // note each array has a limit of 100 characters.

    printf("Enter number of commands: ");
    scanf("%d", &argc2);

    pid = fork();

    if(pid == 0)
    {
            printf("Child's PID is %d. Parent's PID is %d\n", (int)getpid(), (int)getppid());

            for(num=0; num < argc2 && num < 20; num++) // your array is 20 long
            {
                    argv2[num] = &buffer[num * 100];
                    printf("Enter a UNIX command: ");
                    scanf("%s", argv2[num]);
            }

            argv[num] = 0; // no need to add + 1 because the for loop did already anyway.

            execv("Assignments/ls", argv2);
    }
    else
    {
            wait(pid);
            printf("Process Complete.\n");
            exit(0);
    }
}

Alternatively you could just pass arguments to your main program which simply passes them onto the called program like so:

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

void main(int argc, char *argv[])
{
    int pid;
    int num = 0;

    printf("You entered %d commands: \n", argc);

    for (num = 0; num < argc; ++num)
    {
        printf("\t%s\n", argv[num]);
    }

    pid = fork();

    if(pid == 0)
    {
            printf("Child's PID is %d. Parent's PID is %d\n", (int)getpid(), (int)getppid());

            execv("Assignments/ls", &argv[1]);
    }
    else
    {
            wait(pid);
            printf("Process Complete.\n");
            exit(0);
    }
}

OTHER TIPS

One specific problem your code has is you must pass argv[idx] as the argument to exec. You're passing an array of char pointers, by passing argv.

Please also be advised that argc contains the full count of arguments, and that full count includes the program itself. argv[0] contains the program name to which you are passing the arguments. I'm not seeing that being reflected in your for loop. That is you are processing your own program and running it.

The way I've written these is to traverse argv in a while (or for, if you prefer), using an int varaiable -- for example int idx=0; -- until I find an argv[idx] pointer that is null.

If, for example, you had three arguments, argc would be 4, and argv[3] would be your last argument to process. argv[4] would be null.

Based on some of the answers you've received, here's a discussion of execv and fork.

  1. You have wrong logic. use fork just before execv
  2. move execv (together with fork) out of the loop;
  3. 1st argument of the execv - is a path to the binary file to execute; 2nd - array of arguments to pass to the binary. Is this correct that you have in the current directory the sub-directory named 'Assignments' and this directory contains the executable named 'ls'? And, please, read 'man execv' carefully

Update:

Disregard points 1 and 2 above.

man execv:

   The execv(), execvp(), and execvpe()  functions  provide  an  array  of
   pointers  to  null-terminated  strings that represent the argument list
   available to the new  program.   The  first  argument,  by  convention,
   should  point  to the filename associated with the file being executed.
   The array of pointers must be terminated by a NULL pointer.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top