コード例 #1
0
ファイル: journal-vacuum.c プロジェクト: arthur-c/systemd
int journal_directory_vacuum(
                const char *directory,
                uint64_t max_use,
                uint64_t n_max_files,
                usec_t max_retention_usec,
                usec_t *oldest_usec,
                bool verbose) {

        _cleanup_closedir_ DIR *d = NULL;
        struct vacuum_info *list = NULL;
        unsigned n_list = 0, i, n_active_files = 0;
        size_t n_allocated = 0;
        uint64_t sum = 0, freed = 0;
        usec_t retention_limit = 0;
        char sbytes[FORMAT_BYTES_MAX];
        struct dirent *de;
        int r;

        assert(directory);

        if (max_use <= 0 && max_retention_usec <= 0 && n_max_files <= 0)
                return 0;

        if (max_retention_usec > 0) {
                retention_limit = now(CLOCK_REALTIME);
                if (retention_limit > max_retention_usec)
                        retention_limit -= max_retention_usec;
                else
                        max_retention_usec = retention_limit = 0;
        }

        d = opendir(directory);
        if (!d)
                return -errno;

        FOREACH_DIRENT_ALL(de, d, r = -errno; goto finish) {

                unsigned long long seqnum = 0, realtime;
                _cleanup_free_ char *p = NULL;
                sd_id128_t seqnum_id;
                bool have_seqnum;
                uint64_t size;
                struct stat st;
                size_t q;

                if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) {
                        log_debug_errno(errno, "Failed to stat file %s while vacuuming, ignoring: %m", de->d_name);
                        continue;
                }

                if (!S_ISREG(st.st_mode))
                        continue;

                q = strlen(de->d_name);

                if (endswith(de->d_name, ".journal")) {

                        /* Vacuum archived files. Active files are
                         * left around */

                        if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8) {
                                n_active_files++;
                                continue;
                        }

                        if (de->d_name[q-8-16-1] != '-' ||
                            de->d_name[q-8-16-1-16-1] != '-' ||
                            de->d_name[q-8-16-1-16-1-32-1] != '@') {
                                n_active_files++;
                                continue;
                        }

                        p = strdup(de->d_name);
                        if (!p) {
                                r = -ENOMEM;
                                goto finish;
                        }

                        de->d_name[q-8-16-1-16-1] = 0;
                        if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
                                n_active_files++;
                                continue;
                        }

                        if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
                                n_active_files++;
                                continue;
                        }

                        have_seqnum = true;

                } else if (endswith(de->d_name, ".journal~")) {
                        unsigned long long tmp;

                        /* Vacuum corrupted files */

                        if (q < 1 + 16 + 1 + 16 + 8 + 1) {
                                n_active_files ++;
                                continue;
                        }

                        if (de->d_name[q-1-8-16-1] != '-' ||
                            de->d_name[q-1-8-16-1-16-1] != '@') {
                                n_active_files ++;
                                continue;
                        }

                        p = strdup(de->d_name);
                        if (!p) {
                                r = -ENOMEM;
                                goto finish;
                        }

                        if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
                                n_active_files ++;
                                continue;
                        }

                        have_seqnum = false;
                } else {
                        /* We do not vacuum unknown files! */
                        log_debug("Not vacuuming unknown file %s.", de->d_name);
                        continue;
                }

                size = 512UL * (uint64_t) st.st_blocks;

                r = journal_file_empty(dirfd(d), p);
                if (r < 0) {
                        log_debug_errno(r, "Failed check if %s is empty, ignoring: %m", p);
                        continue;
                }
                if (r > 0) {
                        /* Always vacuum empty non-online files. */

                        if (unlinkat(dirfd(d), p, 0) >= 0) {

                                log_full(verbose ? LOG_INFO : LOG_DEBUG,
                                         "Deleted empty archived journal %s/%s (%s).", directory, p, format_bytes(sbytes, sizeof(sbytes), size));

                                freed += size;
                        } else if (errno != ENOENT)
                                log_warning_errno(errno, "Failed to delete empty archived journal %s/%s: %m", directory, p);

                        continue;
                }

                patch_realtime(dirfd(d), p, &st, &realtime);

                if (!GREEDY_REALLOC(list, n_allocated, n_list + 1)) {
                        r = -ENOMEM;
                        goto finish;
                }

                list[n_list].filename = p;
                list[n_list].usage = size;
                list[n_list].seqnum = seqnum;
                list[n_list].realtime = realtime;
                list[n_list].seqnum_id = seqnum_id;
                list[n_list].have_seqnum = have_seqnum;
                n_list ++;

                p = NULL;
                sum += size;
        }

        qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare);

        for (i = 0; i < n_list; i++) {
                unsigned left;

                left = n_active_files + n_list - i;

                if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) &&
                    (max_use <= 0 || sum <= max_use) &&
                    (n_max_files <= 0 || left <= n_max_files))
                        break;

                if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
                        log_full(verbose ? LOG_INFO : LOG_DEBUG, "Deleted archived journal %s/%s (%s).", directory, list[i].filename, format_bytes(sbytes, sizeof(sbytes), list[i].usage));
                        freed += list[i].usage;

                        if (list[i].usage < sum)
                                sum -= list[i].usage;
                        else
                                sum = 0;

                } else if (errno != ENOENT)
                        log_warning_errno(errno, "Failed to delete archived journal %s/%s: %m", directory, list[i].filename);
        }

        if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec))
                *oldest_usec = list[i].realtime;

        r = 0;

