Getting all output from terminal in C - c

I am currently working on a ssh program and I want to be able to have full control over the terminal via networking. My question is, if I send a command to the server to run in the terminal, how do I get the output that the terminal prints? I have seen many posts saying to use the popen() command but from what I have tried I can't change directories and do other commands using this, only simple things such as ls. Is there any other way to get output from terminal besides sending it to a file like command > filetoholdcommand. Thanks in advance!

I would put this as a comment, but I dont have enough rep as I'm new. cd is a built in shell command so you want to use system(). But cd will have no effect on your process (you have to use chdir(), for that),so what you really want to do is start a shell as a subprocess via fork/exec, connect pipes to it stdin and stdout,then pipe it commands for the duration of the user session or connection.
Following code give the general idea. Basic, and flawed - use select() not usleep() for one.
int argc2;
printf( "Server started - %d\n", getpid() );
char buf[1024] = {0};
int pid;
int pipe_fd_1[2];
int pipe_fd_2[2];
pipe( pipe_fd_1 );
pipe( pipe_fd_2 );
switch ( pid = fork() )
{
case -1:
exit(1);
case 0: /* child */
close(pipe_fd_1[1]);
close(pipe_fd_2[0]);
dup2( pipe_fd_1[0], STDIN_FILENO );
dup2( pipe_fd_2[1], STDOUT_FILENO );
execlp("/bin/bash", "bash", NULL);
default: /* parent */
close(pipe_fd_1[0]);
close(pipe_fd_2[1]);
fcntl(pipe_fd_2[0], F_SETFL, fcntl(pipe_fd_2[0], F_GETFL, NULL ) | O_NONBLOCK );
while(true)
{
int r = 0;
printf( "Enter cmd:\n" );
r = read( STDIN_FILENO, &buf, 1024 );
if( r > 1 )
{
buf[r] = '\0';
write(pipe_fd_1[1], &buf, r);
}
usleep(100000);
while( ( r = read( pipe_fd_2[0], &buf, 1024 ) ) > 0 )
{
buf[r-1] = '\0';
printf("%s", buf );
}
printf("\n");
}
}

You want the "popen" function. Here's an example of running the command ls /etc and outputting to the console.
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
FILE *fp;
int status;
char path[1035];
/* Open the command for reading. */
fp = popen("/bin/ls /etc/", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit;
}
/* Read the output a line at a time - output it. */
while (fgets(path, sizeof(path), fp) != NULL) {
printf("%s", path);
}
/* close */
pclose(fp);
return 0;
}

Related

Redirecting stdin and stdout?

