Exemplo n.º 1
0
/**
 * udisks_linux_block_object_trigger_uevent:
 * @object: A #UDisksLinuxBlockObject.
 *
 * Triggers a 'change' uevent in the kernel.
 *
 * The triggered event will bubble up from the kernel through the udev
 * stack and will eventually be received by the udisks daemon process
 * itself. This method does not wait for the event to be received.
 */
void
udisks_linux_block_object_trigger_uevent (UDisksLinuxBlockObject *object)
{
  gchar* path = NULL;
  gint fd = -1;

  g_return_if_fail (UDISKS_IS_LINUX_BLOCK_OBJECT (object));

  /* TODO: would be nice with a variant to wait until the request uevent has been received by ourselves */

  path = g_strconcat (g_udev_device_get_sysfs_path (object->device->udev_device), "/uevent", NULL);
  fd = open (path, O_WRONLY);
  if (fd < 0)
    {
      udisks_warning ("Error opening %s: %m", path);
      goto out;
    }

  if (write (fd, "change", sizeof "change" - 1) != sizeof "change" - 1)
    {
      udisks_warning ("Error writing 'change' to file %s: %m", path);
      goto out;
    }

 out:
  if (fd >= 0)
    close (fd);
  g_free (path);
}
Exemplo n.º 2
0
/**
 * udisks_decode_udev_string:
 * @str: An udev-encoded string or %NULL.
 *
 * Unescapes sequences like \x20 to " " and ensures the returned string is valid UTF-8.
 *
 * If the string is not valid UTF-8, try as hard as possible to convert to UTF-8.
 *
 * If %NULL is passed, then %NULL is returned.
 *
 * See udev_util_encode_string() in libudev/libudev-util.c in the udev
 * tree for what kinds of strings can be used.
 *
 * Returns: A valid UTF-8 string that must be freed with g_free().
 */
gchar *
udisks_decode_udev_string (const gchar *str)
{
  GString *s;
  gchar *ret;
  const gchar *end_valid;
  guint n;

  if (str == NULL)
    {
      ret = NULL;
      goto out;
    }

  s = g_string_new (NULL);
  for (n = 0; str[n] != '\0'; n++)
    {
      if (str[n] == '\\')
        {
          gint val;

          if (str[n + 1] != 'x' || str[n + 2] == '\0' || str[n + 3] == '\0')
            {
              udisks_warning ("**** NOTE: malformed encoded string `%s'", str);
              break;
            }

          val = (g_ascii_xdigit_value (str[n + 2]) << 4) | g_ascii_xdigit_value (str[n + 3]);

          g_string_append_c (s, val);

          n += 3;
        }
      else
        {
          g_string_append_c (s, str[n]);
        }
    }

  if (!g_utf8_validate (s->str, -1, &end_valid))
    {
      udisks_warning ("The string `%s' is not valid UTF-8. Invalid characters begins at `%s'", s->str, end_valid);
      ret = g_strndup (s->str, end_valid - s->str);
      g_string_free (s, TRUE);
    }
  else
    {
      ret = g_string_free (s, FALSE);
    }

 out:
  return ret;
}
Exemplo n.º 3
0
/* Runs in housekeeping thread - called without lock held */
static void
housekeeping_all_drives (UDisksLinuxProvider *provider,
                         guint                secs_since_last)
{
  GList *objects;
  GList *l;

  G_LOCK (provider_lock);
  objects = g_hash_table_get_values (provider->vpd_to_drive);
  g_list_foreach (objects, (GFunc) g_object_ref, NULL);
  G_UNLOCK (provider_lock);

  for (l = objects; l != NULL; l = l->next)
    {
      UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (l->data);
      GError *error;

      error = NULL;
      if (!udisks_linux_drive_object_housekeeping (object,
                                                   secs_since_last,
                                                   NULL, /* TODO: cancellable */
                                                   &error))
        {
          udisks_warning ("Error performing housekeeping for drive %s: %s (%s, %d)",
                          g_dbus_object_get_object_path (G_DBUS_OBJECT (object)),
                          error->message, g_quark_to_string (error->domain), error->code);
          g_error_free (error);
        }
    }

  g_list_foreach (objects, (GFunc) g_object_unref, NULL);
  g_list_free (objects);
}
Exemplo n.º 4
0
static GSource *
watch_attr (UDisksLinuxDevice *device,
            const gchar       *attr,
            GSourceFunc        callback,
            gpointer           user_data)
{
  GError *error = NULL;
  gchar *path = NULL;
  GIOChannel *channel = NULL;
  GSource *ret = NULL;;

  g_return_val_if_fail (UDISKS_IS_LINUX_DEVICE (device), NULL);

  path = g_strdup_printf ("%s/%s", g_udev_device_get_sysfs_path (device->udev_device), attr);
  channel = g_io_channel_new_file (path, "r", &error);
  if (channel != NULL)
    {
      ret = g_io_create_watch (channel, G_IO_ERR);
      g_source_set_callback (ret, callback, user_data, NULL);
      g_source_attach (ret, g_main_context_get_thread_default ());
      g_source_unref (ret);
      g_io_channel_unref (channel); /* the keeps a reference to this object */
    }
  else
    {
      udisks_warning ("Error creating watch for file %s: %s (%s, %d)",
                      path, error->message, g_quark_to_string (error->domain), error->code);
      g_clear_error (&error);
    }
  g_free (path);

  return ret;
}
Exemplo n.º 5
0
/**
 * udisks_linux_drive_object_uevent:
 * @object: A #UDisksLinuxDriveObject.
 * @action: Uevent action or %NULL
 * @device: A #UDisksLinuxDevice device object or %NULL if the device hasn't changed.
 *
 * Updates all information on interfaces on @drive.
 */
