WSL/test/linux/unit_tests/lxtmount.c
Josh Soref abce91d14b
Spelling (#12954)
* link: Collect WSL logs (recommended method)

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Advanced Authoring Tests in C++

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: CMake Documentation and Community

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Collect WSL logs for networking issues

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* link: Collect WSL logs (recommended method)

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: ; otherwise,

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: a

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: access

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: accessible

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: across

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: actively

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: adapters

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: address

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: addresses

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: and

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: appropriate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: argument

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: associated

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: attach

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: available

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: beginning

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: between

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: binaries

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: bound

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: buffer

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: buffers

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: cannot

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: canonical

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: capabilities

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: case-insensitive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: case-sensitive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: certified

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: command

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: committer

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: communication

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: complains

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: configuration

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: consumed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: continue

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: converted

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: currently

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: customers

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: daemon

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: deferred

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: definitions

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: delimiter

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: delivered

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: dellink

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: derived

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: descriptor

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destined

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destruct

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destructible

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: destructor

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: detach

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: differentiate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: directories

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: disassociate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: disposition

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: distribution

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: distro

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: duping

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: emitted

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: empty

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: environment

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: every time

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: exclusive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: expected

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: expire

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: explicitly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: fall back

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: false

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: fastfail

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: filesystem

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: first

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: followed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: for

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: functionality

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: functionally

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: github

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: greater

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: guarantee

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: guaranteed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: handles

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hangup

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hierarchy

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hogwarts

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: hydrated

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: icrnl

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: implementation

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: implementing

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: initialize

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: instance

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: instantiate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: instantiations

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: intentionally

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: interpret

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: interpreter

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: irreversibly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: iteration

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: iterator

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: its

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: kernel

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: kmsg

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: knowledge

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: maximum

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: mirrored

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: msftconnecttest

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: multi

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: multiple

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: mutable

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: namespace

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: nonexistent

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: notifications

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: occurred

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: occurring

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: otherwise,

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: outstanding

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: overridden

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: partition

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: pass through

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: passthrough

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: performs

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: periodically

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: positional

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: precedence

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: preexisting

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: preferring

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: prepopulate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: previous

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: privileges

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: process

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: processes

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: programmatically

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: protection

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: provided

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: reasonable

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: receive

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: received

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: red hat

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: reentrant

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: registered

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: regularly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: relay

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: release

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: representing

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: requests

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: response

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: resurrect

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: retention

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: returned

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: security

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: semaphore

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: separate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: separator

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: service

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: set up

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: setup

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: severely

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: should

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: signal

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: similarly

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: simple

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: simplified

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: single

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: specified

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: splitting

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: standard

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: stress

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: succeed

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: success

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: successfully

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: supplementary

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: synced

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: system

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: take

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: than

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: that opening

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: the

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: threadpool

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: to

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: true

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: truncate

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: tunneling

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unexpected

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: uninitialize

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unique

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unprivileged

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: unregistered

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: untrusted

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: upgrade

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: utility

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: validating

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: variant

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: variation

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: variations

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: verify

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: visible

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: whether

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: winget

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: worker

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: written

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* spelling: wslservice

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>

* format source

---------

Signed-off-by: Josh Soref <2119212+jsoref@users.noreply.github.com>
Co-authored-by: Ben Hillis <benhillis@gmail.com>
Co-authored-by: Ben Hillis <benhill@ntdev.microsoft.com>
2025-07-23 15:19:00 -07:00

853 lines
18 KiB
C

/*++
Copyright (c) Microsoft. All rights reserved.
Module Name:
lxtmount.c
Abstract:
This file contains mount primitive support.
--*/
#include "lxtlog.h"
#include <sys/mman.h>
#include "lxtcommon.h"
#include <sys/mount.h>
#include <linux/capability.h>
#include <sys/sysmacros.h>
#include <libgen.h>
#include <fcntl.h>
#include <stdlib.h>
#include <libmount/libmount.h>
#include <sys/mman.h>
#include "lxtmount.h"
#define PATH_MAX (4096)
void MountEscapeString(const char* Source, char* Dest, size_t Length);
int MountCheckIsMount(
const char* Path,
int ExpectedParentId,
const char* ExpectedSource,
const char* ExpectedFsType,
const char* ExpectedRoot,
const char* ExpectedMountOptions,
const char* ExpectedFsOptions,
const char* ExpectedCombinedOptions,
int Flags)
/*++
Description:
This routine checks if a path is a mount point.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns the mount ID on success, -1 on failure.
--*/
{
int Direction;
const char* ExpectedSourceActual;
struct libmnt_fs* FileSystem;
char LocalPath[PATH_MAX];
int MountId;
int Result;
struct stat Stat;
struct libmnt_table* Table;
Table = NULL;
if (strcmp(Path, "/") != 0)
{
LxtCheckResult(MountIsMount(AT_FDCWD, Path));
if (Result == 0)
{
LxtLogError("%s is not a mount point.", Path);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
}
LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
//
// Verify the mount in the /proc/self/mountinfo file.
//
if ((Flags & MOUNT_FIRST_MOUNT) != 0)
{
Direction = MNT_ITER_FORWARD;
}
else
{
Direction = MNT_ITER_BACKWARD;
}
LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, Path, 0, &Table, &FileSystem, Direction));
LxtCheckNotEqual(FileSystem, NULL, "%p");
LxtLogInfo("%s on %s fstype %s (%s)", mnt_fs_get_source(FileSystem), mnt_fs_get_target(FileSystem), mnt_fs_get_fstype(FileSystem), mnt_fs_get_options(FileSystem));
ExpectedSourceActual = ExpectedSource;
#if LIBMOUNT_MAJOR_VERSION >= 2
if ((ExpectedSourceActual == NULL) && (strcmp(ExpectedFsType, "virtiofs") != 0))
{
ExpectedSourceActual = "none";
}
#endif
LxtCheckEqual(ExpectedParentId, mnt_fs_get_parent_id(FileSystem), "%d");
if (ExpectedSourceActual)
{
LxtCheckStringEqual(ExpectedSourceActual, mnt_fs_get_source(FileSystem));
}
LxtCheckStringEqual(ExpectedFsType, mnt_fs_get_fstype(FileSystem));
strcpy(LocalPath, ExpectedRoot);
if ((Flags & MOUNT_SOURCE_DELETED) != 0)
{
strcat(LocalPath, "//deleted");
}
LxtCheckStringEqual(LocalPath, mnt_fs_get_root(FileSystem));
LxtCheckStringEqual(ExpectedMountOptions, mnt_fs_get_vfs_options(FileSystem));
if (ExpectedFsOptions != NULL)
{
LxtCheckStringEqual(ExpectedFsOptions, mnt_fs_get_fs_options(FileSystem));
}
LxtCheckEqual(Stat.st_dev, mnt_fs_get_devno(FileSystem), "%lu");
MountId = mnt_fs_get_id(FileSystem);
LxtCheckGreater(MountId, 0, "%d");
LxtCheckNotEqual(MountId, ExpectedParentId, "%d");
mnt_free_table(Table);
Table = NULL;
//
// Verify the mount in the /proc/mounts file.
//
LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTS, Path, 0, &Table, &FileSystem, Direction));
LxtCheckNotEqual(FileSystem, NULL, "%p");
if (ExpectedSourceActual)
{
LxtCheckStringEqual(ExpectedSourceActual, mnt_fs_get_source(FileSystem));
}
LxtCheckStringEqual(ExpectedFsType, mnt_fs_get_fstype(FileSystem));
if (ExpectedCombinedOptions != NULL)
{
LxtCheckStringEqual(ExpectedCombinedOptions, mnt_fs_get_options(FileSystem));
}
//
// Verify the mount in the /proc/self/mountstats file.
//
if (ExpectedSourceActual)
{
LxtCheckResult(MountFindMountStats(ExpectedSource, Path, ExpectedFsType));
}
Result = MountId;
ErrorExit:
if (Table != NULL)
{
mnt_free_table(Table);
}
return Result;
}
int MountCheckIsNotMount(const char* Path)
/*++
Description:
This routine checks if a path is a mount point.
Arguments:
Args - Supplies the command line arguments.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
struct libmnt_fs* FileSystem;
int Result;
struct libmnt_table* Table;
Table = NULL;
LxtCheckResult(MountIsMount(AT_FDCWD, Path));
if (Result != 0)
{
LxtLogError("%s is a mount point.", Path);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
//
// Verify the mount is not in the /proc/self/mountinfo file.
//
LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, Path, 0, &Table, &FileSystem, MNT_ITER_BACKWARD));
LxtCheckEqual(FileSystem, NULL, "%p");
mnt_free_table(Table);
Table = NULL;
//
// Verify the mount in the /proc/mounts file.
//
LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTS, Path, 0, &Table, &FileSystem, MNT_ITER_BACKWARD));
LxtCheckEqual(FileSystem, NULL, "%p");
ErrorExit:
if (Table != NULL)
{
mnt_free_table(Table);
}
return Result;
}
void MountEscapeString(const char* Source, char* Dest, size_t Length)
/*++
Description:
This routine escapes a string using procfs rules.
Arguments:
Source - Supplies the string to escape.
Dest - Supplies the buffer to write the escaped string to.
Length - Supplies the length of the destination buffer.
Return Value:
None.
--*/
{
size_t Index;
for (Index = 0; (Index < Length - 1) && (*Source != '\0'); Index += 1, Source += 1)
{
switch (*Source)
{
case ' ':
case '\n':
case '\t':
case '\\':
Index += snprintf(Dest + Index, Length - Index, "\\%03o", *Source) - 1;
break;
default:
Dest[Index] = *Source;
break;
}
}
Dest[Index] = '\0';
return;
}
int MountFindMount(const char* MountsFile, const char* MountPoint, dev_t Device, struct libmnt_table** Table, struct libmnt_fs** FileSystem, int Direction)
/*++
Description:
This routine finds a mount in the specified file by either mount point
or device.
Arguments:
MountsFile - Supplies the file to use (e.g. /proc/self/mountinfo).
MountPoint - Supplies the mount point to search for. If NULL, device is
used instead.
Device - Supplies the device to search for if mount point is NULL.
Table - Supplies a pointer that receives the parsed table. The caller
must use mnt_free_table to free the table.
FileSystem - Supplies a pointer that receives the file system, or NULL
if none was found.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
struct libmnt_iter* Iterator;
struct libmnt_fs* LocalFileSystem;
struct libmnt_table* LocalTable;
int Result;
LocalFileSystem = NULL;
Iterator = NULL;
LocalTable = mnt_new_table_from_file(MountsFile);
LxtCheckNotEqual(LocalTable, NULL, "%p");
//
// A backwards iterator is used to find the most recent mount.
//
if (MountPoint != NULL)
{
*FileSystem = mnt_table_find_target(LocalTable, MountPoint, Direction);
}
else
{
*FileSystem = NULL;
Iterator = mnt_new_iter(MNT_ITER_FORWARD);
LxtCheckNotEqual(Iterator, NULL, "%p");
while (mnt_table_next_fs(LocalTable, Iterator, &LocalFileSystem) == 0)
{
if (mnt_fs_get_devno(LocalFileSystem) == Device)
{
*FileSystem = LocalFileSystem;
break;
}
}
}
//
// Return the table so the memory for file system remains valid.
//
if (*FileSystem != NULL)
{
*Table = LocalTable;
LocalTable = NULL;
}
Result = 0;
ErrorExit:
if (Iterator != NULL)
{
mnt_free_iter(Iterator);
}
if (LocalTable != NULL)
{
mnt_free_table(LocalTable);
}
return Result;
}
int MountFindMountStats(const char* Device, const char* MountPoint, const char* FsType)
/*++
Description:
This routine finds a mount with the specified options in the
/proc/self/mountstats file.
N.B. libmount does not support parsing the mountstats file so this is done
manually.
Arguments:
Device - Supplies the mount source.
MountPoint - Supplies the mount point.
FsType - Supplies the file system type.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
char EscapedDevice[100];
char EscapedMountPoint[100];
char ExpectedLine[256];
int Result;
//
// Format the expected mountstats line.
//
MountEscapeString(MountPoint, EscapedMountPoint, LXT_COUNT_OF(EscapedMountPoint));
if (Device == NULL)
{
snprintf(ExpectedLine, sizeof(ExpectedLine), "no device mounted on %s with fstype %s", EscapedMountPoint, FsType);
}
else
{
MountEscapeString(Device, EscapedDevice, LXT_COUNT_OF(EscapedDevice));
snprintf(ExpectedLine, sizeof(ExpectedLine), "device %s mounted on %s with fstype %s", EscapedDevice, EscapedMountPoint, FsType);
}
LxtCheckResult(MountFindMountStatsLine(ExpectedLine));
ErrorExit:
return Result;
}
int MountFindMountStatsLine(char* ExpectedLine)
/*++
Description:
This routine checks if a specific line exists in the mountstats file.
Arguments:
ExpectedLine - Supplies the line to find.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
bool Found;
FILE* File;
char Line[256];
int Result;
File = fopen(MOUNT_PROC_MOUNTSTATS, "r");
LxtCheckNotEqual(File, NULL, "%p");
Found = FALSE;
while (feof(File) == 0)
{
if (fgets(Line, sizeof(Line), File) == NULL)
{
break;
}
//
// Strip the trailing \n and compare.
//
Line[strlen(Line) - 1] = '\0';
if (strncmp(ExpectedLine, Line, sizeof(Line)) == 0)
{
Found = TRUE;
break;
}
}
if (Found == false)
{
LxtLogError("'%s' not found in " MOUNT_PROC_MOUNTSTATS, ExpectedLine);
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
Result = LXT_RESULT_SUCCESS;
ErrorExit:
if (File != NULL)
{
fclose(File);
}
return Result;
}
int MountGetMountId(const char* Path)
/*++
Description:
This routine gets the mount ID for the specified path.
Arguments:
Path - Supplies the path. Does not have to be a mount point.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
struct libmnt_fs* FileSystem;
int Result;
struct stat Stat;
struct libmnt_table* Table;
//
// Find the mount ID of the directory. This is done by device because
// it may not be a mount point.
//
FileSystem = NULL;
Table = NULL;
LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, NULL, Stat.st_dev, &Table, &FileSystem, MNT_ITER_BACKWARD));
LxtCheckNotEqual(FileSystem, NULL, "%p");
Result = mnt_fs_get_id(FileSystem);
ErrorExit:
if (Table != NULL)
{
mnt_free_table(Table);
}
return Result;
}
int MountGetFileSystem(const char* Path, char* FsType, int FsTypeLength, char* Options, int OptionsLength)
/*++
Description:
This routine gets the file system type of the mount containing the
specified path.
Arguments:
Path - Supplies the path.
FsType - Supplies a buffer that receives the name of the file system type.
Length - Supplies the size of the buffer.
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
struct libmnt_fs* FileSystem;
const char* LocalFsType;
const char* LocalOptions;
int Result;
struct stat Stat;
struct libmnt_table* Table;
//
// Find the mount ID of the directory. This is done by device because
// it may not be a mount point.
//
FileSystem = NULL;
Table = NULL;
LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, NULL, Stat.st_dev, &Table, &FileSystem, MNT_ITER_BACKWARD));
LxtCheckNotEqual(FileSystem, NULL, "%p");
LocalFsType = mnt_fs_get_fstype(FileSystem);
LocalOptions = mnt_fs_get_options(FileSystem);
LxtLogInfo("File system at %s uses fstype %s, options %s.", Path, LocalFsType, LocalOptions);
if (strlen(LocalFsType) >= FsTypeLength)
{
LxtLogError("Buffer too small for file system name");
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
if (strlen(LocalOptions) >= OptionsLength)
{
LxtLogError("Buffer too small for options.");
Result = LXT_RESULT_FAILURE;
goto ErrorExit;
}
strcpy(FsType, LocalFsType);
strcpy(Options, LocalOptions);
ErrorExit:
if (Table != NULL)
{
mnt_free_table(Table);
}
return Result;
}
int MountGetMountOptions(const char* Path, char* Options)
/*++
Description:
This routine gets mount options, which generally describe the mount peer
group information for the specified path.
Arguments:
Path - Supplies the path. Does not have to be a mount point.
Options - Supplies a string buffer to receive the options
Return Value:
Returns 0 on success, -1 on failure.
--*/
{
struct libmnt_fs* FileSystem;
const char* LocalOptions;
int Result;
struct libmnt_table* Table;
//
// Find the mount ID of the directory.
//
FileSystem = NULL;
Table = NULL;
LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, Path, 0, &Table, &FileSystem, MNT_ITER_BACKWARD));
//
// shared:X, master:X, propagate_from:X, unbindable
//
LocalOptions = mnt_fs_get_optional_fields(FileSystem);
if (LocalOptions != NULL)
{
strcpy(Options, LocalOptions);
}
else
{
Options[0] = '\0';
}
ErrorExit:
if (Table != NULL)
{
mnt_free_table(Table);
}
return Result;
}
int MountIsFileSystem(const char* Path, const char* FsType)
/*++
Description:
This routine checks the file system type of the mount containing the
specified path.
Arguments:
Path - Supplies the path.
FsType - Supplies the name of the file system type.
Return Value:
Returns 1 if the path uses the specified file system, 0 if not, and -1 on
failure.
--*/
{
const char* ActualFsType;
struct libmnt_fs* FileSystem;
int Result;
struct stat Stat;
struct libmnt_table* Table;
//
// Find the mount ID of the directory. This is done by device because
// it may not be a mount point.
//
FileSystem = NULL;
Table = NULL;
LxtCheckErrnoZeroSuccess(stat(Path, &Stat));
LxtCheckResult(MountFindMount(MOUNT_PROC_MOUNTINFO, NULL, Stat.st_dev, &Table, &FileSystem, MNT_ITER_BACKWARD));
LxtCheckNotEqual(FileSystem, NULL, "%p");
ActualFsType = mnt_fs_get_fstype(FileSystem);
LxtLogInfo("File system at %s uses fstype %s.", Path, ActualFsType);
if (strcmp(ActualFsType, FsType) == 0)
{
Result = 1;
}
else
{
Result = 0;
}
ErrorExit:
if (Table != NULL)
{
mnt_free_table(Table);
}
return Result;
}
int MountIsMount(int DirFd, const char* Path)
/*++
Description:
This routine checks if a path is a mount point.
Arguments:
Fd - Supplies the file descriptor to start resolving the path.
Path - Supplies the path.
Return Value:
Returns 0 if the path is not a mount point, 1 if it is a mount point, or
-1 on failure.
--*/
{
char LocalPath[PATH_MAX];
char* ParentPath;
struct stat ParentStat;
int Result;
struct stat Stat;
LxtCheckErrnoZeroSuccess(fstatat(DirFd, Path, &Stat, AT_SYMLINK_NOFOLLOW));
strncpy(LocalPath, Path, sizeof(LocalPath) - 1);
ParentPath = dirname(LocalPath);
LxtCheckErrnoZeroSuccess(fstatat(DirFd, ParentPath, &ParentStat, AT_SYMLINK_NOFOLLOW));
LxtLogInfo(
"%s device: %u,%u; %s device: %u,%u", ParentPath, major(ParentStat.st_dev), minor(ParentStat.st_dev), Path, major(Stat.st_dev), minor(Stat.st_dev));
if (Stat.st_dev == ParentStat.st_dev)
{
Result = 0;
}
else
{
Result = 1;
}
ErrorExit:
return Result;
}
int MountPrepareTmpfs(char* Path, char* Device, int ExpectedParentId)
/*++
Description:
This routine creates a tmpfs mount for testing.
Arguments:
Path - Supplies the mount point path.
Device - Supplies the device name to use.
ExpectedParentId - Supplies the expected parent mount ID.
Return Value:
Returns the mount ID on success, -1 on failure.
--*/
{
return MountPrepareTmpfsEx(Path, Device, ExpectedParentId, 0, "rw,relatime");
}
int MountPrepareTmpfsEx(char* Path, char* Device, int ExpectedParentId, int Flags, const char* ExpectedOptions)
/*++
Description:
This routine creates a tmpfs mount for testing.
Arguments:
Path - Supplies the mount point path.
Device - Supplies the device name to use.
ExpectedParentId - Supplies the expected parent mount ID.
Flags - Supplies the mount flags.
ExpectedOptions - Supplies the expected mount option string.
Return Value:
Returns the mount ID on success, -1 on failure.
--*/
{
int MountId;
int Result;
LxtCheckErrnoZeroSuccess(mkdir(Path, 0700));
LxtCheckErrnoZeroSuccess(mount(Device, Path, "tmpfs", Flags, NULL));
LxtCheckResult(MountId = MountCheckIsMount(Path, ExpectedParentId, Device, "tmpfs", "/", ExpectedOptions, "rw", ExpectedOptions, 0));
Result = MountId;
ErrorExit:
return Result;
}