mount-tool: use libmount to parse /proc/self/mountinfo

Same motivation as in other places: let's use a single logic to parse this.

Use path_equal() to compare the path.

A bug in error handling is fixed: if we failed after the GREEDY_REALLOC but
before the line that sets the last item to NULL, we would jump to
_cleanup_strv_free_ with the strv unterminated. Let's use GREEDY_REALLOC0
to avoid the issue.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-04-04 13:41:47 +02:00
parent 13dcfe4661
commit 7d991d4818
2 changed files with 32 additions and 36 deletions

View File

@ -2470,6 +2470,7 @@ exe = executable('systemd-mount',
'src/mount/mount-tool.c',
include_directories : includes,
link_with : [libshared],
dependencies: [libmount],
install_rpath : rootlibexecdir,
install : true)
public_programs += exe

View File

@ -17,6 +17,7 @@
#include "format-util.h"
#include "fs-util.h"
#include "fstab-util.h"
#include "libmount-util.h"
#include "main-func.h"
#include "mount-util.h"
#include "mountpoint-util.h"
@ -713,9 +714,11 @@ static int start_transient_automount(
}
static int find_mount_points(const char *what, char ***list) {
_cleanup_fclose_ FILE *proc_self_mountinfo = NULL;
_cleanup_(mnt_free_tablep) struct libmnt_table *table = NULL;
_cleanup_(mnt_free_iterp) struct libmnt_iter *iter = NULL;
_cleanup_strv_free_ char **l = NULL;
size_t bufsize = 0, n = 0;
int r;
assert(what);
assert(list);
@ -723,55 +726,47 @@ static int find_mount_points(const char *what, char ***list) {
/* Returns all mount points obtained from /proc/self/mountinfo in *list,
* and the number of mount points as return value. */
proc_self_mountinfo = fopen("/proc/self/mountinfo", "re");
if (!proc_self_mountinfo)
return log_error_errno(errno, "Can't open /proc/self/mountinfo: %m");
table = mnt_new_table();
iter = mnt_new_iter(MNT_ITER_FORWARD);
if (!table || !iter)
return log_oom();
r = mnt_table_parse_mtab(table, NULL);
if (r < 0)
return log_error_errno(r, "Failed to parse /proc/self/mountinfo: %m");
for (;;) {
_cleanup_free_ char *path = NULL, *where = NULL, *dev = NULL;
int r;
struct libmnt_fs *fs;
const char *source, *target;
r = fscanf(proc_self_mountinfo,
"%*s " /* (1) mount id */
"%*s " /* (2) parent id */
"%*s " /* (3) major:minor */
"%*s " /* (4) root */
"%ms " /* (5) mount point */
"%*s" /* (6) mount options */
"%*[^-]" /* (7) optional fields */
"- " /* (8) separator */
"%*s " /* (9) file system type */
"%ms" /* (10) mount source */
"%*s" /* (11) mount options 2 */
"%*[^\n]", /* some rubbish at the end */
&path, &dev);
if (r != 2) {
if (r == EOF)
break;
continue;
}
if (!streq(what, dev))
continue;
r = cunescape(path, UNESCAPE_RELAX, &where);
r = mnt_table_next_fs(table, iter, &fs);
if (r == 1)
break;
if (r < 0)
return log_error_errno(r, "Failed to get next entry from /proc/self/mountinfo: %m");
source = mnt_fs_get_source(fs);
target = mnt_fs_get_target(fs);
if (!source || !target)
continue;
if (!path_equal(source, what))
continue;
/* one extra slot is needed for the terminating NULL */
if (!GREEDY_REALLOC(l, bufsize, n + 2))
if (!GREEDY_REALLOC0(l, bufsize, n + 2))
return log_oom();
l[n++] = TAKE_PTR(where);
l[n] = strdup(target);
if (!l[n])
return log_oom();
n++;
}
if (!GREEDY_REALLOC(l, bufsize, n + 1))
if (!GREEDY_REALLOC0(l, bufsize, n + 1))
return log_oom();
l[n] = NULL;
*list = TAKE_PTR(l);
return n;
}