void
udisks_linux_drive_object_uevent (UDisksLinuxDriveObject *object,
                                  const gchar            *action,
                                  UDisksLinuxDevice      *device)
{
  GList *link;
  gboolean conf_changed;

  g_return_if_fail (UDISKS_IS_LINUX_DRIVE_OBJECT (object));
  g_return_if_fail (device == NULL || UDISKS_IS_LINUX_DEVICE (device));

  link = NULL;
  if (device != NULL)
    link = find_link_for_sysfs_path (object, g_udev_device_get_sysfs_path (device->udev_device));
  if (g_strcmp0 (action, "remove") == 0)
    {
      if (link != NULL)
        {
          g_object_unref (UDISKS_LINUX_DEVICE (link->data));
          object->devices = g_list_delete_link (object->devices, link);
        }
      else
        {
          udisks_warning ("Drive doesn't have device with sysfs path %s on remove event",
                          g_udev_device_get_sysfs_path (device->udev_device));
        }
    }
  else
    {
      if (link != NULL)
        {
          g_object_unref (UDISKS_LINUX_DEVICE (link->data));
          link->data = g_object_ref (device);
        }
      else
        {
          if (device != NULL)
            object->devices = g_list_append (object->devices, g_object_ref (device));
        }
    }

  conf_changed = FALSE;
  conf_changed |= update_iface (object, action, drive_check, drive_connect, drive_update,
                                UDISKS_TYPE_LINUX_DRIVE, &object->iface_drive);
  conf_changed |= update_iface (object, action, drive_ata_check, drive_ata_connect, drive_ata_update,
                                UDISKS_TYPE_LINUX_DRIVE_ATA, &object->iface_drive_ata);

  if (conf_changed)
    apply_configuration (object);
}
Exemplo n.º 6
0
/**
 * udisks_linux_block_object_reread_partition_table:
 * @object: A #UDisksLinuxBlockObject.
 *
 * Requests the kernel to re-read the partition table for @object.
 *
 * The events from any change this may cause will bubble up from the
 * kernel through the udev stack and will eventually be received by
 * the udisks daemon process itself. This method does not wait for the
 * event to be received.
 */
