| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514 |
- /** BEGIN COPYRIGHT BLOCK
- * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission.
- * Copyright (C) 2005 Red Hat, Inc.
- * All rights reserved.
- *
- * License: GPL (version 3 or any later version).
- * See LICENSE for details.
- * END COPYRIGHT BLOCK **/
- #ifdef HAVE_CONFIG_H
- # include <config.h>
- #endif
- /* protect_db.c
- * Used to police access to the db. Prevents different instances of
- * slapd from clobbering each other
- */
- #define LOCK_FILE "lock"
- #define IMPORT_DIR "imports"
- #define EXPORT_DIR "exports"
- #define SERVER_DIR "server"
- #define NUM_TRIES 20
- #define WAIT_TIME 250
- #include <sys/types.h>
- #include <sys/time.h>
- #include <sys/stat.h>
- #include <fcntl.h> /* open */
- #include <unistd.h>
- #include <errno.h>
- #include <signal.h>
- #include <sys/param.h> /* MAXPATHLEN */
- #include <dirent.h>
- #include <pwd.h>
- #include "protect_db.h"
- #include "slap.h"
- static int
- grab_lockfile()
- {
- pid_t pid, owning_pid;
- char lockfile[MAXPATHLEN];
- int fd, x;
- int removed_lockfile = 0;
- struct timeval t;
- slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
- /* Don't use anything that makes a NSPR call here (like LDAPDebug)! This function
- gets called by an atexit function, and NSPR is long gone by then. */
- /* Get the name of the lockfile */
- snprintf(lockfile, sizeof(lockfile), "%s/%s", slapdFrontendConfig->lockdir, LOCK_FILE);
- lockfile[sizeof(lockfile)-1] = (char)0;
- /* Get our pid */
- pid = getpid();
- /* Try to grab it */
- if ((fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0644)) != -1) {
- /* We got the lock, write our pid to the file */
- write(fd, (void *) &pid, sizeof(pid_t));
- close(fd);
- return 0;
- }
-
- /* We weren't able to get the lock. Find out why. */
- if (errno != EEXIST) {
- /* Hmm, something happened that we weren't prepared to handle */
- fprintf(stderr, ERROR_ACCESSING_LOCKFILE, lockfile);
- return -1;
- }
- while(1) {
- /* Try to grab the lockfile NUM_TRIES times waiting WAIT_TIME milliseconds after each try */
- t.tv_sec = 0;
- t.tv_usec = WAIT_TIME * 1000;
- for(x = 0; x < NUM_TRIES; x++) {
- if ((fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0644)) != -1) {
- /* Got the lock */
- write(fd, (void *) &pid, sizeof(pid_t));
- close(fd);
- return 0;
- }
- select(0, NULL, NULL, NULL, &t);
- }
-
- /* We still haven't got the lockfile. Find out who owns it and see if they are still up */
- if ((fd = open(lockfile, O_RDONLY)) != -1) {
- size_t nb_bytes=0;
- nb_bytes = read(fd, (void *) &owning_pid, sizeof(pid_t));
- if ( (nb_bytes != (size_t)(sizeof(pid_t)) ) || (owning_pid == 0) || (kill(owning_pid, 0) != 0 && errno == ESRCH) ) {
- /* The process that owns the lock is dead. Try to remove the old lockfile. */
- if (unlink(lockfile) != 0) {
- /* Unable to remove the stale lockfile. */
- fprintf(stderr, LOCKFILE_DEAD_OWNER, lockfile, owning_pid);
- return -1;
- }
- if (removed_lockfile) {
- /* We already removed the lockfile once. Best thing to do is give up. */
- /* I'm not sure what should be given as an error here */
- fprintf(stderr, UNABLE_TO_GET_LOCKFILE, lockfile);
- return -1;
- } else {
- removed_lockfile = 1;
- }
- } else {
- /* It looks like the owner of the lockfile is still up and running. */
- fprintf(stderr, LOCKFILE_ALREADY_OWNED, owning_pid);
- return -1;
- }
- }
- }
- }
- static void
- release_lockfile()
- {
- char lockfile[MAXPATHLEN];
- slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
- /* This function assumes that the caller owns the lock, it doesn't check to make sure! */
- snprintf(lockfile, sizeof(lockfile), "%s/%s", slapdFrontendConfig->lockdir, LOCK_FILE);
- lockfile[sizeof(lockfile)-1] = (char)0;
- unlink(lockfile);
- }
- /* Takes the pid of a process. Returns 1 if the process seems
- * to be up, otherwise it returns 0.
- */
- static int
- is_process_up(pid_t pid)
- {
- if (kill(pid, 0) == -1 && errno == ESRCH) {
- return 0;
- } else {
- return 1;
- }
- }
- /* Make sure the directory 'dir' exists and is owned bye the user
- * the server runs as. Returns 0 if everything is ok.
- */
- static int
- make_sure_dir_exists(char *dir)
- {
- struct passwd* pw;
- struct stat stat_buffer;
- slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
- /* Make sure it exists */
- if (PR_MkDir(dir, 0755) != PR_SUCCESS) {
- PRErrorCode prerr = PR_GetError();
- if (prerr != PR_FILE_EXISTS_ERROR) {
- LDAPDebug(LDAP_DEBUG_ANY, FILE_CREATE_ERROR, dir, prerr, slapd_pr_strerror(prerr));
- return 1;
- }
- }
- /* Make sure it's owned by the correct user */
- if (slapdFrontendConfig->localuser != NULL &&
- slapdFrontendConfig->localuserinfo != NULL) {
- pw = slapdFrontendConfig->localuserinfo;
- if (chown(dir, pw->pw_uid, -1) == -1) {
- if ((stat(dir, &stat_buffer) == 0) && (stat_buffer.st_uid != pw->pw_uid)) {
- LDAPDebug(LDAP_DEBUG_ANY, CHOWN_WARNING, dir, 0, 0);
- return 1;
- } else {
- LDAPDebug(LDAP_DEBUG_ANY, STAT_ERROR, dir, errno, 0);
- return 1;
- }
- }
- }
- return 0;
- }
-
- /* Creates a file in the directory 'dir_name' whose name is the
- * pid for this process.
- */
- static void
- add_this_process_to(char *dir_name)
- {
- char file_name[MAXPATHLEN];
- struct passwd* pw;
- struct stat stat_buffer;
- PRFileDesc* prfd;
- slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
- snprintf(file_name, sizeof(file_name), "%s/%d", dir_name, getpid());
- file_name[sizeof(file_name)-1] = (char)0;
-
- if ((prfd = PR_Open(file_name, PR_RDWR | PR_CREATE_FILE, 0644)) == NULL) {
- LDAPDebug(LDAP_DEBUG_ANY, FILE_CREATE_WARNING, file_name, 0, 0);
- return;
- }
-
- /* Make sure the owner is of the file is the user the server
- * runs as. */
- if (slapdFrontendConfig->localuser != NULL &&
- slapdFrontendConfig->localuserinfo != NULL) {
- pw = slapdFrontendConfig->localuserinfo;
- if (chown(file_name, pw->pw_uid, -1) == -1) {
- if ((stat(file_name, &stat_buffer) == 0) && (stat_buffer.st_uid != pw->pw_uid)) {
- LDAPDebug(LDAP_DEBUG_ANY, CHOWN_WARNING, file_name, 0, 0);
- }
- }
- }
- PR_Close(prfd);
- }
- /* The directory 'dir_name' is expected to contain files whose
- * names are the pid of running slapd processes. This
- * function will check each entry in the directory and remove
- * any files that represent processes that don't exist.
- * Returns 0 if there are no processes represented, or
- * the pid of one of the processes.
- */
- static long
- sample_and_update(char *dir_name)
- {
- PRDir *dir;
- PRDirEntry *entry;
- pid_t pid;
- long result = 0;
- char *endp;
- char file_name[MAXPATHLEN];
- if ((dir = PR_OpenDir(dir_name)) == NULL) {
- return 0;
- }
- while((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
- pid = (pid_t) strtol(entry->name, &endp, 0);
- if (*endp != '\0') {
- /* not quite sure what this file was, but we
- * didn't put it there */
- continue;
- }
- if (is_process_up(pid)) {
- result = (long) pid;
- } else {
- PR_snprintf(file_name, MAXPATHLEN, "%s/%s", dir_name, entry->name);
- PR_Delete(file_name);
- }
- }
- PR_CloseDir(dir);
- return result;
- }
- /* Removes any stale pid entries and the pid entry for this
- * process from the directory 'dir_name'.
- */
- static void
- remove_and_update(char *dir_name)
- {
- /* since this is called from an atexit function, we can't use
- * NSPR. */
- DIR *dir;
- struct dirent *entry;
- pid_t pid;
- pid_t our_pid;
- char *endp;
- char file_name[MAXPATHLEN];
- /* get our pid */
- our_pid = getpid();
- if ((dir = opendir(dir_name)) == NULL) {
- return;
- }
- while((entry = readdir(dir)) != NULL) {
-
- /* skip dot and dot-dot */
- if (strcmp(entry->d_name, ".") == 0 ||
- strcmp(entry->d_name, "..") == 0)
- continue;
- pid = (pid_t) strtol(entry->d_name, &endp, 0);
- if (*endp != '\0') {
- /* not quite sure what this file was, but we
- * didn't put it there */
- continue;
- }
- if (!is_process_up(pid) || pid == our_pid) {
- PR_snprintf(file_name, sizeof(file_name), "%s/%s", dir_name, entry->d_name);
- unlink(file_name);
- }
- }
- closedir(dir);
- }
-
- /* Walks through all the pid directories and clears any stale
- * pids. It also removes the files for this process.
- */
- void
- remove_slapd_process()
- {
- char import_dir[MAXPATHLEN];
- char export_dir[MAXPATHLEN];
- char server_dir[MAXPATHLEN];
- slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
- /* Create the name of the directories that hold the pids of the currently running
- * ns-slapd processes */
- snprintf(import_dir, sizeof(import_dir), "%s/%s", slapdFrontendConfig->lockdir, IMPORT_DIR);
- import_dir[sizeof(import_dir)-1] = (char)0;
- snprintf(export_dir, sizeof(export_dir), "%s/%s", slapdFrontendConfig->lockdir, EXPORT_DIR);
- export_dir[sizeof(export_dir)-1] = (char)0;
- snprintf(server_dir, sizeof(server_dir), "%s/%s", slapdFrontendConfig->lockdir, SERVER_DIR);
- server_dir[sizeof(server_dir)-1] = (char)0;
- /* Grab the lockfile */
- if (grab_lockfile() != 0) {
- /* Unable to grab the lockfile */
- return;
- }
- remove_and_update(import_dir);
- remove_and_update(export_dir);
- remove_and_update(server_dir);
- release_lockfile();
- }
- int
- add_new_slapd_process(int exec_mode, int r_flag, int skip_flag)
- {
- char import_dir[MAXPATHLEN];
- char export_dir[MAXPATHLEN];
- char server_dir[MAXPATHLEN];
- int running, importing, exporting;
- int result = 0;
- slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
- if (skip_flag) {
- return 0;
- }
- /* Create the name of the directories that hold the pids of the currently running
- * ns-slapd processes */
- snprintf(import_dir, sizeof(import_dir), "%s/%s", slapdFrontendConfig->lockdir, IMPORT_DIR);
- import_dir[sizeof(import_dir)-1] = (char)0;
- snprintf(export_dir, sizeof(export_dir), "%s/%s", slapdFrontendConfig->lockdir, EXPORT_DIR);
- export_dir[sizeof(export_dir)-1] = (char)0;
- snprintf(server_dir, sizeof(server_dir), "%s/%s", slapdFrontendConfig->lockdir, SERVER_DIR);
- server_dir[sizeof(server_dir)-1] = (char)0;
- /* Grab the lockfile */
- if (grab_lockfile() != 0) {
- /* Unable to grab the lockfile */
- return -1;
- }
- /* Make sure the directories exist */
- if (make_sure_dir_exists(slapdFrontendConfig->lockdir) != 0 ||
- make_sure_dir_exists(import_dir) != 0 ||
- make_sure_dir_exists(export_dir) != 0 ||
- make_sure_dir_exists(server_dir) != 0) {
- release_lockfile();
- return -1;
- }
- /* Go through the directories and find out what's going on.
- * Clear any stale pids encountered. */
- importing = sample_and_update(import_dir);
- exporting = sample_and_update(export_dir);
- running = sample_and_update(server_dir);
- switch (exec_mode) {
- case SLAPD_EXEMODE_SLAPD:
- if (running) {
- result = -1;
- LDAPDebug(LDAP_DEBUG_ANY, NO_SERVER_DUE_TO_SERVER, running, 0, 0);
- } else if (importing) {
- result = -1;
- LDAPDebug(LDAP_DEBUG_ANY, NO_SERVER_DUE_TO_IMPORT, importing, 0, 0);
- } else {
- add_this_process_to(server_dir);
- result = 0;
- }
- break;
- case SLAPD_EXEMODE_DB2LDIF:
- if (r_flag) {
- /* When the -r flag is used in db2ldif we need to make sure
- * we get a consistent snapshot of the server. As a result
- * it needs to run by itself, so no other slapd process can
- * change the database while it is running. */
- if (running || importing) {
- LDAPDebug(LDAP_DEBUG_ANY, NO_DB2LDIFR_DUE_TO_USE, 0, 0, 0);
- result = -1;
- } else {
- /* Even though this is really going to export code, we will
- * but it in the importing dir so no other process can change
- * things while we are doing ldif2db with the -r flag. */
- add_this_process_to(import_dir);
- result = 0;
- }
- } else {
- if (importing) {
- LDAPDebug(LDAP_DEBUG_ANY, NO_DB2LDIF_DUE_TO_IMPORT, importing, 0, 0);
- result = -1;
- } else {
- add_this_process_to(export_dir);
- result = 0;
- }
- }
- break;
- case SLAPD_EXEMODE_DB2ARCHIVE:
- if (importing) {
- LDAPDebug(LDAP_DEBUG_ANY, NO_DB2BAK_DUE_TO_IMPORT, importing, 0, 0);
- result = -1;
- } else {
- add_this_process_to(export_dir);
- result = 0;
- }
- break;
- case SLAPD_EXEMODE_ARCHIVE2DB:
- case SLAPD_EXEMODE_LDIF2DB:
- if (running || importing || exporting) {
- LDAPDebug(LDAP_DEBUG_ANY, NO_IMPORT_DUE_TO_USE, 0, 0, 0);
- result = -1;
- } else {
- add_this_process_to(import_dir);
- result = 0;
- }
- break;
- case SLAPD_EXEMODE_DB2INDEX:
- if (running || importing || exporting) {
- LDAPDebug(LDAP_DEBUG_ANY, NO_DB2INDEX_DUE_TO_USE, 0, 0, 0);
- result = -1;
- } else {
- add_this_process_to(import_dir);
- result = 0;
- }
- break;
- case SLAPD_EXEMODE_UPGRADEDB:
- if (running || importing || exporting) {
- LDAPDebug(LDAP_DEBUG_ANY, NO_UPGRADEDB_DUE_TO_USE, 0, 0, 0);
- result = -1;
- } else {
- add_this_process_to(import_dir);
- result = 0;
- }
- break;
- case SLAPD_EXEMODE_UPGRADEDNFORMAT:
- if (running || importing || exporting) {
- LDAPDebug(LDAP_DEBUG_ANY, NO_UPGRADEDNFORMAT_DUE_TO_USE, 0, 0, 0);
- result = -1;
- } else {
- add_this_process_to(import_dir);
- result = 0;
- }
- break;
- case SLAPD_EXEMODE_DBTEST:
- if (running || importing || exporting) {
- LDAPDebug(LDAP_DEBUG_ANY, NO_DBTEST_DUE_TO_USE, 0, 0, 0);
- result = -1;
- } else {
- add_this_process_to(import_dir);
- result = 0;
- }
- break;
- }
- release_lockfile();
-
- if (result == 0) {
- atexit(remove_slapd_process);
- }
- return result;
- }
- /* is_slapd_running()
- * returns 1 if slapd is running, 0 if not, -1 on error
- */
- int
- is_slapd_running() {
- char server_dir[MAXPATHLEN];
- slapdFrontendConfig_t *cfg = getFrontendConfig();
- int running = 0;
-
- snprintf(server_dir, sizeof(server_dir), "%s/%s", cfg->lockdir, SERVER_DIR);
- server_dir[sizeof(server_dir)-1] = (char)0;
-
- /* Grab the lockfile */
- if (grab_lockfile() != 0) {
- /* Unable to grab the lockfile */
- return -1;
- }
- /* Make sure the directories exist */
- if (make_sure_dir_exists(cfg->lockdir) != 0 ||
- make_sure_dir_exists(server_dir) != 0) {
- release_lockfile();
- return -1;
- }
-
- running = sample_and_update(server_dir);
- release_lockfile();
- return running;
- }
|