C Using popen to execute cmds on data - c

TL;DR How do you send a string to cmd.exe, execute grep/findstr or sort, and then print the output using popen?
I have a client and server setup. The user enters a command, such as 'list X: | grep name', which is then broken into 'list X:' and 'grep name'. 'list X:' is sent to the server which then executes a list function and returns a char[] containing the list result. The client then needs to feed this into cmd.exe and execute the 'grep name' command on that data and print it out to the user. I don't need to return the data from cmd to the client process, just output it.
I know my code isn't trying to write at the moment (I'm opening the file in read mode) but I had tried a few other things and can't seem to send the data to cmd.exe)
Code is as follows:
...
int n = recv(clientSocket, reply, sizeof(reply), 0);
std::string* cmdStr = new std::string(cmd);
cmdStr->erase(std::remove(cmdStr->begin(), cmdStr->end(), '\n'), cmdStr->end());
if(cmdStr->compare("") != 0) //Something to pipe to command
{
char pipeBuffer[8192];
FILE* pipe;
char c [8192];
strcat(c, "cmd.exe /C ");
strcat(c, reply);
strcat(c, " | ");
strcat(c, cmdStr->c_str());
if((pipe = _popen(c, "r")) == NULL)
{
printf("Unable to create pipe!\n");
}
while(!feof(pipe))
{
if(fgets(pipeBuffer, 8192, pipe) != NULL)
{
printf(pipeBuffer);
}
}
}
...

I ended up fixing it with this, just in case anyone else runs into a similar problem:
FILE* pipe;
if((pipe = _popen(cmdStr->c_str(), "w")) == NULL)
{
printf("Unable to create pipe!\n");
}
fprintf(pipe, "%s", reply);
printf("\nPipe process returned %d\n", _pclose(pipe));

well, if your application is already running as a console, you can use the function system() that executes a command on CMD, if not, you can simulate a console using AllocConsole() and then using system(), if you want to really emulate, you can use pipes

Related

Can't write to stdin with popen opened with write

I'm trying to create a GUI for the linux version of windscribe, so I wish to communicate with the windscribe CLI from my C program. I chose to use popen.
I can write single commands with popen("command", "w"), but I want to add informations when asked, like login in the CLI :
$ windscribe login
Windscribe Username: myname
Windscribe Password: mypassword
So I keep the FILE opened and use fputs to keep sending informations.
I finally wrote this function:
void write_in_shell_commands(char** commands, int length){
FILE *fp = NULL;
// sending first command
if (length > 0) {
debug("Writing \"%s\" to shell.", commands[0]);
fp = popen(commands[0], "w");
}
// sending the rest
if (fp) {
debug("File successfully opened.");
for (int i = 1; i < length; i++){
debug("%s", "Writing to shell.");
fputs(commands[i], fp);
}
pclose(fp);
} else {
debug("Operation failed.");
}
}
But when I use this function (e.g.) for login, it doesn't behave as I expected, it seems the additional commands are lost and not taken into account.
char* cmd1 = "windscribe login";
char* cmd2 = "myname";
char* cmd3 = "mypassword";
char** commands = malloc(3 * sizeof(char*));
commands[0] = cmd1;
commands[1] = cmd2;
commands[2] = cmd3;
write_in_shell_commands(commands, 3);
I expect the program to :
Write cmd1 in shell
Write cmd2 in stdin
Write cmd3 in stdin
But actually this happens
DEBUG output/shellwriter.c:22: Writing "windscribe login" to shell.
DEBUG output/shellwriter.c:27: File successfully opened.
DEBUG output/shellwriter.c:30: Writing to shell.
DEBUG output/shellwriter.c:30: Writing to shell.
Windscribe Password: Windscribe Username:
It's actually asking for the password in the terminal and eventually fails because credentials are bad.
What's actually happening here ? Where are my second and third commands ? Am I using the wrong functions ?
cmd1, cmd2, cmd3 are pointers to char. So you should allocate memory for 3 pointers to char for commands which is a pointer to pointer to char.
char** commands = malloc(3*sizeof(char*));

How to get return value from shell script using c code [duplicate]

This question already has answers here:
How to execute a shell script from C in Linux?
(6 answers)
Closed 5 years ago.
I want to get return value from my script using c code.
Consider my script is in another partition, I am mounting that partition and i am calling like,
value=system("./mnt1/myscript.img");
I need one function in myscript.img file and that should return one value (ex: mmcpart)
How can i frame the script to get return value. can anyone help me to solve this issue.
Thanks in advance.
You can write the output of the shell script in a file and read the file content from the C program.
Your C program must attempt to read the file only when the shell script process is complted, preferably with $? = 0.
You can put the name of your shell script file in .profile file and it will automatically execute your shell script.
Shell script programming possesses powerful file handling commands writing to files should not be an issue.
Not sure why **tee ** command is used. Do you want the output to be sent t STDOUT as well?
What you really need is a pipe and then fork and execvp where you can execute your script. Something like this should work for you
int mypipe[2];
if(pipe(mypipe) == -1) {
perror("Pipe creation failed");
exit(1);
}
if(fork() == 0) //first fork
{
close(STDOUT_FILENO); //closing stdout
dup(mypipe[1]); //replacing stdout with pipe write
close(mypipe[0]); //closing pipe read
close(mypipe[1]);
const char* myprog[] = { "ps", "-ef", 0};
execvp(myprog[0], myprog);
perror("error in execvp for ps command");
exit(1);
}
char str[200];
FILE* fp = fdopen(mypipe[0], "r");
while (fgets(str, 200, fp) != 0) {
printf("%s\n", str);
}

