Store output of system(file) command as a string in C - c++

To get the type of file we can execute the command
system("file --mime-type -b filename");
The output displays in to terminal.But could not store the file type using the command
char file_type[40] = system("file --mime-type -b filename");
So how to store file type as a string using system(file) function.

See the man page of system: It does not return the output of the command executed (but an errorcode or the return value of the command).
What you want is popen. It return a FILE* which you can use to read the output of the command (see popen man page for details).

You can use popen like this:
#include <stdio.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
FILE *fp;
char file_type[40];
fp = popen("file --mime-type -b filename", "r");
if (fp == NULL) {
printf("Failed to run command\n" );
exit -1;
}
while (fgets(file_type, sizeof(file_type), fp) != NULL) {
printf("%s", file_type);
}
pclose(fp);
return 0;
}

Hmmm the first and easiest way that comes to my mind for achieving what you want would be to redirect the output to a temp-file and then read it into a char buffer.
system("file --mime-type -b filename > tmp.txt");
after that you can use fopen and fscanf or whatever you want to read the content of the file.
Ofcourse, youl'll have the check the return value of system() before attempting to read the temp-file.

Related

Handing user input on terminal for application launched via exec in C++

xfreerdp asks for password if /p is not supplied as command line argument; when launched via terminal.
But when it is launched via execvp or exec, there is no prompt?
How to show this prompt? Is there a way where I can directly input password on prompt programmatically?
Same is automatically handled in Mac using swift using tasks & pipes. How to do it in C++.
Is there a way where I can directly input password on prompt programmatically?
An example (written in C) using popen() ...
#include <stdio.h>
#include <stdlib.h>
int main(void) {
const char *cmd = "xfreerdp";
char output[128] = {'\0'};
const char *arg = "myargs";
// Open process
FILE *fp = popen(cmd, "w");
if (!fp) {
fprintf(stderr, "Could not execute command ...\n");
exit(EXIT_FAILURE);
}
// Pass arguments
if (fprintf(fp, "%s", arg) < 0) {
puts("Could not pass arguments ...");
}
// Print command output (if required)
while (fgets(output, sizeof(output), fp) != NULL) {
puts(output);
}
pclose(fp);
return 0;
}

system / pipe call changes special characters in command passed for execution

