/* * Project 3 - Shared memory and semaphores. * Dr. Silaghi's Operating System Concepts. * daemon.c - Contains daemon init/destroy functions. * By Michael Rywalt - 2569 */ #include #include #include #include #include #include #include #include #include #include "main.h" #define MAXSTRLEN 128 #define ROOTDIR "/" #define LOCKFILE "/tmp/.rywaltP3" static int *pMemory; /*********** * SigTerm * *********** * * Function: SigTerm * * Purpose: Log and shut daemon down. * * Parameters: None. * * Returns: Nothing. */ static void SigTerm() { syslog(LOG_INFO, " [SIGTERM Caught] Terminating."); DestroyDaemon(0); } /*************** * daemon_init * *************** * * Function: daemon_init * * Purpose: To spin off the daemon with all appropriate parameters and * configuration settings. * * Parameters: None. * * Returns: Nothing. */ static void daemon_init() { pid_t pid; char szLogMsg[MAXSTRLEN]; int iLockFileDescriptor; /* Check if we're already a daemon. */ if(getppid() == 1) { return; } syslog(LOG_INFO, " [%s] Forking.", __FUNCTION__); /* Fork first child. */ pid = fork(); /* Handle fork error. */ if(pid < 0) { sprintf(szLogMsg, " [%s] Fork failed with error %d", __FUNCTION__, pid); syslog(LOG_INFO, szLogMsg); exit(EXIT_ERROR); } /* Handle parent quitting. */ if(pid > 1) { syslog(LOG_INFO, " [%s] parent quitting.", __FUNCTION__); exit(EXIT_OK); } /******** Daemon ********/ syslog(LOG_INFO, " [%s] Fork succeeded, executing child.", __FUNCTION__); /* Create a new session. */ setsid(); /* Catch signals. */ signal(SIGTTOU, SIG_IGN); /* Ignore background processes on same tty. */ signal(SIGTTIN, SIG_IGN); /* Ignore background processes on same tty. */ signal(SIGCHLD, SIG_IGN); /* Ability to avoid zombie processes. */ signal(SIGTSTP, SIG_IGN); /* We never want to be suspended. */ signal(SIGHUP , SIG_IGN); /* Ignore hangups. */ signal(SIGTERM, SigTerm); /* We will quit when sent the term signal. */ /* The first child (Session Leader) should quit. */ pid = fork(); /* Handle fork error. */ if(pid < 0) { sprintf(szLogMsg, " [%s] Fork failed with error %d", __FUNCTION__, pid); syslog(LOG_INFO, szLogMsg); exit(EXIT_ERROR); } /* This is our daemon. */ else if(pid > 0) { /* We can now change directories and close file descriptors. */ chdir(ROOTDIR); umask(0); close(0); close(1); close(2); syslog(LOG_INFO, " [%s] Daemon has officially started.", __FUNCTION__); /* Set up a lockfile so no other instances of this daemon run at once. */ iLockFileDescriptor = open(LOCKFILE, O_RDWR | O_CREAT, 0640); /* Validate lockfile. */ if(iLockFileDescriptor < 0) { syslog(LOG_INFO, " [%s] Failed to open lock file, quitting.", __FUNCTION__); exit(EXIT_ERROR); } if(lockf(iLockFileDescriptor, F_TLOCK, 0) < 0) { syslog(LOG_INFO, " [%s] Cannot lock. Is another instance running?", __FUNCTION__); exit(EXIT_ERROR); } syslog(LOG_INFO, " [%s] Lock file installed.", __FUNCTION__); /* Write the PID to the lockfile. */ sprintf(szLogMsg, "%d\n", getpid()); write(iLockFileDescriptor, szLogMsg, strlen(szLogMsg)); } /* Otherwise, we are the first child and must quit. */ else { syslog(LOG_INFO, " [%s] First child quitting...", __FUNCTION__); exit(EXIT_OK); } } /************** * InitDaemon * ************** * * Function: InitDaemon * * Purpose: To initialize logging of daemon to system log and call the main * daemon function. * * Parameters: None. * * Returns: Nothing. */ void InitDaemon(int *pMem) { pMemory = pMem; printf("Daemon starting...\n"); /* Open logging. */ openlog(PROJECT, LOG_PID, LOG_DAEMON); syslog(LOG_INFO, "[%s] Project's daemon is starting.", __FUNCTION__); /* Call the main daemon function. */ daemon_init(); } /***************** * DestroyDaemon * ***************** * * Function: DestroyDaemon * * Purpose: To shut down logging and exit with an appropriate level. * * Parameters: iLevel - Exit level. * * Returns: Nothing. */ void DestroyDaemon(int iLevel) { if(pMemory) { DetatchSharedMemory(pMemory); } DestroySemaphore(); /* Shut down logging in preparation to quit. */ syslog(LOG_INFO, "[%s] Project's daemon is stopping.", __FUNCTION__); closelog(); /* Exit with appropriate level. */ exit(iLevel); }