static void
update_progress_for_device (StoragedDaemon *daemon,
                            const gchar    *operation,
                            const gchar    *dev,
                            double          progress)
{
    GDBusObjectManager *object_manager;
    GList *objects, *l;

    object_manager = G_DBUS_OBJECT_MANAGER (storaged_daemon_get_object_manager (daemon));
    objects = g_dbus_object_manager_get_objects (object_manager);

    for (l = objects; l; l = l->next)
    {
        StoragedObject *object = STORAGED_OBJECT (l->data);
        StoragedJob *job;
        const gchar *const *job_objects;
        int i;

        job = storaged_object_peek_job (object);
        if (job == NULL)
            continue;

        if (g_strcmp0 (storaged_job_get_operation (job), operation) != 0)
            continue;

        job_objects = storaged_job_get_objects (job);
        for (i = 0; job_objects[i]; i++)
        {
            StoragedBlock *block = STORAGED_BLOCK (g_dbus_object_manager_get_interface (object_manager,
                                                   job_objects[i],
                                                   "org.storaged.Storaged.Block"));

            if (block)
            {
                const gchar *const *symlinks;
                int j;
                if (g_strcmp0 (storaged_block_get_device (block), dev) == 0)
                    goto found;
                symlinks = storaged_block_get_symlinks (block);
                for (j = 0; symlinks[j]; j++)
                    if (g_strcmp0 (symlinks[j], dev) == 0)
                        goto found;

                continue;
found:
                storaged_job_set_progress (job, progress);
                storaged_job_set_progress_valid (job, TRUE);
            }
        }

    }
    g_list_free_full (objects, g_object_unref);
}
Ejemplo n.º 2
0
static gboolean
handle_volume_group_create (StoragedManagerLVM2     *_object,
                            GDBusMethodInvocation   *invocation,
                            const gchar             *arg_name,
                            const gchar *const      *arg_blocks,
                            GVariant                *arg_options)
{
  StoragedLinuxManagerLVM2 *manager = STORAGED_LINUX_MANAGER_LVM2(_object);
  uid_t caller_uid;
  GError *error = NULL;
  const gchar *message;
  const gchar *action_id;
  GList *blocks = NULL;
  GList *l;
  guint n;
  gchar *escaped_name = NULL;
  GString *str = NULL;
  gint status;
  gchar *error_message = NULL;
  StoragedObject *group_object = NULL;

  error = NULL;
  if (!storaged_daemon_util_get_caller_uid_sync (manager->daemon, invocation, NULL /* GCancellable */, &caller_uid, NULL, NULL, &error))
    {
      g_dbus_method_invocation_return_gerror (invocation, error);
      g_clear_error (&error);
      goto out;
    }

  message = N_("Authentication is required to create a volume group");
  action_id = "org.storaged.Storaged.lvm2.manage-lvm";
  if (!storaged_daemon_util_check_authorization_sync (manager->daemon,
                                                      NULL,
                                                      action_id,
                                                      arg_options,
                                                      message,
                                                      invocation))
    goto out;

  /* Collect and validate block objects
   *
   * Also, check we can open the block devices at the same time - this
   * is to avoid start deleting half the block devices while the other
   * half is already in use.
   */
  for (n = 0; arg_blocks != NULL && arg_blocks[n] != NULL; n++)
    {
      StoragedObject *object = NULL;
      StoragedBlock *block = NULL;

      object = storaged_daemon_find_object (manager->daemon, arg_blocks[n]);
      if (object == NULL)
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 STORAGED_ERROR,
                                                 STORAGED_ERROR_FAILED,
                                                 "Invalid object path %s at index %u",
                                                 arg_blocks[n], n);
          goto out;
        }

      block = storaged_object_get_block (object);
      if (block == NULL)
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 STORAGED_ERROR,
                                                 STORAGED_ERROR_FAILED,
                                                 "Object path %s for index %u is not a block device",
                                                 arg_blocks[n], n);
          goto out;
        }

      if (!storaged_daemon_util_lvm2_block_is_unused (block, &error))
        {
          g_dbus_method_invocation_take_error (invocation, error);
          goto out;
        }

      blocks = g_list_prepend (blocks, block); /* adopts ownership */
      g_object_unref (object);
    }
  blocks = g_list_reverse (blocks);

  /* wipe existing devices */
  for (l = blocks; l != NULL; l = l->next)
    {
      if (!storaged_daemon_util_lvm2_wipe_block (manager->daemon, STORAGED_BLOCK (l->data), &error))
        {
          g_dbus_method_invocation_take_error (invocation, error);
          goto out;
        }
    }

  /* Create the volume group... */
  escaped_name = storaged_daemon_util_escape_and_quote (arg_name);
  str = g_string_new ("vgcreate");
  g_string_append_printf (str, " %s", escaped_name);
  for (l = blocks; l != NULL; l = l->next)
    {
      StoragedBlock *block = STORAGED_BLOCK (l->data);
      gchar *escaped_device;
      escaped_device = storaged_daemon_util_escape_and_quote (storaged_block_get_device (block));
      g_string_append_printf (str, " %s", escaped_device);
      g_free (escaped_device);
    }

  if (!storaged_daemon_launch_spawned_job_sync (manager->daemon,
                                                NULL,
                                                "lvm-vg-create", caller_uid,
                                                NULL, /* cancellable */
                                                0,    /* uid_t run_as_uid */
                                                0,    /* uid_t run_as_euid */
                                                &status,
                                                &error_message,
                                                NULL, /* input_string */
                                                "%s",
                                                str->str))
    {
      g_dbus_method_invocation_return_error (invocation,
                                             STORAGED_ERROR,
                                             STORAGED_ERROR_FAILED,
                                             "Error creating volume group: %s",
                                             error_message);
      g_free (error_message);
      goto out;
    }

  for (l = blocks; l != NULL; l = l->next)
    {
      StoragedBlock *block = STORAGED_BLOCK (l->data);
      StoragedObject *object_for_block;
      object_for_block = storaged_daemon_util_dup_object (block, &error);
      if (object_for_block != NULL)
        storaged_linux_block_object_trigger_uevent (STORAGED_LINUX_BLOCK_OBJECT (object_for_block));
      g_object_unref (object_for_block);
    }

  /* ... then, sit and wait for the object to show up */
  group_object = storaged_daemon_wait_for_object_sync (manager->daemon,
                                                       wait_for_volume_group_object,
                                                       (gpointer) arg_name,
                                                       NULL,
                                                       10, /* timeout_seconds */
                                                       &error);
  if (group_object == NULL)
    {
      g_prefix_error (&error,
                      "Error waiting for volume group object for %s",
                      arg_name);
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  storaged_manager_lvm2_complete_volume_group_create (_object,
                                                      invocation,
                                                      g_dbus_object_get_object_path (G_DBUS_OBJECT (group_object)));

 out:
  if (str != NULL)
    g_string_free (str, TRUE);
  g_list_free_full (blocks, g_object_unref);
  g_free (escaped_name);

  return TRUE; /* returning TRUE means that we handled the method invocation */
}
Ejemplo n.º 3
0
static gboolean
handle_mdraid_create (StoragedManager         *_object,
                      GDBusMethodInvocation   *invocation,
                      const gchar *const      *arg_blocks,
                      const gchar             *arg_level,
                      const gchar             *arg_name,
                      guint64                  arg_chunk,
                      GVariant                *arg_options)
{
  StoragedLinuxManager *manager = STORAGED_LINUX_MANAGER (_object);
  StoragedObject *array_object = NULL;
  uid_t caller_uid;
  GError *error = NULL;
  const gchar *message;
  const gchar *action_id;
  guint num_devices = 0;
  GList *blocks = NULL;
  GList *l;
  guint n;
  gchar *escaped_name = NULL;
  GString *str = NULL;
  gint status;
  gchar *error_message = NULL;
  gchar *raid_device_file = NULL;
  struct stat statbuf;
  dev_t raid_device_num;

  error = NULL;
  if (!storaged_daemon_util_get_caller_uid_sync (manager->daemon, invocation, NULL /* GCancellable */, &caller_uid, NULL, NULL, &error))
    {
      g_dbus_method_invocation_return_gerror (invocation, error);
      g_clear_error (&error);
      goto out;
    }

  /* Translators: Shown in authentication dialog when the user
   * attempts to start a RAID Array.
   */
  /* TODO: variables */
  message = N_("Authentication is required to create a RAID array");
  action_id = "org.storaged.Storaged.manage-md-raid";
  if (!storaged_daemon_util_check_authorization_sync (manager->daemon,
                                                      NULL,
                                                      action_id,
                                                      arg_options,
                                                      message,
                                                      invocation))
    goto out;

  /* validate level */
  for (n = 0; raid_level_whitelist[n] != NULL; n++)
    {
      if (g_strcmp0 (raid_level_whitelist[n], arg_level) == 0)
        break;
    }
  if (raid_level_whitelist[n] == NULL)
    {
      g_dbus_method_invocation_return_error (invocation, STORAGED_ERROR, STORAGED_ERROR_FAILED,
                                             "Unsupported RAID level %s", arg_level);
      goto out;
    }

  /* validate chunk (TODO: check that it's a power of 2) */
  if ((arg_chunk & 0x0fff) != 0)
    {
      g_dbus_method_invocation_return_error (invocation, STORAGED_ERROR, STORAGED_ERROR_FAILED,
                                             "Chunk %" G_GUINT64_FORMAT " is not a multiple of 4KiB", arg_chunk);
      goto out;
    }

  /* validate name */
  if (g_strcmp0 (arg_level, "raid1") == 0 && arg_chunk != 0)
    {
      g_dbus_method_invocation_return_error (invocation, STORAGED_ERROR, STORAGED_ERROR_FAILED,
                                             "Chunk must be zero for level 'raid1'");
      goto out;
    }

  /* validate name */
  if (strlen (arg_name) > 32)
    {
      g_dbus_method_invocation_return_error (invocation, STORAGED_ERROR, STORAGED_ERROR_FAILED,
                                             "Name is invalid");
      goto out;
    }

  num_devices = g_strv_length ((gchar **) arg_blocks);

  /* validate number of devices */
  if (num_devices < 2)
    {
      g_dbus_method_invocation_return_error (invocation, STORAGED_ERROR, STORAGED_ERROR_FAILED,
                                             "Must have at least two devices");
      goto out;
    }

  /* Collect and validate block objects
   *
   * Also, check we can open the block devices at the same time - this
   * is to avoid start deleting half the block devices while the other
   * half is already in use.
   */
  for (n = 0; arg_blocks != NULL && arg_blocks[n] != NULL; n++)
    {
      StoragedObject *object = NULL;
      StoragedBlock *block = NULL;
      gchar *device_file = NULL;
      int fd;

      object = storaged_daemon_find_object (manager->daemon, arg_blocks[n]);
      if (object == NULL)
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 STORAGED_ERROR,
                                                 STORAGED_ERROR_FAILED,
                                                 "Invalid object path %s at index %u",
                                                 arg_blocks[n], n);
          goto out;
        }

      block = storaged_object_get_block (object);
      if (block == NULL)
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 STORAGED_ERROR,
                                                 STORAGED_ERROR_FAILED,
                                                 "Object path %s for index %u is not a block device",
                                                 arg_blocks[n], n);
          goto out;
        }

      device_file = storaged_block_dup_device (block);
      fd = open (device_file, O_RDWR | O_EXCL);
      if (fd < 0)
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 STORAGED_ERROR,
                                                 STORAGED_ERROR_FAILED,
                                                 "Error opening device %s: %m",
                                                 device_file);
          g_free (device_file);
          goto out;
        }
      close (fd);
      g_free (device_file);

      blocks = g_list_prepend (blocks, block); /* adopts ownership */
      g_object_unref (object);
    }
  blocks = g_list_reverse (blocks);

  /* wipe existing devices */
  for (l = blocks; l != NULL; l = l->next)
    {
      StoragedBlock *block = STORAGED_BLOCK (l->data);
      StoragedObject *object_for_block;
      gchar *escaped_device;
      object_for_block = storaged_daemon_util_dup_object (block, &error);
      if (object_for_block == NULL)
        {
          g_dbus_method_invocation_return_gerror (invocation, error);
          g_clear_error (&error);
          goto out;
        }
      escaped_device = storaged_daemon_util_escape (storaged_block_get_device (block));
      if (!storaged_daemon_launch_spawned_job_sync (manager->daemon,
                                                  object_for_block,
                                                  "format-erase", caller_uid,
                                                  NULL, /* cancellable */
                                                  0,    /* uid_t run_as_uid */
                                                  0,    /* uid_t run_as_euid */
                                                  &status,
                                                  &error_message,
                                                  NULL, /* input_string */
                                                  "wipefs -a \"%s\"",
                                                  escaped_device))
        {
          g_dbus_method_invocation_return_error (invocation,
                                                 STORAGED_ERROR,
                                                 STORAGED_ERROR_FAILED,
                                                 "Error wiping device %s to be used in a RAID array: %s",
                                                 storaged_block_get_device (block),
                                                 error_message);
          g_free (error_message);
          g_object_unref (object_for_block);
          g_free (escaped_device);
          goto out;
        }
      g_object_unref (object_for_block);
      g_free (escaped_device);
    }

  /* Create the array... */
  escaped_name = storaged_daemon_util_escape (arg_name);
  str = g_string_new ("mdadm");
  raid_device_file = storaged_daemon_util_get_free_mdraid_device ();
  if (raid_device_file == NULL)
    {
      g_dbus_method_invocation_return_error (invocation, STORAGED_ERROR, STORAGED_ERROR_FAILED,
                                             "Unable to find free MD device");
      goto out;
    }
  g_string_append_printf (str, " --create %s", raid_device_file);
  g_string_append_printf (str, " --run");
  if (arg_chunk > 0)
    g_string_append_printf (str, " --chunk %" G_GUINT64_FORMAT, (guint64) (arg_chunk / 1024LL));
  g_string_append_printf (str, " --level %s", arg_level);
  if (strlen (arg_name) > 0)
    g_string_append_printf (str, " --name \"%s\"", escaped_name);
  g_string_append_printf (str, " --raid-devices %u", num_devices);
  for (l = blocks; l != NULL; l = l->next)
    {
      StoragedBlock *block = STORAGED_BLOCK (l->data);
      gchar *escaped_device;
      escaped_device = storaged_daemon_util_escape (storaged_block_get_device (block));
      g_string_append_printf (str, " \"%s\"", escaped_device);
      g_free (escaped_device);
    }

  if (!storaged_daemon_launch_spawned_job_sync (manager->daemon,
                                                NULL,
                                                "mdraid-create", caller_uid,
                                                NULL, /* cancellable */
                                                0,    /* uid_t run_as_uid */
                                                0,    /* uid_t run_as_euid */
                                                &status,
                                                &error_message,
                                                NULL, /* input_string */
                                                "%s",
                                                str->str))
    {
      g_dbus_method_invocation_return_error (invocation,
                                             STORAGED_ERROR,
                                             STORAGED_ERROR_FAILED,
                                             "Error creating RAID array: %s",
                                             error_message);
      g_free (error_message);
      goto out;
    }

  /* ... then, sit and wait for raid array object to show up */
  array_object = storaged_daemon_wait_for_object_sync (manager->daemon,
                                                       wait_for_array_object,
                                                       raid_device_file,
                                                       NULL,
                                                       10, /* timeout_seconds */
                                                       &error);
  if (array_object == NULL)
    {
      g_prefix_error (&error,
                      "Error waiting for array object after creating %s",
                      raid_device_file);
      g_dbus_method_invocation_take_error (invocation, error);
      goto out;
    }

  if (stat (raid_device_file, &statbuf) != 0)
    {
      g_dbus_method_invocation_return_error (invocation,
                                             STORAGED_ERROR,
                                             STORAGED_ERROR_FAILED,
                                             "Error calling stat(2) on %s: %m",
                                             raid_device_file);
      goto out;
    }
  if (!S_ISBLK (statbuf.st_mode))
    {
      g_dbus_method_invocation_return_error (invocation,
                                             STORAGED_ERROR,
                                             STORAGED_ERROR_FAILED,
                                             "Device file %s is not a block device",
                                             raid_device_file);
      goto out;
    }
  raid_device_num = statbuf.st_rdev;

  /* update the mdraid file */
  storaged_state_add_mdraid (storaged_daemon_get_state (manager->daemon),
                             raid_device_num,
                             caller_uid);

  /* ... wipe the created RAID array */
  if (!storaged_daemon_launch_spawned_job_sync (manager->daemon,
                                                array_object,
                                                "format-erase", caller_uid,
                                                NULL, /* cancellable */
                                                0,    /* uid_t run_as_uid */
                                                0,    /* uid_t run_as_euid */
                                                &status,
                                                &error_message,
                                                NULL, /* input_string */
                                                "wipefs -a %s",
                                                raid_device_file))
    {
      g_dbus_method_invocation_return_error (invocation,
                                             STORAGED_ERROR,
                                             STORAGED_ERROR_FAILED,
                                             "Error wiping raid device %s: %s",
                                             raid_device_file,
                                             error_message);
      goto out;
    }

  /* ... finally trigger uevents on the members - we want this so the
   * udev database is updated for them with e.g. ID_FS_TYPE. Ideally
   * mdadm(8) or whatever thing is writing out the RAID metadata would
   * ensure this, but that's not how things currently work :-/
   */
  for (l = blocks; l != NULL; l = l->next)
    {
      StoragedBlock *block = STORAGED_BLOCK (l->data);
      StoragedObject *object_for_block;
      object_for_block = storaged_daemon_util_dup_object (block, &error);
      if (object_for_block == NULL)
        {
          g_dbus_method_invocation_return_gerror (invocation, error);
          g_clear_error (&error);
          goto out;
        }
      storaged_linux_block_object_trigger_uevent (STORAGED_LINUX_BLOCK_OBJECT (object_for_block));
      g_object_unref (object_for_block);
    }

  /* ... and, we're done! */
  storaged_manager_complete_mdraid_create (_object,
                                           invocation,
                                           g_dbus_object_get_object_path (G_DBUS_OBJECT (array_object)));

 out:
  g_free (raid_device_file);
  if (str != NULL)
    g_string_free (str, TRUE);
  g_list_free_full (blocks, g_object_unref);
  g_free (escaped_name);
  g_clear_object (&array_object);

  return TRUE; /* returning TRUE means that we handled the method invocation */
}