When Child process calls a function lost output - c

int handleCommand(char *command) {
pid_t pid;
pid = fork();
if (pid > 0) {
sleep(0.5);
} else if (pid == 0) {
execCommand(command);
//strcat(path[0], command);
//printf("%s", path[0]);
//execve(path[0], path, NULL);
//printf("\n");
} else {
printf("ERROR");
}
}
int execCommand(char *command) {
char* path[] = {"/bin/", NULL};
printf("in execCommand > %s", command );
strcat(path[0], command);
execve(path[0], path, NULL);
printf("\n");
}
at first as you can see i put the code directly in the function where the fork takes place. This would display the output expected when executing the ls command for example. But when I moved this to a function i no longer see any output.

First note that the printf() operations after the execve() are never executed if the command is executed - execve() only returns on error, never on success.
Next, unless you include a newline at the end of the output, the print won't be flushed to the terminal that is standard output (and there are circumstances, such as piping the standard output to another program, where even a newline is not necessarily sufficient to flush standard output). So, you should include a newline in the message, and still do fflush(stdout); before the execve().

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.

c - execl`d program doesn't give promt back

EDIT: THE QUESTION IS ANSWERED IN COMMENTS
So, i'm studying pipes. Long story short, i have two programs:
first program creates a pipe and two forks: first fork closes read descriptor and writes some stuff to write one (then closes it), second fork closes write one, dup2 on read side of pipe to standard input (end closes read side itself) and execl second program, giving a size of a text the first fork writes as an argument; the parent closes both pipe sides and waitpids for child that wasexecld (second one).
second program just reads from its standard input (pipe side) the stuff and writes it out to standard output, then closes pipe side just in case.
In such a setup everything works as I intended, but when I delete waitpid in first program (or just wait for the first child that writes instead of the second one), the second one behaves weirdly - it executes till the end, passing through all the IO (that is, the printf before exit got executed), and then doesn't give me the prompt back. That is, the terminal looks like the program awaits for an input from standard input. If i execute the first program without execl, then everything works fine, If I execute just the second one with one argument, then it waits only until input is provided to standard input (as it should as it is not a part of a pipe in this case).
As i know, when parent terminates, the child is "inherited" by init and got waited. But even if it wasn't, that is, even if it remained as a zombie, then it still would be weird - why i cannot get my prompt back until i wait explicitly?
The code is below (of the setup that works correctly):
First program
/* headers */
int main(void)
{
int fildes[2];
pid_t p1, p2;
int status;
char mess[] = "written from execved program!\n";
int buf = strlen(mess);
if(pipe(fildes) == -1) {
perror("pipe in main");
exit(EXIT_FAILURE);
}
p1 = fork();
if(p1 == -1) {
perror("fork p1 in main");
exit(EXIT_FAILURE);
}
else if (p1 == 0) {
printf("Child 1!\n");
close(fildes[0]);
write(fildes[1], mess, buf);
close(fildes[1]);
printf("Before exit in child 1!\n");
exit(EXIT_SUCCESS);
}
p2 = fork();
if(p2 == -1) {
perror("fork p2 in main");
exit(EXIT_FAILURE);
}
else if (p2 == 0) {
printf("Child 2!\n");
dup2(fildes[0], 0);
close(fildes[0]);
close(fildes[1]);
char s_buf[30];
sprintf(s_buf, "%d", buf);
execl("./pipe2slave", "pipe2slave", s_buf, (char *) 0);
perror("execl have returned");
exit(EXIT_FAILURE);
}
close(fildes[0]);
close(fildes[1]);
/*
below if I wait for, say, p1, or don't wait it all,
the weird behavior described in my question happens
*/
if(waitpid(p2, &status, 0) == -1) {
perror("waitpid in main");
exit(EXIT_FAILURE);
}
if(WIFEXITED(status))
printf("pipe2slave exit status is %d\n", WEXITSTATUS(status));
printf("End of main in pipe2!\n");
exit(EXIT_SUCCESS);
}
Second program
/* headers */
int main(int argc, char **argv)
{
if (argc != 2) {
perror("pipe2slave - not enough args");
exit(EXIT_FAILURE);
}
printf("program name is %s\n", argv[0]);
int buf = atoi(argv[1]);
printf("%d\n", buf);
char mess_in[buf];
read(0, mess_in, buf);
write(1, mess_in, buf);
fsync(1);
close(0);
printf("end of slave!\n");
exit(EXIT_SUCCESS);
}
Thank you in advance!

Piping/dup2() not working properly (Implementing Unix Shell in C)

I'll post my code first, then explain the problem I'm having:
#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <fcntl.h>
#define MAX_ARGS 20
#define BUFSIZE 1024
int get_args(char* cmdline, char* args[])
{
int i = 0;
/* if no args */
if((args[0] = strtok(cmdline, "\n\t ")) == NULL)
return 0;
while((args[++i] = strtok(NULL, "\n\t ")) != NULL) {
if(i >= MAX_ARGS) {
printf("Too many arguments!\n");
exit(1);
}
}
/* the last one is always NULL */
return i;
}
void execute(char* cmdline)
{
int pid, async, oneapp;
char* args[MAX_ARGS];
char* args2[] = {"-l", NULL};
int nargs = get_args(cmdline, args);
if(nargs <= 0) return;
if(!strcmp(args[0], "quit") || !strcmp(args[0], "exit")) {
exit(0);
}
printf("before the if\n");
printf("%s\n",args[nargs - 2]);
int i = 0;
// EDIT: THIS IS WHAT WAS SUPPOSED TO BE COMMENTED OUT
/*
while (args[i] != ">" && i < nargs - 1) {
printf("%s\n",args[i]);
i++;
}
*/
// Presence of ">" token in args
// causes errors in execvp() because ">" is not
// a built-in Unix command, so remove it from args
args[i - 1] = NULL;
printf("Escaped the while\n");
// File descriptor array for the pipe
int fd[2];
// PID for the forked process
pid_t fpid1;
// Open the pipe
pipe(fd);
// Here we fork
fpid1 = fork();
if (fpid1 < 0)
{
// The case where the fork fails
perror("Fork failed!\n");
exit(-1);
}
else if (fpid1 == 0)
{
//dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
//close(fd[0]);
// File pointer for the file that'll be written to
FILE * file;
// freopen() redirects stdin to args[nargs - 1],
// which contains the name of the file we're writing to
file = freopen(args[nargs - 1], "w+", stdin);
// If we include this line, the functionality works
//execvp(args[0],args);
// We're done writing to the file, so close it
fclose(file);
// We're done using the pipe, so close it (unnecessary?)
//close(fd[1]);
}
else
{
// Wait for the child process to terminate
wait(0);
printf("This is the parent\n");
// Connect write end of pipe (fd[1]) to standard output
dup2(fd[1], STDOUT_FILENO);
// We don't need the read end, so close it
close(fd[0]);
// args[0] contains the command "ls", which is
// what we want to execute
execvp(args[0], args);
// This is just a test line I was using before to check
// whether anything was being written to stdout at all
printf("Exec was here\n");
}
// This is here to make sure program execution
// doesn't continue into the original code, which
// currently causes errors due to incomplete functionality
exit(0);
/* check if async call */
printf("Async call part\n");
if(!strcmp(args[nargs-1], "&")) { async = 1; args[--nargs] = 0; }
else async = 0;
pid = fork();
if(pid == 0) { /* child process */
execvp(args[0], args);
/* return only when exec fails */
perror("exec failed");
exit(-1);
} else if(pid > 0) { /* parent process */
if(!async) waitpid(pid, NULL, 0);
else printf("this is an async call\n");
} else { /* error occurred */
perror("fork failed");
exit(1);
}
}
int main (int argc, char* argv [])
{
char cmdline[BUFSIZE];
for(;;) {
printf("COP4338$ ");
if(fgets(cmdline, BUFSIZE, stdin) == NULL) {
perror("fgets failed");
exit(1);
}
execute(cmdline) ;
}
return 0;
}
So, what's the problem? Simple: the code above creates a file with the expected name, i.e. the name provided in the command line, which gets placed at args[nargs - 1]. For instance, running the program and then typing
ls > test.txt
Creates a file called test.txt... but it doesn't actually write anything to it. I did manage to get the program to print garbage characters to the file more than a few times, but this only happened during bouts of desperate hail mary coding where I was basically just trying to get the program to write SOMETHING to the file.
I do think I've managed to narrow down the cause of the problems to this area of the code:
else if (fpid1 == 0)
{
printf("This is the child.\n");
//dup2(fd[1], STDOUT_FILENO);
close(fd[1]);
//close(fd[0]);
// File pointer for the file that'll be written to
FILE * file;
// freopen() redirects stdin to args[nargs - 1],
// which contains the name of the file we're writing to
file = freopen(args[nargs - 1], "w+", stdout);
// If we include this line, the functionality works
//execvp(args[0],args);
// We're done writing to the file, so close it
fclose(file);
// We're done using the pipe, so close it (unnecessary?)
//close(fd[1]);
}
else
{
// Wait for the child process to terminate
wait(0);
printf("This is the parent\n");
// Connect write end of pipe (fd[1]) to standard output
dup2(fd[1], STDOUT_FILENO);
// We don't need the read end, so close it
close(fd[0]);
// args[0] contains the command "ls", which is
// what we want to execute
execvp(args[0], args);
// This is just a test line I was using before to check
// whether anything was being written to stdout at all
printf("Exec was here\n");
}
More specifically, I believe the problem is with the way I'm using (or trying to use) dup2() and the piping functionality. I basically found this out by process of elimination. I spent a few hours commenting things out, moving code around, adding and removing test code, and I've found the following things:
1.) Removing the calls to dup2() and using execvp(args[0], args) prints the result of the ls command to the console. The parent and child processes begin and end properly. So, the calls to execvp() are working properly.
2.) The line
file = freopen(args[nargs - 1], "w+", stdout)
Successfully creates a file with the correct name, so the call to freopen() isn't failing. While this doesn't immediately prove that this function is working properly as it's written now, consider fact #3:
3.) In the child process block, if we make freopen redirect to the output file from stdin (rather than stdout) and uncomment the call to execvp(args[0], args), like so:
// freopen() redirects stdin to args[nargs - 1],
// which contains the name of the file we're writing to
file = freopen(args[nargs - 1], "w+", stdin);
// If we include this line, the functionality works
execvp(args[0],args);
and run the program, then it works and result of the ls command is successfully written to the output file. Knowing this, it seems pretty safe to say that freopen() isn't the problem either.
In other words, the only thing I haven't been able to successfully do is pipe the output of the execvp() call that's done in the parent process to stdout, and then from stdout to the file using freopen().
Any help is appreciated. I've been at this since 10 AM yesterday and I'm completely out of ideas. I just don't know what I'm doing wrong. Why isn't this working?

Trouble creating a C program using fork() and execvp() functions

Here is the following code I am current having issues with:
#include <stdio.h>
#include <unistd.h>
#include<sys/types.h>
#include<sys/wait.h>
#define MAX_LINE 80
int main(void)
{
char *args[MAX_LINE/2+1];
int background= 0;//integer that acts a boolean for if & appears
int should_run = 1;
int status;
while(should_run)//Just to keep the interface going until the user chooses to stop
{
printf("osh>");//prompt
fflush(stdout);
int i = 0;
while(getchar() != '\n')//Use scanf until a new line is found
{
scanf("%s", &args[i]);
if(strcmp(&args[i], "exit") == 0)//temporary exit protocal
{
printf("Exiting now...");
return 0;
}
if(strcmp(&args[i], "&") == 0)//If we find a & in our input then we changed background to 1 or true
background = 1;
printf("Args[%i] = %s\n", i, &args[i]);//Tester
i++;
}
printf("Background = %i\n",background);//Test
pid_t pid= fork();// Create new child process
printf("process %i created\n", pid);//Test
if(pid < 0)//fork() failed
{
printf("Fork Failed.\n");
return 1;
}
else if(pid == 0)//Child process id
{
printf("Child process started %s command\n", &args[0]);
if(execvp(args[0], args) < 0)//change the current child process to execute the input given by the user
//with args[0] being the command and args being the parameters(ls -l is an example).
{
printf("Command failed\n");
}
return 0;
}
else//Parent Process
{
if(background == 1)//If the user typed in a & then the parent will wait for a change in state from the child, if there is no &
//then we will just finish the parent process
{
printf("Parent process waiting on child\n");
wait(NULL);
}
}
}
return 0;
I have one major issue and one minor issue right now. The major issue is that I have a printf method before execvp starts that says "Child Process started" and I get this line to print, but then nothing else happens. No interrupts are thrown, the program just seems to be frozen on my execvp command.
My minor issue is that when my program starts a prompt "osh>" before asking for input. Now if, for example, I would type in "osh>ls -l" then I get args[0] = s, args1 = -l. Now if I put "osh> ls -l" in that exact format I get args[0] = ls, args1 = -l. Is that a part of scanf() that I am not using properly here to make sure I get ever character after "osh>" and between blank spaces as strings?
EDIT:
here is my output for user input "ls -l"
The problem you're having with the missing character is because getchar() is consuming the first character of your input before scanf gets to take a stab at it. You probably want to do something like:
while (scanf("%s", &buffer) > 0)
{
strcpy(args[i], buffer);
/* then do stuff with args[i] */
}

How to catch the ouput from a execl command

I'm using the execl function to run a Linux process from C. When I do, for example:
int cmd_quem() {
int result;
result = fork();
if(result < 0) {
exit(-1);
}
if (result == 0) {
execl("/usr/bin/who", "who", NULL);
sleep(4); //checking if father is being polite
exit(1);
}
else {
// father's time
wait();
}
return 0;
}
I get on the console the result of doing "who" on the terminal. What I'd like to know is if there is any function to "catch" the output result from a command. What I mean is, if there is anyway to catch this:
feuplive tty5 2009-11-21 18:20
Which is one of the lines resulting from the who command.
To do this, you need to open a pipe. You then replace the child's stdout with the writing end of the pipe, and read from the reading end of the pipe in the parent. Like this modified version of your code:
int cmd_quem(void) {
int result;
int pipefd[2];
FILE *cmd_output;
char buf[1024];
int status;
result = pipe(pipefd);
if (result < 0) {
perror("pipe");
exit(-1);
}
result = fork();
if(result < 0) {
exit(-1);
}
if (result == 0) {
dup2(pipefd[1], STDOUT_FILENO); /* Duplicate writing end to stdout */
close(pipefd[0]);
close(pipefd[1]);
execl("/usr/bin/who", "who", NULL);
_exit(1);
}
/* Parent process */
close(pipefd[1]); /* Close writing end of pipe */
cmd_output = fdopen(pipefd[0], "r");
if (fgets(buf, sizeof buf, cmd_output)) {
printf("Data from who command: %s\n", buf);
} else {
printf("No data received.\n");
}
wait(&status);
printf("Child exit status = %d\n", status);
return 0;
}
First, execl does not return unless there's a problem like the executable is not found. That sleep(4) is probably never executed.
As for redirecting and getting the output, check out the Unix Programming FAQ. Look for spawn_background_command.
The exec() family of functions creates a new process image from a regular, executable file. This file is either an executable object file, or an interpreter script. There is no return from a successful call to an exec() function, because the calling process is functionally replaced by the new process.
So any code after exec() is never executed unless it is failed.
If you want to capture output of a shell command you need popen.

Resources