How to execute shell command with arguments in C - c

I'm unable to execute the command alone, with arguments is working. How can I make it work both ways.
char command[256];
char args[10][256];
char buffer[256] __attribute__((aligned(4096)));
Funcion is handling command and arguments and I'm sure they are correct, however I can't find a way to execute it.
pid = fork();
if (pid == -1)
{
printf("Failed forming fork\n");
return;
}
else if (pid == 0)
{
strcpy( cmd , "/usr/bin/");
strcat( cmd, command);
execl(cmd, command, args, NULL);
}else{
wait(NULL);
}
And in general how can I stop fork bombs, how to check for them and avoid them?

Related

Why is there empty output when running commands in this c code?

I have this function that executes a command
int cmd2(char * const *cmd, char * std_out)
{
char tmp[4096];
int pipefds[2], r, status, x;
pid_t pid;
if (pipe(pipefds) == -1){
return -1;
}
if ( (pid = fork()) == -1){
return -1;
}
if (pid == 0)
{
dup2(pipefds[1], STDOUT_FILENO);
dup2(piepfds[1], STDERR_FILENO);
close(pipefds[0]);
close(pipefds[1]);
execvp(cmd[0] , cmd);
}
else
{
close(pipefds[1]);
x = read(pipefds[0], tmp, 4096);
printf("Got %d bytes\n",x);
wait(NULL);
}
return 0;
}
the error message that should be outputted
┌──(kali㉿kali)-[~/]
└─$ ./wow
zsh: no such file or directory: ./wow
when running another c code that fputs a buffer into stderr it is display by the cmd2 without any problems
I tried to redirect stderr to stdout using 2>&1 but this does not seem to have an effect
how to read any/all results from executing the command
If you try running a non-existent command with cmd2, execvp will set errno and return. It will not print anything anywhere. You need to check errno and print the error. Something as simple as:
execvp(cmd[0], cmd);
perror(cmd[0]);
exit(EXIT_FAILURE);
should usually suffice. zsh does something like that when you try to run a non-existent command with it, that's why you see an error message.
Note however that it is the child process that prints the message. You discard child process output and only print its length. You need to do something about it if you want to see the message.

How to use execvp or any of the other exec's to run on only one file?

