15 #include "daemonize.h"
17 static const char *daemon_pidfile
;
20 * Really stupid generic sighandler...
22 void daemon_shutdown(void)
25 unlink(daemon_pidfile
);
30 * Read a pid from "pidfile", which must contain one pid
33 static int read_pid(const char *pidfile
)
38 fd
= open(pidfile
, O_RDONLY
);
42 while ((read(fd
, &c
, 1)) > 0) {
45 pid
= (pid
* 10) + (c
- '0');
54 * Writes out the pidfile
56 static int write_pid(const char *pidfile
, int pid
)
60 if (!(fp
= fopen(pidfile
, "w")))
63 fprintf(fp
, "%d\n", pid
);
71 * Checks if a process with the pid found in *pidfile already exists.
72 * Returns 1 if it does, and 0 if it doesn't.
74 static int already_running(const char *pidfile
)
76 int pid
= read_pid(pidfile
);
81 if (kill(pid
, 0) < 0) {
88 fprintf(stderr
, "Failed to signal process %d: %s\n",
89 pid
, strerror(errno
));
95 static struct passwd
*get_user_entry(const char *user
)
102 while ((pw
= getpwent())) {
103 if (!strcmp(pw
->pw_name
, user
))
107 fprintf(stderr
, "No such user: %s\n", user
);
113 * Drop privileges neatly
115 * This code was taken from a patch I wrote for the Openwall
116 * distro. The patch was/is used in bind, nmap and dhclient
117 * shipped with Openwall
119 static unsigned drop_privs(struct passwd
*pw
)
121 /* XXX: is this enough? Where else is it present? */
122 #if defined(__GLIBC__)
123 /* group first, or we won't be able to swap uid */
124 if (setresgid(pw
->pw_gid
, pw
->pw_gid
, pw
->pw_gid
) < 0)
127 if (setresuid(pw
->pw_uid
, pw
->pw_uid
, pw
->pw_uid
) < 0)
134 if (getegid() != pw
->pw_gid
|| getgid() != pw
->pw_uid
)
137 if (geteuid() != pw
->pw_uid
|| getuid() != pw
->pw_uid
)
143 int kill_daemon(const char *pidfile
)
145 int pid
= already_running(pidfile
);
148 printf("Signalling process with pid %d\n", pid
);
155 puts("No daemon running");
160 int daemon_status(const char *pidfile
)
162 int pid
= already_running(pidfile
);
164 printf("Merlin is running\n");
167 printf("Merlin is not running\n");
173 * runas is the pseudo-user identity we assume
174 * jail is the directory we chdir() to before doing chroot(".")
175 * pidfile is written outside the jail.
176 * flags is a bitflag option specifier
178 int daemonize(const char *runas
, const char *jail
, const char *pidfile
, int flags
)
181 int pid
= already_running(pidfile
);
183 daemon_pidfile
= strdup(pidfile
);
186 fprintf(stderr
, "Another Merlin instance is already running with pid %d\n", pid
);
190 /* don't drop privs or chdir if we're debugging */
191 if (flags
& DMNZ_NOFORK
)
192 return write_pid(pidfile
, getpid());
194 if (jail
&& chdir(jail
) < 0) {
195 fprintf(stderr
, "Failed to chdir() to '%s': %s\n", jail
, strerror(errno
));
201 fprintf(stderr
, "fork() failed: %s\n", strerror(errno
));
206 /* baby daemon goes here */
208 /* start a new process group */
211 if (jail
&& flags
& DMNZ_CHROOT
&& (chroot(".") < 0 || chdir("/") < 0)) {
212 fprintf(stderr
, "chroot(%s) failed: %s", jail
, strerror(errno
));
216 pw
= get_user_entry(runas
);
217 if (pw
&& drop_privs(pw
) != pw
->pw_uid
) {
218 fprintf(stderr
, "Failed to drop privileges to user %s", pw
->pw_name
);
226 if (write_pid(pidfile
, pid
) != pid
) {
227 fprintf(stderr
, "Failed to write pidfile '%s': %s\n",
228 pidfile
, strerror(errno
));
235 if (flags
& DMNZ_NOFORK
)