168 lines
4.3 KiB
C
168 lines
4.3 KiB
C
/*
|
|
* 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;
|
|
}
|