summaryrefslogtreecommitdiffstats
path: root/src/detection/zpool/zpool.c
blob: ce7abb37fbce7fe28becd23eaaa925f7cb4022d7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
#include "zpool.h"

#if FF_HAVE_LIBZFS

    #include "common/kmod.h"

    #ifdef __sun
        #include <libzfs.h>
        #ifndef __illumos__
            // On Solaris 11, zpool_get_prop has only 5 arguments. #2173
            #define ffzpool_get_prop(zhp, prop, buf, len, srctype, literal) \
                ffzpool_get_prop(zhp, prop, buf, len, srctype)
        #endif
    #else
        #include "libzfs_simplified.h"
    #endif

    #include "common/library.h"

typedef struct FFZfsData {
    FF_LIBRARY_SYMBOL(libzfs_fini)
    FF_LIBRARY_SYMBOL(zpool_get_prop_int)
    FF_LIBRARY_SYMBOL(zpool_get_prop)
    FF_LIBRARY_SYMBOL(zpool_close)

    // The fields in this struct store property IDs returned by `zpool_name_to_prop`,
    // not the property values themselves.
    struct {
        int name;
        int health;
        int guid;
        int size;
        int free;
        int allocated;
        int fragmentation;
        int readonly;
    } props;

    libzfs_handle_t* handle;
    FFlist* result;
} FFZfsData;

static inline void cleanLibzfs(FFZfsData* data) {
    if (data->fflibzfs_fini && data->handle) {
        data->fflibzfs_fini(data->handle);
        data->handle = NULL;
    }
}

static int enumZpoolCallback(zpool_handle_t* zpool, void* param) {
    FFZfsData* data = (FFZfsData*) param;
    zprop_source_t source;
    FFZpoolResult* item = FF_LIST_ADD(FFZpoolResult, *data->result);
    char buf[1024];
    if (data->ffzpool_get_prop(zpool, data->props.name, buf, ARRAY_SIZE(buf), &source, false) == 0) {
        ffStrbufInitS(&item->name, buf);
    } else {
        ffStrbufInitStatic(&item->name, "unknown");
    }
    if (data->ffzpool_get_prop(zpool, data->props.health, buf, ARRAY_SIZE(buf), &source, false) == 0) {
        ffStrbufInitS(&item->state, buf);
    } else {
        ffStrbufInitStatic(&item->state, "unknown");
    }
    item->guid = data->ffzpool_get_prop_int(zpool, data->props.guid, &source);
    item->total = data->ffzpool_get_prop_int(zpool, data->props.size, &source);
    item->used = item->total - data->ffzpool_get_prop_int(zpool, data->props.free, &source);
    item->allocated = data->ffzpool_get_prop_int(zpool, data->props.allocated, &source);
    uint64_t fragmentation = data->ffzpool_get_prop_int(zpool, data->props.fragmentation, &source);
    item->fragmentation = fragmentation == UINT64_MAX ? -DBL_MAX : (double) fragmentation;
    item->readOnly = (bool) data->ffzpool_get_prop_int(zpool, data->props.readonly, &source);
    data->ffzpool_close(zpool);
    return 0;
}

const char* ffDetectZpool(FFlist* result /* list of FFZpoolResult */) {
    FF_LIBRARY_LOAD_MESSAGE(libzfs, "libzfs" FF_LIBRARY_EXTENSION, 6);
    FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libzfs, libzfs_init);

    libzfs_handle_t* handle = fflibzfs_init();
    if (!handle) {
        if (!ffKmodLoaded("zfs")) {
            return "`zfs` kernel module is not loaded";
        }
        return "libzfs_init() failed";
    }

    FF_A_CLEANUP(cleanLibzfs) FFZfsData data = {
        .handle = handle,
        .result = result,
    };

    FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libzfs, zpool_name_to_prop);

    #define FF_QUERY_ZPOOL_PROP_FROM_NAME(prop_name)                 \
        do {                                                         \
            data.props.prop_name = ffzpool_name_to_prop(#prop_name); \
            if (data.props.prop_name < 0)                            \
                return "Failed to query prop: " #prop_name;          \
        } while (false)
    FF_QUERY_ZPOOL_PROP_FROM_NAME(name);
    FF_QUERY_ZPOOL_PROP_FROM_NAME(health);
    FF_QUERY_ZPOOL_PROP_FROM_NAME(guid);
    FF_QUERY_ZPOOL_PROP_FROM_NAME(size);
    FF_QUERY_ZPOOL_PROP_FROM_NAME(free);
    FF_QUERY_ZPOOL_PROP_FROM_NAME(allocated);
    FF_QUERY_ZPOOL_PROP_FROM_NAME(fragmentation);
    FF_QUERY_ZPOOL_PROP_FROM_NAME(readonly);
    #undef FF_QUERY_ZPOOL_PROP_FROM_NAME

    FF_LIBRARY_LOAD_SYMBOL_MESSAGE(libzfs, zpool_iter);
    FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libzfs, data, libzfs_fini);
    FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libzfs, data, zpool_get_prop_int);
    FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libzfs, data, zpool_get_prop);
    FF_LIBRARY_LOAD_SYMBOL_VAR_MESSAGE(libzfs, data, zpool_close);

    if (ffzpool_iter(handle, enumZpoolCallback, &data) < 0) {
        return "zpool_iter() failed";
    }

    return NULL;
}

#else

const char* ffDetectZpool(FF_A_UNUSED FFlist* result) {
    return "fastfetch was compiled without libzfs support";
}

#endif