So im trying to redirect the I/O to read command from file then when user runs the output command it will print the compiled command to output file.
For example on the terminal:
./run 2 < test.txt // This would take file using dup and take the input
Then when you want to output the compile:
./run 1 > output.txt // and it would put into an output file
So far i know how to output to a file but my problem is with the input. how do i get the command from the file using the dup2() function? I tried researching this but no luck.
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <unistd.h>
char inputForOutput[100];
void functionOutput(int argc, char **argv){
int ofd; //Init of file desc.
ofd = open(argv[1], O_CREAT|O_TRUNC|O_WRONLY);
dup2(ofd, 1);//Duplicates to stdout
system("ls");//Copies commnd given to output_file
}
//Function is called when argument number is == 1
void functionInput(int argc, char **argv){
FILE *ifd;
printf("\n %s \n ", argv[2]);
ifd = fopen(argv[2] , "r");
if (ifd == NULL){
perror("No file found");
exit(1);
}
fscanf(ifd,"%s",inputForOutput);
printf("\n**%s**\n",inputForOutput);
}
int main(int argc, char **argv)
{
int output;
int input;
output = strcmp("1", argv[1]);
input = strcmp("2" ,argv[1]);
if (output == 0 ) { //Fail safe for number of arguments
functionOutput(argc, argv);
}
else if ( input == 0){
functionInput(argc, argv);
}
else{
fprintf(stderr, "How to use: %s function output_file\n", argv[0]); // FAIL SAFE IF INPUT DOES NOT MATCH BOTH FUNCTIONS
}
return 0;
}
To redirect input and output, use this format
myprogram > out.txt < in.txt //read from in.txt, write to out.txt
myprogram < in.txt > out.txt //read from in.txt, write to out.txt
myprogram < in.txt //redirect stdin only
myprogram > out.txt //redirect stdout only
myprogram //no redirection
...
This should work with any program. Example:
int main(void)
{
char buf[1000];
if(fgets(buf, sizeof(buf), stdin))
printf("write: %s\n", buf);
return 0;
}
To redirect stdin/stdout in the program, use the standard method
freopen("output.txt", "w", stdout);
printf("Testing...");
fclose(stdout);
freopen("input.txt", "r", stdin);
char buf[100];
fgets(buf, sizeof(buf), stdin);
fclose(stdin);
Alternatively, set FILE *fin = stdin; FILE* fout = stdout; to redirect the opposite way.
Next, to write a program using argv elements, always test argc first. The code below shows an example.
#include <stdio.h>
#include <string.h>
int redirect(int argc, char **argv, int *index)
{
//no more redirection!
if(*index >= argc)
return 1;
//not enough parameters
if(*index + 1 >= argc)
{
printf("wrong usage\n");
return 0;
}
if(strcmp(argv[*index], "<") == 0)
{
*index++; //next parameter is to redirect input
if(!freopen(argv[*index], "r", stdin))
printf("error, redirect input failed");
}
else if(strcmp(argv[*index], ">") == 0)
{
*index++; //next parameter is to redirect output
if(!freopen(argv[*index], "w", stdout))
printf("error, redirect output failed");
}
else
{
printf("wrong usage\n");
return 0;
}
return 1;
}
int main(int argc, char **argv)
{
int index = 1;
if(!redirect(argc, argv, &index))
return 1;
if(!redirect(argc, argv, &index))
return 1;
//read
char buf[1000];
if(fgets(buf, sizeof(buf), stdin))
{
//write
printf("write: %s\n", buf);
}
fclose(stdin);
fclose(stdout);
return 0;
}
With functionOutput() you have a good first attempt at capturing the output of a system command to a file. Actually, that is the function called when the first argument is 1, so you might want to update your comment. Also, you're creating a file with the name stored in argv[1], which we already know is 1 so it's probably not doing what you expect, and you probably want:
ofd = open(argv[2], O_CREAT|O_TRUNC|O_WRONLY);
With functionInput() you're reading the first non-whitespace entry from the file. If you're telling it to read the file which you output using the functionOutput() function, that is likely to be (some of) the name of the first file which was listed by ls.
I'm finding it unclear what you're wanting to do which isn't that. If you want to find out what the command was which you ran to generate the output, that information is not available from the file itself, because you didn't write it there. If that's what you want, you may want to consider writing the command as the first line of the file, followed by the output. Then when you read it, you can assume that the first line is the command run, followed by the output of that command.
If I understand your question, and you want to run your program in essentially two different modes, (1) you want to take input if there is input to be taken on stdin; and (2) if there is no input waiting, you want to do an output, then select/pselect or poll are what you are looking for.
For example select allows you to check whether there is input ready to be read on a file descriptor (or set of descriptors) and it will return the number of descriptors with input waiting (or -1 and set errno on error). You could simply use the STDIN_FILENO (a/k/a fd 0) to check if there is input on stdin, e.g.
#include <stdio.h>
#include <unistd.h> /* for STDIN_FILENO */
#include <sys/select.h> /* for pselect */
int input (int filedes)
{
fd_set set;
/* declare/initialize zero timeout */
struct timespec timeout = { .tv_sec = 0 };
/* Initialize the file descriptor set. */
FD_ZERO (&set);
FD_SET (filedes, &set);
/* check whether input is ready on filedes */
return pselect (filedes + 1, &set, NULL, NULL, &timeout, NULL);
}
int main (void)
{
if (input (STDIN_FILENO))
puts ("doing input routine");
else
puts ("doing output routine");
return 0;
}
(note: from the man page "select() uses a timeout that is a struct timeval (with seconds and microseconds), while pselect() uses a struct timespec (with seconds and nanoseconds).")
Example Use/Output
$ ./bin/select_peekstdin < file
doing input routine
$ ./bin/select_peekstdin
doing output routine

how to get the output of a terminal command into a C string [duplicate]

