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