calling ls and other using execve - c

I'm trying to create a simple program that will allow to execute basic
shell commands. Problem is execve just hangs everytime.
Heres the code:
char* arglist[]={"ls","-l",NULL};
char* env[]={NULL};
int status;
while (1)
{
if (fork() != 0)
{
waitpid(-1, &status, 0);
}
else
{
execve(arglist[0],arglist,env);
}
}
return 0;
}

The first arguments should be a full path to the binary you execute:
char* arglist[]={"/bin/ls", "-l", NULL};

Related

how do you take arguments for execv || execl to run either one program or pipe another

Okay I don't want to pass arguments I know that but I am trying to figure out how to pass these arguments from the terminal and where do you learn this?
int
main(int argc, char **argv) {
int infd, outfd, bytes;
char buf[SIZE];
//I WILL READ FILES HERE
while((bytes = read(infd, buf, SIZE)) > 0) {
write(outfd, buf, bytes);
}
int fd[2];
if (pipe(fd) == -1) return 1;
int pid1 = fork();
if (pid1 < 0) return 2;
if (pid1 == 0) {
dup2(fd[0], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execvp("How do i take arguments here?");
// Example, I am showing an example with execl but i would like to use execv
// Assuming wcat is my written program. Am writing wcat in another file? or
// can i call the wcat function if wcat was as an argument? I tried something like below
// Note: that i tried :
/*
execlp("./wcat", argv[1], argv[2], argv[3]); but this does nothing
*/
execlp("wcat", "wcat", "file1", "file2", "file3", NULL);
if ((strcmp(argv[0], "wcat"), 0)) { // i did this but nope
// do something
}
}
int pid2 = fork();
if (pid2 < 0) return 3;
if (pid2 == 0) {
dup2(fd[2], STDIN_FILENO);
close(fd[0]);
close(fd[1]);
execvp("How do i take arguments here?");
// Note: that i tried :
/*
execlp("./ww", argv[1], NULL); but this does nothing
*/
if ((atoi(argv[1], "pass integer here"), 0)) { // i did this but nope
// do something
}
// Example, I am showing an example with execl but i would like to use execv
execlp("use my word-wrap program", " pass second arguments as an integere");
}
// you have to close the both file descriptors for the program to end
close(fd[0]);
close(fd[1]);
// calling waitpid for fd[1] to work before starting fd[2]
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
return 0;
}
I want to run this at the terminal :
./wcat file1 file2 file3 | ./ww 50
Please any knowledge will be helpful. my other programs are done. I just need to run this on the terminal I can pass the arguments in the file and that is fine but I want to run this at the terminal.
execlp takes a variable number of arguments of type const char * terminated by NULL:
execlp("./wcat", "./wcat", "first arg", "second arg", NULL);
The actual issue is that you expect the code after the execlp() call to be executed. It will not as the program you specified is now running instead:
#include <stdio.h>
#include <unistd.h>
int main() {
execlp("/bin/bash", "/bin/bash", "-c", "echo hello", 0);
printf("world\n");
return 0;
}
will only print:
hello

Two way communication from the file that run with exec in child

I am creating a child process with a fork in program y. In that child, I run another program with exec, in which I want the function in that program (let's call it program x) to return something to me. Is there a way to pass this returned value to the parent?
I provided some sort of a pseudo-code that demonstrates what I want to do below.
program.x:
int main(int argc, char** argv)
{
if(argc != 2)
{
printf("argument count does not match\n");
return -1;
}
printf("task1!\n");
...
char *value = "want this"; // how to pass this to the parent in the program y?
...
}
program y:
int main(int argc, char *argv[])
{
int fd[2];
pipe(fd);
pid_t p;
p = fork();
if(p==-1)
{
printf("There is an error while calling fork()");
}
if(p==0)
{
printf("We are in the child process\n");
printf("Calling hello.c from child process\n");
char *args[] = {"Hello", "C", "Programming", NULL};
execv("./hello", args);
close(fd[0]);
write(fd[1], ???, ??);
close(fd[0]);
}
else
{
printf("We are in the parent process");
wait(NULL);
close(fd[1]);
read(fd[0], ???,???);
close(fd[0]);
}
return 0;
}
The only thing you can pass directly is the exit code of the child (via wait()).
To pass a string between two processes, you need an IPC data structure like pipes. See the pipe() function in unistd.h.
For the simple case where there is one-way communication from a child to a parent), you can use popen. It's high level, simple to use, and has little overhead (if any) over fork/exec
int main(...)
{
...
FILE *fp = popen("./hello 'Hello', 'C', 'Programming'", "r") ;
char resp[200] ;
if ( fgets(resp, sizeof(resp, fp) ) {
// Do something
}
int result = pclose(fp) ;
}
Note that the way to pass command line arguments follows shell rules - arguments may need to be quoted (usually, single quote) to pass any special characters.
The 'pclose' result is the exit code of the executed program.

Why isn't chdir() working? [duplicate]

This question already has an answer here:
How can I use chdir function in Linux?
(1 answer)
Closed 6 years ago.
When I try to run ./shell cd includes/
I don't actually change into the includes directory. Here's my code:
int cd(char *path) {
printf("i got there at least\n");
if(path == NULL) {
printf("dont waork\n");
print_usage();
} else {
printf("print please\n");
int dir_change = chdir(path);
if(dir_change != 0)
print_no_directory(path);
}
return 1;
}
int shell(int argc, char *argv[]) {
pid_t pid;
int status;
pid = fork();
if(pid == 0) {
execl("cd", argv[0], argv[1], argv[2], (char*)NULL);
printf("argv[1]: %s\n", argv[1]);
if(!strcmp(argv[1], "cd")) {
cd(argv[2]);
}
} else if(pid > 0) {
waitpid(pid, &status, WUNTRACED);
} else {
print_fork_failed();
}
return 0;
}
I don't see what's wrong with my code.
You can't run a program to change the directory of another program (your shell).
What happens is
A new process is spawned to run your program
That program calls chdir(), to change its current directory
The program end, causing the process to die
The shell is still where it was
That's why cd in the shell is a built-in command.
you cannot create a cd command like this unless you develop your own shell.
The chdir command works, but only inside your program. Once you exit it, you're back to the parent shell current directory.

Getting infinite loop on execvp()

I am learning about how fork() works and I am running into an infinite loop when calling execvp(argh[0], argv);
Here is my program:
int main (int argc, char *argv[])
{
pid_t pid;
pid = fork();
if (pid < 0) { // error occurred
printf("Something went wrong!\n");
exit(-1);
} else if (pid == 0) { // child process
printf("Child process. ");
if(argc == 1 || argc == 0) {
printf("No arguments provided. Terminating child.\n");
exit(0);
} else if(argc == 2) {
printf("One argument provided.\n");
execlp(argv[1], argv[1], NULL);
} else {
printf("More than one argument\n");
execvp(argv[0], argv); // *** It's right here ***
}
} else { // parent process
printf("PARENT started with pid=%d.\n", pid);
int status = 0;
pid_t wait(int *status);
printf("PARENT resumed with status code: %i. Now terminating parent.\n", status);
exit(0);
}
return 0;
}
I'm trying to perform the operation (and arguments) that are passed into the function, with this code execvp(argv[0], argv), but I'm getting an infinite loop when I do ./arguments ls -l. How should I be calling execvp? Or should I call another method?
Thanks for any help
---Update---
I made the change suggested in an answer which was to call execvp(argv[1], argv); (change the arguv[0] to arguv[1]) and I now get cannot access ls: No such file or directory rather than an infinite loop.
When you do ./arguments ls -l, your code is executing execvp("./arguments", {"./arguments", "ls", "-l"}). Your program is forking and calling itself infinitely: you have made fork-bomb. :)
This is because argv[0] is your executable file (i.e. ./arguments).
You should use argv[1] instead, like this:
execvp(argv[1], &argv[1]);
Note you have to change both the first and the second argument.
When executed, that line will be equivalent to: execvp("ls", {"ls", "-l"}).

Call mkdir syscall with execve in C

I am very new to C and am in an OS class where I need to write a basic shell in C (yay). It's actually been going halfway decently, I am just trying to learn C basics while getting through the work.
I am trying to use exec after forking and call, for now, mkdir. The arguments required through me off a little, but I've been trying to figure it out and was hoping someone could tell me where I've gone wrong.
} else {
//fork exec
int pid = fork();
if (pid == 0) {
printf("%s",my_argv[0]);
execve("/bin/mkdir",my_argv,0);
} else wait(NULL);
}
This is the portion where I am responding to the mkdir call. Right now, I have a line[] that is input from the user, the command is taken with
command = strtok(line, DELIMITERS);
The arg is :
arg = strtok(0,DELIMITERS);
my_argv[0] = arg;
Everything compiles fine but the mkdir never works. Printing my_argv[0] gives the correct argument that I expect. I'm sure this is something stupid but any tips would be appreciated.
All Code:
int main(int argc, char *argv[])
{
char *command;
char line[MAXLINE];
char *arg = NULL;
char *my_argv[];
while(1) {
printf(PROMPT);
if (fgets(line,MAXLINE,stdin) != NULL) {
//take out \n
line[strlen(line)-1] = '\0';
}
//looks for first delimiter, saves as the command
command = strtok(line, DELIMITERS);
//start looking at what command it is by comparing
if (strcmp(command,"cd")==0) {
//if they equal zero, they match
//this is a cd command, must have following arg
if (argv[1] == NULL) chdir("/");
else chdir(argv[1]);//chdir is the system call for cd
} else if (strcmp(command,"exit")==0) {
break;
} else if (strcmp(command,"mkdir")==0){
arg = strtok(0,DELIMITERS);
my_argv[0] = arg;
my_argv[1] = NULL;
if (!arg) {
printf("Usage: mkdir missing arg\n");
} else {
//fork exec
int pid = fork();
if (pid == 0) {
printf("%s",my_argv[0]);
//mkdir(arg);
execve("/bin/mkdir",my_argv,0);
} else wait(NULL);
}
}
}
return 0;
}
argv[0] contains the name of the program
argv[1] is the first argument
argument list must be NULL terminated
You could use the mkdir syscall instead of execve

Resources