From 5e635e396020cc08bc21a3e67c20c5294d6d13fd Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Sat, 21 Apr 2007 03:11:10 -0700 Subject: lockfile: record the primary process. The usual process flow is the main process opens and holds the lock to the index, does its thing, perhaps spawning children during the course, and then writes the resulting index out by releaseing the lock. However, the lockfile interface uses atexit(3) to clean it up, without regard to who actually created the lock. This typically leads to a confusing behaviour of lock being released too early when the child exits, and then the parent process when it calls commit_lockfile() finds that it cannot unlock it. This fixes the problem by recording who created and holds the lock, and upon atexit(3) handler, child simply ignores the lockfile the parent created. Signed-off-by: Junio C Hamano --- lockfile.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index bed6b21daf..23db35aff2 100644 --- a/lockfile.c +++ b/lockfile.c @@ -8,8 +8,11 @@ static const char *alternate_index_output; static void remove_lock_file(void) { + pid_t me = getpid(); + while (lock_file_list) { - if (lock_file_list->filename[0]) + if (lock_file_list->owner == me && + lock_file_list->filename[0]) unlink(lock_file_list->filename); lock_file_list = lock_file_list->next; } @@ -28,6 +31,7 @@ static int lock_file(struct lock_file *lk, const char *path) sprintf(lk->filename, "%s.lock", path); fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= fd) { + lk->owner = getpid(); if (!lk->on_list) { lk->next = lock_file_list; lock_file_list = lk; -- cgit v1.2.3 From a6080a0a44d5ead84db3dabbbc80e82df838533d Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 7 Jun 2007 00:04:01 -0700 Subject: War on whitespace This uses "git-apply --whitespace=strip" to fix whitespace errors that have crept in to our source files over time. There are a few files that need to have trailing whitespaces (most notably, test vectors). The results still passes the test, and build result in Documentation/ area is unchanged. Signed-off-by: Junio C Hamano --- lockfile.c | 1 - 1 file changed, 1 deletion(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 23db35aff2..5ad2858b48 100644 --- a/lockfile.c +++ b/lockfile.c @@ -97,4 +97,3 @@ void rollback_lock_file(struct lock_file *lk) unlink(lk->filename); lk->filename[0] = 0; } - -- cgit v1.2.3 From 9a4cbdca34f6aa9424fce8a55fe9dd6f7c25d97b Mon Sep 17 00:00:00 2001 From: Sven Verdoolaege Date: Fri, 13 Jul 2007 16:14:50 +0200 Subject: lockfile.c: schedule remove_lock_file only once. Removing a lockfile once should be enough. Signed-off-by: Sven Verdoolaege Signed-off-by: Junio C Hamano --- lockfile.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 5ad2858b48..fb8f13bbb9 100644 --- a/lockfile.c +++ b/lockfile.c @@ -31,16 +31,16 @@ static int lock_file(struct lock_file *lk, const char *path) sprintf(lk->filename, "%s.lock", path); fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= fd) { + if (!lock_file_list) { + signal(SIGINT, remove_lock_file_on_signal); + atexit(remove_lock_file); + } lk->owner = getpid(); if (!lk->on_list) { lk->next = lock_file_list; lock_file_list = lk; lk->on_list = 1; } - if (lock_file_list) { - signal(SIGINT, remove_lock_file_on_signal); - atexit(remove_lock_file); - } if (adjust_shared_perm(lk->filename)) return error("cannot fix permission bits on %s", lk->filename); -- cgit v1.2.3 From d58e8d34b019d435b424811c6f972910dfac6f55 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Wed, 25 Jul 2007 16:22:55 -0700 Subject: When locking in a symlinked repository, try to lock the original. In a working tree prepared in new-workdir (in contrib/), some files in .git/ directory are symbolic links to the original repository. The usual sequence of lock-write-rename would break the symbolic link. Ideally we should resolve relative symbolic link with maxdepth, but I do not want to risk too elaborate patch before 1.5.3 release, so this is a minimum and trivially obvious fix. new-workdir creates its symbolic links absolute, and does not link from a symlinked workdir, so this fix should suffice for now. Signed-off-by: Junio C Hamano --- lockfile.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index fb8f13bbb9..9202472498 100644 --- a/lockfile.c +++ b/lockfile.c @@ -28,6 +28,19 @@ static void remove_lock_file_on_signal(int signo) static int lock_file(struct lock_file *lk, const char *path) { int fd; + struct stat st; + + if ((!lstat(path, &st)) && S_ISLNK(st.st_mode)) { + ssize_t sz; + static char target[PATH_MAX]; + sz = readlink(path, target, sizeof(target)); + if (sz < 0) + warning("Cannot readlink %s", path); + else if (target[0] != '/') + warning("Cannot lock target of relative symlink %s", path); + else + path = target; + } sprintf(lk->filename, "%s.lock", path); fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= fd) { -- cgit v1.2.3 From 5d5a7a67384ad03007eea1f365ee255c02a40fa3 Mon Sep 17 00:00:00 2001 From: "Bradford C. Smith" Date: Thu, 26 Jul 2007 13:34:14 -0400 Subject: fully resolve symlinks when creating lockfiles Make the code for resolving symlinks in lockfile.c more robust as follows: 1. Handle relative symlinks 2. recursively resolve symlink chains up to 5 [jc: removed lstat/stat calls to do things stupid way] Signed-off-by: Bradford C. Smith Signed-off-by: Junio C Hamano --- lockfile.c | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 102 insertions(+), 14 deletions(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 9202472498..9a1f64d8d7 100644 --- a/lockfile.c +++ b/lockfile.c @@ -25,23 +25,111 @@ static void remove_lock_file_on_signal(int signo) raise(signo); } +/* + * p = absolute or relative path name + * + * Return a pointer into p showing the beginning of the last path name + * element. If p is empty or the root directory ("/"), just return p. + */ +static char *last_path_elm(char *p) +{ + /* r starts pointing to null at the end of the string */ + char *r = strchr(p, '\0'); + + if (r == p) + return p; /* just return empty string */ + + r--; /* back up to last non-null character */ + + /* back up past trailing slashes, if any */ + while (r > p && *r == '/') + r--; + + /* + * then go backwards until I hit a slash, or the beginning of + * the string + */ + while (r > p && *(r-1) != '/') + r--; + return r; +} + + +/* We allow "recursive" symbolic links. Only within reason, though */ +#define MAXDEPTH 5 + +/* + * p = path that may be a symlink + * s = full size of p + * + * If p is a symlink, attempt to overwrite p with a path to the real + * file or directory (which may or may not exist), following a chain of + * symlinks if necessary. Otherwise, leave p unmodified. + * + * This is a best-effort routine. If an error occurs, p will either be + * left unmodified or will name a different symlink in a symlink chain + * that started with p's initial contents. + * + * Always returns p. + */ + +static char *resolve_symlink(char *p, size_t s) +{ + int depth = MAXDEPTH; + + while (depth--) { + char link[PATH_MAX]; + int link_len = readlink(p, link, sizeof(link)); + if (link_len < 0) { + /* not a symlink anymore */ + return p; + } + else if (link_len < sizeof(link)) + /* readlink() never null-terminates */ + link[link_len] = '\0'; + else { + warning("%s: symlink too long", p); + return p; + } + + if (link[0] == '/') { + /* absolute path simply replaces p */ + if (link_len < s) + strcpy(p, link); + else { + warning("%s: symlink too long", p); + return p; + } + } else { + /* + * link is a relative path, so I must replace the + * last element of p with it. + */ + char *r = (char*)last_path_elm(p); + if (r - p + link_len < s) + strcpy(r, link); + else { + warning("%s: symlink too long", p); + return p; + } + } + } + return p; +} + + static int lock_file(struct lock_file *lk, const char *path) { int fd; - struct stat st; - - if ((!lstat(path, &st)) && S_ISLNK(st.st_mode)) { - ssize_t sz; - static char target[PATH_MAX]; - sz = readlink(path, target, sizeof(target)); - if (sz < 0) - warning("Cannot readlink %s", path); - else if (target[0] != '/') - warning("Cannot lock target of relative symlink %s", path); - else - path = target; - } - sprintf(lk->filename, "%s.lock", path); + + if (strlen(path) >= sizeof(lk->filename)) return -1; + strcpy(lk->filename, path); + /* + * subtract 5 from size to make sure there's room for adding + * ".lock" for the lock file name + */ + resolve_symlink(lk->filename, sizeof(lk->filename)-5); + strcat(lk->filename, ".lock"); fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= fd) { if (!lock_file_list) { -- cgit v1.2.3 From 4723ee992cba052dc735b7d2b6f43aad26d9150a Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Tue, 13 Nov 2007 21:05:03 +0100 Subject: Close files opened by lock_file() before unlinking. This is needed on Windows since open files cannot be unlinked. Signed-off-by: Johannes Sixt Signed-off-by: Junio C Hamano --- lockfile.c | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 9a1f64d8d7..258fb3f5ef 100644 --- a/lockfile.c +++ b/lockfile.c @@ -12,8 +12,10 @@ static void remove_lock_file(void) while (lock_file_list) { if (lock_file_list->owner == me && - lock_file_list->filename[0]) + lock_file_list->filename[0]) { + close(lock_file_list->fd); unlink(lock_file_list->filename); + } lock_file_list = lock_file_list->next; } } @@ -120,8 +122,6 @@ static char *resolve_symlink(char *p, size_t s) static int lock_file(struct lock_file *lk, const char *path) { - int fd; - if (strlen(path) >= sizeof(lk->filename)) return -1; strcpy(lk->filename, path); /* @@ -130,8 +130,8 @@ static int lock_file(struct lock_file *lk, const char *path) */ resolve_symlink(lk->filename, sizeof(lk->filename)-5); strcat(lk->filename, ".lock"); - fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); - if (0 <= fd) { + lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); + if (0 <= lk->fd) { if (!lock_file_list) { signal(SIGINT, remove_lock_file_on_signal); atexit(remove_lock_file); @@ -148,7 +148,7 @@ static int lock_file(struct lock_file *lk, const char *path) } else lk->filename[0] = 0; - return fd; + return lk->fd; } int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error) @@ -163,6 +163,7 @@ int commit_lock_file(struct lock_file *lk) { char result_file[PATH_MAX]; int i; + close(lk->fd); strcpy(result_file, lk->filename); i = strlen(result_file) - 5; /* .lock */ result_file[i] = 0; @@ -194,7 +195,9 @@ int commit_locked_index(struct lock_file *lk) void rollback_lock_file(struct lock_file *lk) { - if (lk->filename[0]) + if (lk->filename[0]) { + close(lk->fd); unlink(lk->filename); + } lk->filename[0] = 0; } -- cgit v1.2.3 From ecf4831d89ba6986249e1bf232b2e2f5f7536223 Mon Sep 17 00:00:00 2001 From: Steffen Prohaska Date: Sun, 25 Nov 2007 23:29:03 +0100 Subject: Use is_absolute_path() in diff-lib.c, lockfile.c, setup.c, trace.c Using the helper function to test for absolute paths makes porting easier. Signed-off-by: Steffen Prohaska Signed-off-by: Junio C Hamano --- lockfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 258fb3f5ef..f45d3ed544 100644 --- a/lockfile.c +++ b/lockfile.c @@ -94,7 +94,7 @@ static char *resolve_symlink(char *p, size_t s) return p; } - if (link[0] == '/') { + if (is_absolute_path(link)) { /* absolute path simply replaces p */ if (link_len < s) strcpy(p, link); -- cgit v1.2.3 From d6cf61bfd4bccffcc8b095f8469dbe749d70abdf Mon Sep 17 00:00:00 2001 From: Brandon Casey Date: Wed, 16 Jan 2008 11:05:32 -0800 Subject: close_lock_file(): new function in the lockfile API The lockfile API is a handy way to obtain a file that is cleaned up if you die(). But sometimes you would need this sequence to work: 1. hold_lock_file_for_update() to get a file descriptor for writing; 2. write the contents out, without being able to decide if the results should be committed or rolled back; 3. do something else that makes the decision --- and this "something else" needs the lockfile not to have an open file descriptor for writing (e.g. Windows do not want a open file to be renamed); 4. call commit_lock_file() or rollback_lock_file() as appropriately. This adds close_lock_file() you can call between step 2 and 3 in the above sequence. Signed-off-by: Junio C Hamano --- lockfile.c | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index f45d3ed544..663f18f9c4 100644 --- a/lockfile.c +++ b/lockfile.c @@ -13,7 +13,8 @@ static void remove_lock_file(void) while (lock_file_list) { if (lock_file_list->owner == me && lock_file_list->filename[0]) { - close(lock_file_list->fd); + if (lock_file_list->fd >= 0) + close(lock_file_list->fd); unlink(lock_file_list->filename); } lock_file_list = lock_file_list->next; @@ -159,17 +160,26 @@ int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on return fd; } +int close_lock_file(struct lock_file *lk) +{ + int fd = lk->fd; + lk->fd = -1; + return close(fd); +} + int commit_lock_file(struct lock_file *lk) { char result_file[PATH_MAX]; - int i; - close(lk->fd); + size_t i; + if (lk->fd >= 0 && close_lock_file(lk)) + return -1; strcpy(result_file, lk->filename); i = strlen(result_file) - 5; /* .lock */ result_file[i] = 0; - i = rename(lk->filename, result_file); + if (rename(lk->filename, result_file)) + return -1; lk->filename[0] = 0; - return i; + return 0; } int hold_locked_index(struct lock_file *lk, int die_on_error) @@ -185,9 +195,12 @@ void set_alternate_index_output(const char *name) int commit_locked_index(struct lock_file *lk) { if (alternate_index_output) { - int result = rename(lk->filename, alternate_index_output); + if (lk->fd >= 0 && close_lock_file(lk)) + return -1; + if (rename(lk->filename, alternate_index_output)) + return -1; lk->filename[0] = 0; - return result; + return 0; } else return commit_lock_file(lk); @@ -196,7 +209,8 @@ int commit_locked_index(struct lock_file *lk) void rollback_lock_file(struct lock_file *lk) { if (lk->filename[0]) { - close(lk->fd); + if (lk->fd >= 0) + close(lk->fd); unlink(lk->filename); } lk->filename[0] = 0; -- cgit v1.2.3 From ea3cd5c7c63fadacd66c364ae4b8c6d01e5809b1 Mon Sep 17 00:00:00 2001 From: Daniel Barkalow Date: Thu, 17 Apr 2008 19:32:26 -0400 Subject: Add a lockfile function to append to a file This takes care of copying the original contents into the replacement file after the lock is held, so that concurrent additions can't miss each other's changes. [jc: munged to drop mmap in favor of copy_file.] Signed-off-by: Daniel Barkalow Signed-off-by: Junio C Hamano --- lockfile.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 663f18f9c4..e9e0095e9f 100644 --- a/lockfile.c +++ b/lockfile.c @@ -160,6 +160,34 @@ int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on return fd; } +int hold_lock_file_for_append(struct lock_file *lk, const char *path, int die_on_error) +{ + int fd, orig_fd; + + fd = lock_file(lk, path); + if (fd < 0) { + if (die_on_error) + die("unable to create '%s.lock': %s", path, strerror(errno)); + return fd; + } + + orig_fd = open(path, O_RDONLY); + if (orig_fd < 0) { + if (errno != ENOENT) { + if (die_on_error) + die("cannot open '%s' for copying", path); + close(fd); + return error("cannot open '%s' for copying", path); + } + } else if (copy_fd(orig_fd, fd)) { + if (die_on_error) + exit(128); + close(fd); + return -1; + } + return fd; +} + int close_lock_file(struct lock_file *lk) { int fd = lk->fd; -- cgit v1.2.3 From a1292939381507be9489451076d49a5b927e9cc4 Mon Sep 17 00:00:00 2001 From: Clemens Buchacher Date: Sun, 25 May 2008 20:26:50 +0200 Subject: Reset the signal being handled This did not cause any problems, because remove_lock_file_on_signal is only registered for SIGINT. Signed-off-by: Clemens Buchacher Signed-off-by: Junio C Hamano --- lockfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 663f18f9c4..b0118d0592 100644 --- a/lockfile.c +++ b/lockfile.c @@ -24,7 +24,7 @@ static void remove_lock_file(void) static void remove_lock_file_on_signal(int signo) { remove_lock_file(); - signal(SIGINT, SIG_DFL); + signal(signo, SIG_DFL); raise(signo); } -- cgit v1.2.3 From ad5fa3cc0e115a8b111868af2f727322feb144cb Mon Sep 17 00:00:00 2001 From: Paolo Bonzini Date: Thu, 29 May 2008 16:55:53 +0200 Subject: rollback lock files on more signals than just SIGINT Other signals are also common, for example SIGTERM and SIGHUP. This patch modifies the lock file mechanism to catch more signals. It also modifies http-push.c which was missing SIGTERM. Signed-off-by: Paolo Bonzini Signed-off-by: Junio C Hamano --- lockfile.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index cfc7335347..4023797b00 100644 --- a/lockfile.c +++ b/lockfile.c @@ -135,6 +135,9 @@ static int lock_file(struct lock_file *lk, const char *path) if (0 <= lk->fd) { if (!lock_file_list) { signal(SIGINT, remove_lock_file_on_signal); + signal(SIGHUP, remove_lock_file_on_signal); + signal(SIGTERM, remove_lock_file_on_signal); + signal(SIGQUIT, remove_lock_file_on_signal); atexit(remove_lock_file); } lk->owner = getpid(); -- cgit v1.2.3 From acd3b9eca82e38950f94e4708b528b7dae09a7c8 Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Fri, 17 Oct 2008 15:44:39 -0700 Subject: Enhance hold_lock_file_for_{update,append}() API This changes the "die_on_error" boolean parameter to a mere "flags", and changes the existing callers of hold_lock_file_for_update/append() functions to pass LOCK_DIE_ON_ERROR. Signed-off-by: Junio C Hamano --- lockfile.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 4023797b00..6d75608693 100644 --- a/lockfile.c +++ b/lockfile.c @@ -121,15 +121,17 @@ static char *resolve_symlink(char *p, size_t s) } -static int lock_file(struct lock_file *lk, const char *path) +static int lock_file(struct lock_file *lk, const char *path, int flags) { - if (strlen(path) >= sizeof(lk->filename)) return -1; + if (strlen(path) >= sizeof(lk->filename)) + return -1; strcpy(lk->filename, path); /* * subtract 5 from size to make sure there's room for adding * ".lock" for the lock file name */ - resolve_symlink(lk->filename, sizeof(lk->filename)-5); + if (!(flags & LOCK_NODEREF)) + resolve_symlink(lk->filename, sizeof(lk->filename)-5); strcat(lk->filename, ".lock"); lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= lk->fd) { @@ -155,21 +157,21 @@ static int lock_file(struct lock_file *lk, const char *path) return lk->fd; } -int hold_lock_file_for_update(struct lock_file *lk, const char *path, int die_on_error) +int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags) { - int fd = lock_file(lk, path); - if (fd < 0 && die_on_error) + int fd = lock_file(lk, path, flags); + if (fd < 0 && (flags & LOCK_DIE_ON_ERROR)) die("unable to create '%s.lock': %s", path, strerror(errno)); return fd; } -int hold_lock_file_for_append(struct lock_file *lk, const char *path, int die_on_error) +int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags) { int fd, orig_fd; - fd = lock_file(lk, path); + fd = lock_file(lk, path, flags); if (fd < 0) { - if (die_on_error) + if (flags & LOCK_DIE_ON_ERROR) die("unable to create '%s.lock': %s", path, strerror(errno)); return fd; } @@ -177,13 +179,13 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int die_on orig_fd = open(path, O_RDONLY); if (orig_fd < 0) { if (errno != ENOENT) { - if (die_on_error) + if (flags & LOCK_DIE_ON_ERROR) die("cannot open '%s' for copying", path); close(fd); return error("cannot open '%s' for copying", path); } } else if (copy_fd(orig_fd, fd)) { - if (die_on_error) + if (flags & LOCK_DIE_ON_ERROR) exit(128); close(fd); return -1; @@ -215,7 +217,10 @@ int commit_lock_file(struct lock_file *lk) int hold_locked_index(struct lock_file *lk, int die_on_error) { - return hold_lock_file_for_update(lk, get_index_file(), die_on_error); + return hold_lock_file_for_update(lk, get_index_file(), + die_on_error + ? LOCK_DIE_ON_ERROR + : 0); } void set_alternate_index_output(const char *name) -- cgit v1.2.3 From 0693f9ddad3d9af3d3424087557bbddce480ce3f Mon Sep 17 00:00:00 2001 From: Junio C Hamano Date: Thu, 18 Dec 2008 17:31:57 -0800 Subject: Make sure lockfiles are unlocked when dying on SIGPIPE We cleaned up lockfiles upon receiving the usual suspects HUP, TERM, QUIT but a wicked user could kill us of asphyxiation by piping our output to a pipe that does not read. Protect ourselves by catching SIGPIPE and clean up the lockfiles as well in such a case. Signed-off-by: Junio C Hamano --- lockfile.c | 1 + 1 file changed, 1 insertion(+) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 6d75608693..8589155532 100644 --- a/lockfile.c +++ b/lockfile.c @@ -140,6 +140,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags) signal(SIGHUP, remove_lock_file_on_signal); signal(SIGTERM, remove_lock_file_on_signal); signal(SIGQUIT, remove_lock_file_on_signal); + signal(SIGPIPE, remove_lock_file_on_signal); atexit(remove_lock_file); } lk->owner = getpid(); -- cgit v1.2.3 From 4a16d072723b48699ea162da24eff05eba298834 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Jan 2009 01:02:35 -0500 Subject: chain kill signals for cleanup functions If a piece of code wanted to do some cleanup before exiting (e.g., cleaning up a lockfile or a tempfile), our usual strategy was to install a signal handler that did something like this: do_cleanup(); /* actual work */ signal(signo, SIG_DFL); /* restore previous behavior */ raise(signo); /* deliver signal, killing ourselves */ For a single handler, this works fine. However, if we want to clean up two _different_ things, we run into a problem. The most recently installed handler will run, but when it removes itself as a handler, it doesn't put back the first handler. This patch introduces sigchain, a tiny library for handling a stack of signal handlers. You sigchain_push each handler, and use sigchain_pop to restore whoever was before you in the stack. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- lockfile.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 8589155532..3cd57dc385 100644 --- a/lockfile.c +++ b/lockfile.c @@ -2,6 +2,7 @@ * Copyright (c) 2005, Junio C Hamano */ #include "cache.h" +#include "sigchain.h" static struct lock_file *lock_file_list; static const char *alternate_index_output; @@ -24,7 +25,7 @@ static void remove_lock_file(void) static void remove_lock_file_on_signal(int signo) { remove_lock_file(); - signal(signo, SIG_DFL); + sigchain_pop(signo); raise(signo); } @@ -136,11 +137,11 @@ static int lock_file(struct lock_file *lk, const char *path, int flags) lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= lk->fd) { if (!lock_file_list) { - signal(SIGINT, remove_lock_file_on_signal); - signal(SIGHUP, remove_lock_file_on_signal); - signal(SIGTERM, remove_lock_file_on_signal); - signal(SIGQUIT, remove_lock_file_on_signal); - signal(SIGPIPE, remove_lock_file_on_signal); + sigchain_push(SIGINT, remove_lock_file_on_signal); + sigchain_push(SIGHUP, remove_lock_file_on_signal); + sigchain_push(SIGTERM, remove_lock_file_on_signal); + sigchain_push(SIGQUIT, remove_lock_file_on_signal); + sigchain_push(SIGPIPE, remove_lock_file_on_signal); atexit(remove_lock_file); } lk->owner = getpid(); -- cgit v1.2.3 From 57b235a4bc8884a57c6f863605a54b7bfceb0997 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 22 Jan 2009 01:03:08 -0500 Subject: refactor signal handling for cleanup functions The current code is very inconsistent about which signals are caught for doing cleanup of temporary files and lock files. Some callsites checked only SIGINT, while others checked a variety of death-dealing signals. This patch factors out those signals to a single function, and then calls it everywhere. For some sites, that means this is a simple clean up. For others, it is an improvement in that they will now properly clean themselves up after a larger variety of signals. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- lockfile.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 3cd57dc385..021c3375c1 100644 --- a/lockfile.c +++ b/lockfile.c @@ -137,11 +137,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags) lk->fd = open(lk->filename, O_RDWR | O_CREAT | O_EXCL, 0666); if (0 <= lk->fd) { if (!lock_file_list) { - sigchain_push(SIGINT, remove_lock_file_on_signal); - sigchain_push(SIGHUP, remove_lock_file_on_signal); - sigchain_push(SIGTERM, remove_lock_file_on_signal); - sigchain_push(SIGQUIT, remove_lock_file_on_signal); - sigchain_push(SIGPIPE, remove_lock_file_on_signal); + sigchain_push_common(remove_lock_file_on_signal); atexit(remove_lock_file); } lk->owner = getpid(); -- cgit v1.2.3 From e43a6fd3e94888d76779ad79fb568ed180e5fcdf Mon Sep 17 00:00:00 2001 From: Matthieu Moy Date: Thu, 19 Feb 2009 13:54:18 +0100 Subject: More friendly message when locking the index fails. Just saying that index.lock exists doesn't tell the user _what_ to do to fix the problem. We should give an indication that it's normally safe to delete index.lock after making sure git isn't running here. Signed-off-by: Matthieu Moy Signed-off-by: Junio C Hamano --- lockfile.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 8589155532..8e556ff8c9 100644 --- a/lockfile.c +++ b/lockfile.c @@ -158,11 +158,25 @@ static int lock_file(struct lock_file *lk, const char *path, int flags) return lk->fd; } + +NORETURN void unable_to_lock_index_die(const char *path, int err) +{ + if (errno == EEXIST) { + die("Unable to create '%s.lock': %s.\n\n" + "If no other git process is currently running, this probably means a\n" + "git process crashed in this repository earlier. Make sure no other git\n" + "process is running and remove the file manually to continue.", + path, strerror(err)); + } else { + die("Unable to create '%s.lock': %s", path, strerror(err)); + } +} + int hold_lock_file_for_update(struct lock_file *lk, const char *path, int flags) { int fd = lock_file(lk, path, flags); if (fd < 0 && (flags & LOCK_DIE_ON_ERROR)) - die("unable to create '%s.lock': %s", path, strerror(errno)); + unable_to_lock_index_die(path, errno); return fd; } -- cgit v1.2.3 From bdfd739dac4c109ce360d38d0572d8717a46e795 Mon Sep 17 00:00:00 2001 From: John Tapsell Date: Wed, 4 Mar 2009 15:00:44 +0000 Subject: Make the 'lock file' exists error more informative It looks like someone did 90% of the work, then forgot to actually use the function in one place. Also the helper function did not use the correct variable. Signed-off-by: Junio C Hamano --- lockfile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 1db1a2fefc..3dbb2d1ff9 100644 --- a/lockfile.c +++ b/lockfile.c @@ -158,7 +158,7 @@ static int lock_file(struct lock_file *lk, const char *path, int flags) NORETURN void unable_to_lock_index_die(const char *path, int err) { - if (errno == EEXIST) { + if (err == EEXIST) { die("Unable to create '%s.lock': %s.\n\n" "If no other git process is currently running, this probably means a\n" "git process crashed in this repository earlier. Make sure no other git\n" @@ -184,7 +184,7 @@ int hold_lock_file_for_append(struct lock_file *lk, const char *path, int flags) fd = lock_file(lk, path, flags); if (fd < 0) { if (flags & LOCK_DIE_ON_ERROR) - die("unable to create '%s.lock': %s", path, strerror(errno)); + unable_to_lock_index_die(path, errno); return fd; } -- cgit v1.2.3 From 691f1a28bf57618d8b44a193b1d28013c858aba6 Mon Sep 17 00:00:00 2001 From: Alex Riesen Date: Wed, 29 Apr 2009 23:22:56 +0200 Subject: replace direct calls to unlink(2) with unlink_or_warn This helps to notice when something's going wrong, especially on systems which lock open files. I used the following criteria when selecting the code for replacement: - it was already printing a warning for the unlink failures - it is in a function which already printing something or is called from such a function - it is in a static function, returning void and the function is only called from a builtin main function (cmd_) - it is in a function which handles emergency exit (signal handlers) - it is in a function which is obvously cleaning up the lockfiles Signed-off-by: Alex Riesen Signed-off-by: Junio C Hamano --- lockfile.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 3dbb2d1ff9..984eb320fc 100644 --- a/lockfile.c +++ b/lockfile.c @@ -16,7 +16,7 @@ static void remove_lock_file(void) lock_file_list->filename[0]) { if (lock_file_list->fd >= 0) close(lock_file_list->fd); - unlink(lock_file_list->filename); + unlink_or_warn(lock_file_list->filename); } lock_file_list = lock_file_list->next; } @@ -259,7 +259,7 @@ void rollback_lock_file(struct lock_file *lk) if (lk->filename[0]) { if (lk->fd >= 0) close(lk->fd); - unlink(lk->filename); + unlink_or_warn(lk->filename); } lk->filename[0] = 0; } -- cgit v1.2.3 From 4b25d091ba53c758fae0096b8c0662371857b9d9 Mon Sep 17 00:00:00 2001 From: Felipe Contreras Date: Fri, 1 May 2009 12:06:36 +0300 Subject: Fix a bunch of pointer declarations (codestyle) Essentially; s/type* /type */ as per the coding guidelines. Signed-off-by: Felipe Contreras Signed-off-by: Junio C Hamano --- lockfile.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lockfile.c') diff --git a/lockfile.c b/lockfile.c index 3dbb2d1ff9..828d19f452 100644 --- a/lockfile.c +++ b/lockfile.c @@ -109,7 +109,7 @@ static char *resolve_symlink(char *p, size_t s) * link is a relative path, so I must replace the * last element of p with it. */ - char *r = (char*)last_path_elm(p); + char *r = (char *)last_path_elm(p); if (r - p + link_len < s) strcpy(r, link); else { -- cgit v1.2.3