Linux: write a C program that 'controls' a shell - c

Suppose we have a shell running on terminal, let's say, /dev/pts/1. The shell is already running and we can't restart it.
Now we want to write a C program that will 'control' the shell, i.e. which will itself provide a shell-like interface to the user, read user's input, pass it on to the real shell on /dev/pts/1, have it execute it, read shell's output and print it back to the user.
I know how to do half of this task: I know how to gather user's input and inject this input to the 'real shell' :
#include <fcntl.h>
#include <sys/ioctl.h>
#include <stdio.h>
#define SIZE 100
int main(int argc, char** argv)
{
if( argc>1 )
{
int tty = open( argv[1], O_WRONLY|O_NONBLOCK);
if( tty!=-1 )
{
char *buf,buffer[SIZE+1];
while(1)
{
printf("> ");
fgets( buffer, SIZE, stdin );
if( buffer[0]=='q' && buffer[1]=='u' && buffer[2]=='i' && buffer[3]=='t' ) break;
for(buf=buffer; *buf!='\0'; buf++ ) ioctl(tty, TIOCSTI, buf);
}
close(tty);
}
else printf("Failed to open terminal %s\n", argv[1]);
}
return 0;
}
The above will pass on your input to shell running in terminal ( give its name in the first argument ) and have the shell execute it. However, I don't know how to read the shell's output now.
Any tips?

You can use pipes for that. Linux shells allow redirection.
I used pipes to control tty's.

There are programs that allow you to change the controlling terminal for a process: reptyr and injcode are two such programs.
I do believe that they sever the other terminal, however, so depending on your needs this may or may not fit exactly.

please take a look at libpipeline. maybe this will help you...

Related

How is the speed of printf affected by a presence of a forked process and '\n'?

I had this simple shell like program that works both in interactive and non-interactive mode. I have simplified the code as much as I can to present my question, but it is still a bit long, so sorry for that!
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
/**
*main-entry point for gbk
*Return: returns the index of 0 on sucess
*/
int main(void)
{
char *cmd = malloc(1 * sizeof(char)), *cmdargs[2];
size_t cmdlen = 0;
int childid, len;
struct stat cmdinfo;
while (1)
{
printf("#cisfun$ ");
len = getline(&cmd, &cmdlen, stdin);
if (len == -1)
{
free(cmd);
exit(-1);
}
/*replace the ending new line with \0*/
cmd[len - 1] = '\0';
cmdargs[0] = cmd;
cmdargs[1] = NULL;
childid = fork();
if (childid == 0)
{
if (stat(*cmdargs, &cmdinfo) == 0 && cmdinfo.st_mode & S_IXUSR)
execve(cmdargs[0], cmdargs, NULL);
else
printf("%s: command not found\n", *cmdargs);
exit(0);
}
else
wait(NULL);
}
free(cmd);
exit(EXIT_SUCCESS);
}
To summarize what this program does, it will first print the prompt #cisfun$ , waits for an input in interactive mode and takes the piped value in non-interactive mode, creates a child process, the child process checks if the string passed is a valid executable binary, and if it is, it executes it other wise it prints a command not found message and prompts again.
I have got this program to work fine for most of the scenarios in interactive mode, but when I run it in non-interactive mode all sorts of crazy (unexpected) things start to happen.
For example, when I run echo "/bin/ls"|./a.out, (a.out is the name of the compiled program)
you would first expect the #cisfun$ message to be printed since that is the first thing performed in the while loop, and then the output of the /bin/ls command, and finally #cisfun$ prompt, but that isn't what actually happens. Here is what happens,
It is very weird the ls command is run even before the first print message. I, at first, thought there was some threading going on and the printf was slower than the child process executing the ls command. But I am not sure if that is true as I am a noob. and also things get a bit crazier if I was printing a message with '\n' at the end rather than just a string. (if I change printf("#cisfun$ "); to printf("#cisfun$\n");) the following happens,
It works as it should, so it got me thinking what is the relation between '\n', fork and speed of printf. Just in short what is the explanation for this.
The second question I have is, why doesn't my program execute the first command and go to an interactive mode, I don't understand why it terminates after printing the second #cisfun$ message. By checking the status code (255) after exit I have realized that the effect is the same as pressing ctr+D in the interactive mode, which I believe is exited by the getline function. But I dont understand why EOF is being inserted in the second prompt.

Why isn't redirected input considered a command line argument?

I'm trying to read command line arguments that have been redirected from a file. The command I'm using is ./a.out < test.txt
And the contents of test.txt is: Hello world.
But the output of my program below isn't printing Hello
world. Instead it is only showing ./a.out. Why is this?
int main(int argc, char* argv[], char* envp[]) {
for (int i = 1; i < argc; i++) {
printf("%s\n", argv[i]);
}
}
The shell intercepts the redirection commands before preparing the command line for the program:
myProg <infile -t >outfile
will pass to the program
myProg -t
with stdin and stdout already rerouted before the pogram starts. So the program never sees the rediretion.
There a lot of cases, besides simple derirection:
dir > myfile.txt
Especially you can pipe output from one program to another:
dir | more
It will send output if dir command to more command. Since program launch handled by OS shell, it handles a redirection too.
Because the language is defined that way. Suppose what you say is true —
All the user input will have to come from command line arguments, but text redirected from a file can satisfy input required in different functions. This can be achieved if the input appears as command line arguments.
Consider this program:
#include <stdio.h>
int is_dict(char *word)
{
/* code to look up a dictionary */
int result = 1;
return result;
}
int main(int argc, char *argv[])
{
if(argc == 2 && is_dict(argv[1]))
printf("%s found", argv[1]);
return 0;
}
If the program is written that way to accommodate it, then the input would have to come from the command line arguments. How would you take input when it is not redirected? It would require more program overhead to detect the missing inputs.
Moreover, imagine a text file containing a million words: it is unfeasible to expect each word to arrive as an argv[n].
There are other objections too. Suppose the program prints a series of prompts for responses. The user would have to know in advance what the prompts are, to supply the answers before the prompts appear.
Lastly, if the program is run from a GUI, then all the program's input will have to be edited into its properties before it is run.

