/** Acquire the lock for the socket Returns the name of the lock file if successful or NULL if unable to obtain lock. The returned string must be free()d after unlink()ing the file to release the lock */ static bool acquire_socket_lock(const std::string &sock_name, std::string *out_lockfile_name) { bool success = false; std::string lockfile; lockfile.reserve(sock_name.size() + strlen(LOCKPOSTFIX)); lockfile = sock_name; lockfile.append(LOCKPOSTFIX); if (acquire_lock_file(lockfile, LOCKTIMEOUT, 1)) { out_lockfile_name->swap(lockfile); success = true; } return success; }
/** Acquire the lock for the socket Returns the name of the lock file if successful or NULL if unable to obtain lock. The returned string must be free()d after unlink()ing the file to release the lock */ static char *acquire_socket_lock( const char *sock_name ) { size_t len = strlen( sock_name ); char *lockfile = (char *)malloc( len + strlen( LOCKPOSTFIX ) + 1 ); if( lockfile == NULL ) { wperror( L"acquire_socket_lock" ); exit( EXIT_FAILURE ); } strcpy( lockfile, sock_name ); strcpy( lockfile + len, LOCKPOSTFIX ); if ( !acquire_lock_file( lockfile, LOCKTIMEOUT, 1 ) ) { free( lockfile ); lockfile = NULL; } return lockfile; }
long become_daemon(const char *run_as_user, const char *work_dir, const char *lock_file, int *fd_lock_file) { pid_t pid; int fd; *fd_lock_file = DAEMON_BAD_FD_LOCK_FILE; // Switch to specified user if (run_as_user) { struct passwd *pw_info = getpwnam(run_as_user); if (pw_info) { if (setuid(pw_info->pw_uid) == -1) { syslog_error("setuid failed for %s, code=%d (%s)", run_as_user, errno, strerror(errno)); return DAEMON_FAILURE; } } else { syslog_error("getpwnam failed for %s", run_as_user); return DAEMON_FAILURE; } } // Step 1 : Create a child process pid = fork(); switch (pid) { case -1 : syslog_error("fork(1) failed, code=%d (%s)", errno, strerror(errno)); return DAEMON_FAILURE; case 0 : break; // Child falls through default : exit(EXIT_SUCCESS); // Parent terminates OK } // Step 2 : Become leader of new session if (setsid() == -1) { syslog_error("setsid failed, code=%d (%s)", errno, strerror(errno)); return DAEMON_FAILURE; } // Step 3 : Ensure no controlling terminal pid = fork(); switch (pid) { case -1 : syslog_error("fork(2) failed, code=%d (%s)", errno, strerror(errno)); return DAEMON_FAILURE; case 0 : break; // Grand-child falls through default : exit(EXIT_SUCCESS); // Child terminates OK } // This process (grand-child) will be the actual daemon // Step 4 : Clear file mode creation mask umask(0); // Step 5 : Change current working directory if (chdir(work_dir) == -1) { syslog_error("chdir to '%s' failed, code=%d (%s)", work_dir, errno, strerror(errno)); return DAEMON_FAILURE; } // Step 6: Close standard file descriptors close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); // Step 7 : Redirect standard file descriptors to /dev/null fd = open("/dev/null", O_RDWR); if (fd != STDIN_FILENO) { syslog_error("Redirect STDIN failed, code=%d (%s)", errno, strerror(errno)); return DAEMON_FAILURE; } if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) { syslog_error("Redirect STDOUT failed, code=%d (%s)", errno, strerror(errno)); return DAEMON_FAILURE; } if (dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) { syslog_error("Redirect STDERR failed, code=%d (%s)", errno, strerror(errno)); return DAEMON_FAILURE; } // Create lock file to prevent more than one instance // of the daemon is being executed if (lock_file) { if (acquire_lock_file(lock_file, fd_lock_file) != DAEMON_SUCCESS) { return DAEMON_FAILURE; } } return DAEMON_SUCCESS; }