LCOV - code coverage report
Current view: top level - glib/gio - gunixmounts.c (source / functions) Hit Total Coverage
Test: unnamed Lines: 232 766 30.3 %
Date: 2024-04-23 05:16:05 Functions: 37 78 47.4 %
Branches: 79 658 12.0 %

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

Generated by: LCOV version 1.14