In Linux, I am finding pid of process by opening pipe with "pidof process_name" command and then reading it's output using fgets function. But it fails to find pid once in a while. Below is my code for finding pid of my process.
int FindPidByProcessName(char *pName)
{
int pid = -1;
char line[30] = { 0 };
char buf[64] = { 0 };
sprintf(buf, "pidof %s", pName);
//pipe stream to process
FILE *cmd = popen(buf, "r");
if (NULL != cmd)
{
//get line from pipe stream
fgets(line, 30, cmd);
//close pipe
pclose(cmd); cmd = NULL;
//convert string to unsigned LONG integer
pid = strtoul(line, NULL, 10);
}
return pid;
}
In output sometimes pid=0 comes even though process is available in "ps" command output.
So, I try to find root cause behind this issue and i found something like input/output buffer mechanism is may creating issue in my scenario.
So I try to use sync() function before opening popen() and strangely my function starts working with 100% accuracy.
Now sync() function is taking too much time(approximately 2min sometime) to complete its execution which is not desirable. So i try to use fflush(), fsync() and fdatasync() but these all are not working appropriately.
So please anyone tell me what was the exact root cause behind this issue And how to solve this issue appropriately?
Ok, the root cause of the error is stored in the errno variable (which btw you do not need to initialize). You can get an informative message using the fucntion
perror("Error: ");
If u use perror the variable errno is interpreted and you get a descriptive message.
Another way (the right way!) of finding the root cause is compiling your program with the -g flag and running the binary with gdb.
Edit: I strongly suggest the use of the gdb debugger so that you can look exactly what path does your code follow, so that you can explain the strange behaviour you described.
Second Edit: Errno stores the last error (return value). Instead of calling the functions as you do, you should write, and check errno immediately:
if ((<function>) <0) {
perror("<function>: ");
exit(1);
}
Related
I am writing some code that has to communicate with gdb mi. So I forked my programm, put two pipes in place and started gdb mi in the child, so that I can communicate with gdb mi from the parent.
gdb always returns "(gdb) \n" when it is finished, so I look for that and write my next command. This is a minimum example of my code:
int main(){
printf("Starting Test\n");
int fromGDB[2], toGDB[2], nbytes;
pid_t childpid;
char readbuffer[80] = "";
pipe(fromGDB);
pipe(toGDB);
if((childpid = fork())==-1)
{
perror("fork");
exit(1);
}
if(childpid == 0){
close(toGDB[1]);
close(fromGDB[0]);
int backup = dup(1); //store stdout
if (dup2(fromGDB[1],1) < 0){puts("hat nicht geklappt");}
int backupStdin = dup(0); //store stdin
if (dup2(toGDB[0],0) < 0){puts("hat nicht geklappt");}
system("gdb -q --interpreter=mi2"); // start gdb mi
dup2(backup,1); // restore stdout
puts("child fertig");
exit(0);
}else{
close(toGDB[0]);
close(fromGDB[1]);
char* writeCommand = "";
int commandCounter = 0;
while (commandCounter <3){
nbytes = read(fromGDB[0],readbuffer,sizeof(readbuffer));
printf("parent recived: %s", readbuffer);
if (strncmp(readbuffer+strlen(readbuffer)-strlen("(gdb) \n"),"(gdb) \n", strlen("(gdb) \n")) == 0){
switch (commandCounter){
case 0: writeCommand = "-file-exec-and-symbols /home/dev/spielwiese/build/main\n"; break;
case 1: writeCommand = "-gdb-exit\n"; break;
default: writeCommand = "you should never reach here\n"; break;
}
write(toGDB[1],writeCommand,strlen(writeCommand)+1);
printf("wrote: %s", writeCommand);
commandCounter++;
}else if(strncmp(readbuffer,"^exit", sizeof("^exit")-1) == 0){
break;
}
memset(readbuffer,'\0',strlen(readbuffer)); //clear the readbuffer
}
puts("parent fertig");
sleep(5);
}
return 0;
}
If I call the same commands by hand, thats the output I get (-> means input from me)
-> gdb -q --interpreter=mi2
=thread-group-added,id="i1"
(gdb)
-> -file-exec-and-symbols /home/dev/spielwiese/build/main
^done
(gdb)
-> -gdb-exit
^exit
But if I run my code, which should be essentialy the same, I get this output:
Starting Test
parent recived: =thread-group-added,id="i1"
parent recived: (gdb)
wrote: -file-exec-and-symbols /home/dev/spielwiese/build/main
parent recived: ^done
(gdb)
wrote: -gdb-exit
parent recived: &"\n"
parent recived: ^done
(gdb)
wrote: you should never reach here
parent fertig
According to the gdb mi manual, an & preceeds a log entry, but this log entry is empty, exept for the newline. Also, I don't know why there should be a log entry for exiting, or why it fails to exit, but doesen't produce an error.
Also, if you know any better sources for gdb mi than this: https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html#GDB_002fMI , please let me know.
There are several issues with your example code, many of which have already been summarized in comments:
read() and write() transfer only the bytes specified, or a leading subsequence of those. They do not append null bytes to the transfer.
read() and write() are not guaranteed to transfer the full number of bytes requested on any given call.
your buffer might not be long enough to accommodate some responses from the child all in a single read().
According to the gdb mi manual, an & preceeds a log entry, but this log entry is empty, exept for the newline. Also, I don't know why there should be a log entry for exiting, or why it fails to exit, but doesen't produce an error.
None of the above explain the log entry or other behavior differences, but this probably does:
write(toGDB[1],writeCommand,strlen(writeCommand)+1);
Supposing that the full number of bytes requested is transferred, you are writing not only the command, but also a string terminator. The terminator is not part of the MI protocol, so your program is not behaving the same as your interactive session. Moreover, the particular error -- an extra null byte -- is one that is especially likely to produce mysterious output. I can only speculate about the specifics, but I could believe that gdb is treating the extra null byte immediately following a newline as if it terminated a zero-byte command. If so, then you are effectively issuing three commands to gdb, not two, and the gdb log output is about the null byte / empty command.
You would probably find stream I/O to be more convenient for your purposes than raw I/O. That would insulate you from many of the idiosyncrasies of raw I/O, and it would make fgets() available to you for input, which would be to your advantage. The fdopen() function can wrap streams around your file descriptors:
#define BUFFER_SIZE 1024
// Parent
FILE *fFromGDB = fdopen(fromGDB[0], "r");
FILE *fToGDB = fdopen(fToGDB[1], "w");
if (!fFromGDB || ! fToGDB) // ...
// You probably want fToGDB to be line-buffered, not block buffered:
setvbuf(fToGDB, NULL, _IOLBF, BUFFER_SIZE);
Then use fputs(), fgets(), fprintf(), etc. to interact with the child.
Also, if you know any better sources for gdb mi than this: https://sourceware.org/gdb/current/onlinedocs/gdb/GDB_002fMI.html#GDB_002fMI , please let me know.
Requests for external resources are off-topic here.
In any event, you are referencing the appropriate manual, and short of analyzing the source code, that is the ultimate source of knowledge on the matter.
Line number #15 { printf("This goes to the terminal\n"); } is not getting printed anywhere not in the terminal nor in the file.
//inputs argc = 3 :- ./executable_file output_file command
int main(int argc, char **argv)
{
if(argc < 3)
{
return 0;
}
int stdout_copy = dup(1);
int fd = open(argv[1], O_CREAT | O_RDWR | O_TRUNC, 0644);
if (fd < 0)
{
printf("ERROR\n");
return 0;
}
printf("This goes to the standard output(terminal).\n");
printf("Now the standard output will go to \"%s\" file .\n", argv[1]);
dup2(fd, 1);
printf("This output goes to \"%s\"\n",argv[1]);
close(fd);
execvp(argv[2],argv+2);
dup2(stdout_copy,1);
printf("This goes to the terminal\n");
return 0;
}
Apologies for the Previous Question :
I'm really sorry, it was my mistake in analysing it.
And special thanks for all answers and hints.
problem in writing to terminal after using execvp and dup2 syscalls
Neither:
execvp(argc[2],argc+2);
dup2(stdout_copy,1);
printf("This goes to the terminal\n");
Or:
dup2(stdout_copy,1);
execvp(argc[2],argc+2);
printf("This goes to the terminal\n");
...will output to stdout if the call to execvp(argc[2],argc+2); succeeds.
However, both will output to stdout if it fails.
(Unless command line arguments are incorrect, dup2() likely has nothing to do with failure to output to stdout. See additional content below for how to check this.)
Read all about it here: execvp.
In a nutshell, execvp() replaces the current process with a new process. If it is successful the current process is no longer what you are viewing on the terminal. Only when it is not successful will the commands following it be executed.
The following suggestions are not precisely on-topic, but important nonetheless...
Change:
int main(int argv, char **argc)
To:
int main(int argc, char **argv) //or int main(int argc, char *argv[]), either are fine.
This will be the foundation of seeing normal behavior. Anything else is very confusing to future maintainers of your code, and to people trying to understand what you are doing here.
These names are easily remembered by keeping in mind that argc is used for the count of command line arguments, and argv is the vector that is use to store them.
Also, your code shows no indications that you are checking/validating these arguments, but given the nature of your program, they should be validated before going on. For example:
//verify required number of command line arguments was entered
if(argc <!= 3)//requires at least one additional command line argument
{
printf("Usage: prog.exe [path_filename]\nInclude path_filename and try again.\nProgram will exit.");
return 0;
}
//check if file exists before going on
if( access( argv[1], F_OK ) != -1 )
{
// file exists
} else {
// file doesn't exist
}
//do same for argv[2]
(2nd example to check file in Linux environment is from here)
BTW, Knowing the command line arguments that were passed into the program, would help to provide a more definitive answer here. Their syntax and content, and whether or not the files that they reference exist, determine how the call to execvp will behave.
Suggestions
It is generally always look at the return values of functions that have them. But because of the unique behavior of execvp If is successful it does not return, and if it fails it will always return -1. So in this case pay special attention to the value of errno for error indications, again all of which are covered in the link above.
As mentioned in comments (in two places.) it is a good idea to use fflush(stdout) to empty buffers when interpreting standard I/O and file descriptor I/O, and before using any of the exec*() family of calls.
Take time to read the man pages for the functions - shell commands that are used. It will save time, and guide you during debugging sessions.
I've found that a open filestream will get messed up if we do fork() before closing it. It is well known that concurrency, i.e., race conditions can happen when parent and child process want to modify the filestream. However, even when the child process doesn't ever touch the filestream, it still has undefined behavior. I was wondering if someone can explain this maybe from how the kernel deals with a filestream during the stages where child process is forked and exited.
Below is a quick snippet of a strange behavior:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
// Open file
FILE* fp = fopen("test.txt", "r");
int count = 0;
char* buffer = NULL;
size_t capacity = 0;
ssize_t line = 0;
while ( (line = getline(&buffer, &capacity, fp)) != -1 ) {
if (line > 0 && buffer[line - 1] == '\n') // remove the end '\n'
buffer[line - 1] = 0;
pid_t pid = fork();
if (pid == 0) {
// fclose(fp); // Magic line here: when you add this, everything is fine
if (*buffer == '2')
execlp("xyz", "xyz", NULL);
else
execlp("pwd", "pwd", NULL);
exit(1);
} else {
waitpid(pid, NULL, 0);
}
count++;
}
printf("Loops: %d\n", count);
return 0;
}
Just copy the code into a new file (e.g., test.c). And create a .txt file test.txt with the simple content
1
2
3
4
and run
$ gcc test.c && ./a.out
There are 4 lines in the file. The loops is expected to read each line and execute exactly 4 times (1 2 3 4). And I choose to let it exec an invalid command "xyz" when it's in the 2nd loop. Then, you will find the loop actually executes 6 times (1 2 3 4 3 4)! The fact is that, when all four commands executed are valid, nothing will go wrong. But if there is an invalid command executed, every command after it will be executed twice. (Please note that this strange behavior only occurs with Linux machine, my Mac OS is doing okay, not sure about Windows. So the problem is platform-dependent?)
It looks like whenever I fork(), the filestream in parent is no longer promised to be the old fp (non-deterministic behavior), even when my child process doesn't touch it.
A temporary solution I found is: fclose(fp) in child process. This will silence the above strange behavior, but in more complex conditions, there are still other things can be observed. It would be appreciated if somebody can give me some insight into this problem. Thanks
As said in the comments already you need to close open file descriptors before calling exec.
In this blogpost (section 4) there is a neat code sample you can use to ensure all fds are closed even in complex applications where you don't always know what files are open at the moment:
for ( i=getdtablesize(); i>2; --i)
close(i); /* close all descriptors */
(slightly modified to keep stdin, stdout, stderr open)
It's kind of hacky but it works. If you want to avoid that you can also set the O_CLOEXEC flag on each file descriptor that you open. Since when using fopen you do not directly call open() you can accomplish this by adding the 'e' flag to it (when using glibc >= 2.7):
FILE* fp = fopen("test.txt", "er");
When calling exec*() all file descriptors with this flag are automatically closed.
I'm not an expert in C and I'm looking for some advice to to make my program more robust and reliable. Just to give some context: I've written a program to do some scientific computation that takes quite a long time (about 20h) that I'm executing on a large university HPC linux cluster using a SLRUM scheduling system and NFS mounted file systems. What seems to happen is that some time during the 20h the connection to the file system goes stale (on the entire machine; independent of my program) and the first attempt to open & write a file takes a really long time and that results in a segfault cored dumped error that I have so far not been able to precisely track down. Below is a minimal file that at least conceptually reproduces the error: The program starts, opens a file and everything works. The program does some long computation (simulated by sleep()), tries to open & write to the same file again, and it fails. What are some conventions to make my code more robust and reliably write my results to file without crashing?
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char **argv) {
// Declare variables
FILE *outfile;
char outname[150] = "result.csv";
// Open file for writing
printf("CHECKING if output file '%s' is writable?", outname);
outfile=fopen(outname, "w");
if (outfile == NULL) {
perror("Failed: ");
exit(EXIT_FAILURE);
}
fclose(outfile);
printf(" PASSED.\n");
// Do some computation that takes really long (around 19h)
sleep(3);
// Open file again and Write results
printf("Writing results to %s ...", outname);
outfile=fopen(outname, "w");
if (outfile == NULL) {
perror("Failed writing in tabulate_vector_new: ");
exit(EXIT_FAILURE);
}
fprintf( outfile, "This is the important result.\n");
fclose(outfile);
printf(" DONE.\n");
return 0;
}
It seems odd that your program would segfault due to an NFS issue. I would expect it to hang indefinitely, not crash. That having been said, I would suggest forking a new process to check whether the NFS mount is working. That way, your important code won't be directly involved in testing the problematic file system. Something like the following approach may be useful:
pid_t pid = fork();
if (pid == -1)
{
// error, failed to fork(). should probably give up now. something is really wrong.
}
else if (pid > 0)
{
// if the child exits, it has successfully interacted with the NFS file system
wait(NULL);
// proceed with attempting to write important data
}
else
{
// we are the child; fork df in order to test the NFS file system
execlp("df", "df", "/mnt", (char *)NULL)
// the child has been replaced by df, which will try to statfs(2) /mnt for us
}
The general concept here is that we utilize the df command to check whether the NFS file system (which I assume is at /mnt) is working. If it's temporarily not working, df should hang until it starts working again, and then exit, returning control to your program. If you suspect df might hang forever, you could enhance my example by using alarm(2) to wait a certain period of time, probably at least a few minutes, after which you could retry running df. Note that this could result in zombie df processes sticking around.
In the end, the correct solution is to try to get a more reliable NFS server, but until you can do that, I hope this is helpful.
I need to kill a process using the kill API. For that I need the process id of the process. I tried to get it using:
ret = system("pidof -s raj-srv");
but it is not returning the correct value. I dont want to kill the process using this:
ret = system("pkill raj");
Is there any API that could be used to get the process id?
You are getting the return status of system. That's not the pid. You want something like this:
char line[LEN];
FILE *cmd = popen("pidof...", "r");
fgets(line, LEN, cmd);
pid_t pid = strtoul(line, NULL, 10);
pclose(cmd);
There could be multiple instances of processes running in that case , pidof returns strings of pid seperated by space .
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
main()
{
char pidline[1024];
char *pid;
int i =0;
int pidno[64];
FILE *fp = popen("pidof bash","r");
fgets(pidline,1024,fp);
printf("%s",pidline);
pid = strtok (pidline," ");
while(pid != NULL)
{
pidno[i] = atoi(pid);
printf("%d\n",pidno[i]);
pid = strtok (NULL , " ");
i++;
}
pclose(fp);
}
The system() call doesn't return the output of pidof, it returns pidof's return code, which is zero if it succeeds.
You could consume the output of pidof using popen() instead of system(), but I'm sure there's a better way (the way pidof itself uses). Perhaps it wanders through /proc.
What is returned by the system function is the return code from the command being executed.
What you can do is something like this:
system("pidof -s raj-srv > /tmp/pid-of-raj-srv");
And then read the contents of the file /tmp/pid-of-raj-srv.
I know it is not a fresh thread, but as I have only recently faced the same question, I will ask you. Did you see one of this:
Get process id by name in C
C function to find a process ID and kill it
man sysctl(3)
You can use sysctl to give you the needed information without having to pass through a system( "bla, bla" ) call.
It seems to be far more complicated at first, but may be worth depending on your needs.