static void create_lockfile(void) { char pid_str[sizeof(long)*3 + 4]; sprintf(pid_str, "%lu", (long)getpid()); char *lock_filename = concat_path_file(g_settings_dump_location, "post-create.lock"); /* Someone else's post-create may take a long-ish time to finish. * For example, I had a failing email sending there, it took * a minute to time out. * That's why timeout is large (100 seconds): */ int count = 100; while (1) { /* Return values: * -1: error (in this case, errno is 0 if error message is already logged) * 0: failed to lock (someone else has it locked) * 1: success */ int r = create_symlink_lockfile(lock_filename, pid_str); if (r > 0) break; if (r < 0) error_msg_and_die("Can't create '%s'", lock_filename); if (--count == 0) { /* Someone else's post-create process is alive but stuck. * Don't wait forever. */ error_msg("Stale lock '%s', removing it", lock_filename); xunlink(lock_filename); break; } sleep(1); } free(lock_filename); }
static int dd_lock(struct dump_dir *dd, unsigned sleep_usec, int flags) { if (dd->locked) error_msg_and_die("Locking bug on '%s'", dd->dd_dirname); char pid_buf[sizeof(long)*3 + 2]; snprintf(pid_buf, sizeof(pid_buf), "%lu", (long)getpid()); unsigned dirname_len = strlen(dd->dd_dirname); char lock_buf[dirname_len + sizeof("/.lock")]; strcpy(lock_buf, dd->dd_dirname); strcpy(lock_buf + dirname_len, "/.lock"); unsigned count = NO_TIME_FILE_COUNT; retry: while (1) { int r = create_symlink_lockfile(lock_buf, pid_buf); if (r < 0) return r; /* error */ if (r > 0 || errno == EALREADY) break; /* locked successfully */ /* Other process has the lock, wait for it to go away */ usleep(sleep_usec); } /* Reset errno to 0 only if errno is EALREADY (used by * create_symlink_lockfile() to signal that the dump directory is already * locked by us) */ if (!(dd->owns_lock = (errno != EALREADY))) errno = 0; /* Are we called by dd_opendir (as opposed to dd_create)? */ if (sleep_usec == WAIT_FOR_OTHER_PROCESS_USLEEP) /* yes */ { const char *missing_file = dd_check(dd); /* some of the required files don't exist. We managed to lock the directory * which was just created by somebody else, or is almost deleted * by delete_file_dir. * Unlock and back off. */ if (missing_file) { if (dd->owns_lock) xunlink(lock_buf); log_warning("Unlocked '%s' (no or corrupted '%s' file)", lock_buf, missing_file); if (--count == 0 || flags & DD_DONT_WAIT_FOR_LOCK) { errno = EISDIR; /* "this is an ordinary dir, not dump dir" */ return -1; } usleep(NO_TIME_FILE_USLEEP); goto retry; } } dd->locked = true; return 0; }