I wanted to use system / pipe command to execute command which has special characters. below is the sample code.
After executing the command through system / pipe, it changes the command by changing special characters.
I am surprised to see that system command is changing the text passed as command.
run(char *cmd)
{
FILE *in;
extern FILE *popen();
char buff[2048]= {0,};
if(!(in = popen(cmd, "r")))
{
exit(1);
}
while(fgets(buff, sizeof(buff), in)!=NULL)
{
printf("%s", buff);
}
pclose(in);
}
main()
{
char cmd[2048]={0,};
sprintf(cmd,"echo \"'http://1.2.3.4/files-spaces-specialchars-
ascii/%23#%23##!#!#!#%23%23$$$$$$$ASA(()
(!FreemakeAudioConverterSetup.exe'\" >>/tmp/logger 2>&1");
printf("this is CMD:[%s]\n",cmd);
system("echo "" > /tmp/logger"); /* to clear file containt */
system(cmd);
run(cmd);
}
OUTPUT
[terminal]$ ./a.out
this is CMD:[echo "'http://1.2.3.4/files-spaces-specialchars-ascii/%23#%23##!#!#!#%23$$$$$$$ASA(()(!FreemakeAudioConverterSetup.exe'" >>/tmp/logger 2>&1]
[terminal]$ cat /tmp/logger
'http://1.2.3.4/files-spaces-specialchars-ascii/%23#%23##!#!#!#%23538853885388(()(!FreemakeAudioConverterSetup.exe'
'http://1.2.3.4/files-spaces-specialchars-ascii/%23#%23##!#!#!#%23538953895389(()(!FreemakeAudioConverterSetup.exe'
[terminal]$
As shown above the original command URL is getting changed after executing through system / pipe command.
Any inputs from developers?
correcting the code, so it cleanly compiles results in:
Note: I also added a call to perror() so if the call to popen() fails the user is properly notified of what happened.
#include <stdio.h>
#include <stdlib.h>
void run(char *cmd)
{
FILE *in;
extern FILE *popen();
char buff[2048]= {'\0'};
if(!(in = popen(cmd, "r")))
{
perror( "popen for read failed" );
exit(1);
}
while(fgets(buff, sizeof(buff), in)!=NULL)
{
printf("%s", buff);
}
pclose(in);
}
int main( void )
{
char cmd[2048]={'\0'};
sprintf(cmd, "%s", "echo \"'http://1.2.3.4/files-spaces-specialchars-"
"ascii/%23#%23##!#!#!#%23%23$$$$$$$ASA(()"
"(!FreemakeAudioConverterSetup.exe'\" >>/tmp/logger 2>&1");
printf("this is CMD:[%s]\n",cmd);
system("echo "" > /tmp/logger"); /* to clear file containt */
system(cmd);
run(cmd);
}
then running that code results in:
this is CMD:[echo "'http://1.2.3.4/files-spaces-specialchars-ascii/%23#%23##!#!#!#%23%23$$$$$$$ASA(()(!FreemakeAudioConverterSetup.exe'" >>/tmp/logger 2>&1]
and cat /tmp/logger results in:
cat /tmp/logger
'http://1.2.3.4/files-spaces-specialchars-ascii/%23#%23##!#!#!#%23%23193951939519395(()(!FreemakeAudioConverterSetup.exe'
'http://1.2.3.4/files-spaces-specialchars-ascii/%23#%23##!#!#!#%23%23193961939619396(()(!FreemakeAudioConverterSetup.exe'

how to get linux command output string and output status in c++

I want to get a Linux command's output string as well as command output status in a C++ program. I am executing Linux commands in my application.
for example:
Command:
rmdir abcd
Command output string:
rmdir: failed to remove `abcd': No such file or directory
Command Status:
1 (Which means command has been failed)
I tried using Linux function system() which gives the output status, and function popen() which gives me output string of a command, but neither function gives me both
the output string and output status of a Linux command.
The output string is in standard output or standard error descriptor (1 or 2, respectively).
You have to redirect these streams (take a look at dup and dup2 function) to a place, where you can read them (for example - a POSIX pipe).
In C I'd do something like this:
int pd[2];
int retValue;
char buffer[MAXBUF] = {0};
pipe(pd);
dup2(pd[1],1);
retValue = system("your command");
read(pd[0], buffer, MAXBUF);
Now, you have (a part of) your output in buffer and the return code in retValue.
Alternatively, you can use a function from exec (i.e. execve) and get the return value with wait or waitpid.
Update: this will redirect only standard output. To redirect standard error, use dup2(pd[1],1).
The simplest solution is to use system, and to redirect standard out and standard error to a temporarly file, which you can delete later.
Unfortunately there's no easy and simple way in C on Linux to do this. Here's an example how to read/write stdout/stderr/stdin of child process correctly.
And when you want to receive exit code you have to use waitpid (complete example is provided on the bottom of the provided page):
endID = waitpid(childID, &status, WNOHANG|WUNTRACED);
Now you just have to join those two together :)
There's also a great free book named Advanced Linux Programming (ALP) containing detailed information about these kinds of problem available here.
Building on Piotr Zierhoffer answer above, here's a function that does just that, and also restores stdout and stderr their original state.
// Execute command <cmd>, put its output (stdout and stderr) in <output>,
// and return its status
int exec_command(string& cmd, string& output) {
// Save original stdout and stderr to enable restoring
int org_stdout = dup(1);
int org_stderr = dup(2);
int pd[2];
pipe(pd);
// Make the read-end of the pipe non blocking, so if the command being
// executed has no output the read() call won't get stuck
int flags = fcntl(pd[0], F_GETFL);
flags |= O_NONBLOCK;
if(fcntl(pd[0], F_SETFL, flags) == -1) {
throw string("fcntl() failed");
}
// Redirect stdout and stderr to the write-end of the pipe
dup2(pd[1], 1);
dup2(pd[1], 2);
int status = system(cmd.c_str());
int buf_size = 1000;
char buf[buf_size];
// Read from read-end of the pipe
long num_bytes = read(pd[0], buf, buf_size);
if(num_bytes > 0) {
output.clear();
output.append(buf, num_bytes);
}
// Restore stdout and stderr and release the org* descriptors
dup2(org_stdout, 1);
dup2(org_stderr, 2);
close(org_stdout);
close(org_stderr);
return status;
}
you can use popen system call, it will redirect output to a file and from file you can redirect output to a string. like :
char buffer[MAXBUF] = {0};
FILE *fd = popen("openssl version -v", "r");
if (NULL == fd)
{
printf("Error in popen");
return;
}
fread(buffer, MAXBUF, 1, fd);
printf("%s",buffer);
pclose(fd);
For more information read man page for popen.

How to read the failure log message displayed when a system call failed in C++?

I have a C++ code that calls a test. I am doing a system call to execute this test. When this test fails, it will display something like this " ERROR: One or more devices of following component type(s) could not be discovered:"
I have a C++ code that runs on Linux redhat and it is capable of detecting if the system call pass or failed. But it can not capture the error message (ERROR: One or more devices of following component type(s) could not be discovered:) and append into the log file or print it.
Can someone please tell me how to capture the error message (ERROR: One or more devices of following component type(s) could not be discovered:)?
PS: I am an intern, any help would be really nice.
#include<iostream.h>
int main ()
{
int i;
if (system(NULL))
puts ("Ok");
else
exit (1);
i=system("hpsp --discover -verbose --user Admin --oapasswd password");
printf ("The value returned was: %d.\n",i);
return false;
}
Instead of using system() use popen(). This will open a pipe capturing the standard output of the test program so that your program can read it via the pipe.
Example EDITED:
#define _BSD_SOURCE 1
#define BUFFSIZE 400
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char *cmd = "hpsp --discover -verbose --user Admin --oapasswd password";
char buf[BUFFSIZE];
char* searchResult;
int testPassed = 0;
FILE *ptr;
if ((ptr = popen(cmd, "r")) != NULL)
while (fgets(buf, BUFFSIZE, ptr) != NULL)
{
if ((searchResult = strstr(buf, "The test passed")) != NULL )
{
testPassed = 1;
break;
}
}
if (testPassed)
printf("yea!!\n");
else
printf("boo!!\n");
pclose(ptr);
return 0;
}
You can use dup and dup2 to backup/store the stderr file descriptor to redirect to your log file. Well, I'm guessing that errors go to stderr anyways.
Here's an example if you just want to write to a log file.
//open log file, choose whatever flags you need
int logfd = open("whateveryourlogfileis", O_APPEND);
//back up stderr file descriptor
int stderr_copy = dup(STDERR_FILENO);
//redirect stderr to your opened log file
dup2(logfd, STDERR_FILENO);
//close the original file descriptor for the log file
close(logfd);
//system call here
//restore stderr
dup2(stderr_copy, STDERR_FILENO);
//close stderr copy
close(stderr_copy);
Note: dup2 closes the target file descriptor before dup2ing to it. dup just duplicates the file descriptor and returns to you the new file descriptor.

Detect if stdin is a terminal or pipe?

When I execute "python" from the terminal with no arguments it brings up the Python interactive shell.
When I execute "cat | python" from the terminal it doesn't launch the interactive mode. Somehow, without getting any input, it has detected that it is connected to a pipe.
How would I do a similar detection in C or C++ or Qt?
Use isatty:
#include <stdio.h>
#include <io.h>
...
if (isatty(fileno(stdin)))
printf( "stdin is a terminal\n" );
else
printf( "stdin is a file or a pipe\n");
(On windows they're prefixed with underscores: _isatty, _fileno)
Summary
For many use cases the POSIX function isatty() is all what it is needed to detect if stdin is connected to a terminal. A minimal example:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char **argv)
{
if (isatty(fileno(stdin)))
puts("stdin is connected to a terminal");
else
puts("stdin is NOT connected to a terminal");
return 0;
}
The following section compares different methods that can be used if different degrees of interactivity have to be tested.
Methods in Detail
There are several methods to detect if a program is running interactively.
Following table shows an overview:
cmd\method ctermid open isatty fstat
――――――――――――――――――――――――――――――――――――――――――――――――――――――――――――
./test /dev/tty OK YES S_ISCHR
./test < test.cc /dev/tty OK NO S_ISREG
cat test.cc | ./test /dev/tty OK NO S_ISFIFO
echo ./test | at now /dev/tty FAIL NO S_ISREG
The results are from a Ubuntu Linux 11.04 system using the following program:
#include <stdio.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
int main() {
char tty[L_ctermid+1];
ctermid(tty);
printf("ID: %s\n", tty);
int fd = open(tty, O_RDONLY);
if (fd < 0) perror("Could not open terminal");
else {
printf("Opened terminal\n");
struct termios term;
int r = tcgetattr(fd, &term);
if (r < 0) perror("Could not get attributes");
else printf("Got attributes\n");
}
if (isatty(fileno(stdin))) printf("Is a terminal\n");
else printf("Is not a terminal\n");
struct stat stats;
int r = fstat(fileno(stdin), &stats);
if (r < 0) perror("fstat failed");
else {
if (S_ISCHR(stats.st_mode)) printf("S_ISCHR\n");
else if (S_ISFIFO(stats.st_mode)) printf("S_ISFIFO\n");
else if (S_ISREG(stats.st_mode)) printf("S_ISREG\n");
else printf("unknown stat mode\n");
}
return 0;
}
Terminal device
If the interactive session needs certain capabilities, you can open the
terminal device and (temporarily) set terminal attributes you need
via tcsetattr().
Python Example
The Python code that decides whether the interpreter runs interactively uses isatty(). The Function PyRun_AnyFileExFlags()
/* Parse input from a file and execute it */
int
PyRun_AnyFileExFlags(FILE *fp, const char *filename, int closeit,
PyCompilerFlags *flags)
{
if (filename == NULL)
filename = "???";
if (Py_FdIsInteractive(fp, filename)) {
int err = PyRun_InteractiveLoopFlags(fp, filename, flags);
calls Py_FdIsInteractive()
/*
* The file descriptor fd is considered ``interactive'' if either
* a) isatty(fd) is TRUE, or
* b) the -i flag was given, and the filename associated with
* the descriptor is NULL or "<stdin>" or "???".
*/
int
Py_FdIsInteractive(FILE *fp, const char *filename)
{
if (isatty((int)fileno(fp)))
return 1;
which calls isatty().
Conclusion
There are different degrees of interactivity. For checking if stdin is connected to a pipe/file or a real terminal isatty() is a natural method to do that.
Probably they are checking the type of file that "stdin" is with fstat, something like this:
struct stat stats;
fstat(0, &stats);
if (S_ISCHR(stats.st_mode)) {
// Looks like a tty, so we're in interactive mode.
} else if (S_ISFIFO(stats.st_mode)) {
// Looks like a pipe, so we're in non-interactive mode.
}
Of course Python is open source, so you can just look at what they do and know for sure:
http://www.python.org/ftp/python/2.6.2/Python-2.6.2.tar.bz2
On Windows you can use GetFileType.
HANDLE hIn = GetStdHandle(STD_INPUT_HANDLE);
DWORD type = GetFileType(hIn);
switch (type) {
case FILE_TYPE_CHAR:
// it's from a character device, almost certainly the console
case FILE_TYPE_DISK:
// redirected from a file
case FILE_TYPE_PIPE:
// piped from another program, a la "echo hello | myprog"
case FILE_TYPE_UNKNOWN:
// this shouldn't be happening...
}
Call stat() or fstat() and see if S_IFIFO is set in st_mode.
You can call stat(0, &result) and check for !S_ISREG( result.st_mode ). That's Posix, not C/C++, though.