finish:
        for (i = 0; i < n_list; i++)
                free(list[i].filename);
        free(list);

        log_full(verbose ? LOG_INFO : LOG_DEBUG, "Vacuuming done, freed %s of archived journals on disk.", format_bytes(sbytes, sizeof(sbytes), freed));

        return r;
}
コード例 #2
0
ファイル: journal-vacuum.c プロジェクト: Mathnerd314/systemd
int journal_directory_vacuum(
                const char *directory,
                uint64_t max_use,
                usec_t max_retention_usec,
                usec_t *oldest_usec) {

        _cleanup_closedir_ DIR *d = NULL;
        int r = 0;
        struct vacuum_info *list = NULL;
        unsigned n_list = 0, i;
        size_t n_allocated = 0;
        uint64_t sum = 0, freed = 0;
        usec_t retention_limit = 0;

        assert(directory);

        if (max_use <= 0 && max_retention_usec <= 0)
                return 0;

        if (max_retention_usec > 0) {
                retention_limit = now(CLOCK_REALTIME);
                if (retention_limit > max_retention_usec)
                        retention_limit -= max_retention_usec;
                else
                        max_retention_usec = retention_limit = 0;
        }

        d = opendir(directory);
        if (!d)
                return -errno;

        for (;;) {
                struct dirent *de;
                size_t q;
                struct stat st;
                char *p;
                unsigned long long seqnum = 0, realtime;
                sd_id128_t seqnum_id;
                bool have_seqnum;

                errno = 0;
                de = readdir(d);
                if (!de && errno != 0) {
                        r = -errno;
                        goto finish;
                }

                if (!de)
                        break;

                if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0)
                        continue;

                if (!S_ISREG(st.st_mode))
                        continue;

                q = strlen(de->d_name);

                if (endswith(de->d_name, ".journal")) {

                        /* Vacuum archived files */

                        if (q < 1 + 32 + 1 + 16 + 1 + 16 + 8)
                                continue;

                        if (de->d_name[q-8-16-1] != '-' ||
                            de->d_name[q-8-16-1-16-1] != '-' ||
                            de->d_name[q-8-16-1-16-1-32-1] != '@')
                                continue;

                        p = strdup(de->d_name);
                        if (!p) {
                                r = -ENOMEM;
                                goto finish;
                        }

                        de->d_name[q-8-16-1-16-1] = 0;
                        if (sd_id128_from_string(de->d_name + q-8-16-1-16-1-32, &seqnum_id) < 0) {
                                free(p);
                                continue;
                        }

                        if (sscanf(de->d_name + q-8-16-1-16, "%16llx-%16llx.journal", &seqnum, &realtime) != 2) {
                                free(p);
                                continue;
                        }

                        have_seqnum = true;

                } else if (endswith(de->d_name, ".journal~")) {
                        unsigned long long tmp;

                        /* Vacuum corrupted files */

                        if (q < 1 + 16 + 1 + 16 + 8 + 1)
                                continue;

                        if (de->d_name[q-1-8-16-1] != '-' ||
                            de->d_name[q-1-8-16-1-16-1] != '@')
                                continue;

                        p = strdup(de->d_name);
                        if (!p) {
                                r = -ENOMEM;
                                goto finish;
                        }

                        if (sscanf(de->d_name + q-1-8-16-1-16, "%16llx-%16llx.journal~", &realtime, &tmp) != 2) {
                                free(p);
                                continue;
                        }

                        have_seqnum = false;
                } else
                        /* We do not vacuum active files or unknown files! */
                        continue;

                if (journal_file_empty(dirfd(d), p)) {
                        /* Always vacuum empty non-online files. */

                        uint64_t size = 512UL * (uint64_t) st.st_blocks;

                        if (unlinkat(dirfd(d), p, 0) >= 0) {
                                log_info("Deleted empty journal %s/%s (%"PRIu64" bytes).",
                                         directory, p, size);
                                freed += size;
                        } else if (errno != ENOENT)
                                log_warning("Failed to delete %s/%s: %m", directory, p);

                        free(p);

                        continue;
                }

                patch_realtime(directory, p, &st, &realtime);

                GREEDY_REALLOC(list, n_allocated, n_list + 1);

                list[n_list].filename = p;
                list[n_list].usage = 512UL * (uint64_t) st.st_blocks;
                list[n_list].seqnum = seqnum;
                list[n_list].realtime = realtime;
                list[n_list].seqnum_id = seqnum_id;
                list[n_list].have_seqnum = have_seqnum;

                sum += list[n_list].usage;

                n_list ++;
        }

        qsort_safe(list, n_list, sizeof(struct vacuum_info), vacuum_compare);

        for (i = 0; i < n_list; i++) {
                if ((max_retention_usec <= 0 || list[i].realtime >= retention_limit) &&
                    (max_use <= 0 || sum <= max_use))
                        break;

                if (unlinkat(dirfd(d), list[i].filename, 0) >= 0) {
                        log_debug("Deleted archived journal %s/%s (%"PRIu64" bytes).",
                                  directory, list[i].filename, list[i].usage);
                        freed += list[i].usage;

                        if (list[i].usage < sum)
                                sum -= list[i].usage;
                        else
                                sum = 0;

                } else if (errno != ENOENT)
                        log_warning("Failed to delete %s/%s: %m", directory, list[i].filename);
        }

        if (oldest_usec && i < n_list && (*oldest_usec == 0 || list[i].realtime < *oldest_usec))
                *oldest_usec = list[i].realtime;

finish:
        for (i = 0; i < n_list; i++)
                free(list[i].filename);
        free(list);

        log_debug("Vacuuming done, freed %"PRIu64" bytes", freed);

        return r;
}