Interacting with a Shell using C - c

I have a binary called TEST which spawns a bash shell, I was hoping to write a C program that runs TEST and then passes commands to the bash shell that it spawns - I have tried the following - can someone indicate if this is possible. I can run the file using, but don't know how to then pass commands to shell it spawns:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main()
{
system("/var/testfolder/TEST"); #run the test file
return 0;
}

The UNIX styled popen() function is what you want to use.
See the man page for specifics.
It runs your command in a subprocess and gives you a pipe to interact with it. It returns a FILE handle like fopen() does, but you close it with pclose() rather than fclose(). Otherwise you can interact with the pipe the same way as for a file stream. Very easy to use and useful.
Here's a link to a use case example
Also check out this example illustrating a way to do what you are trying to do:
#include <stdio.h>
int main(void) {
FILE *in;
extern FILE *popen();
char buf[512];
if (!(in = popen("ls -sail", "r")))
exit(1);
while (fgets(buf, sizeof(buf), in) != NULL)
printf("%s", buf);
pclose(in);
}

Related

Load script from memory in C

I have a script starting with a shebang stored in a string. I would like to execute this script without writing it in a temporary file.
I saw that execve takes a filename as argument. Is it possible to do the same with a script in memory.
A script is not directly executable, when executing a script, the kernel identify which interpreter to launch then pass the file name as an argument to the interpreter, in your case a shell.
Should you want to execute a script stored in a string, you might directly launch the shell of your choice and pass your string as its standard input through a pipe.
Here is way to do it using popen:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
FILE *fp;
char *prefix="/bin/bash <<'%EOF%'\n";
char *script="#!/bin/bash\necho foo\ndate\n";
char *suffix="%EOF%\n";
char *command;
char buf[1024];
command=malloc(strlen(prefix)+strlen(script)+strlen(suffix)+1);
sprintf(command,"%s%s%s",prefix,script,suffix);
fp=popen(command, "r");
if(fp == NULL) {
perror("Error\n");
exit(1);
}
while(fgets(buf, sizeof(buf), fp) != NULL) {
printf("%s", buf);
}
pclose(fp);
return 0;
}
As you say that the script starts with a shebang string, you cannot directly pipe it into the standard input of a shell. But you can mimic what a shell would have done:
extract the shell command from the shebang line
start it with a pipe as standard input
pipe the remaining of the script into that shell command
A more generalist version would control whether the script string starts with a #!. If it does, use the above way, else just pipe the whole string into an instance of /bin/sh (or whatever shell you are used to)

Prevent popen() from displaying error on stderr

I have the following code to find the release of the Linux distribution that I am using.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
return print_osinfo();
}
int print_osinfo()
{
FILE *fp;
extern FILE* popen();
char buffer[128];
int index = 0;
memset(buffer,0,sizeof(buffer));
fp = popen("/etc/centos-release", "r");
if(!fp)
{
pclose(fp);
fp = popen("/etc/redhat-release", "r");
if(!fp)
{
pclose(fp);
return 1;
}
}
while(fgets(buffer, sizeof(buffer), fp)!= NULL)
{
printf("%s\n",buffer);
}
pclose(fp);
return 0;
}
If I run the above code on Ubuntu 14.04 I get the following error.
sh: 1: /etc/centos-release: not found
I fail to understand why it is not trying to open redhat-release and then return -1. Also, is there a way to prevent the above error from being displayed on the screen?
popen is a function more suited for accessing the output of a subprocess than for simply accessing the contents of a file. For that, you should use fopen. fopen takes a file path and a mode as arguments, so all you would need to do is replace your popens with fopens and it should work perfectly.
If you really want to use popen, it takes a shell command as it's first argument, not a filename. Try popen("cat /etc/centos-release","r"); instead.
Now, you might be a bit confused, because both of these functions return a FILE pointer. fopen returns a pointer to the file you passed as an argument. popen, however, returns a pipe pointing to the output of the command you passed to it, which C sees as a FILE pointer. This is because, in C, all i/o is file access; C's only connection to the outside world is through files. So, in order to pass the output of some shell command, popen creates what C sees as a FILE in memory, containing the output of said shell command. Since it is rather absurd to run a whole other program (the shell command) just to do what fopen does perfectly well, it makes far more sense to just use fopen to read from files that already exist on disk.

Output of the Linux System Call in C program

