Branch data Line data Source code
1 : : /* GLib testing framework examples and tests
2 : : *
3 : : * Copyright © 2017 Endless Mobile, Inc.
4 : : *
5 : : * SPDX-License-Identifier: LGPL-2.1-or-later
6 : : *
7 : : * This library is free software; you can redistribute it and/or
8 : : * modify it under the terms of the GNU Lesser General Public
9 : : * License as published by the Free Software Foundation; either
10 : : * version 2.1 of the License, or (at your option) any later version.
11 : : *
12 : : * This library is distributed in the hope that it will be useful,
13 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : : * Lesser General Public License for more details.
16 : : *
17 : : * You should have received a copy of the GNU Lesser General
18 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
19 : : */
20 : :
21 : : #include "config.h"
22 : :
23 : : #include <glib.h>
24 : :
25 : : #ifndef G_OS_UNIX
26 : : #error This is a Unix-specific test
27 : : #endif
28 : :
29 : : #include <errno.h>
30 : : #include <locale.h>
31 : :
32 : : #ifdef HAVE_XLOCALE_H
33 : : /* Needed on macOS and FreeBSD for uselocale() */
34 : : #include <xlocale.h>
35 : : #endif
36 : :
37 : : #include <glib/gstdio.h>
38 : : #include <gio/gio.h>
39 : : #include <gio/gunixmounts.h>
40 : :
41 : : #include "../gunixmounts-private.h"
42 : :
43 : : /* We test all of the old g_unix_mount_*() API before it was renamed to
44 : : * g_unix_mount_entry_*(). The old API calls the new API, so both methods get
45 : : * tested at once. */
46 : : G_GNUC_BEGIN_IGNORE_DEPRECATIONS
47 : :
48 : : static void
49 : 1 : test_is_system_fs_type (void)
50 : : {
51 : 1 : g_assert_true (g_unix_is_system_fs_type ("tmpfs"));
52 : 1 : g_assert_false (g_unix_is_system_fs_type ("ext4"));
53 : :
54 : : /* Check that some common network file systems aren’t considered ‘system’. */
55 : 1 : g_assert_false (g_unix_is_system_fs_type ("cifs"));
56 : 1 : g_assert_false (g_unix_is_system_fs_type ("nfs"));
57 : 1 : g_assert_false (g_unix_is_system_fs_type ("nfs4"));
58 : 1 : g_assert_false (g_unix_is_system_fs_type ("smbfs"));
59 : 1 : }
60 : :
61 : : static void
62 : 1 : test_is_system_device_path (void)
63 : : {
64 : 1 : g_assert_true (g_unix_is_system_device_path ("devpts"));
65 : 1 : g_assert_false (g_unix_is_system_device_path ("/"));
66 : 1 : }
67 : :
68 : : static void
69 : 1 : test_system_mount_paths_sorted (void)
70 : : {
71 : : size_t i;
72 : 1 : size_t n_paths = G_N_ELEMENTS (system_mount_paths);
73 : :
74 : 1 : g_test_summary ("Verify that system_mount_paths array is sorted for bsearch");
75 : :
76 : 40 : for (i = 1; i < n_paths; i++)
77 : : {
78 : 39 : int cmp = strcmp (system_mount_paths[i - 1], system_mount_paths[i]);
79 : 39 : if (cmp > 0)
80 : : {
81 : 0 : g_test_fail_printf ("system_mount_paths array is not sorted: "
82 : : "\"%s\" should come before \"%s\"",
83 : 0 : system_mount_paths[i - 1],
84 : : system_mount_paths[i]);
85 : 0 : return;
86 : : }
87 : : }
88 : : }
89 : :
90 : : static void
91 : 8 : assert_cmp_icon (GIcon *icon,
92 : : gboolean expected_icon)
93 : : {
94 : 8 : if (expected_icon)
95 : : {
96 : 8 : char *icon_str = NULL;
97 : :
98 : : /* While it would be nice to compare the icon value, that would make these
99 : : * tests depend on the icon themes installed. So just compare nullness. */
100 : 8 : g_assert_nonnull (icon);
101 : 8 : icon_str = g_icon_to_string (icon);
102 : 8 : g_test_message ("Icon: %s", icon_str);
103 : 8 : g_free (icon_str);
104 : : }
105 : : else
106 : : {
107 : 0 : g_assert_null (icon);
108 : : }
109 : 8 : }
110 : :
111 : : static void
112 : 1 : test_get_mount_points (void)
113 : : {
114 : 1 : GUnixMountPoint **points = NULL;
115 : 1 : uint64_t time_read = 0;
116 : 1 : size_t n_points = 0;
117 : 1 : int fd = -1;
118 : 1 : char *tmp_file = NULL;
119 : : gboolean res;
120 : : #ifdef HAVE_USELOCALE
121 : : locale_t original_locale;
122 : : locale_t new_locale;
123 : : locale_t result;
124 : : #endif
125 : 1 : const char *fake_fstab = "# Some comment\n"
126 : : "/dev/mapper/fedora-root / ext4 defaults,x-systemd.device-timeout=0 1 1\n"
127 : : "UUID=1234-ABCD /boot ext4 defaults 1 2\n"
128 : : "UUID=ABCD-1234 /boot/efi vfat umask=0077,shortname=winnt,ro 0 2\n"
129 : : "/dev/mapper/fedora-home /home ext4 defaults,x-systemd.device-timeout=0 1 2\n"
130 : : "/dev/mapper/fedora-swap none swap defaults,x-systemd.device-timeout=0 0 0\n"
131 : : "/dev/mapper/unused none ext4 defaults\n";
132 : : const struct
133 : : {
134 : : const char *device_path;
135 : : const char *fs_type;
136 : : const char *options;
137 : : gboolean is_readonly;
138 : : gboolean is_user_mountable;
139 : : gboolean is_loopback;
140 : : gboolean guessed_icon;
141 : : gboolean guessed_symbolic_icon;
142 : : const char *guessed_name;
143 : : gboolean guessed_can_eject;
144 : : }
145 : 1 : expected_points[] =
146 : : {
147 : : {
148 : : .device_path = "/dev/mapper/fedora-root",
149 : : .fs_type = "ext4",
150 : : .options = "defaults,x-systemd.device-timeout=0",
151 : : .is_readonly = FALSE,
152 : : .is_user_mountable = FALSE,
153 : : .is_loopback = FALSE,
154 : : .guessed_icon = TRUE,
155 : : .guessed_symbolic_icon = TRUE,
156 : : .guessed_name = "Filesystem root",
157 : : .guessed_can_eject = FALSE,
158 : : },
159 : : {
160 : : .device_path = "UUID=1234-ABCD",
161 : : .fs_type = "ext4",
162 : : .options = "defaults",
163 : : .is_readonly = FALSE,
164 : : .is_user_mountable = FALSE,
165 : : .is_loopback = FALSE,
166 : : .guessed_icon = TRUE,
167 : : .guessed_symbolic_icon = TRUE,
168 : : .guessed_name = "boot",
169 : : .guessed_can_eject = FALSE,
170 : : },
171 : : {
172 : : .device_path = "UUID=ABCD-1234",
173 : : .fs_type = "vfat",
174 : : .options = "umask=0077,shortname=winnt,ro",
175 : : .is_readonly = TRUE,
176 : : .is_user_mountable = FALSE,
177 : : .is_loopback = FALSE,
178 : : .guessed_icon = TRUE,
179 : : .guessed_symbolic_icon = TRUE,
180 : : .guessed_name = "efi",
181 : : .guessed_can_eject = FALSE,
182 : : },
183 : : {
184 : : .device_path = "/dev/mapper/fedora-home",
185 : : .fs_type = "ext4",
186 : : .options = "defaults,x-systemd.device-timeout=0",
187 : : .is_readonly = FALSE,
188 : : .is_user_mountable = FALSE,
189 : : .is_loopback = FALSE,
190 : : .guessed_icon = TRUE,
191 : : .guessed_symbolic_icon = TRUE,
192 : : .guessed_name = "home",
193 : : .guessed_can_eject = FALSE,
194 : : },
195 : : /* the swap partition is ignored */
196 : : /* as is the ignored unused partition */
197 : : };
198 : :
199 : 1 : g_test_summary ("Basic test of g_unix_mount_points_get_from_file()");
200 : :
201 : 1 : fd = g_file_open_tmp ("unix-mounts-XXXXXX", &tmp_file, NULL);
202 : 1 : g_assert (fd != -1);
203 : 1 : close (fd);
204 : :
205 : 1 : res = g_file_set_contents (tmp_file, fake_fstab, -1, NULL);
206 : 1 : g_assert (res);
207 : :
208 : 1 : points = g_unix_mount_points_get_from_file (tmp_file, &time_read, &n_points);
209 : :
210 : 1 : if (points == NULL)
211 : : {
212 : : /* Some platforms may not support parsing a specific mount point file */
213 : 0 : g_assert_cmpuint (time_read, ==, 0);
214 : 0 : g_assert_cmpuint (n_points, ==, 0);
215 : 0 : g_test_skip ("Parsing mount points from a file not supported on this platform");
216 : 0 : return;
217 : : }
218 : :
219 : 1 : g_assert_nonnull (points);
220 : :
221 : : /* Check the properties of the mount points. This needs to be done in a known
222 : : * locale, because the guessed mount point name is translatable. */
223 : 1 : g_assert_cmpuint (n_points, ==, G_N_ELEMENTS (expected_points));
224 : :
225 : : #ifdef HAVE_USELOCALE
226 : 1 : original_locale = uselocale ((locale_t) 0);
227 : 1 : g_assert_true (original_locale != (locale_t) 0);
228 : 1 : new_locale = newlocale (LC_ALL_MASK, "C", (locale_t) 0);
229 : 1 : g_assert_true (new_locale != (locale_t) 0);
230 : 1 : result = uselocale (new_locale);
231 : 1 : g_assert_true (result == original_locale);
232 : : #endif /* HAVE_USELOCALE */
233 : :
234 : 5 : for (size_t i = 0; i < n_points; i++)
235 : : {
236 : 4 : GIcon *icon = NULL;
237 : 4 : char *name = NULL;
238 : :
239 : 4 : g_assert_cmpstr (g_unix_mount_point_get_device_path (points[i]), ==, expected_points[i].device_path);
240 : 4 : g_assert_cmpstr (g_unix_mount_point_get_fs_type (points[i]), ==, expected_points[i].fs_type);
241 : 4 : g_assert_cmpstr (g_unix_mount_point_get_options (points[i]), ==, expected_points[i].options);
242 : 4 : g_assert_true (g_unix_mount_point_is_readonly (points[i]) == expected_points[i].is_readonly);
243 : 4 : g_assert_true (g_unix_mount_point_is_user_mountable (points[i]) == expected_points[i].is_user_mountable);
244 : 4 : g_assert_true (g_unix_mount_point_is_loopback (points[i]) == expected_points[i].is_loopback);
245 : :
246 : 4 : icon = g_unix_mount_point_guess_icon (points[i]);
247 : 4 : assert_cmp_icon (icon, expected_points[i].guessed_icon);
248 : 4 : g_clear_object (&icon);
249 : :
250 : 4 : icon = g_unix_mount_point_guess_symbolic_icon (points[i]);
251 : 4 : assert_cmp_icon (icon, expected_points[i].guessed_symbolic_icon);
252 : 4 : g_clear_object (&icon);
253 : :
254 : 4 : name = g_unix_mount_point_guess_name (points[i]);
255 : : #ifdef HAVE_USELOCALE
256 : 4 : g_assert_cmpstr (name, ==, expected_points[i].guessed_name);
257 : : #else
258 : : g_assert_nonnull (name);
259 : : #endif
260 : 4 : g_free (name);
261 : :
262 : 4 : g_assert_true (g_unix_mount_point_guess_can_eject (points[i]) == expected_points[i].guessed_can_eject);
263 : : }
264 : :
265 : 5 : for (size_t i = 0; i < n_points; i++)
266 : 4 : g_unix_mount_point_free (points[i]);
267 : 1 : g_free (points);
268 : 1 : g_free (tmp_file);
269 : :
270 : : #ifdef HAVE_USELOCALE
271 : 1 : result = uselocale (original_locale);
272 : 1 : g_assert_true (result == new_locale);
273 : 1 : freelocale (new_locale);
274 : : #endif
275 : : }
276 : :
277 : : static void
278 : 1 : test_get_mount_entries (void)
279 : : {
280 : 1 : GUnixMountEntry **entries = NULL;
281 : 1 : uint64_t time_read = 0;
282 : 1 : size_t n_entries = 0;
283 : 1 : int fd = -1;
284 : 1 : char *tmp_file = NULL;
285 : : gboolean res;
286 : : #ifdef HAVE_LIBMOUNT
287 : : /* This is an edited /proc/self/mountinfo file, used because that’s what
288 : : * libmount parses by default, and it allows for the representation of root_path. */
289 : 1 : const char *fake_mtab = "# Some comment\n"
290 : : "67 1 253:1 / / rw,relatime shared:1 - ext4 /dev/mapper/fedora-root rw,seclabel\n"
291 : : "35 67 0:6 / /dev rw,nosuid shared:2 - devtmpfs devtmpfs rw,seclabel,size=4096k,nr_inodes=1995515,mode=755,inode64\n"
292 : : "1537 1080 253:1 /usr/share/fonts /run/host/fonts ro,nosuid,nodev,relatime master:1 - ext4 /dev/mapper/fedora-root rw,seclabel\n";
293 : : #else
294 : : /* This is an edited /proc/mounts, used because that’s what getmntent() parses
295 : : * (and it can’t parse mountinfo files). Unfortunately this means that
296 : : * non-NULL root_path values are not representable. */
297 : : const char *fake_mtab = "# Some comment\n"
298 : : "/dev/mapper/fedora-root / ext4 rw,relatime,seclabel 0 0\n"
299 : : "devtmpfs /dev devtmpfs rw,nosuid,seclabel,size=4096k,nr_inodes=1995515,mode=755,inode64 0 0\n";
300 : : #endif
301 : : const struct
302 : : {
303 : : const char *device_path;
304 : : const char *fs_type;
305 : : const char *mount_path;
306 : : const char *options;
307 : : const char *root_path; /* if supported */
308 : : }
309 : 1 : expected_entries[] =
310 : : {
311 : : {
312 : : .device_path = "/dev/mapper/fedora-root",
313 : : .fs_type = "ext4",
314 : : .mount_path = "/",
315 : : .options = "rw,relatime,seclabel",
316 : : .root_path = "/",
317 : : },
318 : : {
319 : : .device_path = "devtmpfs",
320 : : .fs_type = "devtmpfs",
321 : : .mount_path = "/dev",
322 : : .options = "rw,nosuid,seclabel,size=4096k,nr_inodes=1995515,mode=755,inode64",
323 : : .root_path = "/",
324 : : },
325 : : #ifdef HAVE_LIBMOUNT
326 : : {
327 : : .device_path = "/dev/mapper/fedora-root",
328 : : .fs_type = "ext4",
329 : : .mount_path = "/run/host/fonts",
330 : : .options = "ro,nosuid,nodev,relatime,seclabel",
331 : : .root_path = "/usr/share/fonts",
332 : : },
333 : : #endif
334 : : };
335 : :
336 : 1 : g_test_summary ("Basic test of g_unix_mounts_get_from_file()");
337 : :
338 : 1 : fd = g_file_open_tmp ("unix-mounts-XXXXXX", &tmp_file, NULL);
339 : 1 : g_assert (fd != -1);
340 : 1 : close (fd);
341 : :
342 : 1 : res = g_file_set_contents (tmp_file, fake_mtab, -1, NULL);
343 : 1 : g_assert (res);
344 : :
345 : 1 : entries = g_unix_mounts_get_from_file (tmp_file, &time_read, &n_entries);
346 : :
347 : 1 : if (entries == NULL)
348 : : {
349 : : /* Some platforms may not support parsing a specific mount entry file */
350 : 0 : g_assert_cmpuint (time_read, ==, 0);
351 : 0 : g_assert_cmpuint (n_entries, ==, 0);
352 : 0 : g_test_skip ("Parsing mount entries from a file not supported on this platform");
353 : 0 : return;
354 : : }
355 : :
356 : 1 : g_assert_nonnull (entries);
357 : :
358 : : /* Check the properties of the mount entries. */
359 : 1 : g_assert_cmpuint (n_entries, ==, G_N_ELEMENTS (expected_entries));
360 : :
361 : 4 : for (size_t i = 0; i < n_entries; i++)
362 : : {
363 : 3 : g_assert_cmpstr (g_unix_mount_get_device_path (entries[i]), ==, expected_entries[i].device_path);
364 : 3 : g_assert_cmpstr (g_unix_mount_get_fs_type (entries[i]), ==, expected_entries[i].fs_type);
365 : 3 : g_assert_cmpstr (g_unix_mount_get_mount_path (entries[i]), ==, expected_entries[i].mount_path);
366 : 3 : g_assert_cmpstr (g_unix_mount_get_options (entries[i]), ==, expected_entries[i].options);
367 : :
368 : : /* root_path is only supported by libmount */
369 : : #ifdef HAVE_LIBMOUNT
370 : 3 : g_assert_cmpstr (g_unix_mount_get_root_path (entries[i]), ==, expected_entries[i].root_path);
371 : : #else
372 : : g_assert_null (g_unix_mount_get_root_path (entries[i]));
373 : : #endif
374 : : }
375 : :
376 : 4 : for (size_t i = 0; i < n_entries; i++)
377 : 3 : g_unix_mount_free (entries[i]);
378 : 1 : g_free (entries);
379 : 1 : g_free (tmp_file);
380 : : }
381 : :
382 : : G_GNUC_END_IGNORE_DEPRECATIONS
383 : :
384 : : int
385 : 1 : main (int argc,
386 : : char *argv[])
387 : : {
388 : 1 : setlocale (LC_ALL, "");
389 : :
390 : 1 : g_test_init (&argc, &argv, NULL);
391 : :
392 : 1 : g_test_add_func ("/unix-mounts/is-system-fs-type", test_is_system_fs_type);
393 : 1 : g_test_add_func ("/unix-mounts/is-system-device-path", test_is_system_device_path);
394 : 1 : g_test_add_func ("/unix-mounts/system-mount-paths-sorted", test_system_mount_paths_sorted);
395 : 1 : g_test_add_func ("/unix-mounts/get-mount-points", test_get_mount_points);
396 : 1 : g_test_add_func ("/unix-mounts/get-mount-entries", test_get_mount_entries);
397 : :
398 : 1 : return g_test_run ();
399 : : }
|