Beispiel #1
0
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);
}
Beispiel #2
0
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;
}