Run a system command with system() and send output

So what I am trying to do is to invoke a system command with system() function and then whatever its output is I would like to take it and send it over to the client (socket connection).
Client can send various messages. It can be ls but it might be even qwerty. I would like to take the ouput and place it in the write() function as a const void* buffer argument. I have seen this topic but I can get it done to work. So far I thought it could go somewhere of these lines but whatever I tried it did not work.
/* buffer is message from the client: ls, ls -l, whatever*/
system(buffer)
fp = popen(buffer, "r");
if(fp == NULL)
printf("Failed ot run command\n");
while(fgets(path, sizeof(path), fp) != NULL) {
//modify output here?
}
pclose(fp);
write(socket_fd, output, strlen(buffer));
You should only use popen() and not system() as it describes in the question you linked.
The path variable in the question you linked seems to be misnamed. It contains the output of the system call. You can rename it to output if you wish.
write() takes the length of the buffer you are sending it. In this case, that will be the length of output, not the length of buffer.
Putting this all together gives the following:
char output[1035];
fp = popen(buffer, "r");
if(fp == NULL)
printf("Failed ot run command\n");
while(fgets(output, sizeof(output), fp) != NULL) {
write(socket_fd, output, strlen(output));
}
pclose(fp);

Redirection error occurs only on "ls" command. Other commands are redirected well. What's wrong with my code?

I'm doing a small school project making my own bash shell.
It must include simple redirection function.
I almost made it... following commands work well 'pwd > sample', 'cat sample > sample1', 'echo sentence > sample2'
However, 'ls > sample' command is malfunctioning!
Whenever I do this, it makes a new file but it's empty. If a 'sample' file already exist and not empty, 'ls > sample' command makes the file empty.
Just a single 'ls' command itself works very well, showing all files and dir names even though they are not alphabetically sorted.
I can't find something wrong with my code.. please somebody help me.
Below is redirection part
int bak, new;
int redirLoca; // indicates ">" location in argv[].
else if (boolRedirect == 1) {
redirLoca = checkRedirLoca(argc, argv);
fflush(stdout);
bak = dup(1);
new = open(argv[redirLoca + 1], O_WRONLY | O_CREAT | O_TRUNC, 0777);
dup2(new, 1);
close(new);
executeCmd(argc, argv, boolCorrect, cmdNum, boolRedirect); // 'ls' command executed here.
fflush(stdout);
dup2(bak, 1);
close(bak);
}
And here is implementation of 'ls' command.
int list_ls(int argc, char **argv)
{
DIR *dirP;
struct dirent *direntP;
if (argc == 1) {
dirP = opendir(".");
while ((direntP = readdir(dirP)) != NULL) {
printf("%s\n", direntP -> d_name);
}
closedir(dirP);
} else if (argc == 2) {
dirP = opendir(argv[1]);
while ((direntP = readdir(dirP)) != NULL) {
printf("%s\n", direntP -> d_name);
}
closedir(dirP);
}
return 0;
}
Thank you.
man dup2 says:
"The dup2() system call performs the same task as dup(), but instead of using the lowest-numbered unused file descriptor, it uses the descriptor number specified in newfd. If the descriptor newfd was previously open, it is silently closed before being reused."
You are placing your opened parameter file inplace of stdout and closing the stdout. That makes stdout output always zero length creating zero length redirected files.
Addition: You could try to debug the issue with strace to see what system level operations your application is doing. Then you can check man pages for each call to see what it does with given parameters.

command prompt program: how to allow user to enter unix commands?

I'm having trouble writing a C program that displays a command prompt (no problem here) which allows the user to enter unix commands & then displays the results. I've tried many things but I only started programming a year ago and haven't gone anywhere besides displaying the command prompt; I need help on how to accept unix commands + display their results.
My only constraint is that instead of the user providing an absolute path, I need my program to search the directories specified in the path environment variable and find the location of the command's executable. I don't understand how to do this either but searching online has told me this would be best using "getenv() to access the OS PATH variable and prefix the user-supplied command appropriately". Can anyone help me out here? Thanks for your assistance in advance.
Try popen(), which can be found here in the manpages.
Check this out:
#include <stdio.h>
#include <stdlib.h>
void write_netstat(FILE * stream)
{
FILE * outfile;
outfile = fopen("output.txt","w");
char line[128];
if(!ferror(stream))
{
while(fgets(line, sizeof(line), stream) != NULL)
{
fputs(line, outfile);
printf("%s", line);
}
fclose(outfile);
}
else
{
fprintf(stderr, "Output to stream failed.n");
exit(EXIT_FAILURE);
}
}
int main(void)
{
FILE * output;
output = popen("netstat", "r");
if(!output)
{
fprintf(stderr, "incorrect params or too many files.n");
return EXIT_FAILURE;
}
write_netstat(output);
if(pclose(output) != 0)
{
fprintf(stderr, "Could not run 'netstat' or other error.n");
}
return EXIT_SUCCESS;
}
This prints a netstat to a file. You can do this for all commands. It uses popen(). I wrote it because I needed a log of a netstat.

Resources