Blame gio/gunixmounts.c

Packit ae235b
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
Packit ae235b
Packit ae235b
/* GIO - GLib Input, Output and Streaming Library
Packit ae235b
 * 
Packit ae235b
 * Copyright (C) 2006-2007 Red Hat, Inc.
Packit ae235b
 *
Packit ae235b
 * This library is free software; you can redistribute it and/or
Packit ae235b
 * modify it under the terms of the GNU Lesser General Public
Packit ae235b
 * License as published by the Free Software Foundation; either
Packit ae235b
 * version 2.1 of the License, or (at your option) any later version.
Packit ae235b
 *
Packit ae235b
 * This library is distributed in the hope that it will be useful,
Packit ae235b
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit ae235b
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit ae235b
 * Lesser General Public License for more details.
Packit ae235b
 *
Packit ae235b
 * You should have received a copy of the GNU Lesser General
Packit ae235b
 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
Packit ae235b
 *
Packit ae235b
 * Author: Alexander Larsson <alexl@redhat.com>
Packit ae235b
 */
Packit ae235b
Packit ae235b
/* Prologue {{{1 */
Packit ae235b
Packit ae235b
#include "config.h"
Packit ae235b
Packit ae235b
#include <sys/types.h>
Packit ae235b
#include <sys/stat.h>
Packit ae235b
#include <sys/wait.h>
Packit ae235b
#ifndef HAVE_SYSCTLBYNAME
Packit ae235b
#ifdef HAVE_SYS_PARAM_H
Packit ae235b
#include <sys/param.h>
Packit ae235b
#endif
Packit ae235b
#endif
Packit ae235b
#ifdef HAVE_POLL
Packit ae235b
#include <poll.h>
Packit ae235b
#endif
Packit ae235b
#include <stdio.h>
Packit ae235b
#include <unistd.h>
Packit ae235b
#include <sys/time.h>
Packit ae235b
#include <errno.h>
Packit ae235b
#include <string.h>
Packit ae235b
#include <signal.h>
Packit ae235b
#include <gstdio.h>
Packit ae235b
#include <dirent.h>
Packit ae235b
Packit ae235b
#if HAVE_SYS_STATFS_H
Packit ae235b
#include <sys/statfs.h>
Packit ae235b
#endif
Packit ae235b
#if HAVE_SYS_STATVFS_H
Packit ae235b
#include <sys/statvfs.h>
Packit ae235b
#endif
Packit ae235b
#if HAVE_SYS_VFS_H
Packit ae235b
#include <sys/vfs.h>
Packit ae235b
#elif HAVE_SYS_MOUNT_H
Packit ae235b
#if HAVE_SYS_PARAM_H
Packit ae235b
#include <sys/param.h>
Packit ae235b
#endif
Packit ae235b
#include <sys/mount.h>
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#ifndef O_BINARY
Packit ae235b
#define O_BINARY 0
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#include "gunixmounts.h"
Packit ae235b
#include "glocalfileprivate.h"
Packit ae235b
#include "gfile.h"
Packit ae235b
#include "gfilemonitor.h"
Packit ae235b
#include "glibintl.h"
Packit ae235b
#include "gthemedicon.h"
Packit ae235b
#include "gcontextspecificgroup.h"
Packit ae235b
Packit ae235b
Packit ae235b
#ifdef HAVE_MNTENT_H
Packit ae235b
static const char *_resolve_dev_root (void);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * SECTION:gunixmounts
Packit ae235b
 * @include: gio/gunixmounts.h
Packit ae235b
 * @short_description: UNIX mounts
Packit ae235b
 *
Packit ae235b
 * Routines for managing mounted UNIX mount points and paths.
Packit ae235b
 *
Packit ae235b
 * Note that `<gio/gunixmounts.h>` belongs to the UNIX-specific GIO
Packit ae235b
 * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config
Packit ae235b
 * file when using it.
Packit ae235b
 */
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * GUnixMountType:
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_CDROM: CDROM UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_NFS: Network File System (NFS) UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_ZIP: ZIP UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_JAZ: JAZZ UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_MEMSTICK: Memory Stick UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_CF: Compact Flash UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_SM: Smart Media UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_SDMMC: SD/MMC UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_IPOD: iPod UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_CAMERA: Digital camera UNIX mount type.
Packit ae235b
 * @G_UNIX_MOUNT_TYPE_HD: Hard drive UNIX mount type.
Packit ae235b
 * 
Packit ae235b
 * Types of UNIX mounts.
Packit ae235b
 **/
Packit ae235b
typedef enum {
Packit ae235b
  G_UNIX_MOUNT_TYPE_UNKNOWN,
Packit ae235b
  G_UNIX_MOUNT_TYPE_FLOPPY,
Packit ae235b
  G_UNIX_MOUNT_TYPE_CDROM,
Packit ae235b
  G_UNIX_MOUNT_TYPE_NFS,
Packit ae235b
  G_UNIX_MOUNT_TYPE_ZIP,
Packit ae235b
  G_UNIX_MOUNT_TYPE_JAZ,
Packit ae235b
  G_UNIX_MOUNT_TYPE_MEMSTICK,
Packit ae235b
  G_UNIX_MOUNT_TYPE_CF,
Packit ae235b
  G_UNIX_MOUNT_TYPE_SM,
Packit ae235b
  G_UNIX_MOUNT_TYPE_SDMMC,
Packit ae235b
  G_UNIX_MOUNT_TYPE_IPOD,
Packit ae235b
  G_UNIX_MOUNT_TYPE_CAMERA,
Packit ae235b
  G_UNIX_MOUNT_TYPE_HD
Packit ae235b
} GUnixMountType;
Packit ae235b
Packit ae235b
struct _GUnixMountEntry {
Packit ae235b
  char *mount_path;
Packit ae235b
  char *device_path;
Packit ae235b
  char *filesystem_type;
Packit ae235b
  gboolean is_read_only;
Packit ae235b
  gboolean is_system_internal;
Packit ae235b
};
Packit ae235b
Packit ae235b
G_DEFINE_BOXED_TYPE (GUnixMountEntry, g_unix_mount_entry,
Packit ae235b
                     g_unix_mount_copy, g_unix_mount_free)
Packit ae235b
Packit ae235b
struct _GUnixMountPoint {
Packit ae235b
  char *mount_path;
Packit ae235b
  char *device_path;
Packit ae235b
  char *filesystem_type;
Packit ae235b
  char *options;
Packit ae235b
  gboolean is_read_only;
Packit ae235b
  gboolean is_user_mountable;
Packit ae235b
  gboolean is_loopback;
Packit ae235b
};
Packit ae235b
Packit ae235b
G_DEFINE_BOXED_TYPE (GUnixMountPoint, g_unix_mount_point,
Packit ae235b
                     g_unix_mount_point_copy, g_unix_mount_point_free)
