Pass variable arguments to newly created process - c

In linux
I have temp.c file. In that i created new process and i need to pass all arguments to that
int main (int argc, char *argv[])
{
if( (cid1 = fork()) == 0 ) //child1
{
res = execv(proc1, &argv[1]);
}
}
Now i compile this and run as
./a.out "arg1 arg2 arg3"
Now i want to pass this arg1, arg2 and arg3 to new process created but inside that when i check argc it show me 2 instead of 4
Why this mismatch happen and inside proc1 i have only 1 argument which value is "arg1 arg2 arg3" but here i want 3 argument so argv[1] = arg1, argv[2]=arg2, argv[3]=arg3
How to achive this?

Very useful example at
https://support.sas.com/documentation/onlinedoc/sasc/doc/lr2/execv.htm
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
main()
{
pid_t pid;
char *const parmList[] = {"/bin/ls", "-l", "/u/userid/dirname", NULL};
if ((pid = fork()) == -1)
perror("fork error");
else if (pid == 0) {
execv("/bin/ls", parmList);
printf("Return not expected. Must be an execv error.n");
}
}
As you can see execv() accepts two arguments. The first is executable filename. The second is a pointer to an array of pointers to null-terminated character strings and NULL pointer is used to mark the end of the array.
Create new char* array, assign proc1 to first element (index 0) and required parameters to next elements.

Related

Why is argv[0] not consistent?

From what I understand, argv[0] is the program's path. However, we are doing an assignment and one of my friends gets the name of the first argument when invoking argv[0].
Why does this happen and how can I change this behaviour?
Edit: This is the parent process
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#define SIZE 200
int main(int argc, char const *argv[])
{
char fileName[SIZE];
int bytesToRead;
int status;
bytesToRead = read(0, fileName, SIZE);
int p[2];
pipe(p);
pid_t pid;
if((pid = fork()) == -1) {
perror("error en el fork");
} else
if(pid == 0) {
close(p[0]);
dup2(STDOUT_FILENO, p[1]);
execl("./printTest", fileName, NULL);
close(p[1]);
exit(0);
}
waitpid(pid, &status, 0);
return 0;
}
And next is a child process:
#include <stdio.h>
#include <unistd.h>
#define SIZE 512
int main(int argc, char const *argv[])
{
printf("%s\n",argv[0]);
printf("Exec executed\n");
return 0;
}
From what we understand, argv[0] should hold the program's name, yet it's printing the first argument (whatever was input from stdin in the parent process)
argv[0] isn't necessarily the program's path. It is simply the first argument.
It just so happens that by convention, we use it for the program's name.
For your specific case, you need:
execl("./printTest", "./printTest", fileName, NULL);
Note that this means you always should check if argv[0] is defined before using it.
As per C standard argv[0] should contain the program name.

Making simple unix shell using fork,execvp

printf(*arg);
execvp(*arg, arg);
Here printf() statement prints value= ls.But when running program execvp gives there is no such file or directory.
else if (pid == 0) {
printf(*arg);
execvp(*arg, arg);
char* error = strerror(errno);
printf("shell: %s: %s\n", arg[0], error);
return 0;
if(execvp(arg[0], arg)<0)
{
printf("***ERROR: execution failedn\n");
}
return 0;
}
In the following code are two examples of how to use execvp.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv) {
char *args[] = {"ls", "-l", NULL};
/* an example with a decleared array containing the commande */
if (fork() == 0) {
execvp(args[0], args);
}
/* another example where the commande was passed to main */
printf("argv[0] is the programme/executable name!\nargv[0] = %s\n", argv[0]);
if (fork() == 0) {
execvp(argv[1], argv + 1);
}
return EXIT_SUCCESS;
}
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.

Using Fork for Command Line Arguements

I'm trying to execute the command "ls -l" but I'm not exactly sure how to approach it.
This is what I've tried:
int main(void) {
char * input;
char * args[2];
char buff[100];
input = malloc(sizeof(buff));
while(fgets(input,sizeof(input),stdin) != NULL) {
printf("Enter a command\n");
if(strcmp(input,"ls -l\n") ==0) {
pid_t childPid;
childPid = fork();
if(childPid == 0) {
args[0] = "/bin/ls -l";
args[1] = NULL;
execv(args[0],args);
}
}
}
free(input);
}
However, the command doesn't seem to work here. It works if I just simply use "ls" but I want to use "ls -l" is there another argument I have to pass to get this to work?
When you call any of the exec() variants, you have to pass each argument separately, as in
args[0] = "/bin/ls";
args[1] = "-l";
args[2] = NULL;
First you have to understand this simple example.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
/* status of child execution */
int status;
/* pointer * to array of char*(strings)*/
char ** args;
/* allocate memory for three char*(stings) */
args = (char**) malloc( 3 * sizeof(char*) );
/* fork program and store each fork id */
pid_t childPid = fork();
/* if this is child process */
if(childPid == 0) {
args[0] = "ls";
args[1] = "-l";
args[2] = NULL;
/* execute args[0] command with args arguments */
execvp(args[0],args);
/* send execution code 0 to parent and terminate child */
exit(0);
} else {
/* wait execution code from child*/
wait(&status);
/* free allocated space */
free(input);
free(args);
/* exit program with received code from child */
exit(status);
}
}
I commented every line, but tell me if you want more informations.
You have to understand how to execute commands from child and inform parent before continue to user's input commands.

Calling 'ls' with execv

I am new to system calls and C programming and am working on my university assignment.
I want to call the 'ls' command and have it print the directory.
What I have: (I have added comments in so you can see what I see coming through each variable.
int execute( command* cmd ){
char full_path[50];
find_fullP(full_path, p_cmd);
//find_fullP successfully updates full_path to /bin/ls
char* args[p_cmd->argc];
args[0] = p_cmd->name;
int i;
for(i = 1; i < p_cmd->argc; i++){
args[i] = p_cmd->argv[i];
}
/*
* this piece of code updates an args variable which holds arguments
* (stored in the struct) in case the command is something else that takes
* arguments. In this case, it will hold nothing since the command
* will be just 'ls'.
*/
int child_process_status;
pid_t child_pid;
pid_t pid;
child_pid = fork();
if ( child_pid == 0 ) {
execv( full_path, args );
perror("fork child process error condition!" );
}
pid = wait( &child_process_status );
return 0;
}
I am not seeing anything happening and am confused, any idea?
Here's the minimal program that invokes ls using execv. Things to note
the list of args should include the executable as the first arg
the list of args must be NULL terminated
if the args are set up correctly, then args[0] can be passed as the first parameter to execv
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
int main( void )
{
int status;
char *args[2];
args[0] = "/bin/ls"; // first arg is the full path to the executable
args[1] = NULL; // list of args must be NULL terminated
if ( fork() == 0 )
execv( args[0], args ); // child: call execv with the path and the args
else
wait( &status ); // parent: wait for the child (not really necessary)
return 0;
}

Reading commands from cmd line, and executing them in C

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:
Ask user for number of commands input
Fork() to create child process
Output Child PID and Parent PID
Allow user to input each command, read each input into an index of argv
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);
}
}
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);
}
}
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.
You have wrong logic. use fork just before execv
move execv (together with fork) out of the loop;
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.

Resources