Can't write to stdin with popen opened with write - c

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*));

Related

save stderr with _popen to a variable in C on Windows 10

When I use something like
char result[1000] = "";
char psBuffer[1000];
FILE* pPipe = _popen(command, "rt");
while(fgets(psBuffer, 1000, pPipe) != NULL)
{
strcat(result, psBuffer);
}
printf(result);
Either when command = "echo 123" or command = "ErrorCommand" result only gets the value of the stdout, it never gets the stderr. At first it looks like it does since you get the error printed on your CMD but if you'll save the output and print it or save it to a file you'll see that it only contains the stdout.
Is there a way to make result also include the stderr?

It possible to replace file to buffer while pass input to an exe as shell command?

I'm using "system" API calls to run shell commands in my C program, now
there is case where I want to redirect the output generated by an executableto a buffer instead of a file (named recv.mail)
An example of how I write the output to the file:
cmd[] = "mda "/bin/sh -c 'cat > recv.mail'";
system (cmd);
Similarly I want to replace input taken from the file (send.mail) with input taken from a buffer.
An example of how I take input from a file:
cmd[] = "msmtp < cat send.mail";
system (cmd);
NOTE: The send.mail and recv.mail files have formatted data.
Are pipes a better replacement?
Can anyone suggest another alternative?
popen/pclose may do what you want:
FILE *f = popen("program to execute", "r");
if (NULL != f)
{
char buffer[128];
while (fgets(buffer, sizeof buffer, f)
{
printf("Read from program: '%s'\n", buffer);
}
pclose (f);
}
popen/pclose again:
FILE *f = popen("program to execute", "w");
...

C Using popen to execute cmds on data

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

Executing a separated command using execvp in C

I've separated a given command from the user into substrings , here's the code :
int i;
char *line = malloc(BUFFER);
char *origLine = line;
fgets(line, 128, stdin); // get a line from stdin
// get complete diagnostics on the given string
lineData info = runDiagnostics(line);
char command[20];
sscanf(line, "%20s ", command);
line = strchr(line, ' ');
printf("The Command is: %s\n", command);
int currentCount = 0; // number of elements in the line
int *argumentsCount = &currentCount; // pointer to that
// get the elements separated
char** arguments = separateLineGetElements(line,argumentsCount);
// here we call a method that would execute the commands
if (execvp(*arguments,*argumentsCount) < 0) // execute the command
{
printf("ERROR: exec failed\n");
exit(1);
}
When I execute the command in execvp(*arguments,*argumentsCount) , it fails .
What's wrong ?
Thanks .
EDIT :
The input from the user is : ls > a.out , hence I have 3 strings , which are :
ls , > , a.out , and it fails .
Shell redirection won't work if you aren't invoking a shell. You also won't have path searching to find the ls program. Some options
use system() instead, and exit when it returns
exec a shell and have it run your command
setup redirection as a shell would, then fork and execute each required child program.
Also your command doesn't make a lot of sense, you probably want ¦ instead of > and may need to specify the directory of a.out if it is not in your path. Consider giving it a meaningful name as well.
From man page of execvp command:
int execvp(const char *file, char *const argv[]);
The second argument is a list of null-terminated C-strings as arguments to the command to be executed by execvp. But in your code, you pass an int as the second argument which is wrong.
If you have list of arguments in the variable arguments then call execvp as:
execvp(arguments[0],arguments);
When you run ls > a.out at the command-line, > and a.out are not arguments passed to the application; they're interpreted by the shell to redirect stdout.
So in short, it is not possible to do what you want to do.1
1. Well, it is, but not this way. Your application would need to interpret the arguments, create the file, and set up a stream redirect.

using readline() to edit commands, in c

i have to implement a few CLI features and now I am trying to use readline() so that the user can edit or go through their commands. Its working so far in that it allows the user to enter their commands and scroll through the history. Its when the user tries to edit the command. The cursor somehow manages to pass the command and go into the prompt eg
"desktop r1234|5$: ls" where "desktop r12345(sp)$: " is the prompt showing working directory & root dir; and "|" is the cursor. The cursor should stop in-between '$' and 'ls' ie "desktop r12345$:| ls" .The showWrkngDir() method just displays a prompt just like a normal terminal.
int main (int argc, char * argv[])
{
showWrkngDir();
static char *line_read = (char *)NULL;
using_history();
rl_readline_name = basename(argv[0]);
if (line_read)
{
free (line_read);
line_read = (char *)NULL;
}
while(strcmp((line_read = readline ("")) , "EXIT") != 0)
{
if (line_read && *line_read)
add_history (line_read);
tokenize(line_read);
showWrkngDir();
}
return 0;
}
void showWrkngDir()
{
char curDir[MAX_COMMAND_SZ];
char *env;
getcwd(curDir, sizeof(curDir));
env = (char *)getenv("USER");
printf("%s ",basename(curDir));
printf("%s(sp)$ ", env);
}
I'm fairly sure that readline wants to display the prompt itself, because sometimes it needs to erase the entire screen line and redraw it from scratch. This happens especially when browsing through history, but also when editing a command that spills over to the next line, or when ^L is pressed.
Give your prompt as the argument to readline(),
Pass the prompt to readline and let it print it rather than printing it yourself using printf.

Resources