I am currently working on a ssh program and I want to be able to have full control over the terminal via networking. My question is, if I send a command to the server to run in the terminal, how do I get the output that the terminal prints? I have seen many posts saying to use the popen() command but from what I have tried I can't change directories and do other commands using this, only simple things such as ls. Is there any other way to get output from terminal besides sending it to a file like command > filetoholdcommand. Thanks in advance!
I would put this as a comment, but I dont have enough rep as I'm new. cd is a built in shell command so you want to use system(). But cd will have no effect on your process (you have to use chdir(), for that),so what you really want to do is start a shell as a subprocess via fork/exec, connect pipes to it stdin and stdout,then pipe it commands for the duration of the user session or connection.
Following code give the general idea. Basic, and flawed - use select() not usleep() for one.
int argc2;
printf( "Server started - %d\n", getpid() );
char buf[1024] = {0};
int pid;
int pipe_fd_1[2];
int pipe_fd_2[2];
pipe( pipe_fd_1 );
pipe( pipe_fd_2 );
switch ( pid = fork() )
{
case -1:
exit(1);
case 0: /* child */
close(pipe_fd_1[1]);
close(pipe_fd_2[0]);
dup2( pipe_fd_1[0], STDIN_FILENO );
dup2( pipe_fd_2[1], STDOUT_FILENO );
execlp("/bin/bash", "bash", NULL);
default: /* parent */
close(pipe_fd_1[0]);
close(pipe_fd_2[1]);
fcntl(pipe_fd_2[0], F_SETFL, fcntl(pipe_fd_2[0], F_GETFL, NULL ) | O_NONBLOCK );
while(true)
{
int r = 0;
printf( "Enter cmd:\n" );
r = read( STDIN_FILENO, &buf, 1024 );
if( r > 1 )
{
buf[r] = '\0';
write(pipe_fd_1[1], &buf, r);
}
usleep(100000);
while( ( r = read( pipe_fd_2[0], &buf, 1024 ) ) > 0 )
{
buf[r-1] = '\0';
printf("%s", buf );
}
printf("\n");
}
}
You want the "popen" function. Here's an example of running the command ls /etc and outputting to the console.
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
FILE *fp;
int status;
char path[1035];
/* Open the command for reading. */
fp = popen("/bin/ls /etc/", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit;
}
/* Read the output a line at a time - output it. */
while (fgets(path, sizeof(path), fp) != NULL) {
printf("%s", path);
}
/* close */
pclose(fp);
return 0;
}

pipe "closing" after fclose()

int fd[2];
void write_to_pipe(char* str)
{
int file = fd[1];
FILE *stream;
//printf("writing to pipe : %s\n", str);
stream = fdopen(file, "w");
//printf("fdopen returned : %d\n",(int)stream);
fprintf(stream, "%s", str);
fclose(stream);
}
At main() : pipe(fd);
If I call write_to_pipe first then it works perfectly fine.
If the function is called second time then fdopen fails(returns 0).
I assumed the stream/pipe/somthing is closed
What is the safe way to "not close the pipe" and call the function multiple times
Compiler : gcc 6.3.1
p.s.
This read function could have similar problem too.
char* read_from_pipe()
{
int file = fd[0];
static char buf[100];
FILE *stream;
stream = fdopen(file, "r");
read(file,buf,100);
fclose(stream);
return buf;
}
Standard C doesn't know POSIX file descriptors, only FILE * is standard, and fclose() closes the file. This of course implies to do whatever is necessary on the platform to close the file, so in this case, calling close() on the underlying descriptor.
What you should do is just use FILE * wherever appropriate. So if you need a pipe as a backend for your FILE *, fdopen() the file right after creating the pipe. This way, you have your platform-specific code in a single place.
If you happen to need the file descriptor for anything else than closing the pipe, you can use fileno() on the FILE *, but then you have another platform-dependent part in your code.
What is the safe way to "not close the pipe" and call the function multiple times
Don't use fdopen() on the file descriptor:
void write_to_pipe(char* str)
{
write( fd[ 1 ], str, strlen( str ) );
}
or use fdopen() at the same scope as the pipe itself:
int fd[2];
.
.
.
FILE *stream = fdopen( fd[ 1 ] );
.
.
.
void write_to_pipe(char* str)
{
fprintf(stream, "%s", str);
}
You could dup the file descriptor and perform the fdopen on the duplicate.
int write_to_pipe(char* str)
{
int file = dup(fd[1]);
if(0>file)
return -1;
FILE *stream;
//...
}
In any case, your function should probably return an integer so that it could signal possible errors that might occur inside the function.
You are closing the stdout file descriptor, which closes the pipe. Open it once and keep it around until you are finished.
this function:
char* read_from_pipe()
{
int file = fd[0];
static char buf[100];
FILE *stream;
stream = fdopen(file, "r");
read(file,buf,100);
fclose(stream);
return buf;
}
contains several problems.
Suggest writing it similar to:
#define MAX_BUF_LEN 100
char* read_from_pipe()
{
static char buf[ MAX_BUF_LEN +1 ];
ssize_t byteCount = read( fd[0], buf, MAX_BUF_LEN );
if( 0 > byteCount )
{ // an error occurred
perror( "read from pipe failed" );
buf[0] = '\0';
}
else if( 0 == byteCount )
{
fprintf( stderr, "no bytes read\n" );
buf[0] = '\0';
}
else
{
buf[byteCount] = '\0';
}
return buf;
} // end function: read_from_pipe
Note: read() does not terminate the char array, so the code has to do that And the array has to be 1 char longer than the max number of characters ask for in the read() statement.
Note: the syntax for read() wants a int, not FILE* for its' first parameter. Here is the proper syntax:
ssize_t read(int fd, void *buf, size_t count);
this function:
int fd[2];
void write_to_pipe(char* str)
{
int file = fd[1];
FILE *stream;
//printf("writing to pipe : %s\n", str);
stream = fdopen(file, "w");
//printf("fdopen returned : %d\n",(int)stream);
fprintf(stream, "%s", str);
fclose(stream);
}
leaves a lot to be desired.
Suggest something similar to:
int fd[2]; << in file scope, so visible from functions
void write_to_pipe(char* str)
{
//printf("writing to pipe : %s\n", str);
ssize_t bytesWritten = write( fd[1], str, strlen(str) );
if( strlen(str) != bytesWritten )
{
fprintf( stderr, "write to pipe failed to write all bytes\n" );
}
else if( 0 > bytesWritten )
{
perror( "write to pipe failed" );
}
} // end function: write_to_pipe
Duplicate the descriptor and use the duplicate in the fdopen call.

