Branch data Line data Source code
1 : : /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
2 : :
3 : : /* GIO - GLib Input, Output and Streaming Library
4 : : *
5 : : * Copyright (C) 2006-2007 Red Hat, Inc.
6 : : *
7 : : * SPDX-License-Identifier: LGPL-2.1-or-later
8 : : *
9 : : * This library is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU Lesser General Public
11 : : * License as published by the Free Software Foundation; either
12 : : * version 2.1 of the License, or (at your option) any later version.
13 : : *
14 : : * This library is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : * Lesser General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU Lesser General
20 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 : : *
22 : : * Author: Alexander Larsson <alexl@redhat.com>
23 : : */
24 : :
25 : : /* Prologue {{{1 */
26 : :
27 : : #include "config.h"
28 : :
29 : : #include <sys/types.h>
30 : : #include <sys/stat.h>
31 : : #include <sys/wait.h>
32 : : #ifndef HAVE_SYSCTLBYNAME
33 : : #ifdef HAVE_SYS_PARAM_H
34 : : #include <sys/param.h>
35 : : #endif
36 : : #endif
37 : : #ifdef HAVE_POLL
38 : : #include <poll.h>
39 : : #endif
40 : : #include <stdio.h>
41 : : #include <unistd.h>
42 : : #include <sys/time.h>
43 : : #include <errno.h>
44 : : #include <string.h>
45 : : #include <signal.h>
46 : : #include <gstdio.h>
47 : : #include <dirent.h>
48 : :
49 : : #if defined(__ANDROID__) && (__ANDROID_API__ < 26)
50 : : #include <mntent.h>
51 : : /* the shared object of recent bionic libc's have hasmntopt symbol, but
52 : : some a possible common build environment for android, termux ends
53 : : up with insufficient __ANDROID_API__ value for building.
54 : : */
55 : : extern char* hasmntopt(const struct mntent* mnt, const char* opt);
56 : : #endif
57 : :
58 : : #if HAVE_SYS_STATFS_H
59 : : #include <sys/statfs.h>
60 : : #endif
61 : : #if HAVE_SYS_STATVFS_H
62 : : #include <sys/statvfs.h>
63 : : #endif
64 : : #if HAVE_SYS_VFS_H
65 : : #include <sys/vfs.h>
66 : : #elif HAVE_SYS_MOUNT_H
67 : : #if HAVE_SYS_PARAM_H
68 : : #include <sys/param.h>
69 : : #endif
70 : : #include <sys/mount.h>
71 : : #endif
72 : :
73 : : #ifndef O_BINARY
74 : : #define O_BINARY 0
75 : : #endif
76 : :
77 : : #include "gunixmounts.h"
78 : : #include "gfile.h"
79 : : #include "gfilemonitor.h"
80 : : #include "glibintl.h"
81 : : #include "glocalfile.h"
82 : : #include "gthemedicon.h"
83 : : #include "gcontextspecificgroup.h"
84 : :
85 : :
86 : : #ifdef HAVE_MNTENT_H
87 : : static const char *_resolve_dev_root (void);
88 : : #endif
89 : :
90 : : /**
91 : : * GUnixMountType:
92 : : * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type.
93 : : * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type.
94 : : * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type.
95 : : * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type.
96 : : * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type.
97 : : * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type.
98 : : * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type.
99 : : * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type.
100 : : * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type.
101 : : * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type.
102 : : * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type.
103 : : * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type.
104 : : * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type.
105 : : *
106 : : * Types of UNIX mounts.
107 : : **/
108 : : typedef enum {
109 : : G_UNIX_MOUNT_TYPE_UNKNOWN,
110 : : G_UNIX_MOUNT_TYPE_FLOPPY,
111 : : G_UNIX_MOUNT_TYPE_CDROM,
112 : : G_UNIX_MOUNT_TYPE_NFS,
113 : : G_UNIX_MOUNT_TYPE_ZIP,
114 : : G_UNIX_MOUNT_TYPE_JAZ,
115 : : G_UNIX_MOUNT_TYPE_MEMSTICK,
116 : : G_UNIX_MOUNT_TYPE_CF,
117 : : G_UNIX_MOUNT_TYPE_SM,
118 : : G_UNIX_MOUNT_TYPE_SDMMC,
119 : : G_UNIX_MOUNT_TYPE_IPOD,
120 : : G_UNIX_MOUNT_TYPE_CAMERA,
121 : : G_UNIX_MOUNT_TYPE_HD
122 : : } GUnixMountType;
123 : :
124 : : struct _GUnixMountEntry {
125 : : char *mount_path;
126 : : char *device_path;
127 : : char *root_path;
128 : : char *filesystem_type;
129 : : char *options;
130 : : gboolean is_read_only;
131 : : gboolean is_system_internal;
132 : : };
133 : :
134 : 4 : G_DEFINE_BOXED_TYPE (GUnixMountEntry, g_unix_mount_entry, g_unix_mount_entry_copy, g_unix_mount_entry_free)
135 : :
136 : : struct _GUnixMountPoint {
137 : : char *mount_path;
138 : : char *device_path;
139 : : char *filesystem_type;
140 : : char *options;
141 : : gboolean is_read_only;
142 : : gboolean is_user_mountable;
143 : : gboolean is_loopback;
144 : : };
145 : :
146 : 4 : G_DEFINE_BOXED_TYPE (GUnixMountPoint, g_unix_mount_point,
147 : : g_unix_mount_point_copy, g_unix_mount_point_free)
148 : :
149 : : static GList *_g_get_unix_mounts (void);
150 : : static GUnixMountEntry **_g_unix_mounts_get_from_file (const char *table_path,
151 : : uint64_t *time_read_out,
152 : : size_t *n_entries_out);
153 : : static GList *_g_get_unix_mount_points (void);
154 : : static GUnixMountPoint **_g_unix_mount_points_get_from_file (const char *table_path,
155 : : uint64_t *time_read_out,
156 : : size_t *n_points_out);
157 : : static gboolean proc_mounts_watch_is_running (void);
158 : :
159 : : G_LOCK_DEFINE_STATIC (proc_mounts_source);
160 : :
161 : : /* Protected by proc_mounts_source lock */
162 : : static guint64 mount_poller_time = 0;
163 : : static GSource *proc_mounts_watch_source = NULL;
164 : :
165 : : #ifdef HAVE_SYS_MNTTAB_H
166 : : #define MNTOPT_RO "ro"
167 : : #endif
168 : :
169 : : #ifdef HAVE_MNTENT_H
170 : : #include <mntent.h>
171 : : #ifdef HAVE_LIBMOUNT
172 : : #include <libmount.h>
173 : : #endif
174 : : #elif defined (HAVE_SYS_MNTTAB_H)
175 : : #include <sys/mnttab.h>
176 : : #if defined(__sun) && !defined(mnt_opts)
177 : : #define mnt_opts mnt_mntopts
178 : : #endif
179 : : #endif
180 : :
181 : : #ifdef HAVE_SYS_VFSTAB_H
182 : : #include <sys/vfstab.h>
183 : : #endif
184 : :
185 : : #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
186 : : #include <sys/mntctl.h>
187 : : #include <sys/vfs.h>
188 : : #include <sys/vmount.h>
189 : : #include <fshelp.h>
190 : : #endif
191 : :
192 : : #if (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
193 : : #include <sys/param.h>
194 : : #include <sys/ucred.h>
195 : : #include <sys/mount.h>
196 : : #include <fstab.h>
197 : : #ifdef HAVE_SYS_SYSCTL_H
198 : : #include <sys/sysctl.h>
199 : : #endif
200 : : #endif
201 : :
202 : : #ifndef HAVE_SETMNTENT
203 : : #define setmntent(f,m) fopen(f,m)
204 : : #endif
205 : : #ifndef HAVE_ENDMNTENT
206 : : #define endmntent(f) fclose(f)
207 : : #endif
208 : :
209 : : #ifdef HAVE_LIBMOUNT
210 : : /* Protected by proc_mounts_source lock */
211 : : static struct libmnt_monitor *proc_mounts_monitor = NULL;
212 : : #endif
213 : :
214 : : static guint64 get_mounts_timestamp (void);
215 : : static guint64 get_mount_points_timestamp (void);
216 : :
217 : : static gboolean
218 : 1993 : is_in (const char *value, const char *set[])
219 : : {
220 : : int i;
221 : 57278 : for (i = 0; set[i] != NULL; i++)
222 : : {
223 : 56991 : if (strcmp (set[i], value) == 0)
224 : 1706 : return TRUE;
225 : : }
226 : 287 : return FALSE;
227 : : }
228 : :
229 : : /* Marked as unused because these are only used on some platform variants, but
230 : : * working out the #if sequence for that would be too much for my little brain. */
231 : : static GList *unix_mount_entry_array_free_to_list (GUnixMountEntry **entries,
232 : : size_t n_entries) G_GNUC_UNUSED;
233 : : static GList *unix_mount_point_array_free_to_list (GUnixMountPoint **points,
234 : : size_t n_points) G_GNUC_UNUSED;
235 : :
236 : : /* Helper to convert to a list for the old API.
237 : : * Steals ownership of the @entries array. */
238 : : static GList *
239 : 46 : unix_mount_entry_array_free_to_list (GUnixMountEntry **entries,
240 : : size_t n_entries)
241 : : {
242 : 46 : GList *l = NULL;
243 : :
244 : 1840 : for (size_t i = 0; i < n_entries; i++)
245 : 1794 : l = g_list_prepend (l, g_steal_pointer (&entries[i]));
246 : :
247 : 46 : g_free (entries);
248 : :
249 : 46 : return g_list_reverse (l);
250 : : }
251 : :
252 : : /* Helper to convert to a list for the old API.
253 : : * Steals ownership of the @entries array. */
254 : : static GList *
255 : 1 : unix_mount_point_array_free_to_list (GUnixMountPoint **points,
256 : : size_t n_points)
257 : : {
258 : 1 : GList *l = NULL;
259 : :
260 : 1 : for (size_t i = 0; i < n_points; i++)
261 : 0 : l = g_list_prepend (l, g_steal_pointer (&points[i]));
262 : :
263 : 1 : g_free (points);
264 : :
265 : 1 : return g_list_reverse (l);
266 : : }
267 : :
268 : : /**
269 : : * g_unix_is_mount_path_system_internal:
270 : : * @mount_path: (type filename): a mount path, e.g. `/media/disk` or `/usr`
271 : : *
272 : : * Determines if @mount_path is considered an implementation of the
273 : : * OS. This is primarily used for hiding mountable and mounted volumes
274 : : * that only are used in the OS and has little to no relevance to the
275 : : * casual user.
276 : : *
277 : : * Returns: %TRUE if @mount_path is considered an implementation detail
278 : : * of the OS.
279 : : **/
280 : : gboolean
281 : 94 : g_unix_is_mount_path_system_internal (const char *mount_path)
282 : : {
283 : 94 : const char *ignore_mountpoints[] = {
284 : : /* Includes all FHS 2.3 toplevel dirs and other specialized
285 : : * directories that we want to hide from the user.
286 : : */
287 : : "/", /* we already have "Filesystem root" in Nautilus */
288 : : "/bin",
289 : : "/boot",
290 : : "/compat/linux/proc",
291 : : "/compat/linux/sys",
292 : : "/dev",
293 : : "/etc",
294 : : "/home",
295 : : "/lib",
296 : : "/lib64",
297 : : "/libexec",
298 : : "/live/cow",
299 : : "/live/image",
300 : : "/media",
301 : : "/mnt",
302 : : "/opt",
303 : : "/rescue",
304 : : "/root",
305 : : "/sbin",
306 : : "/srv",
307 : : "/tmp",
308 : : "/usr",
309 : : "/usr/X11R6",
310 : : "/usr/local",
311 : : "/usr/obj",
312 : : "/usr/ports",
313 : : "/usr/src",
314 : : "/usr/xobj",
315 : : "/var",
316 : : "/var/crash",
317 : : "/var/local",
318 : : GLIB_LOCALSTATEDIR,
319 : : "/var/log",
320 : : "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */
321 : : "/var/mail",
322 : : "/var/run",
323 : : GLIB_RUNSTATEDIR,
324 : : "/var/tmp", /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */
325 : : "/proc",
326 : : "/sbin",
327 : : "/net",
328 : : "/sys",
329 : : NULL
330 : : };
331 : :
332 : 94 : if (is_in (mount_path, ignore_mountpoints))
333 : 1 : return TRUE;
334 : :
335 : 93 : if (g_str_has_prefix (mount_path, "/dev/") ||
336 : 93 : g_str_has_prefix (mount_path, "/proc/") ||
337 : 93 : g_str_has_prefix (mount_path, "/sys/"))
338 : 46 : return TRUE;
339 : :
340 : 47 : if (g_str_has_suffix (mount_path, "/.gvfs"))
341 : 0 : return TRUE;
342 : :
343 : 47 : return FALSE;
344 : : }
345 : :
346 : : /**
347 : : * g_unix_is_system_fs_type:
348 : : * @fs_type: a file system type, e.g. `procfs` or `tmpfs`
349 : : *
350 : : * Determines if @fs_type is considered a type of file system which is only
351 : : * used in implementation of the OS. This is primarily used for hiding
352 : : * mounted volumes that are intended as APIs for programs to read, and system
353 : : * administrators at a shell; rather than something that should, for example,
354 : : * appear in a GUI. For example, the Linux `/proc` filesystem.
355 : : *
356 : : * The list of file system types considered ‘system’ ones may change over time.
357 : : *
358 : : * Returns: %TRUE if @fs_type is considered an implementation detail of the OS.
359 : : * Since: 2.56
360 : : */
361 : : gboolean
362 : 1803 : g_unix_is_system_fs_type (const char *fs_type)
363 : : {
364 : 1803 : const char *ignore_fs[] = {
365 : : "adfs",
366 : : "afs",
367 : : "auto",
368 : : "autofs",
369 : : "autofs4",
370 : : "cgroup",
371 : : "configfs",
372 : : "cxfs",
373 : : "debugfs",
374 : : "devfs",
375 : : "devpts",
376 : : "devtmpfs",
377 : : "ecryptfs",
378 : : "fdescfs",
379 : : "fusectl",
380 : : "gfs",
381 : : "gfs2",
382 : : "gpfs",
383 : : "hugetlbfs",
384 : : "kernfs",
385 : : "linprocfs",
386 : : "linsysfs",
387 : : "lustre",
388 : : "lustre_lite",
389 : : "mfs",
390 : : "mqueue",
391 : : "ncpfs",
392 : : "nfsd",
393 : : "nullfs",
394 : : "ocfs2",
395 : : "overlay",
396 : : "proc",
397 : : "procfs",
398 : : "pstore",
399 : : "ptyfs",
400 : : "rootfs",
401 : : "rpc_pipefs",
402 : : "securityfs",
403 : : "selinuxfs",
404 : : "sysfs",
405 : : "tmpfs",
406 : : "usbfs",
407 : : NULL
408 : : };
409 : :
410 : 1803 : g_return_val_if_fail (fs_type != NULL && *fs_type != '\0', FALSE);
411 : :
412 : 1803 : return is_in (fs_type, ignore_fs);
413 : : }
414 : :
415 : : /**
416 : : * g_unix_is_system_device_path:
417 : : * @device_path: a device path, e.g. `/dev/loop0` or `nfsd`
418 : : *
419 : : * Determines if @device_path is considered a block device path which is only
420 : : * used in implementation of the OS. This is primarily used for hiding
421 : : * mounted volumes that are intended as APIs for programs to read, and system
422 : : * administrators at a shell; rather than something that should, for example,
423 : : * appear in a GUI. For example, the Linux `/proc` filesystem.
424 : : *
425 : : * The list of device paths considered ‘system’ ones may change over time.
426 : : *
427 : : * Returns: %TRUE if @device_path is considered an implementation detail of
428 : : * the OS.
429 : : * Since: 2.56
430 : : */
431 : : gboolean
432 : 96 : g_unix_is_system_device_path (const char *device_path)
433 : : {
434 : 96 : const char *ignore_devices[] = {
435 : : "none",
436 : : "sunrpc",
437 : : "devpts",
438 : : "nfsd",
439 : : "/dev/loop",
440 : : "/dev/vn",
441 : : NULL
442 : : };
443 : :
444 : 96 : g_return_val_if_fail (device_path != NULL && *device_path != '\0', FALSE);
445 : :
446 : 96 : return is_in (device_path, ignore_devices);
447 : : }
448 : :
449 : : static gboolean
450 : 1797 : guess_system_internal (const char *mountpoint,
451 : : const char *fs,
452 : : const char *device,
453 : : const char *root)
454 : : {
455 : 1797 : if (g_unix_is_system_fs_type (fs))
456 : 1703 : return TRUE;
457 : :
458 : 94 : if (g_unix_is_system_device_path (device))
459 : 0 : return TRUE;
460 : :
461 : 94 : if (g_unix_is_mount_path_system_internal (mountpoint))
462 : 47 : return TRUE;
463 : :
464 : : /* It is not possible to reliably detect mounts which were created by bind
465 : : * operation. mntent-based _g_get_unix_mounts() implementation blindly skips
466 : : * mounts with a device path that is repeated (e.g. mounts created by bind
467 : : * operation, btrfs subvolumes). This usually chooses the most important
468 : : * mounts (i.e. which points to the root of filesystem), but it doesn't work
469 : : * in all cases and also it is not ideal that those mounts are completely
470 : : * ignored (e.g. x-gvfs-show doesn't work for them, trash backend can't handle
471 : : * files on btrfs subvolumes). libmount-based _g_get_unix_mounts()
472 : : * implementation provides a root path. So there is no need to completely
473 : : * ignore those mounts, because e.g. our volume monitors can use the root path
474 : : * to not mengle those mounts with the "regular" mounts (i.e. which points to
475 : : * the root). But because those mounts usually just duplicate other mounts and
476 : : * are completely ignored with mntend-based implementation, let's mark them as
477 : : * system internal. Given the different approaches it doesn't mean that all
478 : : * mounts which were ignored will be system internal now, but this should work
479 : : * in most cases. For more info, see g_unix_mount_entry_get_root_path()
480 : : * annotation, comment in mntent-based _g_get_unix_mounts() implementation and
481 : : * the https://gitlab.gnome.org/GNOME/glib/issues/1271 issue.
482 : : */
483 : 47 : if (root != NULL && g_strcmp0 (root, "/") != 0)
484 : 47 : return TRUE;
485 : :
486 : 0 : return FALSE;
487 : : }
488 : :
489 : : /* GUnixMounts (ie: mtab) implementations {{{1 */
490 : :
491 : : static GUnixMountEntry *
492 : 1797 : create_unix_mount_entry (const char *device_path,
493 : : const char *mount_path,
494 : : const char *root_path,
495 : : const char *filesystem_type,
496 : : const char *options,
497 : : gboolean is_read_only)
498 : : {
499 : 1797 : GUnixMountEntry *mount_entry = NULL;
500 : :
501 : 1797 : mount_entry = g_new0 (GUnixMountEntry, 1);
502 : 1797 : mount_entry->device_path = g_strdup (device_path);
503 : 1797 : mount_entry->mount_path = g_strdup (mount_path);
504 : 1797 : mount_entry->root_path = g_strdup (root_path);
505 : 1797 : mount_entry->filesystem_type = g_strdup (filesystem_type);
506 : 1797 : mount_entry->options = g_strdup (options);
507 : 1797 : mount_entry->is_read_only = is_read_only;
508 : :
509 : 1797 : mount_entry->is_system_internal =
510 : 1797 : guess_system_internal (mount_entry->mount_path,
511 : 1797 : mount_entry->filesystem_type,
512 : 1797 : mount_entry->device_path,
513 : 1797 : mount_entry->root_path);
514 : :
515 : 1797 : return mount_entry;
516 : : }
517 : :
518 : : static GUnixMountPoint *
519 : 4 : create_unix_mount_point (const char *device_path,
520 : : const char *mount_path,
521 : : const char *filesystem_type,
522 : : const char *options,
523 : : gboolean is_read_only,
524 : : gboolean is_user_mountable,
525 : : gboolean is_loopback)
526 : : {
527 : 4 : GUnixMountPoint *mount_point = NULL;
528 : :
529 : 4 : mount_point = g_new0 (GUnixMountPoint, 1);
530 : 4 : mount_point->device_path = g_strdup (device_path);
531 : 4 : mount_point->mount_path = g_strdup (mount_path);
532 : 4 : mount_point->filesystem_type = g_strdup (filesystem_type);
533 : 4 : mount_point->options = g_strdup (options);
534 : 4 : mount_point->is_read_only = is_read_only;
535 : 4 : mount_point->is_user_mountable = is_user_mountable;
536 : 4 : mount_point->is_loopback = is_loopback;
537 : :
538 : 4 : return mount_point;
539 : : }
540 : :
541 : : /* mntent.h (Linux, GNU, NSS) {{{2 */
542 : : #ifdef HAVE_MNTENT_H
543 : :
544 : : #ifdef HAVE_LIBMOUNT
545 : :
546 : : /* For documentation on /proc/self/mountinfo see
547 : : * http://www.kernel.org/doc/Documentation/filesystems/proc.txt
548 : : */
549 : : #define PROC_MOUNTINFO_PATH "/proc/self/mountinfo"
550 : :
551 : : static GUnixMountEntry **
552 : 47 : _g_unix_mounts_get_from_file (const char *table_path,
553 : : uint64_t *time_read_out,
554 : : size_t *n_entries_out)
555 : : {
556 : 47 : struct libmnt_table *table = NULL;
557 : 47 : struct libmnt_iter* iter = NULL;
558 : 47 : struct libmnt_fs *fs = NULL;
559 : 47 : GUnixMountEntry *mount_entry = NULL;
560 : 47 : GPtrArray *return_array = NULL;
561 : :
562 : 47 : if (time_read_out != NULL)
563 : 1 : *time_read_out = get_mounts_timestamp ();
564 : :
565 : 47 : return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_entry_free, TRUE);
566 : 47 : table = mnt_new_table ();
567 : 47 : if (mnt_table_parse_mtab (table, table_path) < 0)
568 : 0 : goto out;
569 : :
570 : 47 : iter = mnt_new_iter (MNT_ITER_FORWARD);
571 : 1844 : while (mnt_table_next_fs (table, iter, &fs) == 0)
572 : : {
573 : 1797 : const char *device_path = NULL;
574 : 1797 : char *mount_options = NULL;
575 : 1797 : unsigned long mount_flags = 0;
576 : 1797 : gboolean is_read_only = FALSE;
577 : :
578 : 1797 : device_path = mnt_fs_get_source (fs);
579 : 1797 : if (g_strcmp0 (device_path, "/dev/root") == 0)
580 : 0 : device_path = _resolve_dev_root ();
581 : :
582 : 1797 : mount_options = mnt_fs_strdup_options (fs);
583 : 1797 : if (mount_options)
584 : : {
585 : 1797 : mnt_optstr_get_flags (mount_options, &mount_flags, mnt_get_builtin_optmap (MNT_LINUX_MAP));
586 : 1797 : g_free (mount_options);
587 : : }
588 : 1797 : is_read_only = (mount_flags & MS_RDONLY) ? TRUE : FALSE;
589 : :
590 : 1797 : mount_entry = create_unix_mount_entry (device_path,
591 : : mnt_fs_get_target (fs),
592 : : mnt_fs_get_root (fs),
593 : : mnt_fs_get_fstype (fs),
594 : : mnt_fs_get_options (fs),
595 : : is_read_only);
596 : :
597 : 1797 : g_ptr_array_add (return_array, g_steal_pointer (&mount_entry));
598 : : }
599 : 47 : mnt_free_iter (iter);
600 : :
601 : 47 : out:
602 : 47 : mnt_free_table (table);
603 : :
604 : 47 : if (n_entries_out != NULL)
605 : 47 : *n_entries_out = return_array->len;
606 : :
607 : 47 : return (GUnixMountEntry **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
608 : : }
609 : :
610 : : static GList *
611 : 46 : _g_get_unix_mounts (void)
612 : : {
613 : 46 : GUnixMountEntry **entries = NULL;
614 : 46 : size_t n_entries = 0;
615 : :
616 : 46 : entries = _g_unix_mounts_get_from_file (NULL /* default libmount filename */,
617 : : NULL, &n_entries);
618 : :
619 : 46 : return unix_mount_entry_array_free_to_list (g_steal_pointer (&entries), n_entries);
620 : : }
621 : :
622 : : #else
623 : :
624 : : static const char *
625 : : get_mtab_read_file (void)
626 : : {
627 : : #ifdef _PATH_MOUNTED
628 : : # ifdef __linux__
629 : : return "/proc/mounts";
630 : : # else
631 : : return _PATH_MOUNTED;
632 : : # endif
633 : : #else
634 : : return "/etc/mtab";
635 : : #endif
636 : : }
637 : :
638 : : #ifndef HAVE_GETMNTENT_R
639 : : G_LOCK_DEFINE_STATIC(getmntent);
640 : : #endif
641 : :
642 : : static GUnixMountEntry **
643 : : _g_unix_mounts_get_from_file (const char *table_path,
644 : : uint64_t *time_read_out,
645 : : size_t *n_entries_out)
646 : : {
647 : : #ifdef HAVE_GETMNTENT_R
648 : : struct mntent ent;
649 : : char buf[1024];
650 : : #endif
651 : : struct mntent *mntent;
652 : : FILE *file;
653 : : GUnixMountEntry *mount_entry;
654 : : GHashTable *mounts_hash;
655 : : GPtrArray *return_array = NULL;
656 : :
657 : : if (time_read_out != NULL)
658 : : *time_read_out = get_mounts_timestamp ();
659 : :
660 : : file = setmntent (table_path, "re");
661 : : if (file == NULL)
662 : : return NULL;
663 : :
664 : : return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_entry_free, TRUE);
665 : : mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
666 : :
667 : : #ifdef HAVE_GETMNTENT_R
668 : : while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
669 : : #else
670 : : G_LOCK (getmntent);
671 : : while ((mntent = getmntent (file)) != NULL)
672 : : #endif
673 : : {
674 : : const char *device_path = NULL;
675 : : gboolean is_read_only = FALSE;
676 : :
677 : : /* ignore any mnt_fsname that is repeated and begins with a '/'
678 : : *
679 : : * We do this to avoid being fooled by --bind mounts, since
680 : : * these have the same device as the location they bind to.
681 : : * It's not an ideal solution to the problem, but it's likely that
682 : : * the most important mountpoint is first and the --bind ones after
683 : : * that aren't as important. So it should work.
684 : : *
685 : : * The '/' is to handle procfs, tmpfs and other no device mounts.
686 : : */
687 : : if (mntent->mnt_fsname != NULL &&
688 : : mntent->mnt_fsname[0] == '/' &&
689 : : g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
690 : : continue;
691 : :
692 : : if (g_strcmp0 (mntent->mnt_fsname, "/dev/root") == 0)
693 : : device_path = _resolve_dev_root ();
694 : : else
695 : : device_path = mntent->mnt_fsname;
696 : :
697 : : #if defined (HAVE_HASMNTOPT)
698 : : if (hasmntopt (mntent, MNTOPT_RO) != NULL)
699 : : is_read_only = TRUE;
700 : : #endif
701 : :
702 : : mount_entry = create_unix_mount_entry (device_path,
703 : : mntent->mnt_dir,
704 : : NULL,
705 : : mntent->mnt_type,
706 : : mntent->mnt_opts,
707 : : is_read_only);
708 : :
709 : : g_hash_table_insert (mounts_hash,
710 : : mount_entry->device_path,
711 : : mount_entry->device_path);
712 : :
713 : : g_ptr_array_add (return_array, g_steal_pointer (&mount_entry));
714 : : }
715 : : g_hash_table_destroy (mounts_hash);
716 : :
717 : : endmntent (file);
718 : :
719 : : #ifndef HAVE_GETMNTENT_R
720 : : G_UNLOCK (getmntent);
721 : : #endif
722 : :
723 : : if (n_entries_out != NULL)
724 : : *n_entries_out = return_array->len;
725 : :
726 : : return (GUnixMountEntry **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
727 : : }
728 : :
729 : : static GList *
730 : : _g_get_unix_mounts (void)
731 : : {
732 : : GUnixMountEntry **entries = NULL;
733 : : size_t n_entries = 0;
734 : :
735 : : entries = _g_unix_mounts_get_from_file (get_mtab_read_file (), NULL, &n_entries);
736 : :
737 : : return unix_mount_entry_array_free_to_list (g_steal_pointer (&entries), n_entries);
738 : : }
739 : :
740 : : #endif /* HAVE_LIBMOUNT */
741 : :
742 : : static const char *
743 : 3 : get_mtab_monitor_file (void)
744 : : {
745 : : static const char *mountinfo_path = NULL;
746 : : #ifdef HAVE_LIBMOUNT
747 : : struct stat buf;
748 : : #endif
749 : :
750 : 3 : if (mountinfo_path != NULL)
751 : 1 : return mountinfo_path;
752 : :
753 : : #ifdef HAVE_LIBMOUNT
754 : : /* The mtab file is still used by some distros, so it has to be monitored in
755 : : * order to avoid races between g_unix_mounts_get and "mounts-changed" signal:
756 : : * https://bugzilla.gnome.org/show_bug.cgi?id=782814
757 : : */
758 : 2 : if (mnt_has_regular_mtab (&mountinfo_path, NULL))
759 : : {
760 : 0 : return mountinfo_path;
761 : : }
762 : :
763 : 2 : if (stat (PROC_MOUNTINFO_PATH, &buf) == 0)
764 : : {
765 : 2 : mountinfo_path = PROC_MOUNTINFO_PATH;
766 : 2 : return mountinfo_path;
767 : : }
768 : : #endif
769 : :
770 : : #ifdef _PATH_MOUNTED
771 : : # ifdef __linux__
772 : 0 : mountinfo_path = "/proc/mounts";
773 : : # else
774 : : mountinfo_path = _PATH_MOUNTED;
775 : : # endif
776 : : #else
777 : : mountinfo_path = "/etc/mtab";
778 : : #endif
779 : :
780 : 0 : return mountinfo_path;
781 : : }
782 : :
783 : : /* mnttab.h {{{2 */
784 : : #elif defined (HAVE_SYS_MNTTAB_H)
785 : :
786 : : G_LOCK_DEFINE_STATIC(getmntent);
787 : :
788 : : static const char *
789 : : get_mtab_read_file (void)
790 : : {
791 : : #ifdef _PATH_MOUNTED
792 : : return _PATH_MOUNTED;
793 : : #else
794 : : return "/etc/mnttab";
795 : : #endif
796 : : }
797 : :
798 : : static const char *
799 : : get_mtab_monitor_file (void)
800 : : {
801 : : return get_mtab_read_file ();
802 : : }
803 : :
804 : : static GUnixMountEntry **
805 : : _g_unix_mounts_get_from_file (const char *table_path,
806 : : uint64_t *time_read_out,
807 : : size_t *n_entries_out)
808 : : {
809 : : struct mnttab mntent;
810 : : FILE *file;
811 : : GUnixMountEntry *mount_entry;
812 : : GPtrArray *return_array = NULL;
813 : :
814 : : if (time_read_out != NULL)
815 : : *time_read_out = get_mounts_timestamp ();
816 : :
817 : : file = setmntent (table_path, "re");
818 : : if (file == NULL)
819 : : return NULL;
820 : :
821 : : return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_entry_free, TRUE);
822 : :
823 : : G_LOCK (getmntent);
824 : : while (! getmntent (file, &mntent))
825 : : {
826 : : gboolean is_read_only = FALSE;
827 : :
828 : : #if defined (HAVE_HASMNTOPT)
829 : : if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
830 : : is_read_only = TRUE;
831 : : #endif
832 : :
833 : : mount_entry = create_unix_mount_entry (mntent.mnt_special,
834 : : mntent.mnt_mountp,
835 : : NULL,
836 : : mntent.mnt_fstype,
837 : : mntent.mnt_opts,
838 : : is_read_only);
839 : :
840 : : g_ptr_array_add (return_array, g_steal_pointer (&mount_entry));
841 : : }
842 : :
843 : : endmntent (file);
844 : :
845 : : G_UNLOCK (getmntent);
846 : :
847 : : if (n_entries_out != NULL)
848 : : *n_entries_out = return_array->len;
849 : :
850 : : return (GUnixMountEntry **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
851 : : }
852 : :
853 : : static GList *
854 : : _g_get_unix_mounts (void)
855 : : {
856 : : GUnixMountEntry **entries = NULL;
857 : : size_t n_entries = 0;
858 : :
859 : : entries = _g_unix_mounts_get_from_file (get_mtab_read_file (), NULL, &n_entries);
860 : :
861 : : return unix_mount_entry_array_free_to_list (g_steal_pointer (&entries), n_entries);
862 : : }
863 : :
864 : : /* mntctl.h (AIX) {{{2 */
865 : : #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
866 : :
867 : : static const char *
868 : : get_mtab_monitor_file (void)
869 : : {
870 : : return NULL;
871 : : }
872 : :
873 : : static GList *
874 : : _g_get_unix_mounts (void)
875 : : {
876 : : struct vfs_ent *fs_info;
877 : : struct vmount *vmount_info;
878 : : int vmount_number;
879 : : unsigned int vmount_size;
880 : : int current;
881 : : GList *return_list;
882 : :
883 : : if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0)
884 : : {
885 : : g_warning ("Unable to know the number of mounted volumes");
886 : :
887 : : return NULL;
888 : : }
889 : :
890 : : vmount_info = (struct vmount*)g_malloc (vmount_size);
891 : :
892 : : vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info);
893 : :
894 : : if (vmount_info->vmt_revision != VMT_REVISION)
895 : : g_warning ("Bad vmount structure revision number, want %d, got %d", VMT_REVISION, vmount_info->vmt_revision);
896 : :
897 : : if (vmount_number < 0)
898 : : {
899 : : g_warning ("Unable to recover mounted volumes information");
900 : :
901 : : g_free (vmount_info);
902 : : return NULL;
903 : : }
904 : :
905 : : return_list = NULL;
906 : : while (vmount_number > 0)
907 : : {
908 : : gboolean is_read_only = FALSE;
909 : :
910 : : fs_info = getvfsbytype (vmount_info->vmt_gfstype);
911 : :
912 : : /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
913 : : is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0;
914 : :
915 : : mount_entry = create_unix_mount_entry (vmt2dataptr (vmount_info, VMT_OBJECT),
916 : : vmt2dataptr (vmount_info, VMT_STUB),
917 : : NULL,
918 : : fs_info == NULL ? "unknown" : fs_info->vfsent_name,
919 : : NULL,
920 : : is_read_only);
921 : :
922 : : return_list = g_list_prepend (return_list, mount_entry);
923 : :
924 : : vmount_info = (struct vmount *)( (char*)vmount_info
925 : : + vmount_info->vmt_length);
926 : : vmount_number--;
927 : : }
928 : :
929 : : g_free (vmount_info);
930 : :
931 : : return g_list_reverse (return_list);
932 : : }
933 : :
934 : : static GUnixMountEntry **
935 : : _g_unix_mounts_get_from_file (const char *table_path,
936 : : uint64_t *time_read_out,
937 : : size_t *n_entries_out)
938 : : {
939 : : /* Not supported on mntctl() systems. */
940 : : if (time_read_out != NULL)
941 : : *time_read_out = 0;
942 : : if (n_entries_out != NULL)
943 : : *n_entries_out = 0;
944 : :
945 : : return NULL;
946 : : }
947 : :
948 : : /* sys/mount.h {{{2 */
949 : : #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
950 : :
951 : : static const char *
952 : : get_mtab_monitor_file (void)
953 : : {
954 : : return NULL;
955 : : }
956 : :
957 : : static GList *
958 : : _g_get_unix_mounts (void)
959 : : {
960 : : #if defined(USE_STATVFS)
961 : : struct statvfs *mntent = NULL;
962 : : #elif defined(USE_STATFS)
963 : : struct statfs *mntent = NULL;
964 : : #else
965 : : #error statfs juggling failed
966 : : #endif
967 : : size_t bufsize;
968 : : int num_mounts, i;
969 : : GUnixMountEntry *mount_entry;
970 : : GList *return_list;
971 : :
972 : : /* Pass NOWAIT to avoid blocking trying to update NFS mounts. */
973 : : #if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
974 : : num_mounts = getvfsstat (NULL, 0, ST_NOWAIT);
975 : : #elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
976 : : num_mounts = getfsstat (NULL, 0, MNT_NOWAIT);
977 : : #endif
978 : : if (num_mounts == -1)
979 : : return NULL;
980 : :
981 : : bufsize = num_mounts * sizeof (*mntent);
982 : : mntent = g_malloc (bufsize);
983 : : #if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
984 : : num_mounts = getvfsstat (mntent, bufsize, ST_NOWAIT);
985 : : #elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
986 : : num_mounts = getfsstat (mntent, bufsize, MNT_NOWAIT);
987 : : #endif
988 : : if (num_mounts == -1)
989 : : return NULL;
990 : :
991 : : return_list = NULL;
992 : :
993 : : for (i = 0; i < num_mounts; i++)
994 : : {
995 : : gboolean is_read_only = FALSE;
996 : :
997 : : #if defined(USE_STATVFS)
998 : : if (mntent[i].f_flag & ST_RDONLY)
999 : : #elif defined(USE_STATFS)
1000 : : if (mntent[i].f_flags & MNT_RDONLY)
1001 : : #else
1002 : : #error statfs juggling failed
1003 : : #endif
1004 : : is_read_only = TRUE;
1005 : :
1006 : : mount_entry = create_unix_mount_entry (mntent[i].f_mntfromname,
1007 : : mntent[i].f_mntonname,
1008 : : NULL,
1009 : : mntent[i].f_fstypename,
1010 : : NULL,
1011 : : is_read_only);
1012 : :
1013 : : return_list = g_list_prepend (return_list, mount_entry);
1014 : : }
1015 : :
1016 : : g_free (mntent);
1017 : :
1018 : : return g_list_reverse (return_list);
1019 : : }
1020 : :
1021 : : static GUnixMountEntry **
1022 : : _g_unix_mounts_get_from_file (const char *table_path,
1023 : : uint64_t *time_read_out,
1024 : : size_t *n_entries_out)
1025 : : {
1026 : : /* Not supported on getvfsstat()/getfsstat() systems. */
1027 : : if (time_read_out != NULL)
1028 : : *time_read_out = 0;
1029 : : if (n_entries_out != NULL)
1030 : : *n_entries_out = 0;
1031 : :
1032 : : return NULL;
1033 : : }
1034 : :
1035 : : /* Interix {{{2 */
1036 : : #elif defined(__INTERIX)
1037 : :
1038 : : static const char *
1039 : : get_mtab_monitor_file (void)
1040 : : {
1041 : : return NULL;
1042 : : }
1043 : :
1044 : : static GList *
1045 : : _g_get_unix_mounts (void)
1046 : : {
1047 : : DIR *dirp;
1048 : : GList* return_list = NULL;
1049 : : char filename[9 + NAME_MAX];
1050 : :
1051 : : dirp = opendir ("/dev/fs");
1052 : : if (!dirp)
1053 : : {
1054 : : g_warning ("unable to read /dev/fs!");
1055 : : return NULL;
1056 : : }
1057 : :
1058 : : while (1)
1059 : : {
1060 : : struct statvfs statbuf;
1061 : : struct dirent entry;
1062 : : struct dirent* result;
1063 : :
1064 : : if (readdir_r (dirp, &entry, &result) || result == NULL)
1065 : : break;
1066 : :
1067 : : strcpy (filename, "/dev/fs/");
1068 : : strcat (filename, entry.d_name);
1069 : :
1070 : : if (statvfs (filename, &statbuf) == 0)
1071 : : {
1072 : : GUnixMountEntry* mount_entry = g_new0(GUnixMountEntry, 1);
1073 : :
1074 : : mount_entry->mount_path = g_strdup (statbuf.f_mntonname);
1075 : : mount_entry->device_path = g_strdup (statbuf.f_mntfromname);
1076 : : mount_entry->filesystem_type = g_strdup (statbuf.f_fstypename);
1077 : :
1078 : : if (statbuf.f_flag & ST_RDONLY)
1079 : : mount_entry->is_read_only = TRUE;
1080 : :
1081 : : return_list = g_list_prepend(return_list, mount_entry);
1082 : : }
1083 : : }
1084 : :
1085 : : return_list = g_list_reverse (return_list);
1086 : :
1087 : : closedir (dirp);
1088 : :
1089 : : return return_list;
1090 : : }
1091 : :
1092 : : static GUnixMountEntry **
1093 : : _g_unix_mounts_get_from_file (const char *table_path,
1094 : : uint64_t *time_read_out,
1095 : : size_t *n_entries_out)
1096 : : {
1097 : : /* Not supported on Interix systems. */
1098 : : if (time_read_out != NULL)
1099 : : *time_read_out = 0;
1100 : : if (n_entries_out != NULL)
1101 : : *n_entries_out = 0;
1102 : :
1103 : : return NULL;
1104 : : }
1105 : :
1106 : : /* QNX {{{2 */
1107 : : #elif defined (HAVE_QNX)
1108 : :
1109 : : static char *
1110 : : get_mtab_monitor_file (void)
1111 : : {
1112 : : /* TODO: Not implemented */
1113 : : return NULL;
1114 : : }
1115 : :
1116 : : static GUnixMountEntry **
1117 : : _g_unix_mounts_get_from_file (const char *table_path,
1118 : : uint64_t *time_read_out,
1119 : : size_t *n_entries_out)
1120 : : {
1121 : : /* Not implemented, as per _g_get_unix_mounts() below */
1122 : : if (time_read_out != NULL)
1123 : : *time_read_out = 0;
1124 : : if (n_entries_out != NULL)
1125 : : *n_entries_out = 0;
1126 : :
1127 : : return NULL;
1128 : : }
1129 : :
1130 : : static GList *
1131 : : _g_get_unix_mounts (void)
1132 : : {
1133 : : /* TODO: Not implemented */
1134 : : return NULL;
1135 : : }
1136 : :
1137 : : /* Common code {{{2 */
1138 : : #else
1139 : : #error No _g_get_unix_mounts() implementation for system
1140 : : #endif
1141 : :
1142 : : /* GUnixMountPoints (ie: fstab) implementations {{{1 */
1143 : :
1144 : : /* _g_get_unix_mount_points():
1145 : : * read the fstab.
1146 : : * don't return swap and ignore mounts.
1147 : : */
1148 : :
1149 : : static char *
1150 : 4 : get_fstab_file (void)
1151 : : {
1152 : : #ifdef HAVE_LIBMOUNT
1153 : 4 : return (char *) mnt_get_fstab_path ();
1154 : : #else
1155 : : #if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
1156 : : /* AIX */
1157 : : return "/etc/filesystems";
1158 : : #elif defined(_PATH_MNTTAB)
1159 : : return _PATH_MNTTAB;
1160 : : #elif defined(VFSTAB)
1161 : : return VFSTAB;
1162 : : #else
1163 : : return "/etc/fstab";
1164 : : #endif
1165 : : #endif
1166 : : }
1167 : :
1168 : : /* mntent.h (Linux, GNU, NSS) {{{2 */
1169 : : #ifdef HAVE_MNTENT_H
1170 : :
1171 : : #ifdef HAVE_LIBMOUNT
1172 : :
1173 : : static GUnixMountPoint **
1174 : 2 : _g_unix_mount_points_get_from_file (const char *table_path,
1175 : : uint64_t *time_read_out,
1176 : : size_t *n_points_out)
1177 : : {
1178 : 2 : struct libmnt_table *table = NULL;
1179 : 2 : struct libmnt_iter* iter = NULL;
1180 : 2 : struct libmnt_fs *fs = NULL;
1181 : 2 : GUnixMountPoint *mount_point = NULL;
1182 : 2 : GPtrArray *return_array = NULL;
1183 : :
1184 : 2 : if (time_read_out != NULL)
1185 : 1 : *time_read_out = get_mount_points_timestamp ();
1186 : :
1187 : 2 : return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_point_free, TRUE);
1188 : 2 : table = mnt_new_table ();
1189 : 2 : if (mnt_table_parse_fstab (table, table_path) < 0)
1190 : 1 : goto out;
1191 : :
1192 : 1 : iter = mnt_new_iter (MNT_ITER_FORWARD);
1193 : 7 : while (mnt_table_next_fs (table, iter, &fs) == 0)
1194 : : {
1195 : 6 : const char *device_path = NULL;
1196 : 6 : const char *mount_path = NULL;
1197 : 6 : const char *mount_fstype = NULL;
1198 : 6 : char *mount_options = NULL;
1199 : 6 : gboolean is_read_only = FALSE;
1200 : 6 : gboolean is_user_mountable = FALSE;
1201 : 6 : gboolean is_loopback = FALSE;
1202 : :
1203 : 6 : mount_path = mnt_fs_get_target (fs);
1204 : 6 : if ((strcmp (mount_path, "ignore") == 0) ||
1205 : 6 : (strcmp (mount_path, "swap") == 0) ||
1206 : 6 : (strcmp (mount_path, "none") == 0))
1207 : 2 : continue;
1208 : :
1209 : 4 : mount_fstype = mnt_fs_get_fstype (fs);
1210 : 4 : mount_options = mnt_fs_strdup_options (fs);
1211 : 4 : if (mount_options)
1212 : : {
1213 : 4 : unsigned long mount_flags = 0;
1214 : 4 : unsigned long userspace_flags = 0;
1215 : :
1216 : 4 : mnt_optstr_get_flags (mount_options, &mount_flags, mnt_get_builtin_optmap (MNT_LINUX_MAP));
1217 : 4 : mnt_optstr_get_flags (mount_options, &userspace_flags, mnt_get_builtin_optmap (MNT_USERSPACE_MAP));
1218 : :
1219 : : /* We ignore bind fstab entries, as we ignore bind mounts anyway */
1220 : 4 : if (mount_flags & MS_BIND)
1221 : : {
1222 : 0 : g_free (mount_options);
1223 : 0 : continue;
1224 : : }
1225 : :
1226 : 4 : is_read_only = (mount_flags & MS_RDONLY) != 0;
1227 : 4 : is_loopback = (userspace_flags & MNT_MS_LOOP) != 0;
1228 : :
1229 : 4 : if ((mount_fstype != NULL && g_strcmp0 ("supermount", mount_fstype) == 0) ||
1230 : 4 : ((userspace_flags & MNT_MS_USER) &&
1231 : 0 : (g_strstr_len (mount_options, -1, "user_xattr") == NULL)) ||
1232 : 4 : (userspace_flags & MNT_MS_USERS) ||
1233 : 4 : (userspace_flags & MNT_MS_OWNER))
1234 : : {
1235 : 0 : is_user_mountable = TRUE;
1236 : : }
1237 : : }
1238 : :
1239 : 4 : device_path = mnt_fs_get_source (fs);
1240 : 4 : if (g_strcmp0 (device_path, "/dev/root") == 0)
1241 : 0 : device_path = _resolve_dev_root ();
1242 : :
1243 : 4 : mount_point = create_unix_mount_point (device_path,
1244 : : mount_path,
1245 : : mount_fstype,
1246 : : mount_options,
1247 : : is_read_only,
1248 : : is_user_mountable,
1249 : : is_loopback);
1250 : 4 : if (mount_options)
1251 : 4 : g_free (mount_options);
1252 : :
1253 : 4 : g_ptr_array_add (return_array, g_steal_pointer (&mount_point));
1254 : : }
1255 : 1 : mnt_free_iter (iter);
1256 : :
1257 : 2 : out:
1258 : 2 : mnt_free_table (table);
1259 : :
1260 : 2 : if (n_points_out != NULL)
1261 : 2 : *n_points_out = return_array->len;
1262 : :
1263 : 2 : return (GUnixMountPoint **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
1264 : : }
1265 : :
1266 : : static GList *
1267 : 1 : _g_get_unix_mount_points (void)
1268 : : {
1269 : 1 : GUnixMountPoint **points = NULL;
1270 : 1 : size_t n_points = 0;
1271 : :
1272 : 1 : points = _g_unix_mount_points_get_from_file (NULL /* default libmount filename */,
1273 : : NULL, &n_points);
1274 : :
1275 : 1 : return unix_mount_point_array_free_to_list (g_steal_pointer (&points), n_points);
1276 : : }
1277 : :
1278 : : #else
1279 : :
1280 : : static GUnixMountPoint **
1281 : : _g_unix_mount_points_get_from_file (const char *table_path,
1282 : : uint64_t *time_read_out,
1283 : : size_t *n_points_out)
1284 : : {
1285 : : #ifdef HAVE_GETMNTENT_R
1286 : : struct mntent ent;
1287 : : char buf[1024];
1288 : : #endif
1289 : : struct mntent *mntent;
1290 : : FILE *file;
1291 : : GUnixMountPoint *mount_point;
1292 : : GPtrArray *return_array = NULL;
1293 : :
1294 : : if (time_read_out != NULL)
1295 : : *time_read_out = get_mount_points_timestamp ();
1296 : :
1297 : : file = setmntent (table_path, "re");
1298 : : if (file == NULL)
1299 : : {
1300 : : if (n_points_out != NULL)
1301 : : *n_points_out = 0;
1302 : : return NULL;
1303 : : }
1304 : :
1305 : : return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_point_free, TRUE);
1306 : :
1307 : : #ifdef HAVE_GETMNTENT_R
1308 : : while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
1309 : : #else
1310 : : G_LOCK (getmntent);
1311 : : while ((mntent = getmntent (file)) != NULL)
1312 : : #endif
1313 : : {
1314 : : const char *device_path = NULL;
1315 : : gboolean is_read_only = FALSE;
1316 : : gboolean is_user_mountable = FALSE;
1317 : : gboolean is_loopback = FALSE;
1318 : :
1319 : : if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
1320 : : (strcmp (mntent->mnt_dir, "swap") == 0) ||
1321 : : (strcmp (mntent->mnt_dir, "none") == 0))
1322 : : continue;
1323 : :
1324 : : #ifdef HAVE_HASMNTOPT
1325 : : /* We ignore bind fstab entries, as we ignore bind mounts anyway */
1326 : : if (hasmntopt (mntent, "bind"))
1327 : : continue;
1328 : : #endif
1329 : :
1330 : : if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
1331 : : device_path = _resolve_dev_root ();
1332 : : else
1333 : : device_path = mntent->mnt_fsname;
1334 : :
1335 : : #ifdef HAVE_HASMNTOPT
1336 : : if (hasmntopt (mntent, MNTOPT_RO) != NULL)
1337 : : is_read_only = TRUE;
1338 : :
1339 : : if (hasmntopt (mntent, "loop") != NULL)
1340 : : is_loopback = TRUE;
1341 : :
1342 : : #endif
1343 : :
1344 : : if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0)
1345 : : #ifdef HAVE_HASMNTOPT
1346 : : || (hasmntopt (mntent, "user") != NULL
1347 : : && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr"))
1348 : : || hasmntopt (mntent, "users") != NULL
1349 : : || hasmntopt (mntent, "owner") != NULL
1350 : : #endif
1351 : : )
1352 : : is_user_mountable = TRUE;
1353 : :
1354 : : mount_point = create_unix_mount_point (device_path,
1355 : : mntent->mnt_dir,
1356 : : mntent->mnt_type,
1357 : : mntent->mnt_opts,
1358 : : is_read_only,
1359 : : is_user_mountable,
1360 : : is_loopback);
1361 : :
1362 : : g_ptr_array_add (return_array, g_steal_pointer (&mount_point));
1363 : : }
1364 : :
1365 : : endmntent (file);
1366 : :
1367 : : #ifndef HAVE_GETMNTENT_R
1368 : : G_UNLOCK (getmntent);
1369 : : #endif
1370 : :
1371 : : if (n_points_out != NULL)
1372 : : *n_points_out = return_array->len;
1373 : :
1374 : : return (GUnixMountPoint **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
1375 : : }
1376 : :
1377 : : static GList *
1378 : : _g_get_unix_mount_points (void)
1379 : : {
1380 : : GUnixMountPoint **points = NULL;
1381 : : size_t n_points = 0;
1382 : :
1383 : : points = _g_unix_mount_points_get_from_file (get_fstab_file (),
1384 : : NULL, &n_points);
1385 : :
1386 : : return unix_mount_point_array_free_to_list (g_steal_pointer (&points), n_points);
1387 : : }
1388 : :
1389 : : #endif /* HAVE_LIBMOUNT */
1390 : :
1391 : : /* mnttab.h {{{2 */
1392 : : #elif defined (HAVE_SYS_MNTTAB_H)
1393 : :
1394 : : static GUnixMountPoint **
1395 : : _g_unix_mount_points_get_from_file (const char *table_path,
1396 : : uint64_t *time_read_out,
1397 : : size_t *n_points_out)
1398 : : {
1399 : : struct mnttab mntent;
1400 : : FILE *file;
1401 : : GUnixMountPoint *mount_point;
1402 : : GPtrArray *return_array = NULL;
1403 : :
1404 : : if (time_read_out != NULL)
1405 : : *time_read_out = get_mount_points_timestamp ();
1406 : :
1407 : : file = setmntent (table_path, "re");
1408 : : if (file == NULL)
1409 : : {
1410 : : if (n_points_out != NULL)
1411 : : *n_points_out = 0;
1412 : : return NULL;
1413 : : }
1414 : :
1415 : : return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_point_free, TRUE);
1416 : :
1417 : : G_LOCK (getmntent);
1418 : : while (! getmntent (file, &mntent))
1419 : : {
1420 : : gboolean is_read_only = FALSE;
1421 : : gboolean is_user_mountable = FALSE;
1422 : : gboolean is_loopback = FALSE;
1423 : :
1424 : : if ((strcmp (mntent.mnt_mountp, "ignore") == 0) ||
1425 : : (strcmp (mntent.mnt_mountp, "swap") == 0) ||
1426 : : (strcmp (mntent.mnt_mountp, "none") == 0))
1427 : : continue;
1428 : :
1429 : : #ifdef HAVE_HASMNTOPT
1430 : : if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
1431 : : is_read_only = TRUE;
1432 : :
1433 : : if (hasmntopt (&mntent, "lofs") != NULL)
1434 : : is_loopback = TRUE;
1435 : : #endif
1436 : :
1437 : : if ((mntent.mnt_fstype != NULL)
1438 : : #ifdef HAVE_HASMNTOPT
1439 : : || (hasmntopt (&mntent, "user") != NULL
1440 : : && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr"))
1441 : : || hasmntopt (&mntent, "users") != NULL
1442 : : || hasmntopt (&mntent, "owner") != NULL
1443 : : #endif
1444 : : )
1445 : : is_user_mountable = TRUE;
1446 : :
1447 : : mount_point = create_unix_mount_point (mntent.mnt_special,
1448 : : mntent.mnt_mountp,
1449 : : mntent.mnt_fstype,
1450 : : mntent.mnt_mntopts,
1451 : : is_read_only,
1452 : : is_user_mountable,
1453 : : is_loopback);
1454 : :
1455 : : g_ptr_array_add (return_array, g_steal_pointer (&mount_point));
1456 : : }
1457 : :
1458 : : endmntent (file);
1459 : : G_UNLOCK (getmntent);
1460 : :
1461 : : if (n_points_out != NULL)
1462 : : *n_points_out = return_array->len;
1463 : :
1464 : : return (GUnixMountPoint **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
1465 : : }
1466 : :
1467 : : static GList *
1468 : : _g_get_unix_mount_points (void)
1469 : : {
1470 : : GUnixMountPoint **points = NULL;
1471 : : size_t n_points = 0;
1472 : :
1473 : : points = _g_unix_mount_points_get_from_file (get_fstab_file (),
1474 : : NULL, &n_points);
1475 : :
1476 : : return unix_mount_point_array_free_to_list (g_steal_pointer (&points), n_points);
1477 : : }
1478 : :
1479 : : /* mntctl.h (AIX) {{{2 */
1480 : : #elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
1481 : :
1482 : : /* functions to parse /etc/filesystems on aix */
1483 : :
1484 : : /* read character, ignoring comments (begin with '*', end with '\n' */
1485 : : static int
1486 : : aix_fs_getc (FILE *fd)
1487 : : {
1488 : : int c;
1489 : :
1490 : : while ((c = getc (fd)) == '*')
1491 : : {
1492 : : while (((c = getc (fd)) != '\n') && (c != EOF))
1493 : : ;
1494 : : }
1495 : : }
1496 : :
1497 : : /* eat all continuous spaces in a file */
1498 : : static int
1499 : : aix_fs_ignorespace (FILE *fd)
1500 : : {
1501 : : int c;
1502 : :
1503 : : while ((c = aix_fs_getc (fd)) != EOF)
1504 : : {
1505 : : if (!g_ascii_isspace (c))
1506 : : {
1507 : : ungetc (c,fd);
1508 : : return c;
1509 : : }
1510 : : }
1511 : :
1512 : : return EOF;
1513 : : }
1514 : :
1515 : : /* read one word from file */
1516 : : static int
1517 : : aix_fs_getword (FILE *fd,
1518 : : char *word)
1519 : : {
1520 : : int c;
1521 : :
1522 : : aix_fs_ignorespace (fd);
1523 : :
1524 : : while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c))
1525 : : {
1526 : : if (c == '"')
1527 : : {
1528 : : while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
1529 : : *word++ = c;
1530 : : else
1531 : : *word++ = c;
1532 : : }
1533 : : }
1534 : : *word = 0;
1535 : :
1536 : : return c;
1537 : : }
1538 : :
1539 : : typedef struct {
1540 : : char mnt_mount[PATH_MAX];
1541 : : char mnt_special[PATH_MAX];
1542 : : char mnt_fstype[16];
1543 : : char mnt_options[128];
1544 : : } AixMountTableEntry;
1545 : :
1546 : : /* read mount points properties */
1547 : : static int
1548 : : aix_fs_get (FILE *fd,
1549 : : AixMountTableEntry *prop)
1550 : : {
1551 : : static char word[PATH_MAX] = { 0 };
1552 : : char value[PATH_MAX];
1553 : :
1554 : : /* read stanza */
1555 : : if (word[0] == 0)
1556 : : {
1557 : : if (aix_fs_getword (fd, word) == EOF)
1558 : : return EOF;
1559 : : }
1560 : :
1561 : : word[strlen(word) - 1] = 0;
1562 : : strcpy (prop->mnt_mount, word);
1563 : :
1564 : : /* read attributes and value */
1565 : :
1566 : : while (aix_fs_getword (fd, word) != EOF)
1567 : : {
1568 : : /* test if is attribute or new stanza */
1569 : : if (word[strlen(word) - 1] == ':')
1570 : : return 0;
1571 : :
1572 : : /* read "=" */
1573 : : aix_fs_getword (fd, value);
1574 : :
1575 : : /* read value */
1576 : : aix_fs_getword (fd, value);
1577 : :
1578 : : if (strcmp (word, "dev") == 0)
1579 : : strcpy (prop->mnt_special, value);
1580 : : else if (strcmp (word, "vfs") == 0)
1581 : : strcpy (prop->mnt_fstype, value);
1582 : : else if (strcmp (word, "options") == 0)
1583 : : strcpy(prop->mnt_options, value);
1584 : : }
1585 : :
1586 : : return 0;
1587 : : }
1588 : :
1589 : : static GUnixMountPoint **
1590 : : _g_unix_mount_points_get_from_file (const char *table_path,
1591 : : uint64_t *time_read_out,
1592 : : size_t *n_points_out)
1593 : : {
1594 : : struct mntent *mntent;
1595 : : FILE *file;
1596 : : GUnixMountPoint *mount_point;
1597 : : AixMountTableEntry mntent;
1598 : : GPtrArray *return_array = NULL;
1599 : :
1600 : : if (time_read_out != NULL)
1601 : : *time_read_out = get_mount_points_timestamp ();
1602 : :
1603 : : file = setmntent (table_path, "re");
1604 : : if (file == NULL)
1605 : : {
1606 : : if (n_points_out != NULL)
1607 : : *n_points_out = 0;
1608 : : return NULL;
1609 : : }
1610 : :
1611 : : return_array = g_ptr_array_new_null_terminated (0, (GDestroyNotify) g_unix_mount_point_free, TRUE);
1612 : :
1613 : : while (!aix_fs_get (file, &mntent))
1614 : : {
1615 : : if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
1616 : : {
1617 : : mount_point = create_unix_mount_point (mntent.mnt_special,
1618 : : mntent.mnt_mount,
1619 : : mntent.mnt_fstype,
1620 : : mntent.mnt_options,
1621 : : TRUE,
1622 : : TRUE,
1623 : : FALSE);
1624 : :
1625 : : g_ptr_array_add (return_array, g_steal_pointer (&mount_point));
1626 : : }
1627 : : }
1628 : :
1629 : : endmntent (file);
1630 : :
1631 : : if (n_points_out != NULL)
1632 : : *n_points_out = return_array->len;
1633 : :
1634 : : return (GUnixMountPoint **) g_ptr_array_free (g_steal_pointer (&return_array), FALSE);
1635 : : }
1636 : :
1637 : : static GList *
1638 : : _g_get_unix_mount_points (void)
1639 : : {
1640 : : GUnixMountPoint **points = NULL;
1641 : : size_t n_points = 0;
1642 : :
1643 : : points = _g_unix_mount_points_get_from_file (get_fstab_file (),
1644 : : NULL, &n_points);
1645 : :
1646 : : return unix_mount_point_array_free_to_list (g_steal_pointer (&points), n_points);
1647 : : }
1648 : :
1649 : : #elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
1650 : :
1651 : : static GList *
1652 : : _g_get_unix_mount_points (void)
1653 : : {
1654 : : struct fstab *fstab = NULL;
1655 : : GUnixMountPoint *mount_point;
1656 : : GList *return_list = NULL;
1657 : : G_LOCK_DEFINE_STATIC (fsent);
1658 : : #ifdef HAVE_SYS_SYSCTL_H
1659 : : uid_t uid = getuid ();
1660 : : int usermnt = 0;
1661 : : struct stat sb;
1662 : : #endif
1663 : :
1664 : : #ifdef HAVE_SYS_SYSCTL_H
1665 : : #if defined(HAVE_SYSCTLBYNAME)
1666 : : {
1667 : : size_t len = sizeof(usermnt);
1668 : :
1669 : : sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
1670 : : }
1671 : : #elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
1672 : : {
1673 : : int mib[2];
1674 : : size_t len = sizeof(usermnt);
1675 : :
1676 : : mib[0] = CTL_VFS;
1677 : : mib[1] = VFS_USERMOUNT;
1678 : : sysctl (mib, 2, &usermnt, &len, NULL, 0);
1679 : : }
1680 : : #elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
1681 : : {
1682 : : int mib[2];
1683 : : size_t len = sizeof(usermnt);
1684 : :
1685 : : mib[0] = CTL_KERN;
1686 : : mib[1] = KERN_USERMOUNT;
1687 : : sysctl (mib, 2, &usermnt, &len, NULL, 0);
1688 : : }
1689 : : #endif
1690 : : #endif
1691 : :
1692 : : G_LOCK (fsent);
1693 : : if (!setfsent ())
1694 : : {
1695 : : G_UNLOCK (fsent);
1696 : : return NULL;
1697 : : }
1698 : :
1699 : : while ((fstab = getfsent ()) != NULL)
1700 : : {
1701 : : gboolean is_read_only = FALSE;
1702 : : gboolean is_user_mountable = FALSE;
1703 : :
1704 : : if (strcmp (fstab->fs_vfstype, "swap") == 0)
1705 : : continue;
1706 : :
1707 : : if (strcmp (fstab->fs_type, "ro") == 0)
1708 : : is_read_only = TRUE;
1709 : :
1710 : : #ifdef HAVE_SYS_SYSCTL_H
1711 : : if (usermnt != 0)
1712 : : {
1713 : : if (uid == 0 ||
1714 : : (stat (fstab->fs_file, &sb) == 0 && sb.st_uid == uid))
1715 : : {
1716 : : is_user_mountable = TRUE;
1717 : : }
1718 : : }
1719 : : #endif
1720 : :
1721 : : mount_point = create_unix_mount_point (fstab->fs_spec,
1722 : : fstab->fs_file,
1723 : : fstab->fs_vfstype,
1724 : : fstab->fs_mntops,
1725 : : is_read_only,
1726 : : is_user_mountable,
1727 : : FALSE);
1728 : :
1729 : : return_list = g_list_prepend (return_list, mount_point);
1730 : : }
1731 : :
1732 : : endfsent ();
1733 : : G_UNLOCK (fsent);
1734 : :
1735 : : return g_list_reverse (return_list);
1736 : : }
1737 : :
1738 : : static GUnixMountPoint **
1739 : : _g_unix_mount_points_get_from_file (const char *table_path,
1740 : : uint64_t *time_read_out,
1741 : : size_t *n_points_out)
1742 : : {
1743 : : /* Not supported on getfsent() systems. */
1744 : : if (time_read_out != NULL)
1745 : : *time_read_out = 0;
1746 : : if (n_points_out != NULL)
1747 : : *n_points_out = 0;
1748 : : return NULL;
1749 : : }
1750 : :
1751 : : /* Common code {{{2 */
1752 : : #else
1753 : : #error No g_get_mount_table() implementation for system
1754 : : #endif
1755 : :
1756 : : static guint64
1757 : 1 : get_mounts_timestamp (void)
1758 : : {
1759 : : const char *monitor_file;
1760 : : struct stat buf;
1761 : 1 : guint64 timestamp = 0;
1762 : :
1763 : 1 : G_LOCK (proc_mounts_source);
1764 : :
1765 : 1 : monitor_file = get_mtab_monitor_file ();
1766 : : /* Don't return mtime for /proc/ files */
1767 : 1 : if (monitor_file && !g_str_has_prefix (monitor_file, "/proc/"))
1768 : : {
1769 : 0 : if (stat (monitor_file, &buf) == 0)
1770 : 0 : timestamp = buf.st_mtime;
1771 : : }
1772 : 1 : else if (proc_mounts_watch_is_running ())
1773 : : {
1774 : : /* it's being monitored by poll, so return mount_poller_time */
1775 : 0 : timestamp = mount_poller_time;
1776 : : }
1777 : : else
1778 : : {
1779 : : /* Case of /proc/ file not being monitored - Be on the safe side and
1780 : : * send a new timestamp to force g_unix_mount_entries_changed_since() to
1781 : : * return TRUE so any application caches depending on it (like eg.
1782 : : * the one in GIO) get invalidated and don't hold possibly outdated
1783 : : * data - see Bug 787731 */
1784 : 1 : timestamp = g_get_monotonic_time ();
1785 : : }
1786 : :
1787 : 1 : G_UNLOCK (proc_mounts_source);
1788 : :
1789 : 1 : return timestamp;
1790 : : }
1791 : :
1792 : : static guint64
1793 : 2 : get_mount_points_timestamp (void)
1794 : : {
1795 : : const char *monitor_file;
1796 : : struct stat buf;
1797 : :
1798 : 2 : monitor_file = get_fstab_file ();
1799 : 2 : if (monitor_file)
1800 : : {
1801 : 2 : if (stat (monitor_file, &buf) == 0)
1802 : 0 : return (guint64)buf.st_mtime;
1803 : : }
1804 : 2 : return 0;
1805 : : }
1806 : :
1807 : : /**
1808 : : * g_unix_mounts_get:
1809 : : * @time_read: (out) (optional): guint64 to contain a timestamp, or %NULL
1810 : : *
1811 : : * Gets a #GList of #GUnixMountEntry containing the unix mounts.
1812 : : * If @time_read is set, it will be filled with the mount
1813 : : * timestamp, allowing for checking if the mounts have changed
1814 : : * with g_unix_mount_entries_changed_since().
1815 : : *
1816 : : * Returns: (element-type GUnixMountEntry) (transfer full):
1817 : : * a #GList of the UNIX mounts.
1818 : : *
1819 : : * Deprecated: 2.84: Use g_unix_mount_entries_get() instead.
1820 : : */
1821 : : GList *
1822 : 0 : g_unix_mounts_get (guint64 *time_read)
1823 : : {
1824 : 0 : return g_unix_mount_entries_get (time_read);
1825 : : }
1826 : :
1827 : : /**
1828 : : * g_unix_mount_entries_get:
1829 : : * @time_read: (out) (optional): guint64 to contain a timestamp, or %NULL
1830 : : *
1831 : : * Gets a #GList of #GUnixMountEntry containing the unix mounts.
1832 : : * If @time_read is set, it will be filled with the mount
1833 : : * timestamp, allowing for checking if the mounts have changed
1834 : : * with g_unix_mount_entries_changed_since().
1835 : : *
1836 : : * Returns: (element-type GUnixMountEntry) (transfer full):
1837 : : * a #GList of the UNIX mounts.
1838 : : *
1839 : : * Since: 2.84
1840 : : */
1841 : : GList *
1842 : 46 : g_unix_mount_entries_get (guint64 *time_read)
1843 : : {
1844 : 46 : if (time_read)
1845 : 0 : *time_read = get_mounts_timestamp ();
1846 : :
1847 : 46 : return _g_get_unix_mounts ();
1848 : : }
1849 : :
1850 : : /**
1851 : : * g_unix_mounts_get_from_file:
1852 : : * @table_path: path to the mounts table file (for example `/proc/self/mountinfo`)
1853 : : * @time_read_out: (optional) (out caller-allocates): return location for the
1854 : : * modification time of @table_path
1855 : : * @n_entries_out: (optional) (out caller-allocates): return location for the
1856 : : * number of mount entries returned
1857 : : *
1858 : : * Gets an array of [struct@Gio.UnixMountEntry]s containing the Unix mounts
1859 : : * listed in @table_path.
1860 : : *
1861 : : * This is a generalized version of g_unix_mount_entries_get(), mainly intended for
1862 : : * internal testing use. Note that g_unix_mount_entries_get() may parse multiple
1863 : : * hierarchical table files, so this function is not a direct superset of its
1864 : : * functionality.
1865 : : *
1866 : : * If there is an error reading or parsing the file, `NULL` will be returned
1867 : : * and both out parameters will be set to `0`.
1868 : : *
1869 : : * Returns: (transfer full) (array length=n_entries_out) (nullable): mount
1870 : : * entries, or `NULL` if there was an error loading them
1871 : : *
1872 : : * Since: 2.82
1873 : : * Deprecated: 2.84: Use g_unix_mount_entries_get_from_file() instead.
1874 : : */
1875 : : GUnixMountEntry **
1876 : 1 : g_unix_mounts_get_from_file (const char *table_path,
1877 : : uint64_t *time_read_out,
1878 : : size_t *n_entries_out)
1879 : : {
1880 : 1 : return g_unix_mount_entries_get_from_file (table_path, time_read_out, n_entries_out);
1881 : : }
1882 : :
1883 : : /**
1884 : : * g_unix_mount_entries_get_from_file:
1885 : : * @table_path: path to the mounts table file (for example `/proc/self/mountinfo`)
1886 : : * @time_read_out: (optional) (out caller-allocates): return location for the
1887 : : * modification time of @table_path
1888 : : * @n_entries_out: (optional) (out caller-allocates): return location for the
1889 : : * number of mount entries returned
1890 : : *
1891 : : * Gets an array of [struct@Gio.UnixMountEntry]s containing the Unix mounts
1892 : : * listed in @table_path.
1893 : : *
1894 : : * This is a generalized version of g_unix_mount_entries_get(), mainly intended for
1895 : : * internal testing use. Note that g_unix_mount_entries_get() may parse multiple
1896 : : * hierarchical table files, so this function is not a direct superset of its
1897 : : * functionality.
1898 : : *
1899 : : * If there is an error reading or parsing the file, `NULL` will be returned
1900 : : * and both out parameters will be set to `0`.
1901 : : *
1902 : : * Returns: (transfer full) (array length=n_entries_out) (nullable): mount
1903 : : * entries, or `NULL` if there was an error loading them
1904 : : *
1905 : : * Since: 2.84
1906 : : */
1907 : : GUnixMountEntry **
1908 : 1 : g_unix_mount_entries_get_from_file (const char *table_path,
1909 : : uint64_t *time_read_out,
1910 : : size_t *n_entries_out)
1911 : : {
1912 : 1 : return _g_unix_mounts_get_from_file (table_path, time_read_out, n_entries_out);
1913 : : }
1914 : :
1915 : : /**
1916 : : * g_unix_mount_at:
1917 : : * @mount_path: (type filename): path for a possible unix mount.
1918 : : * @time_read: (out) (optional): guint64 to contain a timestamp.
1919 : : *
1920 : : * Gets a #GUnixMountEntry for a given mount path. If @time_read
1921 : : * is set, it will be filled with a unix timestamp for checking
1922 : : * if the mounts have changed since with g_unix_mount_entries_changed_since().
1923 : : *
1924 : : * If more mounts have the same mount path, the last matching mount
1925 : : * is returned.
1926 : : *
1927 : : * This will return %NULL if there is no mount point at @mount_path.
1928 : : *
1929 : : * Returns: (transfer full) (nullable): a #GUnixMountEntry.
1930 : : *
1931 : : * Deprecated: 2.84: Use g_unix_mount_entry_at() instead.
1932 : : **/
1933 : : GUnixMountEntry *
1934 : 0 : g_unix_mount_at (const char *mount_path,
1935 : : guint64 *time_read)
1936 : : {
1937 : 0 : return g_unix_mount_entry_at (mount_path, time_read);
1938 : : }
1939 : :
1940 : : /**
1941 : : * g_unix_mount_entry_at:
1942 : : * @mount_path: (type filename): path for a possible unix mount.
1943 : : * @time_read: (out) (optional): guint64 to contain a timestamp.
1944 : : *
1945 : : * Gets a #GUnixMountEntry for a given mount path. If @time_read
1946 : : * is set, it will be filled with a unix timestamp for checking
1947 : : * if the mounts have changed since with g_unix_mount_entries_changed_since().
1948 : : *
1949 : : * If more mounts have the same mount path, the last matching mount
1950 : : * is returned.
1951 : : *
1952 : : * This will return %NULL if there is no mount point at @mount_path.
1953 : : *
1954 : : * Returns: (transfer full) (nullable): a #GUnixMountEntry.
1955 : : *
1956 : : * Since: 2.84
1957 : : **/
1958 : : GUnixMountEntry *
1959 : 45 : g_unix_mount_entry_at (const char *mount_path,
1960 : : guint64 *time_read)
1961 : : {
1962 : : GList *mounts, *l;
1963 : : GUnixMountEntry *mount_entry, *found;
1964 : :
1965 : 45 : mounts = g_unix_mount_entries_get (time_read);
1966 : :
1967 : 45 : found = NULL;
1968 : 1800 : for (l = mounts; l != NULL; l = l->next)
1969 : : {
1970 : 1755 : mount_entry = l->data;
1971 : :
1972 : 1755 : if (strcmp (mount_path, mount_entry->mount_path) == 0)
1973 : : {
1974 : 41 : if (found != NULL)
1975 : 0 : g_unix_mount_entry_free (found);
1976 : :
1977 : 41 : found = mount_entry;
1978 : : }
1979 : : else
1980 : 1714 : g_unix_mount_entry_free (mount_entry);
1981 : : }
1982 : 45 : g_list_free (mounts);
1983 : :
1984 : 45 : return found;
1985 : : }
1986 : :
1987 : : /**
1988 : : * g_unix_mount_for:
1989 : : * @file_path: (type filename): file path on some unix mount.
1990 : : * @time_read: (out) (optional): guint64 to contain a timestamp.
1991 : : *
1992 : : * Gets a #GUnixMountEntry for a given file path. If @time_read
1993 : : * is set, it will be filled with a unix timestamp for checking
1994 : : * if the mounts have changed since with g_unix_mount_entries_changed_since().
1995 : : *
1996 : : * If more mounts have the same mount path, the last matching mount
1997 : : * is returned.
1998 : : *
1999 : : * This will return %NULL if looking up the mount entry fails, if
2000 : : * @file_path doesn’t exist or there is an I/O error.
2001 : : *
2002 : : * Returns: (transfer full) (nullable): a #GUnixMountEntry.
2003 : : *
2004 : : * Since: 2.52
2005 : : * Deprecated: 2.84: Use g_unix_mount_entry_for() instead.
2006 : : **/
2007 : : GUnixMountEntry *
2008 : 0 : g_unix_mount_for (const char *file_path,
2009 : : guint64 *time_read)
2010 : : {
2011 : 0 : return g_unix_mount_entry_for (file_path, time_read);
2012 : : }
2013 : :
2014 : : /**
2015 : : * g_unix_mount_entry_for:
2016 : : * @file_path: (type filename): file path on some unix mount.
2017 : : * @time_read: (out) (optional): guint64 to contain a timestamp.
2018 : : *
2019 : : * Gets a #GUnixMountEntry for a given file path. If @time_read
2020 : : * is set, it will be filled with a unix timestamp for checking
2021 : : * if the mounts have changed since with g_unix_mount_entries_changed_since().
2022 : : *
2023 : : * If more mounts have the same mount path, the last matching mount
2024 : : * is returned.
2025 : : *
2026 : : * This will return %NULL if looking up the mount entry fails, if
2027 : : * @file_path doesn’t exist or there is an I/O error.
2028 : : *
2029 : : * Returns: (transfer full) (nullable): a #GUnixMountEntry.
2030 : : *
2031 : : * Since: 2.84
2032 : : **/
2033 : : GUnixMountEntry *
2034 : 3 : g_unix_mount_entry_for (const char *file_path,
2035 : : guint64 *time_read)
2036 : : {
2037 : : GUnixMountEntry *entry;
2038 : :
2039 : 3 : g_return_val_if_fail (file_path != NULL, NULL);
2040 : :
2041 : 3 : entry = g_unix_mount_entry_at (file_path, time_read);
2042 : 3 : if (entry == NULL)
2043 : : {
2044 : : char *topdir;
2045 : :
2046 : 3 : topdir = _g_local_file_find_topdir_for (file_path);
2047 : 3 : if (topdir != NULL)
2048 : : {
2049 : 3 : entry = g_unix_mount_entry_at (topdir, time_read);
2050 : 3 : g_free (topdir);
2051 : : }
2052 : : }
2053 : :
2054 : 3 : return entry;
2055 : : }
2056 : :
2057 : : static gpointer
2058 : 0 : copy_mount_point_cb (gconstpointer src,
2059 : : gpointer data)
2060 : : {
2061 : 0 : GUnixMountPoint *src_mount_point = (GUnixMountPoint *) src;
2062 : 0 : return g_unix_mount_point_copy (src_mount_point);
2063 : : }
2064 : :
2065 : : /**
2066 : : * g_unix_mount_points_get:
2067 : : * @time_read: (out) (optional): guint64 to contain a timestamp.
2068 : : *
2069 : : * Gets a #GList of #GUnixMountPoint containing the unix mount points.
2070 : : * If @time_read is set, it will be filled with the mount timestamp,
2071 : : * allowing for checking if the mounts have changed with
2072 : : * g_unix_mount_points_changed_since().
2073 : : *
2074 : : * Returns: (element-type GUnixMountPoint) (transfer full):
2075 : : * a #GList of the UNIX mountpoints.
2076 : : **/
2077 : : GList *
2078 : 1 : g_unix_mount_points_get (guint64 *time_read)
2079 : : {
2080 : : static GList *mnt_pts_last = NULL;
2081 : : static guint64 time_read_last = 0;
2082 : 1 : GList *mnt_pts = NULL;
2083 : : guint64 time_read_now;
2084 : : G_LOCK_DEFINE_STATIC (unix_mount_points);
2085 : :
2086 : 1 : G_LOCK (unix_mount_points);
2087 : :
2088 : 1 : time_read_now = get_mount_points_timestamp ();
2089 : 1 : if (time_read_now != time_read_last || mnt_pts_last == NULL)
2090 : : {
2091 : 1 : time_read_last = time_read_now;
2092 : 1 : g_list_free_full (mnt_pts_last, (GDestroyNotify) g_unix_mount_point_free);
2093 : 1 : mnt_pts_last = _g_get_unix_mount_points ();
2094 : : }
2095 : 1 : mnt_pts = g_list_copy_deep (mnt_pts_last, copy_mount_point_cb, NULL);
2096 : :
2097 : 1 : G_UNLOCK (unix_mount_points);
2098 : :
2099 : 1 : if (time_read)
2100 : 0 : *time_read = time_read_now;
2101 : :
2102 : 1 : return mnt_pts;
2103 : : }
2104 : :
2105 : : /**
2106 : : * g_unix_mount_points_get_from_file:
2107 : : * @table_path: path to the mount points table file (for example `/etc/fstab`)
2108 : : * @time_read_out: (optional) (out caller-allocates): return location for the
2109 : : * modification time of @table_path
2110 : : * @n_points_out: (optional) (out caller-allocates): return location for the
2111 : : * number of mount points returned
2112 : : *
2113 : : * Gets an array of [struct@Gio.UnixMountPoint]s containing the Unix mount
2114 : : * points listed in @table_path.
2115 : : *
2116 : : * This is a generalized version of g_unix_mount_points_get(), mainly intended
2117 : : * for internal testing use. Note that g_unix_mount_points_get() may parse
2118 : : * multiple hierarchical table files, so this function is not a direct superset
2119 : : * of its functionality.
2120 : : *
2121 : : * If there is an error reading or parsing the file, `NULL` will be returned
2122 : : * and both out parameters will be set to `0`.
2123 : : *
2124 : : * Returns: (transfer full) (array length=n_points_out) (nullable): mount
2125 : : * points, or `NULL` if there was an error loading them
2126 : : * Since: 2.82
2127 : : */
2128 : : GUnixMountPoint **
2129 : 1 : g_unix_mount_points_get_from_file (const char *table_path,
2130 : : uint64_t *time_read_out,
2131 : : size_t *n_points_out)
2132 : : {
2133 : 1 : return _g_unix_mount_points_get_from_file (table_path, time_read_out, n_points_out);
2134 : : }
2135 : :
2136 : : /**
2137 : : * g_unix_mount_point_at:
2138 : : * @mount_path: (type filename): path for a possible unix mount point.
2139 : : * @time_read: (out) (optional): guint64 to contain a timestamp.
2140 : : *
2141 : : * Gets a #GUnixMountPoint for a given mount path. If @time_read is set, it
2142 : : * will be filled with a unix timestamp for checking if the mount points have
2143 : : * changed since with g_unix_mount_points_changed_since().
2144 : : *
2145 : : * If more mount points have the same mount path, the last matching mount point
2146 : : * is returned.
2147 : : *
2148 : : * Returns: (transfer full) (nullable): a #GUnixMountPoint, or %NULL if no match
2149 : : * is found.
2150 : : *
2151 : : * Since: 2.66
2152 : : **/
2153 : : GUnixMountPoint *
2154 : 0 : g_unix_mount_point_at (const char *mount_path,
2155 : : guint64 *time_read)
2156 : : {
2157 : : GList *mount_points, *l;
2158 : : GUnixMountPoint *mount_point, *found;
2159 : :
2160 : 0 : mount_points = g_unix_mount_points_get (time_read);
2161 : :
2162 : 0 : found = NULL;
2163 : 0 : for (l = mount_points; l != NULL; l = l->next)
2164 : : {
2165 : 0 : mount_point = l->data;
2166 : :
2167 : 0 : if (strcmp (mount_path, mount_point->mount_path) == 0)
2168 : : {
2169 : 0 : if (found != NULL)
2170 : 0 : g_unix_mount_point_free (found);
2171 : :
2172 : 0 : found = mount_point;
2173 : : }
2174 : : else
2175 : 0 : g_unix_mount_point_free (mount_point);
2176 : : }
2177 : 0 : g_list_free (mount_points);
2178 : :
2179 : 0 : return found;
2180 : : }
2181 : :
2182 : : /**
2183 : : * g_unix_mounts_changed_since:
2184 : : * @time: guint64 to contain a timestamp.
2185 : : *
2186 : : * Checks if the unix mounts have changed since a given unix time.
2187 : : *
2188 : : * Returns: %TRUE if the mounts have changed since @time.
2189 : : *
2190 : : * Deprecated: 2.84: Use g_unix_mount_entry_free() instead.
2191 : : **/
2192 : : gboolean
2193 : 0 : g_unix_mounts_changed_since (guint64 time)
2194 : : {
2195 : 0 : return g_unix_mount_entries_changed_since (time);
2196 : : }
2197 : :
2198 : : /**
2199 : : * g_unix_mount_entries_changed_since:
2200 : : * @time: guint64 to contain a timestamp.
2201 : : *
2202 : : * Checks if the unix mounts have changed since a given unix time.
2203 : : *
2204 : : * Returns: %TRUE if the mounts have changed since @time.
2205 : : * Since 2.84
2206 : : **/
2207 : : gboolean
2208 : 0 : g_unix_mount_entries_changed_since (guint64 time)
2209 : : {
2210 : 0 : return get_mounts_timestamp () != time;
2211 : : }
2212 : :
2213 : : /**
2214 : : * g_unix_mount_points_changed_since:
2215 : : * @time: guint64 to contain a timestamp.
2216 : : *
2217 : : * Checks if the unix mount points have changed since a given unix time.
2218 : : *
2219 : : * Returns: %TRUE if the mount points have changed since @time.
2220 : : **/
2221 : : gboolean
2222 : 0 : g_unix_mount_points_changed_since (guint64 time)
2223 : : {
2224 : 0 : return get_mount_points_timestamp () != time;
2225 : : }
2226 : :
2227 : : /* GUnixMountMonitor {{{1 */
2228 : :
2229 : : enum {
2230 : : MOUNTS_CHANGED,
2231 : : MOUNTPOINTS_CHANGED,
2232 : : LAST_SIGNAL
2233 : : };
2234 : :
2235 : : static guint signals[LAST_SIGNAL];
2236 : :
2237 : : struct _GUnixMountMonitor {
2238 : : GObject parent;
2239 : :
2240 : : GMainContext *context;
2241 : : };
2242 : :
2243 : : struct _GUnixMountMonitorClass {
2244 : : GObjectClass parent_class;
2245 : : };
2246 : :
2247 : :
2248 : 10 : G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT)
2249 : :
2250 : : static GContextSpecificGroup mount_monitor_group;
2251 : : static GFileMonitor *fstab_monitor;
2252 : : static GFileMonitor *mtab_monitor;
2253 : : static GList *mount_poller_mounts;
2254 : : static guint mtab_file_changed_id;
2255 : :
2256 : : /* Called with proc_mounts_source lock held. */
2257 : : static gboolean
2258 : 1 : proc_mounts_watch_is_running (void)
2259 : : {
2260 : 1 : return proc_mounts_watch_source != NULL &&
2261 : 0 : !g_source_is_destroyed (proc_mounts_watch_source);
2262 : : }
2263 : :
2264 : : static void
2265 : 0 : fstab_file_changed (GFileMonitor *monitor,
2266 : : GFile *file,
2267 : : GFile *other_file,
2268 : : GFileMonitorEvent event_type,
2269 : : gpointer user_data)
2270 : : {
2271 : 0 : if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
2272 : 0 : event_type != G_FILE_MONITOR_EVENT_CREATED &&
2273 : : event_type != G_FILE_MONITOR_EVENT_DELETED)
2274 : 0 : return;
2275 : :
2276 : 0 : g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
2277 : : }
2278 : :
2279 : : static gboolean
2280 : 0 : mtab_file_changed_cb (gpointer user_data)
2281 : : {
2282 : 0 : mtab_file_changed_id = 0;
2283 : 0 : g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
2284 : :
2285 : 0 : return G_SOURCE_REMOVE;
2286 : : }
2287 : :
2288 : : static void
2289 : 0 : mtab_file_changed (GFileMonitor *monitor,
2290 : : GFile *file,
2291 : : GFile *other_file,
2292 : : GFileMonitorEvent event_type,
2293 : : gpointer user_data)
2294 : : {
2295 : : GMainContext *context;
2296 : : GSource *source;
2297 : :
2298 : 0 : if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
2299 : 0 : event_type != G_FILE_MONITOR_EVENT_CREATED &&
2300 : : event_type != G_FILE_MONITOR_EVENT_DELETED)
2301 : 0 : return;
2302 : :
2303 : : /* Skip accumulated events from file monitor which we are not able to handle
2304 : : * in a real time instead of emitting mounts_changed signal several times.
2305 : : * This should behave equally to GIOChannel based monitoring. See Bug 792235.
2306 : : */
2307 : 0 : if (mtab_file_changed_id > 0)
2308 : 0 : return;
2309 : :
2310 : 0 : context = g_main_context_get_thread_default ();
2311 : 0 : if (!context)
2312 : 0 : context = g_main_context_default ();
2313 : :
2314 : 0 : source = g_idle_source_new ();
2315 : 0 : g_source_set_priority (source, G_PRIORITY_DEFAULT);
2316 : 0 : g_source_set_callback (source, mtab_file_changed_cb, NULL, NULL);
2317 : 0 : g_source_set_static_name (source, "[gio] mtab_file_changed_cb");
2318 : 0 : g_source_attach (source, context);
2319 : 0 : g_source_unref (source);
2320 : : }
2321 : :
2322 : : static gboolean
2323 : 0 : proc_mounts_changed (GIOChannel *channel,
2324 : : GIOCondition cond,
2325 : : gpointer user_data)
2326 : : {
2327 : 0 : gboolean has_changed = FALSE;
2328 : :
2329 : : #ifdef HAVE_LIBMOUNT
2330 : 0 : if (cond & G_IO_IN)
2331 : : {
2332 : 0 : G_LOCK (proc_mounts_source);
2333 : 0 : if (proc_mounts_monitor != NULL)
2334 : : {
2335 : : int ret;
2336 : :
2337 : : /* The mnt_monitor_next_change function needs to be used to avoid false-positives. */
2338 : 0 : ret = mnt_monitor_next_change (proc_mounts_monitor, NULL, NULL);
2339 : 0 : if (ret == 0)
2340 : : {
2341 : 0 : has_changed = TRUE;
2342 : 0 : ret = mnt_monitor_event_cleanup (proc_mounts_monitor);
2343 : : }
2344 : :
2345 : 0 : if (ret < 0)
2346 : 0 : g_debug ("mnt_monitor_next_change failed: %s", g_strerror (-ret));
2347 : : }
2348 : 0 : G_UNLOCK (proc_mounts_source);
2349 : : }
2350 : : #endif
2351 : :
2352 : 0 : if (cond & G_IO_ERR)
2353 : 0 : has_changed = TRUE;
2354 : :
2355 : 0 : if (has_changed)
2356 : : {
2357 : 0 : G_LOCK (proc_mounts_source);
2358 : 0 : mount_poller_time = (guint64) g_get_monotonic_time ();
2359 : 0 : G_UNLOCK (proc_mounts_source);
2360 : :
2361 : 0 : g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
2362 : : }
2363 : :
2364 : 0 : return TRUE;
2365 : : }
2366 : :
2367 : : static gboolean
2368 : 0 : mount_change_poller (gpointer user_data)
2369 : : {
2370 : : GList *current_mounts, *new_it, *old_it;
2371 : 0 : gboolean has_changed = FALSE;
2372 : :
2373 : 0 : current_mounts = _g_get_unix_mounts ();
2374 : :
2375 : 0 : for ( new_it = current_mounts, old_it = mount_poller_mounts;
2376 : 0 : new_it != NULL && old_it != NULL;
2377 : 0 : new_it = g_list_next (new_it), old_it = g_list_next (old_it) )
2378 : : {
2379 : 0 : if (g_unix_mount_entry_compare (new_it->data, old_it->data) != 0)
2380 : : {
2381 : 0 : has_changed = TRUE;
2382 : 0 : break;
2383 : : }
2384 : : }
2385 : 0 : if (!(new_it == NULL && old_it == NULL))
2386 : 0 : has_changed = TRUE;
2387 : :
2388 : 0 : g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_entry_free);
2389 : :
2390 : 0 : mount_poller_mounts = current_mounts;
2391 : :
2392 : 0 : if (has_changed)
2393 : : {
2394 : 0 : G_LOCK (proc_mounts_source);
2395 : 0 : mount_poller_time = (guint64) g_get_monotonic_time ();
2396 : 0 : G_UNLOCK (proc_mounts_source);
2397 : :
2398 : 0 : g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
2399 : : }
2400 : :
2401 : 0 : return TRUE;
2402 : : }
2403 : :
2404 : :
2405 : : static void
2406 : 1 : mount_monitor_stop (void)
2407 : : {
2408 : 1 : if (fstab_monitor)
2409 : : {
2410 : 1 : g_file_monitor_cancel (fstab_monitor);
2411 : 1 : g_object_unref (fstab_monitor);
2412 : : }
2413 : :
2414 : 1 : G_LOCK (proc_mounts_source);
2415 : 1 : if (proc_mounts_watch_source != NULL)
2416 : : {
2417 : 1 : g_source_destroy (proc_mounts_watch_source);
2418 : 1 : proc_mounts_watch_source = NULL;
2419 : : }
2420 : :
2421 : : #ifdef HAVE_LIBMOUNT
2422 : 1 : g_clear_pointer (&proc_mounts_monitor, mnt_unref_monitor);
2423 : : #endif
2424 : 1 : G_UNLOCK (proc_mounts_source);
2425 : :
2426 : 1 : if (mtab_monitor)
2427 : : {
2428 : 0 : g_file_monitor_cancel (mtab_monitor);
2429 : 0 : g_object_unref (mtab_monitor);
2430 : : }
2431 : :
2432 : 1 : if (mtab_file_changed_id)
2433 : : {
2434 : 0 : g_source_remove (mtab_file_changed_id);
2435 : 0 : mtab_file_changed_id = 0;
2436 : : }
2437 : :
2438 : 1 : g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_entry_free);
2439 : 1 : }
2440 : :
2441 : : static void
2442 : 1 : mount_monitor_start (void)
2443 : : {
2444 : : GFile *file;
2445 : :
2446 : 1 : if (get_fstab_file () != NULL)
2447 : : {
2448 : 1 : file = g_file_new_for_path (get_fstab_file ());
2449 : 1 : fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
2450 : 1 : g_object_unref (file);
2451 : :
2452 : 1 : g_signal_connect (fstab_monitor, "changed", (GCallback)fstab_file_changed, NULL);
2453 : : }
2454 : :
2455 : 1 : if (get_mtab_monitor_file () != NULL)
2456 : : {
2457 : : const gchar *mtab_path;
2458 : :
2459 : 1 : mtab_path = get_mtab_monitor_file ();
2460 : : /* Monitoring files in /proc/ is special - can't just use GFileMonitor.
2461 : : * See 'man proc' for more details.
2462 : : */
2463 : 1 : if (g_str_has_prefix (mtab_path, "/proc/"))
2464 : : {
2465 : 1 : GIOChannel *proc_mounts_channel = NULL;
2466 : 1 : GError *error = NULL;
2467 : : #ifdef HAVE_LIBMOUNT
2468 : : int ret;
2469 : :
2470 : 1 : G_LOCK (proc_mounts_source);
2471 : :
2472 : 1 : proc_mounts_monitor = mnt_new_monitor ();
2473 : 1 : ret = mnt_monitor_enable_kernel (proc_mounts_monitor, TRUE);
2474 : 1 : if (ret < 0)
2475 : 0 : g_warning ("mnt_monitor_enable_kernel failed: %s", g_strerror (-ret));
2476 : :
2477 : 1 : ret = mnt_monitor_enable_userspace (proc_mounts_monitor, TRUE, NULL);
2478 : 1 : if (ret < 0)
2479 : 0 : g_warning ("mnt_monitor_enable_userspace failed: %s", g_strerror (-ret));
2480 : :
2481 : : #ifdef HAVE_MNT_MONITOR_VEIL_KERNEL
2482 : : ret = mnt_monitor_veil_kernel (proc_mounts_monitor, TRUE);
2483 : : if (ret < 0)
2484 : : g_warning ("mnt_monitor_veil_kernel failed: %s", g_strerror (-ret));
2485 : : #endif
2486 : :
2487 : 1 : ret = mnt_monitor_get_fd (proc_mounts_monitor);
2488 : 1 : if (ret >= 0)
2489 : : {
2490 : 1 : proc_mounts_channel = g_io_channel_unix_new (ret);
2491 : : }
2492 : : else
2493 : : {
2494 : 0 : g_debug ("mnt_monitor_get_fd failed: %s", g_strerror (-ret));
2495 : 0 : g_clear_pointer (&proc_mounts_monitor, mnt_unref_monitor);
2496 : :
2497 : : /* The mnt_monitor_get_fd function failed e.g. inotify limits are
2498 : : * exceeded. Let's try to silently fallback to the old behavior.
2499 : : * See: https://gitlab.gnome.org/GNOME/tracker-miners/-/issues/315
2500 : : */
2501 : : }
2502 : :
2503 : 1 : G_UNLOCK (proc_mounts_source);
2504 : : #endif
2505 : 1 : if (proc_mounts_channel == NULL)
2506 : 0 : proc_mounts_channel = g_io_channel_new_file (mtab_path, "r", &error);
2507 : :
2508 : 1 : if (error != NULL)
2509 : : {
2510 : 0 : g_warning ("Error creating IO channel for %s: %s (%s, %d)", mtab_path,
2511 : : error->message, g_quark_to_string (error->domain), error->code);
2512 : 0 : g_error_free (error);
2513 : : }
2514 : : else
2515 : : {
2516 : 1 : G_LOCK (proc_mounts_source);
2517 : :
2518 : : #ifdef HAVE_LIBMOUNT
2519 : 1 : if (proc_mounts_monitor != NULL)
2520 : 1 : proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_IN);
2521 : : #endif
2522 : 1 : if (proc_mounts_watch_source == NULL)
2523 : 0 : proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_ERR);
2524 : :
2525 : 1 : mount_poller_time = (guint64) g_get_monotonic_time ();
2526 : 1 : g_source_set_callback (proc_mounts_watch_source,
2527 : : (GSourceFunc) proc_mounts_changed,
2528 : : NULL, NULL);
2529 : 1 : g_source_attach (proc_mounts_watch_source,
2530 : : g_main_context_get_thread_default ());
2531 : 1 : g_source_unref (proc_mounts_watch_source);
2532 : 1 : g_io_channel_unref (proc_mounts_channel);
2533 : :
2534 : 1 : G_UNLOCK (proc_mounts_source);
2535 : : }
2536 : : }
2537 : : else
2538 : : {
2539 : 0 : file = g_file_new_for_path (mtab_path);
2540 : 0 : mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
2541 : 0 : g_object_unref (file);
2542 : 0 : g_signal_connect (mtab_monitor, "changed", (GCallback)mtab_file_changed, NULL);
2543 : : }
2544 : : }
2545 : : else
2546 : : {
2547 : 0 : G_LOCK (proc_mounts_source);
2548 : :
2549 : 0 : proc_mounts_watch_source = g_timeout_source_new_seconds (3);
2550 : 0 : mount_poller_mounts = _g_get_unix_mounts ();
2551 : 0 : mount_poller_time = (guint64)g_get_monotonic_time ();
2552 : 0 : g_source_set_callback (proc_mounts_watch_source,
2553 : : mount_change_poller,
2554 : : NULL, NULL);
2555 : 0 : g_source_attach (proc_mounts_watch_source,
2556 : : g_main_context_get_thread_default ());
2557 : 0 : g_source_unref (proc_mounts_watch_source);
2558 : :
2559 : 0 : G_UNLOCK (proc_mounts_source);
2560 : : }
2561 : 1 : }
2562 : :
2563 : : static void
2564 : 1 : g_unix_mount_monitor_finalize (GObject *object)
2565 : : {
2566 : : GUnixMountMonitor *monitor;
2567 : :
2568 : 1 : monitor = G_UNIX_MOUNT_MONITOR (object);
2569 : :
2570 : 1 : g_context_specific_group_remove (&mount_monitor_group, monitor->context, monitor, mount_monitor_stop);
2571 : :
2572 : 1 : G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize (object);
2573 : 1 : }
2574 : :
2575 : : static void
2576 : 3 : g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
2577 : : {
2578 : 3 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
2579 : :
2580 : 3 : gobject_class->finalize = g_unix_mount_monitor_finalize;
2581 : :
2582 : : /**
2583 : : * GUnixMountMonitor::mounts-changed:
2584 : : * @monitor: the object on which the signal is emitted
2585 : : *
2586 : : * Emitted when the unix mounts have changed.
2587 : : */
2588 : 3 : signals[MOUNTS_CHANGED] =
2589 : 3 : g_signal_new (I_("mounts-changed"),
2590 : : G_TYPE_FROM_CLASS (klass),
2591 : : G_SIGNAL_RUN_LAST,
2592 : : 0,
2593 : : NULL, NULL,
2594 : : NULL,
2595 : : G_TYPE_NONE, 0);
2596 : :
2597 : : /**
2598 : : * GUnixMountMonitor::mountpoints-changed:
2599 : : * @monitor: the object on which the signal is emitted
2600 : : *
2601 : : * Emitted when the unix mount points have changed.
2602 : : */
2603 : 3 : signals[MOUNTPOINTS_CHANGED] =
2604 : 3 : g_signal_new (I_("mountpoints-changed"),
2605 : : G_TYPE_FROM_CLASS (klass),
2606 : : G_SIGNAL_RUN_LAST,
2607 : : 0,
2608 : : NULL, NULL,
2609 : : NULL,
2610 : : G_TYPE_NONE, 0);
2611 : 3 : }
2612 : :
2613 : : static void
2614 : 1 : g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
2615 : : {
2616 : 1 : }
2617 : :
2618 : : /**
2619 : : * g_unix_mount_monitor_set_rate_limit:
2620 : : * @mount_monitor: a #GUnixMountMonitor
2621 : : * @limit_msec: a integer with the limit in milliseconds to
2622 : : * poll for changes.
2623 : : *
2624 : : * This function does nothing.
2625 : : *
2626 : : * Before 2.44, this was a partially-effective way of controlling the
2627 : : * rate at which events would be reported under some uncommon
2628 : : * circumstances. Since @mount_monitor is a singleton, it also meant
2629 : : * that calling this function would have side effects for other users of
2630 : : * the monitor.
2631 : : *
2632 : : * Since: 2.18
2633 : : *
2634 : : * Deprecated:2.44:This function does nothing. Don't call it.
2635 : : */
2636 : : void
2637 : 0 : g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
2638 : : gint limit_msec)
2639 : : {
2640 : 0 : }
2641 : :
2642 : : /**
2643 : : * g_unix_mount_monitor_get:
2644 : : *
2645 : : * Gets the #GUnixMountMonitor for the current thread-default main
2646 : : * context.
2647 : : *
2648 : : * The mount monitor can be used to monitor for changes to the list of
2649 : : * mounted filesystems as well as the list of mount points (ie: fstab
2650 : : * entries).
2651 : : *
2652 : : * You must only call g_object_unref() on the return value from under
2653 : : * the same main context as you called this function.
2654 : : *
2655 : : * Returns: (transfer full): the #GUnixMountMonitor.
2656 : : *
2657 : : * Since: 2.44
2658 : : **/
2659 : : GUnixMountMonitor *
2660 : 1 : g_unix_mount_monitor_get (void)
2661 : : {
2662 : 1 : return g_context_specific_group_get (&mount_monitor_group,
2663 : : G_TYPE_UNIX_MOUNT_MONITOR,
2664 : : G_STRUCT_OFFSET(GUnixMountMonitor, context),
2665 : : mount_monitor_start);
2666 : : }
2667 : :
2668 : : /**
2669 : : * g_unix_mount_monitor_new:
2670 : : *
2671 : : * Deprecated alias for g_unix_mount_monitor_get().
2672 : : *
2673 : : * This function was never a true constructor, which is why it was
2674 : : * renamed.
2675 : : *
2676 : : * Returns: a #GUnixMountMonitor.
2677 : : *
2678 : : * Deprecated:2.44:Use g_unix_mount_monitor_get() instead.
2679 : : */
2680 : : GUnixMountMonitor *
2681 : 0 : g_unix_mount_monitor_new (void)
2682 : : {
2683 : 0 : return g_unix_mount_monitor_get ();
2684 : : }
2685 : :
2686 : : /* GUnixMount {{{1 */
2687 : : /**
2688 : : * g_unix_mount_free:
2689 : : * @mount_entry: a #GUnixMountEntry.
2690 : : *
2691 : : * Frees a unix mount.
2692 : : *
2693 : : * Deprecated: 2.84: Use g_unix_mount_entry_free() instead.
2694 : : */
2695 : : void
2696 : 3 : g_unix_mount_free (GUnixMountEntry *mount_entry)
2697 : : {
2698 : 3 : g_unix_mount_entry_free (mount_entry);
2699 : 3 : }
2700 : :
2701 : : /**
2702 : : * g_unix_mount_entry_free:
2703 : : * @mount_entry: a #GUnixMountEntry.
2704 : : *
2705 : : * Frees a unix mount.
2706 : : *
2707 : : * Since: 2.84
2708 : : */
2709 : : void
2710 : 1797 : g_unix_mount_entry_free (GUnixMountEntry *mount_entry)
2711 : : {
2712 : 1797 : g_return_if_fail (mount_entry != NULL);
2713 : :
2714 : 1797 : g_free (mount_entry->mount_path);
2715 : 1797 : g_free (mount_entry->device_path);
2716 : 1797 : g_free (mount_entry->root_path);
2717 : 1797 : g_free (mount_entry->filesystem_type);
2718 : 1797 : g_free (mount_entry->options);
2719 : 1797 : g_free (mount_entry);
2720 : : }
2721 : :
2722 : : /**
2723 : : * g_unix_mount_copy:
2724 : : * @mount_entry: a #GUnixMountEntry.
2725 : : *
2726 : : * Makes a copy of @mount_entry.
2727 : : *
2728 : : * Returns: (transfer full): a new #GUnixMountEntry
2729 : : *
2730 : : * Since: 2.54
2731 : : * Deprecated: 2.84: Use g_unix_mount_entry_copy() instead.
2732 : : */
2733 : : GUnixMountEntry *
2734 : 0 : g_unix_mount_copy (GUnixMountEntry *mount_entry)
2735 : : {
2736 : 0 : return g_unix_mount_entry_copy (mount_entry);
2737 : : }
2738 : :
2739 : : /**
2740 : : * g_unix_mount_entry_copy:
2741 : : * @mount_entry: a #GUnixMountEntry.
2742 : : *
2743 : : * Makes a copy of @mount_entry.
2744 : : *
2745 : : * Returns: (transfer full): a new #GUnixMountEntry
2746 : : *
2747 : : * Since: 2.84
2748 : : */
2749 : : GUnixMountEntry *
2750 : 0 : g_unix_mount_entry_copy (GUnixMountEntry *mount_entry)
2751 : : {
2752 : : GUnixMountEntry *copy;
2753 : :
2754 : 0 : g_return_val_if_fail (mount_entry != NULL, NULL);
2755 : :
2756 : 0 : copy = g_new0 (GUnixMountEntry, 1);
2757 : 0 : copy->mount_path = g_strdup (mount_entry->mount_path);
2758 : 0 : copy->device_path = g_strdup (mount_entry->device_path);
2759 : 0 : copy->root_path = g_strdup (mount_entry->root_path);
2760 : 0 : copy->filesystem_type = g_strdup (mount_entry->filesystem_type);
2761 : 0 : copy->options = g_strdup (mount_entry->options);
2762 : 0 : copy->is_read_only = mount_entry->is_read_only;
2763 : 0 : copy->is_system_internal = mount_entry->is_system_internal;
2764 : :
2765 : 0 : return copy;
2766 : : }
2767 : :
2768 : : /**
2769 : : * g_unix_mount_point_free:
2770 : : * @mount_point: unix mount point to free.
2771 : : *
2772 : : * Frees a unix mount point.
2773 : : */
2774 : : void
2775 : 4 : g_unix_mount_point_free (GUnixMountPoint *mount_point)
2776 : : {
2777 : 4 : g_return_if_fail (mount_point != NULL);
2778 : :
2779 : 4 : g_free (mount_point->mount_path);
2780 : 4 : g_free (mount_point->device_path);
2781 : 4 : g_free (mount_point->filesystem_type);
2782 : 4 : g_free (mount_point->options);
2783 : 4 : g_free (mount_point);
2784 : : }
2785 : :
2786 : : /**
2787 : : * g_unix_mount_point_copy:
2788 : : * @mount_point: a #GUnixMountPoint.
2789 : : *
2790 : : * Makes a copy of @mount_point.
2791 : : *
2792 : : * Returns: (transfer full): a new #GUnixMountPoint
2793 : : *
2794 : : * Since: 2.54
2795 : : */
2796 : : GUnixMountPoint*
2797 : 0 : g_unix_mount_point_copy (GUnixMountPoint *mount_point)
2798 : : {
2799 : : GUnixMountPoint *copy;
2800 : :
2801 : 0 : g_return_val_if_fail (mount_point != NULL, NULL);
2802 : :
2803 : 0 : copy = g_new0 (GUnixMountPoint, 1);
2804 : 0 : copy->mount_path = g_strdup (mount_point->mount_path);
2805 : 0 : copy->device_path = g_strdup (mount_point->device_path);
2806 : 0 : copy->filesystem_type = g_strdup (mount_point->filesystem_type);
2807 : 0 : copy->options = g_strdup (mount_point->options);
2808 : 0 : copy->is_read_only = mount_point->is_read_only;
2809 : 0 : copy->is_user_mountable = mount_point->is_user_mountable;
2810 : 0 : copy->is_loopback = mount_point->is_loopback;
2811 : :
2812 : 0 : return copy;
2813 : : }
2814 : :
2815 : : /**
2816 : : * g_unix_mount_compare:
2817 : : * @mount1: first #GUnixMountEntry to compare.
2818 : : * @mount2: second #GUnixMountEntry to compare.
2819 : : *
2820 : : * Compares two unix mounts.
2821 : : *
2822 : : * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
2823 : : * or less than @mount2, respectively.
2824 : : *
2825 : : * Deprecated: 2.84: Use g_unix_mount_entry_compare() instead.
2826 : : */
2827 : : gint
2828 : 0 : g_unix_mount_compare (GUnixMountEntry *mount1,
2829 : : GUnixMountEntry *mount2)
2830 : : {
2831 : 0 : return g_unix_mount_entry_compare (mount1, mount2);
2832 : : }
2833 : :
2834 : : /**
2835 : : * g_unix_mount_entry_compare:
2836 : : * @mount1: first #GUnixMountEntry to compare.
2837 : : * @mount2: second #GUnixMountEntry to compare.
2838 : : *
2839 : : * Compares two unix mounts.
2840 : : *
2841 : : * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
2842 : : * or less than @mount2, respectively.
2843 : : *
2844 : : * Since: 2.84
2845 : : */
2846 : : gint
2847 : 150 : g_unix_mount_entry_compare (GUnixMountEntry *mount1,
2848 : : GUnixMountEntry *mount2)
2849 : : {
2850 : : int res;
2851 : :
2852 : 150 : g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
2853 : :
2854 : 150 : res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
2855 : 150 : if (res != 0)
2856 : 148 : return res;
2857 : :
2858 : 2 : res = g_strcmp0 (mount1->device_path, mount2->device_path);
2859 : 2 : if (res != 0)
2860 : 0 : return res;
2861 : :
2862 : 2 : res = g_strcmp0 (mount1->root_path, mount2->root_path);
2863 : 2 : if (res != 0)
2864 : 0 : return res;
2865 : :
2866 : 2 : res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
2867 : 2 : if (res != 0)
2868 : 0 : return res;
2869 : :
2870 : 2 : res = g_strcmp0 (mount1->options, mount2->options);
2871 : 2 : if (res != 0)
2872 : 0 : return res;
2873 : :
2874 : 2 : res = mount1->is_read_only - mount2->is_read_only;
2875 : 2 : if (res != 0)
2876 : 0 : return res;
2877 : :
2878 : 2 : return 0;
2879 : : }
2880 : :
2881 : : /**
2882 : : * g_unix_mount_get_mount_path:
2883 : : * @mount_entry: input #GUnixMountEntry to get the mount path for.
2884 : : *
2885 : : * Gets the mount path for a unix mount.
2886 : : *
2887 : : * Returns: (type filename): the mount path for @mount_entry.
2888 : : *
2889 : : * Deprecated: 2.84: Use g_unix_mount_entry_get_mount_path() instead.
2890 : : */
2891 : : const gchar *
2892 : 3 : g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry)
2893 : : {
2894 : 3 : return g_unix_mount_entry_get_mount_path (mount_entry);
2895 : : }
2896 : :
2897 : : /**
2898 : : * g_unix_mount_entry_get_mount_path:
2899 : : * @mount_entry: input #GUnixMountEntry to get the mount path for.
2900 : : *
2901 : : * Gets the mount path for a unix mount.
2902 : : *
2903 : : * Returns: (type filename): the mount path for @mount_entry.
2904 : : *
2905 : : * Since: 2.84
2906 : : */
2907 : : const gchar *
2908 : 45 : g_unix_mount_entry_get_mount_path (GUnixMountEntry *mount_entry)
2909 : : {
2910 : 45 : g_return_val_if_fail (mount_entry != NULL, NULL);
2911 : :
2912 : 45 : return mount_entry->mount_path;
2913 : : }
2914 : :
2915 : : /**
2916 : : * g_unix_mount_get_device_path:
2917 : : * @mount_entry: a #GUnixMount.
2918 : : *
2919 : : * Gets the device path for a unix mount.
2920 : : *
2921 : : * Returns: (type filename): a string containing the device path.
2922 : : *
2923 : : * Deprecated: 2.84: Use g_unix_mount_entry_get_device_path() instead.
2924 : : */
2925 : : const gchar *
2926 : 3 : g_unix_mount_get_device_path (GUnixMountEntry *mount_entry)
2927 : : {
2928 : 3 : return g_unix_mount_entry_get_device_path (mount_entry);
2929 : : }
2930 : :
2931 : : /**
2932 : : * g_unix_mount_entry_get_device_path:
2933 : : * @mount_entry: a #GUnixMount.
2934 : : *
2935 : : * Gets the device path for a unix mount.
2936 : : *
2937 : : * Returns: (type filename): a string containing the device path.
2938 : : *
2939 : : * Since: 2.84
2940 : : */
2941 : : const gchar *
2942 : 4 : g_unix_mount_entry_get_device_path (GUnixMountEntry *mount_entry)
2943 : : {
2944 : 4 : g_return_val_if_fail (mount_entry != NULL, NULL);
2945 : :
2946 : 4 : return mount_entry->device_path;
2947 : : }
2948 : :
2949 : : /**
2950 : : * g_unix_mount_get_root_path:
2951 : : * @mount_entry: a #GUnixMountEntry.
2952 : : *
2953 : : * Gets the root of the mount within the filesystem. This is useful e.g. for
2954 : : * mounts created by bind operation, or btrfs subvolumes.
2955 : : *
2956 : : * For example, the root path is equal to "/" for mount created by
2957 : : * "mount /dev/sda1 /mnt/foo" and "/bar" for
2958 : : * "mount --bind /mnt/foo/bar /mnt/bar".
2959 : : *
2960 : : * Returns: (nullable): a string containing the root, or %NULL if not supported.
2961 : : *
2962 : : * Since: 2.60
2963 : : * Deprecated: 2.84: Use g_unix_mount_entry_get_root_path() instead.
2964 : : */
2965 : : const gchar *
2966 : 3 : g_unix_mount_get_root_path (GUnixMountEntry *mount_entry)
2967 : : {
2968 : 3 : return g_unix_mount_entry_get_root_path (mount_entry);
2969 : : }
2970 : :
2971 : : /**
2972 : : * g_unix_mount_entry_get_root_path:
2973 : : * @mount_entry: a #GUnixMountEntry.
2974 : : *
2975 : : * Gets the root of the mount within the filesystem. This is useful e.g. for
2976 : : * mounts created by bind operation, or btrfs subvolumes.
2977 : : *
2978 : : * For example, the root path is equal to "/" for mount created by
2979 : : * "mount /dev/sda1 /mnt/foo" and "/bar" for
2980 : : * "mount --bind /mnt/foo/bar /mnt/bar".
2981 : : *
2982 : : * Returns: (nullable): a string containing the root, or %NULL if not supported.
2983 : : *
2984 : : * Since: 2.84
2985 : : */
2986 : : const gchar *
2987 : 4 : g_unix_mount_entry_get_root_path (GUnixMountEntry *mount_entry)
2988 : : {
2989 : 4 : g_return_val_if_fail (mount_entry != NULL, NULL);
2990 : :
2991 : 4 : return mount_entry->root_path;
2992 : : }
2993 : :
2994 : : /**
2995 : : * g_unix_mount_get_fs_type:
2996 : : * @mount_entry: a #GUnixMount.
2997 : : *
2998 : : * Gets the filesystem type for the unix mount.
2999 : : *
3000 : : * Returns: a string containing the file system type.
3001 : : *
3002 : : * Deprecated: 2.84: Use g_unix_mount_entry_get_fs_type() instead.
3003 : : */
3004 : : const gchar *
3005 : 3 : g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry)
3006 : : {
3007 : 3 : return g_unix_mount_entry_get_fs_type (mount_entry);
3008 : : }
3009 : :
3010 : : /**
3011 : : * g_unix_mount_entry_get_fs_type:
3012 : : * @mount_entry: a #GUnixMount.
3013 : : *
3014 : : * Gets the filesystem type for the unix mount.
3015 : : *
3016 : : * Returns: a string containing the file system type.
3017 : : *
3018 : : * Since: 2.84
3019 : : */
3020 : : const gchar *
3021 : 4 : g_unix_mount_entry_get_fs_type (GUnixMountEntry *mount_entry)
3022 : : {
3023 : 4 : g_return_val_if_fail (mount_entry != NULL, NULL);
3024 : :
3025 : 4 : return mount_entry->filesystem_type;
3026 : : }
3027 : :
3028 : : /**
3029 : : * g_unix_mount_get_options:
3030 : : * @mount_entry: a #GUnixMountEntry.
3031 : : *
3032 : : * Gets a comma-separated list of mount options for the unix mount. For example,
3033 : : * `rw,relatime,seclabel,data=ordered`.
3034 : : *
3035 : : * This is similar to g_unix_mount_point_get_options(), but it takes
3036 : : * a #GUnixMountEntry as an argument.
3037 : : *
3038 : : * Returns: (nullable): a string containing the options, or %NULL if not
3039 : : * available.
3040 : : *
3041 : : * Since: 2.58
3042 : : * Deprecated: 2.84: Use g_unix_mount_entry_get_options() instead.
3043 : : */
3044 : : const gchar *
3045 : 3 : g_unix_mount_get_options (GUnixMountEntry *mount_entry)
3046 : : {
3047 : 3 : return g_unix_mount_entry_get_options (mount_entry);
3048 : : }
3049 : :
3050 : : /**
3051 : : * g_unix_mount_entry_get_options:
3052 : : * @mount_entry: a #GUnixMountEntry.
3053 : : *
3054 : : * Gets a comma-separated list of mount options for the unix mount. For example,
3055 : : * `rw,relatime,seclabel,data=ordered`.
3056 : : *
3057 : : * This is similar to g_unix_mount_point_get_options(), but it takes
3058 : : * a #GUnixMountEntry as an argument.
3059 : : *
3060 : : * Returns: (nullable): a string containing the options, or %NULL if not
3061 : : * available.
3062 : : *
3063 : : * Since: 2.84
3064 : : */
3065 : : const gchar *
3066 : 42 : g_unix_mount_entry_get_options (GUnixMountEntry *mount_entry)
3067 : : {
3068 : 42 : g_return_val_if_fail (mount_entry != NULL, NULL);
3069 : :
3070 : 42 : return mount_entry->options;
3071 : : }
3072 : :
3073 : : /**
3074 : : * g_unix_mount_is_readonly:
3075 : : * @mount_entry: a #GUnixMount.
3076 : : *
3077 : : * Checks if a unix mount is mounted read only.
3078 : : *
3079 : : * Returns: %TRUE if @mount_entry is read only.
3080 : : *
3081 : : * Deprecated: 2.84: Use g_unix_mount_entry_is_readonly() instead.
3082 : : */
3083 : : gboolean
3084 : 0 : g_unix_mount_is_readonly (GUnixMountEntry *mount_entry)
3085 : : {
3086 : 0 : return g_unix_mount_entry_is_readonly (mount_entry);
3087 : : }
3088 : :
3089 : : /**
3090 : : * g_unix_mount_entry_is_readonly:
3091 : : * @mount_entry: a #GUnixMount.
3092 : : *
3093 : : * Checks if a unix mount is mounted read only.
3094 : : *
3095 : : * Returns: %TRUE if @mount_entry is read only.
3096 : : *
3097 : : * Since: 2.84
3098 : : */
3099 : : gboolean
3100 : 0 : g_unix_mount_entry_is_readonly (GUnixMountEntry *mount_entry)
3101 : : {
3102 : 0 : g_return_val_if_fail (mount_entry != NULL, FALSE);
3103 : :
3104 : 0 : return mount_entry->is_read_only;
3105 : : }
3106 : :
3107 : : /**
3108 : : * g_unix_mount_is_system_internal:
3109 : : * @mount_entry: a #GUnixMount.
3110 : : *
3111 : : * Checks if a Unix mount is a system mount. This is the Boolean OR of
3112 : : * g_unix_is_system_fs_type(), g_unix_is_system_device_path() and
3113 : : * g_unix_is_mount_path_system_internal() on @mount_entry’s properties.
3114 : : *
3115 : : * The definition of what a ‘system’ mount entry is may change over time as new
3116 : : * file system types and device paths are ignored.
3117 : : *
3118 : : * Returns: %TRUE if the unix mount is for a system path.
3119 : : *
3120 : : * Deprecated: 2.84: Use g_unix_mount_entry_is_system_internal() instead.
3121 : : */
3122 : : gboolean
3123 : 0 : g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry)
3124 : : {
3125 : 0 : return g_unix_mount_entry_is_system_internal (mount_entry);
3126 : : }
3127 : :
3128 : : /**
3129 : : * g_unix_mount_entry_is_system_internal:
3130 : : * @mount_entry: a #GUnixMount.
3131 : : *
3132 : : * Checks if a Unix mount is a system mount. This is the Boolean OR of
3133 : : * g_unix_is_system_fs_type(), g_unix_is_system_device_path() and
3134 : : * g_unix_is_mount_path_system_internal() on @mount_entry’s properties.
3135 : : *
3136 : : * The definition of what a ‘system’ mount entry is may change over time as new
3137 : : * file system types and device paths are ignored.
3138 : : *
3139 : : * Returns: %TRUE if the unix mount is for a system path.
3140 : : *
3141 : : * Since: 2.84
3142 : : */
3143 : : gboolean
3144 : 77 : g_unix_mount_entry_is_system_internal (GUnixMountEntry *mount_entry)
3145 : : {
3146 : 77 : g_return_val_if_fail (mount_entry != NULL, FALSE);
3147 : :
3148 : 77 : return mount_entry->is_system_internal;
3149 : : }
3150 : :
3151 : : /* GUnixMountPoint {{{1 */
3152 : : /**
3153 : : * g_unix_mount_point_compare:
3154 : : * @mount1: a #GUnixMount.
3155 : : * @mount2: a #GUnixMount.
3156 : : *
3157 : : * Compares two unix mount points.
3158 : : *
3159 : : * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
3160 : : * or less than @mount2, respectively.
3161 : : */
3162 : : gint
3163 : 0 : g_unix_mount_point_compare (GUnixMountPoint *mount1,
3164 : : GUnixMountPoint *mount2)
3165 : : {
3166 : : int res;
3167 : :
3168 : 0 : g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
3169 : :
3170 : 0 : res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
3171 : 0 : if (res != 0)
3172 : 0 : return res;
3173 : :
3174 : 0 : res = g_strcmp0 (mount1->device_path, mount2->device_path);
3175 : 0 : if (res != 0)
3176 : 0 : return res;
3177 : :
3178 : 0 : res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
3179 : 0 : if (res != 0)
3180 : 0 : return res;
3181 : :
3182 : 0 : res = g_strcmp0 (mount1->options, mount2->options);
3183 : 0 : if (res != 0)
3184 : 0 : return res;
3185 : :
3186 : 0 : res = mount1->is_read_only - mount2->is_read_only;
3187 : 0 : if (res != 0)
3188 : 0 : return res;
3189 : :
3190 : 0 : res = mount1->is_user_mountable - mount2->is_user_mountable;
3191 : 0 : if (res != 0)
3192 : 0 : return res;
3193 : :
3194 : 0 : res = mount1->is_loopback - mount2->is_loopback;
3195 : 0 : if (res != 0)
3196 : 0 : return res;
3197 : :
3198 : 0 : return 0;
3199 : : }
3200 : :
3201 : : /**
3202 : : * g_unix_mount_point_get_mount_path:
3203 : : * @mount_point: a #GUnixMountPoint.
3204 : : *
3205 : : * Gets the mount path for a unix mount point.
3206 : : *
3207 : : * Returns: (type filename): a string containing the mount path.
3208 : : */
3209 : : const gchar *
3210 : 0 : g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point)
3211 : : {
3212 : 0 : g_return_val_if_fail (mount_point != NULL, NULL);
3213 : :
3214 : 0 : return mount_point->mount_path;
3215 : : }
3216 : :
3217 : : /**
3218 : : * g_unix_mount_point_get_device_path:
3219 : : * @mount_point: a #GUnixMountPoint.
3220 : : *
3221 : : * Gets the device path for a unix mount point.
3222 : : *
3223 : : * Returns: (type filename): a string containing the device path.
3224 : : */
3225 : : const gchar *
3226 : 4 : g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point)
3227 : : {
3228 : 4 : g_return_val_if_fail (mount_point != NULL, NULL);
3229 : :
3230 : 4 : return mount_point->device_path;
3231 : : }
3232 : :
3233 : : /**
3234 : : * g_unix_mount_point_get_fs_type:
3235 : : * @mount_point: a #GUnixMountPoint.
3236 : : *
3237 : : * Gets the file system type for the mount point.
3238 : : *
3239 : : * Returns: a string containing the file system type.
3240 : : */
3241 : : const gchar *
3242 : 4 : g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point)
3243 : : {
3244 : 4 : g_return_val_if_fail (mount_point != NULL, NULL);
3245 : :
3246 : 4 : return mount_point->filesystem_type;
3247 : : }
3248 : :
3249 : : /**
3250 : : * g_unix_mount_point_get_options:
3251 : : * @mount_point: a #GUnixMountPoint.
3252 : : *
3253 : : * Gets the options for the mount point.
3254 : : *
3255 : : * Returns: (nullable): a string containing the options.
3256 : : *
3257 : : * Since: 2.32
3258 : : */
3259 : : const gchar *
3260 : 4 : g_unix_mount_point_get_options (GUnixMountPoint *mount_point)
3261 : : {
3262 : 4 : g_return_val_if_fail (mount_point != NULL, NULL);
3263 : :
3264 : 4 : return mount_point->options;
3265 : : }
3266 : :
3267 : : /**
3268 : : * g_unix_mount_point_is_readonly:
3269 : : * @mount_point: a #GUnixMountPoint.
3270 : : *
3271 : : * Checks if a unix mount point is read only.
3272 : : *
3273 : : * Returns: %TRUE if a mount point is read only.
3274 : : */
3275 : : gboolean
3276 : 4 : g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point)
3277 : : {
3278 : 4 : g_return_val_if_fail (mount_point != NULL, FALSE);
3279 : :
3280 : 4 : return mount_point->is_read_only;
3281 : : }
3282 : :
3283 : : /**
3284 : : * g_unix_mount_point_is_user_mountable:
3285 : : * @mount_point: a #GUnixMountPoint.
3286 : : *
3287 : : * Checks if a unix mount point is mountable by the user.
3288 : : *
3289 : : * Returns: %TRUE if the mount point is user mountable.
3290 : : */
3291 : : gboolean
3292 : 4 : g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point)
3293 : : {
3294 : 4 : g_return_val_if_fail (mount_point != NULL, FALSE);
3295 : :
3296 : 4 : return mount_point->is_user_mountable;
3297 : : }
3298 : :
3299 : : /**
3300 : : * g_unix_mount_point_is_loopback:
3301 : : * @mount_point: a #GUnixMountPoint.
3302 : : *
3303 : : * Checks if a unix mount point is a loopback device.
3304 : : *
3305 : : * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise.
3306 : : */
3307 : : gboolean
3308 : 4 : g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point)
3309 : : {
3310 : 4 : g_return_val_if_fail (mount_point != NULL, FALSE);
3311 : :
3312 : 4 : return mount_point->is_loopback;
3313 : : }
3314 : :
3315 : : static GUnixMountType
3316 : 12 : guess_mount_type (const char *mount_path,
3317 : : const char *device_path,
3318 : : const char *filesystem_type)
3319 : : {
3320 : : GUnixMountType type;
3321 : : char *basename;
3322 : :
3323 : 12 : type = G_UNIX_MOUNT_TYPE_UNKNOWN;
3324 : :
3325 : 12 : if ((strcmp (filesystem_type, "udf") == 0) ||
3326 : 12 : (strcmp (filesystem_type, "iso9660") == 0) ||
3327 : 12 : (strcmp (filesystem_type, "cd9660") == 0))
3328 : 0 : type = G_UNIX_MOUNT_TYPE_CDROM;
3329 : 12 : else if ((strcmp (filesystem_type, "nfs") == 0) ||
3330 : 12 : (strcmp (filesystem_type, "nfs4") == 0))
3331 : 0 : type = G_UNIX_MOUNT_TYPE_NFS;
3332 : 12 : else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") ||
3333 : 12 : g_str_has_prefix (device_path, "/dev/fd") ||
3334 : 12 : g_str_has_prefix (device_path, "/dev/floppy"))
3335 : 0 : type = G_UNIX_MOUNT_TYPE_FLOPPY;
3336 : 12 : else if (g_str_has_prefix (device_path, "/dev/cdrom") ||
3337 : 12 : g_str_has_prefix (device_path, "/dev/acd") ||
3338 : 12 : g_str_has_prefix (device_path, "/dev/cd"))
3339 : 0 : type = G_UNIX_MOUNT_TYPE_CDROM;
3340 : 12 : else if (g_str_has_prefix (device_path, "/vol/"))
3341 : : {
3342 : 0 : const char *name = mount_path + strlen ("/");
3343 : :
3344 : 0 : if (g_str_has_prefix (name, "cdrom"))
3345 : 0 : type = G_UNIX_MOUNT_TYPE_CDROM;
3346 : 0 : else if (g_str_has_prefix (name, "floppy") ||
3347 : 0 : g_str_has_prefix (device_path, "/vol/dev/diskette/"))
3348 : 0 : type = G_UNIX_MOUNT_TYPE_FLOPPY;
3349 : 0 : else if (g_str_has_prefix (name, "rmdisk"))
3350 : 0 : type = G_UNIX_MOUNT_TYPE_ZIP;
3351 : 0 : else if (g_str_has_prefix (name, "jaz"))
3352 : 0 : type = G_UNIX_MOUNT_TYPE_JAZ;
3353 : 0 : else if (g_str_has_prefix (name, "memstick"))
3354 : 0 : type = G_UNIX_MOUNT_TYPE_MEMSTICK;
3355 : : }
3356 : : else
3357 : : {
3358 : 12 : basename = g_path_get_basename (mount_path);
3359 : :
3360 : 12 : if (g_str_has_prefix (basename, "cdr") ||
3361 : 12 : g_str_has_prefix (basename, "cdwriter") ||
3362 : 12 : g_str_has_prefix (basename, "burn") ||
3363 : 12 : g_str_has_prefix (basename, "dvdr"))
3364 : 0 : type = G_UNIX_MOUNT_TYPE_CDROM;
3365 : 12 : else if (g_str_has_prefix (basename, "floppy"))
3366 : 0 : type = G_UNIX_MOUNT_TYPE_FLOPPY;
3367 : 12 : else if (g_str_has_prefix (basename, "zip"))
3368 : 0 : type = G_UNIX_MOUNT_TYPE_ZIP;
3369 : 12 : else if (g_str_has_prefix (basename, "jaz"))
3370 : 0 : type = G_UNIX_MOUNT_TYPE_JAZ;
3371 : 12 : else if (g_str_has_prefix (basename, "camera"))
3372 : 0 : type = G_UNIX_MOUNT_TYPE_CAMERA;
3373 : 12 : else if (g_str_has_prefix (basename, "memstick") ||
3374 : 12 : g_str_has_prefix (basename, "memory_stick") ||
3375 : 12 : g_str_has_prefix (basename, "ram"))
3376 : 0 : type = G_UNIX_MOUNT_TYPE_MEMSTICK;
3377 : 12 : else if (g_str_has_prefix (basename, "compact_flash"))
3378 : 0 : type = G_UNIX_MOUNT_TYPE_CF;
3379 : 12 : else if (g_str_has_prefix (basename, "smart_media"))
3380 : 0 : type = G_UNIX_MOUNT_TYPE_SM;
3381 : 12 : else if (g_str_has_prefix (basename, "sd_mmc"))
3382 : 0 : type = G_UNIX_MOUNT_TYPE_SDMMC;
3383 : 12 : else if (g_str_has_prefix (basename, "ipod"))
3384 : 0 : type = G_UNIX_MOUNT_TYPE_IPOD;
3385 : :
3386 : 12 : g_free (basename);
3387 : : }
3388 : :
3389 : 12 : if (type == G_UNIX_MOUNT_TYPE_UNKNOWN)
3390 : 12 : type = G_UNIX_MOUNT_TYPE_HD;
3391 : :
3392 : 12 : return type;
3393 : : }
3394 : :
3395 : : /**
3396 : : * g_unix_mount_entry_guess_type:
3397 : : * @mount_entry: a #GUnixMount.
3398 : : *
3399 : : * Guesses the type of a unix mount. If the mount type cannot be
3400 : : * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
3401 : : *
3402 : : * Returns: a #GUnixMountType.
3403 : : */
3404 : : static GUnixMountType
3405 : 0 : g_unix_mount_entry_guess_type (GUnixMountEntry *mount_entry)
3406 : : {
3407 : 0 : g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
3408 : 0 : g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
3409 : 0 : g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
3410 : 0 : g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
3411 : :
3412 : 0 : return guess_mount_type (mount_entry->mount_path,
3413 : 0 : mount_entry->device_path,
3414 : 0 : mount_entry->filesystem_type);
3415 : : }
3416 : :
3417 : : /**
3418 : : * g_unix_mount_point_guess_type:
3419 : : * @mount_point: a #GUnixMountPoint.
3420 : : *
3421 : : * Guesses the type of a unix mount point.
3422 : : * If the mount type cannot be determined,
3423 : : * returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
3424 : : *
3425 : : * Returns: a #GUnixMountType.
3426 : : */
3427 : : static GUnixMountType
3428 : 12 : g_unix_mount_point_guess_type (GUnixMountPoint *mount_point)
3429 : : {
3430 : 12 : g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
3431 : 12 : g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
3432 : 12 : g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
3433 : 12 : g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
3434 : :
3435 : 12 : return guess_mount_type (mount_point->mount_path,
3436 : 12 : mount_point->device_path,
3437 : 12 : mount_point->filesystem_type);
3438 : : }
3439 : :
3440 : : static const char *
3441 : 8 : type_to_icon (GUnixMountType type, gboolean is_mount_point, gboolean use_symbolic)
3442 : : {
3443 : : const char *icon_name;
3444 : :
3445 : 8 : switch (type)
3446 : : {
3447 : 8 : case G_UNIX_MOUNT_TYPE_HD:
3448 : 8 : if (is_mount_point)
3449 : 8 : icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
3450 : : else
3451 : 0 : icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
3452 : 8 : break;
3453 : 0 : case G_UNIX_MOUNT_TYPE_FLOPPY:
3454 : : case G_UNIX_MOUNT_TYPE_ZIP:
3455 : : case G_UNIX_MOUNT_TYPE_JAZ:
3456 : 0 : if (is_mount_point)
3457 : 0 : icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
3458 : : else
3459 : 0 : icon_name = use_symbolic ? "media-removable-symbolic" : "media-floppy";
3460 : 0 : break;
3461 : 0 : case G_UNIX_MOUNT_TYPE_CDROM:
3462 : 0 : if (is_mount_point)
3463 : 0 : icon_name = use_symbolic ? "drive-optical-symbolic" : "drive-optical";
3464 : : else
3465 : 0 : icon_name = use_symbolic ? "media-optical-symbolic" : "media-optical";
3466 : 0 : break;
3467 : 0 : case G_UNIX_MOUNT_TYPE_NFS:
3468 : 0 : icon_name = use_symbolic ? "folder-remote-symbolic" : "folder-remote";
3469 : 0 : break;
3470 : 0 : case G_UNIX_MOUNT_TYPE_MEMSTICK:
3471 : 0 : if (is_mount_point)
3472 : 0 : icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
3473 : : else
3474 : 0 : icon_name = use_symbolic ? "media-removable-symbolic" : "media-flash";
3475 : 0 : break;
3476 : 0 : case G_UNIX_MOUNT_TYPE_CAMERA:
3477 : 0 : if (is_mount_point)
3478 : 0 : icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
3479 : : else
3480 : 0 : icon_name = use_symbolic ? "camera-photo-symbolic" : "camera-photo";
3481 : 0 : break;
3482 : 0 : case G_UNIX_MOUNT_TYPE_IPOD:
3483 : 0 : if (is_mount_point)
3484 : 0 : icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
3485 : : else
3486 : 0 : icon_name = use_symbolic ? "multimedia-player-symbolic" : "multimedia-player";
3487 : 0 : break;
3488 : 0 : case G_UNIX_MOUNT_TYPE_UNKNOWN:
3489 : : default:
3490 : 0 : if (is_mount_point)
3491 : 0 : icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
3492 : : else
3493 : 0 : icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
3494 : 0 : break;
3495 : : }
3496 : :
3497 : 8 : return icon_name;
3498 : : }
3499 : :
3500 : : /**
3501 : : * g_unix_mount_guess_name:
3502 : : * @mount_entry: a #GUnixMountEntry
3503 : : *
3504 : : * Guesses the name of a Unix mount.
3505 : : * The result is a translated string.
3506 : : *
3507 : : * Returns: A newly allocated string that must
3508 : : * be freed with g_free()
3509 : : *
3510 : : * Deprecated: 2.84: Use g_unix_mount_entry_guess_name() instead.
3511 : : */
3512 : : gchar *
3513 : 0 : g_unix_mount_guess_name (GUnixMountEntry *mount_entry)
3514 : : {
3515 : 0 : return g_unix_mount_entry_guess_name (mount_entry);
3516 : : }
3517 : :
3518 : : /**
3519 : : * g_unix_mount_entry_guess_name:
3520 : : * @mount_entry: a #GUnixMountEntry
3521 : : *
3522 : : * Guesses the name of a Unix mount.
3523 : : * The result is a translated string.
3524 : : *
3525 : : * Returns: A newly allocated string that must
3526 : : * be freed with g_free()
3527 : : *
3528 : : * Since: 2.84
3529 : : */
3530 : : gchar *
3531 : 0 : g_unix_mount_entry_guess_name (GUnixMountEntry *mount_entry)
3532 : : {
3533 : : char *name;
3534 : :
3535 : 0 : if (strcmp (mount_entry->mount_path, "/") == 0)
3536 : 0 : name = g_strdup (_("Filesystem root"));
3537 : : else
3538 : 0 : name = g_filename_display_basename (mount_entry->mount_path);
3539 : :
3540 : 0 : return name;
3541 : : }
3542 : :
3543 : : /**
3544 : : * g_unix_mount_guess_icon:
3545 : : * @mount_entry: a #GUnixMountEntry
3546 : : *
3547 : : * Guesses the icon of a Unix mount.
3548 : : *
3549 : : * Returns: (transfer full): a #GIcon
3550 : : *
3551 : : * Deprecated: 2.84: Use g_unix_mount_entry_guess_icon() instead.
3552 : : */
3553 : : GIcon *
3554 : 0 : g_unix_mount_guess_icon (GUnixMountEntry *mount_entry)
3555 : : {
3556 : 0 : return g_unix_mount_entry_guess_icon (mount_entry);
3557 : : }
3558 : :
3559 : : /**
3560 : : * g_unix_mount_entry_guess_icon:
3561 : : * @mount_entry: a #GUnixMountEntry
3562 : : *
3563 : : * Guesses the icon of a Unix mount.
3564 : : *
3565 : : * Returns: (transfer full): a #GIcon
3566 : : *
3567 : : * Since: 2.84
3568 : : */
3569 : : GIcon *
3570 : 0 : g_unix_mount_entry_guess_icon (GUnixMountEntry *mount_entry)
3571 : : {
3572 : 0 : return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_entry_guess_type (mount_entry), FALSE, FALSE));
3573 : : }
3574 : :
3575 : : /**
3576 : : * g_unix_mount_guess_symbolic_icon:
3577 : : * @mount_entry: a #GUnixMountEntry
3578 : : *
3579 : : * Guesses the symbolic icon of a Unix mount.
3580 : : *
3581 : : * Returns: (transfer full): a #GIcon
3582 : : *
3583 : : * Since: 2.34
3584 : : * Deprecated: 2.84: Use g_unix_mount_entry_guess_symbolic_icon() instead.
3585 : : */
3586 : : GIcon *
3587 : 0 : g_unix_mount_guess_symbolic_icon (GUnixMountEntry *mount_entry)
3588 : : {
3589 : 0 : return g_unix_mount_entry_guess_symbolic_icon (mount_entry);
3590 : : }
3591 : :
3592 : : /**
3593 : : * g_unix_mount_entry_guess_symbolic_icon:
3594 : : * @mount_entry: a #GUnixMountEntry
3595 : : *
3596 : : * Guesses the symbolic icon of a Unix mount.
3597 : : *
3598 : : * Returns: (transfer full): a #GIcon
3599 : : *
3600 : : * Since: 2.84
3601 : : */
3602 : : GIcon *
3603 : 0 : g_unix_mount_entry_guess_symbolic_icon (GUnixMountEntry *mount_entry)
3604 : : {
3605 : 0 : return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_entry_guess_type (mount_entry), FALSE, TRUE));
3606 : : }
3607 : :
3608 : : /**
3609 : : * g_unix_mount_point_guess_name:
3610 : : * @mount_point: a #GUnixMountPoint
3611 : : *
3612 : : * Guesses the name of a Unix mount point.
3613 : : * The result is a translated string.
3614 : : *
3615 : : * Returns: A newly allocated string that must
3616 : : * be freed with g_free()
3617 : : */
3618 : : gchar *
3619 : 4 : g_unix_mount_point_guess_name (GUnixMountPoint *mount_point)
3620 : : {
3621 : : char *name;
3622 : :
3623 : 4 : if (strcmp (mount_point->mount_path, "/") == 0)
3624 : 2 : name = g_strdup (_("Filesystem root"));
3625 : : else
3626 : 3 : name = g_filename_display_basename (mount_point->mount_path);
3627 : :
3628 : 4 : return name;
3629 : : }
3630 : :
3631 : : /**
3632 : : * g_unix_mount_point_guess_icon:
3633 : : * @mount_point: a #GUnixMountPoint
3634 : : *
3635 : : * Guesses the icon of a Unix mount point.
3636 : : *
3637 : : * Returns: (transfer full): a #GIcon
3638 : : */
3639 : : GIcon *
3640 : 4 : g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point)
3641 : : {
3642 : 4 : return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, FALSE));
3643 : : }
3644 : :
3645 : : /**
3646 : : * g_unix_mount_point_guess_symbolic_icon:
3647 : : * @mount_point: a #GUnixMountPoint
3648 : : *
3649 : : * Guesses the symbolic icon of a Unix mount point.
3650 : : *
3651 : : * Returns: (transfer full): a #GIcon
3652 : : *
3653 : : * Since: 2.34
3654 : : */
3655 : : GIcon *
3656 : 4 : g_unix_mount_point_guess_symbolic_icon (GUnixMountPoint *mount_point)
3657 : : {
3658 : 4 : return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, TRUE));
3659 : : }
3660 : :
3661 : : /**
3662 : : * g_unix_mount_guess_can_eject:
3663 : : * @mount_entry: a #GUnixMountEntry
3664 : : *
3665 : : * Guesses whether a Unix mount can be ejected.
3666 : : *
3667 : : * Returns: %TRUE if @mount_entry is deemed to be ejectable.
3668 : : *
3669 : : * Deprecated: 2.84: Use g_unix_mount_entry_guess_can_eject() instead.
3670 : : */
3671 : : gboolean
3672 : 0 : g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry)
3673 : : {
3674 : 0 : return g_unix_mount_entry_guess_can_eject (mount_entry);
3675 : : }
3676 : :
3677 : : /**
3678 : : * g_unix_mount_entry_guess_can_eject:
3679 : : * @mount_entry: a #GUnixMountEntry
3680 : : *
3681 : : * Guesses whether a Unix mount can be ejected.
3682 : : *
3683 : : * Returns: %TRUE if @mount_entry is deemed to be ejectable.
3684 : : *
3685 : : * Since: 2.84
3686 : : */
3687 : : gboolean
3688 : 0 : g_unix_mount_entry_guess_can_eject (GUnixMountEntry *mount_entry)
3689 : : {
3690 : : GUnixMountType guessed_type;
3691 : :
3692 : 0 : guessed_type = g_unix_mount_entry_guess_type (mount_entry);
3693 : 0 : if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
3694 : : guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
3695 : 0 : return TRUE;
3696 : :
3697 : 0 : return FALSE;
3698 : : }
3699 : :
3700 : : /**
3701 : : * g_unix_mount_guess_should_display:
3702 : : * @mount_entry: a #GUnixMountEntry
3703 : : *
3704 : : * Guesses whether a Unix mount should be displayed in the UI.
3705 : : *
3706 : : * Returns: %TRUE if @mount_entry is deemed to be displayable.
3707 : : *
3708 : : * Deprecated: 2.84: Use g_unix_mount_entry_guess_should_display() instead.
3709 : : */
3710 : : gboolean
3711 : 0 : g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry)
3712 : : {
3713 : 0 : return g_unix_mount_entry_guess_should_display (mount_entry);
3714 : : }
3715 : :
3716 : : /**
3717 : : * g_unix_mount_entry_guess_should_display:
3718 : : * @mount_entry: a #GUnixMountEntry
3719 : : *
3720 : : * Guesses whether a Unix mount should be displayed in the UI.
3721 : : *
3722 : : * Returns: %TRUE if @mount_entry is deemed to be displayable.
3723 : : * Since: 2.84
3724 : : */
3725 : : gboolean
3726 : 39 : g_unix_mount_entry_guess_should_display (GUnixMountEntry *mount_entry)
3727 : : {
3728 : : const char *mount_path;
3729 : : const gchar *user_name;
3730 : : gsize user_name_len;
3731 : :
3732 : : /* Never display internal mountpoints */
3733 : 39 : if (g_unix_mount_entry_is_system_internal (mount_entry))
3734 : 39 : return FALSE;
3735 : :
3736 : : /* Only display things in /media (which are generally user mountable)
3737 : : and home dir (fuse stuff) and /run/media/$USER */
3738 : 0 : mount_path = mount_entry->mount_path;
3739 : 0 : if (mount_path != NULL)
3740 : : {
3741 : 0 : const gboolean running_as_root = (getuid () == 0);
3742 : 0 : gboolean is_in_runtime_dir = FALSE;
3743 : :
3744 : : /* Hide mounts within a dot path, suppose it was a purpose to hide this mount */
3745 : 0 : if (g_strstr_len (mount_path, -1, "/.") != NULL)
3746 : 0 : return FALSE;
3747 : :
3748 : : /* Check /run/media/$USER/. If running as root, display any mounts below
3749 : : * /run/media/. */
3750 : 0 : if (running_as_root)
3751 : : {
3752 : 0 : if (strncmp (mount_path, "/run/media/", strlen ("/run/media/")) == 0)
3753 : 0 : is_in_runtime_dir = TRUE;
3754 : : }
3755 : : else
3756 : : {
3757 : 0 : user_name = g_get_user_name ();
3758 : 0 : user_name_len = strlen (user_name);
3759 : 0 : if (strncmp (mount_path, "/run/media/", strlen ("/run/media/")) == 0 &&
3760 : 0 : strncmp (mount_path + strlen ("/run/media/"), user_name, user_name_len) == 0 &&
3761 : 0 : mount_path[strlen ("/run/media/") + user_name_len] == '/')
3762 : 0 : is_in_runtime_dir = TRUE;
3763 : : }
3764 : :
3765 : 0 : if (is_in_runtime_dir || g_str_has_prefix (mount_path, "/media/"))
3766 : : {
3767 : : char *path;
3768 : : /* Avoid displaying mounts that are not accessible to the user.
3769 : : *
3770 : : * See http://bugzilla.gnome.org/show_bug.cgi?id=526320 for why we
3771 : : * want to avoid g_access() for mount points which can potentially
3772 : : * block or fail stat()'ing, such as network mounts.
3773 : : */
3774 : 0 : path = g_path_get_dirname (mount_path);
3775 : 0 : if (g_str_has_prefix (path, "/media/"))
3776 : : {
3777 : 0 : if (g_access (path, R_OK|X_OK) != 0)
3778 : : {
3779 : 0 : g_free (path);
3780 : 0 : return FALSE;
3781 : : }
3782 : : }
3783 : 0 : g_free (path);
3784 : :
3785 : 0 : if (mount_entry->device_path && mount_entry->device_path[0] == '/')
3786 : : {
3787 : : struct stat st;
3788 : 0 : if (g_stat (mount_entry->device_path, &st) == 0 &&
3789 : 0 : S_ISBLK(st.st_mode) &&
3790 : 0 : g_access (mount_path, R_OK|X_OK) != 0)
3791 : 0 : return FALSE;
3792 : : }
3793 : 0 : return TRUE;
3794 : : }
3795 : :
3796 : 0 : if (g_str_has_prefix (mount_path, g_get_home_dir ()) &&
3797 : 0 : mount_path[strlen (g_get_home_dir())] == G_DIR_SEPARATOR)
3798 : 0 : return TRUE;
3799 : : }
3800 : :
3801 : 0 : return FALSE;
3802 : : }
3803 : :
3804 : : /**
3805 : : * g_unix_mount_point_guess_can_eject:
3806 : : * @mount_point: a #GUnixMountPoint
3807 : : *
3808 : : * Guesses whether a Unix mount point can be ejected.
3809 : : *
3810 : : * Returns: %TRUE if @mount_point is deemed to be ejectable.
3811 : : */
3812 : : gboolean
3813 : 4 : g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point)
3814 : : {
3815 : : GUnixMountType guessed_type;
3816 : :
3817 : 4 : guessed_type = g_unix_mount_point_guess_type (mount_point);
3818 : 4 : if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
3819 : : guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
3820 : 0 : return TRUE;
3821 : :
3822 : 4 : return FALSE;
3823 : : }
3824 : :
3825 : : /* Utility functions {{{1 */
3826 : :
3827 : : #ifdef HAVE_MNTENT_H
3828 : : /* borrowed from gtk/gtkfilesystemunix.c in GTK on 02/23/2006 */
3829 : : static void
3830 : 0 : _canonicalize_filename (gchar *filename)
3831 : : {
3832 : : gchar *p, *q;
3833 : 0 : gboolean last_was_slash = FALSE;
3834 : :
3835 : 0 : p = filename;
3836 : 0 : q = filename;
3837 : :
3838 : 0 : while (*p)
3839 : : {
3840 : 0 : if (*p == G_DIR_SEPARATOR)
3841 : : {
3842 : 0 : if (!last_was_slash)
3843 : 0 : *q++ = G_DIR_SEPARATOR;
3844 : :
3845 : 0 : last_was_slash = TRUE;
3846 : : }
3847 : : else
3848 : : {
3849 : 0 : if (last_was_slash && *p == '.')
3850 : : {
3851 : 0 : if (*(p + 1) == G_DIR_SEPARATOR ||
3852 : 0 : *(p + 1) == '\0')
3853 : : {
3854 : 0 : if (*(p + 1) == '\0')
3855 : 0 : break;
3856 : :
3857 : 0 : p += 1;
3858 : : }
3859 : 0 : else if (*(p + 1) == '.' &&
3860 : 0 : (*(p + 2) == G_DIR_SEPARATOR ||
3861 : 0 : *(p + 2) == '\0'))
3862 : : {
3863 : 0 : if (q > filename + 1)
3864 : : {
3865 : 0 : q--;
3866 : 0 : while (q > filename + 1 &&
3867 : 0 : *(q - 1) != G_DIR_SEPARATOR)
3868 : 0 : q--;
3869 : : }
3870 : :
3871 : 0 : if (*(p + 2) == '\0')
3872 : 0 : break;
3873 : :
3874 : 0 : p += 2;
3875 : : }
3876 : : else
3877 : : {
3878 : 0 : *q++ = *p;
3879 : 0 : last_was_slash = FALSE;
3880 : : }
3881 : : }
3882 : : else
3883 : : {
3884 : 0 : *q++ = *p;
3885 : 0 : last_was_slash = FALSE;
3886 : : }
3887 : : }
3888 : :
3889 : 0 : p++;
3890 : : }
3891 : :
3892 : 0 : if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
3893 : 0 : q--;
3894 : :
3895 : 0 : *q = '\0';
3896 : 0 : }
3897 : :
3898 : : static char *
3899 : 0 : _resolve_symlink (const char *file)
3900 : : {
3901 : : GError *error;
3902 : : char *dir;
3903 : : char *link;
3904 : : char *f;
3905 : : char *f1;
3906 : :
3907 : 0 : f = g_strdup (file);
3908 : :
3909 : 0 : while (g_file_test (f, G_FILE_TEST_IS_SYMLINK))
3910 : : {
3911 : 0 : link = g_file_read_link (f, &error);
3912 : 0 : if (link == NULL)
3913 : : {
3914 : 0 : g_error_free (error);
3915 : 0 : g_free (f);
3916 : 0 : f = NULL;
3917 : 0 : goto out;
3918 : : }
3919 : :
3920 : 0 : dir = g_path_get_dirname (f);
3921 : 0 : f1 = g_strdup_printf ("%s/%s", dir, link);
3922 : 0 : g_free (dir);
3923 : 0 : g_free (link);
3924 : 0 : g_free (f);
3925 : 0 : f = f1;
3926 : : }
3927 : :
3928 : 0 : out:
3929 : 0 : if (f != NULL)
3930 : 0 : _canonicalize_filename (f);
3931 : 0 : return f;
3932 : : }
3933 : :
3934 : : static const char *
3935 : 0 : _resolve_dev_root (void)
3936 : : {
3937 : : static gboolean have_real_dev_root = FALSE;
3938 : : static char real_dev_root[256];
3939 : : struct stat statbuf;
3940 : :
3941 : : /* see if it's cached already */
3942 : 0 : if (have_real_dev_root)
3943 : 0 : goto found;
3944 : :
3945 : : /* otherwise we're going to find it right away.. */
3946 : 0 : have_real_dev_root = TRUE;
3947 : :
3948 : 0 : if (stat ("/dev/root", &statbuf) == 0)
3949 : : {
3950 : 0 : if (! S_ISLNK (statbuf.st_mode))
3951 : : {
3952 : 0 : dev_t root_dev = statbuf.st_dev;
3953 : : FILE *f;
3954 : :
3955 : : /* see if device with similar major:minor as /dev/root is mention
3956 : : * in /etc/mtab (it usually is)
3957 : : */
3958 : 0 : f = fopen ("/etc/mtab", "re");
3959 : 0 : if (f != NULL)
3960 : : {
3961 : : struct mntent *entp;
3962 : : #ifdef HAVE_GETMNTENT_R
3963 : : struct mntent ent;
3964 : : char buf[1024];
3965 : 0 : while ((entp = getmntent_r (f, &ent, buf, sizeof (buf))) != NULL)
3966 : : {
3967 : : #else
3968 : : G_LOCK (getmntent);
3969 : : while ((entp = getmntent (f)) != NULL)
3970 : : {
3971 : : #endif
3972 : 0 : if (stat (entp->mnt_fsname, &statbuf) == 0 &&
3973 : 0 : statbuf.st_dev == root_dev)
3974 : : {
3975 : 0 : strncpy (real_dev_root, entp->mnt_fsname, sizeof (real_dev_root) - 1);
3976 : 0 : real_dev_root[sizeof (real_dev_root) - 1] = '\0';
3977 : 0 : fclose (f);
3978 : 0 : goto found;
3979 : : }
3980 : : }
3981 : :
3982 : 0 : endmntent (f);
3983 : :
3984 : : #ifndef HAVE_GETMNTENT_R
3985 : : G_UNLOCK (getmntent);
3986 : : #endif
3987 : : }
3988 : :
3989 : : /* no, that didn't work.. next we could scan /dev ... but I digress.. */
3990 : :
3991 : : }
3992 : : else
3993 : : {
3994 : : char *resolved;
3995 : 0 : resolved = _resolve_symlink ("/dev/root");
3996 : 0 : if (resolved != NULL)
3997 : : {
3998 : 0 : strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1);
3999 : 0 : real_dev_root[sizeof (real_dev_root) - 1] = '\0';
4000 : 0 : g_free (resolved);
4001 : 0 : goto found;
4002 : : }
4003 : : }
4004 : : }
4005 : :
4006 : : /* bah sucks.. */
4007 : 0 : strcpy (real_dev_root, "/dev/root");
4008 : :
4009 : 0 : found:
4010 : 0 : return real_dev_root;
4011 : : }
4012 : : #endif
4013 : :
4014 : : /* Epilogue {{{1 */
4015 : : /* vim:set foldmethod=marker: */
|