1/*
2 * Copyright (c) 2000-2004,2011,2014 Apple Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25//
26// demon - support code for writing UNIXoid demons
27//
28#include <security_utilities/daemon.h>
29#include <security_utilities/logging.h>
30#include <security_utilities/debugging.h>
31#include <sys/types.h>
32#include <errno.h>
33#include <unistd.h>
34#include <fcntl.h>
35
36namespace Security {
37namespace Daemon {
38
39
40//
41// Daemonize this process, the UNIX way.
42//
43bool incarnate(bool doFork /*=true*/)
44{
45	if (doFork) {
46		// fork with slight resilience
47		for (int forkTries = 1; forkTries <= 5; forkTries++) {
48			switch (fork()) {
49				case 0:			// child
50							// we are the daemon process (Har! Har!)
51					break;
52				case -1:		// parent: fork failed
53					switch (errno) {
54						case EAGAIN:
55						case ENOMEM:
56							Syslog::warning("fork() short on resources (errno=%d); retrying", errno);
57							sleep(forkTries);
58							continue;
59						default:
60							Syslog::error("fork() failed (errno=%d)", errno);
61							return false;
62					}
63				default:		// parent
64							// @@@ we could close an assurance loop here, but we don't (yet?)
65					exit(0);
66			}
67		}
68		// fork succeeded; we are the child; parent is terminating
69	}
70
71	// create new session (the magic set-me-apart system call)
72	setsid();
73
74	// redirect standard channels to /dev/null
75	close(0);	// fail silently in case 0 is closed
76	if (open("/dev/null", O_RDWR, 0) == 0) {	// /dev/null could be missing, I suppose...
77		dup2(0, 1);
78		dup2(0, 2);
79	}
80
81	// ready to roll
82	return true;
83}
84
85
86//
87// Re-execute myself.
88// This is a pretty bad hack for libraries that are pretty broken and (essentially)
89// don't work after a fork() unless you also exec().
90//
91// WARNING: Don't even THINK of doing this in a setuid-anything program.
92//
93bool executeSelf(char **argv)
94{
95	static const char reExecEnv[] = "_RE_EXECUTE";
96	if (getenv(reExecEnv)) {		// was re-executed
97		secdebug("daemon", "self-execution complete");
98		unsetenv(reExecEnv);
99		return true;
100	} else {
101		setenv(reExecEnv, "go", 1);
102		secdebug("daemon", "self-executing (ouch!)");
103		execv(argv[0], argv);
104		perror("re-execution");
105		Syslog::error("Re-execution attempt failed");
106		return false;
107	}
108}
109
110
111} // end namespace Daemon
112} // end namespace Security
113