How many ways are there to execute system command in C program for windows

I am using MS visual studio 2008, for C coding.
I know we can use
"int system(const char *command)" to execute commands.
Is there any other method to execute system commands in C program.
Also I need to store output of executed command in a variable.
system() function execute command and send output to stdout , is there any way to read from stdout and store in variable.
So my ultimate goal is to execute system command in C program for windows (using visual studio) and store output of that command in a variable.
Any suggestions ?
Standard C libraries give you only one way to execute external command in OS, so use int system(const char *command).
You can save output of this command to text file, and then read this file from you program.
For example:
#include <stdio.h>
#include <stdlib.h>
#define TMP_FILE_NAME "TMP_FOLDER_CONTENT.txt"
int main(int argc, char *argv[])
{
system("dir C:\* > "TMP_FILE_NAME);
FILE * fdir = fopen(TMP_FILE_NAME, "r");
char buff[100];
if (fdir)
{
while (1) {
if (fgets(buff, 100, fdir) == NULL) break;
printf("%s", buff);
}
}
fclose(fdir);
remove(TMP_FILE_NAME);
return 0;
}
Where dir is a program to be executed, C:\* - argument of the program, and > - redirection of standard output for that command after which filename TMP_FOLDER_CONTENT.txt will be substituted.
Also you can check returned value, as:
int errorcode = system("dir C:\* > "TMP_FILE_NAME);
printf("Command executed and returned a value %d\n", errorcode);
or taking into account command you use, change the logic of your program, e.g.:
int errorcode = system("dir C:\* > "TMP_FILE_NAME);
if( errorcode )
{
return errorcode;
}
UPDATE:
Alternatively, you could use pipes in C++, for example as shown in the answer to question How to execute a command and get output of command within C++ using POSIX?
you can do as #VolAnd said or also if you don't care about/don't want the output of the command to be in stdout and you also don't want anything else to be printed to stdout you can use freopen to set stdout to a file of your choice.

How can i save all output to the screen while still displaying it?

I am currently writing a custom shell for a CS course.
It is a basic shell that reads in user input, and checks for shell functions, and then forks itself and passes the commands that were parsed to execvp().
I need to save the output from the screen into a text file while the shell is currently being run. I looked into freopen but that cut off all printing to the screen.
Can anyone give me a hint in which direction to look to perform this functionality?
You need something which will read from standard input and write same thing into both standard output as well standard error, that way you can print one, while save other in file.
Here is a simple implementation:
#include <stdio.h>
#include <unistd.h>
#define BUF_SIZE 1000
int main ()
{
char buffer[BUF_SIZE];
ssize_t read_size;
while ((read_size = read (STDIN_FILENO, buffer, BUF_SIZE)) > 0)
{
if (write (STDOUT_FILENO, buffer, read_size) <= 0 ||
write (STDERR_FILENO, buffer, read_size) <= 0)
return 1;
}
return 0;
}
If program is called dupl then you can do something like this
ls | ./dupl 2> file
This will display and as well save standard output of ls into file

Pass a string as standard input to an executable

I have count = read(pipe, buffer, buffsize); and am trying to run what is received (buffer) through another executable to have a differing process done on it.
printf("%s", buffer); prints it out correctly, but running it through execl("/path", "/path", buffer, NULL); or a number of other ways I've tried doesn't seem to run the executable. path is a compiled executable.
The executable does run properly if I use execv("./path", STDIN_FILENO);, but that isn't being taken from the pipe. path is expecting a the string as standard input.
The situation of the program is that I'm typing in input on one program using a while loop and read(), using a pipe to send that text to the program that is running execl (nothing else needs to be done in this program), that is then trying to call the executable with the string as an stdin. Only the intended input is coming in through the pipe, in chunks when the user presses enter.
An example of a string coming through the pipe is this is an example. The executable needs to have this inputted as standard input.
How can I get the string to be used as standard input for /path executable correctly?
It sounds like popen() is what you're looking for, to open a pipe to your desired executable so you can either pass stuff to its standard input, or read stuff from its standard output.
For instance:
#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
int main(void) {
FILE * p = popen("/bin/cat", "w");
if ( !p ) {
perror("error opening pipe");
return EXIT_FAILURE;
}
fputs("Echo me via /bin/cat\n", p);
if ( pclose(p) == -1 ) {
perror("error closing pipe");
return EXIT_FAILURE;
}
return 0;
}
which outputs:
paul#thoth:~/src/sandbox$ ./testpopen
Echo me via /bin/cat
paul#thoth:~/src/sandbox$

Resources