1

I have an strange issue. I am not very good in C language. I am trying to create a daemon to execute my bash script based service in Linux. To make it easy I have made the code simple. Below is my code.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <syslog.h>

int main(int argc, char* argv[])
{
    pid_t process_id = 0;
    pid_t sid = 0;
    process_id = fork();
    if (process_id < 0)
    {
        printf("fork failed!\n");
        exit(1);
    }
    if (process_id > 0)
    {
        printf("daemon creatd with process id %d \n", process_id);
        exit(0);
    }

    umask(0);
    sid = setsid();
    if(sid < 0)
    {
        fprintf(stderr, "Return error\n");
        exit(1);
    }

    chdir("/");
    close(STDIN_FILENO);
    close(STDOUT_FILENO);
    close(STDERR_FILENO);



    int status = system("ls");

    openlog("slog", LOG_PID|LOG_CONS, LOG_USER);
    syslog(LOG_INFO, "Returned status is %d", status);
    closelog();

    return (0);
}

As you can see, the above program will execute the system function to execute the ls command and output the exit code to system log.

After I compile the program and run, in the logs I can see the status code is 512. But If I comment out the following line,

close(STDOUT_FILENO);

then it works perfect and I can see in the log the status code is 0,

What I might be doing wrong?

UPDATE

My program is pretty big and I am not using ls in real environment. i made the program simple to reproduce the issue what I am facing. Also, to see the status of program, I am not looking at the output but the status code in the syslog.

Muneer
  • 7,384
  • 7
  • 38
  • 62
  • Why are you doing the `ls` and where do you expect its output to go? Child processes by convention inherit the stdout of the parent process. You closed the stdout in the parent process. `ls` uses stdout. This is the correct expected behaviour. – cdarke Nov 09 '16 at 16:39
  • [Somewhat related post](https://stackoverflow.com/questions/33121631/return-value-of-system-function) – user3386109 Nov 09 '16 at 16:42
  • my program is pretty big and I am not using `ls` in real environment. i made the program simple to reproduce the issue what I am facing. Also, to see the status of program, I am not looking at the out but but the statis code in the syslog. Hope you understand. – Muneer Nov 10 '16 at 02:31

2 Answers2

2

Your daemon creation looks fine. But daemon processes by convention do not have a controlling terminal which you accomplish by closing all the standard file descriptors and call setsid() to create a new session to make the daemon a session leader. So, you can't make the daemon produce any output on the stdout stream. It obviously works if you don't close the stdout stream.

So, what you are doing is trying to write something to a tty from a terminal. So, you either don't need a daemon for this purpose or you need to write to a different file (instead of stdout).

P.P
  • 117,907
  • 20
  • 175
  • 238
  • thanks for the response. unfortunately I am not expecting any output in this program. I am completely aware that there wont be any output after closing tbe `STDOUT`. Thats y I am using `log`. And my real program is not using `ls` at all. this is to minimize the scenario. I just put an update on the question. All what I need to know is, wether the externel program exited with `0` exit code or not using the `syslog`. – Muneer Nov 10 '16 at 02:37
2

In case it is not clear from other comments and answers, ls writes its output to stdout. If it can not write to stdout it terminates and (apparently) sets an status code of 512 (non-zero in any case).

The child process will inherit stdout from the parent, so if you do not close stdout in the parent, the child will have a stdout to write to and the command will succeed. If you close stdout, then the child has nowhere to write its output and the error occurs.

So, although ls is just an example for this question, your actual child process is writing to stdout which results in the same problem.

The simplest way around this, and assuming that you do not want the child's output, is to redirect the child's stdout on the command line:

int status = system("ls >/dev/null 2>&1");

This will redirect stdout and stderr to /dev/null, effectively throwing away the child's output while still giving it somewhere to write to.

mhawke
  • 84,695
  • 9
  • 117
  • 138