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 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
|
/*
* Copyright (C) 2024 Karel Zak <kzak@redhat.com>
*
* This file may be redistributed under the terms of the
* GNU Lesser General Public License.
*/
#include <stdlib.h>
#include "c.h"
#include "strutils.h"
#include "timeutils.h"
#include "pathnames.h"
#include "libmount.h"
#include "mount-api-utils.h" /* fallback for old linux/mount.h */
static void __iter_table( struct libmnt_table *tb,
struct libmnt_iter *itr, int output, int reverse)
{
struct libmnt_fs *fs = NULL;
int rc;
mnt_reset_iter(itr, reverse ? MNT_ITER_BACKWARD : MNT_ITER_FORWARD);
while ((rc = mnt_table_next_fs(tb, itr, &fs)) == 0) {
const char *tgt = mnt_fs_get_target(fs);
const char *type = mnt_fs_get_fstype(fs);
if (output)
printf (" %15s %s\n", type, tgt);
}
if (rc < 0)
warn("cannot iterate on filesystems");
}
#define fetch_data(t, i) __iter_table(t, i, 0, 0)
#define print_table(t, i) __iter_table(t, i, 1, 0)
#define print_table_reverse(t, i) __iter_table(t, i, 1, 1)
int main(int argc, char *argv[])
{
struct libmnt_table *tb;
struct libmnt_statmnt *sm;
struct libmnt_iter *itr;
struct timeval start, end;
uint64_t id = 0;
double sec_lsmnt, sec_lsstmnt, sec_mountinfo;
mnt_init_debug(0);
if (argc == 2) {
const char *arg = argv[1];
if (!isdigit_string(arg))
mnt_id_from_path(arg, &id, NULL);
else
id = strtou64_or_err(arg, "cannot ID");
}
itr = mnt_new_iter(MNT_ITER_FORWARD);
if (!itr)
err(MNT_EX_SYSERR, "failed to initialize libmount iterator");
tb = mnt_new_table();
if (!tb)
err(EXIT_FAILURE, "failed to allocate table handler");
if (id)
mnt_table_listmount_set_id(tb, id);
/*
* A) listmount() and statmount() based table
*/
sm = mnt_new_statmnt();
if (!sm)
err(EXIT_FAILURE, "failed to allocate statmnt handler");
/* Without this mask setting, the library will make two statmount() calls
* for each node. */
#if defined(STATMOUNT_MNT_POINT) && defined(STATMOUNT_FS_TYPE)
mnt_statmnt_set_mask(sm, STATMOUNT_MNT_POINT | STATMOUNT_FS_TYPE);
#endif
/* force fetch all data
mnt_statmnt_set_mask(sm,
STATMOUNT_SB_BASIC |
STATMOUNT_MNT_BASIC |
STATMOUNT_PROPAGATE_FROM |
STATMOUNT_MNT_ROOT |
STATMOUNT_MNT_POINT |
STATMOUNT_FS_TYPE
STATMOUNT_MNT_OPTS);
*/
/* enable don-demand statmount() call for all filesystems in the table */
mnt_table_refer_statmnt(tb, sm);
/* listmount() only */
gettimeofday(&start, NULL);
if (mnt_table_fetch_listmount(tb) != 0)
warn("failed to read mount table by listmount()");
gettimeofday(&end, NULL);
sec_lsmnt = time_diff(&end, &start);
/* force statmount() for all nodes */
fetch_data(tb, itr);
gettimeofday(&end, NULL);
sec_lsstmnt = time_diff(&end, &start);
fprintf(stdout, "listmount() based table:\n");
print_table(tb, itr);
/* disable statmount() and listmount(); reset table */
mnt_statmnt_disable_fetching(sm, 1);
mnt_table_enable_listmount(tb, 0);
mnt_reset_table(tb);
/*
* B) /proc/self/mountinfo based table
*/
gettimeofday(&start, NULL);
mnt_table_parse_file(tb, _PATH_PROC_MOUNTINFO);
gettimeofday(&end, NULL);
sec_mountinfo = time_diff(&end, &start);
fprintf(stdout, "\nprocfs based table:\n");
print_table(tb, itr);
fprintf(stdout, "\n"
"%f sec listmount()\n"
"%f sec listmount()+statmount()\n"
"%f sec /proc/sef/mountinfo"
"\n\n",
sec_lsmnt, sec_lsstmnt, sec_mountinfo);
mnt_reset_table(tb);
/*
* C) Instead of reading the entire mount table with one listmount() call, read
* it in smaller steps. This is particularly useful for systems with large
* mount tables, where we may only need to access one specific node (usually the
* last one).
*
* By default, libmount reads 512 nodes in one call. To test this sample
* on normal systems, we will reduce this number to 5 nodes. The listmount()
* function is used as a backend for regular mnt_table_next_fs().
* There is no need to make any changes to the application, just enable
* on-demand listmount() by using mnt_table_enable_listmount().
*/
if (mnt_table_listmount_set_stepsiz(tb, 5) != 0)
warn("failed to initialize listmount()");
mnt_table_enable_listmount(tb, 1);
/* enable also statmount() */
mnt_statmnt_disable_fetching(sm, 0);
fprintf(stdout, "\nlistmount() - small steps (reverse):\n");
print_table_reverse(tb, itr);
mnt_unref_table(tb);
mnt_unref_statmnt(sm);
mnt_free_iter(itr);
return EXIT_SUCCESS;
}
|