/* mini-at/src/mini-atd/setup.c * * (c)2006, Laurence Withers, . * 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); } void debug_handler(int sig); void setup_signals(void) { signal(SIGINT, signal_handler); signal(SIGTERM, signal_handler); signal(SIGUSR1, debug_handler); } /* options for text editors kate: replace-trailing-space-save true; space-indent true; tab-width 4; vim: expandtab:ts=4:sw=4 */