void
udisks_linux_block_object_reread_partition_table (UDisksLinuxBlockObject *object)
{
  const gchar *device_file;
  gint fd;

  g_return_if_fail (UDISKS_IS_LINUX_BLOCK_OBJECT (object));

  device_file = g_udev_device_get_device_file (object->device->udev_device);
  fd = open (device_file, O_RDONLY);
  if (fd == -1)
    {
      udisks_warning ("Error opening %s: %m", device_file);
    }
  else
    {
      if (ioctl (fd, BLKRRPART) != 0)
        {
          udisks_warning ("Error issuing BLKRRPART to %s: %m", device_file);
        }
      close (fd);
    }
}
Exemplo n.º 7
0
static void
udisks_linux_provider_init (UDisksLinuxProvider *provider)
{
  const gchar *subsystems[] = {"block", "iscsi_connection", "scsi", NULL};
  GFile *file;
  GError *error = NULL;

  /* get ourselves an udev client */
  provider->gudev_client = g_udev_client_new (subsystems);

  g_signal_connect (provider->gudev_client,
                    "uevent",
                    G_CALLBACK (on_uevent),
                    provider);

  provider->probe_request_queue = g_async_queue_new ();
  provider->probe_request_thread = g_thread_new ("probing-thread",
                                                 probe_request_thread_func,
                                                 provider);

  file = g_file_new_for_path (PACKAGE_SYSCONF_DIR "/udisks2");
  provider->etc_udisks2_dir_monitor = g_file_monitor_directory (file,
                                                                G_FILE_MONITOR_NONE,
                                                                NULL,
                                                                &error);
  if (provider->etc_udisks2_dir_monitor != NULL)
    {
      g_signal_connect (provider->etc_udisks2_dir_monitor,
                        "changed",
                        G_CALLBACK (on_etc_udisks2_dir_monitor_changed),
                        provider);
    }
  else
    {
      udisks_warning ("Error monitoring directory %s: %s (%s, %d)",
                      PACKAGE_SYSCONF_DIR "/udisks2",
                      error->message, g_quark_to_string (error->domain), error->code);
      g_clear_error (&error);
    }
  g_object_unref (file);

}
Exemplo n.º 8
0
static gboolean
perform_initial_housekeeping_for_drive (GIOSchedulerJob *job,
                                        GCancellable    *cancellable,
                                        gpointer         user_data)
{
  UDisksLinuxDriveObject *object = UDISKS_LINUX_DRIVE_OBJECT (user_data);
  GError *error;

  error = NULL;
  if (!udisks_linux_drive_object_housekeeping (object, 0,
                                               NULL, /* TODO: cancellable */
                                               &error))
    {
      udisks_warning ("Error performing initial housekeeping for drive %s: %s (%s, %d)",
                      g_dbus_object_get_object_path (G_DBUS_OBJECT (object)),
                      error->message, g_quark_to_string (error->domain), error->code);
      g_error_free (error);
    }
  return FALSE; /* job is complete */
}
Exemplo n.º 9
0
static void
lvm_update_vgs (GObject      *source_obj,
                GAsyncResult *result,
                gpointer      user_data)
{
  UDisksLVM2State *state;
  UDisksDaemon *daemon = UDISKS_DAEMON (source_obj);
  GDBusObjectManagerServer *manager;

  GTask *task = G_TASK (result);
  GError *error = NULL;
  VGsPVsData *data = g_task_propagate_pointer (task, &error);
  BDLVMVGdata **vgs = NULL;
  BDLVMPVdata **pvs = NULL;

  GHashTableIter vg_name_iter;
  gpointer key, value;
  const gchar *vg_name;

  if (!data)
    {
      if (error)
        udisks_warning ("LVM2 plugin: %s", error->message);
      else
        /* this should never happen */
        udisks_warning ("LVM2 plugin: failure but no error when getting VGs!");

      return;
    }
  vgs = data->vgs;
  pvs = data->pvs;

  /* free the data container (but not 'vgs' and 'pvs') */
  g_free (data);

  manager = udisks_daemon_get_object_manager (daemon);
  state = get_module_state (daemon);

  /* Remove obsolete groups */
  g_hash_table_iter_init (&vg_name_iter,
                          udisks_lvm2_state_get_name_to_volume_group (state));
  while (g_hash_table_iter_next (&vg_name_iter, &key, &value))
    {
      UDisksLinuxVolumeGroupObject *group;
      gboolean found = FALSE;

      vg_name = key;
      group = value;

      for (BDLVMVGdata **vgs_p=vgs; !found && (*vgs_p); vgs_p++)
          found = g_strcmp0 ((*vgs_p)->name, vg_name) == 0;

      if (!found)
        {
          udisks_linux_volume_group_object_destroy (group);
          g_dbus_object_manager_server_unexport (manager,
                                                 g_dbus_object_get_object_path (G_DBUS_OBJECT (group)));
          g_hash_table_iter_remove (&vg_name_iter);
        }
    }

  /* Add new groups and update existing groups */
  for (BDLVMVGdata **vgs_p=vgs; *vgs_p; vgs_p++)
    {
      UDisksLinuxVolumeGroupObject *group;
      GSList *vg_pvs = NULL;
      vg_name = (*vgs_p)->name;
      group = g_hash_table_lookup (udisks_lvm2_state_get_name_to_volume_group (state),
                                   vg_name);

      if (group == NULL)
        {
          group = udisks_linux_volume_group_object_new (daemon, vg_name);
          g_hash_table_insert (udisks_lvm2_state_get_name_to_volume_group (state),
                               g_strdup (vg_name), group);
        }

      for (BDLVMPVdata **pvs_p=pvs; *pvs_p; pvs_p++)
        if (g_strcmp0 ((*pvs_p)->vg_name, vg_name) == 0)
            vg_pvs = g_slist_prepend (vg_pvs, *pvs_p);

      udisks_linux_volume_group_object_update (group, *vgs_p, vg_pvs);
    }

  /* this is safe to do -- all BDLVMPVdata objects are still existing because
     the function that frees them is scheduled in main loop by the
     udisks_linux_volume_group_object_update() call above */
  for (BDLVMPVdata **pvs_p=pvs; *pvs_p; pvs_p++)
    if ((*pvs_p)->vg_name == NULL)
      bd_lvm_pvdata_free (*pvs_p);

  /* only free the containers, the contents were passed further */
  g_free (vgs);
  g_free (pvs);
}
Exemplo n.º 10
0
/**
 * udisks_linux_mdraid_object_uevent:
 * @object: A #UDisksLinuxMDRaidObject.
 * @action: Uevent action or %NULL
 * @device: A #UDisksLinuxDevice device object or %NULL if the device hasn't changed.
 * @is_member: %TRUE if @device is a member, %FALSE if it's the raid device.
 *
 * Updates all information on interfaces on @mdraid.
 */