I want to execute execvp, or really any of them that would work for this, but only run it on the file given. To explain what I am trying to do, I am trying to run it on files that meet the other arguments given. Ex: (./a.out -s 1024 -e "ls -l") -s being if the file size is >= 1024 then show that file and then excute the command "ls -l" on that file. My code checks every file in the directory and only shows the ones that pass. I am having trouble understanding how I would just show that one file and not all the files in the directory.
if (flagArgs.e_flag) // e case
{
char *cmd = "ls";
char *argv[3];
argv[0] = "ls";
argv[1] = "-la";
argv[2] = NULL;
printf("DIRFILE: %s\n", dirfile);
if (strcmp(line, "") != 0){
if ((pid = fork()) < 0) { /* fork a child process */
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if (pid == 0) { /* for the child process: */
if (execvp(dirfile, argv) < 0) { /* execute the command */
printf("*** ERROR: exec failed\n");
exit(1);
}
}
else { /* for the parent: */
while (wait(&status) != pid) /* wait for completion */
;
}
}
}
I understand that i am using execvp wrong in this code as i should be passing (cmd, argv) but I am trying to figure out how i can just run the given command on one singular file. Is there any way i can do this or is using execvp wrong?
Thanks for any help!
Add the filename to the argv array. The first argument to execvp() should be the program to run, which is usually the same as argv[0].
if (flagArgs.e_flag) // e case
{
char *cmd = "ls";
char *argv[4];
argv[0] = "ls";
argv[1] = "-la";
argv[2] = dirfile;
argv[3] = NULL;
printf("DIRFILE: %s\n", dirfile);
if (strcmp(line, "") != 0){
if ((pid = fork()) < 0) { /* fork a child process */
printf("*** ERROR: forking child process failed\n");
exit(1);
}
else if (pid == 0) { /* for the child process: */
if (execvp(argv[0], argv) < 0) { /* execute the command */
printf("*** ERROR: exec failed\n");
exit(1);
}
}
else { /* for the parent: */
while (wait(&status) != pid) /* wait for completion */
;
}
}
}

Why does wc command in execvp() return the wrong results when taking input from a pipe in my shell?

I'm working on writing a shell in C for learning purposes and I'm trying to allow for a variable number of pipes. In general, it seems to work great. But I noticed a problem with the wc command.
When I pipe some output of another program into wc like ls | wc it always returns
1 3 35 no matter what I pipe into it. Other commands work as expected when I pipe into them. In my normal zsh shell wc works fine. I'm struggling to find the problem. I've tried adding waitpid after the forks but no dice.
Here's the main shell loop in the main function:
while (1) {
printf("\033[31;1mshell:\033[0m ");
line = read_cmds();
if (strstr(line, "|")) {
// check for pipes first
pipe_exec(line);
} else {
// we have a single command
tokens = split(line, " \t\r\n");
if (*tokens != NULL) shell_exec(tokens);
free(tokens);
}
}
Here is the function that loops through the commands:
void pipe_exec(char *line)
{
int in, status;
int pipe_no; // keep track of ptr to bring it back to free
int pfd[2];
pid_t rc;
char **cmd, **pipe_cmds;
// split takes a string and splits into array of strings based on delimiter
pipe_cmds = split(line, "|");
in = 0;
pipe_no = 0;
while (*pipe_cmds) {
cmd = split(*pipe_cmds, " \t\r\n");
if (pipe(pfd) < 0) perror("pipe");
make_proc(in, pfd[1], cmd);
close(pfd[1]);
in = pfd[0];
pipe_cmds++; // move ptr ahead one
pipe_no++;
}
// move pointer back and free
pipe_cmds -= pipe_no;
free(pipe_cmds);
rc = fork();
if (rc == 0) {
if (in != 0) dup2(in, STDIN_FILENO);
execvp(*cmd, cmd);
}
}
And then the make_proc function that the above function calls:
void make_proc(int in, int out, char **cmd)
{
pid_t rc;
rc = fork();
if (rc == 0) {
if (in != STDIN_FILENO) {
dup2(in, STDIN_FILENO);
close(in);
}
if (out != STDOUT_FILENO) {
dup2(out, STDOUT_FILENO);
close(out);
}
execvp(*cmd, cmd);
}
}
I took out some of the error checking to save space here.
Any help is appreciated!
You execute the last command twice and pipe its first instance to the second. Adding something like:
while (*pipe_cmds) {
cmd = split(*pipe_cmds, " \t\r\n");
if (!pipe_cmds[1]) {
break;
}
if (pipe(pfd) < 0) perror("pipe");
make_proc(in, pfd[1], cmd);
close(pfd[1]);
in = pfd[0];
pipe_cmds++; // move ptr ahead one
pipe_no++;
}
would prevent the unnecessary instance, although I would rather have refactored this function a bit.

Custom shell stops working after dup2

I am writing a function to my shell where I need to redirect output to file. For example user write: ls -l >> file and ls -l should be written to file. Almost all things are correct but after first calling my function program stop and I can't write anything else. Below I present my function and I would appreciate any clues to resolve the problem:
void execute2(char *command, char **argv, char **argv2)
{
pid_t pid;
int status;
if ((pid = fork()) < 0)
{
printf("*** ERROR ***\n");
exit(1);
}
else if (pid == 0)
{
close(1);
parse(command, argv, argv2);
int output = open(*argv2, O_APPEND | O_WRONLY);
dup2(output,1);
if (strcmp(argv[0], "exit") == 0)
exit(0);
if (execvp(*argv, argv) < 0)
{
printf("*** ERROR ***\n");
exit(1);
}
close(output);
}
else
{
while (wait(&status) != pid);
}
}
command is command getting from user, argv is part of instruction and parameters and argv2 is the output file.
#Jonathan Leffler I checked this and I think it doesn 't resolve problem. I suggest that when I call first time execute2 it works as well as I want but I never finish that proces. Or I don 't undestand something

How to execute arbitrary pipes in c and continue

I'm trying to fork and then execute two or more piped commands in the child process. My idea is to use a while loop to continuously fork and execute the command in one process while continuing the loop in the other. Here's my code:
void
execute_pipe_command(command_t *c)
{
command_t command = *c;
pid_t pid = fork();
if(pid > 0) {
int status;
while(waitpid(pid, &status, 0) < 0)
continue;
if(!WIFEXITED(status))
error(1, errno, "Child exit error");
command->status = WEXITSTATUS(status);
return;
} else if (pid == 0) {
while(command->type == PIPE_COMMAND)
{
int fd[2]; pipe(fd);
pid = fork();
if(pid > 0) {
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
char **args = command->u.command[1]->u.word;
execvp(args[0], args);
} else if (pid == 0) {
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
command = command->u.command[0];
continue;
} else {
error(1, errno, "forking error");
}
}
char **args = command->u.word;
execvp(args[0], args);
} else {
error(1, errno, "forking error");
}
}
Command is a struct that hold it's type, and if it's a pipe command it holds left and right children commands. Otherwise if it's a simple command it holds an array of strings that make up the command.
When I call this function with a pipe command like ls | cat it should execute the commands, but instead it behaves weirdly. The first two piped commands will run but won't give control back to the program. Instead it'll hang. The subsequent commands are just ignored. So if I give this ls | cat | wc this function will print ls and won't exit until I give a SIGINT.
I'm pretty much confused as to what's going on. I'd appreciate if someone could point out the problem.
while (command->type == PIPE_COMMAND) is always true! This is way it hangs.

Resources