summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAn-Cheng Huang <ancheng@vyatta.com>2007-12-14 16:11:16 -0800
committerAn-Cheng Huang <ancheng@vyatta.com>2007-12-14 16:11:16 -0800
commit95d19bd7cb014b65816dd9ccf61733c57f369b05 (patch)
treebeae37f09bc84860b36674aea0aad8a20410131b /src
parentd82436aecf73516a7a6ed92165478a8d462820f4 (diff)
downloadvyatta-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.c93
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 */