I want to manipulate the output of the ls -al command in my C program.
Is there a way to do it ?
int main()
{
int return_value;
return_value = system("ls -al ");
return return_value;
}
You need a pipe to the process.
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *fp;
char output[1024];
fp = popen("/bin/ls -al", "r");
if (fp == NULL)
exit(1);
while (fgets(output, 1023, fp) != NULL)
printf("%s", output);
pclose(fp);
return 0;
}
You could use popen(3) on /bin/ls as answered by Baris Demiray.
But in your particular case (getting the files in a directory), you don't really need to start some external process running ls, you could simply use opendir(3) & readdir(3) to read the directory entries, and use stat(2) on each of them (you'll build the path using snprintf(3)). See also glob(7), nftw(3) and read Advanced Linux Programming
Notice that the system(3) is a very poorly named standard C library function. It is not a direct system call (they are listed in syscalls(2)...), but uses fork(2), execve(2), waitpid(2), etc...

How to take the output of grep and write it to a new file

I want to take the output of the grep command on a file, create a new file and save that grep output to the new created file, can someone please point me to the right direction in how I would do that?
The path you choose depends a great deal on how simple you want it to be.
Perhaps the simplest method is the use of system:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
system ("grep a *.c >outfile.txt");
return 0;
}
though you also could construct the command dynamically if you have different arguments to grep or a non-fixed output file.
Beyond that, you could use popen() (if available on your implementation - it's not mandated by ISO but is instead a POSIX thing) along with fgets() or fgetc() to read the output of that command and do whatever you want with it:
#include <stdio.h>
int main (void) {
int chr;
FILE *echo = popen ("echo hello there", "r");
if (echo != NULL) {
while ((chr = fgetc (echo)) != EOF)
putchar (chr);
fclose (echo);
}
return 0;
}
The next step up from there may be to not rely on an external grep at all but instead include something like PCRE (Perl-compatible regular expressions) into your own code, giving you much finer control over what happens.

How to redirect the output of system() to a file?

In this C program
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main()
{
int file = open("Result", O_CREAT|O_WRONLY, S_IRWXU);
dup2(stdout, file);
system("ls -l");
return 0;
}
I'm trying to redirect the output of system() to a file, for that i have used dup2 but it is not working.
What's wrong with this code?
and, please tell me if there is any better way to do this? (without using > at the terminal )
stdout is a FILE * pointer of the standard output stream. dup2 expects file descriptor, also you've messed up the parameters order.
Use
dup2(file, 1);
instead.
On the better-way-to-do-this part. This way is bad because you probably want to restore your standard output after this system call completes. You can do this in a variety of ways. You can dup it somewhere and then dup2 it back (and close the dupped one). I personally don't like writing own cat implementations as suggested in other answers. If the only thing you want is redirecting a single shell command with system to a file in the filesystem, then probably the most direct and simple way is to construct the shell command to do this like
system("ls -l > Result");
But you have to be careful if filename (Result) comes from user input as user can supply something like 'Result; rm -rf /*' as the filename.
Also, on the topic of security, you should consider specifying the full path to ls as suggested in the comments:
system("/bin/ls -l > Result");
The simple thing is to use > indeed:
#include <stdio.h>
int main()
{
system("ls -l > /some/file");
return 0;
}
An alternative is using popen(), something along the lines of
#include <stdio.h>
#include <stdlib.h>
main()
{
char *cmd = "ls -l";
char buf[BUFSIZ];
FILE *ptr, *file;
file = fopen("/some/file", "w");
if (!file) abort();
if ((ptr = popen(cmd, "r")) != NULL) {
while (fgets(buf, BUFSIZ, ptr) != NULL)
fprintf(file, "%s", buf);
pclose(ptr);
}
fclose(file);
return 0;
}
You should use the popen() library function and read chunks of data from the returned FILE * and write them to whatever output file you like.
Reference.
use dup instead of dup2. dup creates a alias file descriptor, which value should be always the smallest available file descriptor.
new_fd = dup(file); - In this statement file might be having the value 3 (because stdin is 0, stdout is 1 and stderr is 2). so new_fd will be 4
If you want to redirect stdout into file. Then do as below.
close(stdout);
new_fd = dup(file);
Now dup will return 1 as the alias for the file descriptor, because we closed stdout so opened file descriptors are 0,2,3 and 1 is smallest available file descriptor.
If you are using dup2 means, dup2(file,1); - do like this

Resources