Linux Daemon not working - c++

I have created a daemon for linux in c++, however, the child process does not seem to be doing anything. Once it reaches the if(pid > 0) statement, everything seems to stop.
The code for the Daemon.Start() is as follows:
//Process ID and Session ID
pid_t pid,sid;
//Fork off the Parent Process
pid = fork();
if(pid < 0)
exit(EXIT_FAILURE);
//If PID is good, then exit the Parent Process
if(pid > 0)
exit(EXIT_SUCCESS);
//Change the file mode mask
umask(0);
//Create a new SID for the Child Process
sid = setsid();
if(sid < 0)
{
exit(EXIT_FAILURE);
}
//Change the current working directory
if((chdir("/")) < 0)
{
//Log the failure
exit(EXIT_FAILURE);
}
//Close out the standard file descriptors
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
//The main loop.
Globals::LogError("Service started.");
while(true)
{
//The Service task
Globals::LogError("Service working.");
if(!SystemConfiguration::IsFirstRun() && !SystemConfiguration::GetMediaUpdateReady())
{
SyncServer();
}
sleep(SystemConfiguration::GetServerConnectionFrequency()); //Wait 30 seconds
}
exit(EXIT_SUCCESS);
Any help would be great! :)

I'm pretty sure your child process dies within either the sid < 0 or the chdir("/") < 0 if statement. Write to stderr in these cases before exit to reveal what the problem is:
//Create a new SID for the Child Process
sid = setsid();
if(sid < 0)
{
fprintf(stderr,"Failed to create SID: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
//Change the current working directory
int chdir_rv = chdir("/");
if(chdir_rv < 0)
{
fprintf(stderr,"Failed to chdir: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
You need to include <errno.h> and <string.h> in order to have errno and strerror defined (respectively).
Regards

Related

How to run a Bash script and receive its exit code asynchronously on a macOS?

I'm new to macOS dev. Most of my background is on Windows.
I am trying to write a function for my launch daemon that should run a Bash script via its file path and then get notified asynchronously when it finishes running and get its exit code (I think it's called "status code" on Linux.) Or send an error in the callback if it fails to run the Bash script.
I'm using the following, which also includes my two-part question in comments:
void RunExternalScript(const char* pScriptFilePath,
void (*pfnCallback)(int exitCode, const void* pParam),
const void* pParam)
{
//'pfnCallback' = should be called when 'pScriptFilePath' finishes running
//Fork our process
pid_t pidChild = fork();
if(pidChild == 0)
{
//Child process, start our Bash script
execl(pScriptFilePath, (const char*)nullptr);
//We get here only if we failed to run our script
log("Error %d running script: %s", errno, pScriptFilePath);
abort();
}
else if(pidChild != -1)
{
//Started our script OK, but how do I wait for it
//asynchronously to finish?
//
//If I call here:
//
// int nExitCode;
// waitpid(pidChild, &nExitCode, 0);
//
//It will block until the child process exits,
//which I don't want to do since I may want to
//run more than one script, plus my daemon may
//receive a request to quit, so I need to be able
//to cancel this wait for the child process...
//And the second question:
//
//How do I know from this process that the forked
//process failed to run my script?
}
else
{
log("Error running: %s", pScriptFilePath);
}
}
You can use the "waitpid" function with the "WNOHANG" option. This will allow you to wait for the child process to finish, but not block the calling process.
You can then also check the return value of "waitpid" to determine if the child process has finished or not.
To check if the child process failed to run the script, you can check the return value of "execl".
void RunExternalScript(const char* pScriptFilePath,
void (pfnCallback)(int exitCode, const void pParam),
const void* pParam)
{
pid_t pidChild = fork();
if(pidChild == 0)
{
if (execl(pScriptFilePath, (const char*)nullptr) == -1)
{
log("Error %d running script: %s", errno, pScriptFilePath);
exit(EXIT_FAILURE);
}
}
else if(pidChild != -1)
{
int nExitCode;
pid_t ret = waitpid(pidChild, &nExitCode, WNOHANG);
if (ret == -1)
{
log("Error %d waiting for child process", errno);
}
else if (ret == 0)
{
}
else
{
if (WIFEXITED(nExitCode))
{
nExitCode = WEXITSTATUS(nExitCode);
}
else
{
nExitCode = -1;
}
pfnCallback(nExitCode, pParam);
}
}
else
{
log("Error running: %s", pScriptFilePath);
}
}

Hung parent while reading stderr from child process through pipe in C++

I fork a child process which in turn spawns a grand-child process and returns. If there are any errors in spawning that grand-child, the child writes to stderr using fprintf statements and exits.
I am trying to read stderr from the child process in the parent. But, the parent gets hung in the while loop reading from child process. When I look at ps -ef the child is <defunct>.
Following is the code I wrote to accomplish this. I am new to this and the search on web does not give enough information about why the parent is hung when the child is
int pipe_out[2];
// Create the pipe
if (pipe(pipe_out) < 0) {
perror("Failed pipe");
exit(1);
}
// Create the child process
int status;
pid_t pid = fork();
switch(pid) {
case -1:
perror("Failed fork");
exit(1);
case 0: { // Child
close(pipe_out[0]); // close read end
// Make stderr go to pipe write end
dup2(pipe_out[1], STDERR_FILENO);
close(pipe_out[1]);
// start my process
execvp(inp_args[0], inp_args);
_exit(EXIT_FAILURE);
break;
}
default: { // Parent
close(pipe_out[1]); // close write end
// read from child
while( read(pipe_out[0], buffer, sizeof(buffer)) )
log(stdout, "%s\n",buffer);
}
// wait for end then close other end of pipe
waitpid(pid, &status, 0);
if (WIFSIGNALED(status))
log(stdout, "killed by signal %d\n", WTERMSIG(status));
close(pipe_out[0]);
}
}

Exec after forking a process doesn't return the result before the program finishes

I'm trying to make a program that forks once and while the parent waits for the child terminates, this child forks again and then executes two execs. There is a Pipe on the program and I've checked the return values of every dup2() and pipe() on the program -just omitted them here to make it looks more concise-. The problem is that I only get the result of ls -a | sort -r AFTER the program finishes.
The code is:
#include <cstdio>
#include <cstring>
#include <sys/wait.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
int main(int argc, char *argv[]) {
printf("Shell> \n"); fflush(stdout);
pid_t pid1;
pid_t pid2;
int status = 0;
int fd[2];
if(pipe(fd) < 0) {
printf("FATAL ERROR.\n");
}
pid1 = fork();
if(pid1 > 0) { // Parent
waitpid(pid1, &status, 0);
printf("\t\t------PID1 Complete-------\n\n");
}
else { // Child
if(pid1 == 0) {
printf("ON CHILD\n");
pid2 = fork();
if(pid2 > 0) { // Child -> Parent
printf("ON CHILD-Parent\n");
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
waitpid(pid2, &status, 0);
printf("ON CHILD-Parent after wait\n");
execlp("sort", "sort", "-r", NULL);
perror("Problem with execlp\n");
exit(1);
}
else { // Child -> Child
printf("ON CHILD->Child\n");
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
execlp("ls", "ls", "-a", NULL);
perror("Problem with execvp\n");
exit(1);
}
} // End of if(pid1 == 0)
} // End of Child
printf("\nEnd of program.\n");
return 0;
}
My current output is:
Shell>
ON CHILD
ON CHILD-Parent
ON CHILD->Child
ON CHILD-Parent after wait
I think the problem is on the waits, but I just can't figure out how to make this work. Any ideas? Thanks!
The problem is that you call pipe in the grandparent process. After the grandchild process (ls -a) exits, the parent process (sort -r) blocks indefinitely waiting to read more input from the pipe since some process - the grandparent - holds an open descriptor to the write end of the pipe.
If you close the pipe descriptors in the grandparent process, or better yet move the pipe call into the first forked process, then the sort process will terminate when the last process with an open descriptor for the write end of the pipe exits (DEMO):
int main() {
// Turn off buffering of stdout, to help with debugging
setvbuf(stdout, NULL, _IONBF, 0);
printf("Shell> \n");
pid_t pid1 = fork();
if(pid1 < 0) {
perror("fork failed");
}
if(pid1 > 0) { // Parent
int status;
waitpid(pid1, &status, 0);
printf("\t\t------PID1 Complete (%d) -------\n\n", status);
} else { // Child
printf("ON CHILD\n");
int fd[2];
if(pipe(fd) < 0) {
perror("pipe failed");
return 1;
}
pid_t pid2 = fork();
if(pid2 < 0) {
perror("fork failed");
}
if(pid2 > 0) { // Child -> Parent
printf("ON CHILD-Parent\n");
close(fd[1]);
dup2(fd[0], STDIN_FILENO);
execlp("sort", "sort", "-r", NULL);
perror("Problem with execlp");
return 1;
} else { // Child -> Child
printf("ON CHILD->Child\n");
close(fd[0]);
dup2(fd[1], STDOUT_FILENO);
execlp("ls", "ls", "-a", NULL);
perror("Problem with execvp");
return 1;
}
}
printf("\nEnd of program.\n");
}
The other problem with the program is the one #nategoose commented on: the call to waitpid could lead to a deadlock if the output of "ls -a" is too large to fit in the pipe's buffer. There's no reason to wait, so it should simply be eliminated.
This isn't a real answer, but I have some into that I'd like to share.
To make sure that your output comes out in the order that it should, I'm flushing a lot more than you were. Remember that when you are calling functions like fork(), clone(), vfork(), dup(), dup2(), close(), or any of the exec() family of functions you are doing stuff that is BELOW the C runtime environment, which includes stdio. If you do:
printf("cat");
fork();
fflush(stdout);
You are very likely to get:
catcat
as your output because you've duplicated the stdout structure, including all buffered data, so unless stdio decided that it was time to flush anyway before the end of the printf function, then "cat" is in each process's stdout buffer.
There's also the fact that since data can stay buffered when you run a function in the exec family your data may not be flushed before your program is replaced with the new program. When your program is replaced by ls or sort then any data pending in stdout gets lost forever.
Also, when you use dup you have the another issue since you are swapping the file descriptor out from under stdio so it may not have flushed yet and the data may end up getting flushed to the new file after the dup.
Because of these things you should have a lot more calls to fflush, but I don't think that's your problem here.

c++ ServerSocket(), FD_CLOEXEC, fork() & execl()

I had issues trying to background a command in my app, so I was told here to double fork and clear some of the settings, so this was my result:
if((pid = fork()) < 0)
perror("Error with Fork()");
else if(pid > 0) {
return "";
}
if (setsid()==-1) {
Log("failed to become a session leader");
}
if (chdir("/") == -1) {
Log("failed to change working directory");
}
umask(0);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
if (open("/dev/null",O_RDONLY) == -1) {
Log("failed to reopen stdin");
}
if (open("/dev/null",O_WRONLY) == -1) {
Log("failed to reopen stdout");
}
if (open("/dev/null",O_RDWR) == -1) {
Log("failed to reopen stderr");
}
signal(SIGHUP, SIG_IGN);
Log("No return, forking..");
if((pid = fork()) < 0)
perror("Error with Fork()");
else if(pid > 0) {
return "";
} else {
if(execl("/bin/bash", "/bin/bash", "-c", cmddo, (char*) 0) < 0) perror("execl()");
exit(0);
}
Double forking fixed the issue of the execl'd proc stopping when its parent is closed but it left me with the execl'd process holding onto the parents socket, so when the parent tries to start again it can't.
Here is my parent socket stuff:
ServerSocket server(listenport);
while(true)
{
ServerSocket* new_sock = new ServerSocket();
server.accept (*new_sock);
pthread_t thread;
int rc = pthread_create(&thread, NULL, &LoadThread, (void*)(new_sock));
if (rc) Log_warn("Fatal Error: pthread_create() #%d", rc);
pthread_detach(thread);
}
I was told to FD_CLOEXEC on the socket in my last question but I do not understand how-to do that - and google (plus stack) isn't showing me much help in regards to that.
How do I FD_CLOEXEC on my ServerSocket() so when I fork/execl a sub process it won't hang my socket?
Thanks :D
ANSWER:
As told below to clear the fd's out - my code actually had this, and it worked for me:
struct rlimit rl;
int i;
if (rl.rlim_max == RLIM_INFINITY)
rl.rlim_max = 1024;
for (i = 0; (unsigned) i < rl.rlim_max; i++)
close(i);
FD_CLOEXEC is a flag that can be set on the file descriptor -- its effect is that when a process holding the handle calls exec(), the descriptor is closed.
Use
fcntl(fd, F_SETFD, (long)FD_CLOEXEC);
to set the flag; for this to work, you need to access the actual file descriptor.
Also, setsid() is fully sufficient to disassociate yourself from the parent process group, and while double fork() also works, it does not earn you brownie points with the embedded folks.
And last, there is no guarantee that after closing the first three filedescriptors, the next fds opened will be those three; it is better to use
fd newstdin = open(...);
if(dup2(newstdin, STDIN_FILENO) != 0) { /* handle error */ }
close(newstdin);

How to use Ptrace on Linux to print Call Stack of Other Processes of C++

i am working on an application which needs call stack of all executing processes on Linux.
i am trying to use ptrace but not able to go ahead with it because the steps i need to follow in my code are not clear to me.
i also tryied backtrace, but its use is limmited to current process.
could some one guide me on the same.
Thanks,
Sandeep
Take a look at the pstack code. pstack is available on ubuntu lucid.
This code is taken from HP UX man page of ptrace.
Hope this is useful.
The following example illustrates the use of some of the ptrace()
calls by a tracing process.
#include <stdio.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/ptrace.h>
#define BUFSIZ 1024
#define MAXPATH 1024
pid_t npid, cpid, pid;
int status, errors=0, pathlength;
ptrace_event_t *event_addr;
ptrace_state_t *state_addr;
char *buf_addr;
size_t event_len, state_len;
int filed[2];
child()
{
int n, bar;
close(filed[1]);
/* Wait for parent to write to pipe */
while ((n = read(filed[0], &bar, BUFSIZ)) == 0);
/* Now the child can exec. */
if (execlp("ls", "ls", (char *)0) < 0) /* error during exec */
printf("Child: exec failed\n");
exit(0);
}
parent()
{
close(filed[0]);
/* Before child does an exec, attach it and set its event flag. */
if (ptrace(PT_ATTACH,pid)) /* failed to attach process */
printf("Parent: Failed to attach child\n");
if (pid != wait(&status)) /* wait failed */
printf("Parent: attach failed with wrong wait status\n");
if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP))
printf("Parent: SIGTRAP didn't stop child\n");
/*
* The child process has now stopped. Set its event flag indicating
* that it needs to trigger on a PTRACE_EXEC event.
*/
event_addr->pe_set_event = PTRACE_EXEC;
if (ptrace(PT_SET_EVENT_MASK, pid, event_addr, event_len))
printf("Parent: PT_SET_EVENT_MASK ptrace request failed\n");
if (pid != wait(&status)) /* wait failed */
printf("Parent: wait() failed with wrong wait status\n");
/*
* Send the child a message so it can break out of the while loop.
* Get it running so it can exec.
*/
write(filed[1], "now run", 7);
if (ptrace(PT_CONTIN, pid, 1, 0) != 0)
printf("Parent: failed to get child process running\n");
/*
* Wait for the traced child to stop after the exec system call in
* response to an exec event set in its ptrace_event structure.
*/
if (pid != (npid = wait(&status))) /* wait failed */
printf("Parent: wait() failed with wrong status\n");
if (!WIFSTOPPED(status))
printf("Parent: invalid wait() completion\n");
/*
* Child has stopped; fetch its process state and examine state
* information.
*/
if (ptrace(PT_GET_PROCESS_STATE, pid, state_addr, state_len) < 0)
printf("Parent: PT_GET_PROCESS_STATE ptrace request failed\n");
if (pid != wait(&status)) /* wait failed */
printf("Parent: wait() failed with wrong wait status\n");
/* Check if the pathlength value returned is non-zero */
if ((pathlength = state_addr->pe_path_len) == 0)
printf("Parent: zero length pathname returned\n");
/* Fetch exec'd file pathname and store it in the buffer. */
if (ptrace(PT_GET_PROCESS_PATHNAME, pid, buf_addr, (pathlength+1))
< 0){
printf("Parent: Failed to get exec pathname\n");
} else {
printf("Parent: the exec pathname is %s\n", buf_addr);
if (pid != wait(&status)) /* wait failed */
printf("Parent: wait() failed with wrong status\n");
}
}
main()
{
event_len = sizeof(ptrace_event_t);
state_len = sizeof(ptrace_state_t);
event_addr = calloc(event_len, 1);
state_addr = calloc(state_len, 1);
buf_addr = calloc(MAXPATH, 1);
pipe(filed);
switch (pid = fork()) {
case -1:
exit(1);
case 0:
child();
break;
default:
parent();
break;
}
}