(root)/
glib-2.79.0/
gio/
gunixvolume.c
       1  /* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
       2  
       3  /* GIO - GLib Input, Output and Streaming Library
       4   * 
       5   * Copyright (C) 2006-2007 Red Hat, Inc.
       6   *
       7   * SPDX-License-Identifier: LGPL-2.1-or-later
       8   *
       9   * This library is free software; you can redistribute it and/or
      10   * modify it under the terms of the GNU Lesser General Public
      11   * License as published by the Free Software Foundation; either
      12   * version 2.1 of the License, or (at your option) any later version.
      13   *
      14   * This library is distributed in the hope that it will be useful,
      15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      17   * Lesser General Public License for more details.
      18   *
      19   * You should have received a copy of the GNU Lesser General
      20   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      21   *
      22   * Author: Alexander Larsson <alexl@redhat.com>
      23   *         David Zeuthen <davidz@redhat.com>
      24   */
      25  
      26  #include "config.h"
      27  
      28  #include <string.h>
      29  #include <sys/wait.h>
      30  #include <unistd.h>
      31  
      32  #include <glib.h>
      33  #include "gunixvolume.h"
      34  #include "gunixmount.h"
      35  #include "gunixmounts.h"
      36  #include "gthemedicon.h"
      37  #include "gvolume.h"
      38  #include "gvolumemonitor.h"
      39  #include "gtask.h"
      40  #include "gioerror.h"
      41  #include "glibintl.h"
      42  /* for BUFSIZ */
      43  #include <stdio.h>
      44  
      45  
      46  struct _GUnixVolume {
      47    GObject parent;
      48  
      49    GVolumeMonitor *volume_monitor;
      50    GUnixMount     *mount; /* owned by volume monitor */
      51    
      52    char *device_path;
      53    char *mount_path;
      54    gboolean can_eject;
      55  
      56    char *identifier;
      57    char *identifier_type;
      58    
      59    char *name;
      60    GIcon *icon;
      61    GIcon *symbolic_icon;
      62  };
      63  
      64  static void g_unix_volume_volume_iface_init (GVolumeIface *iface);
      65  
      66  #define g_unix_volume_get_type _g_unix_volume_get_type
      67  G_DEFINE_TYPE_WITH_CODE (GUnixVolume, g_unix_volume, G_TYPE_OBJECT,
      68  			 G_IMPLEMENT_INTERFACE (G_TYPE_VOLUME,
      69  						g_unix_volume_volume_iface_init))
      70  
      71  static void
      72  g_unix_volume_finalize (GObject *object)
      73  {
      74    GUnixVolume *volume;
      75    
      76    volume = G_UNIX_VOLUME (object);
      77  
      78    if (volume->volume_monitor != NULL)
      79      g_object_unref (volume->volume_monitor);
      80  
      81    if (volume->mount)
      82      _g_unix_mount_unset_volume (volume->mount, volume);
      83    
      84    g_object_unref (volume->icon);
      85    g_object_unref (volume->symbolic_icon);
      86    g_free (volume->name);
      87    g_free (volume->mount_path);
      88    g_free (volume->device_path);
      89    g_free (volume->identifier);
      90    g_free (volume->identifier_type);
      91  
      92    G_OBJECT_CLASS (g_unix_volume_parent_class)->finalize (object);
      93  }
      94  
      95  static void
      96  g_unix_volume_class_init (GUnixVolumeClass *klass)
      97  {
      98    GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
      99  
     100    gobject_class->finalize = g_unix_volume_finalize;
     101  }
     102  
     103  static void
     104  g_unix_volume_init (GUnixVolume *unix_volume)
     105  {
     106  }
     107  
     108  GUnixVolume *
     109  _g_unix_volume_new (GVolumeMonitor  *volume_monitor,
     110                      GUnixMountPoint *mountpoint)
     111  {
     112    GUnixVolume *volume;
     113    
     114    if (!(g_unix_mount_point_is_user_mountable (mountpoint) ||
     115  	g_str_has_prefix (g_unix_mount_point_get_device_path (mountpoint), "/vol/")) ||
     116        g_unix_mount_point_is_loopback (mountpoint))
     117      return NULL;
     118    
     119    volume = g_object_new (G_TYPE_UNIX_VOLUME, NULL);
     120    volume->volume_monitor = volume_monitor != NULL ? g_object_ref (volume_monitor) : NULL;
     121    volume->mount_path = g_strdup (g_unix_mount_point_get_mount_path (mountpoint));
     122    volume->device_path = g_strdup (g_unix_mount_point_get_device_path (mountpoint));
     123    volume->can_eject = g_unix_mount_point_guess_can_eject (mountpoint);
     124  
     125    volume->name = g_unix_mount_point_guess_name (mountpoint);
     126    volume->icon = g_unix_mount_point_guess_icon (mountpoint);
     127    volume->symbolic_icon = g_unix_mount_point_guess_symbolic_icon (mountpoint);
     128  
     129  
     130    if (strcmp (g_unix_mount_point_get_fs_type (mountpoint), "nfs") == 0)
     131      {
     132        volume->identifier_type = g_strdup (G_VOLUME_IDENTIFIER_KIND_NFS_MOUNT);
     133        volume->identifier = g_strdup (volume->device_path);
     134      }
     135    else if (g_str_has_prefix (volume->device_path, "LABEL="))
     136      {
     137        volume->identifier_type = g_strdup (G_VOLUME_IDENTIFIER_KIND_LABEL);
     138        volume->identifier = g_strdup (volume->device_path + 6);
     139      }
     140    else if (g_str_has_prefix (volume->device_path, "UUID="))
     141      {
     142        volume->identifier_type = g_strdup (G_VOLUME_IDENTIFIER_KIND_UUID);
     143        volume->identifier = g_strdup (volume->device_path + 5);
     144      }
     145    else if (g_path_is_absolute (volume->device_path))
     146      {
     147        volume->identifier_type = g_strdup (G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE);
     148        volume->identifier = g_strdup (volume->device_path);
     149      }
     150    
     151    return volume;
     152  }
     153  
     154  void
     155  _g_unix_volume_disconnected (GUnixVolume *volume)
     156  {
     157    if (volume->mount)
     158      {
     159        _g_unix_mount_unset_volume (volume->mount, volume);
     160        volume->mount = NULL;
     161      }
     162  }
     163  
     164  void
     165  _g_unix_volume_set_mount (GUnixVolume *volume,
     166                            GUnixMount  *mount)
     167  {
     168    if (volume->mount == mount)
     169      return;
     170    
     171    if (volume->mount)
     172      _g_unix_mount_unset_volume (volume->mount, volume);
     173    
     174    volume->mount = mount;
     175    
     176    /* TODO: Emit changed in idle to avoid locking issues */
     177    g_signal_emit_by_name (volume, "changed");
     178    if (volume->volume_monitor != NULL)
     179      g_signal_emit_by_name (volume->volume_monitor, "volume-changed", volume);
     180  }
     181  
     182  void
     183  _g_unix_volume_unset_mount (GUnixVolume  *volume,
     184                              GUnixMount *mount)
     185  {
     186    if (volume->mount == mount)
     187      {
     188        volume->mount = NULL;
     189        /* TODO: Emit changed in idle to avoid locking issues */
     190        g_signal_emit_by_name (volume, "changed");
     191        if (volume->volume_monitor != NULL)
     192          g_signal_emit_by_name (volume->volume_monitor, "volume-changed", volume);
     193      }
     194  }
     195  
     196  static GIcon *
     197  g_unix_volume_get_icon (GVolume *volume)
     198  {
     199    GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
     200    return g_object_ref (unix_volume->icon);
     201  }
     202  
     203  static GIcon *
     204  g_unix_volume_get_symbolic_icon (GVolume *volume)
     205  {
     206    GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
     207    return g_object_ref (unix_volume->symbolic_icon);
     208  }
     209  
     210  static char *
     211  g_unix_volume_get_name (GVolume *volume)
     212  {
     213    GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
     214    return g_strdup (unix_volume->name);
     215  }
     216  
     217  static char *
     218  g_unix_volume_get_uuid (GVolume *volume)
     219  {
     220    return NULL;
     221  }
     222  
     223  static gboolean
     224  g_unix_volume_can_mount (GVolume *volume)
     225  {
     226    return TRUE;
     227  }
     228  
     229  static gboolean
     230  g_unix_volume_can_eject (GVolume *volume)
     231  {
     232    GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
     233    return unix_volume->can_eject;
     234  }
     235  
     236  static gboolean
     237  g_unix_volume_should_automount (GVolume *volume)
     238  {
     239    /* We automount all local volumes because we don't even
     240     * make the internal stuff visible
     241     */
     242    return TRUE;
     243  }
     244  
     245  static GDrive *
     246  g_unix_volume_get_drive (GVolume *volume)
     247  {
     248    return NULL;
     249  }
     250  
     251  static GMount *
     252  g_unix_volume_get_mount (GVolume *volume)
     253  {
     254    GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
     255  
     256    if (unix_volume->mount != NULL)
     257      return g_object_ref (G_MOUNT (unix_volume->mount));
     258  
     259    return NULL;
     260  }
     261  
     262  
     263  gboolean
     264  _g_unix_volume_has_mount_path (GUnixVolume *volume,
     265                                 const char  *mount_path)
     266  {
     267    return strcmp (volume->mount_path, mount_path) == 0;
     268  }
     269  
     270  static void
     271  eject_mount_done (GObject      *source,
     272                    GAsyncResult *result,
     273                    gpointer      user_data)
     274  {
     275    GSubprocess *subprocess = G_SUBPROCESS (source);
     276    GTask *task = user_data;
     277    GError *error = NULL;
     278    gchar *stderr_str;
     279    GUnixVolume *unix_volume;
     280  
     281    if (!g_subprocess_communicate_utf8_finish (subprocess, result, NULL, &stderr_str, &error))
     282      {
     283        g_task_return_error (task, error);
     284        g_error_free (error);
     285      }
     286    else /* successful communication */
     287      {
     288        if (!g_subprocess_get_successful (subprocess))
     289          /* ...but bad exit code */
     290          g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED, stderr_str);
     291        else
     292          {
     293            /* ...and successful exit code */
     294            unix_volume = G_UNIX_VOLUME (g_task_get_source_object (task));
     295            _g_unix_volume_monitor_update (G_UNIX_VOLUME_MONITOR (unix_volume->volume_monitor));
     296            g_task_return_boolean (task, TRUE);
     297          }
     298  
     299        g_free (stderr_str);
     300      }
     301  
     302    g_object_unref (task);
     303  }
     304  
     305  static void
     306  eject_mount_do (GVolume              *volume,
     307                  GCancellable         *cancellable,
     308                  GAsyncReadyCallback   callback,
     309                  gpointer              user_data,
     310                  const gchar * const  *argv,
     311                  const gchar          *task_name)
     312  {
     313    GSubprocess *subprocess;
     314    GError *error = NULL;
     315    GTask *task;
     316  
     317    task = g_task_new (volume, cancellable, callback, user_data);
     318    g_task_set_source_tag (task, eject_mount_do);
     319    g_task_set_name (task, task_name);
     320  
     321    if (g_task_return_error_if_cancelled (task))
     322      {
     323        g_object_unref (task);
     324        return;
     325      }
     326  
     327    subprocess = g_subprocess_newv (argv, G_SUBPROCESS_FLAGS_STDOUT_SILENCE | G_SUBPROCESS_FLAGS_STDERR_PIPE, &error);
     328    g_assert_no_error (error);
     329  
     330    g_subprocess_communicate_utf8_async (subprocess, NULL,
     331                                         g_task_get_cancellable (task),
     332                                         eject_mount_done, task);
     333  }
     334  
     335  static void
     336  g_unix_volume_mount (GVolume            *volume,
     337                       GMountMountFlags    flags,
     338                       GMountOperation     *mount_operation,
     339                       GCancellable        *cancellable,
     340                       GAsyncReadyCallback  callback,
     341                       gpointer             user_data)
     342  {
     343    GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
     344    const gchar *argv[] = { "mount", NULL, NULL };
     345  
     346    if (unix_volume->mount_path != NULL)
     347      argv[1] = unix_volume->mount_path;
     348    else
     349      argv[1] = unix_volume->device_path;
     350  
     351    eject_mount_do (volume, cancellable, callback, user_data, argv, "[gio] mount volume");
     352  }
     353  
     354  static gboolean
     355  g_unix_volume_mount_finish (GVolume        *volume,
     356                              GAsyncResult  *result,
     357                              GError       **error)
     358  {
     359    g_return_val_if_fail (g_task_is_valid (result, volume), FALSE);
     360  
     361    return g_task_propagate_boolean (G_TASK (result), error);
     362  }
     363  
     364  static void
     365  g_unix_volume_eject (GVolume             *volume,
     366                       GMountUnmountFlags   flags,
     367                       GCancellable        *cancellable,
     368                       GAsyncReadyCallback  callback,
     369                       gpointer             user_data)
     370  {
     371    GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
     372    const gchar *argv[] = { "eject", NULL, NULL };
     373  
     374    argv[1] = unix_volume->device_path;
     375  
     376    eject_mount_do (volume, cancellable, callback, user_data, argv, "[gio] eject volume");
     377  }
     378  
     379  static gboolean
     380  g_unix_volume_eject_finish (GVolume       *volume,
     381                              GAsyncResult  *result,
     382                              GError       **error)
     383  {
     384    g_return_val_if_fail (g_task_is_valid (result, volume), FALSE);
     385  
     386    return g_task_propagate_boolean (G_TASK (result), error);
     387  }
     388  
     389  static gchar *
     390  g_unix_volume_get_identifier (GVolume     *volume,
     391                                const gchar *kind)
     392  {
     393    GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
     394  
     395    if (unix_volume->identifier_type != NULL &&
     396        strcmp (kind, unix_volume->identifier_type) == 0)
     397      return g_strdup (unix_volume->identifier);
     398  
     399    return NULL;
     400  }
     401  
     402  static gchar **
     403  g_unix_volume_enumerate_identifiers (GVolume *volume)
     404  {
     405    GUnixVolume *unix_volume = G_UNIX_VOLUME (volume);
     406    gchar **res;
     407  
     408    if (unix_volume->identifier_type)
     409      {
     410        res = g_new (gchar *, 2);
     411        res[0] = g_strdup (unix_volume->identifier_type);
     412        res[1] = NULL;
     413      }
     414    else
     415      {
     416        res = g_new (gchar *, 1);
     417        res[0] = NULL;
     418      }
     419  
     420    return res;
     421  }
     422  
     423  static void
     424  g_unix_volume_volume_iface_init (GVolumeIface *iface)
     425  {
     426    iface->get_name = g_unix_volume_get_name;
     427    iface->get_icon = g_unix_volume_get_icon;
     428    iface->get_symbolic_icon = g_unix_volume_get_symbolic_icon;
     429    iface->get_uuid = g_unix_volume_get_uuid;
     430    iface->get_drive = g_unix_volume_get_drive;
     431    iface->get_mount = g_unix_volume_get_mount;
     432    iface->can_mount = g_unix_volume_can_mount;
     433    iface->can_eject = g_unix_volume_can_eject;
     434    iface->should_automount = g_unix_volume_should_automount;
     435    iface->mount_fn = g_unix_volume_mount;
     436    iface->mount_finish = g_unix_volume_mount_finish;
     437    iface->eject = g_unix_volume_eject;
     438    iface->eject_finish = g_unix_volume_eject_finish;
     439    iface->get_identifier = g_unix_volume_get_identifier;
     440    iface->enumerate_identifiers = g_unix_volume_enumerate_identifiers;
     441  }