]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/tab_diff.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 * This file is part of libmount from util-linux project.
5 * Copyright (C) 2011-2018 Karel Zak <kzak@redhat.com>
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
15 * @title: Compare changes in mount tables
16 * @short_description: compare changes in the list of the mounted filesystems
20 struct tabdiff_entry
{
21 int oper
; /* MNT_TABDIFF_* flags; */
23 struct libmnt_fs
*old_fs
; /* pointer to the old FS */
24 struct libmnt_fs
*new_fs
; /* pointer to the new FS */
26 struct list_head changes
;
29 struct libmnt_tabdiff
{
30 int nchanges
; /* number of changes */
32 struct list_head changes
; /* list with modified entries */
33 struct list_head unused
; /* list with unused entries */
39 * Allocates a new table diff struct.
41 * Returns: new diff handler or NULL.
43 struct libmnt_tabdiff
*mnt_new_tabdiff(void)
45 struct libmnt_tabdiff
*df
= calloc(1, sizeof(*df
));
50 DBG(DIFF
, ul_debugobj(df
, "alloc"));
52 INIT_LIST_HEAD(&df
->changes
);
53 INIT_LIST_HEAD(&df
->unused
);
57 static void free_tabdiff_entry(struct tabdiff_entry
*de
)
61 list_del(&de
->changes
);
62 mnt_unref_fs(de
->new_fs
);
63 mnt_unref_fs(de
->old_fs
);
71 * Deallocates tab diff struct and all entries.
73 void mnt_free_tabdiff(struct libmnt_tabdiff
*df
)
78 DBG(DIFF
, ul_debugobj(df
, "free"));
80 while (!list_empty(&df
->changes
)) {
81 struct tabdiff_entry
*de
= list_entry(df
->changes
.next
,
82 struct tabdiff_entry
, changes
);
83 free_tabdiff_entry(de
);
90 * mnt_tabdiff_next_change:
91 * @df: tabdiff pointer
93 * @old_fs: returns the old entry or NULL if new entry added
94 * @new_fs: returns the new entry or NULL if old entry removed
95 * @oper: MNT_TABDIFF_{MOVE,UMOUNT,REMOUNT,MOUNT} flags
97 * The options @old_fs, @new_fs and @oper are optional.
99 * Returns: 0 on success, negative number in case of error or 1 at the end of list.
101 int mnt_tabdiff_next_change(struct libmnt_tabdiff
*df
, struct libmnt_iter
*itr
,
102 struct libmnt_fs
**old_fs
, struct libmnt_fs
**new_fs
, int *oper
)
105 struct tabdiff_entry
*de
= NULL
;
111 MNT_ITER_INIT(itr
, &df
->changes
);
112 if (itr
->p
!= itr
->head
) {
113 MNT_ITER_ITERATE(itr
, de
, struct tabdiff_entry
, changes
);
118 *old_fs
= de
? de
->old_fs
: NULL
;
120 *new_fs
= de
? de
->new_fs
: NULL
;
122 *oper
= de
? de
->oper
: 0;
127 static int tabdiff_reset(struct libmnt_tabdiff
*df
)
131 DBG(DIFF
, ul_debugobj(df
, "resetting"));
133 /* zeroize all entries and move them to the list of unused
135 while (!list_empty(&df
->changes
)) {
136 struct tabdiff_entry
*de
= list_entry(df
->changes
.next
,
137 struct tabdiff_entry
, changes
);
139 list_del_init(&de
->changes
);
140 list_add_tail(&de
->changes
, &df
->unused
);
142 mnt_unref_fs(de
->new_fs
);
143 mnt_unref_fs(de
->old_fs
);
145 de
->new_fs
= de
->old_fs
= NULL
;
153 static int tabdiff_add_entry(struct libmnt_tabdiff
*df
, struct libmnt_fs
*old
,
154 struct libmnt_fs
*new, int oper
)
156 struct tabdiff_entry
*de
;
160 DBG(DIFF
, ul_debugobj(df
, "add change on %s",
161 mnt_fs_get_target(new ? new : old
)));
163 if (!list_empty(&df
->unused
)) {
164 de
= list_entry(df
->unused
.next
, struct tabdiff_entry
, changes
);
165 list_del(&de
->changes
);
167 de
= calloc(1, sizeof(*de
));
172 INIT_LIST_HEAD(&de
->changes
);
177 mnt_unref_fs(de
->new_fs
);
178 mnt_unref_fs(de
->old_fs
);
184 list_add_tail(&de
->changes
, &df
->changes
);
189 static struct tabdiff_entry
*tabdiff_get_mount(struct libmnt_tabdiff
*df
,
197 list_for_each(p
, &df
->changes
) {
198 struct tabdiff_entry
*de
;
200 de
= list_entry(p
, struct tabdiff_entry
, changes
);
202 if (de
->oper
== MNT_TABDIFF_MOUNT
&& de
->new_fs
&&
203 mnt_fs_get_id(de
->new_fs
) == id
) {
205 const char *s
= mnt_fs_get_source(de
->new_fs
);
207 if (s
== NULL
&& src
== NULL
)
209 if (s
&& src
&& strcmp(s
, src
) == 0)
219 * @old_tab: old table
220 * @new_tab: new table
222 * Compares @old_tab and @new_tab, the result is stored in @df and accessible by
223 * mnt_tabdiff_next_change().
225 * Returns: number of changes, negative number in case of error.
227 int mnt_diff_tables(struct libmnt_tabdiff
*df
, struct libmnt_table
*old_tab
,
228 struct libmnt_table
*new_tab
)
230 struct libmnt_fs
*fs
;
231 struct libmnt_iter itr
;
234 if (!df
|| !old_tab
|| !new_tab
)
239 no
= mnt_table_get_nents(old_tab
);
240 nn
= mnt_table_get_nents(new_tab
);
242 if (!no
&& !nn
) /* both tables are empty */
245 DBG(DIFF
, ul_debugobj(df
, "analyze new (%d entries), "
249 mnt_reset_iter(&itr
, MNT_ITER_FORWARD
);
251 /* all mounted or umounted */
253 while(mnt_table_next_fs(new_tab
, &itr
, &fs
) == 0)
254 tabdiff_add_entry(df
, NULL
, fs
, MNT_TABDIFF_MOUNT
);
257 } else if (no
&& !nn
) {
258 while(mnt_table_next_fs(old_tab
, &itr
, &fs
) == 0)
259 tabdiff_add_entry(df
, fs
, NULL
, MNT_TABDIFF_UMOUNT
);
263 /* search newly mounted or modified */
264 while(mnt_table_next_fs(new_tab
, &itr
, &fs
) == 0) {
265 struct libmnt_fs
*o_fs
;
266 const char *src
= mnt_fs_get_source(fs
),
267 *tgt
= mnt_fs_get_target(fs
);
269 o_fs
= mnt_table_find_pair(old_tab
, src
, tgt
, MNT_ITER_FORWARD
);
271 /* 'fs' is not in the old table -- so newly mounted */
272 tabdiff_add_entry(df
, NULL
, fs
, MNT_TABDIFF_MOUNT
);
275 const char *v1
= mnt_fs_get_vfs_options(o_fs
),
276 *v2
= mnt_fs_get_vfs_options(fs
),
277 *f1
= mnt_fs_get_fs_options(o_fs
),
278 *f2
= mnt_fs_get_fs_options(fs
);
280 if ((v1
&& v2
&& strcmp(v1
, v2
) != 0) || (f1
&& f2
&& strcmp(f1
, f2
) != 0))
281 tabdiff_add_entry(df
, o_fs
, fs
, MNT_TABDIFF_REMOUNT
);
285 /* search umounted or moved */
286 mnt_reset_iter(&itr
, MNT_ITER_FORWARD
);
287 while(mnt_table_next_fs(old_tab
, &itr
, &fs
) == 0) {
288 const char *src
= mnt_fs_get_source(fs
),
289 *tgt
= mnt_fs_get_target(fs
);
291 if (!mnt_table_find_pair(new_tab
, src
, tgt
, MNT_ITER_FORWARD
)) {
292 struct tabdiff_entry
*de
;
294 de
= tabdiff_get_mount(df
, src
, mnt_fs_get_id(fs
));
297 mnt_unref_fs(de
->old_fs
);
298 de
->oper
= MNT_TABDIFF_MOVE
;
301 tabdiff_add_entry(df
, fs
, NULL
, MNT_TABDIFF_UMOUNT
);
305 DBG(DIFF
, ul_debugobj(df
, "%d changes detected", df
->nchanges
));
311 static int test_diff(struct libmnt_test
*ts
, int argc
, char *argv
[])
313 struct libmnt_table
*tb_old
, *tb_new
;
314 struct libmnt_tabdiff
*diff
;
315 struct libmnt_iter
*itr
;
316 struct libmnt_fs
*old
, *new;
319 tb_old
= mnt_new_table_from_file(argv
[1]);
320 tb_new
= mnt_new_table_from_file(argv
[2]);
321 diff
= mnt_new_tabdiff();
322 itr
= mnt_new_iter(MNT_ITER_FORWARD
);
324 if (!tb_old
|| !tb_new
|| !diff
|| !itr
) {
325 warnx("failed to allocate resources");
329 rc
= mnt_diff_tables(diff
, tb_old
, tb_new
);
333 while(mnt_tabdiff_next_change(diff
, itr
, &old
, &new, &change
) == 0) {
335 printf("%s on %s: ", mnt_fs_get_source(new ? new : old
),
336 mnt_fs_get_target(new ? new : old
));
339 case MNT_TABDIFF_MOVE
:
340 printf("MOVED to %s\n", mnt_fs_get_target(new));
342 case MNT_TABDIFF_UMOUNT
:
343 printf("UMOUNTED\n");
345 case MNT_TABDIFF_REMOUNT
:
346 printf("REMOUNTED from '%s' to '%s'\n",
347 mnt_fs_get_options(old
),
348 mnt_fs_get_options(new));
350 case MNT_TABDIFF_MOUNT
:
354 printf("unknown change!\n");
360 mnt_unref_table(tb_old
);
361 mnt_unref_table(tb_new
);
362 mnt_free_tabdiff(diff
);
367 int main(int argc
, char *argv
[])
369 struct libmnt_test tss
[] = {
370 { "--diff", test_diff
, "<old> <new> prints change" },
374 return mnt_run_test(tss
, argc
, argv
);
377 #endif /* TEST_PROGRAM */