Executing Command and Getting Output From C With MPI - c

I have an MPI C program, and I need to get the output of an executable. The executable does a complicated calculation and outputs the results.
The output of the executable is something like this:
0.0225873863659866,0.0000000000000000,0.0000000000000000,
whithout a new line character at the end.
To execute and get the output of the command I tried:
double vals[3];
char command[256];
sprintf (command, "./a.out");
// Execute the command
FILE *cmd = popen(command, "r");
// Get the command output
char buf[256] = {0x0};
while (fgets(buf, sizeof(buf), cmd) != NULL) {
// Output is separated with ,
// separate the string
char *token = strtok(buf, ",");
for (int i = 0; i < 3; ++i) {
// store integral value
vals[i] = atof(token);
token = strtok(NULL, ",");
}
}
printf("vals = (%g, %g, %g) pid = %d \n", vals[0], vals[1], vals[2], pid);
// Close file
pclose(cmd);
In a serial test program, this works great. The problem is that with the MPI program, only PID 0 executes the command, and the rest of the processors don't do it. I also tried having each process call a different executable and different configurations of MPI_BARRIER, but nothing worked.
Why does this happen, and how can I fix it?

Related

fopen and fopen_s seem to be crashing on long file names

I am using visual studio 2013 to build a c application
The code looks like this -
int main( int argc, char *argv[] )
{
char *InFilename = NULL;
char *OutFilename = NULL;
int ff_count; // counts the number of successive 0xff's read from the file buffer
int fpga_end, nios_start, nios_end; // used to report the size of each region
int file_length, file_index, temp_length, new_file_length;
int root_length;
int result;
FILE *infile = NULL;
FILE *outfile = NULL;
printf("Start JIC 2 rbf\r\n");
if ((argc != 2))
{
printf("\r\n\r\nV1.2 - Usage: <jic2rbf> <name of jicfile> \r\n");
printf("\r\n This program strips out the header info at the top of the file\r\n");
printf("\r\n and most of the ff's at the bottom. \r\n");
exit(1);
}
//
// Extract the name of the input file up to the '.' and use it to create the output file name with a .rbf extension.
//
InFilename = argv[1];
root_length = strcspn(InFilename,".");
printf("Root len = %d\r\n",root_length);
OutFilename = (char *)malloc(root_length+EXT_LENGTH);
memcpy(OutFilename,InFilename,root_length);
OutFilename[root_length] = 0;
strcat(OutFilename,".rbf");
printf("In file to be used %s\r\n", InFilename);
printf("Out file to be used %s\r\n", OutFilename);
result = fopen_s(&outfile, OutFilename, "wb");
if (result)
{
printf("Cannot open this file %s\r\n - 0x%x", OutFilename, result);
return 0;
}
printf("Open In - %d\r\n",result);
If I call this executable from a dos command line with -
E:/projects/Q4300_Hdcp/q_series_hdcp_base/fpga/q_series_hdcp_tx_dual_singleHID/par/q_series_hdcp_tx_dual_singleHID/output_files/q_series_hdcp_tx_dual_singleHID_elf.jic
The entire application works
If I call the application with the following command line -
E:/projects/Q4300_Hdcp/q_series_hdcp_base/fpga/q_series_hdcp_tx_dual_fpga/par/q_series_hdcp_tx_dual_fpga/output_files/q_series_hdcp_tx_dual_fpga_elf.jic
I do not see the printf("Open In - %d\r\n",result); output. The application just seems to crash.
I thought it might be some sort of buffer overflow in the file name but the shorter file name works..... If I cd to the directory with the file and call with the command line q_series_hdcp_tx_dual_fpga_elf.jic that works.
If I dir the file - E:/projects/Q4300_Hdcp/q_series_hdcp_base/fpga/q_series_hdcp_tx_dual_fpga/par/q_series_hdcp_tx_dual_fpga/output_files/q_series_hdcp_tx_dual_fpga_elf.jic
I see the file.......
I do not know how to catch the exception or what else to pursue to resolve this, any ideas would be great.
Thanks,
Martin
Try changing this line:
OutFilename = (char *)malloc(root_length+EXT_LENGTH);
to this:
OutFilename = malloc(1 + root_length + EXT_LENGTH);
to allocate space for the null terminator. Also, no need to cast malloc's return value.
DOS has some severe limits on command line length
so when the command line is too long, problems such as you are experience will occur.
Did you really mean that your using Visual Studio and Windows?
Many of the limitations of DOS have been carried forward into Windows and Visual Studio

Using a system call to execute "which" command in C

I'm trying to get the pathname for specific user input. For example, if the user inputs ls | wc I want to create two strings the first one being a which(ls), and the second one being a which(wc) so I have the pathname. I am doing this inside a C program and my code looks like the following.
/*This is a basic example of what i'm trying to do*/
char* temp;
printf("Enter a command\n");
/* assume user enters ls */
scanf("%s", temp);
char* path = system(which temp);
printf("Testing proper output: %s\n", path);
/*I should be seeing "/bin/ls" but the system call doesn't work properly*/
Can anyone point me in the right direction?
You are using an uninitialized pointer. But even if you had initialized it properly, it still wouldn't work because system() doesn't return the output of the command it executes.
You want to use popen() to do that.
Here's an example (untested):
if (fgets(cmd, sizeof cmd, stdin)) {
char cmd[512];
cmd[strcspn(cmd, "\n")] = 0; // in case there's a trailing newline
char which_cmd[1024];
snprintf(which_cmd, sizeof which_cmd, "which %s", cmd);
char out[1024];
FILE *fp = popen(which_cmd);
if (fp && fgets(out, sizeof out, fp)) {
printf("output: %s\n", out);
}
}

Writing my own linux shell I/O redirect '>' function

I am writing the redirect function that writes the output of a command to a given filename.
For example:
echo Hello World > hello.txt would write 'Hello World' into hello.txt.
ls -al > file_list.txt would write the list of all file/directory names in the current directory into file_list.txt.
My function so far is defined as:
int my_redirect(char **args, int count) {
if (count == 0 || args[count + 1] == NULL) {
printf("The redirect function must follow a command and be followed by a target filename.\n");
return 1;
}
char *filename = args[count + 1];
//Concatenates each argument into a string separated by spaces to form the command
char *command = (char *) malloc(256);
for (int i = 0; i < (count); i++) {
if (i == 0) {
strcpy(command, args[i]);
strcat(command, " ");
}
else if (i == count - 1) {
strcat(command, args[i]);
}
else {
strcat(command, args[i]);
strcat(command, " ");
}
}
//command execution to file goes here
free(command);
return 1;
}
where args[count] is ">".
How can I execute the command given by the string from args[0] to args[count - 1] into the file given at args[count + 1]?
EDIT
These are the instructions we have been given:
"Improve your shell by adding a redirect for stdout to a file. Only attempt after completing Feature 1. Parse the line for >, take everything before as command, and the first word after as the filename (ignore <, >>, | etc).
Standard out is written out to file descriptor 1 (stdin is 0, stderr is 2). So this task can be achieved by opening the file, and copying it’s file descriptor over to 1 with dup2 system call.
int f = open( filename , O_WRONLY|O_CREAT|O_TRUNC, 0666) ;
dup2( f , 1 ) ;
Note: Using system call open not library wrapper fopen here."
If you are allowed to solve this problem in a special way, so it works only for a narrow range of problems, like capturing stdout of a command into a file, you can avoid reinventing the wheel using the popen() function from <stdio.h>.
Sketch of the program:
Determine output file name
Open output file for writing
Determine command and arguments
Construct the command string from the args up to the >.
Call FILE *cmd = popen(command, "r");
Read line from cmd stream, write to output file
Goto 6 while not EOF on the cmd stream.
pclose(cmd), fclose output stream
Do this only if your instructor does not expect you to use fork, dup, and friends.

linux how to get process params with pid?

When I execute the program ./test -debug 7 -m player,I use C language how to get the parameter values of -m -debug?
I have tried:
char* name = (char*)calloc(1024,sizeof(char));
if(name){
sprintf(name, "/proc/%d/cmdline",pid);
FILE* f = fopen(name,"r");
if(f){
size_t size;
size = fread(name, sizeof(char), 1024, f);
if(size>0){
if('\n'==name[size-1])
name[size-1]='\0';
}
fclose(f);
}
}
But it only returns the name of the process.exec "xargs -0 < /proc/pid/cmdline" can return the right value(mytest -debug 7 -m player),I want to get in another process, rather than in the main method of the process.such as,in process mytest2,I want to get mytest process debug value with pid(via pid = getpid() and via pid get mytest process info,and than get debug value ).
From proc(5):
The command-line arguments appear in this file as a set of strings
separated by null bytes ('\0'), with a further null byte after the
last string.
So, this code should work:
for (i = 0; i < size; i++) {
if (!i)
printf("%s\n", name);
else if (!name[i - 1])
printf("%s\n", name + i);
}

Pipe behavior is erratic, not confident about implementation

I am learning about ipc in Linux and trying out pipes. I've set up two pipes between the parent and two child processes. While the data goes through the pipes, I get weird newlines. For instance, the output would sometimes have an extra newline or no newline entirely or even appear on the command line itself. Also, I am unsure whether the way I have set up pipes is correct. I may have overlooked some important details and leave dangling file descriptors.
void run_processes(Command_Args *cmd_args, char *file_paths)
{
pipe(pipe_RtoA1);
pipe(pipe_RtoA2);
pipe(pipe_A1toT1);
pipe(pipe_A2toT2);
pipe(pipe_T1toR);
pipe(pipe_T2toR);
if (!(pid_A1 = fork())) {
long read = 0;
size_t size = 0;
char *input_str = NULL;
close(pipe_RtoA1[1]);
dup2(pipe_RtoA1[0], 0);
read = getline(&input_str, &size, stdin);
printf("A1 : %s\n", input_str);
} else if (!(pid_A2 = fork())) {
long read = 0;
size_t size = 0;
char *input_str = NULL;
close(pipe_RtoA2[1]);
dup2(pipe_RtoA2[0], 0);
read = getline(&input_str, &size, stdin);
printf("A2 : %s\n", input_str);
} else {
FILE *fRtoA1 = NULL;
FILE *fRtoA2 = NULL;
fRtoA1 = fdopen(pipe_RtoA1[1], "w");
fRtoA2 = fdopen(pipe_RtoA2[1], "w");
close(pipe_RtoA1[0]);
close(pipe_RtoA2[0]);
fprintf(fRtoA1, "%s", file_paths);
fprintf(fRtoA2, "%s", file_paths);
}
}
I plan on having pipes to other processes, but now I just want to get the pipes from this program R to two other programs A1 and A2 working.
Program R will send file_paths do the pipes and A1 and A2 will print them.
You are launching two distinct processes that are ouputting on th standard output in an unpredictable order. Their output may be interlaced. Just to make sure, open output an file for each subprocess, and check the content.

Resources