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.
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
sorry for the stupid question, im new to the world of linux and c..
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.
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.
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
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 u helped me so much already
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.