diff options
author | An-Cheng Huang <ancheng@vyatta.com> | 2007-12-14 16:11:16 -0800 |
---|---|---|
committer | An-Cheng Huang <ancheng@vyatta.com> | 2007-12-14 16:11:16 -0800 |
commit | 95d19bd7cb014b65816dd9ccf61733c57f369b05 (patch) | |
tree | beae37f09bc84860b36674aea0aad8a20410131b /src | |
parent | d82436aecf73516a7a6ed92165478a8d462820f4 (diff) | |
download | vyatta-cfg-95d19bd7cb014b65816dd9ccf61733c57f369b05.tar.gz vyatta-cfg-95d19bd7cb014b65816dd9ccf61733c57f369b05.zip |
fix for bug 2479: when commit cannot obtain the config lock, it will retry
a fixed number of times and then check if the lock owner is still alive.
if not, the orphaned lock is cleaned up so that the later commit can proceed
as usual.
Diffstat (limited to 'src')
-rw-r--r-- | src/cli_new.c | 93 |
1 files changed, 91 insertions, 2 deletions
diff --git a/src/cli_new.c b/src/cli_new.c index 3f64489..b668e5b 100644 --- a/src/cli_new.c +++ b/src/cli_new.c @@ -14,6 +14,8 @@ #include "cli_val.h" #include "cli_parse.h" #include <regex.h> +#include <errno.h> +#include <time.h> #include "cli_objects.h" #include "cli_val_engine.h" @@ -229,6 +231,7 @@ void di(vtw_sorted *srtp) } #define LOCK_FILE "/opt/vyatta/config/.lock" +#define COMMIT_CMD "/opt/vyatta/sbin/my_commit" static void release_config_lock() @@ -237,6 +240,92 @@ release_config_lock() /* error ignored */ } +/* try to clean up orphaned lock file. return -1 if failed */ +static int +try_lock_cleanup() +{ + char buf[128]; + char proc[128]; + FILE *f = NULL; + int ret = -1; + struct stat statb; + + do { + /* get the proc entry */ + if ((f = fopen(LOCK_FILE, "r")) == NULL) { + break; + } + if (fgets(proc, 128, f) == NULL) { + break; + } + /* read the proc entry */ + if (stat(proc, &statb) == -1) { + if (errno == ENOENT) { + /* proc entry doesn't exist. can clean up the lock now */ + ret = 0; + break; + } + } + fclose(f); + if ((f = fopen(proc, "r")) == NULL) { + /* can't open proc entry. assume we can't clean up */ + break; + } + if (fgets(buf, 128, f) == NULL) { + /* can't read proc entry. assume we can't clean up */ + break; + } + /* check if the process is commit */ + if (strcmp(buf, COMMIT_CMD) == 0) { + /* it is commit. can't clean up */ + break; + } + /* can clean up the lock */ + ret = 0; + } while (0); + if (f) { + fclose(f); + } + if (ret == 0) { + unlink(LOCK_FILE); + if (stat(LOCK_FILE, &statb) != -1 || errno != ENOENT) { + /* proc entry still exists. cleanup failed */ + ret = -1; + } + } + return ret; +} + +static int +create_lock_file(int try_cleanup) +{ + int fd = -1; + int i = 0; + struct timespec req; + +#define LOCK_WAIT_TIME 2 +#define LOCK_NUM_RETRIES 5 + req.tv_sec = LOCK_WAIT_TIME; + req.tv_nsec = 0; + fd = open(LOCK_FILE, O_WRONLY | O_CREAT | O_EXCL, 0660); + if (fd == -1) { + for (i = 0; i < LOCK_NUM_RETRIES; i++) { + nanosleep(&req, NULL); + fd = open(LOCK_FILE, O_WRONLY | O_CREAT | O_EXCL, 0660); + if (fd >= 0) { + break; + } + } + } + if (fd == -1 && try_cleanup) { + if (try_lock_cleanup() != -1) { + /* cleanup succeeded */ + fd = create_lock_file(0); + } + } + return fd; +} + int get_config_lock() { @@ -246,7 +335,7 @@ get_config_lock() do { /* create lock file */ - fd = open(LOCK_FILE, O_WRONLY | O_CREAT | O_EXCL, 0660); + fd = create_lock_file(1); if (fd == -1) { break; } @@ -255,7 +344,7 @@ get_config_lock() if ((lfile = fdopen(fd, "w")) == NULL) { break; } - if (fprintf(lfile, "%u", getpid()) < 0) { + if (fprintf(lfile, "/proc/%u/cmdline", getpid()) < 0) { break; } /* fclose also closes fd */ |