Reading and writing(at back) simultaneously in a fifo

I'm trying to copy the contents of a file1 into other file2 through fifo. The first four characters I want to write back in the fifo (during reading, not earlier when writing contents from file1 to fifo) and then copy it in the file2 also. But the first four characters don't get appended at back but they get inserted randomly in the middle. My code is
int main( int argc, char* argv[] ) {
int fdes,fdes1;
pid_t pid;
ssize_t numRead;
char readBuff[1];
char writeBuff[1];
int readCounter;
int c=0;
umask(0);
if (mkfifo("ajjp.e",0666) == -1 /*make the fifo*/
&& errno != EEXIST)
{}
if( argc < 3 ) {
printf( "Atleast need 2 params " );
exit(1);
}
int to_copy = open( argv[1], 0 );/* file from which contents are to be copied */
int oo = creat(argv[2], 0666);/* file created where we've to write contents*/
if ( to_copy == -1 ) {
printf( "Opening file failed " );
exit(1);
}
if ( (pid = fork()) < 0) /* child process is made*/
perror("fork error");
/* in parent process,I'm cwriting contents of file1 to fifo character by character */
else if(pid>0)
{
fdes = open("ajjp.e", O_WRONLY);
while( (readCounter = read( to_copy, readBuff, sizeof( readBuff ) ) > 0 ) ) {
write( fdes, readBuff, sizeof( readBuff ) );
}
close(to_copy);
}
/* now, in child process, I opened its read end then I'm reading contents from fifo and writing it to file2(i.e copy_to here) but for first four characters( c< 5 here), I'm writing them to fifo also by opening its write end. */
else
{
fdes1 = open("ajjp.e", O_RDONLY);
fdes = open("ajjp.e", O_WRONLY);
if (signal(SIGPIPE, SIG_IGN) == SIG_ERR)
printf("signal");
int copy_to = open( argv[2], 0666);/* opened the file where we've to write*/
if ( copy_to == -1 ) {
printf( "Opening file failed " );
exit(1);
}
for(;;) {
c++;
numRead = read(fdes1, readBuff, sizeof(readBuff));/* reading from read end of fifo*/
if (numRead == 0)
break;
/* write to the file2*/
if (write(copy_to, readBuff, numRead) != numRead)
{}
/* for first 4 characters, I am rewriting to the back of fifo*/
if(c<5)
{
write(fdes,readBuff,sizeof(readBuff));
}
/*after writing those 4 characters, write end I've closed*/
if(c==5)
close(fdes);
}
close(fdes);
close(fdes1);
}//end else
return 0;
}
Now, if on terminal, I run
$ ./a.out a.txt b.txt
I want to copy from a.txt to b.txt, b.txt contains a.txt plus first 4 characters inserted randomly between characters.
You've got some logic problems and synchronization problems. Your goal isn't too clear, but it seems like you want to copy a file, say "Hello World" and in the copy, it should have "Hello World" but also have "Hell" sprinkled in. So, maybe "HelHleo llWorld"?
Computers are fast and can buffer and do quite a lot at once. Your child process may not even execute until after the parent is completely done because it takes a bit of time to start a new process. As such you are probably getting "Hello WorldHell". That is, the parent totally copies the file to the FIFO before the child even starts reading. You need to look into some synchronization methods. For example, using the tools you have, you could make another fifo. Have the parent wait until it can read from it. Have the child write to it when it is loaded as a way to tell the parent it is ready to go. Making your file really really large might also give the child time to start or adding sleep statements after each character.
It would be easier to speculate if you had provided your input file as well as your output(the wrong output). But, basically, you have a multi-process/multi-threading problem where you want them to operate together but they really end up running one at a time. Slow down the parent or make it wait for the child.

