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
|
|
|
|
*/
|