2 * Copyright (C) 1997-2008 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file daemon.c Some helpers for programs that detach from the console. */
13 #include <sys/types.h>
19 * Do the usual stuff to become a daemon.
21 * Fork, become session leader, dup fd 0, 1, 2 to /dev/null.
23 * \sa fork(2), setsid(2), dup(2).
25 void daemon_init(void)
30 PARA_INFO_LOG("daemonizing\n");
35 exit(EXIT_SUCCESS
); /* parent exits */
36 /* become session leader */
42 null
= open("/dev/null", O_RDONLY
);
45 if (dup2(null
, STDIN_FILENO
) < 0)
47 if (dup2(null
, STDOUT_FILENO
) < 0)
49 if (dup2(null
, STDERR_FILENO
) < 0)
54 PARA_EMERG_LOG("fatal: %s\n", strerror(errno
));
59 * fopen() the given file in append mode.
61 * \param logfile_name The name of the file to open.
63 * \return Either calls exit() or returns a valid file handle.
65 FILE *open_log(const char *logfile_name
)
70 logfile
= fopen(logfile_name
, "a");
72 PARA_EMERG_LOG("can not open %s: %s\n", logfile_name
,
81 * Close the log file of the daemon.
83 * \param logfile The log file handle.
85 * It's OK to call this with logfile == \p NULL.
87 void close_log(FILE* logfile
)
91 PARA_INFO_LOG("closing logfile\n");
96 * Log the startup message containing the paraslash version.
98 void log_welcome(const char *whoami
, int loglevel
)
100 PARA_INFO_LOG("welcome to %s " PACKAGE_VERSION
" ("BUILD_DATE
")\n",
102 PARA_DEBUG_LOG("using loglevel %d\n", loglevel
);
106 * Give up superuser privileges.
108 * \param username The user to switch to.
109 * \param groupname The group to switch to.
111 * This function returns immediately if not invoked with EUID zero. Otherwise,
112 * it tries to obtain the GID of \a groupname and the UID of \a username. On
113 * success, effective and real GID/UID and the saved set-group-ID/set-user-ID
114 * are all set accordingly. On errors, an appropriate message is logged and
115 * exit() is called to terminate the process.
117 * \sa getpwnam(3), getuid(2), setuid(2), getgrnam(2), setgid(2)
119 void para_drop_privileges(const char *username
, const char *groupname
)
127 struct group
*g
= getgrnam(groupname
);
129 PARA_EMERG_LOG("failed to get group %s: %s\n",
130 groupname
, strerror(errno
));
133 if (setgid(g
->gr_gid
) < 0) {
134 PARA_EMERG_LOG("failed to set group id %d: %s\n",
135 (int)g
->gr_gid
, strerror(errno
));
140 PARA_EMERG_LOG("root privileges, but no user option given\n");
143 tmp
= para_strdup(username
);
147 PARA_EMERG_LOG("%s: no such user\n", username
);
150 PARA_INFO_LOG("dropping root privileges\n");
152 PARA_DEBUG_LOG("uid: %d, euid: %d\n", (int)getuid(), (int)geteuid());
156 * Set/get the server uptime.
158 * \param set_or_get Chose one of the two modes.
160 * This should be called at startup time with \a set_or_get equal to \p
161 * UPTIME_SET which sets the uptime to zero. Subsequent calls with \a
162 * set_or_get equal to \p UPTIME_GET return the uptime.
164 * \return Zero if called with \a set_or_get equal to \p UPTIME_SET, the number
165 * of seconds ellapsed since the last reset otherwise.
167 * \sa time(2), difftime(3).
169 time_t server_uptime(enum uptime set_or_get
)
171 static time_t startuptime
;
175 if (set_or_get
== UPTIME_SET
) {
180 diff
= difftime(now
, startuptime
);
181 return (time_t) diff
;
185 * Construct string containing uptime.
187 * \return A dynamically allocated string of the form "days:hours:minutes".
191 __malloc
char *uptime_str(void)
193 long t
= server_uptime(UPTIME_GET
);
194 return make_message("%li:%02li:%02li", t
/ 86400,
195 (t
/ 3600) % 24, (t
/ 60) % 60);