Not able to close the file open using popen

I'm new to C language and today, i am facing a problem while i am trying to close the "Open Stream" created by using the popen function.
1. Is this problem seeing, because of the poll function that i used in this program?
2. Or because of the fcntl function?
I will be very happy, if somebody teach me the exact cause of this issue. I am attaching the code sample below, please have a look.
Code Sample:
#include <stdio.h>
#include <stdlib.h>
#include <poll.h>
#include <fcntl.h>
char line[1024];
FILE *tfd;
int readData(int *fd)
{
struct pollfd pfd;
int pollTime = 10000;
pfd.events = POLLIN;
pfd.fd = *fd;
int ret=1;
ret = poll(&pfd,1,pollTime);
printf("\nAfter ret=%d\n.",ret);
if(ret == -1 || ret ==0)
{
printf("Couldn't poll returned : %d\n", ret);
return 0;
} else {
if( fgets(line,sizeof(line),tfd) == NULL )
{
printf("\nReturns nothing.");
return 0;
}
printf("\nRead Some data.");
}
return ret;
}
void main(void)
{
int ret;
int fd, flags;
char filepath[] = "/home/TEST/";
char filename[] = "log.txt";
char cmd[100];
sprintf(cmd,"tail -f %s%s",filepath, filename);
tfd = popen(cmd, "r");
fd = fileno(tfd);
flags = fcntl(fd, F_GETFL, 0);
flags |= O_NONBLOCK;
fcntl(fd, F_SETFL, flags);
if(tfd==NULL)
{
printf("\npopen failed, exiting.\n");
exit(0);
}
while( (ret=readData(&fd)) > 0 )
{
printf("\nret2=%d.",ret);
printf("\nLine : %s",line);
}
printf("\n**********DONE****************.\n");
pclose(tfd);
}
output:
[root#localhost TEST]# ./polltail
After ret=1
.
Read Some data.
ret2=1.
Line : 64 bytes from maa03s05-in-f4.1e100.net (74.125.236.68): icmp_req=31 ttl=52 time=38.4 ms
After ret=0
.Couldn't poll returned : 0
**********DONE****************.
Here i am expecting the prompt to appear at the end of the execution. But, it is not coming.
You're getting a timeout, because tail didn't produce any output for 10 seconds. Then you call pclose() , however, this is what the documentation says about pclose().
The pclose() function waits for the associated process to terminate and returns the exit status of the command as returned by wait4(2).
The tail command is still running, and will continue to do so until someone kills it, so pclose() will block indefinitely. If you need your program to kill the tail command you're running, you'll need another approach than using popen/pclose.
The -f option causes tail to not stop when end of file is
reached, but rather to wait for additional data to be appended to
the input. The -f option is ignored if the standard input is a
pipe, but not if it is a FIFO.
The pclose() function waits for the associated process to terminate; it
returns the exit status of the command, as returned by wait4(2).
The pclose() function returns -1 if stream is not associated with a
"popened" command, if stream already "pclosed", or if wait4(2)
returns an error.
Check the return value of pclose().

Resources