]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/hooks.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 * This file is part of libmount from util-linux project.
5 * Copyright (C) 2022 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.
13 * The "hookset" is a set of callbacks (hooks) that implement some functionality.
14 * The library defines stages where hooks are called (e.g. when preparing source, post
15 * mount(2), etc.). An arbitrary hook can, on the fly, define another hook for the
16 * arbitrary stage. The first hook from the hookset which goes to the game is a
17 * "firstcall" (defined in struct libmnt_hookset). This first hook controls
18 * what will happen in the next stages (usually nothing).
20 * The library supports two kinds of data for hooksets:
22 * - global data; accessible for all callbacks. Makes sense for complex
23 * hooksets with more callbacks in more stages. Usually implemented by
24 * locally defined 'struct hookset_data' in hook_*.c.
26 * - per-hook data; acessible for specific callback
27 * Usually implemented by locally defined 'struct hook_data' in hook_*.c.
30 #include "mount-api-utils.h"
32 /* built-in hooksets */
33 static const struct libmnt_hookset
*hooksets
[] =
37 #ifdef HAVE_CRYPTSETUP
41 #ifdef HAVE_LIBSELINUX
42 &hookset_selinux_target
,
45 #ifdef USE_LIBMOUNT_MOUNTFD_SUPPORT
48 &hookset_mount_legacy
,
49 #ifdef HAVE_MOUNTFD_API
56 /* hooksets data (this is global list of hookset data) */
58 const struct libmnt_hookset
*hookset
;
61 struct list_head datas
;
64 /* individial callback */
66 const struct libmnt_hookset
*hookset
;
71 int (*func
)(struct libmnt_context
*, const struct libmnt_hookset
*, void *);
73 struct list_head hooks
;
74 unsigned int executed
: 1;
77 static const char *stagenames
[] = {
79 [MNT_STAGE_PREP_SOURCE
] = "prep-source",
80 [MNT_STAGE_PREP_TARGET
] = "prep-target",
81 [MNT_STAGE_PREP_OPTIONS
] = "prep-options",
82 [MNT_STAGE_PREP
] = "prep",
85 [MNT_STAGE_MOUNT_PRE
] = "pre-mount",
86 [MNT_STAGE_MOUNT
] = "mount",
87 [MNT_STAGE_MOUNT_POST
] = "post-mount",
90 [MNT_STAGE_POST
] = "post",
93 static int call_depend_hooks(struct libmnt_context
*cxt
, const char *name
, int stage
);
96 int mnt_context_deinit_hooksets(struct libmnt_context
*cxt
)
103 for (i
= 0; i
< ARRAY_SIZE(hooksets
); i
++) {
104 const struct libmnt_hookset
*hs
= hooksets
[i
];
106 rc
+= hs
->deinit(cxt
, hs
);
109 assert(list_empty(&cxt
->hooksets_datas
));
110 assert(list_empty(&cxt
->hooksets_hooks
));
112 INIT_LIST_HEAD(&cxt
->hooksets_datas
);
113 INIT_LIST_HEAD(&cxt
->hooksets_hooks
);
118 const struct libmnt_hookset
*mnt_context_get_hookset(
119 struct libmnt_context
*cxt
, const char *name
)
126 for (i
= 0; i
< ARRAY_SIZE(hooksets
); i
++) {
127 const struct libmnt_hookset
*hs
= hooksets
[i
];
129 if (strcmp(name
, hs
->name
) == 0)
136 static struct hookset_data
*get_hookset_data(
137 struct libmnt_context
*cxt
,
138 const struct libmnt_hookset
*hs
)
145 list_for_each(p
, &cxt
->hooksets_datas
) {
146 struct hookset_data
*x
= list_entry(p
, struct hookset_data
, datas
);
148 if (x
->hookset
== hs
)
154 int mnt_context_set_hookset_data(struct libmnt_context
*cxt
,
155 const struct libmnt_hookset
*hs
,
158 struct hookset_data
*hd
= NULL
;
160 hd
= get_hookset_data(cxt
, hs
);
162 /* deallocate old data */
165 DBG(CXT
, ul_debugobj(cxt
, " free '%s' data", hs
->name
));
166 list_del(&hd
->datas
);
172 /* create and append new data */
174 hd
= calloc(1, sizeof(*hd
));
178 DBG(CXT
, ul_debugobj(cxt
, " alloc '%s' data", hs
->name
));
179 INIT_LIST_HEAD(&hd
->datas
);
181 list_add_tail(&hd
->datas
, &cxt
->hooksets_datas
);
188 void *mnt_context_get_hookset_data(struct libmnt_context
*cxt
,
189 const struct libmnt_hookset
*hs
)
191 struct hookset_data
*hd
= get_hookset_data(cxt
, hs
);
193 return hd
? hd
->data
: NULL
;
196 static int append_hook(struct libmnt_context
*cxt
,
197 const struct libmnt_hookset
*hs
,
200 int (*func
)(struct libmnt_context
*,
201 const struct libmnt_hookset
*,
205 struct hookset_hook
*hook
;
211 hook
= calloc(1, sizeof(*hook
));
215 DBG(CXT
, ul_debugobj(cxt
, " appending %s hook from %s",
216 stagenames
[stage
], hs
->name
));
218 INIT_LIST_HEAD(&hook
->hooks
);
226 list_add_tail(&hook
->hooks
, &cxt
->hooksets_hooks
);
230 int mnt_context_append_hook(struct libmnt_context
*cxt
,
231 const struct libmnt_hookset
*hs
,
234 int (*func
)(struct libmnt_context
*,
235 const struct libmnt_hookset
*,
238 return append_hook(cxt
, hs
, stage
, data
, func
, NULL
);
241 int mnt_context_insert_hook(struct libmnt_context
*cxt
,
243 const struct libmnt_hookset
*hs
,
246 int (*func
)(struct libmnt_context
*,
247 const struct libmnt_hookset
*,
250 return append_hook(cxt
, hs
, stage
, data
, func
, after
);
253 static struct hookset_hook
*get_hookset_hook(struct libmnt_context
*cxt
,
254 const struct libmnt_hookset
*hs
,
258 struct list_head
*p
, *next
;
262 list_for_each_safe(p
, next
, &cxt
->hooksets_hooks
) {
263 struct hookset_hook
*x
= list_entry(p
, struct hookset_hook
, hooks
);
265 if (hs
&& x
->hookset
!= hs
)
267 if (stage
&& x
->stage
!= stage
)
269 if (data
&& x
->data
!= data
)
277 int mnt_context_remove_hook(struct libmnt_context
*cxt
,
278 const struct libmnt_hookset
*hs
,
282 struct hookset_hook
*hook
;
286 hook
= get_hookset_hook(cxt
, hs
, stage
, NULL
);
288 DBG(CXT
, ul_debugobj(cxt
, " removing %s hook from %s",
289 stagenames
[hook
->stage
], hook
->hookset
->name
));
294 list_del(&hook
->hooks
);
302 int mnt_context_has_hook(struct libmnt_context
*cxt
,
303 const struct libmnt_hookset
*hs
,
307 return get_hookset_hook(cxt
, hs
, stage
, data
) ? 1 : 0;
310 static int call_hook(struct libmnt_context
*cxt
, struct hookset_hook
*hook
)
312 int rc
= hook
->func(cxt
, hook
->hookset
, hook
->data
);
316 rc
= call_depend_hooks(cxt
, hook
->hookset
->name
, hook
->stage
);
320 static int call_depend_hooks(struct libmnt_context
*cxt
, const char *name
, int stage
)
322 struct list_head
*p
= NULL
, *next
= NULL
;
325 list_for_each_safe(p
, next
, &cxt
->hooksets_hooks
) {
326 struct hookset_hook
*x
= list_entry(p
, struct hookset_hook
, hooks
);
328 if (x
->stage
!= stage
|| x
->executed
||
329 x
->after
== NULL
|| strcmp(x
->after
, name
) != 0)
332 DBG(CXT
, ul_debugobj(cxt
, "calling %s [after]", x
->hookset
->name
));
333 rc
= call_hook(cxt
, x
);
341 int mnt_context_call_hooks(struct libmnt_context
*cxt
, int stage
)
343 struct list_head
*p
= NULL
, *next
= NULL
;
347 DBG(CXT
, ul_debugobj(cxt
, "---> stage:%s", stagenames
[stage
]));
349 /* call initial hooks */
350 for (i
= 0; i
< ARRAY_SIZE(hooksets
); i
++) {
351 const struct libmnt_hookset
*hs
= hooksets
[i
];
353 if (hs
->firststage
!= stage
)
356 DBG(CXT
, ul_debugobj(cxt
, "calling %s [first]", hs
->name
));
358 rc
= hs
->firstcall(cxt
, hs
, NULL
);
360 rc
= call_depend_hooks(cxt
, hs
->name
, stage
);
365 /* call already active hooks */
366 list_for_each_safe(p
, next
, &cxt
->hooksets_hooks
) {
367 struct hookset_hook
*x
= list_entry(p
, struct hookset_hook
, hooks
);
369 if (x
->stage
!= stage
|| x
->executed
)
372 DBG(CXT
, ul_debugobj(cxt
, "calling %s [active]", x
->hookset
->name
));
373 rc
= call_hook(cxt
, x
);
381 list_for_each_safe(p
, next
, &cxt
->hooksets_hooks
) {
382 struct hookset_hook
*x
= list_entry(p
, struct hookset_hook
, hooks
);
384 if (x
->stage
!= stage
)
389 DBG(CXT
, ul_debugobj(cxt
, "<--- stage:%s [rc=%d status=%d]",
390 stagenames
[stage
], rc
, cxt
->syscall_status
));