Merge branch 'wip/pwithnall/unix-mount-tests' into 'main'

gunixmounts: Add mount point/entry getters from files and add tests based on them

See merge request GNOME/glib!4163
This commit is contained in:
Philip Withnall 2024-08-15 14:25:52 +00:00
commit f4aceb0e91
3 changed files with 684 additions and 88 deletions

View File

@ -148,7 +148,13 @@ G_DEFINE_BOXED_TYPE (GUnixMountPoint, g_unix_mount_point,
g_unix_mount_point_copy, g_unix_mount_point_free)
static GList *_g_get_unix_mounts (void);
static GUnixMountEntry **_g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out);
static GList *_g_get_unix_mount_points (void);
static GUnixMountPoint **_g_unix_mount_points_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_points_out);
static gboolean proc_mounts_watch_is_running (void);
G_LOCK_DEFINE_STATIC (proc_mounts_source);
@ -206,6 +212,9 @@ static GSource *proc_mounts_watch_source = NULL;
static struct libmnt_monitor *proc_mounts_monitor = NULL;
#endif
static guint64 get_mounts_timestamp (void);
static guint64 get_mount_points_timestamp (void);
static gboolean
is_in (const char *value, const char *set[])
{
@ -218,6 +227,45 @@ is_in (const char *value, const char *set[])
return FALSE;
}
/* Marked as unused because these are only used on some platform variants, but
* working out the #if sequence for that would be too much for my little brain. */
static GList *unix_mount_entry_array_free_to_list (GUnixMountEntry **entries,
size_t n_entries) G_GNUC_UNUSED;
static GList *unix_mount_point_array_free_to_list (GUnixMountPoint **points,
size_t n_points) G_GNUC_UNUSED;
/* Helper to convert to a list for the old API.
* Steals ownership of the @entries array. */
static GList *
unix_mount_entry_array_free_to_list (GUnixMountEntry **entries,
size_t n_entries)
{
GList *l = NULL;
for (size_t i = 0; i < n_entries; i++)
l = g_list_prepend (l, g_steal_pointer (&entries[i]));
g_free (entries);
return g_list_reverse (l);
}
/* Helper to convert to a list for the old API.
* Steals ownership of the @entries array. */
static GList *
unix_mount_point_array_free_to_list (GUnixMountPoint **points,
size_t n_points)
{
GList *l = NULL;
for (size_t i = 0; i < n_points; i++)
l = g_list_prepend (l, g_steal_pointer (&points[i]));
g_free (points);
return g_list_reverse (l);
}
/**
* g_unix_is_mount_path_system_internal:
* @mount_path: (type filename): a mount path, e.g. `/media/disk` or `/usr`
@ -501,17 +549,23 @@ create_unix_mount_point (const char *device_path,
*/
#define PROC_MOUNTINFO_PATH "/proc/self/mountinfo"
static GList *
_g_get_unix_mounts (void)
static GUnixMountEntry **
_g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out)
{
struct libmnt_table *table = NULL;
struct libmnt_iter* iter = NULL;
struct libmnt_fs *fs = NULL;
GUnixMountEntry *mount_entry = NULL;
GList *return_list = NULL;
GPtrArray *return_array = NULL;
if (time_read_out != NULL)
*time_read_out = get_mounts_timestamp ();
return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_free, TRUE);
table = mnt_new_table ();
if (mnt_table_parse_mtab (table, NULL) < 0)
if (mnt_table_parse_mtab (table, table_path) < 0)
goto out;
iter = mnt_new_iter (MNT_ITER_FORWARD);
@ -541,14 +595,29 @@ _g_get_unix_mounts (void)
mnt_fs_get_options (fs),
is_read_only);
return_list = g_list_prepend (return_list, mount_entry);
g_ptr_array_add (return_array, g_steal_pointer (&mount_entry));
}
mnt_free_iter (iter);
out:
mnt_free_table (table);
return g_list_reverse (return_list);
if (n_entries_out != NULL)
*n_entries_out = return_array->len;
return (GUnixMountEntry **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
}
static GList *
_g_get_unix_mounts (void)
{
GUnixMountEntry **entries = NULL;
size_t n_entries = 0;
entries = _g_unix_mounts_get_from_file (NULL /* default libmount filename */,
NULL, &n_entries);
return unix_mount_entry_array_free_to_list (g_steal_pointer (&entries), n_entries);
}
#else
@ -571,8 +640,10 @@ get_mtab_read_file (void)
G_LOCK_DEFINE_STATIC(getmntent);
#endif
static GList *
_g_get_unix_mounts (void)
static GUnixMountEntry **
_g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out)
{
#ifdef HAVE_GETMNTENT_R
struct mntent ent;
@ -580,19 +651,18 @@ _g_get_unix_mounts (void)
#endif
struct mntent *mntent;
FILE *file;
const char *read_file;
GUnixMountEntry *mount_entry;
GHashTable *mounts_hash;
GList *return_list;
read_file = get_mtab_read_file ();
GPtrArray *return_array = NULL;
file = setmntent (read_file, "re");
if (time_read_out != NULL)
*time_read_out = get_mounts_timestamp ();
file = setmntent (table_path, "re");
if (file == NULL)
return NULL;
return_list = NULL;
return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_free, TRUE);
mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
#ifdef HAVE_GETMNTENT_R
@ -641,7 +711,7 @@ _g_get_unix_mounts (void)
mount_entry->device_path,
mount_entry->device_path);
return_list = g_list_prepend (return_list, mount_entry);
g_ptr_array_add (return_array, g_steal_pointer (&mount_entry));
}
g_hash_table_destroy (mounts_hash);
@ -651,7 +721,21 @@ _g_get_unix_mounts (void)
G_UNLOCK (getmntent);
#endif
return g_list_reverse (return_list);
if (n_entries_out != NULL)
*n_entries_out = return_array->len;
return (GUnixMountEntry **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
}
static GList *
_g_get_unix_mounts (void)
{
GUnixMountEntry **entries = NULL;
size_t n_entries = 0;
entries = _g_unix_mounts_get_from_file (get_mtab_read_file (), NULL, &n_entries);
return unix_mount_entry_array_free_to_list (g_steal_pointer (&entries), n_entries);
}
#endif /* HAVE_LIBMOUNT */
@ -718,23 +802,26 @@ get_mtab_monitor_file (void)
return get_mtab_read_file ();
}
static GList *
_g_get_unix_mounts (void)
static GUnixMountEntry **
_g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out)
{
struct mnttab mntent;
FILE *file;
const char *read_file;
GUnixMountEntry *mount_entry;
GList *return_list;
read_file = get_mtab_read_file ();
GPtrArray *return_array = NULL;
if (time_read_out != NULL)
*time_read_out = get_mounts_timestamp ();
file = setmntent (read_file, "re");
if (file == NULL)
return NULL;
return_list = NULL;
return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_free, TRUE);
G_LOCK (getmntent);
while (! getmntent (file, &mntent))
{
@ -752,14 +839,28 @@ _g_get_unix_mounts (void)
mntent.mnt_opts,
is_read_only);
return_list = g_list_prepend (return_list, mount_entry);
g_ptr_array_add (return_array, g_steal_pointer (&mount_entry));
}
endmntent (file);
G_UNLOCK (getmntent);
return g_list_reverse (return_list);
if (n_entries_out != NULL)
*n_entries_out = return_array->len;
return (GUnixMountEntry **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
}
static GList *
_g_get_unix_mounts (void)
{
GUnixMountEntry **entries = NULL;
size_t n_entries = 0;
entries = _g_unix_mounts_get_from_file (get_mtab_read_file (), NULL, &n_entries);
return unix_mount_entry_array_free_to_list (g_steal_pointer (&entries), n_entries);
}
/* mntctl.h (AIX) {{{2 */
@ -832,6 +933,20 @@ _g_get_unix_mounts (void)
return g_list_reverse (return_list);
}
static GUnixMountEntry **
_g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out)
{
/* Not supported on mntctl() systems. */
if (time_read_out != NULL)
*time_read_out = 0;
if (n_entries_out != NULL)
*n_entries_out = 0;
return NULL;
}
/* sys/mount.h {{{2 */
#elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
@ -905,6 +1020,20 @@ _g_get_unix_mounts (void)
return g_list_reverse (return_list);
}
static GUnixMountEntry **
_g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out)
{
/* Not supported on getvfsstat()/getfsstat() systems. */
if (time_read_out != NULL)
*time_read_out = 0;
if (n_entries_out != NULL)
*n_entries_out = 0;
return NULL;
}
/* Interix {{{2 */
#elif defined(__INTERIX)
@ -962,6 +1091,20 @@ _g_get_unix_mounts (void)
return return_list;
}
static GUnixMountEntry **
_g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out)
{
/* Not supported on Interix systems. */
if (time_read_out != NULL)
*time_read_out = 0;
if (n_entries_out != NULL)
*n_entries_out = 0;
return NULL;
}
/* QNX {{{2 */
#elif defined (HAVE_QNX)
@ -972,6 +1115,20 @@ get_mtab_monitor_file (void)
return NULL;
}
static GUnixMountEntry **
_g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out)
{
/* Not implemented, as per _g_get_unix_mounts() below */
if (time_read_out != NULL)
*time_read_out = 0;
if (n_entries_out != NULL)
*n_entries_out = 0;
return NULL;
}
static GList *
_g_get_unix_mounts (void)
{
@ -1015,17 +1172,23 @@ get_fstab_file (void)
#ifdef HAVE_LIBMOUNT
static GList *
_g_get_unix_mount_points (void)
static GUnixMountPoint **
_g_unix_mount_points_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_points_out)
{
struct libmnt_table *table = NULL;
struct libmnt_iter* iter = NULL;
struct libmnt_fs *fs = NULL;
GUnixMountPoint *mount_point = NULL;
GList *return_list = NULL;
GPtrArray *return_array = NULL;
if (time_read_out != NULL)
*time_read_out = get_mount_points_timestamp ();
return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_point_free, TRUE);
table = mnt_new_table ();
if (mnt_table_parse_fstab (table, NULL) < 0)
if (mnt_table_parse_fstab (table, table_path) < 0)
goto out;
iter = mnt_new_iter (MNT_ITER_FORWARD);
@ -1089,20 +1252,37 @@ _g_get_unix_mount_points (void)
if (mount_options)
g_free (mount_options);
return_list = g_list_prepend (return_list, mount_point);
g_ptr_array_add (return_array, g_steal_pointer (&mount_point));
}
mnt_free_iter (iter);
out:
mnt_free_table (table);
return g_list_reverse (return_list);
if (n_points_out != NULL)
*n_points_out = return_array->len;
return (GUnixMountPoint **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
}
static GList *
_g_get_unix_mount_points (void)
{
GUnixMountPoint **points = NULL;
size_t n_points = 0;
points = _g_unix_mount_points_get_from_file (NULL /* default libmount filename */,
NULL, &n_points);
return unix_mount_point_array_free_to_list (g_steal_pointer (&points), n_points);
}
#else
static GList *
_g_get_unix_mount_points (void)
static GUnixMountPoint **
_g_unix_mount_points_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_points_out)
{
#ifdef HAVE_GETMNTENT_R
struct mntent ent;
@ -1112,16 +1292,21 @@ _g_get_unix_mount_points (void)
FILE *file;
char *read_file;
GUnixMountPoint *mount_point;
GList *return_list;
read_file = get_fstab_file ();
file = setmntent (read_file, "re");
if (file == NULL)
return NULL;
GPtrArray *return_array = NULL;
if (time_read_out != NULL)
*time_read_out = get_mount_points_timestamp ();
file = setmntent (table_path, "re");
if (file == NULL)
{
if (n_points_out != NULL)
*n_points_out = 0;
return NULL;
}
return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_point_free, TRUE);
return_list = NULL;
#ifdef HAVE_GETMNTENT_R
while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
#else
@ -1177,7 +1362,7 @@ _g_get_unix_mount_points (void)
is_user_mountable,
is_loopback);
return_list = g_list_prepend (return_list, mount_point);
g_ptr_array_add (return_array, g_steal_pointer (&mount_point));
}
endmntent (file);
@ -1185,8 +1370,23 @@ _g_get_unix_mount_points (void)
#ifndef HAVE_GETMNTENT_R
G_UNLOCK (getmntent);
#endif
return g_list_reverse (return_list);
if (n_points_out != NULL)
*n_points_out = return_array->len;
return (GUnixMountPoint **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
}
static GList *
_g_get_unix_mount_points (void)
{
GUnixMountPoint **points = NULL;
size_t n_points = 0;
points = _g_unix_mount_points_get_from_file (get_fstab_file (),
NULL, &n_points);
return unix_mount_point_array_free_to_list (g_steal_pointer (&points), n_points);
}
#endif /* HAVE_LIBMOUNT */
@ -1194,22 +1394,29 @@ _g_get_unix_mount_points (void)
/* mnttab.h {{{2 */
#elif defined (HAVE_SYS_MNTTAB_H)
static GList *
_g_get_unix_mount_points (void)
static GUnixMountPoint **
_g_unix_mount_points_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_points_out)
{
struct mnttab mntent;
FILE *file;
char *read_file;
GUnixMountPoint *mount_point;
GList *return_list;
read_file = get_fstab_file ();
file = setmntent (read_file, "re");
if (file == NULL)
return NULL;
GPtrArray *return_array = NULL;
return_list = NULL;
if (time_read_out != NULL)
*time_read_out = get_mount_points_timestamp ();
file = setmntent (table_path, "re");
if (file == NULL)
{
if (n_points_out != NULL)
*n_points_out = 0;
return NULL;
}
return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_point_free, TRUE);
G_LOCK (getmntent);
while (! getmntent (file, &mntent))
@ -1249,13 +1456,28 @@ _g_get_unix_mount_points (void)
is_user_mountable,
is_loopback);
return_list = g_list_prepend (return_list, mount_point);
g_ptr_array_add (return_array, g_steal_pointer (&mount_point));
}
endmntent (file);
G_UNLOCK (getmntent);
return g_list_reverse (return_list);
if (n_points_out != NULL)
*n_points_out = return_array->len;
return (GUnixMountPoint **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
}
static GList *
_g_get_unix_mount_points (void)
{
GUnixMountPoint **points = NULL;
size_t n_points = 0;
points = _g_unix_mount_points_get_from_file (get_fstab_file (),
NULL, &n_points);
return unix_mount_point_array_free_to_list (g_steal_pointer (&points), n_points);
}
/* mntctl.h (AIX) {{{2 */
@ -1368,24 +1590,31 @@ aix_fs_get (FILE *fd,
return 0;
}
static GList *
_g_get_unix_mount_points (void)
static GUnixMountPoint **
_g_unix_mount_points_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_points_out)
{
struct mntent *mntent;
FILE *file;
char *read_file;
GUnixMountPoint *mount_point;
AixMountTableEntry mntent;
GList *return_list;
read_file = get_fstab_file ();
file = setmntent (read_file, "re");
GPtrArray *return_array = NULL;
if (time_read_out != NULL)
*time_read_out = get_mount_points_timestamp ();
file = setmntent (table_path, "re");
if (file == NULL)
return NULL;
return_list = NULL;
{
if (n_points_out != NULL)
*n_points_out = 0;
return NULL;
}
return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_point_free, TRUE);
while (!aix_fs_get (file, &mntent))
{
if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
@ -1398,13 +1627,28 @@ _g_get_unix_mount_points (void)
TRUE,
FALSE);
return_list = g_list_prepend (return_list, mount_point);
g_ptr_array_add (return_array, g_steal_pointer (&mount_point));
}
}
endmntent (file);
return g_list_reverse (return_list);
if (n_points_out != NULL)
*n_points_out = return_array->len;
return (GUnixMountPoint **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
}
static GList *
_g_get_unix_mount_points (void)
{
GUnixMountPoint **points = NULL;
size_t n_points = 0;
points = _g_unix_mount_points_get_from_file (get_fstab_file (),
NULL, &n_points);
return unix_mount_point_array_free_to_list (g_steal_pointer (&points), n_points);
}
#elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
@ -1495,20 +1739,18 @@ _g_get_unix_mount_points (void)
return g_list_reverse (return_list);
}
/* Interix {{{2 */
#elif defined(__INTERIX)
static GList *
_g_get_unix_mount_points (void)
{
return _g_get_unix_mounts ();
}
/* QNX {{{2 */
#elif defined (HAVE_QNX)
static GList *
_g_get_unix_mount_points (void)
static GUnixMountPoint **
_g_unix_mount_points_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_points_out)
{
return _g_get_unix_mounts ();
/* Not supported on getfsent() systems. */
if (time_read_out != NULL)
*time_read_out = 0;
if (n_points_out != NULL)
*n_points_out = 0;
return NULL;
}
/* Common code {{{2 */
@ -1588,6 +1830,37 @@ g_unix_mounts_get (guint64 *time_read)
return _g_get_unix_mounts ();
}
/**
* g_unix_mounts_get_from_file:
* @table_path: path to the mounts table file (for example `/proc/self/mountinfo`)
* @time_read_out: (optional) (out caller-allocates): return location for the
* modification time of @table_path
* @n_entries_out: (optional) (out caller-allocates): return location for the
* number of mount entries returned
*
* Gets an array of [struct@Gio.UnixMountEntry]s containing the Unix mounts
* listed in @table_path.
*
* This is a generalized version of g_unix_mounts_get(), mainly intended for
* internal testing use. Note that g_unix_mounts_get() may parse multiple
* hierarchical table files, so this function is not a direct superset of its
* functionality.
*
* If there is an error reading or parsing the file, `NULL` will be returned
* and both out parameters will be set to `0`.
*
* Returns: (transfer full) (array length=n_entries_out) (nullable): mount
* entries, or `NULL` if there was an error loading them
* Since: 2.82
*/
GUnixMountEntry **
g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out)
{
return _g_unix_mounts_get_from_file (table_path, time_read_out, n_entries_out);
}
/**
* g_unix_mount_at:
* @mount_path: (type filename): path for a possible unix mount.
@ -1724,6 +1997,37 @@ g_unix_mount_points_get (guint64 *time_read)
return mnt_pts;
}
/**
* g_unix_mount_points_get_from_file:
* @table_path: path to the mount points table file (for example `/etc/fstab`)
* @time_read_out: (optional) (out caller-allocates): return location for the
* modification time of @table_path
* @n_points_out: (optional) (out caller-allocates): return location for the
* number of mount points returned
*
* Gets an array of [struct@Gio.UnixMountPoint]s containing the Unix mount
* points listed in @table_path.
*
* This is a generalized version of g_unix_mount_points_get(), mainly intended
* for internal testing use. Note that g_unix_mount_points_get() may parse
* multiple hierarchical table files, so this function is not a direct superset
* of its functionality.
*
* If there is an error reading or parsing the file, `NULL` will be returned
* and both out parameters will be set to `0`.
*
* Returns: (transfer full) (array length=n_points_out) (nullable): mount
* points, or `NULL` if there was an error loading them
* Since: 2.82
*/
GUnixMountPoint **
g_unix_mount_points_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_points_out)
{
return _g_unix_mount_points_get_from_file (table_path, time_read_out, n_points_out);
}
/**
* g_unix_mount_point_at:
* @mount_path: (type filename): path for a possible unix mount point.

View File

@ -24,6 +24,7 @@
#define __G_UNIX_MOUNTS_H__
#include <gio/gio.h>
#include <stdint.h>
G_BEGIN_DECLS
@ -134,11 +135,19 @@ GIcon * g_unix_mount_point_guess_symbolic_icon (GUnixMountPoint *mount
GIO_AVAILABLE_IN_ALL
GList * g_unix_mount_points_get (guint64 *time_read);
GIO_AVAILABLE_IN_2_82
GUnixMountPoint **g_unix_mount_points_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_points_out);
GIO_AVAILABLE_IN_2_66
GUnixMountPoint *g_unix_mount_point_at (const char *mount_path,
guint64 *time_read);
GIO_AVAILABLE_IN_ALL
GList * g_unix_mounts_get (guint64 *time_read);
GIO_AVAILABLE_IN_2_82
GUnixMountEntry **g_unix_mounts_get_from_file (const char *table_path,
uint64_t *time_read_out,
size_t *n_entries_out);
GIO_AVAILABLE_IN_ALL
GUnixMountEntry *g_unix_mount_at (const char *mount_path,
guint64 *time_read);

View File

@ -18,6 +18,8 @@
* Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib.h>
#ifndef G_OS_UNIX
@ -26,6 +28,12 @@
#include <errno.h>
#include <locale.h>
#ifdef HAVE_XLOCALE_H
/* Needed on macOS and FreeBSD for uselocale() */
#include <xlocale.h>
#endif
#include <glib/gstdio.h>
#include <gio/gio.h>
#include <gio/gunixmounts.h>
@ -50,6 +58,279 @@ test_is_system_device_path (void)
g_assert_false (g_unix_is_system_device_path ("/"));
}
static void
assert_cmp_icon (GIcon *icon,
gboolean expected_icon)
{
if (expected_icon)
{
char *icon_str = NULL;
/* While it would be nice to compare the icon value, that would make these
* tests depend on the icon themes installed. So just compare nullness. */
g_assert_nonnull (icon);
icon_str = g_icon_to_string (icon);
g_test_message ("Icon: %s", icon_str);
g_free (icon_str);
}
else
{
g_assert_null (icon);
}
}
static void
test_get_mount_points (void)
{
GUnixMountPoint **points = NULL;
uint64_t time_read = 0;
size_t n_points = 0;
int fd = -1;
char *tmp_file = NULL;
gboolean res;
#ifdef HAVE_USELOCALE
locale_t original_locale;
locale_t new_locale;
locale_t result;
#endif
const char *fake_fstab = "# Some comment\n"
"/dev/mapper/fedora-root / ext4 defaults,x-systemd.device-timeout=0 1 1\n"
"UUID=1234-ABCD /boot ext4 defaults 1 2\n"
"UUID=ABCD-1234 /boot/efi vfat umask=0077,shortname=winnt,ro 0 2\n"
"/dev/mapper/fedora-home /home ext4 defaults,x-systemd.device-timeout=0 1 2\n"
"/dev/mapper/fedora-swap none swap defaults,x-systemd.device-timeout=0 0 0\n"
"/dev/mapper/unused none ext4 defaults\n";
const struct
{
const char *device_path;
const char *fs_type;
const char *options;
gboolean is_readonly;
gboolean is_user_mountable;
gboolean is_loopback;
gboolean guessed_icon;
gboolean guessed_symbolic_icon;
const char *guessed_name;
gboolean guessed_can_eject;
}
expected_points[] =
{
{
.device_path = "/dev/mapper/fedora-root",
.fs_type = "ext4",
.options = "defaults,x-systemd.device-timeout=0",
.is_readonly = FALSE,
.is_user_mountable = FALSE,
.is_loopback = FALSE,
.guessed_icon = TRUE,
.guessed_symbolic_icon = TRUE,
.guessed_name = "Filesystem root",
.guessed_can_eject = FALSE,
},
{
.device_path = "UUID=1234-ABCD",
.fs_type = "ext4",
.options = "defaults",
.is_readonly = FALSE,
.is_user_mountable = FALSE,
.is_loopback = FALSE,
.guessed_icon = TRUE,
.guessed_symbolic_icon = TRUE,
.guessed_name = "boot",
.guessed_can_eject = FALSE,
},
{
.device_path = "UUID=ABCD-1234",
.fs_type = "vfat",
.options = "umask=0077,shortname=winnt,ro",
.is_readonly = TRUE,
.is_user_mountable = FALSE,
.is_loopback = FALSE,
.guessed_icon = TRUE,
.guessed_symbolic_icon = TRUE,
.guessed_name = "efi",
.guessed_can_eject = FALSE,
},
{
.device_path = "/dev/mapper/fedora-home",
.fs_type = "ext4",
.options = "defaults,x-systemd.device-timeout=0",
.is_readonly = FALSE,
.is_user_mountable = FALSE,
.is_loopback = FALSE,
.guessed_icon = TRUE,
.guessed_symbolic_icon = TRUE,
.guessed_name = "home",
.guessed_can_eject = FALSE,
},
/* the swap partition is ignored */
/* as is the ignored unused partition */
};
g_test_summary ("Basic test of g_unix_mount_points_get_from_file()");
fd = g_file_open_tmp ("unix-mounts-XXXXXX", &tmp_file, NULL);
g_assert (fd != -1);
close (fd);
res = g_file_set_contents (tmp_file, fake_fstab, -1, NULL);
g_assert (res);
points = g_unix_mount_points_get_from_file (tmp_file, &time_read, &n_points);
if (points == NULL)
{
/* Some platforms may not support parsing a specific mount point file */
g_assert_cmpuint (time_read, ==, 0);
g_assert_cmpuint (n_points, ==, 0);
g_test_skip ("Parsing mount points from a file not supported on this platform");
return;
}
g_assert_nonnull (points);
/* Check the properties of the mount points. This needs to be done in a known
* locale, because the guessed mount point name is translatable. */
g_assert_cmpuint (n_points, ==, G_N_ELEMENTS (expected_points));
#ifdef HAVE_USELOCALE
original_locale = uselocale ((locale_t) 0);
g_assert_true (original_locale != (locale_t) 0);
new_locale = newlocale (LC_ALL_MASK, "C", (locale_t) 0);
g_assert_true (new_locale != (locale_t) 0);
result = uselocale (new_locale);
g_assert_true (result == original_locale);
#endif /* HAVE_USELOCALE */
for (size_t i = 0; i < n_points; i++)
{
GIcon *icon = NULL;
char *name = NULL;
g_assert_cmpstr (g_unix_mount_point_get_device_path (points[i]), ==, expected_points[i].device_path);
g_assert_cmpstr (g_unix_mount_point_get_fs_type (points[i]), ==, expected_points[i].fs_type);
g_assert_cmpstr (g_unix_mount_point_get_options (points[i]), ==, expected_points[i].options);
g_assert_true (g_unix_mount_point_is_readonly (points[i]) == expected_points[i].is_readonly);
g_assert_true (g_unix_mount_point_is_user_mountable (points[i]) == expected_points[i].is_user_mountable);
g_assert_true (g_unix_mount_point_is_loopback (points[i]) == expected_points[i].is_loopback);
icon = g_unix_mount_point_guess_icon (points[i]);
assert_cmp_icon (icon, expected_points[i].guessed_icon);
g_clear_object (&icon);
icon = g_unix_mount_point_guess_symbolic_icon (points[i]);
assert_cmp_icon (icon, expected_points[i].guessed_symbolic_icon);
g_clear_object (&icon);
name = g_unix_mount_point_guess_name (points[i]);
#ifdef HAVE_USELOCALE
g_assert_cmpstr (name, ==, expected_points[i].guessed_name);
#else
g_assert_nonnull (name);
#endif
g_free (name);
g_assert_true (g_unix_mount_point_guess_can_eject (points[i]) == expected_points[i].guessed_can_eject);
}
for (size_t i = 0; i < n_points; i++)
g_unix_mount_point_free (points[i]);
g_free (points);
g_free (tmp_file);
#ifdef HAVE_USELOCALE
result = uselocale (original_locale);
g_assert_true (result == new_locale);
freelocale (new_locale);
#endif
}
static void
test_get_mount_entries (void)
{
GUnixMountEntry **entries = NULL;
uint64_t time_read = 0;
size_t n_entries = 0;
int fd = -1;
char *tmp_file = NULL;
gboolean res;
const char *fake_mtab = "# Some comment\n"
"67 1 253:1 / / rw,relatime shared:1 - ext4 /dev/mapper/fedora-root rw,seclabel\n"
"35 67 0:6 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=4096k,nr_inodes=1995515,mode=755,inode64\n"
"1537 1080 253:1 /usr/share/fonts /run/host/fonts ro,nosuid,nodev,relatime master:1 - ext4 /dev/mapper/fedora-root rw,seclabel\n";
const struct
{
const char *device_path;
const char *fs_type;
const char *mount_path;
const char *options;
const char *root_path;
}
expected_entries[] =
{
{
.device_path = "/dev/mapper/fedora-root",
.fs_type = "ext4",
.mount_path = "/",
.options = "rw,relatime,seclabel",
.root_path = "/",
},
{
.device_path = "devtmpfs",
.fs_type = "devtmpfs",
.mount_path = "/dev",
.options = "rw,nosuid,seclabel,size=4096k,nr_inodes=1995515,mode=755,inode64",
.root_path = "/",
},
{
.device_path = "/dev/mapper/fedora-root",
.fs_type = "ext4",
.mount_path = "/run/host/fonts",
.options = "ro,nosuid,nodev,relatime,seclabel",
.root_path = "/usr/share/fonts",
},
};
g_test_summary ("Basic test of g_unix_mounts_get_from_file()");
fd = g_file_open_tmp ("unix-mounts-XXXXXX", &tmp_file, NULL);
g_assert (fd != -1);
close (fd);
res = g_file_set_contents (tmp_file, fake_mtab, -1, NULL);
g_assert (res);
entries = g_unix_mounts_get_from_file (tmp_file, &time_read, &n_entries);
if (entries == NULL)
{
/* Some platforms may not support parsing a specific mount entry file */
g_assert_cmpuint (time_read, ==, 0);
g_assert_cmpuint (n_entries, ==, 0);
g_test_skip ("Parsing mount entries from a file not supported on this platform");
return;
}
g_assert_nonnull (entries);
/* Check the properties of the mount entries. */
g_assert_cmpuint (n_entries, ==, G_N_ELEMENTS (expected_entries));
for (size_t i = 0; i < n_entries; i++)
{
g_assert_cmpstr (g_unix_mount_get_device_path (entries[i]), ==, expected_entries[i].device_path);
g_assert_cmpstr (g_unix_mount_get_fs_type (entries[i]), ==, expected_entries[i].fs_type);
g_assert_cmpstr (g_unix_mount_get_mount_path (entries[i]), ==, expected_entries[i].mount_path);
g_assert_cmpstr (g_unix_mount_get_options (entries[i]), ==, expected_entries[i].options);
g_assert_cmpstr (g_unix_mount_get_root_path (entries[i]), ==, expected_entries[i].root_path);
}
for (size_t i = 0; i < n_entries; i++)
g_unix_mount_free (entries[i]);
g_free (entries);
g_free (tmp_file);
}
int
main (int argc,
char *argv[])
@ -60,6 +341,8 @@ main (int argc,
g_test_add_func ("/unix-mounts/is-system-fs-type", test_is_system_fs_type);
g_test_add_func ("/unix-mounts/is-system-device-path", test_is_system_device_path);
g_test_add_func ("/unix-mounts/get-mount-points", test_get_mount_points);
g_test_add_func ("/unix-mounts/get-mount-entries", test_get_mount_entries);
return g_test_run ();
}