/* zentific-poll: statistics collection daemon for Zentific * Copyright (C) 2007, 2008 * Steven Maresca, Justin Demaris, * and Zentific LLC * * All rights reserved. * Use is subject to license terms. * * Please visit http://zentific.com for news and updates * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ #ifndef DAEMONIZE_H_ #define DAEMONIZE_H_ #include #include #include #include #include #include #include #include #include #include #include extern int errno; /** * Detaches daemon from the terminal and it's caller * * @param int ignsigcld 0 if we want to pay attention to child deaths, 1 to ignore. */ int daemonize(int ignsigcld) { register int childpid; // If we are a child of init, then we don't need to break out any further if ( getppid() != 1 ) { // Ignore most signals that would make us exit signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTERM, SIG_IGN); // Fork and kill the parent - makes sure we aren't a process group leader if ( (childpid = fork()) < 0 ) perror("ERROR: Can't fork first child.\n"); else if ( childpid > 0 ) exit(0); // parent exits // Disassociate from controlling terminal and group if ( setpgrp() == -1 ){ perror("ERROR: Can't become process group leader.\n"); return -1; } // ignore group leader death signal(SIGHUP, SIG_IGN); // fork and kill parent again - makes sure we can't reaquire a command terminal if ( (childpid = fork()) < 0 ) { perror("ERROR: Can't fork second child.\n"); } else if (childpid > 0) { // first child exits exit(0); } } // mark no errors so far errno = 0; // set file creation umask(027); if (chdir("/") < 0) return -1; // Check if we want to ignore children exit statuses if ( ignsigcld ) signal(SIGCLD, SIG_IGN); return 0; } int detach_daemon(){ // if pidfile is to be generated, do so before calling this function // (needs stderr to still be open) /* redirect fd 0,1,2 to /dev/null */ int fd; if ((fd = open("/dev/null",O_RDWR)) == -1) { return -1; } int i; for (i = 0; i <= 2; i++) { close(i); int dup = dup2(fd, i); if(dup == -1) return -1; } close(fd); return 0; } int make_pidfile(char *filename){ //NOTE: open is by nature more primitive than fopen, but permits a higher level of granularity in permissions, // locking, and error handling //FIXME: may want O_EXCL here to replace O_TRUNC. the latter truncates the file to 0 if it already exists, // whereas the former causes it to fail if file exists (implying either that the daemon is already // running or it exited uncleanly last time. side topic: existence of a pidfile is lockfile enough // modes for file perms: the access permission bits in the file mode of the file are set to permit reading and writing by // the owner, and to permit reading only by group members and others mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; int fd = open(filename, O_RDWR | O_EXCL | O_CREAT, mode); // fd = open(pidfile, O_RDWR | O_TRUNC | O_CREAT, mode); if (fd == -1) //to signal potential unclean exit and/or daemon is already running return -2; if (lockf(fd, F_TLOCK, 0) == -1) return -1; char buf[100]; int len = sprintf(buf, "%ld\n", (long)getpid()); if (write(fd, buf, len) < 0) return -1; //unlocking can probably fail silently, POSIX locks are generally ignored anyway lockf(fd, F_ULOCK, 0); int closed = close(fd); if(closed == -1) return -1; return 0; } #endif /*DAEMONIZE_H_*/