mini-at/src/mini-atd/setup.c

183 lines
3.9 KiB
C
Raw Normal View History

2006-10-09 16:21:24 +01:00
/* mini-at/src/mini-atd/setup.c
*
* (c)2006, Laurence Withers, <l@lwithers.me.uk>.
* Released under the GNU GPLv2. See file COPYING or
* http://www.gnu.org/copyleft/gpl.html for details.
*/
/* Daemon
*
* Global flag which records whether or not we're daemonised. In daemon mode, we LOG() to syslog;
* otherwise, we LOG() to stdout/stderr.
*/
int Daemon = 0;
/* LOG(), do_log()
*
* The logging system.
*/
#define LOG(_level, _fmt, ...) do { \
do_log(_level, "%s:%d: %s: " _fmt, __FILE__, __LINE__, __FUNCTION__ , ##__VA_ARGS__); \
}while(0)
void do_log(int level, const char* fmt, ...)
{
va_list va;
va_start(va, fmt);
if(Daemon) {
vsyslog(level, fmt, va);
} else {
FILE* out = stdout;
switch(level) {
case LOG_WARNING:
case LOG_ERR:
case LOG_CRIT:
case LOG_ALERT:
case LOG_EMERG:
out = stderr;
}
vfprintf(out, fmt, va);
fputc('\n', out);
}
va_end(va);
}
/* daemonise()
*
* Turns us into a daemon. Returns 0 on success.
*/
int daemonise(void)
{
// normal daemon stuff
switch(fork()) {
case -1:
perror("fork");
return 1;
case 0:
// child
break;
default:
// parent
exit(0);
}
if(setsid() == -1) {
perror("setsid");
return 1;
}
// switch LOG() over to syslog
++Daemon;
openlog("mini-atd", 0, LOG_DAEMON);
// close file descriptors, re-open on /dev/null
close(0);
close(1);
close(2);
if(open("/dev/null", O_RDWR) == -1 || dup(0) == -1 || dup(1) == -1) {
LOG(LOG_CRIT, "Opening /dev/null or dup() failed - %s (%d).",
strerror(errno), errno);
return 123;
}
return 0;
}
/* setup_socket()
*
* Sets up a unix socket with the given name and permissions. Returns file descriptor on success,
* or -1 on error.
*/
int setup_socket(const char* name, int perms)
{
int fd;
long flags;
struct sockaddr_un addr;
// create socket structure
fd = socket(PF_UNIX, SOCK_DGRAM, 0);
if(fd == -1) {
LOG(LOG_CRIT, "Creating new socket with socket() failed - %s (%d).",
strerror(errno), errno);
return -1;
}
// set non-blocking mode
if( (flags = fcntl(fd, F_GETFL, 0)) == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK)) {
LOG(LOG_CRIT, "Couldn't set non-blocking mode on fd %d - %s (%d).",
fd, strerror(errno), errno);
return -1;
}
// bind to filename we were passed
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
strcpy(addr.sun_path, name); // main() ensures it is less than UNIX_PATH_MAX bytes
if(bind(fd, (struct sockaddr*)&addr, sizeof(addr))) {
LOG(LOG_CRIT, "Couldn't bind socket (fd %d) to file ``%s'' - %s (%d).",
fd, name, strerror(errno), errno);
close(fd);
return -1;
}
// set permissions
if(fchmod(fd, perms)) {
LOG(LOG_CRIT, "Couldn't set permissions %04o on socket ``%s'' (fd %d) - %s (%d).",
perms, name, fd, strerror(errno), errno);
close(fd);
unlink(name);
return -1;
}
return fd;
}
/* setup_signals(), signal_handler(), Quit
*
* Our signal handling mechanism. We want to exit cleanly on SIGINT or SIGTERM (these will set the
* global variable Quit). Otherwise, we want to abort.
*/
volatile int Quit = 0;
void signal_handler(int sig)
{
LOG(LOG_NOTICE, "Received signal %d, send again to force quit now.", sig);
Quit = 1;
// restore default signal handler to force quit next time
signal(sig, SIG_DFL);
}
2006-10-10 16:58:06 +01:00
void debug_handler(int sig);
2006-10-09 16:21:24 +01:00
void setup_signals(void)
{
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
2006-10-10 16:58:06 +01:00
signal(SIGUSR1, debug_handler);
2006-10-09 16:21:24 +01:00
}
/* options for text editors
kate: replace-trailing-space-save true; space-indent true; tab-width 4;
vim: expandtab:ts=4:sw=4
*/