Packit ae235b
Packit ae235b
static GList *_g_get_unix_mounts (void);
Packit ae235b
static GList *_g_get_unix_mount_points (void);
Packit ae235b
static gboolean proc_mounts_watch_is_running (void);
Packit ae235b
Packit ae235b
static guint64 mount_poller_time = 0;
Packit ae235b
Packit ae235b
#ifdef HAVE_SYS_MNTTAB_H
Packit ae235b
#define MNTOPT_RO	"ro"
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#ifdef HAVE_MNTENT_H
Packit ae235b
#include <mntent.h>
Packit ae235b
#ifdef HAVE_LIBMOUNT
Packit ae235b
#include <libmount.h>
Packit ae235b
#endif
Packit ae235b
#elif defined (HAVE_SYS_MNTTAB_H)
Packit ae235b
#include <sys/mnttab.h>
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#ifdef HAVE_SYS_VFSTAB_H
Packit ae235b
#include <sys/vfstab.h>
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
Packit ae235b
#include <sys/mntctl.h>
Packit ae235b
#include <sys/vfs.h>
Packit ae235b
#include <sys/vmount.h>
Packit ae235b
#include <fshelp.h>
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#if (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
Packit ae235b
#include <sys/param.h>
Packit ae235b
#include <sys/ucred.h>
Packit ae235b
#include <sys/mount.h>
Packit ae235b
#include <fstab.h>
Packit ae235b
#ifdef HAVE_SYS_SYSCTL_H
Packit ae235b
#include <sys/sysctl.h>
Packit ae235b
#endif
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#ifndef HAVE_SETMNTENT
Packit ae235b
#define setmntent(f,m) fopen(f,m)
Packit ae235b
#endif
Packit ae235b
#ifndef HAVE_ENDMNTENT
Packit ae235b
#define endmntent(f) fclose(f)
Packit ae235b
#endif
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
is_in (const char *value, const char *set[])
Packit ae235b
{
Packit ae235b
  int i;
Packit ae235b
  for (i = 0; set[i] != NULL; i++)
Packit ae235b
    {
Packit ae235b
      if (strcmp (set[i], value) == 0)
Packit ae235b
	return TRUE;
Packit ae235b
    }
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_is_mount_path_system_internal:
Packit ae235b
 * @mount_path: (type filename): a mount path, e.g. `/media/disk` or `/usr`
Packit ae235b
 *
Packit ae235b
 * Determines if @mount_path is considered an implementation of the
Packit ae235b
 * OS. This is primarily used for hiding mountable and mounted volumes
Packit ae235b
 * that only are used in the OS and has little to no relevance to the
Packit ae235b
 * casual user.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if @mount_path is considered an implementation detail 
Packit ae235b
 *     of the OS.
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_unix_is_mount_path_system_internal (const char *mount_path)
Packit ae235b
{
Packit ae235b
  const char *ignore_mountpoints[] = {
Packit ae235b
    /* Includes all FHS 2.3 toplevel dirs and other specialized
Packit ae235b
     * directories that we want to hide from the user.
Packit ae235b
     */
Packit ae235b
    "/",              /* we already have "Filesystem root" in Nautilus */ 
Packit ae235b
    "/bin",
Packit ae235b
    "/boot",
Packit ae235b
    "/compat/linux/proc",
Packit ae235b
    "/compat/linux/sys",
Packit ae235b
    "/dev",
Packit ae235b
    "/etc",
Packit ae235b
    "/home",
Packit ae235b
    "/lib",
Packit ae235b
    "/lib64",
Packit ae235b
    "/libexec",
Packit ae235b
    "/live/cow",
Packit ae235b
    "/live/image",
Packit ae235b
    "/media",
Packit ae235b
    "/mnt",
Packit ae235b
    "/opt",
Packit ae235b
    "/rescue",
Packit ae235b
    "/root",
Packit ae235b
    "/sbin",
Packit ae235b
    "/srv",
Packit ae235b
    "/tmp",
Packit ae235b
    "/usr",
Packit ae235b
    "/usr/X11R6",
Packit ae235b
    "/usr/local",
Packit ae235b
    "/usr/obj",
Packit ae235b
    "/usr/ports",
Packit ae235b
    "/usr/src",
Packit ae235b
    "/usr/xobj",
Packit ae235b
    "/var",
Packit ae235b
    "/var/crash",
Packit ae235b
    "/var/local",
Packit ae235b
    "/var/log",
Packit ae235b
    "/var/log/audit", /* https://bugzilla.redhat.com/show_bug.cgi?id=333041 */
Packit ae235b
    "/var/mail",
Packit ae235b
    "/var/run",
Packit ae235b
    "/var/tmp",       /* https://bugzilla.redhat.com/show_bug.cgi?id=335241 */
Packit ae235b
    "/proc",
Packit ae235b
    "/sbin",
Packit ae235b
    "/net",
Packit ae235b
    "/sys",
Packit ae235b
    NULL
Packit ae235b
  };
Packit ae235b
Packit ae235b
  if (is_in (mount_path, ignore_mountpoints))
Packit ae235b
    return TRUE;
Packit ae235b
  
Packit ae235b
  if (g_str_has_prefix (mount_path, "/dev/") ||
Packit ae235b
      g_str_has_prefix (mount_path, "/proc/") ||
Packit ae235b
      g_str_has_prefix (mount_path, "/sys/"))
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  if (g_str_has_suffix (mount_path, "/.gvfs"))
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_is_system_fs_type:
Packit ae235b
 * @fs_type: a file system type, e.g. `procfs` or `tmpfs`
Packit ae235b
 *
Packit ae235b
 * Determines if @fs_type is considered a type of file system which is only
Packit ae235b
 * used in implementation of the OS. This is primarily used for hiding
Packit ae235b
 * mounted volumes that are intended as APIs for programs to read, and system
Packit ae235b
 * administrators at a shell; rather than something that should, for example,
Packit ae235b
 * appear in a GUI. For example, the Linux `/proc` filesystem.
Packit ae235b
 *
Packit ae235b
 * The list of file system types considered ‘system’ ones may change over time.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if @fs_type is considered an implementation detail of the OS.
Packit ae235b
 * Since: 2.56
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_is_system_fs_type (const char *fs_type)
Packit ae235b
{
Packit ae235b
  const char *ignore_fs[] = {
Packit ae235b
    "adfs",
Packit ae235b
    "afs",
Packit ae235b
    "auto",
Packit ae235b
    "autofs",
Packit ae235b
    "autofs4",
Packit ae235b
    "cgroup",
Packit ae235b
    "cifs",
Packit ae235b
    "configfs",
Packit ae235b
    "cxfs",
Packit ae235b
    "debugfs",
Packit ae235b
    "devfs",
Packit ae235b
    "devpts",
Packit ae235b
    "devtmpfs",
Packit ae235b
    "ecryptfs",
Packit ae235b
    "fdescfs",
Packit ae235b
    "fusectl",
Packit ae235b
    "gfs",
Packit ae235b
    "gfs2",
Packit ae235b
    "gpfs",
Packit ae235b
    "hugetlbfs",
Packit ae235b
    "kernfs",
Packit ae235b
    "linprocfs",
Packit ae235b
    "linsysfs",
Packit ae235b
    "lustre",
Packit ae235b
    "lustre_lite",
Packit ae235b
    "mfs",
Packit ae235b
    "mqueue",
Packit ae235b
    "ncpfs",
Packit ae235b
    "nfs",
Packit ae235b
    "nfs4",
Packit ae235b
    "nfsd",
Packit ae235b
    "nullfs",
Packit ae235b
    "ocfs2",
Packit ae235b
    "overlay",
Packit ae235b
    "proc",
Packit ae235b
    "procfs",
Packit ae235b
    "pstore",
Packit ae235b
    "ptyfs",
Packit ae235b
    "rootfs",
Packit ae235b
    "rpc_pipefs",
Packit ae235b
    "securityfs",
Packit ae235b
    "selinuxfs",
Packit ae235b
    "smbfs",
Packit ae235b
    "sysfs",
Packit ae235b
    "tmpfs",
Packit ae235b
    "usbfs",
Packit ae235b
    "zfs",
Packit ae235b
    NULL
Packit ae235b
  };
Packit ae235b
Packit ae235b
  g_return_val_if_fail (fs_type != NULL && *fs_type != '\0', FALSE);
Packit ae235b
Packit ae235b
  return is_in (fs_type, ignore_fs);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_is_system_device_path:
Packit ae235b
 * @device_path: a device path, e.g. `/dev/loop0` or `nfsd`
Packit ae235b
 *
Packit ae235b
 * Determines if @device_path is considered a block device path which is only
Packit ae235b
 * used in implementation of the OS. This is primarily used for hiding
Packit ae235b
 * mounted volumes that are intended as APIs for programs to read, and system
Packit ae235b
 * administrators at a shell; rather than something that should, for example,
Packit ae235b
 * appear in a GUI. For example, the Linux `/proc` filesystem.
Packit ae235b
 *
Packit ae235b
 * The list of device paths considered ‘system’ ones may change over time.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if @device_path is considered an implementation detail of
Packit ae235b
 *    the OS.
Packit ae235b
 * Since: 2.56
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_is_system_device_path (const char *device_path)
Packit ae235b
{
Packit ae235b
  const char *ignore_devices[] = {
Packit ae235b
    "none",
Packit ae235b
    "sunrpc",
Packit ae235b
    "devpts",
Packit ae235b
    "nfsd",
Packit ae235b
    "/dev/loop",
Packit ae235b
    "/dev/vn",
Packit ae235b
    NULL
Packit ae235b
  };
Packit ae235b
Packit ae235b
  g_return_val_if_fail (device_path != NULL && *device_path != '\0', FALSE);
Packit ae235b
Packit ae235b
  return is_in (device_path, ignore_devices);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
guess_system_internal (const char *mountpoint,
Packit ae235b
		       const char *fs,
Packit ae235b
		       const char *device)
Packit ae235b
{
Packit ae235b
  if (g_unix_is_system_fs_type (fs))
Packit ae235b
    return TRUE;
Packit ae235b
  
Packit ae235b
  if (g_unix_is_system_device_path (device))
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  if (g_unix_is_mount_path_system_internal (mountpoint))
Packit ae235b
    return TRUE;
Packit ae235b
  
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* GUnixMounts (ie: mtab) implementations {{{1 */
Packit ae235b
Packit ae235b
static GUnixMountEntry *
Packit ae235b
create_unix_mount_entry (const char *device_path,
Packit ae235b
                         const char *mount_path,
Packit ae235b
                         const char *filesystem_type,
Packit ae235b
                         gboolean    is_read_only)
Packit ae235b
{
Packit ae235b
  GUnixMountEntry *mount_entry = NULL;
Packit ae235b
Packit ae235b
  mount_entry = g_new0 (GUnixMountEntry, 1);
Packit ae235b
  mount_entry->device_path = g_strdup (device_path);
Packit ae235b
  mount_entry->mount_path = g_strdup (mount_path);
Packit ae235b
  mount_entry->filesystem_type = g_strdup (filesystem_type);
Packit ae235b
  mount_entry->is_read_only = is_read_only;
Packit ae235b
Packit ae235b
  mount_entry->is_system_internal =
Packit ae235b
    guess_system_internal (mount_entry->mount_path,
Packit ae235b
                           mount_entry->filesystem_type,
Packit ae235b
                           mount_entry->device_path);
Packit ae235b
  return mount_entry;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GUnixMountPoint *
Packit ae235b
create_unix_mount_point (const char *device_path,
Packit ae235b
                         const char *mount_path,
Packit ae235b
                         const char *filesystem_type,
Packit ae235b
                         const char *options,
Packit ae235b
                         gboolean    is_read_only,
Packit ae235b
                         gboolean    is_user_mountable,
Packit ae235b
                         gboolean    is_loopback)
Packit ae235b
{
Packit ae235b
  GUnixMountPoint *mount_point = NULL;
Packit ae235b
Packit ae235b
  mount_point = g_new0 (GUnixMountPoint, 1);
Packit ae235b
  mount_point->device_path = g_strdup (device_path);
Packit ae235b
  mount_point->mount_path = g_strdup (mount_path);
Packit ae235b
  mount_point->filesystem_type = g_strdup (filesystem_type);
Packit ae235b
  mount_point->options = g_strdup (options);
Packit ae235b
  mount_point->is_read_only = is_read_only;
Packit ae235b
  mount_point->is_user_mountable = is_user_mountable;
Packit ae235b
  mount_point->is_loopback = is_loopback;
Packit ae235b
Packit ae235b
  return mount_point;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* mntent.h (Linux, GNU, NSS) {{{2 */
Packit ae235b
#ifdef HAVE_MNTENT_H
Packit ae235b
Packit ae235b
#ifdef HAVE_LIBMOUNT
Packit ae235b
Packit ae235b
/* For documentation on /proc/self/mountinfo see
Packit ae235b
 * http://www.kernel.org/doc/Documentation/filesystems/proc.txt
Packit ae235b
 */
Packit ae235b
#define PROC_MOUNTINFO_PATH "/proc/self/mountinfo"
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mounts (void)
Packit ae235b
{
Packit ae235b
  struct libmnt_table *table = NULL;
Packit ae235b
  struct libmnt_iter* iter = NULL;
Packit ae235b
  struct libmnt_fs *fs = NULL;
Packit ae235b
  GUnixMountEntry *mount_entry = NULL;
Packit ae235b
  GList *return_list = NULL;
Packit ae235b
Packit ae235b
  table = mnt_new_table ();
Packit ae235b
  if (mnt_table_parse_mtab (table, NULL) < 0)
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  iter = mnt_new_iter (MNT_ITER_FORWARD);
Packit ae235b
  while (mnt_table_next_fs (table, iter, &fs) == 0)
Packit ae235b
    {
Packit ae235b
      const char *device_path = NULL;
Packit ae235b
      char *mount_options = NULL;
Packit ae235b
      unsigned long mount_flags = 0;
Packit ae235b
      gboolean is_read_only = FALSE;
Packit ae235b
Packit ae235b
      device_path = mnt_fs_get_source (fs);
Packit ae235b
      if (g_strcmp0 (device_path, "/dev/root") == 0)
Packit ae235b
        device_path = _resolve_dev_root ();
Packit ae235b
Packit ae235b
      mount_options = mnt_fs_strdup_options (fs);
Packit ae235b
      if (mount_options)
Packit ae235b
        {
Packit ae235b
          mnt_optstr_get_flags (mount_options, &mount_flags, mnt_get_builtin_optmap (MNT_LINUX_MAP));
Packit ae235b
          g_free (mount_options);
Packit ae235b
        }
Packit ae235b
      is_read_only = (mount_flags & MS_RDONLY) ? TRUE : FALSE;
Packit ae235b
Packit ae235b
      mount_entry = create_unix_mount_entry (device_path,
Packit ae235b
                                             mnt_fs_get_target (fs),
Packit ae235b
                                             mnt_fs_get_fstype (fs),
Packit ae235b
                                             is_read_only);
Packit ae235b
Packit ae235b
      return_list = g_list_prepend (return_list, mount_entry);
Packit ae235b
    }
Packit ae235b
  mnt_free_iter (iter);
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  mnt_free_table (table);
Packit ae235b
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
#else
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
get_mtab_read_file (void)
Packit ae235b
{
Packit ae235b
#ifdef _PATH_MOUNTED
Packit ae235b
# ifdef __linux__
Packit ae235b
  return "/proc/mounts";
Packit ae235b
# else
Packit ae235b
  return _PATH_MOUNTED;
Packit ae235b
# endif
Packit ae235b
#else
Packit ae235b
  return "/etc/mtab";
Packit ae235b
#endif
Packit ae235b
}
Packit ae235b
Packit ae235b
#ifndef HAVE_GETMNTENT_R
Packit ae235b
G_LOCK_DEFINE_STATIC(getmntent);
Packit ae235b
#endif
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mounts (void)
Packit ae235b
{
Packit ae235b
#ifdef HAVE_GETMNTENT_R
Packit ae235b
  struct mntent ent;
Packit ae235b
  char buf[1024];
Packit ae235b
#endif
Packit ae235b
  struct mntent *mntent;
Packit ae235b
  FILE *file;
Packit ae235b
  const char *read_file;
Packit ae235b
  GUnixMountEntry *mount_entry;
Packit ae235b
  GHashTable *mounts_hash;
Packit ae235b
  GList *return_list;
Packit ae235b
  
Packit ae235b
  read_file = get_mtab_read_file ();
Packit ae235b
Packit ae235b
  file = setmntent (read_file, "r");
Packit ae235b
  if (file == NULL)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  return_list = NULL;
Packit ae235b
  
Packit ae235b
  mounts_hash = g_hash_table_new (g_str_hash, g_str_equal);
Packit ae235b
  
Packit ae235b
#ifdef HAVE_GETMNTENT_R
Packit ae235b
  while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
Packit ae235b
#else
Packit ae235b
  G_LOCK (getmntent);
Packit ae235b
  while ((mntent = getmntent (file)) != NULL)
Packit ae235b
#endif
Packit ae235b
    {
Packit ae235b
      const char *device_path = NULL;
Packit ae235b
      gboolean is_read_only = FALSE;
Packit ae235b
Packit ae235b
      /* ignore any mnt_fsname that is repeated and begins with a '/'
Packit ae235b
       *
Packit ae235b
       * We do this to avoid being fooled by --bind mounts, since
Packit ae235b
       * these have the same device as the location they bind to.
Packit ae235b
       * It's not an ideal solution to the problem, but it's likely that
Packit ae235b
       * the most important mountpoint is first and the --bind ones after
Packit ae235b
       * that aren't as important. So it should work.
Packit ae235b
       *
Packit ae235b
       * The '/' is to handle procfs, tmpfs and other no device mounts.
Packit ae235b
       */
Packit ae235b
      if (mntent->mnt_fsname != NULL &&
Packit ae235b
	  mntent->mnt_fsname[0] == '/' &&
Packit ae235b
	  g_hash_table_lookup (mounts_hash, mntent->mnt_fsname))
Packit ae235b
        continue;
Packit ae235b
Packit ae235b
      if (g_strcmp0 (mntent->mnt_fsname, "/dev/root") == 0)
Packit ae235b
        device_path = _resolve_dev_root ();
Packit ae235b
      else
Packit ae235b
        device_path = mntent->mnt_fsname;
Packit ae235b
Packit ae235b
#if defined (HAVE_HASMNTOPT)
Packit ae235b
      if (hasmntopt (mntent, MNTOPT_RO) != NULL)
Packit ae235b
	is_read_only = TRUE;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
      mount_entry = create_unix_mount_entry (device_path,
Packit ae235b
                                             mntent->mnt_dir,
Packit ae235b
                                             mntent->mnt_type,
Packit ae235b
                                             is_read_only);
Packit ae235b
Packit ae235b
      g_hash_table_insert (mounts_hash,
Packit ae235b
			   mount_entry->device_path,
Packit ae235b
			   mount_entry->device_path);
Packit ae235b
Packit ae235b
      return_list = g_list_prepend (return_list, mount_entry);
Packit ae235b
    }
Packit ae235b
  g_hash_table_destroy (mounts_hash);
Packit ae235b
  
Packit ae235b
  endmntent (file);
Packit ae235b
Packit ae235b
#ifndef HAVE_GETMNTENT_R
Packit ae235b
  G_UNLOCK (getmntent);
Packit ae235b
#endif
Packit ae235b
  
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
#endif /* HAVE_LIBMOUNT */
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
get_mtab_monitor_file (void)
Packit ae235b
{
Packit ae235b
  static const char *mountinfo_path = NULL;
Packit ae235b
#ifdef HAVE_LIBMOUNT
Packit ae235b
  struct stat buf;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  if (mountinfo_path != NULL)
Packit ae235b
    return mountinfo_path;
Packit ae235b
Packit ae235b
#ifdef HAVE_LIBMOUNT
Packit ae235b
  /* The mtab file is still used by some distros, so it has to be monitored in
Packit ae235b
   * order to avoid races between g_unix_mounts_get and "mounts-changed" signal:
Packit ae235b
   * https://bugzilla.gnome.org/show_bug.cgi?id=782814
Packit ae235b
   */
Packit ae235b
  if (mnt_has_regular_mtab (&mountinfo_path, NULL))
Packit ae235b
    {
Packit ae235b
      return mountinfo_path;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (stat (PROC_MOUNTINFO_PATH, &buf) == 0)
Packit ae235b
    {
Packit ae235b
      mountinfo_path = PROC_MOUNTINFO_PATH;
Packit ae235b
      return mountinfo_path;
Packit ae235b
    }
Packit ae235b
#endif
Packit ae235b
Packit ae235b
#ifdef _PATH_MOUNTED
Packit ae235b
# ifdef __linux__
Packit ae235b
  mountinfo_path = "/proc/mounts";
Packit ae235b
# else
Packit ae235b
  mountinfo_path = _PATH_MOUNTED;
Packit ae235b
# endif
Packit ae235b
#else
Packit ae235b
  mountinfo_path = "/etc/mtab";
Packit ae235b
#endif
Packit ae235b
Packit ae235b
  return mountinfo_path;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* mnttab.h {{{2 */
Packit ae235b
#elif defined (HAVE_SYS_MNTTAB_H)
Packit ae235b
Packit ae235b
G_LOCK_DEFINE_STATIC(getmntent);
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
get_mtab_read_file (void)
Packit ae235b
{
Packit ae235b
#ifdef _PATH_MOUNTED
Packit ae235b
  return _PATH_MOUNTED;
Packit ae235b
#else	
Packit ae235b
  return "/etc/mnttab";
Packit ae235b
#endif
Packit ae235b
}
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
get_mtab_monitor_file (void)
Packit ae235b
{
Packit ae235b
  return get_mtab_read_file ();
Packit ae235b
}
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mounts (void)
Packit ae235b
{
Packit ae235b
  struct mnttab mntent;
Packit ae235b
  FILE *file;
Packit ae235b
  const char *read_file;
Packit ae235b
  GUnixMountEntry *mount_entry;
Packit ae235b
  GList *return_list;
Packit ae235b
  
Packit ae235b
  read_file = get_mtab_read_file ();
Packit ae235b
  
Packit ae235b
  file = setmntent (read_file, "r");
Packit ae235b
  if (file == NULL)
Packit ae235b
    return NULL;
Packit ae235b
  
Packit ae235b
  return_list = NULL;
Packit ae235b
  
Packit ae235b
  G_LOCK (getmntent);
Packit ae235b
  while (! getmntent (file, &mntent))
Packit ae235b
    {
Packit ae235b
      gboolean is_read_only = FALSE;
Packit ae235b
Packit ae235b
#if defined (HAVE_HASMNTOPT)
Packit ae235b
      if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
Packit ae235b
	is_read_only = TRUE;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
      mount_entry = create_unix_mount_entry (mntent.mnt_special,
Packit ae235b
                                             mntent.mnt_mountp,
Packit ae235b
                                             mntent.mnt_fstype,
Packit ae235b
                                             is_read_only);
Packit ae235b
Packit ae235b
      return_list = g_list_prepend (return_list, mount_entry);
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  endmntent (file);
Packit ae235b
  
Packit ae235b
  G_UNLOCK (getmntent);
Packit ae235b
  
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* mntctl.h (AIX) {{{2 */
Packit ae235b
#elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
get_mtab_monitor_file (void)
Packit ae235b
{
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mounts (void)
Packit ae235b
{
Packit ae235b
  struct vfs_ent *fs_info;
Packit ae235b
  struct vmount *vmount_info;
Packit ae235b
  int vmount_number;
Packit ae235b
  unsigned int vmount_size;
Packit ae235b
  int current;
Packit ae235b
  GList *return_list;
Packit ae235b
  
Packit ae235b
  if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0)
Packit ae235b
    {
Packit ae235b
      g_warning ("Unable to know the number of mounted volumes\n");
Packit ae235b
      
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  vmount_info = (struct vmount*)g_malloc (vmount_size);
Packit ae235b
Packit ae235b
  vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info);
Packit ae235b
  
Packit ae235b
  if (vmount_info->vmt_revision != VMT_REVISION)
Packit ae235b
    g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision);
Packit ae235b
Packit ae235b
  if (vmount_number < 0)
Packit ae235b
    {
Packit ae235b
      g_warning ("Unable to recover mounted volumes information\n");
Packit ae235b
      
Packit ae235b
      g_free (vmount_info);
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  return_list = NULL;
Packit ae235b
  while (vmount_number > 0)
Packit ae235b
    {
Packit ae235b
      gboolean is_read_only = FALSE;
Packit ae235b
Packit ae235b
      fs_info = getvfsbytype (vmount_info->vmt_gfstype);
Packit ae235b
Packit ae235b
      /* is_removable = (vmount_info->vmt_flags & MNT_REMOVABLE) ? 1 : 0; */
Packit ae235b
      is_read_only = (vmount_info->vmt_flags & MNT_READONLY) ? 1 : 0;
Packit ae235b
Packit ae235b
      mount_entry = create_unix_mount_entry (vmt2dataptr (vmount_info, VMT_OBJECT),
Packit ae235b
                                             vmt2dataptr (vmount_info, VMT_STUB),
Packit ae235b
                                             fs_info == NULL ? "unknown" : fs_info->vfsent_name,
Packit ae235b
                                             is_read_only);
Packit ae235b
Packit ae235b
      return_list = g_list_prepend (return_list, mount_entry);
Packit ae235b
      
Packit ae235b
      vmount_info = (struct vmount *)( (char*)vmount_info 
Packit ae235b
				       + vmount_info->vmt_length);
Packit ae235b
      vmount_number--;
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  g_free (vmount_info);
Packit ae235b
  
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* sys/mount.h {{{2 */
Packit ae235b
#elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
get_mtab_monitor_file (void)
Packit ae235b
{
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mounts (void)
Packit ae235b
{
Packit ae235b
#if defined(USE_STATVFS)
Packit ae235b
  struct statvfs *mntent = NULL;
Packit ae235b
#elif defined(USE_STATFS)
Packit ae235b
  struct statfs *mntent = NULL;
Packit ae235b
#else
Packit ae235b
  #error statfs juggling failed
Packit ae235b
#endif
Packit ae235b
  size_t bufsize;
Packit ae235b
  int num_mounts, i;
Packit ae235b
  GUnixMountEntry *mount_entry;
Packit ae235b
  GList *return_list;
Packit ae235b
  
Packit ae235b
  /* Pass NOWAIT to avoid blocking trying to update NFS mounts. */
Packit ae235b
#if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
Packit ae235b
  num_mounts = getvfsstat (NULL, 0, ST_NOWAIT);
Packit ae235b
#elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
Packit ae235b
  num_mounts = getfsstat (NULL, 0, MNT_NOWAIT);
Packit ae235b
#endif
Packit ae235b
  if (num_mounts == -1)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  bufsize = num_mounts * sizeof (*mntent);
Packit ae235b
  mntent = g_malloc (bufsize);
Packit ae235b
#if defined(USE_STATVFS) && defined(HAVE_GETVFSSTAT)
Packit ae235b
  num_mounts = getvfsstat (mntent, bufsize, ST_NOWAIT);
Packit ae235b
#elif defined(USE_STATFS) && defined(HAVE_GETFSSTAT)
Packit ae235b
  num_mounts = getfsstat (mntent, bufsize, MNT_NOWAIT);
Packit ae235b
#endif
Packit ae235b
  if (num_mounts == -1)
Packit ae235b
    return NULL;
Packit ae235b
  
Packit ae235b
  return_list = NULL;
Packit ae235b
  
Packit ae235b
  for (i = 0; i < num_mounts; i++)
Packit ae235b
    {
Packit ae235b
      gboolean is_read_only = FALSE;
Packit ae235b
Packit ae235b
#if defined(USE_STATVFS)
Packit ae235b
      if (mntent[i].f_flag & ST_RDONLY)
Packit ae235b
#elif defined(USE_STATFS)
Packit ae235b
      if (mntent[i].f_flags & MNT_RDONLY)
Packit ae235b
#else
Packit ae235b
      #error statfs juggling failed
Packit ae235b
#endif
Packit ae235b
        is_read_only = TRUE;
Packit ae235b
Packit ae235b
      mount_entry = create_unix_mount_entry (mntent[i].f_mntfromname,
Packit ae235b
                                             mntent[i].f_mntonname,
Packit ae235b
                                             mntent[i].f_fstypename,
Packit ae235b
                                             is_read_only);
Packit ae235b
Packit ae235b
      return_list = g_list_prepend (return_list, mount_entry);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_free (mntent);
Packit ae235b
  
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* Interix {{{2 */
Packit ae235b
#elif defined(__INTERIX)
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
get_mtab_monitor_file (void)
Packit ae235b
{
Packit ae235b
  return NULL;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mounts (void)
Packit ae235b
{
Packit ae235b
  DIR *dirp;
Packit ae235b
  GList* return_list = NULL;
Packit ae235b
  char filename[9 + NAME_MAX];
Packit ae235b
Packit ae235b
  dirp = opendir ("/dev/fs");
Packit ae235b
  if (!dirp)
Packit ae235b
    {
Packit ae235b
      g_warning ("unable to read /dev/fs!");
Packit ae235b
      return NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  while (1)
Packit ae235b
    {
Packit ae235b
      struct statvfs statbuf;
Packit ae235b
      struct dirent entry;
Packit ae235b
      struct dirent* result;
Packit ae235b
      
Packit ae235b
      if (readdir_r (dirp, &entry, &result) || result == NULL)
Packit ae235b
        break;
Packit ae235b
      
Packit ae235b
      strcpy (filename, "/dev/fs/");
Packit ae235b
      strcat (filename, entry.d_name);
Packit ae235b
      
Packit ae235b
      if (statvfs (filename, &statbuf) == 0)
Packit ae235b
        {
Packit ae235b
          GUnixMountEntry* mount_entry = g_new0(GUnixMountEntry, 1);
Packit ae235b
          
Packit ae235b
          mount_entry->mount_path = g_strdup (statbuf.f_mntonname);
Packit ae235b
          mount_entry->device_path = g_strdup (statbuf.f_mntfromname);
Packit ae235b
          mount_entry->filesystem_type = g_strdup (statbuf.f_fstypename);
Packit ae235b
          
Packit ae235b
          if (statbuf.f_flag & ST_RDONLY)
Packit ae235b
            mount_entry->is_read_only = TRUE;
Packit ae235b
          
Packit ae235b
          return_list = g_list_prepend(return_list, mount_entry);
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  return_list = g_list_reverse (return_list);
Packit ae235b
  
Packit ae235b
  closedir (dirp);
Packit ae235b
Packit ae235b
  return return_list;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* Common code {{{2 */
Packit ae235b
#else
Packit ae235b
#error No _g_get_unix_mounts() implementation for system
Packit ae235b
#endif
Packit ae235b
Packit ae235b
/* GUnixMountPoints (ie: fstab) implementations {{{1 */
Packit ae235b
Packit ae235b
/* _g_get_unix_mount_points():
Packit ae235b
 * read the fstab.
Packit ae235b
 * don't return swap and ignore mounts.
Packit ae235b
 */
Packit ae235b
Packit ae235b
static char *
Packit ae235b
get_fstab_file (void)
Packit ae235b
{
Packit ae235b
#ifdef HAVE_LIBMOUNT
Packit ae235b
  return (char *) mnt_get_fstab_path ();
Packit ae235b
#else
Packit ae235b
#if defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
Packit ae235b
  /* AIX */
Packit ae235b
  return "/etc/filesystems";
Packit ae235b
#elif defined(_PATH_MNTTAB)
Packit ae235b
  return _PATH_MNTTAB;
Packit ae235b
#elif defined(VFSTAB)
Packit ae235b
  return VFSTAB;
Packit ae235b
#else
Packit ae235b
  return "/etc/fstab";
Packit ae235b
#endif
Packit ae235b
#endif
Packit ae235b
}
Packit ae235b
Packit ae235b
/* mntent.h (Linux, GNU, NSS) {{{2 */
Packit ae235b
#ifdef HAVE_MNTENT_H
Packit ae235b
Packit ae235b
#ifdef HAVE_LIBMOUNT
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mount_points (void)
Packit ae235b
{
Packit ae235b
  struct libmnt_table *table = NULL;
Packit ae235b
  struct libmnt_iter* iter = NULL;
Packit ae235b
  struct libmnt_fs *fs = NULL;
Packit ae235b
  GUnixMountPoint *mount_point = NULL;
Packit ae235b
  GList *return_list = NULL;
Packit ae235b
Packit ae235b
  table = mnt_new_table ();
Packit ae235b
  if (mnt_table_parse_fstab (table, NULL) < 0)
Packit ae235b
    goto out;
Packit ae235b
Packit ae235b
  iter = mnt_new_iter (MNT_ITER_FORWARD);
Packit ae235b
  while (mnt_table_next_fs (table, iter, &fs) == 0)
Packit ae235b
    {
Packit ae235b
      const char *device_path = NULL;
Packit ae235b
      const char *mount_path = NULL;
Packit ae235b
      const char *mount_fstype = NULL;
Packit ae235b
      char *mount_options = NULL;
Packit ae235b
      gboolean is_read_only = FALSE;
Packit ae235b
      gboolean is_user_mountable = FALSE;
Packit ae235b
      gboolean is_loopback = FALSE;
Packit ae235b
Packit ae235b
      mount_path = mnt_fs_get_target (fs);
Packit ae235b
      if ((strcmp (mount_path, "ignore") == 0) ||
Packit ae235b
          (strcmp (mount_path, "swap") == 0) ||
Packit ae235b
          (strcmp (mount_path, "none") == 0))
Packit ae235b
        continue;
Packit ae235b
Packit ae235b
      mount_fstype = mnt_fs_get_fstype (fs);
Packit ae235b
      mount_options = mnt_fs_strdup_options (fs);
Packit ae235b
      if (mount_options)
Packit ae235b
        {
Packit ae235b
          unsigned long mount_flags = 0;
Packit ae235b
          unsigned long userspace_flags = 0;
Packit ae235b
Packit ae235b
          mnt_optstr_get_flags (mount_options, &mount_flags, mnt_get_builtin_optmap (MNT_LINUX_MAP));
Packit ae235b
          mnt_optstr_get_flags (mount_options, &userspace_flags, mnt_get_builtin_optmap (MNT_USERSPACE_MAP));
Packit ae235b
Packit ae235b
          /* We ignore bind fstab entries, as we ignore bind mounts anyway */
Packit ae235b
          if (mount_flags & MS_BIND)
Packit ae235b
            {
Packit ae235b
              g_free (mount_options);
Packit ae235b
              continue;
Packit ae235b
            }
Packit ae235b
Packit ae235b
          is_read_only = (mount_flags & MS_RDONLY) != 0;
Packit ae235b
          is_loopback = (userspace_flags & MNT_MS_LOOP) != 0;
Packit ae235b
Packit ae235b
          if ((mount_fstype != NULL && g_strcmp0 ("supermount", mount_fstype) == 0) ||
Packit ae235b
              ((userspace_flags & MNT_MS_USER) &&
Packit ae235b
               (g_strstr_len (mount_options, -1, "user_xattr") == NULL)) ||
Packit ae235b
              (g_strstr_len (mount_options, -1, "pamconsole") == NULL) ||
Packit ae235b
              (userspace_flags & MNT_MS_USERS) ||
Packit ae235b
              (userspace_flags & MNT_MS_OWNER))
Packit ae235b
            {
Packit ae235b
              is_user_mountable = TRUE;
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
Packit ae235b
      device_path = mnt_fs_get_source (fs);
Packit ae235b
      if (g_strcmp0 (device_path, "/dev/root") == 0)
Packit ae235b
        device_path = _resolve_dev_root ();
Packit ae235b
Packit ae235b
      mount_point = create_unix_mount_point (device_path,
Packit ae235b
                                             mount_path,
Packit ae235b
                                             mount_fstype,
Packit ae235b
                                             mount_options,
Packit ae235b
                                             is_read_only,
Packit ae235b
                                             is_user_mountable,
Packit ae235b
                                             is_loopback);
Packit ae235b
      if (mount_options)
Packit ae235b
        g_free (mount_options);
Packit ae235b
Packit ae235b
      return_list = g_list_prepend (return_list, mount_point);
Packit ae235b
    }
Packit ae235b
  mnt_free_iter (iter);
Packit ae235b
Packit ae235b
 out:
Packit ae235b
  mnt_free_table (table);
Packit ae235b
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
#else
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mount_points (void)
Packit ae235b
{
Packit ae235b
#ifdef HAVE_GETMNTENT_R
Packit ae235b
  struct mntent ent;
Packit ae235b
  char buf[1024];
Packit ae235b
#endif
Packit ae235b
  struct mntent *mntent;
Packit ae235b
  FILE *file;
Packit ae235b
  char *read_file;
Packit ae235b
  GUnixMountPoint *mount_point;
Packit ae235b
  GList *return_list;
Packit ae235b
  
Packit ae235b
  read_file = get_fstab_file ();
Packit ae235b
  
Packit ae235b
  file = setmntent (read_file, "r");
Packit ae235b
  if (file == NULL)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  return_list = NULL;
Packit ae235b
  
Packit ae235b
#ifdef HAVE_GETMNTENT_R
Packit ae235b
  while ((mntent = getmntent_r (file, &ent, buf, sizeof (buf))) != NULL)
Packit ae235b
#else
Packit ae235b
  G_LOCK (getmntent);
Packit ae235b
  while ((mntent = getmntent (file)) != NULL)
Packit ae235b
#endif
Packit ae235b
    {
Packit ae235b
      const char *device_path = NULL;
Packit ae235b
      gboolean is_read_only = FALSE;
Packit ae235b
      gboolean is_user_mountable = FALSE;
Packit ae235b
      gboolean is_loopback = FALSE;
Packit ae235b
Packit ae235b
      if ((strcmp (mntent->mnt_dir, "ignore") == 0) ||
Packit ae235b
          (strcmp (mntent->mnt_dir, "swap") == 0) ||
Packit ae235b
          (strcmp (mntent->mnt_dir, "none") == 0))
Packit ae235b
	continue;
Packit ae235b
Packit ae235b
#ifdef HAVE_HASMNTOPT
Packit ae235b
      /* We ignore bind fstab entries, as we ignore bind mounts anyway */
Packit ae235b
      if (hasmntopt (mntent, "bind"))
Packit ae235b
        continue;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
      if (strcmp (mntent->mnt_fsname, "/dev/root") == 0)
Packit ae235b
        device_path = _resolve_dev_root ();
Packit ae235b
      else
Packit ae235b
        device_path = mntent->mnt_fsname;
Packit ae235b
Packit ae235b
#ifdef HAVE_HASMNTOPT
Packit ae235b
      if (hasmntopt (mntent, MNTOPT_RO) != NULL)
Packit ae235b
	is_read_only = TRUE;
Packit ae235b
Packit ae235b
      if (hasmntopt (mntent, "loop") != NULL)
Packit ae235b
	is_loopback = TRUE;
Packit ae235b
Packit ae235b
#endif
Packit ae235b
Packit ae235b
      if ((mntent->mnt_type != NULL && strcmp ("supermount", mntent->mnt_type) == 0)
Packit ae235b
#ifdef HAVE_HASMNTOPT
Packit ae235b
	  || (hasmntopt (mntent, "user") != NULL
Packit ae235b
	      && hasmntopt (mntent, "user") != hasmntopt (mntent, "user_xattr"))
Packit ae235b
	  || hasmntopt (mntent, "pamconsole") != NULL
Packit ae235b
	  || hasmntopt (mntent, "users") != NULL
Packit ae235b
	  || hasmntopt (mntent, "owner") != NULL
Packit ae235b
#endif
Packit ae235b
	  )
Packit ae235b
	is_user_mountable = TRUE;
Packit ae235b
Packit ae235b
      mount_point = create_unix_mount_point (device_path,
Packit ae235b
                                             mntent->mnt_dir,
Packit ae235b
                                             mntent->mnt_type,
Packit ae235b
                                             mntent->mnt_opts,
Packit ae235b
                                             is_read_only,
Packit ae235b
                                             is_user_mountable,
Packit ae235b
                                             is_loopback);
Packit ae235b
Packit ae235b
      return_list = g_list_prepend (return_list, mount_point);
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  endmntent (file);
Packit ae235b
Packit ae235b
#ifndef HAVE_GETMNTENT_R
Packit ae235b
  G_UNLOCK (getmntent);
Packit ae235b
#endif
Packit ae235b
  
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
#endif /* HAVE_LIBMOUNT */
Packit ae235b
Packit ae235b
/* mnttab.h {{{2 */
Packit ae235b
#elif defined (HAVE_SYS_MNTTAB_H)
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mount_points (void)
Packit ae235b
{
Packit ae235b
  struct mnttab mntent;
Packit ae235b
  FILE *file;
Packit ae235b
  char *read_file;
Packit ae235b
  GUnixMountPoint *mount_point;
Packit ae235b
  GList *return_list;
Packit ae235b
  
Packit ae235b
  read_file = get_fstab_file ();
Packit ae235b
  
Packit ae235b
  file = setmntent (read_file, "r");
Packit ae235b
  if (file == NULL)
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  return_list = NULL;
Packit ae235b
  
Packit ae235b
  G_LOCK (getmntent);
Packit ae235b
  while (! getmntent (file, &mntent))
Packit ae235b
    {
Packit ae235b
      gboolean is_read_only = FALSE;
Packit ae235b
      gboolean is_user_mountable = FALSE;
Packit ae235b
      gboolean is_loopback = FALSE;
Packit ae235b
Packit ae235b
      if ((strcmp (mntent.mnt_mountp, "ignore") == 0) ||
Packit ae235b
          (strcmp (mntent.mnt_mountp, "swap") == 0) ||
Packit ae235b
          (strcmp (mntent.mnt_mountp, "none") == 0))
Packit ae235b
	continue;
Packit ae235b
Packit ae235b
#ifdef HAVE_HASMNTOPT
Packit ae235b
      if (hasmntopt (&mntent, MNTOPT_RO) != NULL)
Packit ae235b
	is_read_only = TRUE;
Packit ae235b
Packit ae235b
      if (hasmntopt (&mntent, "lofs") != NULL)
Packit ae235b
	is_loopback = TRUE;
Packit ae235b
#endif
Packit ae235b
Packit ae235b
      if ((mntent.mnt_fstype != NULL)
Packit ae235b
#ifdef HAVE_HASMNTOPT
Packit ae235b
	  || (hasmntopt (&mntent, "user") != NULL
Packit ae235b
	      && hasmntopt (&mntent, "user") != hasmntopt (&mntent, "user_xattr"))
Packit ae235b
	  || hasmntopt (&mntent, "pamconsole") != NULL
Packit ae235b
	  || hasmntopt (&mntent, "users") != NULL
Packit ae235b
	  || hasmntopt (&mntent, "owner") != NULL
Packit ae235b
#endif
Packit ae235b
	  )
Packit ae235b
	is_user_mountable = TRUE;
Packit ae235b
Packit ae235b
      mount_point = create_unix_mount_point (mntent.mnt_special,
Packit ae235b
                                             mntent.mnt_mountp,
Packit ae235b
                                             mntent.mnt_fstype,
Packit ae235b
                                             mntent.mnt_mntopts,
Packit ae235b
                                             is_read_only,
Packit ae235b
                                             is_user_mountable,
Packit ae235b
                                             is_loopback);
Packit ae235b
Packit ae235b
      return_list = g_list_prepend (return_list, mount_point);
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  endmntent (file);
Packit ae235b
  G_UNLOCK (getmntent);
Packit ae235b
  
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
/* mntctl.h (AIX) {{{2 */
Packit ae235b
#elif defined(HAVE_SYS_MNTCTL_H) && defined(HAVE_SYS_VMOUNT_H) && defined(HAVE_SYS_VFS_H)
Packit ae235b
Packit ae235b
/* functions to parse /etc/filesystems on aix */
Packit ae235b
Packit ae235b
/* read character, ignoring comments (begin with '*', end with '\n' */
Packit ae235b
static int
Packit ae235b
aix_fs_getc (FILE *fd)
Packit ae235b
{
Packit ae235b
  int c;
Packit ae235b
  
Packit ae235b
  while ((c = getc (fd)) == '*')
Packit ae235b
    {
Packit ae235b
      while (((c = getc (fd)) != '\n') && (c != EOF))
Packit ae235b
	;
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
/* eat all continuous spaces in a file */
Packit ae235b
static int
Packit ae235b
aix_fs_ignorespace (FILE *fd)
Packit ae235b
{
Packit ae235b
  int c;
Packit ae235b
  
Packit ae235b
  while ((c = aix_fs_getc (fd)) != EOF)
Packit ae235b
    {
Packit ae235b
      if (!g_ascii_isspace (c))
Packit ae235b
	{
Packit ae235b
	  ungetc (c,fd);
Packit ae235b
	  return c;
Packit ae235b
	}
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  return EOF;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* read one word from file */
Packit ae235b
static int
Packit ae235b
aix_fs_getword (FILE *fd, 
Packit ae235b
                char *word)
Packit ae235b
{
Packit ae235b
  int c;
Packit ae235b
  
Packit ae235b
  aix_fs_ignorespace (fd);
Packit ae235b
Packit ae235b
  while (((c = aix_fs_getc (fd)) != EOF) && !g_ascii_isspace (c))
Packit ae235b
    {
Packit ae235b
      if (c == '"')
Packit ae235b
	{
Packit ae235b
	  while (((c = aix_fs_getc (fd)) != EOF) && (c != '"'))
Packit ae235b
	    *word++ = c;
Packit ae235b
	  else
Packit ae235b
	    *word++ = c;
Packit ae235b
	}
Packit ae235b
    }
Packit ae235b
  *word = 0;
Packit ae235b
  
Packit ae235b
  return c;
Packit ae235b
}
Packit ae235b
Packit ae235b
typedef struct {
Packit ae235b
  char mnt_mount[PATH_MAX];
Packit ae235b
  char mnt_special[PATH_MAX];
Packit ae235b
  char mnt_fstype[16];
Packit ae235b
  char mnt_options[128];
Packit ae235b
} AixMountTableEntry;
Packit ae235b
Packit ae235b
/* read mount points properties */
Packit ae235b
static int
Packit ae235b
aix_fs_get (FILE               *fd, 
Packit ae235b
            AixMountTableEntry *prop)
Packit ae235b
{
Packit ae235b
  static char word[PATH_MAX] = { 0 };
Packit ae235b
  char value[PATH_MAX];
Packit ae235b
  
Packit ae235b
  /* read stanza */
Packit ae235b
  if (word[0] == 0)
Packit ae235b
    {
Packit ae235b
      if (aix_fs_getword (fd, word) == EOF)
Packit ae235b
	return EOF;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  word[strlen(word) - 1] = 0;
Packit ae235b
  strcpy (prop->mnt_mount, word);
Packit ae235b
  
Packit ae235b
  /* read attributes and value */
Packit ae235b
  
Packit ae235b
  while (aix_fs_getword (fd, word) != EOF)
Packit ae235b
    {
Packit ae235b
      /* test if is attribute or new stanza */
Packit ae235b
      if (word[strlen(word) - 1] == ':')
Packit ae235b
	return 0;
Packit ae235b
      
Packit ae235b
      /* read "=" */
Packit ae235b
      aix_fs_getword (fd, value);
Packit ae235b
      
Packit ae235b
      /* read value */
Packit ae235b
      aix_fs_getword (fd, value);
Packit ae235b
      
Packit ae235b
      if (strcmp (word, "dev") == 0)
Packit ae235b
	strcpy (prop->mnt_special, value);
Packit ae235b
      else if (strcmp (word, "vfs") == 0)
Packit ae235b
	strcpy (prop->mnt_fstype, value);
Packit ae235b
      else if (strcmp (word, "options") == 0)
Packit ae235b
	strcpy(prop->mnt_options, value);
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  return 0;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mount_points (void)
Packit ae235b
{
Packit ae235b
  struct mntent *mntent;
Packit ae235b
  FILE *file;
Packit ae235b
  char *read_file;
Packit ae235b
  GUnixMountPoint *mount_point;
Packit ae235b
  AixMountTableEntry mntent;
Packit ae235b
  GList *return_list;
Packit ae235b
  
Packit ae235b
  read_file = get_fstab_file ();
Packit ae235b
  
Packit ae235b
  file = setmntent (read_file, "r");
Packit ae235b
  if (file == NULL)
Packit ae235b
    return NULL;
Packit ae235b
  
Packit ae235b
  return_list = NULL;
Packit ae235b
  
Packit ae235b
  while (!aix_fs_get (file, &mntent))
Packit ae235b
    {
Packit ae235b
      if (strcmp ("cdrfs", mntent.mnt_fstype) == 0)
Packit ae235b
	{
Packit ae235b
          mount_point = create_unix_mount_point (mntent.mnt_special,
Packit ae235b
                                                 mntent.mnt_mount,
Packit ae235b
                                                 mntent.mnt_fstype,
Packit ae235b
                                                 mntent.mnt_options,
Packit ae235b
                                                 TRUE,
Packit ae235b
                                                 TRUE,
Packit ae235b
                                                 FALSE);
Packit ae235b
Packit ae235b
	  return_list = g_list_prepend (return_list, mount_point);
Packit ae235b
	}
Packit ae235b
    }
Packit ae235b
	
Packit ae235b
  endmntent (file);
Packit ae235b
  
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
Packit ae235b
#elif (defined(HAVE_GETVFSSTAT) || defined(HAVE_GETFSSTAT)) && defined(HAVE_FSTAB_H) && defined(HAVE_SYS_MOUNT_H)
Packit ae235b
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mount_points (void)
Packit ae235b
{
Packit ae235b
  struct fstab *fstab = NULL;
Packit ae235b
  GUnixMountPoint *mount_point;
Packit ae235b
  GList *return_list;
Packit ae235b
#ifdef HAVE_SYS_SYSCTL_H
Packit ae235b
  int usermnt = 0;
Packit ae235b
  struct stat sb;
Packit ae235b
#endif
Packit ae235b
  
Packit ae235b
  if (!setfsent ())
Packit ae235b
    return NULL;
Packit ae235b
Packit ae235b
  return_list = NULL;
Packit ae235b
  
Packit ae235b
#ifdef HAVE_SYS_SYSCTL_H
Packit ae235b
#if defined(HAVE_SYSCTLBYNAME)
Packit ae235b
  {
Packit ae235b
    size_t len = sizeof(usermnt);
Packit ae235b
Packit ae235b
    sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
Packit ae235b
  }
Packit ae235b
#elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
Packit ae235b
  {
Packit ae235b
    int mib[2];
Packit ae235b
    size_t len = sizeof(usermnt);
Packit ae235b
    
Packit ae235b
    mib[0] = CTL_VFS;
Packit ae235b
    mib[1] = VFS_USERMOUNT;
Packit ae235b
    sysctl (mib, 2, &usermnt, &len, NULL, 0);
Packit ae235b
  }
Packit ae235b
#elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
Packit ae235b
  {
Packit ae235b
    int mib[2];
Packit ae235b
    size_t len = sizeof(usermnt);
Packit ae235b
    
Packit ae235b
    mib[0] = CTL_KERN;
Packit ae235b
    mib[1] = KERN_USERMOUNT;
Packit ae235b
    sysctl (mib, 2, &usermnt, &len, NULL, 0);
Packit ae235b
  }
Packit ae235b
#endif
Packit ae235b
#endif
Packit ae235b
  
Packit ae235b
  while ((fstab = getfsent ()) != NULL)
Packit ae235b
    {
Packit ae235b
      gboolean is_read_only = FALSE;
Packit ae235b
      gboolean is_user_mountable = FALSE;
Packit ae235b
Packit ae235b
      if (strcmp (fstab->fs_vfstype, "swap") == 0)
Packit ae235b
	continue;
Packit ae235b
Packit ae235b
      if (strcmp (fstab->fs_type, "ro") == 0)
Packit ae235b
	is_read_only = TRUE;
Packit ae235b
Packit ae235b
#ifdef HAVE_SYS_SYSCTL_H
Packit ae235b
      if (usermnt != 0)
Packit ae235b
	{
Packit ae235b
	  uid_t uid = getuid ();
Packit ae235b
	  if (stat (fstab->fs_file, &sb) == 0)
Packit ae235b
	    {
Packit ae235b
	      if (uid == 0 || sb.st_uid == uid)
Packit ae235b
		is_user_mountable = TRUE;
Packit ae235b
	    }
Packit ae235b
	}
Packit ae235b
#endif
Packit ae235b
Packit ae235b
      mount_point = create_unix_mount_point (fstab->fs_spec,
Packit ae235b
                                             fstab->fs_file,
Packit ae235b
                                             fstab->fs_vfstype,
Packit ae235b
                                             fstab->fs_mntops,
Packit ae235b
                                             is_read_only,
Packit ae235b
                                             is_user_mountable,
Packit ae235b
                                             FALSE);
Packit ae235b
Packit ae235b
      return_list = g_list_prepend (return_list, mount_point);
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  endfsent ();
Packit ae235b
  
Packit ae235b
  return g_list_reverse (return_list);
Packit ae235b
}
Packit ae235b
/* Interix {{{2 */
Packit ae235b
#elif defined(__INTERIX)
Packit ae235b
static GList *
Packit ae235b
_g_get_unix_mount_points (void)
Packit ae235b
{
Packit ae235b
  return _g_get_unix_mounts ();
Packit ae235b
}
Packit ae235b
Packit ae235b
/* Common code {{{2 */
Packit ae235b
#else
Packit ae235b
#error No g_get_mount_table() implementation for system
Packit ae235b
#endif
Packit ae235b
Packit ae235b
static guint64
Packit ae235b
get_mounts_timestamp (void)
Packit ae235b
{
Packit ae235b
  const char *monitor_file;
Packit ae235b
  struct stat buf;
Packit ae235b
Packit ae235b
  monitor_file = get_mtab_monitor_file ();
Packit ae235b
  /* Don't return mtime for /proc/ files */
Packit ae235b
  if (monitor_file && !g_str_has_prefix (monitor_file, "/proc/"))
Packit ae235b
    {
Packit ae235b
      if (stat (monitor_file, &buf) == 0)
Packit ae235b
        return (guint64)buf.st_mtime;
Packit ae235b
    }
Packit ae235b
  else if (proc_mounts_watch_is_running ())
Packit ae235b
    {
Packit ae235b
      /* it's being monitored by poll, so return mount_poller_time */
Packit ae235b
      return mount_poller_time;
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      /* Case of /proc/ file not being monitored - Be on the safe side and
Packit ae235b
       * send a new timestamp to force g_unix_mounts_changed_since() to
Packit ae235b
       * return TRUE so any application caches depending on it (like eg.
Packit ae235b
       * the one in GIO) get invalidated and don't hold possibly outdated
Packit ae235b
       * data - see Bug 787731 */
Packit ae235b
     return (guint64) g_get_monotonic_time ();
Packit ae235b
    }
Packit ae235b
  return 0;
Packit ae235b
}
Packit ae235b
Packit ae235b
static guint64
Packit ae235b
get_mount_points_timestamp (void)
Packit ae235b
{
Packit ae235b
  const char *monitor_file;
Packit ae235b
  struct stat buf;
Packit ae235b
Packit ae235b
  monitor_file = get_fstab_file ();
Packit ae235b
  if (monitor_file)
Packit ae235b
    {
Packit ae235b
      if (stat (monitor_file, &buf) == 0)
Packit ae235b
        return (guint64)buf.st_mtime;
Packit ae235b
    }
Packit ae235b
  return 0;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mounts_get:
Packit ae235b
 * @time_read: (out) (optional): guint64 to contain a timestamp, or %NULL
Packit ae235b
 *
Packit ae235b
 * Gets a #GList of #GUnixMountEntry containing the unix mounts.
Packit ae235b
 * If @time_read is set, it will be filled with the mount
Packit ae235b
 * timestamp, allowing for checking if the mounts have changed
Packit ae235b
 * with g_unix_mounts_changed_since().
Packit ae235b
 *
Packit ae235b
 * Returns: (element-type GUnixMountEntry) (transfer full):
Packit ae235b
 *     a #GList of the UNIX mounts.
Packit ae235b
 **/
Packit ae235b
GList *
Packit ae235b
g_unix_mounts_get (guint64 *time_read)
Packit ae235b
{
Packit ae235b
  if (time_read)
Packit ae235b
    *time_read = get_mounts_timestamp ();
Packit ae235b
Packit ae235b
  return _g_get_unix_mounts ();
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_at:
Packit ae235b
 * @mount_path: (type filename): path for a possible unix mount.
Packit ae235b
 * @time_read: (out) (optional): guint64 to contain a timestamp.
Packit ae235b
 * 
Packit ae235b
 * Gets a #GUnixMountEntry for a given mount path. If @time_read
Packit ae235b
 * is set, it will be filled with a unix timestamp for checking
Packit ae235b
 * if the mounts have changed since with g_unix_mounts_changed_since().
Packit ae235b
 * 
Packit ae235b
 * Returns: (transfer full): a #GUnixMountEntry.
Packit ae235b
 **/
Packit ae235b
GUnixMountEntry *
Packit ae235b
g_unix_mount_at (const char *mount_path,
Packit ae235b
		 guint64    *time_read)
Packit ae235b
{
Packit ae235b
  GList *mounts, *l;
Packit ae235b
  GUnixMountEntry *mount_entry, *found;
Packit ae235b
  
Packit ae235b
  mounts = g_unix_mounts_get (time_read);
Packit ae235b
Packit ae235b
  found = NULL;
Packit ae235b
  for (l = mounts; l != NULL; l = l->next)
Packit ae235b
    {
Packit ae235b
      mount_entry = l->data;
Packit ae235b
Packit ae235b
      if (!found && strcmp (mount_path, mount_entry->mount_path) == 0)
Packit ae235b
        found = mount_entry;
Packit ae235b
      else
Packit ae235b
        g_unix_mount_free (mount_entry);
Packit ae235b
    }
Packit ae235b
  g_list_free (mounts);
Packit ae235b
Packit ae235b
  return found;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_for:
Packit ae235b
 * @file_path: (type filename): file path on some unix mount.
Packit ae235b
 * @time_read: (out) (optional): guint64 to contain a timestamp.
Packit ae235b
 *
Packit ae235b
 * Gets a #GUnixMountEntry for a given file path. If @time_read
Packit ae235b
 * is set, it will be filled with a unix timestamp for checking
Packit ae235b
 * if the mounts have changed since with g_unix_mounts_changed_since().
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): a #GUnixMountEntry.
Packit ae235b
 *
Packit ae235b
 * Since: 2.52
Packit ae235b
 **/
Packit ae235b
GUnixMountEntry *
Packit ae235b
g_unix_mount_for (const char *file_path,
Packit ae235b
                  guint64    *time_read)
Packit ae235b
{
Packit ae235b
  GUnixMountEntry *entry;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (file_path != NULL, NULL);
Packit ae235b
Packit ae235b
  entry = g_unix_mount_at (file_path, time_read);
Packit ae235b
  if (entry == NULL)
Packit ae235b
    {
Packit ae235b
      char *topdir;
Packit ae235b
Packit ae235b
      topdir = _g_local_file_find_topdir_for (file_path);
Packit ae235b
      if (topdir != NULL)
Packit ae235b
        {
Packit ae235b
          entry = g_unix_mount_at (topdir, time_read);
Packit ae235b
          g_free (topdir);
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return entry;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_points_get:
Packit ae235b
 * @time_read: (out) (optional): guint64 to contain a timestamp.
Packit ae235b
 *
Packit ae235b
 * Gets a #GList of #GUnixMountPoint containing the unix mount points.
Packit ae235b
 * If @time_read is set, it will be filled with the mount timestamp,
Packit ae235b
 * allowing for checking if the mounts have changed with
Packit ae235b
 * g_unix_mount_points_changed_since().
Packit ae235b
 *
Packit ae235b
 * Returns: (element-type GUnixMountPoint) (transfer full):
Packit ae235b
 *     a #GList of the UNIX mountpoints.
Packit ae235b
 **/
Packit ae235b
GList *
Packit ae235b
g_unix_mount_points_get (guint64 *time_read)
Packit ae235b
{
Packit ae235b
  if (time_read)
Packit ae235b
    *time_read = get_mount_points_timestamp ();
Packit ae235b
Packit ae235b
  return _g_get_unix_mount_points ();
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mounts_changed_since:
Packit ae235b
 * @time: guint64 to contain a timestamp.
Packit ae235b
 * 
Packit ae235b
 * Checks if the unix mounts have changed since a given unix time.
Packit ae235b
 * 
Packit ae235b
 * Returns: %TRUE if the mounts have changed since @time. 
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_unix_mounts_changed_since (guint64 time)
Packit ae235b
{
Packit ae235b
  return get_mounts_timestamp () != time;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_points_changed_since:
Packit ae235b
 * @time: guint64 to contain a timestamp.
Packit ae235b
 * 
Packit ae235b
 * Checks if the unix mount points have changed since a given unix time.
Packit ae235b
 * 
Packit ae235b
 * Returns: %TRUE if the mount points have changed since @time. 
Packit ae235b
 **/
Packit ae235b
gboolean
Packit ae235b
g_unix_mount_points_changed_since (guint64 time)
Packit ae235b
{
Packit ae235b
  return get_mount_points_timestamp () != time;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* GUnixMountMonitor {{{1 */
Packit ae235b
Packit ae235b
enum {
Packit ae235b
  MOUNTS_CHANGED,
Packit ae235b
  MOUNTPOINTS_CHANGED,
Packit ae235b
  LAST_SIGNAL
Packit ae235b
};
Packit ae235b
Packit ae235b
static guint signals[LAST_SIGNAL];
Packit ae235b
Packit ae235b
struct _GUnixMountMonitor {
Packit ae235b
  GObject parent;
Packit ae235b
Packit ae235b
  GMainContext *context;
Packit ae235b
};
Packit ae235b
Packit ae235b
struct _GUnixMountMonitorClass {
Packit ae235b
  GObjectClass parent_class;
Packit ae235b
};
Packit ae235b
Packit ae235b
Packit ae235b
G_DEFINE_TYPE (GUnixMountMonitor, g_unix_mount_monitor, G_TYPE_OBJECT)
Packit ae235b
Packit ae235b
static GContextSpecificGroup  mount_monitor_group;
Packit ae235b
static GFileMonitor          *fstab_monitor;
Packit ae235b
static GFileMonitor          *mtab_monitor;
Packit ae235b
static GSource               *proc_mounts_watch_source;
Packit ae235b
static GList                 *mount_poller_mounts;
Packit ae235b
static guint                  mtab_file_changed_id;
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
proc_mounts_watch_is_running (void)
Packit ae235b
{
Packit ae235b
  return proc_mounts_watch_source != NULL &&
Packit ae235b
         !g_source_is_destroyed (proc_mounts_watch_source);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
fstab_file_changed (GFileMonitor      *monitor,
Packit ae235b
                    GFile             *file,
Packit ae235b
                    GFile             *other_file,
Packit ae235b
                    GFileMonitorEvent  event_type,
Packit ae235b
                    gpointer           user_data)
Packit ae235b
{
Packit ae235b
  if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
Packit ae235b
      event_type != G_FILE_MONITOR_EVENT_CREATED &&
Packit ae235b
      event_type != G_FILE_MONITOR_EVENT_DELETED)
Packit ae235b
    return;
Packit ae235b
Packit ae235b
  g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
mtab_file_changed_cb (gpointer user_data)
Packit ae235b
{
Packit ae235b
  mtab_file_changed_id = 0;
Packit ae235b
  g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
Packit ae235b
Packit ae235b
  return G_SOURCE_REMOVE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
mtab_file_changed (GFileMonitor      *monitor,
Packit ae235b
                   GFile             *file,
Packit ae235b
                   GFile             *other_file,
Packit ae235b
                   GFileMonitorEvent  event_type,
Packit ae235b
                   gpointer           user_data)
Packit ae235b
{
Packit ae235b
  if (event_type != G_FILE_MONITOR_EVENT_CHANGED &&
Packit ae235b
      event_type != G_FILE_MONITOR_EVENT_CREATED &&
Packit ae235b
      event_type != G_FILE_MONITOR_EVENT_DELETED)
Packit ae235b
    return;
Packit ae235b
Packit ae235b
  /* Skip accumulated events from file monitor which we are not able to handle
Packit ae235b
   * in a real time instead of emitting mounts_changed signal several times.
Packit ae235b
   * This should behave equally to GIOChannel based monitoring. See Bug 792235.
Packit ae235b
   */
Packit ae235b
  if (mtab_file_changed_id > 0)
Packit ae235b
    return;
Packit ae235b
Packit ae235b
  mtab_file_changed_id = g_idle_add (mtab_file_changed_cb, NULL);
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
proc_mounts_changed (GIOChannel   *channel,
Packit ae235b
                     GIOCondition  cond,
Packit ae235b
                     gpointer      user_data)
Packit ae235b
{
Packit ae235b
  if (cond & G_IO_ERR)
Packit ae235b
    {
Packit ae235b
      mount_poller_time = (guint64) g_get_monotonic_time ();
Packit ae235b
      g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
static gboolean
Packit ae235b
mount_change_poller (gpointer user_data)
Packit ae235b
{
Packit ae235b
  GList *current_mounts, *new_it, *old_it;
Packit ae235b
  gboolean has_changed = FALSE;
Packit ae235b
Packit ae235b
  current_mounts = _g_get_unix_mounts ();
Packit ae235b
Packit ae235b
  for ( new_it = current_mounts, old_it = mount_poller_mounts;
Packit ae235b
        new_it != NULL && old_it != NULL;
Packit ae235b
        new_it = g_list_next (new_it), old_it = g_list_next (old_it) )
Packit ae235b
    {
Packit ae235b
      if (g_unix_mount_compare (new_it->data, old_it->data) != 0)
Packit ae235b
        {
Packit ae235b
          has_changed = TRUE;
Packit ae235b
          break;
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  if (!(new_it == NULL && old_it == NULL))
Packit ae235b
    has_changed = TRUE;
Packit ae235b
Packit ae235b
  g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_free);
Packit ae235b
Packit ae235b
  mount_poller_mounts = current_mounts;
Packit ae235b
Packit ae235b
  if (has_changed)
Packit ae235b
    {
Packit ae235b
      mount_poller_time = (guint64) g_get_monotonic_time ();
Packit ae235b
      g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTPOINTS_CHANGED]);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return TRUE;
Packit ae235b
}
Packit ae235b
Packit ae235b
Packit ae235b
static void
Packit ae235b
mount_monitor_stop (void)
Packit ae235b
{
Packit ae235b
  if (fstab_monitor)
Packit ae235b
    {
Packit ae235b
      g_file_monitor_cancel (fstab_monitor);
Packit ae235b
      g_object_unref (fstab_monitor);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (proc_mounts_watch_source != NULL)
Packit ae235b
    {
Packit ae235b
      g_source_destroy (proc_mounts_watch_source);
Packit ae235b
      proc_mounts_watch_source = NULL;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (mtab_monitor)
Packit ae235b
    {
Packit ae235b
      g_file_monitor_cancel (mtab_monitor);
Packit ae235b
      g_object_unref (mtab_monitor);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  g_list_free_full (mount_poller_mounts, (GDestroyNotify) g_unix_mount_free);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
mount_monitor_start (void)
Packit ae235b
{
Packit ae235b
  GFile *file;
Packit ae235b
Packit ae235b
  if (get_fstab_file () != NULL)
Packit ae235b
    {
Packit ae235b
      file = g_file_new_for_path (get_fstab_file ());
Packit ae235b
      fstab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
Packit ae235b
      g_object_unref (file);
Packit ae235b
Packit ae235b
      g_signal_connect (fstab_monitor, "changed", (GCallback)fstab_file_changed, NULL);
Packit ae235b
    }
Packit ae235b
Packit ae235b
  if (get_mtab_monitor_file () != NULL)
Packit ae235b
    {
Packit ae235b
      const gchar *mtab_path;
Packit ae235b
Packit ae235b
      mtab_path = get_mtab_monitor_file ();
Packit ae235b
      /* Monitoring files in /proc/ is special - can't just use GFileMonitor.
Packit ae235b
       * See 'man proc' for more details.
Packit ae235b
       */
Packit ae235b
      if (g_str_has_prefix (mtab_path, "/proc/"))
Packit ae235b
        {
Packit ae235b
          GIOChannel *proc_mounts_channel;
Packit ae235b
          GError *error = NULL;
Packit ae235b
          proc_mounts_channel = g_io_channel_new_file (mtab_path, "r", &error);
Packit ae235b
          if (proc_mounts_channel == NULL)
Packit ae235b
            {
Packit ae235b
              g_warning ("Error creating IO channel for %s: %s (%s, %d)", mtab_path,
Packit ae235b
                         error->message, g_quark_to_string (error->domain), error->code);
Packit ae235b
              g_error_free (error);
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_ERR);
Packit ae235b
              g_source_set_callback (proc_mounts_watch_source,
Packit ae235b
                                     (GSourceFunc) proc_mounts_changed,
Packit ae235b
                                     NULL, NULL);
Packit ae235b
              g_source_attach (proc_mounts_watch_source,
Packit ae235b
                               g_main_context_get_thread_default ());
Packit ae235b
              g_source_unref (proc_mounts_watch_source);
Packit ae235b
              g_io_channel_unref (proc_mounts_channel);
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          file = g_file_new_for_path (mtab_path);
Packit ae235b
          mtab_monitor = g_file_monitor_file (file, 0, NULL, NULL);
Packit ae235b
          g_object_unref (file);
Packit ae235b
          g_signal_connect (mtab_monitor, "changed", (GCallback)mtab_file_changed, NULL);
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      proc_mounts_watch_source = g_timeout_source_new_seconds (3);
Packit ae235b
      mount_poller_mounts = _g_get_unix_mounts ();
Packit ae235b
      mount_poller_time = (guint64)g_get_monotonic_time ();
Packit ae235b
      g_source_set_callback (proc_mounts_watch_source,
Packit ae235b
                             mount_change_poller,
Packit ae235b
                             NULL, NULL);
Packit ae235b
      g_source_attach (proc_mounts_watch_source,
Packit ae235b
                       g_main_context_get_thread_default ());
Packit ae235b
      g_source_unref (proc_mounts_watch_source);
Packit ae235b
    }
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_unix_mount_monitor_finalize (GObject *object)
Packit ae235b
{
Packit ae235b
  GUnixMountMonitor *monitor;
Packit ae235b
Packit ae235b
  monitor = G_UNIX_MOUNT_MONITOR (object);
Packit ae235b
Packit ae235b
  g_context_specific_group_remove (&mount_monitor_group, monitor->context, monitor, mount_monitor_stop);
Packit ae235b
Packit ae235b
  G_OBJECT_CLASS (g_unix_mount_monitor_parent_class)->finalize (object);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_unix_mount_monitor_class_init (GUnixMountMonitorClass *klass)
Packit ae235b
{
Packit ae235b
  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
Packit ae235b
Packit ae235b
  gobject_class->finalize = g_unix_mount_monitor_finalize;
Packit ae235b
 
Packit ae235b
  /**
Packit ae235b
   * GUnixMountMonitor::mounts-changed:
Packit ae235b
   * @monitor: the object on which the signal is emitted
Packit ae235b
   * 
Packit ae235b
   * Emitted when the unix mounts have changed.
Packit ae235b
   */ 
Packit ae235b
  signals[MOUNTS_CHANGED] =
Packit ae235b
    g_signal_new (I_("mounts-changed"),
Packit ae235b
		  G_TYPE_FROM_CLASS (klass),
Packit ae235b
		  G_SIGNAL_RUN_LAST,
Packit ae235b
		  0,
Packit ae235b
		  NULL, NULL,
Packit ae235b
		  g_cclosure_marshal_VOID__VOID,
Packit ae235b
		  G_TYPE_NONE, 0);
Packit ae235b
Packit ae235b
  /**
Packit ae235b
   * GUnixMountMonitor::mountpoints-changed:
Packit ae235b
   * @monitor: the object on which the signal is emitted
Packit ae235b
   * 
Packit ae235b
   * Emitted when the unix mount points have changed.
Packit ae235b
   */
Packit ae235b
  signals[MOUNTPOINTS_CHANGED] =
Packit ae235b
    g_signal_new (I_("mountpoints-changed"),
Packit ae235b
		  G_TYPE_FROM_CLASS (klass),
Packit ae235b
		  G_SIGNAL_RUN_LAST,
Packit ae235b
		  0,
Packit ae235b
		  NULL, NULL,
Packit ae235b
		  g_cclosure_marshal_VOID__VOID,
Packit ae235b
		  G_TYPE_NONE, 0);
Packit ae235b
}
Packit ae235b
Packit ae235b
static void
Packit ae235b
g_unix_mount_monitor_init (GUnixMountMonitor *monitor)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_monitor_set_rate_limit:
Packit ae235b
 * @mount_monitor: a #GUnixMountMonitor
Packit ae235b
 * @limit_msec: a integer with the limit in milliseconds to
Packit ae235b
 *     poll for changes.
Packit ae235b
 *
Packit ae235b
 * This function does nothing.
Packit ae235b
 *
Packit ae235b
 * Before 2.44, this was a partially-effective way of controlling the
Packit ae235b
 * rate at which events would be reported under some uncommon
Packit ae235b
 * circumstances.  Since @mount_monitor is a singleton, it also meant
Packit ae235b
 * that calling this function would have side effects for other users of
Packit ae235b
 * the monitor.
Packit ae235b
 *
Packit ae235b
 * Since: 2.18
Packit ae235b
 *
Packit ae235b
 * Deprecated:2.44:This function does nothing.  Don't call it.
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount_monitor,
Packit ae235b
                                     gint               limit_msec)
Packit ae235b
{
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_monitor_get:
Packit ae235b
 *
Packit ae235b
 * Gets the #GUnixMountMonitor for the current thread-default main
Packit ae235b
 * context.
Packit ae235b
 *
Packit ae235b
 * The mount monitor can be used to monitor for changes to the list of
Packit ae235b
 * mounted filesystems as well as the list of mount points (ie: fstab
Packit ae235b
 * entries).
Packit ae235b
 *
Packit ae235b
 * You must only call g_object_unref() on the return value from under
Packit ae235b
 * the same main context as you called this function.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): the #GUnixMountMonitor.
Packit ae235b
 *
Packit ae235b
 * Since: 2.44
Packit ae235b
 **/
Packit ae235b
GUnixMountMonitor *
Packit ae235b
g_unix_mount_monitor_get (void)
Packit ae235b
{
Packit ae235b
  return g_context_specific_group_get (&mount_monitor_group,
Packit ae235b
                                       G_TYPE_UNIX_MOUNT_MONITOR,
Packit ae235b
                                       G_STRUCT_OFFSET(GUnixMountMonitor, context),
Packit ae235b
                                       mount_monitor_start);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_monitor_new:
Packit ae235b
 *
Packit ae235b
 * Deprecated alias for g_unix_mount_monitor_get().
Packit ae235b
 *
Packit ae235b
 * This function was never a true constructor, which is why it was
Packit ae235b
 * renamed.
Packit ae235b
 *
Packit ae235b
 * Returns: a #GUnixMountMonitor.
Packit ae235b
 *
Packit ae235b
 * Deprecated:2.44:Use g_unix_mount_monitor_get() instead.
Packit ae235b
 */
Packit ae235b
GUnixMountMonitor *
Packit ae235b
g_unix_mount_monitor_new (void)
Packit ae235b
{
Packit ae235b
  return g_unix_mount_monitor_get ();
Packit ae235b
}
Packit ae235b
Packit ae235b
/* GUnixMount {{{1 */
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_free:
Packit ae235b
 * @mount_entry: a #GUnixMountEntry.
Packit ae235b
 * 
Packit ae235b
 * Frees a unix mount.
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_unix_mount_free (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (mount_entry != NULL);
Packit ae235b
Packit ae235b
  g_free (mount_entry->mount_path);
Packit ae235b
  g_free (mount_entry->device_path);
Packit ae235b
  g_free (mount_entry->filesystem_type);
Packit ae235b
  g_free (mount_entry);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_copy:
Packit ae235b
 * @mount_entry: a #GUnixMountEntry.
Packit ae235b
 *
Packit ae235b
 * Makes a copy of @mount_entry.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): a new #GUnixMountEntry
Packit ae235b
 *
Packit ae235b
 * Since: 2.54
Packit ae235b
 */
Packit ae235b
GUnixMountEntry *
Packit ae235b
g_unix_mount_copy (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  GUnixMountEntry *copy;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (mount_entry != NULL, NULL);
Packit ae235b
Packit ae235b
  copy = g_new0 (GUnixMountEntry, 1);
Packit ae235b
  copy->mount_path = g_strdup (mount_entry->mount_path);
Packit ae235b
  copy->device_path = g_strdup (mount_entry->device_path);
Packit ae235b
  copy->filesystem_type = g_strdup (mount_entry->filesystem_type);
Packit ae235b
  copy->is_read_only = mount_entry->is_read_only;
Packit ae235b
  copy->is_system_internal = mount_entry->is_system_internal;
Packit ae235b
Packit ae235b
  return copy;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_free:
Packit ae235b
 * @mount_point: unix mount point to free.
Packit ae235b
 * 
Packit ae235b
 * Frees a unix mount point.
Packit ae235b
 */
Packit ae235b
void
Packit ae235b
g_unix_mount_point_free (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  g_return_if_fail (mount_point != NULL);
Packit ae235b
Packit ae235b
  g_free (mount_point->mount_path);
Packit ae235b
  g_free (mount_point->device_path);
Packit ae235b
  g_free (mount_point->filesystem_type);
Packit ae235b
  g_free (mount_point->options);
Packit ae235b
  g_free (mount_point);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_copy:
Packit ae235b
 * @mount_point: a #GUnixMountPoint.
Packit ae235b
 *
Packit ae235b
 * Makes a copy of @mount_point.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): a new #GUnixMountPoint
Packit ae235b
 *
Packit ae235b
 * Since: 2.54
Packit ae235b
 */
Packit ae235b
GUnixMountPoint*
Packit ae235b
g_unix_mount_point_copy (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  GUnixMountPoint *copy;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (mount_point != NULL, NULL);
Packit ae235b
Packit ae235b
  copy = g_new0 (GUnixMountPoint, 1);
Packit ae235b
  copy->mount_path = g_strdup (mount_point->mount_path);
Packit ae235b
  copy->device_path = g_strdup (mount_point->device_path);
Packit ae235b
  copy->filesystem_type = g_strdup (mount_point->filesystem_type);
Packit ae235b
  copy->options = g_strdup (mount_point->options);
Packit ae235b
  copy->is_read_only = mount_point->is_read_only;
Packit ae235b
  copy->is_user_mountable = mount_point->is_user_mountable;
Packit ae235b
  copy->is_loopback = mount_point->is_loopback;
Packit ae235b
Packit ae235b
  return copy;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_compare:
Packit ae235b
 * @mount1: first #GUnixMountEntry to compare.
Packit ae235b
 * @mount2: second #GUnixMountEntry to compare.
Packit ae235b
 * 
Packit ae235b
 * Compares two unix mounts.
Packit ae235b
 * 
Packit ae235b
 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
Packit ae235b
 * or less than @mount2, respectively. 
Packit ae235b
 */
Packit ae235b
gint
Packit ae235b
g_unix_mount_compare (GUnixMountEntry *mount1,
Packit ae235b
		      GUnixMountEntry *mount2)
Packit ae235b
{
Packit ae235b
  int res;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
Packit ae235b
  
Packit ae235b
  res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
Packit ae235b
  if (res != 0)
Packit ae235b
    return res;
Packit ae235b
	
Packit ae235b
  res = g_strcmp0 (mount1->device_path, mount2->device_path);
Packit ae235b
  if (res != 0)
Packit ae235b
    return res;
Packit ae235b
	
Packit ae235b
  res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
Packit ae235b
  if (res != 0)
Packit ae235b
    return res;
Packit ae235b
Packit ae235b
  res =  mount1->is_read_only - mount2->is_read_only;
Packit ae235b
  if (res != 0)
Packit ae235b
    return res;
Packit ae235b
  
Packit ae235b
  return 0;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_get_mount_path:
Packit ae235b
 * @mount_entry: input #GUnixMountEntry to get the mount path for.
Packit ae235b
 * 
Packit ae235b
 * Gets the mount path for a unix mount.
Packit ae235b
 * 
Packit ae235b
 * Returns: (type filename): the mount path for @mount_entry.
Packit ae235b
 */
Packit ae235b
const gchar *
Packit ae235b
g_unix_mount_get_mount_path (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_entry != NULL, NULL);
Packit ae235b
Packit ae235b
  return mount_entry->mount_path;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_get_device_path:
Packit ae235b
 * @mount_entry: a #GUnixMount.
Packit ae235b
 * 
Packit ae235b
 * Gets the device path for a unix mount.
Packit ae235b
 * 
Packit ae235b
 * Returns: (type filename): a string containing the device path.
Packit ae235b
 */
Packit ae235b
const gchar *
Packit ae235b
g_unix_mount_get_device_path (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_entry != NULL, NULL);
Packit ae235b
Packit ae235b
  return mount_entry->device_path;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_get_fs_type:
Packit ae235b
 * @mount_entry: a #GUnixMount.
Packit ae235b
 * 
Packit ae235b
 * Gets the filesystem type for the unix mount.
Packit ae235b
 * 
Packit ae235b
 * Returns: a string containing the file system type.
Packit ae235b
 */
Packit ae235b
const gchar *
Packit ae235b
g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_entry != NULL, NULL);
Packit ae235b
Packit ae235b
  return mount_entry->filesystem_type;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_is_readonly:
Packit ae235b
 * @mount_entry: a #GUnixMount.
Packit ae235b
 * 
Packit ae235b
 * Checks if a unix mount is mounted read only.
Packit ae235b
 * 
Packit ae235b
 * Returns: %TRUE if @mount_entry is read only.
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_mount_is_readonly (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_entry != NULL, FALSE);
Packit ae235b
Packit ae235b
  return mount_entry->is_read_only;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_is_system_internal:
Packit ae235b
 * @mount_entry: a #GUnixMount.
Packit ae235b
 *
Packit ae235b
 * Checks if a Unix mount is a system mount. This is the Boolean OR of
Packit ae235b
 * g_unix_is_system_fs_type(), g_unix_is_system_device_path() and
Packit ae235b
 * g_unix_is_mount_path_system_internal() on @mount_entry’s properties.
Packit ae235b
 * 
Packit ae235b
 * The definition of what a ‘system’ mount entry is may change over time as new
Packit ae235b
 * file system types and device paths are ignored.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if the unix mount is for a system path.
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_mount_is_system_internal (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_entry != NULL, FALSE);
Packit ae235b
Packit ae235b
  return mount_entry->is_system_internal;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* GUnixMountPoint {{{1 */
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_compare:
Packit ae235b
 * @mount1: a #GUnixMount.
Packit ae235b
 * @mount2: a #GUnixMount.
Packit ae235b
 * 
Packit ae235b
 * Compares two unix mount points.
Packit ae235b
 * 
Packit ae235b
 * Returns: 1, 0 or -1 if @mount1 is greater than, equal to,
Packit ae235b
 * or less than @mount2, respectively.
Packit ae235b
 */
Packit ae235b
gint
Packit ae235b
g_unix_mount_point_compare (GUnixMountPoint *mount1,
Packit ae235b
			    GUnixMountPoint *mount2)
Packit ae235b
{
Packit ae235b
  int res;
Packit ae235b
Packit ae235b
  g_return_val_if_fail (mount1 != NULL && mount2 != NULL, 0);
Packit ae235b
Packit ae235b
  res = g_strcmp0 (mount1->mount_path, mount2->mount_path);
Packit ae235b
  if (res != 0) 
Packit ae235b
    return res;
Packit ae235b
	
Packit ae235b
  res = g_strcmp0 (mount1->device_path, mount2->device_path);
Packit ae235b
  if (res != 0) 
Packit ae235b
    return res;
Packit ae235b
	
Packit ae235b
  res = g_strcmp0 (mount1->filesystem_type, mount2->filesystem_type);
Packit ae235b
  if (res != 0) 
Packit ae235b
    return res;
Packit ae235b
Packit ae235b
  res = g_strcmp0 (mount1->options, mount2->options);
Packit ae235b
  if (res != 0) 
Packit ae235b
    return res;
Packit ae235b
Packit ae235b
  res =  mount1->is_read_only - mount2->is_read_only;
Packit ae235b
  if (res != 0) 
Packit ae235b
    return res;
Packit ae235b
Packit ae235b
  res = mount1->is_user_mountable - mount2->is_user_mountable;
Packit ae235b
  if (res != 0) 
Packit ae235b
    return res;
Packit ae235b
Packit ae235b
  res = mount1->is_loopback - mount2->is_loopback;
Packit ae235b
  if (res != 0)
Packit ae235b
    return res;
Packit ae235b
  
Packit ae235b
  return 0;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_get_mount_path:
Packit ae235b
 * @mount_point: a #GUnixMountPoint.
Packit ae235b
 * 
Packit ae235b
 * Gets the mount path for a unix mount point.
Packit ae235b
 * 
Packit ae235b
 * Returns: (type filename): a string containing the mount path.
Packit ae235b
 */
Packit ae235b
const gchar *
Packit ae235b
g_unix_mount_point_get_mount_path (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_point != NULL, NULL);
Packit ae235b
Packit ae235b
  return mount_point->mount_path;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_get_device_path:
Packit ae235b
 * @mount_point: a #GUnixMountPoint.
Packit ae235b
 * 
Packit ae235b
 * Gets the device path for a unix mount point.
Packit ae235b
 * 
Packit ae235b
 * Returns: (type filename): a string containing the device path.
Packit ae235b
 */
Packit ae235b
const gchar *
Packit ae235b
g_unix_mount_point_get_device_path (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_point != NULL, NULL);
Packit ae235b
Packit ae235b
  return mount_point->device_path;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_get_fs_type:
Packit ae235b
 * @mount_point: a #GUnixMountPoint.
Packit ae235b
 * 
Packit ae235b
 * Gets the file system type for the mount point.
Packit ae235b
 * 
Packit ae235b
 * Returns: a string containing the file system type.
Packit ae235b
 */
Packit ae235b
const gchar *
Packit ae235b
g_unix_mount_point_get_fs_type (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_point != NULL, NULL);
Packit ae235b
Packit ae235b
  return mount_point->filesystem_type;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_get_options:
Packit ae235b
 * @mount_point: a #GUnixMountPoint.
Packit ae235b
 * 
Packit ae235b
 * Gets the options for the mount point.
Packit ae235b
 * 
Packit ae235b
 * Returns: a string containing the options.
Packit ae235b
 *
Packit ae235b
 * Since: 2.32
Packit ae235b
 */
Packit ae235b
const gchar *
Packit ae235b
g_unix_mount_point_get_options (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_point != NULL, NULL);
Packit ae235b
Packit ae235b
  return mount_point->options;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_is_readonly:
Packit ae235b
 * @mount_point: a #GUnixMountPoint.
Packit ae235b
 * 
Packit ae235b
 * Checks if a unix mount point is read only.
Packit ae235b
 * 
Packit ae235b
 * Returns: %TRUE if a mount point is read only.
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_mount_point_is_readonly (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_point != NULL, FALSE);
Packit ae235b
Packit ae235b
  return mount_point->is_read_only;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_is_user_mountable:
Packit ae235b
 * @mount_point: a #GUnixMountPoint.
Packit ae235b
 * 
Packit ae235b
 * Checks if a unix mount point is mountable by the user.
Packit ae235b
 * 
Packit ae235b
 * Returns: %TRUE if the mount point is user mountable.
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_mount_point_is_user_mountable (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_point != NULL, FALSE);
Packit ae235b
Packit ae235b
  return mount_point->is_user_mountable;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_is_loopback:
Packit ae235b
 * @mount_point: a #GUnixMountPoint.
Packit ae235b
 * 
Packit ae235b
 * Checks if a unix mount point is a loopback device.
Packit ae235b
 * 
Packit ae235b
 * Returns: %TRUE if the mount point is a loopback. %FALSE otherwise. 
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_mount_point_is_loopback (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_point != NULL, FALSE);
Packit ae235b
Packit ae235b
  return mount_point->is_loopback;
Packit ae235b
}
Packit ae235b
Packit ae235b
static GUnixMountType
Packit ae235b
guess_mount_type (const char *mount_path,
Packit ae235b
		  const char *device_path,
Packit ae235b
		  const char *filesystem_type)
Packit ae235b
{
Packit ae235b
  GUnixMountType type;
Packit ae235b
  char *basename;
Packit ae235b
Packit ae235b
  type = G_UNIX_MOUNT_TYPE_UNKNOWN;
Packit ae235b
  
Packit ae235b
  if ((strcmp (filesystem_type, "udf") == 0) ||
Packit ae235b
      (strcmp (filesystem_type, "iso9660") == 0) ||
Packit ae235b
      (strcmp (filesystem_type, "cd9660") == 0))
Packit ae235b
    type = G_UNIX_MOUNT_TYPE_CDROM;
Packit ae235b
  else if ((strcmp (filesystem_type, "nfs") == 0) ||
Packit ae235b
           (strcmp (filesystem_type, "nfs4") == 0))
Packit ae235b
    type = G_UNIX_MOUNT_TYPE_NFS;
Packit ae235b
  else if (g_str_has_prefix (device_path, "/vol/dev/diskette/") ||
Packit ae235b
	   g_str_has_prefix (device_path, "/dev/fd") ||
Packit ae235b
	   g_str_has_prefix (device_path, "/dev/floppy"))
Packit ae235b
    type = G_UNIX_MOUNT_TYPE_FLOPPY;
Packit ae235b
  else if (g_str_has_prefix (device_path, "/dev/cdrom") ||
Packit ae235b
	   g_str_has_prefix (device_path, "/dev/acd") ||
Packit ae235b
	   g_str_has_prefix (device_path, "/dev/cd"))
Packit ae235b
    type = G_UNIX_MOUNT_TYPE_CDROM;
Packit ae235b
  else if (g_str_has_prefix (device_path, "/vol/"))
Packit ae235b
    {
Packit ae235b
      const char *name = mount_path + strlen ("/");
Packit ae235b
      
Packit ae235b
      if (g_str_has_prefix (name, "cdrom"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_CDROM;
Packit ae235b
      else if (g_str_has_prefix (name, "floppy") ||
Packit ae235b
	       g_str_has_prefix (device_path, "/vol/dev/diskette/")) 
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_FLOPPY;
Packit ae235b
      else if (g_str_has_prefix (name, "rmdisk")) 
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_ZIP;
Packit ae235b
      else if (g_str_has_prefix (name, "jaz"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_JAZ;
Packit ae235b
      else if (g_str_has_prefix (name, "memstick"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_MEMSTICK;
Packit ae235b
    }
Packit ae235b
  else
Packit ae235b
    {
Packit ae235b
      basename = g_path_get_basename (mount_path);
Packit ae235b
      
Packit ae235b
      if (g_str_has_prefix (basename, "cdr") ||
Packit ae235b
	  g_str_has_prefix (basename, "cdwriter") ||
Packit ae235b
	  g_str_has_prefix (basename, "burn") ||
Packit ae235b
	  g_str_has_prefix (basename, "dvdr"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_CDROM;
Packit ae235b
      else if (g_str_has_prefix (basename, "floppy"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_FLOPPY;
Packit ae235b
      else if (g_str_has_prefix (basename, "zip"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_ZIP;
Packit ae235b
      else if (g_str_has_prefix (basename, "jaz"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_JAZ;
Packit ae235b
      else if (g_str_has_prefix (basename, "camera"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_CAMERA;
Packit ae235b
      else if (g_str_has_prefix (basename, "memstick") ||
Packit ae235b
	       g_str_has_prefix (basename, "memory_stick") ||
Packit ae235b
	       g_str_has_prefix (basename, "ram"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_MEMSTICK;
Packit ae235b
      else if (g_str_has_prefix (basename, "compact_flash"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_CF;
Packit ae235b
      else if (g_str_has_prefix (basename, "smart_media"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_SM;
Packit ae235b
      else if (g_str_has_prefix (basename, "sd_mmc"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_SDMMC;
Packit ae235b
      else if (g_str_has_prefix (basename, "ipod"))
Packit ae235b
	type = G_UNIX_MOUNT_TYPE_IPOD;
Packit ae235b
      
Packit ae235b
      g_free (basename);
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  if (type == G_UNIX_MOUNT_TYPE_UNKNOWN)
Packit ae235b
    type = G_UNIX_MOUNT_TYPE_HD;
Packit ae235b
  
Packit ae235b
  return type;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_guess_type:
Packit ae235b
 * @mount_entry: a #GUnixMount.
Packit ae235b
 * 
Packit ae235b
 * Guesses the type of a unix mount. If the mount type cannot be 
Packit ae235b
 * determined, returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
Packit ae235b
 * 
Packit ae235b
 * Returns: a #GUnixMountType. 
Packit ae235b
 */
Packit ae235b
static GUnixMountType
Packit ae235b
g_unix_mount_guess_type (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_entry != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
Packit ae235b
  g_return_val_if_fail (mount_entry->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
Packit ae235b
  g_return_val_if_fail (mount_entry->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
Packit ae235b
  g_return_val_if_fail (mount_entry->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
Packit ae235b
Packit ae235b
  return guess_mount_type (mount_entry->mount_path,
Packit ae235b
			   mount_entry->device_path,
Packit ae235b
			   mount_entry->filesystem_type);
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_guess_type:
Packit ae235b
 * @mount_point: a #GUnixMountPoint.
Packit ae235b
 * 
Packit ae235b
 * Guesses the type of a unix mount point. 
Packit ae235b
 * If the mount type cannot be determined, 
Packit ae235b
 * returns %G_UNIX_MOUNT_TYPE_UNKNOWN.
Packit ae235b
 * 
Packit ae235b
 * Returns: a #GUnixMountType.
Packit ae235b
 */
Packit ae235b
static GUnixMountType
Packit ae235b
g_unix_mount_point_guess_type (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  g_return_val_if_fail (mount_point != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
Packit ae235b
  g_return_val_if_fail (mount_point->mount_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
Packit ae235b
  g_return_val_if_fail (mount_point->device_path != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
Packit ae235b
  g_return_val_if_fail (mount_point->filesystem_type != NULL, G_UNIX_MOUNT_TYPE_UNKNOWN);
Packit ae235b
Packit ae235b
  return guess_mount_type (mount_point->mount_path,
Packit ae235b
			   mount_point->device_path,
Packit ae235b
			   mount_point->filesystem_type);
Packit ae235b
}
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
type_to_icon (GUnixMountType type, gboolean is_mount_point, gboolean use_symbolic)
Packit ae235b
{
Packit ae235b
  const char *icon_name;
Packit ae235b
  
Packit ae235b
  switch (type)
Packit ae235b
    {
Packit ae235b
    case G_UNIX_MOUNT_TYPE_HD:
Packit ae235b
      if (is_mount_point)
Packit ae235b
        icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
Packit ae235b
      else
Packit ae235b
        icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
Packit ae235b
      break;
Packit ae235b
    case G_UNIX_MOUNT_TYPE_FLOPPY:
Packit ae235b
    case G_UNIX_MOUNT_TYPE_ZIP:
Packit ae235b
    case G_UNIX_MOUNT_TYPE_JAZ:
Packit ae235b
      if (is_mount_point)
Packit ae235b
        icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
Packit ae235b
      else
Packit ae235b
        icon_name = use_symbolic ? "media-removable-symbolic" : "media-floppy";
Packit ae235b
      break;
Packit ae235b
    case G_UNIX_MOUNT_TYPE_CDROM:
Packit ae235b
      if (is_mount_point)
Packit ae235b
        icon_name = use_symbolic ? "drive-optical-symbolic" : "drive-optical";
Packit ae235b
      else
Packit ae235b
        icon_name = use_symbolic ? "media-optical-symbolic" : "media-optical";
Packit ae235b
      break;
Packit ae235b
    case G_UNIX_MOUNT_TYPE_NFS:
Packit ae235b
        icon_name = use_symbolic ? "folder-remote-symbolic" : "folder-remote";
Packit ae235b
      break;
Packit ae235b
    case G_UNIX_MOUNT_TYPE_MEMSTICK:
Packit ae235b
      if (is_mount_point)
Packit ae235b
        icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
Packit ae235b
      else
Packit ae235b
        icon_name = use_symbolic ? "media-removable-symbolic" : "media-flash";
Packit ae235b
      break;
Packit ae235b
    case G_UNIX_MOUNT_TYPE_CAMERA:
Packit ae235b
      if (is_mount_point)
Packit ae235b
        icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
Packit ae235b
      else
Packit ae235b
        icon_name = use_symbolic ? "camera-photo-symbolic" : "camera-photo";
Packit ae235b
      break;
Packit ae235b
    case G_UNIX_MOUNT_TYPE_IPOD:
Packit ae235b
      if (is_mount_point)
Packit ae235b
        icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
Packit ae235b
      else
Packit ae235b
        icon_name = use_symbolic ? "multimedia-player-symbolic" : "multimedia-player";
Packit ae235b
      break;
Packit ae235b
    case G_UNIX_MOUNT_TYPE_UNKNOWN:
Packit ae235b
    default:
Packit ae235b
      if (is_mount_point)
Packit ae235b
        icon_name = use_symbolic ? "drive-removable-media-symbolic" : "drive-removable-media";
Packit ae235b
      else
Packit ae235b
        icon_name = use_symbolic ? "drive-harddisk-symbolic" : "drive-harddisk";
Packit ae235b
      break;
Packit ae235b
    }
Packit ae235b
Packit ae235b
  return icon_name;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_guess_name:
Packit ae235b
 * @mount_entry: a #GUnixMountEntry
Packit ae235b
 * 
Packit ae235b
 * Guesses the name of a Unix mount. 
Packit ae235b
 * The result is a translated string.
Packit ae235b
 *
Packit ae235b
 * Returns: A newly allocated string that must
Packit ae235b
 *     be freed with g_free()
Packit ae235b
 */
Packit ae235b
gchar *
Packit ae235b
g_unix_mount_guess_name (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  char *name;
Packit ae235b
Packit ae235b
  if (strcmp (mount_entry->mount_path, "/") == 0)
Packit ae235b
    name = g_strdup (_("Filesystem root"));
Packit ae235b
  else
Packit ae235b
    name = g_filename_display_basename (mount_entry->mount_path);
Packit ae235b
Packit ae235b
  return name;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_guess_icon:
Packit ae235b
 * @mount_entry: a #GUnixMountEntry
Packit ae235b
 * 
Packit ae235b
 * Guesses the icon of a Unix mount. 
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): a #GIcon
Packit ae235b
 */
Packit ae235b
GIcon *
Packit ae235b
g_unix_mount_guess_icon (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE, FALSE));
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_guess_symbolic_icon:
Packit ae235b
 * @mount_entry: a #GUnixMountEntry
Packit ae235b
 *
Packit ae235b
 * Guesses the symbolic icon of a Unix mount.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): a #GIcon
Packit ae235b
 *
Packit ae235b
 * Since: 2.34
Packit ae235b
 */
Packit ae235b
GIcon *
Packit ae235b
g_unix_mount_guess_symbolic_icon (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_guess_type (mount_entry), FALSE, TRUE));
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_guess_name:
Packit ae235b
 * @mount_point: a #GUnixMountPoint
Packit ae235b
 * 
Packit ae235b
 * Guesses the name of a Unix mount point. 
Packit ae235b
 * The result is a translated string.
Packit ae235b
 *
Packit ae235b
 * Returns: A newly allocated string that must 
Packit ae235b
 *     be freed with g_free()
Packit ae235b
 */
Packit ae235b
gchar *
Packit ae235b
g_unix_mount_point_guess_name (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  char *name;
Packit ae235b
Packit ae235b
  if (strcmp (mount_point->mount_path, "/") == 0)
Packit ae235b
    name = g_strdup (_("Filesystem root"));
Packit ae235b
  else
Packit ae235b
    name = g_filename_display_basename (mount_point->mount_path);
Packit ae235b
Packit ae235b
  return name;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_guess_icon:
Packit ae235b
 * @mount_point: a #GUnixMountPoint
Packit ae235b
 * 
Packit ae235b
 * Guesses the icon of a Unix mount point. 
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): a #GIcon
Packit ae235b
 */
Packit ae235b
GIcon *
Packit ae235b
g_unix_mount_point_guess_icon (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, FALSE));
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_guess_symbolic_icon:
Packit ae235b
 * @mount_point: a #GUnixMountPoint
Packit ae235b
 *
Packit ae235b
 * Guesses the symbolic icon of a Unix mount point.
Packit ae235b
 *
Packit ae235b
 * Returns: (transfer full): a #GIcon
Packit ae235b
 *
Packit ae235b
 * Since: 2.34
Packit ae235b
 */
Packit ae235b
GIcon *
Packit ae235b
g_unix_mount_point_guess_symbolic_icon (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  return g_themed_icon_new_with_default_fallbacks (type_to_icon (g_unix_mount_point_guess_type (mount_point), TRUE, TRUE));
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_guess_can_eject:
Packit ae235b
 * @mount_entry: a #GUnixMountEntry
Packit ae235b
 * 
Packit ae235b
 * Guesses whether a Unix mount can be ejected.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if @mount_entry is deemed to be ejectable.
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_mount_guess_can_eject (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  GUnixMountType guessed_type;
Packit ae235b
Packit ae235b
  guessed_type = g_unix_mount_guess_type (mount_entry);
Packit ae235b
  if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
Packit ae235b
      guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_guess_should_display:
Packit ae235b
 * @mount_entry: a #GUnixMountEntry
Packit ae235b
 * 
Packit ae235b
 * Guesses whether a Unix mount should be displayed in the UI.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if @mount_entry is deemed to be displayable.
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry)
Packit ae235b
{
Packit ae235b
  const char *mount_path;
Packit ae235b
  const gchar *user_name;
Packit ae235b
  gsize user_name_len;
Packit ae235b
Packit ae235b
  /* Never display internal mountpoints */
Packit ae235b
  if (g_unix_mount_is_system_internal (mount_entry))
Packit ae235b
    return FALSE;
Packit ae235b
  
Packit ae235b
  /* Only display things in /media (which are generally user mountable)
Packit ae235b
     and home dir (fuse stuff) and /run/media/$USER */
Packit ae235b
  mount_path = mount_entry->mount_path;
Packit ae235b
  if (mount_path != NULL)
Packit ae235b
    {
Packit ae235b
      gboolean is_in_runtime_dir = FALSE;
Packit ae235b
      /* Hide mounts within a dot path, suppose it was a purpose to hide this mount */
Packit ae235b
      if (g_strstr_len (mount_path, -1, "/.") != NULL)
Packit ae235b
        return FALSE;
Packit ae235b
Packit ae235b
      /* Check /run/media/$USER/ */
Packit ae235b
      user_name = g_get_user_name ();
Packit ae235b
      user_name_len = strlen (user_name);
Packit ae235b
      if (strncmp (mount_path, "/run/media/", sizeof ("/run/media/") - 1) == 0 &&
Packit ae235b
          strncmp (mount_path + sizeof ("/run/media/") - 1, user_name, user_name_len) == 0 &&
Packit ae235b
          mount_path[sizeof ("/run/media/") - 1 + user_name_len] == '/')
Packit ae235b
        is_in_runtime_dir = TRUE;
Packit ae235b
Packit ae235b
      if (is_in_runtime_dir || g_str_has_prefix (mount_path, "/media/"))
Packit ae235b
        {
Packit ae235b
          char *path;
Packit ae235b
          /* Avoid displaying mounts that are not accessible to the user.
Packit ae235b
           *
Packit ae235b
           * See http://bugzilla.gnome.org/show_bug.cgi?id=526320 for why we
Packit ae235b
           * want to avoid g_access() for mount points which can potentially
Packit ae235b
           * block or fail stat()'ing, such as network mounts.
Packit ae235b
           */
Packit ae235b
          path = g_path_get_dirname (mount_path);
Packit ae235b
          if (g_str_has_prefix (path, "/media/"))
Packit ae235b
            {
Packit ae235b
              if (g_access (path, R_OK|X_OK) != 0) 
Packit ae235b
                {
Packit ae235b
                  g_free (path);
Packit ae235b
                  return FALSE;
Packit ae235b
                }
Packit ae235b
            }
Packit ae235b
          g_free (path);
Packit ae235b
Packit ae235b
          if (mount_entry->device_path && mount_entry->device_path[0] == '/')
Packit ae235b
           {
Packit ae235b
             struct stat st;
Packit ae235b
             if (g_stat (mount_entry->device_path, &st) == 0 &&
Packit ae235b
                 S_ISBLK(st.st_mode) &&
Packit ae235b
                 g_access (mount_path, R_OK|X_OK) != 0)
Packit ae235b
               return FALSE;
Packit ae235b
           }
Packit ae235b
          return TRUE;
Packit ae235b
        }
Packit ae235b
      
Packit ae235b
      if (g_str_has_prefix (mount_path, g_get_home_dir ()) && 
Packit ae235b
          mount_path[strlen (g_get_home_dir())] == G_DIR_SEPARATOR)
Packit ae235b
        return TRUE;
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/**
Packit ae235b
 * g_unix_mount_point_guess_can_eject:
Packit ae235b
 * @mount_point: a #GUnixMountPoint
Packit ae235b
 * 
Packit ae235b
 * Guesses whether a Unix mount point can be ejected.
Packit ae235b
 *
Packit ae235b
 * Returns: %TRUE if @mount_point is deemed to be ejectable.
Packit ae235b
 */
Packit ae235b
gboolean
Packit ae235b
g_unix_mount_point_guess_can_eject (GUnixMountPoint *mount_point)
Packit ae235b
{
Packit ae235b
  GUnixMountType guessed_type;
Packit ae235b
Packit ae235b
  guessed_type = g_unix_mount_point_guess_type (mount_point);
Packit ae235b
  if (guessed_type == G_UNIX_MOUNT_TYPE_IPOD ||
Packit ae235b
      guessed_type == G_UNIX_MOUNT_TYPE_CDROM)
Packit ae235b
    return TRUE;
Packit ae235b
Packit ae235b
  return FALSE;
Packit ae235b
}
Packit ae235b
Packit ae235b
/* Utility functions {{{1 */
Packit ae235b
Packit ae235b
#ifdef HAVE_MNTENT_H
Packit ae235b
/* borrowed from gtk/gtkfilesystemunix.c in GTK+ on 02/23/2006 */
Packit ae235b
static void
Packit ae235b
_canonicalize_filename (gchar *filename)
Packit ae235b
{
Packit ae235b
  gchar *p, *q;
Packit ae235b
  gboolean last_was_slash = FALSE;
Packit ae235b
  
Packit ae235b
  p = filename;
Packit ae235b
  q = filename;
Packit ae235b
  
Packit ae235b
  while (*p)
Packit ae235b
    {
Packit ae235b
      if (*p == G_DIR_SEPARATOR)
Packit ae235b
        {
Packit ae235b
          if (!last_was_slash)
Packit ae235b
            *q++ = G_DIR_SEPARATOR;
Packit ae235b
          
Packit ae235b
          last_was_slash = TRUE;
Packit ae235b
        }
Packit ae235b
      else
Packit ae235b
        {
Packit ae235b
          if (last_was_slash && *p == '.')
Packit ae235b
            {
Packit ae235b
              if (*(p + 1) == G_DIR_SEPARATOR ||
Packit ae235b
                  *(p + 1) == '\0')
Packit ae235b
                {
Packit ae235b
                  if (*(p + 1) == '\0')
Packit ae235b
                    break;
Packit ae235b
                  
Packit ae235b
                  p += 1;
Packit ae235b
                }
Packit ae235b
              else if (*(p + 1) == '.' &&
Packit ae235b
                       (*(p + 2) == G_DIR_SEPARATOR ||
Packit ae235b
                        *(p + 2) == '\0'))
Packit ae235b
                {
Packit ae235b
                  if (q > filename + 1)
Packit ae235b
                    {
Packit ae235b
                      q--;
Packit ae235b
                      while (q > filename + 1 &&
Packit ae235b
                             *(q - 1) != G_DIR_SEPARATOR)
Packit ae235b
                        q--;
Packit ae235b
                    }
Packit ae235b
                  
Packit ae235b
                  if (*(p + 2) == '\0')
Packit ae235b
                    break;
Packit ae235b
                  
Packit ae235b
                  p += 2;
Packit ae235b
                }
Packit ae235b
              else
Packit ae235b
                {
Packit ae235b
                  *q++ = *p;
Packit ae235b
                  last_was_slash = FALSE;
Packit ae235b
                }
Packit ae235b
            }
Packit ae235b
          else
Packit ae235b
            {
Packit ae235b
              *q++ = *p;
Packit ae235b
              last_was_slash = FALSE;
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
      
Packit ae235b
      p++;
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
Packit ae235b
    q--;
Packit ae235b
  
Packit ae235b
  *q = '\0';
Packit ae235b
}
Packit ae235b
Packit ae235b
static char *
Packit ae235b
_resolve_symlink (const char *file)
Packit ae235b
{
Packit ae235b
  GError *error;
Packit ae235b
  char *dir;
Packit ae235b
  char *link;
Packit ae235b
  char *f;
Packit ae235b
  char *f1;
Packit ae235b
  
Packit ae235b
  f = g_strdup (file);
Packit ae235b
  
Packit ae235b
  while (g_file_test (f, G_FILE_TEST_IS_SYMLINK)) 
Packit ae235b
    {
Packit ae235b
      link = g_file_read_link (f, &error);
Packit ae235b
      if (link == NULL) 
Packit ae235b
        {
Packit ae235b
          g_error_free (error);
Packit ae235b
          g_free (f);
Packit ae235b
          f = NULL;
Packit ae235b
          goto out;
Packit ae235b
        }
Packit ae235b
    
Packit ae235b
      dir = g_path_get_dirname (f);
Packit ae235b
      f1 = g_strdup_printf ("%s/%s", dir, link);
Packit ae235b
      g_free (dir);
Packit ae235b
      g_free (link);
Packit ae235b
      g_free (f);
Packit ae235b
      f = f1;
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
 out:
Packit ae235b
  if (f != NULL)
Packit ae235b
    _canonicalize_filename (f);
Packit ae235b
  return f;
Packit ae235b
}
Packit ae235b
Packit ae235b
static const char *
Packit ae235b
_resolve_dev_root (void)
Packit ae235b
{
Packit ae235b
  static gboolean have_real_dev_root = FALSE;
Packit ae235b
  static char real_dev_root[256];
Packit ae235b
  struct stat statbuf;
Packit ae235b
  
Packit ae235b
  /* see if it's cached already */
Packit ae235b
  if (have_real_dev_root)
Packit ae235b
    goto found;
Packit ae235b
  
Packit ae235b
  /* otherwise we're going to find it right away.. */
Packit ae235b
  have_real_dev_root = TRUE;
Packit ae235b
  
Packit ae235b
  if (stat ("/dev/root", &statbuf) == 0) 
Packit ae235b
    {
Packit ae235b
      if (! S_ISLNK (statbuf.st_mode)) 
Packit ae235b
        {
Packit ae235b
          dev_t root_dev = statbuf.st_dev;
Packit ae235b
          FILE *f;
Packit ae235b
      
Packit ae235b
          /* see if device with similar major:minor as /dev/root is mention
Packit ae235b
           * in /etc/mtab (it usually is) 
Packit ae235b
           */
Packit ae235b
          f = fopen ("/etc/mtab", "r");
Packit ae235b
          if (f != NULL) 
Packit ae235b
            {
Packit ae235b
	      struct mntent *entp;
Packit ae235b
#ifdef HAVE_GETMNTENT_R        
Packit ae235b
              struct mntent ent;
Packit ae235b
              char buf[1024];
Packit ae235b
              while ((entp = getmntent_r (f, &ent, buf, sizeof (buf))) != NULL) 
Packit ae235b
                {
Packit ae235b
#else
Packit ae235b
	      G_LOCK (getmntent);
Packit ae235b
	      while ((entp = getmntent (f)) != NULL) 
Packit ae235b
                { 
Packit ae235b
#endif          
Packit ae235b
                  if (stat (entp->mnt_fsname, &statbuf) == 0 &&
Packit ae235b
                      statbuf.st_dev == root_dev) 
Packit ae235b
                    {
Packit ae235b
                      strncpy (real_dev_root, entp->mnt_fsname, sizeof (real_dev_root) - 1);
Packit ae235b
                      real_dev_root[sizeof (real_dev_root) - 1] = '\0';
Packit ae235b
                      fclose (f);
Packit ae235b
                      goto found;
Packit ae235b
                    }
Packit ae235b
                }
Packit ae235b
Packit ae235b
              endmntent (f);
Packit ae235b
Packit ae235b
#ifndef HAVE_GETMNTENT_R
Packit ae235b
	      G_UNLOCK (getmntent);
Packit ae235b
#endif
Packit ae235b
            }                                        
Packit ae235b
      
Packit ae235b
          /* no, that didn't work.. next we could scan /dev ... but I digress.. */
Packit ae235b
      
Packit ae235b
        } 
Packit ae235b
       else 
Packit ae235b
        {
Packit ae235b
          char *resolved;
Packit ae235b
          resolved = _resolve_symlink ("/dev/root");
Packit ae235b
          if (resolved != NULL)
Packit ae235b
            {
Packit ae235b
              strncpy (real_dev_root, resolved, sizeof (real_dev_root) - 1);
Packit ae235b
              real_dev_root[sizeof (real_dev_root) - 1] = '\0';
Packit ae235b
              g_free (resolved);
Packit ae235b
              goto found;
Packit ae235b
            }
Packit ae235b
        }
Packit ae235b
    }
Packit ae235b
  
Packit ae235b
  /* bah sucks.. */
Packit ae235b
  strcpy (real_dev_root, "/dev/root");
Packit ae235b
  
Packit ae235b
found:
Packit ae235b
  return real_dev_root;
Packit ae235b
}
Packit ae235b
#endif
Packit ae235b
Packit ae235b
/* Epilogue {{{1 */
Packit ae235b
/* vim:set foldmethod=marker: */