void
udisks_linux_mdraid_object_uevent (UDisksLinuxMDRaidObject *object,
                                   const gchar             *action,
                                   UDisksLinuxDevice       *device,
                                   gboolean                 is_member)
{
  gboolean conf_changed = FALSE;

  g_return_if_fail (UDISKS_IS_LINUX_MDRAID_OBJECT (object));
  g_return_if_fail (UDISKS_IS_LINUX_DEVICE (device));

  /* udisks_debug ("is_member=%d for uuid %s and device %s", is_member, object->uuid, g_udev_device_get_device_file (device->udev_device)); */

  if (is_member)
    {
      GList *link = NULL;
      link = NULL;
      if (device != NULL)
        link = find_link_for_sysfs_path_for_member (object, g_udev_device_get_sysfs_path (device->udev_device));

      if (g_strcmp0 (action, "remove") == 0)
        {
          if (link != NULL)
            {
              g_object_unref (UDISKS_LINUX_DEVICE (link->data));
              object->member_devices = g_list_delete_link (object->member_devices, link);
            }
          else
            {
              udisks_warning ("MDRaid with UUID %s doesn't have member device with sysfs path %s on remove event",
                              object->uuid,
                              g_udev_device_get_sysfs_path (device->udev_device));
            }
        }
      else
        {
          if (link != NULL)
            {
              if (device != link->data)
                {
                  g_object_unref (UDISKS_LINUX_DEVICE (link->data));
                  link->data = g_object_ref (device);
                }
            }
          else
            {
              if (device != NULL)
                {
                  object->member_devices = g_list_append (object->member_devices, g_object_ref (device));
                }
            }
        }
    }
  else
    {
      /* Skip partitions of raid devices */
      if (g_strcmp0 (g_udev_device_get_devtype (device->udev_device), "disk") != 0)
        goto out;

      if (g_strcmp0 (action, "remove") == 0)
        {
          if (object->raid_device != NULL)
            if (g_strcmp0 (g_udev_device_get_sysfs_path (object->raid_device->udev_device),
                           g_udev_device_get_sysfs_path (device->udev_device)) == 0)
              {
                g_clear_object (&object->raid_device);
                raid_device_removed (object, object->raid_device);
              }
            else
              {
                udisks_warning ("MDRaid with UUID %s doesn't have raid device with sysfs path %s on remove event (it has %s)",
                                object->uuid,
                                g_udev_device_get_sysfs_path (device->udev_device),
                                g_udev_device_get_sysfs_path (object->raid_device->udev_device));
              }
          else
            {
              udisks_warning ("MDRaid with UUID %s doesn't have raid device with sysfs path %s on remove event",
                              object->uuid,
                              g_udev_device_get_sysfs_path (device->udev_device));
            }
        }
      else
        {
          if (object->raid_device == NULL)
            {
              object->raid_device = g_object_ref (device);
              raid_device_added (object, object->raid_device);
            }
          else
            {
              if (device != object->raid_device)
                {
                  /* device changed -- remove and re-add the file watchers */
                  raid_device_removed (object, object->raid_device);
                  g_clear_object (&object->raid_device);
                  object->raid_device = g_object_ref (device);
                  raid_device_added (object, object->raid_device);
                }
            }
        }
    }

  /* if we don't have any devices, no point in updating (we should get nuked soon anyway) */
  if (udisks_linux_mdraid_object_have_devices (object))
    {
      conf_changed = FALSE;
      conf_changed |= update_iface (object, action, mdraid_check, mdraid_connect, mdraid_update,
                                    UDISKS_TYPE_LINUX_MDRAID, &object->iface_mdraid);
    }
 out:
  ;
}
gboolean take_filesystem_ownership (const gchar *device,
                                    const gchar *fstype,
                                    uid_t caller_uid,
                                    gid_t caller_gid,
                                    gboolean recursive,
                                    GError **error)

