Example #1
0
static RmMountEntries *rm_mount_list_open(RmMountTable *table) {
    RmMountEntries *self = g_slice_new(RmMountEntries);
    self->entries = NULL;
    self->current = NULL;

#if HAVE_GETMNTENT
    struct mntent *entry = NULL;
    self->mnt_ent_file = setmntent("/etc/mtab", "r");

    if(self->mnt_ent_file != NULL) {
        while((entry = getmntent(self->mnt_ent_file))) {
            RmMountEntry *wrap_entry = g_slice_new(RmMountEntry);
            wrap_entry->fsname = g_strdup(entry->mnt_fsname);
            wrap_entry->dir = g_strdup(entry->mnt_dir);
            self->entries = g_list_prepend(self->entries, wrap_entry);
        }

        endmntent(self->mnt_ent_file);
    } else {
        rm_log_perror("getmntent");
    }
#elif HAVE_GETMNTINFO /* probably FreeBSD or other */
    int mnt_list_n = 0;
    struct statfs *mnt_list = NULL;

    if((mnt_list_n = getmntinfo(&mnt_list, MNT_NOWAIT)) != 0) {
        for(int i = 0; i < mnt_list_n; ++i) {
            RmMountEntry *wrap_entry = g_slice_new(RmMountEntry);
            struct statfs *entry = &mnt_list[i];

            wrap_entry->fsname = g_strdup(entry->f_mntfromname);
            wrap_entry->dir = g_strdup(entry->f_mntonname);
            self->entries = g_list_prepend(self->entries, wrap_entry);
        }
    } else {
        rm_log_perror("getmntinfo");
    }
#endif

    RmMountEntry *wrap_entry = NULL;
    while((wrap_entry = rm_mount_list_next(self))) {
        /* bindfs mounts mirror directory trees.
        * This cannot be detected properly by rmlint since
        * files in it have the same inode as their unmirrored file, but
        * a different dev_t.
        *
        * So better go and ignore it.
        */
        static const char *evilfs_types[] = {"bindfs", "nullfs", NULL};

        const char *evilfs_found = NULL;
        for(int i = 0; evilfs_types[i] && !evilfs_found; ++i) {
            if(strcmp(evilfs_types[i], wrap_entry->fsname) == 0) {
                evilfs_found = evilfs_types[i];
            }
        }

        if(evilfs_found != NULL) {
            RmStat dir_stat;
            rm_sys_stat(wrap_entry->dir, &dir_stat);
            g_hash_table_insert(
                table->evilfs_table,
                GUINT_TO_POINTER(dir_stat.st_dev),
                GUINT_TO_POINTER(1)
            );

            rm_log_error(
                YELLOW"WARNING:"RESET" `%s` mount detected at %s (#%u); Ignoring all files in it.\n",
                evilfs_found,
                wrap_entry->dir,
                (unsigned)dir_stat.st_dev
            );
        }
    }

    return self;
}
Example #2
0
static bool rm_mounts_create_tables(RmMountTable *self) {
    /* partition dev_t to disk dev_t */
    self->part_table = g_hash_table_new_full(g_direct_hash,
                       g_direct_equal,
                       NULL,
                       (GDestroyNotify)rm_part_info_free);

    /* disk dev_t to boolean indication if disk is rotational */
    self->disk_table = g_hash_table_new_full(g_direct_hash,
                       g_direct_equal,
                       NULL,
                       (GDestroyNotify)rm_disk_info_free);

    self->nfs_table = g_hash_table_new_full(g_str_hash,
                                            g_str_equal,
                                            g_free,
                                            NULL);

    /* Mapping dev_t => true (used as set) */
    self->evilfs_table = g_hash_table_new(NULL, NULL);

    RmMountEntry *entry = NULL;
    RmMountEntries *mnt_entries = rm_mount_list_open(self);

    if(mnt_entries == NULL) {
        return false;
    }

    while((entry = rm_mount_list_next(mnt_entries))) {
        RmStat stat_buf_folder;
        if(rm_sys_stat(entry->dir, &stat_buf_folder) == -1) {
            continue;
        }

        dev_t whole_disk = 0;
        gchar is_rotational = true;
        char diskname[PATH_MAX];
        memset(diskname, 0, sizeof(diskname));

        RmStat stat_buf_dev;
        if(rm_sys_stat(entry->fsname, &stat_buf_dev) == -1) {
            char *nfs_marker = NULL;
            /* folder rm_sys_stat() is ok but devname rm_sys_stat() is not; this happens for example
             * with tmpfs and with nfs mounts.  Try to handle a few such cases.
             * */
            if(rm_mounts_is_ramdisk(entry->fsname)) {
                strncpy(diskname, entry->fsname, sizeof(diskname));
                is_rotational = false;
                whole_disk = stat_buf_folder.st_dev;
            } else if((nfs_marker = strstr(entry->fsname, ":/")) != NULL) {
                size_t until_slash = MIN((int)sizeof(entry->fsname), nfs_marker - entry->fsname);
                strncpy(diskname, entry->fsname, until_slash);
                is_rotational = true;

                /* Assign different dev ids (with major id 0) to different nfs servers */
                if(!g_hash_table_contains(self->nfs_table, diskname)) {
                    g_hash_table_insert(self->nfs_table, g_strdup(diskname), NULL);
                }
                whole_disk = makedev(0, g_hash_table_size(self->nfs_table));
            } else {
                strncpy(diskname, "unknown", sizeof(diskname));
                is_rotational = true;
                whole_disk = 0;
            }
        } else {
            if(rm_mounts_devno_to_wholedisk(
                        entry, stat_buf_dev.st_rdev, diskname, sizeof(diskname), &whole_disk
                    ) == -1) {
                /* folder and devname rm_sys_stat() are ok but blkid failed; this happens when?
                 * Treat as a non-rotational device using devname dev as whole_disk key
                 * */
                rm_log_debug(RED"devno_to_wholedisk failed for %s\n"RESET, entry->fsname);
                whole_disk = stat_buf_dev.st_dev;
                strncpy(diskname, entry->fsname, sizeof(diskname));
                is_rotational = false;
            } else {
                is_rotational = rm_mounts_is_rotational_blockdev(diskname);
            }
        }

        g_hash_table_insert(
            self->part_table,
            GUINT_TO_POINTER(stat_buf_folder.st_dev),
            rm_part_info_new (entry->dir, whole_disk));

        /* small hack, so also the full disk id can be given to the api below */
        if (!g_hash_table_contains(self->part_table, GINT_TO_POINTER(whole_disk))) {
            g_hash_table_insert(
                self->part_table,
                GUINT_TO_POINTER(whole_disk),
                rm_part_info_new (entry->dir, whole_disk));
        }

        if (!g_hash_table_contains(self->disk_table, GINT_TO_POINTER(whole_disk))) {
            g_hash_table_insert(
                self->disk_table,
                GINT_TO_POINTER(whole_disk),
                rm_disk_info_new(diskname, is_rotational));
        }

        rm_log_info("%02u:%02u %50s -> %02u:%02u %-12s (underlying disk: %s; rotational: %3s\n)",
                    major(stat_buf_folder.st_dev), minor(stat_buf_folder.st_dev),
                    entry->dir,
                    major(whole_disk), minor(whole_disk),
                    entry->fsname, diskname, is_rotational ? "yes" : "no"
                   );

    }

#if HAVE_SYSCTL
    if(DISK_TABLE) {
        g_hash_table_unref(DISK_TABLE);
    }
#endif

    rm_mount_list_close(mnt_entries);
    return true;
}
Example #3
0
static RmMountEntries *rm_mount_list_open(RmMountTable *table) {
    RmMountEntries *self = g_slice_new(RmMountEntries);

    self->mnt_entries = g_unix_mounts_get(NULL);
    self->entries = NULL;
    self->current = NULL;

    for(GList *iter = self->mnt_entries; iter; iter = iter->next) {
        RmMountEntry *wrap_entry = g_slice_new(RmMountEntry);
        GUnixMountEntry *entry = iter->data;

        wrap_entry->fsname = g_strdup(g_unix_mount_get_device_path(entry));
        wrap_entry->dir = g_strdup(g_unix_mount_get_mount_path(entry));
        wrap_entry->type = g_strdup(g_unix_mount_get_fs_type(entry));

        self->entries = g_list_prepend(self->entries, wrap_entry);
    }

    RmMountEntry *wrap_entry = NULL;
    while((wrap_entry = rm_mount_list_next(self))) {
        /* bindfs mounts mirror directory trees.
        * This cannot be detected properly by rmlint since
        * files in it have the same inode as their unmirrored file, but
        * a different dev_t.
        *
        * Also ignore kernel filesystems.
        *
        * So better go and ignore it.
        */
        static struct RmEvilFs {
            /* fsname as show by `mount` */
            const char *name;

            /* Wether to warn about the exclusion on this */
            bool unusual;
        } evilfs_types[] = {{"bindfs", 1},
                            {"nullfs", 1},
                            /* Ignore the usual linux file system spam */
                            {"proc", 0},
                            {"cgroup", 0},
                            {"configfs", 0},
                            {"sys", 0},
                            {"devtmpfs", 0},
                            {"debugfs", 0},
                            {NULL, 0}};

        /* btrfs and ocfs2 filesystems support reflinks for deduplication */
        static const char *reflinkfs_types[] = {"btrfs", "ocfs2", NULL};

        const struct RmEvilFs *evilfs_found = NULL;
        for(int i = 0; evilfs_types[i].name && !evilfs_found; ++i) {
            if(strcmp(evilfs_types[i].name, wrap_entry->type) == 0) {
                evilfs_found = &evilfs_types[i];
            }
        }

        const char *reflinkfs_found = NULL;
        for(int i = 0; reflinkfs_types[i] && !reflinkfs_found; ++i) {
            if(strcmp(reflinkfs_types[i], wrap_entry->type) == 0) {
                reflinkfs_found = reflinkfs_types[i];
                break;
            }
        }

        if(evilfs_found != NULL) {
            RmStat dir_stat;
            rm_sys_stat(wrap_entry->dir, &dir_stat);
            g_hash_table_insert(table->evilfs_table,
                                GUINT_TO_POINTER(dir_stat.st_dev),
                                GUINT_TO_POINTER(1));

            GLogLevelFlags log_level = G_LOG_LEVEL_DEBUG;

            if(evilfs_found->unusual) {
                log_level = G_LOG_LEVEL_WARNING;
                rm_log_warning_prefix();
            } else {
                rm_log_debug_prefix();
            }

            g_log("rmlint", log_level,
                  _("`%s` mount detected at %s (#%u); Ignoring all files in it.\n"),
                  evilfs_found->name, wrap_entry->dir, (unsigned)dir_stat.st_dev);
        }

        rm_log_debug_line("Filesystem %s: %s", wrap_entry->dir,
                          (reflinkfs_found) ? "reflink" : "normal");

        if(reflinkfs_found != NULL) {
            RmStat dir_stat;
            rm_sys_stat(wrap_entry->dir, &dir_stat);
            g_hash_table_insert(table->reflinkfs_table,
                                GUINT_TO_POINTER(dir_stat.st_dev),
                                (gpointer)reflinkfs_found);
        }
    }

    return self;
}