summaryrefslogtreecommitdiff
path: root/libc/unistd/daemon.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/unistd/daemon.c')
-rw-r--r--libc/unistd/daemon.c51
1 files changed, 45 insertions, 6 deletions
diff --git a/libc/unistd/daemon.c b/libc/unistd/daemon.c
index 741672ec0..c3b563179 100644
--- a/libc/unistd/daemon.c
+++ b/libc/unistd/daemon.c
@@ -46,6 +46,20 @@
#include <paths.h>
#include <signal.h>
#include <unistd.h>
+#include <not-cancel.h>
+#include <errno.h>
+
+#ifdef __UCLIBC_HAS_THREADS_NATIVE__
+#include <sys/stat.h>
+#endif
+
+#ifdef __UCLIBC_HAS_LFS__
+#define STAT stat64
+#define FSTAT fstat64
+#else
+#define STAT stat
+#define FSTAT fstat
+#endif
#if defined __USE_BSD || (defined __USE_XOPEN && !defined __USE_UNIX98)
@@ -97,15 +111,40 @@ int daemon(int nochdir, int noclose)
if (setsid() == -1)
return -1;
+#ifndef __UCLIBC_HAS_THREADS_NATIVE__
+ /* Make certain we are not a session leader, or else we
+ * might reacquire a controlling terminal */
+ if (fork())
+ _exit(0);
+#endif
+
if (!nochdir)
chdir("/");
- if (!noclose && (fd = open(_PATH_DEVNULL, O_RDWR)) != -1) {
- dup2(fd, STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
- dup2(fd, STDERR_FILENO);
- if (fd > 2)
- close(fd);
+ if (!noclose)
+ {
+ struct STAT st;
+
+ if ((fd = open_not_cancel(_PATH_DEVNULL, O_RDWR, 0)) != -1
+ && (__builtin_expect (FSTAT (fd, &st), 0) == 0))
+ {
+ if (__builtin_expect (S_ISCHR (st.st_mode), 1) != 0) {
+ dup2(fd, STDIN_FILENO);
+ dup2(fd, STDOUT_FILENO);
+ dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ close(fd);
+ } else {
+ /* We must set an errno value since no
+ function call actually failed. */
+ close_not_cancel_no_status (fd);
+ __set_errno (ENODEV);
+ return -1;
+ }
+ } else {
+ close_not_cancel_no_status (fd);
+ return -1;
+ }
}
return 0;
}