{

  gchar *mountpoint = NULL;
  GError *local_error = NULL;
  gboolean unmount = FALSE;
  gboolean success = TRUE;

  mountpoint = bd_fs_get_mountpoint (device, &local_error);
  if (mountpoint == NULL)
    {
      if (local_error != NULL)
        {
          g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
                       "Error when getting mountpoint for %s: %s.",
                       device, local_error->message);
          g_clear_error (&local_error);
          success = FALSE;
          goto out;
        }
      else
        {
          /* device is not mounted, we need to mount it */
          mountpoint = g_mkdtemp (g_strdup (PACKAGE_LOCALSTATE_DIR "/run/udisks2/temp-mount-XXXXXX"));
          if (mountpoint == NULL)
            {
              g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
                           "Cannot create temporary mountpoint.");
              success = FALSE;
              goto out;
            }

          if (!bd_fs_mount (device, mountpoint, fstype, NULL, NULL, &local_error))
            {
              g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
                           "Cannot mount %s at %s: %s",
                           device, mountpoint, local_error->message);
              g_clear_error (&local_error);
              if (g_rmdir (mountpoint) != 0)
                  udisks_warning ("Error removing temporary mountpoint directory %s.", mountpoint);
              success = FALSE;
              goto out;
            }
          else
            unmount = TRUE;  // unmount during cleanup
        }
    }

  if (recursive)
    {
      if (!recursive_chown (mountpoint, caller_uid, caller_gid))
        {
            g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
                         "Cannot recursively chown %s to uid=%u and gid=%u: %m",
                         mountpoint, caller_uid, caller_gid);

          success = FALSE;
          goto out;
        }
    }
  else
    {
      if (chown (mountpoint, caller_uid, caller_gid) != 0)
        {
          g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
                       "Cannot chown %s to uid=%u and gid=%u: %m",
                       mountpoint, caller_uid, caller_gid);
          success = FALSE;
          goto out;
        }
    }

  if (chmod (mountpoint, 0700) != 0)
    {
      g_set_error (error, UDISKS_ERROR, UDISKS_ERROR_FAILED,
                   "Cannot chmod %s to mode 0700: %m",
                   mountpoint);
      success = FALSE;
      goto out;
    }

 out:
  if (unmount)
    {
      if (! bd_fs_unmount (mountpoint, FALSE, FALSE, NULL, &local_error))
        {
          udisks_warning ("Error unmounting temporary mountpoint %s: %s",
                          mountpoint, local_error->message);
          g_clear_error (&local_error);
        }
      if (g_rmdir (mountpoint) != 0)
          udisks_warning ("Error removing temporary mountpoint directory %s.", mountpoint);
    }

  g_free (mountpoint);

  return success;
}