Commit message: Bug 27494 — publicly exports dm key information

Change udisks-dm-export to only export UDISKS_DM_TARGETS_PARAMS for "linear"
types. It is the only one we care about for now and know how to interpret.
"crypto" types have information about the encryption key in the target
parameters, which we must not leak.

Also add appropriate comments to the two places which currently evaluate
UDISKS_DM_TARGETS_PARAMS.
CVE: CVE-2010-1149
CWE: CWE-200
Vulnerability description: probers/udisks-dm-export.c in udisks before 1.0.1 exports UDISKS_DM_TARGETS_PARAMS information to udev even for a crypt UDISKS_DM_TARGETS_TYPE, which allows local users to discover encryption keys by (1) running a certain udevadm command or (2) reading a certain file under /dev/.udev/db/.

Project: udisks
File: device.c

device_partition_modify_authorized_cb (Daemon *daemon,
                                       Device *device,
                                       DBusGMethodInvocation *context,
                                       const gchar *action_id,
                                       guint num_user_data,
                                       gpointer *user_data_elements)
{
  const char *type = user_data_elements[0];
  const char *label = user_data_elements[1];
  char **flags = user_data_elements[2];
  int n;
  char *argv[128];
  GError *error;
  char *offset_as_string;
  char *size_as_string;
  char *flags_as_string;
  Device *enclosing_device;

  offset_as_string = NULL;
  size_as_string = NULL;
  flags_as_string = NULL;
  error = NULL;

  if (!device->priv->device_is_partition)
    {
      throw_error (context, ERROR_FAILED, "Device is not a partition");
      goto out;
    }

  enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
  if (enclosing_device == NULL)
    {
      throw_error (context, ERROR_FAILED, "Cannot find enclosing device");
      goto out;
    }

  if (device_local_is_busy (enclosing_device, FALSE, &error))
    {
      dbus_g_method_return_error (context, error);
      g_error_free (error);
      goto out;
    }

  if (strlen (type) == 0)
    {
      throw_error (context, ERROR_FAILED, "type not specified");
      goto out;
    }

  offset_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_offset);
  size_as_string = g_strdup_printf ("%" G_GINT64_FORMAT "", device->priv->partition_size);
  /* TODO: check that neither of the flags include ',' */
  flags_as_string = g_strjoinv (",", flags);

  n = 0;
  argv[n++] = "udisks-helper-modify-partition";
  argv[n++] = enclosing_device->priv->device_file;
  argv[n++] = offset_as_string;
  argv[n++] = size_as_string;
  argv[n++] = (char *) type;
  argv[n++] = (char *) label;
  argv[n++] = (char *) flags_as_string;
  argv[n++] = NULL;

  if (!job_new (context,
                "PartitionModify",
                TRUE,
                device,
                argv,
                NULL,
                partition_modify_completed_cb,
                FALSE,
                partition_modify_data_new (context, device, enclosing_device, type, label, flags),
                (GDestroyNotify) partition_modify_data_unref))
    {
      goto out;
    }

 out:
  g_free (offset_as_string);
  g_free (size_as_string);
  g_free (flags_as_string);
}

Project: udisks
File: device.c

device_partition_table_create (Device *device,
                               const char *scheme,
                               char **options,
                               DBusGMethodInvocation *context)
{
  daemon_local_check_auth (device->priv->daemon,
                           device,
                           device->priv->device_is_system_internal ? "org.freedesktop.udisks.change-system-internal"
                           : "org.freedesktop.udisks.change",
                           "PartitionTableCreate",
                           TRUE,
                           device_partition_table_create_authorized_cb,
                           context,
                           2,
                           g_strdup (scheme),
                           g_free,
                           g_strdupv (options),
                           g_strfreev);
  return TRUE;
}

Project: udisks
File: device.c

device_partition_table_create_authorized_cb (Daemon *daemon,
                                             Device *device,
                                             DBusGMethodInvocation *context,
                                             const gchar *action_id,
                                             guint num_user_data,
                                             gpointer *user_data_elements)
{
  const char *scheme = user_data_elements[0];
  char **options = user_data_elements[1];
  int n;
  int m;
  char *argv[128];
  GError *error;

  error = NULL;

  if (device_local_is_busy (device, TRUE, &error))
    {
      dbus_g_method_return_error (context, error);
      g_error_free (error);
      goto out;
    }

  if (strlen (scheme) == 0)
    {
      throw_error (context, ERROR_FAILED, "type not specified");
      goto out;
    }

  n = 0;
  argv[n++] = "udisks-helper-create-partition-table";
  if (device->priv->device_is_linux_dmmp)
    argv[n++] = (gchar *) get_dmmp_device_node (device);
  else
    argv[n++] = device->priv->device_file;
  argv[n++] = (char *) scheme;
  for (m = 0; options[m] != NULL; m++)
    {
      if (n >= (int) sizeof(argv) - 1)
        {
          throw_error (context, ERROR_FAILED, "Too many options");
          goto out;
        }
      /* the helper will validate each option */
      argv[n++] = (char *) options[m];
    }
  argv[n++] = NULL;

  if (!job_new (context,
                "PartitionTableCreate",
                TRUE,
                device,
                argv,
                NULL,
                partition_table_create_completed_cb,
                FALSE,
                partition_table_create_data_new (context, device, scheme),
                (GDestroyNotify) partition_table_create_data_unref))
    {
      goto out;
    }

 out:
  ;
}

Project: udisks
File: device.c

device_removed (Device *device)
{
  guint n;

  device->priv->removed = TRUE;

  dbus_g_connection_unregister_g_object (device->priv->system_bus_connection, G_OBJECT (device));
  g_assert (dbus_g_connection_lookup_g_object (device->priv->system_bus_connection, device->priv->object_path) == NULL);

  /* device is now removed; update all slaves and holders */
  for (n = 0; n < device->priv->slaves_objpath->len; n++)
    {
      const gchar *objpath2 = ((gchar **) device->priv->slaves_objpath->pdata)[n];
      Device *device2;

      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
      if (device2 != NULL)
        {
          update_info (device2);
        }
    }
  for (n = 0; n < device->priv->holders_objpath->len; n++)
    {
      const gchar *objpath2 = ((gchar **) device->priv->holders_objpath->pdata)[n];
      Device *device2;

      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
      if (device2 != NULL)
        {
          update_info (device2);
        }
    }

  /* If the device is busy, we possibly need to clean up if the
   * device itself is busy. This includes
   *
   *  - force unmounting the device and/or all it's partitions
   *
   *  - tearing down a luks mapping if it's a cleartext device
   *    backed by a crypted device
   *
   * but see force_removal() for details.
   *
   * This is the normally the path where the enclosing device is
   * removed. Compare with device_changed() for the
   * other path.
   */
  force_removal (device, NULL, NULL);
}

Project: udisks
File: device.c

diff_sorted_lists (GList *list1,
                   GList *list2,
                   GCompareFunc compare,
                   GList **added,
                   GList **removed)
{
  int order;

  *added = *removed = NULL;

  while (list1 != NULL && list2 != NULL)
    {
      order = (*compare) (list1->data, list2->data);
      if (order < 0)
        {
          *removed = g_list_prepend (*removed, list1->data);
          list1 = list1->next;
        }
      else if (order > 0)
        {
          *added = g_list_prepend (*added, list2->data);
          list2 = list2->next;
        }
      else
        { /* same item */
          list1 = list1->next;
          list2 = list2->next;
        }
    }

  while (list1 != NULL)
    {
      *removed = g_list_prepend (*removed, list1->data);
      list1 = list1->next;
    }
  while (list2 != NULL)
    {
      *added = g_list_prepend (*added, list2->data);
      list2 = list2->next;
    }
}

Project: udisks
File: device.c

drain_pending_changes (Device *device,
                       gboolean force_update)
{
  gboolean emit_changed;

  emit_changed = FALSE;

  /* the update-in-idle is set up if, and only if, there are pending changes - so
   * we should emit a 'change' event only if it is set up
   */
  if (device->priv->emit_changed_idle_id != 0)
    {
      g_source_remove (device->priv->emit_changed_idle_id);
      device->priv->emit_changed_idle_id = 0;
      emit_changed = TRUE;
    }

  if ((!device->priv->removed) && (emit_changed || force_update))
    {
      if (device->priv->object_path != NULL)
        {
          g_print ("**** EMITTING CHANGED for %s\n", device->priv->native_path);
          g_signal_emit_by_name (device, "changed");
          g_signal_emit_by_name (device->priv->daemon, "device-changed", device->priv->object_path);
        }
    }
}

Project: udisks
File: device.c

drive_ata_smart_initiate_selftest_completed_cb (DBusGMethodInvocation *context,
                                                Device *device,
                                                gboolean job_was_cancelled,
                                                int status,
                                                const char *stderr,
                                                const char *stdout,
                                                gpointer user_data)
{
  char *options[] =
    { NULL };

  /* no matter what happened, refresh the data */
  device_drive_ata_smart_refresh_data (device, options, NULL);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      dbus_g_method_return (context);

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error running self test: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

drive_ata_smart_refresh_data_completed_cb (DBusGMethodInvocation *context,
                                           Device *device,
                                           gboolean job_was_cancelled,
                                           int status,
                                           const char *stderr,
                                           const char *stdout,
                                           gpointer user_data)
{
  gint rc;
  SkDisk *d;
  gchar *blob;
  gsize blob_size;
  time_t time_collected;
  SkSmartOverall overall;

  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) start", device->priv->native_path);

  d = NULL;
  blob = NULL;

  if (job_was_cancelled || stdout == NULL)
    {
      if (job_was_cancelled)
        {
          if (context != NULL)
            throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          if (context != NULL)
            throw_error (context,
                         ERROR_FAILED,
                         "Error retrieving ATA SMART data: no output",
                         WEXITSTATUS (status),
                         stderr);
        }
      goto out;
    }

  rc = WEXITSTATUS (status);

  if (rc != 0)
    {
      if (rc == 2)
        {
          if (context != NULL)
            {
              throw_error (context, ERROR_ATA_SMART_WOULD_WAKEUP, "Error retrieving ATA SMART data: %s", stderr);
            }
        }
      else
        {
          if (context != NULL)
            {
              throw_error (context,
                           ERROR_FAILED,
                           "Error retrieving ATA SMART data: helper failed with exit code %d: %s",
                           rc,
                           stderr);
            }
        }
      goto out;
    }

  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) decode blob", device->priv->native_path);
  blob = (gchar *) g_base64_decode (stdout, &blob_size);

  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) set blob", device->priv->native_path);
  if (blob == NULL)
    {
      if (context != NULL)
        {
          throw_error (context, ERROR_FAILED, "Error decoding ATA SMART data: invalid base64 format: %s", stdout);
        }
      else
        {
          g_warning ("Error decoding ATA SMART data: invalid base64 format: %s", stdout);
        }
      goto out;
    }

  if (sk_disk_open (NULL, &d) != 0)
    {
      if (context != NULL)
        {
          throw_error (context, ERROR_FAILED, "unable to open a SkDisk");
        }
      goto out;
    }

  if (sk_disk_set_blob (d, blob, blob_size) != 0)
    {
      if (context != NULL)
        {
          throw_error (context, ERROR_FAILED, "error parsing blob: %s", strerror (errno));
        }
      goto out;
    }

  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) time collected", device->priv->native_path);
  time_collected = time (NULL);
  device_set_drive_ata_smart_time_collected (device, time_collected);

  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) overall smart status", device->priv->native_path);
  if (sk_disk_smart_get_overall (d, &overall) != 0)
    overall = -1;
  device_set_drive_ata_smart_status (device, overall);
  device_set_drive_ata_smart_blob_steal (device, blob, blob_size);
  blob = NULL;

  /* emit change event since we've updated the smart data */
  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) drain pending changes", device->priv->native_path);
  drain_pending_changes (device, FALSE);

  if (context != NULL)
    dbus_g_method_return (context);

 out:
  g_free (blob);
  if (d != NULL)
    sk_disk_free (d);
  PROFILE ("drive_ata_smart_refresh_data_completed_cb(device=%s) end", device->priv->native_path);
}

Project: udisks
File: device.c

drive_benchmark_completed_cb (DBusGMethodInvocation *context,
                              Device *device,
                              gboolean job_was_cancelled,
                              int status,
                              const gchar *stderr,
                              const gchar *stdout,
                              gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      GPtrArray *read_transfer_rate_array;
      GPtrArray *write_transfer_rate_array;
      GPtrArray *access_time_array;
      gchar **lines;
      guint n;
      GType elem_gtype;

      elem_gtype = dbus_g_type_get_struct ("GValueArray", G_TYPE_UINT64, G_TYPE_DOUBLE, G_TYPE_INVALID);

      read_transfer_rate_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
      write_transfer_rate_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);
      access_time_array = g_ptr_array_new_with_free_func ((GDestroyNotify) g_value_array_free);

      lines = g_strsplit (stdout, "\n", 0);
      for (n = 0; lines != NULL && lines[n] != NULL; n++)
        {
          const gchar *line = lines[n];
          guint64 offset;
          gdouble rate;
          gdouble access_time;
          GValue elem =
            { 0 };

          if (sscanf (line, "read_transfer_rate: offset %" G_GUINT64_FORMAT " rate %lf",
                      &offset,
                      &rate) == 2)
            {

              g_value_init (&elem, elem_gtype);
              g_value_take_boxed (&elem, dbus_g_type_specialized_construct (elem_gtype));
              dbus_g_type_struct_set (&elem, 0, offset, 1, rate, G_MAXUINT);
              g_ptr_array_add (read_transfer_rate_array, g_value_get_boxed (&elem));

            }
          else if (sscanf (line, "write_transfer_rate: offset %" G_GUINT64_FORMAT " rate %lf",
                           &offset,
                           &rate) == 2)
            {

              g_value_init (&elem, elem_gtype);
              g_value_take_boxed (&elem, dbus_g_type_specialized_construct (elem_gtype));
              dbus_g_type_struct_set (&elem, 0, offset, 1, rate, G_MAXUINT);
              g_ptr_array_add (write_transfer_rate_array, g_value_get_boxed (&elem));

            }
          else if (sscanf (line, "access_time: offset %" G_GUINT64_FORMAT " time %lf",
                           &offset,
                           &access_time) == 2)
            {

              g_value_init (&elem, elem_gtype);
              g_value_take_boxed (&elem, dbus_g_type_specialized_construct (elem_gtype));
              dbus_g_type_struct_set (&elem, 0, offset, 1, access_time, G_MAXUINT);
              g_ptr_array_add (access_time_array, g_value_get_boxed (&elem));

            }
          else
            {
              g_warning ("unhandled line %d: `%s'", n, line);
            }

        }
      g_strfreev (lines);

      dbus_g_method_return (context, read_transfer_rate_array, write_transfer_rate_array, access_time_array);

      g_ptr_array_unref (read_transfer_rate_array);
      g_ptr_array_unref (write_transfer_rate_array);
      g_ptr_array_unref (access_time_array);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error benchmarking: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

drive_detach_completed_cb (DBusGMethodInvocation *context,
                           Device *device,
                           gboolean job_was_cancelled,
                           int status,
                           const char *stderr,
                           const char *stdout,
                           gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      /* TODO: probably wait for has_media to change to FALSE */
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error detaching: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

drive_eject_completed_cb (DBusGMethodInvocation *context,
                          Device *device,
                          gboolean job_was_cancelled,
                          int status,
                          const char *stderr,
                          const char *stdout,
                          gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      /* TODO: probably wait for has_media to change to FALSE */
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error ejecting: eject exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

drive_poll_media_completed_cb (DBusGMethodInvocation *context,
                               Device *device,
                               gboolean job_was_cancelled,
                               int status,
                               const char *stderr,
                               const char *stdout,
                               gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      device_generate_kernel_change_event (device);

      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error detaching: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

dup_list_from_ptrarray (GPtrArray *p)
{
  GList *ret;
  guint n;

  ret = NULL;

  for (n = 0; n < p->len; n++)
    ret = g_list_prepend (ret, g_strdup (((gchar **) p->pdata)[n]));

  return ret;
}

Project: udisks
File: device.c

emit_job_changed (Device *device)
{
  drain_pending_changes (device, FALSE);

  if (!device->priv->removed)
    {
      g_print ("**** EMITTING JOB-CHANGED for %s\n", device->priv->native_path);
      g_signal_emit_by_name (device->priv->daemon,
                             "device-job-changed",
                             device->priv->object_path,
                             device->priv->job_in_progress,
                             device->priv->job_id,
                             device->priv->job_initiated_by_uid,
                             device->priv->job_is_cancellable,
                             device->priv->job_percentage,
                             NULL);
      g_signal_emit (device,
                     signals[JOB_CHANGED_SIGNAL],
                     0,
                     device->priv->job_in_progress,
                     device->priv->job_id,
                     device->priv->job_initiated_by_uid,
                     device->priv->job_is_cancellable,
                     device->priv->job_percentage);
    }
}

Project: udisks
File: device.c

extract_lvm_uuid (const gchar *s)
{
  GString *str;

  if (s == NULL || strlen (s) < 32)
    return NULL;

  str = g_string_new_len (s, 6);   g_string_append_c (str, '-'); s += 6;
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
  g_string_append_len (str, s, 4); g_string_append_c (str, '-'); s += 4;
  g_string_append_len (str, s, 6);

  return g_string_free (str, FALSE);
}

Project: udisks
File: device.c

filesystem_check_completed_cb (DBusGMethodInvocation *context,
                               Device *device,
                               gboolean job_was_cancelled,
                               int status,
                               const char *stderr,
                               const char *stdout,
                               gpointer user_data)
{
  if (WIFEXITED (status) && !job_was_cancelled)
    {
      int rc;
      gboolean fs_is_clean;

      fs_is_clean = FALSE;

      rc = WEXITSTATUS (status);
      if ((rc == 0) || (((rc & 1) != 0) && ((rc & 4) == 0)))
        {
          fs_is_clean = TRUE;
        }

      dbus_g_method_return (context, fs_is_clean);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error fsck'ing: fsck exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

filesystem_create_completed_cb (DBusGMethodInvocation *context,
                                Device *device,
                                gboolean job_was_cancelled,
                                int status,
                                const char *stderr,
                                const char *stdout,
                                gpointer user_data)
{
  MkfsData *data = user_data;

  /* poke the kernel so we can reread the data */
  device_generate_kernel_change_event (device);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      if (data->hook_func != NULL)
        data->hook_func (context, device, TRUE, data->hook_user_data);
      else
        dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else if (WEXITSTATUS (status) == 3)
        {
          throw_error (context,
                       ERROR_FILESYSTEM_TOOLS_MISSING,
                       "Error creating file system: Cannot run mkfs: %s",
                       stderr);
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error creating file system: helper exited with exit code %d: %s\n%s",
                       WEXITSTATUS (status),
                       stderr,
                       stdout);
        }

      if (data->hook_func != NULL)
        data->hook_func (context, device, FALSE, data->hook_user_data);
    }
}

Project: udisks
File: device.c

filesystem_create_create_luks_device_completed_cb (DBusGMethodInvocation *context,
                                                   Device *device,
                                                   gboolean job_was_cancelled,
                                                   int status,
                                                   const char *stderr,
                                                   const char *stdout,
                                                   gpointer user_data)
{
  MkfsLuksData *data = user_data;

  /* poke the kernel so we can reread the data (new uuid etc.) */
  device_generate_kernel_change_event (device);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      /* OK! So we've got ourselves an luks device. Let's set it up so we can create a file
       * system. Sit and wait for the change event to appear so we can setup with the right UUID.
       */

      data->device_changed_signal_handler_id
        = g_signal_connect_after (device->priv->daemon,
                                  "device-changed",
                                  (GCallback) filesystem_create_wait_for_luks_device_changed_cb,
                                  mkfse_data_ref (data));

      /* set up timeout for error reporting if waiting failed
       *
       * (the signal handler and the timeout handler share the ref to data
       * as one will cancel the other)
       */
      data->device_changed_timeout_id = g_timeout_add (10 * 1000,
                                                       filesystem_create_wait_for_luks_device_not_seen_cb,
                                                       data);

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error creating file system: cryptsetup exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

filesystem_create_wait_for_cleartext_device_hook (DBusGMethodInvocation *context,
                                                  Device *device,
                                                  gpointer user_data)
{
  MkfsLuksData *data = user_data;

  if (device == NULL)
    {
      /* Dang, unlocking failed. The unlock method have already thrown an exception for us. */
    }
  else
    {
      /* We're unlocked.. awesome.. Now we can _finally_ create the file system.
       * What a ride. We're returning to exactly to where we came from. Back to
       * the source. Only the device is different.
       */

      device_filesystem_create_internal (device,
                                         data->fstype,
                                         data->options,
                                         data->mkfs_hook_func,
                                         data->mkfs_hook_user_data,
                                         data->context);
      mkfse_data_unref (data);
    }
}

Project: udisks
File: device.c

filesystem_create_wait_for_luks_device_changed_cb (Daemon *daemon,
                                                   const char *object_path,
                                                   gpointer user_data)
{
  MkfsLuksData *data = user_data;
  Device *device;

  /* check if we're now a LUKS crypto device */
  device = daemon_local_find_by_object_path (daemon, object_path);
  if (device == data->device && (device->priv->id_usage != NULL && strcmp (device->priv->id_usage, "crypto") == 0)
      && (device->priv->id_type != NULL && strcmp (device->priv->id_type, "crypto_LUKS") == 0))
    {

      /* yay! we are now set up the corresponding cleartext device */

      device_luks_unlock_internal (data->device,
                                   data->passphrase,
                                   NULL,
                                   filesystem_create_wait_for_cleartext_device_hook,
                                   data,
                                   data->context);

      g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
      g_source_remove (data->device_changed_timeout_id);
    }
}

Project: udisks
File: device.c

filesystem_create_wait_for_luks_device_not_seen_cb (gpointer user_data)
{
  MkfsLuksData *data = user_data;

  throw_error (data->context,
               ERROR_FAILED,
               "Error creating luks encrypted file system: timeout (10s) waiting for luks device to show up");

  g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);
  mkfse_data_unref (data);

  return FALSE;
}

Project: udisks
File: device.c

filesystem_list_open_files_completed_cb (DBusGMethodInvocation *context,
                                         Device *device,
                                         gboolean job_was_cancelled,
                                         int status,
                                         const char *stderr,
                                         const char *stdout,
                                         gpointer user_data)
{
  if ((WEXITSTATUS (status) == 0 || WEXITSTATUS (status) == 1) && !job_was_cancelled)
    {
      GPtrArray *processes;

      processes = g_ptr_array_new ();
      lsof_parse (stdout, processes);
      dbus_g_method_return (context, processes);
      g_ptr_array_foreach (processes, (GFunc) g_value_array_free, NULL);
      g_ptr_array_free (processes, TRUE);
    }
  else
    {
      throw_error (context,
                   ERROR_FAILED,
                   "Error listing open files: lsof exited with exit code %d: %s",
                   WEXITSTATUS (status),
                   stderr);
    }
}

Project: udisks
File: device.c

filesystem_mount_completed_cb (DBusGMethodInvocation *context,
                               Device *device,
                               gboolean job_was_cancelled,
                               int status,
                               const char *stderr,
                               const char *stdout,
                               gpointer user_data)
{
  MountData *data = (MountData *) user_data;
  uid_t uid;

  daemon_local_get_uid (device->priv->daemon, &uid, context);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      update_info (device);
      drain_pending_changes (device, FALSE);
      unlock_cd_tray (device);

      dbus_g_method_return (context, data->mount_point);
    }
  else
    {
      if (data->remove_dir_on_unmount)
        {
          mount_file_remove (device->priv->device_file, data->mount_point);
          if (g_rmdir (data->mount_point) != 0)
            {
              g_warning ("Error removing dir in late mount error path: %m");
            }
        }

      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else if (WEXITSTATUS (status) == 32)
        {
          throw_error (context, ERROR_FILESYSTEM_DRIVER_MISSING, "Error mounting: %s", stderr);
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error mounting: mount exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

filesystem_mount_data_free (MountData *data)
{
  g_free (data->mount_point);
  g_free (data);
}

Project: udisks
File: device.c

filesystem_mount_data_new (const char *mount_point,
                           gboolean remove_dir_on_unmount)
{
  MountData *data;
  data = g_new0 (MountData, 1);
  data->mount_point = g_strdup (mount_point);
  data->remove_dir_on_unmount = remove_dir_on_unmount;
  return data;
}

Project: udisks
File: device.c

filesystem_set_label_completed_cb (DBusGMethodInvocation *context,
                                   Device *device,
                                   gboolean job_was_cancelled,
                                   int status,
                                   const char *stderr,
                                   const char *stdout,
                                   gpointer user_data)
{
  char *new_label = user_data;

  /* poke the kernel so we can reread the data */
  device_generate_kernel_change_event (device);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      /* update local copy, don't wait for the kernel */
      device_set_id_label (device, new_label);

      drain_pending_changes (device, FALSE);

      dbus_g_method_return (context);

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error changing fslabel: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

filesystem_unmount_completed_cb (DBusGMethodInvocation *context,
                                 Device *device,
                                 gboolean job_was_cancelled,
                                 int status,
                                 const char *stderr,
                                 const char *stdout,
                                 gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      /* update_info_mount_state() will update the mounts file and clean up the directory if needed */
      update_info (device);
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          if (strstr (stderr, "device is busy") != NULL)
            {
              throw_error (context, ERROR_BUSY, "Cannot unmount because file system on device is busy");
            }
          else
            {
              throw_error (context,
                           ERROR_FAILED,
                           "Error unmounting: umount exited with exit code %d: %s",
                           WEXITSTATUS (status),
                           stderr);
            }
        }
    }
}

Project: udisks
File: device.c

find_cleartext_device (Device *device)
{
  GList *devices;
  GList *l;
  Device *ret;

  ret = NULL;

  /* check that there isn't a cleartext device already  */
  devices = daemon_local_get_all_devices (device->priv->daemon);
  for (l = devices; l != NULL; l = l->next)
    {
      Device *d = DEVICE (l->data);
      if (d->priv->device_is_luks_cleartext && d->priv->luks_cleartext_slave != NULL
          && strcmp (d->priv->luks_cleartext_slave, device->priv->object_path) == 0)
        {
          ret = d;
          goto out;
        }
    }

 out:

  g_list_free (devices);

  return ret;
}

Project: udisks
File: device.c

find_lvm2_lv_name_for_uuids (Daemon *daemon,
                             const gchar *group_uuid,
                             const gchar *uuid)
{
  GList *l;
  GList *devices;
  gchar *ret;

  ret = NULL;

  devices = daemon_local_get_all_devices (daemon);
  for (l = devices; l != NULL; l = l->next)
    {
      Device *d = DEVICE (l->data);

      if (d->priv->device_is_linux_lvm2_pv &&
          g_strcmp0 (group_uuid, d->priv->linux_lvm2_pv_group_uuid) == 0)
        {
          guint n;

          for (n = 0; n < d->priv->linux_lvm2_pv_group_logical_volumes->len; n++)
            {
              const gchar *lv_data = d->priv->linux_lvm2_pv_group_logical_volumes->pdata[n];
              gchar **tokens;
              guint m;

              tokens = g_strsplit (lv_data, ";", 0);
              for (m = 0; tokens != NULL && tokens[m] != NULL; m++)
                {
                  if (g_str_has_prefix (tokens[m], "uuid=") && g_strcmp0 (tokens[m] + 5, uuid) == 0)
                    {
                      guint c;
                      for (c = 0; tokens[c] != NULL; c++)
                        {
                          if (g_str_has_prefix (tokens[c], "name="))
                            {
                              ret = g_strdup_printf ("%s/%s",
                                                     d->priv->linux_lvm2_pv_group_name,
                                                     tokens[c] + 5);
                              break;
                            }
                        }
                    }
                }
              g_strfreev (tokens);

              if (ret != NULL)
                break;
            }
        }
      if (ret != NULL)
        break;
    }
  g_list_free (devices);

  return ret;
}

Project: udisks
File: device.c

find_lvm2_vg_name_for_uuid (Daemon *daemon,
                            const gchar *uuid)
{
  GList *l;
  GList *devices;
  const gchar *vg_name;

  vg_name = NULL;

  devices = daemon_local_get_all_devices (daemon);
  for (l = devices; l != NULL; l = l->next)
    {
      Device *d = DEVICE (l->data);

      if (d->priv->device_is_linux_lvm2_pv && g_strcmp0 (uuid, d->priv->linux_lvm2_pv_group_uuid) == 0)
        {
          vg_name = d->priv->linux_lvm2_pv_group_name;
          break;
        }
    }
  g_list_free (devices);

  return vg_name;
}

Project: udisks
File: device.c

find_primary_gid (uid_t uid)
{
  struct passwd *pw;
  gid_t gid;

  gid = (gid_t) - 1;

  pw = getpwuid (uid);
  if (pw == NULL)
    {
      g_warning ("Couldn't look up uid %d: %m", uid);
      goto out;
    }
  gid = pw->pw_gid;

 out:
  return gid;
}

Project: udisks
File: device.c

force_luks_teardown (Device *device,
                     Device *cleartext_device,
                     ForceRemovalCompleteFunc callback,
                     gpointer user_data)
{
  /* first we gotta force remove the clear text device */
  force_removal (cleartext_device,
                 force_luks_teardown_cleartext_done,
                 force_luks_teardown_data_new (device, cleartext_device->priv->dm_name, callback, user_data));
}

Project: udisks

force_luks_teardown_cleartext_done (Device *device,
                                    gboolean success,
                                    gpointer user_data)
{
  int n;
  char *argv[16];
  ForceLuksTeardownData *data = user_data;

  if (!success)
    {
      if (data->fr_callback != NULL)
        data->fr_callback (data->device, FALSE, data->fr_user_data);

      force_luks_teardown_data_unref (data);
      goto out;
    }

  /* ok, clear text device is out of the way; now tear it down */

  n = 0;
  argv[n++] = "cryptsetup";
  argv[n++] = "luksClose";
  argv[n++] = data->dm_name;
  argv[n++] = NULL;


  if (!job_new (NULL,
                "ForceLuksTeardown",
                FALSE,
                data->device,
                argv,
                NULL,
                force_luks_teardown_completed_cb,
                FALSE,
                data,
                (GDestroyNotify) force_luks_teardown_data_unref))
    {

      g_warning ("Couldn't spawn cryptsetup for force teardown for device %s", data->dm_name);
      if (data->fr_callback != NULL)
        data->fr_callback (data->device, FALSE, data->fr_user_data);

      force_luks_teardown_data_unref (data);
    }
 out:
  ;
}

Project: udisks
File: device.c

force_luks_teardown_completed_cb (DBusGMethodInvocation *context,
                                  Device *device,
                                  gboolean job_was_cancelled,
                                  int status,
                                  const char *stderr,
                                  const char *stdout,
                                  gpointer user_data)
{
  ForceLuksTeardownData *data = user_data;

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      g_print ("**** NOTE: Successfully teared down luks device %s\n", device->priv->device_file);

      if (data->fr_callback != NULL)
        data->fr_callback (device, TRUE, data->fr_user_data);
    }
  else
    {
      g_print ("**** NOTE: force luks teardown failed: %s\n", stderr);
      if (data->fr_callback != NULL)
        data->fr_callback (device, FALSE, data->fr_user_data);
    }
}

Project: udisks
File: device.c

force_luks_teardown_data_new (Device *device,
                              const char *dm_name,
                              ForceRemovalCompleteFunc fr_callback,
                              gpointer fr_user_data)
{
  ForceLuksTeardownData *data;

  data = g_new0 (ForceLuksTeardownData, 1);
  data->device = g_object_ref (device);
  data->dm_name = g_strdup (dm_name);
  data->fr_callback = fr_callback;
  data->fr_user_data = fr_user_data;
  return data;
}

Project: udisks
File: device.c

force_luks_teardown_data_unref (ForceLuksTeardownData *data)
{
  if (data->device != NULL)
    g_object_unref (data->device);
  g_free (data->dm_name);
  g_free (data);
}

Project: udisks

force_removal (Device *device,
               ForceRemovalCompleteFunc callback,
               gpointer user_data)
{

  /* Device is going bye bye. If this device is
   *
   *  - Mounted by us, then forcibly unmount it.
   *
   *  - If it's a luks device, check if there's cleartext
   *    companion. If so, tear it down if it was setup by us.
   *
   */
  if (device->priv->device_is_mounted && device->priv->device_mount_paths->len > 0)
    {
      gboolean remove_dir_on_unmount;

      if (mount_file_has_device (device->priv->device_file, NULL, &remove_dir_on_unmount) ||
          is_device_in_fstab (device, NULL))
        {
          g_print ("**** NOTE: Force unmounting device %s\n", device->priv->device_file);
          force_unmount (device, callback, user_data);
          goto pending;
        }
    }

  if (device->priv->id_usage != NULL && strcmp (device->priv->id_usage, "crypto") == 0)
    {
      GList *devices;
      GList *l;

      /* look for cleartext device  */
      devices = daemon_local_get_all_devices (device->priv->daemon);
      for (l = devices; l != NULL; l = l->next)
        {
          Device *d = DEVICE (l->data);
          if (d->priv->device_is_luks_cleartext && d->priv->luks_cleartext_slave != NULL
              && strcmp (d->priv->luks_cleartext_slave, device->priv->object_path) == 0)
            {

              /* Check whether it is set up by us */
              if (d->priv->dm_name != NULL && g_str_has_prefix (d->priv->dm_name, "udisks-luks-uuid-"))
                {

                  g_print ("**** NOTE: Force luks teardown device %s (cleartext %s)\n",
                           device->priv->device_file,
                           d->priv->device_file);

                  /* Gotcha */
                  force_luks_teardown (device, d, callback, user_data);
                  goto pending;
                }
            }
        }
    }

  /* nothing to force remove */
  if (callback != NULL)
    callback (device, TRUE, user_data);

 pending:
  ;
}

Project: udisks
File: device.c

force_unmount (Device *device,
               ForceRemovalCompleteFunc callback,
               gpointer user_data)
{
  int n;
  char *argv[16];
  const gchar *mount_path;

  mount_path = ((gchar **) device->priv->device_mount_paths->pdata)[0];

  n = 0;
  argv[n++] = "umount";
  /* on Linux, we only have lazy unmount for now */
  argv[n++] = "-l";
  argv[n++] = (gchar *) mount_path;
  argv[n++] = NULL;

  if (!job_new (NULL,
                "ForceUnmount",
                FALSE,
                device,
                argv,
                NULL,
                force_unmount_completed_cb,
                FALSE,
                force_unmount_data_new (mount_path, callback, user_data),
                (GDestroyNotify) force_unmount_data_unref))
    {
      g_warning ("Couldn't spawn unmount for force unmounting %s", mount_path);
      if (callback != NULL)
        callback (device, FALSE, user_data);
    }
}

Project: udisks
File: device.c

force_unmount_completed_cb (DBusGMethodInvocation *context,
                            Device *device,
                            gboolean job_was_cancelled,
                            int status,
                            const char *stderr,
                            const char *stdout,
                            gpointer user_data)
{
  ForceUnmountData *data = user_data;

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      g_print ("**** NOTE: Successfully force unmounted device %s\n", device->priv->device_file);
      /* update_info_mount_state() will update the mounts file and clean up the directory if needed */
      update_info (device);

      if (data->fr_callback != NULL)
        data->fr_callback (device, TRUE, data->fr_user_data);
    }
  else
    {
      g_print ("**** NOTE: force unmount failed: %s\n", stderr);
      if (data->fr_callback != NULL)
        data->fr_callback (device, FALSE, data->fr_user_data);
    }
}

Project: udisks
File: device.c

force_unmount_data_unref (ForceUnmountData *data)
{
  g_free (data->mount_path);
  g_free (data);
}

Project: udisks
File: device.c

get_command_line_for_pid (pid_t pid)
{
  char proc_name[32];
  char *buf;
  gsize len;
  char *ret;
  unsigned int n;

  ret = NULL;

  snprintf (proc_name, sizeof(proc_name), "/proc/%d/cmdline", pid);
  if (g_file_get_contents (proc_name, &buf, &len, NULL))
    {
      for (n = 0; n < len; n++)
        {
          if (buf[n] == '\0')
            buf[n] = ' ';
        }
      g_strstrip (buf);
      ret = buf;
    }

  return ret;
}

Project: udisks
File: device.c

get_dmmp_device_node (Device *device)
{
  static gchar buf[1024];

  g_assert (device->priv->device_is_linux_dmmp);
  g_snprintf (buf, sizeof (buf), "/dev/mapper/%s", device->priv->linux_dmmp_name);
  return buf;
}

Project: udisks
File: device.c

get_property (GObject *object,
              guint prop_id,
              GValue *value,
              GParamSpec *pspec)
{
  Device *device = DEVICE (object);

  switch (prop_id)
    {
    case PROP_NATIVE_PATH:
      g_value_set_string (value, device->priv->native_path);
      break;

    case PROP_DEVICE_DETECTION_TIME:
      g_value_set_uint64 (value, device->priv->device_detection_time);
      break;
    case PROP_DEVICE_MEDIA_DETECTION_TIME:
      g_value_set_uint64 (value, device->priv->device_media_detection_time);
      break;
    case PROP_DEVICE_MAJOR:
      g_value_set_int64 (value, major (device->priv->dev));
      break;
    case PROP_DEVICE_MINOR:
      g_value_set_int64 (value, minor (device->priv->dev));
      break;
    case PROP_DEVICE_FILE:
      g_value_set_string (value, device->priv->device_file);
      break;
    case PROP_DEVICE_FILE_PRESENTATION:
      if (device->priv->device_file_presentation != NULL)
        g_value_set_string (value, device->priv->device_file_presentation);
      else
        g_value_set_string (value, device->priv->device_file);
      break;
    case PROP_DEVICE_FILE_BY_ID:
      g_value_set_boxed (value, device->priv->device_file_by_id);
      break;
    case PROP_DEVICE_FILE_BY_PATH:
      g_value_set_boxed (value, device->priv->device_file_by_path);
      break;
    case PROP_DEVICE_IS_SYSTEM_INTERNAL:
      g_value_set_boolean (value, device->priv->device_is_system_internal);
      break;
    case PROP_DEVICE_IS_PARTITION:
      g_value_set_boolean (value, device->priv->device_is_partition);
      break;
    case PROP_DEVICE_IS_PARTITION_TABLE:
      g_value_set_boolean (value, device->priv->device_is_partition_table);
      break;
    case PROP_DEVICE_IS_REMOVABLE:
      g_value_set_boolean (value, device->priv->device_is_removable);
      break;
    case PROP_DEVICE_IS_MEDIA_AVAILABLE:
      g_value_set_boolean (value, device->priv->device_is_media_available);
      break;
    case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTED:
      g_value_set_boolean (value, device->priv->device_is_media_change_detected);
      break;
    case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_POLLING:
      g_value_set_boolean (value, device->priv->device_is_media_change_detection_polling);
      break;
    case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITABLE:
      g_value_set_boolean (value, device->priv->device_is_media_change_detection_inhibitable);
      break;
    case PROP_DEVICE_IS_MEDIA_CHANGE_DETECTION_INHIBITED:
      g_value_set_boolean (value, device->priv->device_is_media_change_detection_inhibited);
      break;
    case PROP_DEVICE_IS_READ_ONLY:
      g_value_set_boolean (value, device->priv->device_is_read_only);
      break;
    case PROP_DEVICE_IS_DRIVE:
      g_value_set_boolean (value, device->priv->device_is_drive);
      break;
    case PROP_DEVICE_IS_OPTICAL_DISC:
      g_value_set_boolean (value, device->priv->device_is_optical_disc);
      break;
    case PROP_DEVICE_IS_LUKS:
      g_value_set_boolean (value, device->priv->device_is_luks);
      break;
    case PROP_DEVICE_IS_LUKS_CLEARTEXT:
      g_value_set_boolean (value, device->priv->device_is_luks_cleartext);
      break;
    case PROP_DEVICE_IS_LINUX_MD_COMPONENT:
      g_value_set_boolean (value, device->priv->device_is_linux_md_component);
      break;
    case PROP_DEVICE_IS_LINUX_MD:
      g_value_set_boolean (value, device->priv->device_is_linux_md);
      break;
    case PROP_DEVICE_IS_LINUX_LVM2_LV:
      g_value_set_boolean (value, device->priv->device_is_linux_lvm2_lv);
      break;
    case PROP_DEVICE_IS_LINUX_LVM2_PV:
      g_value_set_boolean (value, device->priv->device_is_linux_lvm2_pv);
      break;
    case PROP_DEVICE_IS_LINUX_DMMP:
      g_value_set_boolean (value, device->priv->device_is_linux_dmmp);
      break;
    case PROP_DEVICE_IS_LINUX_DMMP_COMPONENT:
      g_value_set_boolean (value, device->priv->device_is_linux_dmmp_component);
      break;
    case PROP_DEVICE_IS_LINUX_LOOP:
      g_value_set_boolean (value, device->priv->device_is_linux_loop);
      break;
    case PROP_DEVICE_SIZE:
      g_value_set_uint64 (value, device->priv->device_size);
      break;
    case PROP_DEVICE_BLOCK_SIZE:
      g_value_set_uint64 (value, device->priv->device_block_size);
      break;
    case PROP_DEVICE_IS_MOUNTED:
      g_value_set_boolean (value, device->priv->device_is_mounted);
      break;
    case PROP_DEVICE_MOUNT_PATHS:
      g_value_set_boxed (value, device->priv->device_mount_paths);
      break;
    case PROP_DEVICE_MOUNTED_BY_UID:
      g_value_set_uint (value, device->priv->device_mounted_by_uid);
      break;
    case PROP_DEVICE_PRESENTATION_HIDE:
      g_value_set_boolean (value, device->priv->device_presentation_hide);
      break;
    case PROP_DEVICE_PRESENTATION_NOPOLICY:
      g_value_set_boolean (value, device->priv->device_presentation_nopolicy);
      break;
    case PROP_DEVICE_PRESENTATION_NAME:
      g_value_set_string (value, device->priv->device_presentation_name);
      break;
    case PROP_DEVICE_PRESENTATION_ICON_NAME:
      g_value_set_string (value, device->priv->device_presentation_icon_name);
      break;

    case PROP_JOB_IN_PROGRESS:
      g_value_set_boolean (value, device->priv->job_in_progress);
      break;
    case PROP_JOB_ID:
      g_value_set_string (value, device->priv->job_id);
      break;
    case PROP_JOB_INITIATED_BY_UID:
      g_value_set_uint (value, device->priv->job_initiated_by_uid);
      break;
    case PROP_JOB_IS_CANCELLABLE:
      g_value_set_boolean (value, device->priv->job_is_cancellable);
      break;
    case PROP_JOB_PERCENTAGE:
      g_value_set_double (value, device->priv->job_percentage);
      break;

    case PROP_ID_USAGE:
      g_value_set_string (value, device->priv->id_usage);
      break;
    case PROP_ID_TYPE:
      g_value_set_string (value, device->priv->id_type);
      break;
    case PROP_ID_VERSION:
      g_value_set_string (value, device->priv->id_version);
      break;
    case PROP_ID_UUID:
      g_value_set_string (value, device->priv->id_uuid);
      break;
    case PROP_ID_LABEL:
      g_value_set_string (value, device->priv->id_label);
      break;

    case PROP_PARTITION_SLAVE:
      if (device->priv->partition_slave != NULL)
        g_value_set_boxed (value, device->priv->partition_slave);
      else
        g_value_set_boxed (value, "/");
      break;
    case PROP_PARTITION_SCHEME:
      g_value_set_string (value, device->priv->partition_scheme);
      break;
    case PROP_PARTITION_TYPE:
      g_value_set_string (value, device->priv->partition_type);
      break;
    case PROP_PARTITION_LABEL:
      g_value_set_string (value, device->priv->partition_label);
      break;
    case PROP_PARTITION_UUID:
      g_value_set_string (value, device->priv->partition_uuid);
      break;
    case PROP_PARTITION_FLAGS:
      g_value_set_boxed (value, device->priv->partition_flags);
      break;
    case PROP_PARTITION_NUMBER:
      g_value_set_int (value, device->priv->partition_number);
      break;
    case PROP_PARTITION_OFFSET:
      g_value_set_uint64 (value, device->priv->partition_offset);
      break;
    case PROP_PARTITION_SIZE:
      g_value_set_uint64 (value, device->priv->partition_size);
      break;
    case PROP_PARTITION_ALIGNMENT_OFFSET:
      g_value_set_uint64 (value, device->priv->partition_alignment_offset);
      break;

    case PROP_PARTITION_TABLE_SCHEME:
      g_value_set_string (value, device->priv->partition_table_scheme);
      break;
    case PROP_PARTITION_TABLE_COUNT:
      g_value_set_int (value, device->priv->partition_table_count);
      break;

    case PROP_LUKS_HOLDER:
      if (device->priv->luks_holder != NULL)
        g_value_set_boxed (value, device->priv->luks_holder);
      else
        g_value_set_boxed (value, "/");
      break;

    case PROP_LUKS_CLEARTEXT_SLAVE:
      if (device->priv->luks_cleartext_slave != NULL)
        g_value_set_boxed (value, device->priv->luks_cleartext_slave);
      else
        g_value_set_boxed (value, "/");
      break;
    case PROP_LUKS_CLEARTEXT_UNLOCKED_BY_UID:
      g_value_set_uint (value, device->priv->luks_cleartext_unlocked_by_uid);
      break;

    case PROP_DRIVE_VENDOR:
      g_value_set_string (value, device->priv->drive_vendor);
      break;
    case PROP_DRIVE_MODEL:
      g_value_set_string (value, device->priv->drive_model);
      break;
    case PROP_DRIVE_REVISION:
      g_value_set_string (value, device->priv->drive_revision);
      break;
    case PROP_DRIVE_SERIAL:
      g_value_set_string (value, device->priv->drive_serial);
      break;
    case PROP_DRIVE_WWN:
      g_value_set_string (value, device->priv->drive_wwn);
      break;
    case PROP_DRIVE_CONNECTION_INTERFACE:
      g_value_set_string (value, device->priv->drive_connection_interface);
      break;
    case PROP_DRIVE_CONNECTION_SPEED:
      g_value_set_uint64 (value, device->priv->drive_connection_speed);
      break;
    case PROP_DRIVE_MEDIA_COMPATIBILITY:
      g_value_set_boxed (value, device->priv->drive_media_compatibility);
      break;
    case PROP_DRIVE_MEDIA:
      g_value_set_string (value, device->priv->drive_media);
      break;
    case PROP_DRIVE_IS_MEDIA_EJECTABLE:
      g_value_set_boolean (value, device->priv->drive_is_media_ejectable);
      break;
    case PROP_DRIVE_CAN_DETACH:
      g_value_set_boolean (value, device->priv->drive_can_detach);
      break;
    case PROP_DRIVE_CAN_SPINDOWN:
      g_value_set_boolean (value, device->priv->drive_can_spindown);
      break;
    case PROP_DRIVE_IS_ROTATIONAL:
      g_value_set_boolean (value, device->priv->drive_is_rotational);
      break;
    case PROP_DRIVE_WRITE_CACHE:
      g_value_set_string (value, device->priv->drive_write_cache);
      break;
    case PROP_DRIVE_ROTATION_RATE:
      g_value_set_uint (value, device->priv->drive_rotation_rate);
      break;
    case PROP_DRIVE_ADAPTER:
      if (device->priv->drive_adapter != NULL)
        g_value_set_boxed (value, device->priv->drive_adapter);
      else
        g_value_set_boxed (value, "/");
      break;
    case PROP_DRIVE_PORTS:
      g_value_set_boxed (value, device->priv->drive_ports);
      break;
    case PROP_DRIVE_SIMILAR_DEVICES:
      g_value_set_boxed (value, device->priv->drive_similar_devices);
      break;

    case PROP_OPTICAL_DISC_IS_BLANK:
      g_value_set_boolean (value, device->priv->optical_disc_is_blank);
      break;
    case PROP_OPTICAL_DISC_IS_APPENDABLE:
      g_value_set_boolean (value, device->priv->optical_disc_is_appendable);
      break;
    case PROP_OPTICAL_DISC_IS_CLOSED:
      g_value_set_boolean (value, device->priv->optical_disc_is_closed);
      break;
    case PROP_OPTICAL_DISC_NUM_TRACKS:
      g_value_set_uint (value, device->priv->optical_disc_num_tracks);
      break;
    case PROP_OPTICAL_DISC_NUM_AUDIO_TRACKS:
      g_value_set_uint (value, device->priv->optical_disc_num_audio_tracks);
      break;
    case PROP_OPTICAL_DISC_NUM_SESSIONS:
      g_value_set_uint (value, device->priv->optical_disc_num_sessions);
      break;

    case PROP_DRIVE_ATA_SMART_IS_AVAILABLE:
      g_value_set_boolean (value, device->priv->drive_ata_smart_is_available);
      break;
    case PROP_DRIVE_ATA_SMART_TIME_COLLECTED:
      g_value_set_uint64 (value, device->priv->drive_ata_smart_time_collected);
      break;
    case PROP_DRIVE_ATA_SMART_STATUS:
      {
        const gchar *status;
        if (device->priv->drive_ata_smart_status == (SkSmartOverall) - 1)
          status = "";
        else
          status = sk_smart_overall_to_string (device->priv->drive_ata_smart_status);
        g_value_set_string (value, status);
      }
      break;
    case PROP_DRIVE_ATA_SMART_BLOB:
      {
        GArray *a;
        a = g_array_new (FALSE, FALSE, 1);
        if (device->priv->drive_ata_smart_blob != NULL)
          {
            g_array_append_vals (a, device->priv->drive_ata_smart_blob, device->priv->drive_ata_smart_blob_size);
          }
        g_value_set_boxed (value, a);
        g_array_unref (a);
      }
      break;

    case PROP_LINUX_MD_COMPONENT_LEVEL:
      g_value_set_string (value, device->priv->linux_md_component_level);
      break;
    case PROP_LINUX_MD_COMPONENT_POSITION:
      g_value_set_int (value, device->priv->linux_md_component_position);
      break;
    case PROP_LINUX_MD_COMPONENT_NUM_RAID_DEVICES:
      g_value_set_int (value, device->priv->linux_md_component_num_raid_devices);
      break;
    case PROP_LINUX_MD_COMPONENT_UUID:
      g_value_set_string (value, device->priv->linux_md_component_uuid);
      break;
    case PROP_LINUX_MD_COMPONENT_HOME_HOST:
      g_value_set_string (value, device->priv->linux_md_component_home_host);
      break;
    case PROP_LINUX_MD_COMPONENT_NAME:
      g_value_set_string (value, device->priv->linux_md_component_name);
      break;
    case PROP_LINUX_MD_COMPONENT_VERSION:
      g_value_set_string (value, device->priv->linux_md_component_version);
      break;
    case PROP_LINUX_MD_COMPONENT_HOLDER:
      if (device->priv->linux_md_component_holder != NULL)
        g_value_set_boxed (value, device->priv->linux_md_component_holder);
      else
        g_value_set_boxed (value, "/");
      break;
    case PROP_LINUX_MD_COMPONENT_STATE:
      g_value_set_boxed (value, device->priv->linux_md_component_state);
      break;

    case PROP_LINUX_MD_STATE:
      g_value_set_string (value, device->priv->linux_md_state);
      break;
    case PROP_LINUX_MD_LEVEL:
      g_value_set_string (value, device->priv->linux_md_level);
      break;
    case PROP_LINUX_MD_NUM_RAID_DEVICES:
      g_value_set_int (value, device->priv->linux_md_num_raid_devices);
      break;
    case PROP_LINUX_MD_UUID:
      g_value_set_string (value, device->priv->linux_md_uuid);
      break;
    case PROP_LINUX_MD_HOME_HOST:
      g_value_set_string (value, device->priv->linux_md_home_host);
      break;
    case PROP_LINUX_MD_NAME:
      g_value_set_string (value, device->priv->linux_md_name);
      break;
    case PROP_LINUX_MD_VERSION:
      g_value_set_string (value, device->priv->linux_md_version);
      break;
    case PROP_LINUX_MD_SLAVES:
      g_value_set_boxed (value, device->priv->linux_md_slaves);
      break;
    case PROP_LINUX_MD_IS_DEGRADED:
      g_value_set_boolean (value, device->priv->linux_md_is_degraded);
      break;
    case PROP_LINUX_MD_SYNC_ACTION:
      g_value_set_string (value, device->priv->linux_md_sync_action);
      break;
    case PROP_LINUX_MD_SYNC_PERCENTAGE:
      g_value_set_double (value, device->priv->linux_md_sync_percentage);
      break;
    case PROP_LINUX_MD_SYNC_SPEED:
      g_value_set_uint64 (value, device->priv->linux_md_sync_speed);
      break;

    case PROP_LINUX_LVM2_LV_NAME:
      g_value_set_string (value, device->priv->linux_lvm2_lv_name);
      break;
    case PROP_LINUX_LVM2_LV_UUID:
      g_value_set_string (value, device->priv->linux_lvm2_lv_uuid);
      break;
    case PROP_LINUX_LVM2_LV_GROUP_NAME:
      g_value_set_string (value, device->priv->linux_lvm2_lv_group_name);
      break;
    case PROP_LINUX_LVM2_LV_GROUP_UUID:
      g_value_set_string (value, device->priv->linux_lvm2_lv_group_uuid);
      break;

    case PROP_LINUX_LVM2_PV_UUID:
      g_value_set_string (value, device->priv->linux_lvm2_pv_uuid);
      break;
    case PROP_LINUX_LVM2_PV_NUM_METADATA_AREAS:
      g_value_set_uint (value, device->priv->linux_lvm2_pv_num_metadata_areas);
      break;
    case PROP_LINUX_LVM2_PV_GROUP_NAME:
      g_value_set_string (value, device->priv->linux_lvm2_pv_group_name);
      break;
    case PROP_LINUX_LVM2_PV_GROUP_UUID:
      g_value_set_string (value, device->priv->linux_lvm2_pv_group_uuid);
      break;
    case PROP_LINUX_LVM2_PV_GROUP_SIZE:
      g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_size);
      break;
    case PROP_LINUX_LVM2_PV_GROUP_UNALLOCATED_SIZE:
      g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_unallocated_size);
      break;
    case PROP_LINUX_LVM2_PV_GROUP_SEQUENCE_NUMBER:
      g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_sequence_number);
      break;
    case PROP_LINUX_LVM2_PV_GROUP_EXTENT_SIZE:
      g_value_set_uint64 (value, device->priv->linux_lvm2_pv_group_extent_size);
      break;
    case PROP_LINUX_LVM2_PV_GROUP_PHYSICAL_VOLUMES:
      g_value_set_boxed (value, device->priv->linux_lvm2_pv_group_physical_volumes);
      break;
    case PROP_LINUX_LVM2_PV_GROUP_LOGICAL_VOLUMES:
      g_value_set_boxed (value, device->priv->linux_lvm2_pv_group_logical_volumes);
      break;

    case PROP_LINUX_DMMP_COMPONENT_HOLDER:
      if (device->priv->linux_dmmp_component_holder != NULL)
        g_value_set_boxed (value, device->priv->linux_dmmp_component_holder);
      else
        g_value_set_boxed (value, "/");
      break;

    case PROP_LINUX_DMMP_NAME:
      g_value_set_string (value, device->priv->linux_dmmp_name);
      break;

    case PROP_LINUX_DMMP_PARAMETERS:
      g_value_set_string (value, device->priv->linux_dmmp_parameters);
      break;

    case PROP_LINUX_DMMP_SLAVES:
      g_value_set_boxed (value, device->priv->linux_dmmp_slaves);
      break;

    case PROP_LINUX_LOOP_FILENAME:
      g_value_set_string (value, device->priv->linux_loop_filename);
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

Project: udisks
File: device.c

is_device_in_fstab (Device *device,
                    char **out_mount_point)
{
  GList *l;
  GList *mount_points;
  gboolean ret;

  ret = FALSE;

  mount_points = g_unix_mount_points_get (NULL);
  for (l = mount_points; l != NULL; l = l->next)
    {
      GUnixMountPoint *mount_point = l->data;
      char canonical_device_file[PATH_MAX];
      char *device_path;
      char *s;

      device_path = g_strdup (g_unix_mount_point_get_device_path (mount_point));

      /* get the canonical path; e.g. resolve
       *
       * /dev/disk/by-path/pci-0000:00:1d.7-usb-0:3:1.0-scsi-0:0:0:3-part5
       * UUID=78af6939-adac-4ea5-a2a8-576e141da010
       * LABEL=foobar
       *
       * into something like /dev/sde5.
       */
      if (g_str_has_prefix (device_path, "UUID="))
        {
          s = device_path;
          device_path = g_strdup_printf ("/dev/disk/by-uuid/%s", device_path + 5);
          g_free (s);
        }
      else if (g_str_has_prefix (device_path, "LABEL="))
        {
          s = device_path;
          device_path = g_strdup_printf ("/dev/disk/by-label/%s", device_path + 6);
          g_free (s);
        }

      if (realpath (device_path, canonical_device_file) == NULL)
        {
          g_free (device_path);
          continue;
        }
      g_free (device_path);

      if (strcmp (device->priv->device_file, canonical_device_file) == 0)
        {
          ret = TRUE;
          if (out_mount_point != NULL)
            *out_mount_point = g_strdup (g_unix_mount_point_get_mount_path (mount_point));
          break;
        }
    }
  g_list_foreach (mount_points, (GFunc) g_unix_mount_point_free, NULL);
  g_list_free (mount_points);

  return ret;
}

Project: udisks
File: device.c

is_mount_option_allowed (const FSMountOptions *fsmo,
                         const char *option,
                         uid_t caller_uid)
{
  int n;
  char *endp;
  uid_t uid;
  gid_t gid;
  gboolean allowed;
  const char *ep;
  gsize ep_len;

  allowed = FALSE;

  /* first run through the allowed mount options */
  if (fsmo != NULL)
    {
      for (n = 0; fsmo->allow != NULL && fsmo->allow[n] != NULL; n++)
        {
          ep = strstr (fsmo->allow[n], "=");
          if (ep != NULL && ep[1] == '\0')
            {
              ep_len = ep - fsmo->allow[n] + 1;
              if (strncmp (fsmo->allow[n], option, ep_len) == 0)
                {
                  allowed = TRUE;
                  goto out;
                }
            }
          else
            {
              if (strcmp (fsmo->allow[n], option) == 0)
                {
                  allowed = TRUE;
                  goto out;
                }
            }
        }
    }
  for (n = 0; any_allow[n] != NULL; n++)
    {
      ep = strstr (any_allow[n], "=");
      if (ep != NULL && ep[1] == '\0')
        {
          ep_len = ep - any_allow[n] + 1;
          if (strncmp (any_allow[n], option, ep_len) == 0)
            {
              allowed = TRUE;
              goto out;
            }
        }
      else
        {
          if (strcmp (any_allow[n], option) == 0)
            {
              allowed = TRUE;
              goto out;
            }
        }
    }

  /* .. then check for mount options where the caller is allowed to pass
   * in his own uid
   */
  if (fsmo != NULL)
    {
      for (n = 0; fsmo->allow_uid_self != NULL && fsmo->allow_uid_self[n] != NULL; n++)
        {
          const char *r_mount_option = fsmo->allow_uid_self[n];
          if (g_str_has_prefix (option, r_mount_option))
            {
              uid = strtol (option + strlen (r_mount_option), &endp, 10);
              if (*endp != '\0')
                continue;
              if (uid == caller_uid)
                {
                  allowed = TRUE;
                  goto out;
                }
            }
        }
    }

  /* .. ditto for gid
   */
  if (fsmo != NULL)
    {
      for (n = 0; fsmo->allow_gid_self != NULL && fsmo->allow_gid_self[n] != NULL; n++)
        {
          const char *r_mount_option = fsmo->allow_gid_self[n];
          if (g_str_has_prefix (option, r_mount_option))
            {
              gid = strtol (option + strlen (r_mount_option), &endp, 10);
              if (*endp != '\0')
                continue;
              if (is_uid_in_gid (caller_uid, gid))
                {
                  allowed = TRUE;
                  goto out;
                }
            }
        }
    }

 out:
  return allowed;
}

Project: udisks
File: device.c

is_uid_in_gid (uid_t uid,
               gid_t gid)
{
  gboolean ret;
  struct passwd *pw;
  static gid_t supplementary_groups[128];
  int num_supplementary_groups = 128;
  int n;

  /* TODO: use some #define instead of harcoding some random number like 128 */

  ret = FALSE;

  pw = getpwuid (uid);
  if (pw == NULL)
    {
      g_warning ("Couldn't look up uid %d: %m", uid);
      goto out;
    }
  if (pw->pw_gid == gid)
    {
      ret = TRUE;
      goto out;
    }

  if (getgrouplist (pw->pw_name, pw->pw_gid, supplementary_groups, &num_supplementary_groups) < 0)
    {
      g_warning ("Couldn't find supplementary groups for uid %d: %m", uid);
      goto out;
    }

  for (n = 0; n < num_supplementary_groups; n++)
    {
      if (supplementary_groups[n] == gid)
        {
          ret = TRUE;
          goto out;
        }
    }

 out:
  return ret;
}

Project: udisks
File: device.c

job_cancel (Device *device)
{
  g_return_if_fail (device->priv->job != NULL);

  device->priv->job->was_cancelled = TRUE;

  /* TODO: maybe wait and user a bigger hammer? (SIGKILL) */
  kill (device->priv->job->pid, SIGTERM);
}

Project: udisks
File: device.c

job_child_watch_cb (GPid pid,
                    int status,
                    gpointer user_data)
{
  char *buf;
  gsize buf_size;
  Job *job = user_data;

  if (g_io_channel_read_to_end (job->error_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
    {
      g_string_append_len (job->error_string, buf, buf_size);
      g_free (buf);
    }
  if (g_io_channel_read_to_end (job->out_channel, &buf, &buf_size, NULL) == G_IO_STATUS_NORMAL)
    {
      g_string_append_len (job->stdout_string, buf, buf_size);
      g_free (buf);
    }

  PROFILE ("job finish (id=%s, pid=%i, device=%s)", job->job_id, job->pid, job->device ? job->device->priv->device_file : "none");
  g_print ("helper(pid %5d): completed with exit code %d\n", job->pid, WEXITSTATUS (status));

  job->status = status;

  /* if requested, run 'udevadm settle' on success */
  if (!job->was_cancelled && WIFEXITED (status) && WEXITSTATUS (status) == 0 && job->udev_settle)
    {
      GError *error;
      gchar *argv[] =
        { "udevadm", "settle", "--quiet", NULL };
      GPid udevadm_pid;

      error = NULL;
      if (!g_spawn_async (NULL,
                          argv,
                          NULL,
                          G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
                          NULL,
                          NULL,
                          &udevadm_pid,
                          &error))
        {
          g_warning ("Error running 'udevadm settle --quiet': %s", error->message);
          g_error_free (error);

          job_complete (job);
        }
      else
        {
          g_child_watch_add (udevadm_pid, job_udevadm_settle_child_cb, job);
        }
    }
  else
    {
      /* return immediately on error */
      job_complete (job);
    }
}

Project: udisks
File: device.c

job_complete (Job *job)
{
  if (job->device != NULL && job->job_id != NULL)
    {
      job->device->priv->job_in_progress = FALSE;
      g_free (job->device->priv->job_id);
      job->device->priv->job_id = NULL;
      job->device->priv->job_initiated_by_uid = 0;
      job->device->priv->job_is_cancellable = FALSE;
      job->device->priv->job_percentage = -1.0;

      job->device->priv->job = NULL;
    }

  job->job_completed_func (job->context,
                           job->device,
                           job->was_cancelled,
                           job->status,
                           job->error_string->str,
                           job->stdout_string->str,
                           job->user_data);

  if (job->device != NULL && job->job_id != NULL)
    {
      emit_job_changed (job->device);
    }

  job_free (job);
}

Project: udisks
File: device.c

job_free (Job *job)
{
  if (job->user_data_destroy_func != NULL)
    job->user_data_destroy_func (job->user_data);
  if (job->device != NULL)
    g_object_unref (job->device);
  if (job->stderr_fd >= 0)
    close (job->stderr_fd);
  if (job->stdout_fd >= 0)
    close (job->stdout_fd);
  if (job->stdin_fd >= 0)
    {
      close (job->stdin_fd);
      g_source_remove (job->in_channel_source_id);
      g_io_channel_unref (job->in_channel);
    }
  g_source_remove (job->error_channel_source_id);
  g_source_remove (job->out_channel_source_id);
  g_io_channel_unref (job->error_channel);
  g_io_channel_unref (job->out_channel);
  g_string_free (job->error_string, TRUE);
  /* scrub stdin (may contain secrets) */
  if (job->stdin_str != NULL)
    {
      memset (job->stdin_str, '\0', strlen (job->stdin_str));
    }
  g_string_free (job->stdout_string, TRUE);
  g_free (job->stdin_str);
  g_free (job->job_id);
  g_free (job);
}

Project: udisks
File: device.c

job_local_end (Device *device)
{
  if (!device->priv->job_in_progress || device->priv->job != NULL)
    {
      g_warning ("There is no job running");
      goto out;
    }

  device->priv->job_in_progress = FALSE;
  g_free (device->priv->job_id);
  device->priv->job_id = NULL;
  device->priv->job_initiated_by_uid = 0;
  device->priv->job_is_cancellable = FALSE;
  device->priv->job_percentage = -1.0;
  emit_job_changed (device);
 out:
  ;
}

Project: udisks
File: device.c

job_new (DBusGMethodInvocation *context,
         const char *job_id,
         gboolean is_cancellable,
         Device *device,
         char **argv,
         const char *stdin_str,
         JobCompletedFunc job_completed_func,
         gboolean udev_settle, /* if TRUE, runs udevsettle before returning if the command succeeded */
         gpointer user_data,
         GDestroyNotify user_data_destroy_func)
{
  Job *job;
  gboolean ret;
  GError *error;

  ret = FALSE;
  job = NULL;

  PROFILE ("job_new(id=%s, device=%s): start", job_id ? job_id : argv[0], device ? device->priv->device_file : "none");

  if (device != NULL)
    {
      if (device->priv->job != NULL || device->priv->job_in_progress)
        {
          throw_error (context, ERROR_BUSY, "There is already a job running");
          goto out;
        }
    }

  job = g_new0 (Job, 1);
  job->context = context;
  job->device = device != NULL ? DEVICE (g_object_ref (device)) : NULL;
  job->job_completed_func = job_completed_func;
  job->user_data = user_data;
  job->user_data_destroy_func = user_data_destroy_func;
  job->stderr_fd = -1;
  job->stdout_fd = -1;
  job->stdin_fd = -1;
  job->stdin_str = g_strdup (stdin_str);
  job->stdin_cursor = job->stdin_str;
  job->stdout_string = g_string_sized_new (1024);
  job->job_id = g_strdup (job_id);
  job->udev_settle = udev_settle;

  if (device != NULL && job_id != NULL)
    {
      g_free (job->device->priv->job_id);
      job->device->priv->job_id = g_strdup (job_id);
    }

  error = NULL;
  if (!g_spawn_async_with_pipes (NULL,
                                 argv,
                                 NULL,
                                 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
                                 NULL,
                                 NULL,
                                 &(job->pid),
                                 stdin_str != NULL ? &(job->stdin_fd) : NULL,
                                 &(job->stdout_fd),
                                 &(job->stderr_fd),
                                 &error))
    {
      throw_error (context, ERROR_FAILED, "Error starting job: %s", error->message);
      g_error_free (error);
      goto out;
    }

  g_child_watch_add (job->pid, job_child_watch_cb, job);

  job->error_string = g_string_new ("");
  job->error_channel = g_io_channel_unix_new (job->stderr_fd);
  error = NULL;
  if (g_io_channel_set_flags (job->error_channel, G_IO_FLAG_NONBLOCK, &error) != G_IO_STATUS_NORMAL)
    {
      g_warning ("Cannon set stderr fd for child to be non blocking: %s", error->message);
      g_error_free (error);
    }
  job->error_channel_source_id = g_io_add_watch (job->error_channel, G_IO_IN, job_read_error, job);

  job->out_channel = g_io_channel_unix_new (job->stdout_fd);
  error = NULL;
  if (g_io_channel_set_flags (job->out_channel, G_IO_FLAG_NONBLOCK, &error) != G_IO_STATUS_NORMAL)
    {
      g_warning ("Cannon set stdout fd for child to be non blocking: %s", error->message);
      g_error_free (error);
    }
  job->out_channel_source_id = g_io_add_watch (job->out_channel, G_IO_IN, job_read_out, job);

  if (job->stdin_fd >= 0)
    {
      job->in_channel = g_io_channel_unix_new (job->stdin_fd);
      if (g_io_channel_set_flags (job->in_channel, G_IO_FLAG_NONBLOCK, &error) != G_IO_STATUS_NORMAL)
        {
          g_warning ("Cannon set stdin fd for child to be non blocking: %s", error->message);
          g_error_free (error);
        }
      job->in_channel_source_id = g_io_add_watch (job->in_channel, G_IO_OUT, job_write_in, job);
    }

  ret = TRUE;

  if (device != NULL && job_id != NULL)
    {
      device->priv->job_in_progress = TRUE;
      device->priv->job_is_cancellable = is_cancellable;
      device->priv->job_percentage = -1.0;
      device->priv->job_initiated_by_uid = 0;
      if (context != NULL)
        {
          daemon_local_get_uid (device->priv->daemon, &(device->priv->job_initiated_by_uid), context);
        }

      device->priv->job = job;

      emit_job_changed (device);
    }

  if (device != NULL)
    {
      g_print ("helper(pid %5d): launched job %s on %s\n", job->pid, argv[0], device->priv->device_file);
    }
  else
    {
      g_print ("helper(pid %5d): launched job %s on daemon\n", job->pid, argv[0]);
    }

 out:
  if (!ret && job != NULL)
    job_free (job);
  PROFILE ("job_new(id=%s, device=%s): end", job_id, device ? device->priv->device_file : "none");
  return ret;
}

Project: udisks
File: device.c

job_read_error (GIOChannel *channel,
                GIOCondition condition,
                gpointer user_data)
{
  char buf[1024];
  gsize bytes_read;
  Job *job = user_data;

  g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
  g_string_append_len (job->error_string, buf, bytes_read);
  return TRUE;
}

Project: udisks

job_read_out (GIOChannel *channel,
              GIOCondition condition,
              gpointer user_data)
{
  char *s;
  char *line;
  char buf[1024];
  gsize bytes_read;
  Job *job = user_data;

  g_io_channel_read_chars (channel, buf, sizeof buf, &bytes_read, NULL);
  g_string_append_len (job->stdout_string, buf, bytes_read);

  do
    {
      gsize line_len;

      s = strstr (job->stdout_string->str + job->stdout_string_cursor, "\n");
      if (s == NULL)
        break;

      line_len = s - (job->stdout_string->str + job->stdout_string_cursor);
      line = g_strndup (job->stdout_string->str + job->stdout_string_cursor, line_len);
      job->stdout_string_cursor += line_len + 1;


      if (strlen (line) < 256)
        {
          double cur_percentage;
          ;

          if (sscanf (line, "udisks-helper-progress: %lg", &cur_percentage) == 1)
            {
              if (job->device != NULL && job->job_id != NULL)
                {
                  job->device->priv->job_percentage = cur_percentage;
                  emit_job_changed (job->device);
                }
            }
        }

      g_free (line);
    }
  while (TRUE);

  return TRUE;
}

Project: udisks
File: device.c

job_udevadm_settle_child_cb (GPid pid,
                             gint status,
                             gpointer user_data)
{
  Job *job = user_data;
  job_complete (job);
}

Project: udisks
File: device.c

job_write_in (GIOChannel *channel,
              GIOCondition condition,
              gpointer user_data)
{
  Job *job = user_data;
  gsize bytes_written;

  if (job->stdin_cursor == NULL || job->stdin_cursor[0] == '\0')
    {
      /* nothing left to write; remove ourselves */
      return FALSE;
    }

  g_io_channel_write_chars (channel, job->stdin_cursor, strlen (job->stdin_cursor), &bytes_written, NULL);
  g_io_channel_flush (channel, NULL);
  job->stdin_cursor += bytes_written;
  return TRUE;
}

Project: udisks
File: device.c

linux_lvm2_lv_create_completed_cb (DBusGMethodInvocation *context,
                                   Device *device,
                                   gboolean job_was_cancelled,
                                   int status,
                                   const char *stderr,
                                   const char *stdout,
                                   gpointer user_data)
{
  CreateLvm2LVData *data = user_data;

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      Device *d;

      d = lvm2_lv_create_has_lv (data);
      if (d != NULL)
        {
          /* yay! it is.. now create the file system if requested */
          lvm2_lv_create_found_device (device, data);
        }
      else
        {
          /* otherwise sit around and wait for the new LV to appear */
          data->device_added_signal_handler_id = g_signal_connect_after (data->daemon,
                                                                         "device-added",
                                                                         G_CALLBACK (lvm2_lv_create_device_added_cb),
                                                                         data);
          data->device_changed_signal_handler_id = g_signal_connect_after (data->daemon,
                                                                           "device-changed",
                                                                         G_CALLBACK (lvm2_lv_create_device_changed_cb),
                                                                           data);
          data->device_added_timeout_id = g_timeout_add (10 * 1000,
                                                         lvm2_lv_create_device_not_seen_cb,
                                                         data);

          lvm2_lv_create_data_ref (data);
        }
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error creating LVM2 Logical Volume: lvcreate exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_lvm2_lv_remove_completed_cb (DBusGMethodInvocation *context,
                                   Device *device,
                                   gboolean job_was_cancelled,
                                   int status,
                                   const char *stderr,
                                   const char *stdout,
                                   gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error removing LVM2 Logical Volume: lvremove exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_lvm2_lv_set_name_completed_cb (DBusGMethodInvocation *context,
                                     Device *device,
                                     gboolean job_was_cancelled,
                                     int status,
                                     const char *stderr,
                                     const char *stdout,
                                     gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error setting name for LVM2 Logical Volume: lvrename exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_lvm2_lv_start_completed_cb (DBusGMethodInvocation *context,
                                  Device *device,
                                  gboolean job_was_cancelled,
                                  int status,
                                  const char *stderr,
                                  const char *stdout,
                                  gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error starting LVM2 Logical Volume: lvchange exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_lvm2_lv_stop_completed_cb (DBusGMethodInvocation *context,
                                 Device *device,
                                 gboolean job_was_cancelled,
                                 int status,
                                 const char *stderr,
                                 const char *stdout,
                                 gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error stopping LVM2 Logical Volume: lvchange exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_lvm2_vg_add_pv_completed_cb (DBusGMethodInvocation *context,
                                     Device *device,
                                     gboolean job_was_cancelled,
                                     int status,
                                     const char *stderr,
                                     const char *stdout,
                                     gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error adding PV for LVM2 Volume Group: vgextend exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_lvm2_vg_remove_pv_completed_cb (DBusGMethodInvocation *context,
                                      Device *device,
                                      gboolean job_was_cancelled,
                                      int status,
                                      const char *stderr,
                                      const char *stdout,
                                      gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error removing PV for LVM2 Volume Group: vgreduce exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_lvm2_vg_set_name_completed_cb (DBusGMethodInvocation *context,
                                     Device *device,
                                     gboolean job_was_cancelled,
                                     int status,
                                     const char *stderr,
                                     const char *stdout,
                                     gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error setting name for LVM2 Volume Group: vgrename exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_lvm2_vg_start_completed_cb (DBusGMethodInvocation *context,
                                  Device *device,
                                  gboolean job_was_cancelled,
                                  int status,
                                  const char *stderr,
                                  const char *stdout,
                                  gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error starting LVM2 Volume Group: vgchange exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_lvm2_vg_stop_completed_cb (DBusGMethodInvocation *context,
                                 Device *device,
                                 gboolean job_was_cancelled,
                                 int status,
                                 const char *stderr,
                                 const char *stdout,
                                 gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error stopping LVM2 Volume Group: vgchange exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_md_add_spare_completed_cb (DBusGMethodInvocation *context,
                                     Device *device,
                                     gboolean job_was_cancelled,
                                     int status,
                                     const char *stderr,
                                     const char *stdout,
                                     gpointer user_data)
{
  Device *slave = DEVICE (user_data);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      /* the slave got new metadata on it; reread that */
      device_generate_kernel_change_event (slave);

      /* the kernel side of md currently doesn't emit a 'changed' event so
       * generate one since state may have changed (e.g. rebuild started etc.)
       */
      device_generate_kernel_change_event (device);

      dbus_g_method_return (context);

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error adding spare: mdadm exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_md_check_completed_cb (DBusGMethodInvocation *context,
                             Device *device,
                             gboolean job_was_cancelled,
                             int status,
                             const char *stderr,
                             const char *stdout,
                             gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      guint64 num_errors;

      num_errors = sysfs_get_uint64 (device->priv->native_path, "md/mismatch_cnt");

      dbus_g_method_return (context, num_errors);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error checking array: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_md_create_completed_cb (DBusGMethodInvocation *context,
                              Device *device,
                              gboolean job_was_cancelled,
                              int status,
                              const char *stderr,
                              const char *stdout,
                              gpointer user_data)
{
  LinuxMdCreateData *data = user_data;

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      GList *l;
      GList *devices;
      char *objpath;

      /* see if the component appeared already */

      objpath = NULL;

      devices = daemon_local_get_all_devices (data->daemon);
      for (l = devices; l != NULL; l = l->next)
        {
          Device *device = DEVICE (l->data);

          if (device->priv->device_is_linux_md)
            {

              /* TODO: check properly */

              /* yup, return to caller */
              objpath = device->priv->object_path;
              break;
            }
        }

      g_list_free (devices);

      if (objpath != NULL)
        {
          dbus_g_method_return (context, objpath);
        }
      else
        {
          /* sit around and wait for the md array to appear */

          /* sit around wait for the cleartext device to appear */
          data->device_added_signal_handler_id = g_signal_connect_after (data->daemon,
                                                                         "device-added",
                                                                         (GCallback) linux_md_create_device_added_cb,
                                                                         linux_md_create_data_ref (data));

          /* set up timeout for error reporting if waiting failed
           *
           * (the signal handler and the timeout handler share the ref to data
           * as one will cancel the other)
           */
          data->device_added_timeout_id = g_timeout_add (10 * 1000, linux_md_create_device_not_seen_cb, data);
        }

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error assembling array: mdadm exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_md_create_data_new (DBusGMethodInvocation *context,
                          Daemon *daemon,
                          const char *first_component_objpath)
{
  LinuxMdCreateData *data;

  data = g_new0 (LinuxMdCreateData, 1);
  data->refcount = 1;

  data->context = context;
  data->daemon = g_object_ref (daemon);
  data->first_component_objpath = g_strdup (first_component_objpath);
  return data;
}

Project: udisks
File: device.c

linux_md_create_data_ref (LinuxMdCreateData *data)
{
  data->refcount++;
  return data;
}

Project: udisks
File: device.c

linux_md_create_data_unref (LinuxMdCreateData *data)
{
  data->refcount--;
  if (data->refcount == 0)
    {
      g_object_unref (data->daemon);
      g_free (data->first_component_objpath);
      g_free (data);
    }
}

Project: udisks
File: device.c

linux_md_create_device_added_cb (Daemon *daemon,
                                 const char *object_path,
                                 gpointer user_data)
{
  LinuxMdCreateData *data = user_data;
  Device *device;

  /* check the device is the one we're looking for */
  device = daemon_local_find_by_object_path (daemon, object_path);

  if (device != NULL && device->priv->device_is_linux_md)
    {

      /* TODO: actually check this properly by looking at slaves vs. components */

      /* yay! it is.. return value to the user */
      dbus_g_method_return (data->context, object_path);

      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
      g_source_remove (data->device_added_timeout_id);
      linux_md_create_data_unref (data);
    }
}

Project: udisks
File: device.c

linux_md_create_device_not_seen_cb (gpointer user_data)
{
  LinuxMdCreateData *data = user_data;

  throw_error (data->context, ERROR_FAILED, "Error assembling array: timeout (10s) waiting for array to show up");

  g_signal_handler_disconnect (data->daemon, data->device_added_signal_handler_id);
  linux_md_create_data_unref (data);
  return FALSE;
}

Project: udisks
File: device.c

linux_md_expand_completed_cb (DBusGMethodInvocation *context,
                                     Device *device,
                                     gboolean job_was_cancelled,
                                     int status,
                                     const char *stderr,
                                     const char *stdout,
                                     gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      /* the kernel side of md currently doesn't emit a 'changed' event so
       * generate one since state may have changed (e.g. rebuild started etc.)
       */
      device_generate_kernel_change_event (device);

      dbus_g_method_return (context);

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error expanding array: helper script exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_md_remove_component_completed_cb (DBusGMethodInvocation *context,
                                        Device *device,
                                        gboolean job_was_cancelled,
                                        int status,
                                        const char *stderr,
                                        const char *stdout,
                                        gpointer user_data)
{
  RemoveComponentData *data = user_data;

  /* the slave got new metadata on it; reread that */
  device_generate_kernel_change_event (data->slave);

  /* the kernel side of md currently doesn't emit a 'changed' event so
   * generate one since state may have changed (e.g. rebuild started etc.)
   */
  device_generate_kernel_change_event (device);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      /* wait for the slave to be busy, then start erasing it */

      data->device_changed_signal_handler_id
        = g_signal_connect_after (device->priv->daemon,
                                  "device-changed",
                                  (GCallback) linux_md_remove_component_device_changed_cb,
                                  remove_component_data_ref (data));

      /* set up timeout for error reporting if waiting failed
       *
       * (the signal handler and the timeout handler share the ref to data
       * as one will cancel the other)
       */
      data->device_changed_timeout_id = g_timeout_add (10 * 1000, linux_md_remove_component_device_not_seen_cb, data);

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error removing component: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_md_remove_component_device_changed_cb (Daemon *daemon,
                                             const char *object_path,
                                             gpointer user_data)
{
  RemoveComponentData *data = user_data;
  Device *device;
  GError *error;

  error = NULL;

  device = daemon_local_find_by_object_path (daemon, object_path);
  if (device == data->slave)
    {

      if (device_local_is_busy (data->slave, FALSE, &error))
        {
          dbus_g_method_return_error (data->context, error);
          g_error_free (error);
        }
      else
        {
          gchar *fs_create_options[] =
            { NULL };

          /* yay! now scrub it! */
          device_filesystem_create (data->slave, "empty", fs_create_options, data->context);

          /* TODO: leaking data? */

          g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
          g_source_remove (data->device_changed_timeout_id);
        }
    }
}

Project: udisks
File: device.c

linux_md_remove_component_device_not_seen_cb (gpointer user_data)
{
  RemoveComponentData *data = user_data;

  throw_error (data->context,
               ERROR_FAILED,
               "Error removing component: timeout (10s) waiting for slave to stop being busy");

  g_signal_handler_disconnect (data->slave->priv->daemon, data->device_changed_signal_handler_id);
  remove_component_data_unref (data);

  return FALSE;
}

Project: udisks
File: device.c

linux_md_start_completed_cb (DBusGMethodInvocation *context,
                             Device *device,
                             gboolean job_was_cancelled,
                             int status,
                             const char *stderr,
                             const char *stdout,
                             gpointer user_data)
{
  LinuxMdStartData *data = user_data;

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      GList *l;
      GList *devices;
      char *objpath;

      /* see if the component appeared already */

      objpath = NULL;

      devices = daemon_local_get_all_devices (data->daemon);
      for (l = devices; l != NULL; l = l->next)
        {
          Device *device = DEVICE (l->data);

          if (device->priv->device_is_linux_md)
            {

              /* TODO: check properly */

              /* yup, return to caller */
              objpath = device->priv->object_path;
              break;
            }
        }

      g_list_free (devices);

      if (objpath != NULL)
        {
          dbus_g_method_return (context, objpath);
        }
      else
        {
          /* sit around and wait for the md array to appear */

          /* sit around wait for the cleartext device to appear */
          data->device_added_signal_handler_id = g_signal_connect_after (data->daemon,
                                                                         "device-added",
                                                                         (GCallback) linux_md_start_device_added_cb,
                                                                         linux_md_start_data_ref (data));

          /* set up timeout for error reporting if waiting failed
           *
           * (the signal handler and the timeout handler share the ref to data
           * as one will cancel the other)
           */
          data->device_added_timeout_id = g_timeout_add (10 * 1000, linux_md_start_device_not_seen_cb, data);
        }

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error assembling array: mdadm exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

linux_md_start_data_new (DBusGMethodInvocation *context,
                         Daemon *daemon,
                         const char *uuid)
{
  LinuxMdStartData *data;

  data = g_new0 (LinuxMdStartData, 1);
  data->refcount = 1;

  data->context = context;
  data->daemon = g_object_ref (daemon);
  data->uuid = g_strdup (uuid);
  return data;
}

Project: udisks
File: device.c

linux_md_start_data_ref (LinuxMdStartData *data)
{
  data->refcount++;
  return data;
}

Project: udisks
File: device.c

linux_md_start_data_unref (LinuxMdStartData *data)
{
  data->refcount--;
  if (data->refcount == 0)
    {
      g_object_unref (data->daemon);
      g_free (data->uuid);
      g_free (data);
    }
}

Project: udisks
File: device.c

linux_md_start_device_added_cb (Daemon *daemon,
                                const char *object_path,
                                gpointer user_data)
{
  LinuxMdStartData *data = user_data;
  Device *device;

  /* check the device is the one we're looking for */
  device = daemon_local_find_by_object_path (daemon, object_path);

  if (device != NULL && device->priv->device_is_linux_md)
    {

      /* TODO: actually check this properly by looking at slaves vs. components */

      /* yay! it is.. return value to the user */
      dbus_g_method_return (data->context, object_path);

      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
      g_source_remove (data->device_added_timeout_id);
      linux_md_start_data_unref (data);
    }
}

Project: udisks
File: device.c

linux_md_start_device_not_seen_cb (gpointer user_data)
{
  LinuxMdStartData *data = user_data;

  throw_error (data->context, ERROR_FAILED, "Error assembling array: timeout (10s) waiting for array to show up");

  g_signal_handler_disconnect (data->daemon, data->device_added_signal_handler_id);
  linux_md_start_data_unref (data);
  return FALSE;
}

Project: udisks
File: device.c

linux_md_stop_completed_cb (DBusGMethodInvocation *context,
                            Device *device,
                            gboolean job_was_cancelled,
                            int status,
                            const char *stderr,
                            const char *stdout,
                            gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      /* the kernel side of md currently doesn't emit a 'changed' event so
       * generate one such that the md device can disappear from our
       * database
       */
      device_generate_kernel_change_event (device);

      dbus_g_method_return (context);

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error stopping array: mdadm exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

lock_encryption_data_new (DBusGMethodInvocation *context,
                          Device *luks_device,
                          Device *cleartext_device)
{
  LockEncryptionData *data;

  data = g_new0 (LockEncryptionData, 1);
  data->refcount = 1;

  data->context = context;
  data->luks_device = g_object_ref (luks_device);
  data->cleartext_device = g_object_ref (cleartext_device);
  return data;
}

Project: udisks
File: device.c

lock_encryption_data_ref (LockEncryptionData *data)
{
  data->refcount++;
  return data;
}

Project: udisks
File: device.c

lock_encryption_data_unref (LockEncryptionData *data)
{
  data->refcount--;
  if (data->refcount == 0)
    {
      g_object_unref (data->luks_device);
      g_object_unref (data->cleartext_device);
      g_free (data);
    }
}

Project: udisks
File: device.c

lsof_parse (const char *stdout,
            GPtrArray *processes)
{
  int n;
  char **tokens;

  tokens = g_strsplit (stdout, "\n", 0);
  for (n = 0; tokens[n] != NULL; n++)
    {
      pid_t pid;
      uid_t uid;
      char *command_line;
      GValue elem =
        { 0 };

      if (strlen (tokens[n]) == 0)
        continue;

      pid = strtol (tokens[n], NULL, 0);
      uid = get_uid_for_pid (pid);
      command_line = get_command_line_for_pid (pid);

      g_value_init (&elem, LSOF_DATA_STRUCT_TYPE);
      g_value_take_boxed (&elem, dbus_g_type_specialized_construct (LSOF_DATA_STRUCT_TYPE));
      dbus_g_type_struct_set (&elem, 0, pid, 1, uid, 2, command_line != NULL ? command_line : "", G_MAXUINT);
      g_ptr_array_add (processes, g_value_get_boxed (&elem));

      g_free (command_line);
    }
  g_strfreev (tokens);
}

Project: udisks
File: device.c

luks_change_passphrase_completed_cb (DBusGMethodInvocation *context,
                                     Device *device,
                                     gboolean job_was_cancelled,
                                     int status,
                                     const char *stderr,
                                     const char *stdout,
                                     gpointer user_data)
{
  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else if (WEXITSTATUS (status) == 3)
        {
          throw_error (context,
                       ERROR_FILESYSTEM_TOOLS_MISSING,
                       "Error changing fs label: tool not available: %s",
                       stderr);
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error changing secret on device: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

luks_get_uid_from_dm_name (const char *dm_name,
                           uid_t *out_uid)
{
  int n;
  gboolean ret;
  uid_t uid;
  char *endp;

  ret = FALSE;

  if (!g_str_has_prefix (dm_name, "udisks-luks-uuid"))
    goto out;

  /* determine who unlocked the device */
  for (n = strlen (dm_name) - 1; n >= 0; n--)
    {
      if (dm_name[n] == '-')
        break;
    }
  if (strncmp (dm_name + n, "-uid", 4) != 0)
    goto out;

  uid = strtol (dm_name + n + 4, &endp, 10);
  if (endp == NULL || *endp != '\0')
    goto out;

  if (out_uid != NULL)
    *out_uid = uid;

  ret = TRUE;
 out:
  return ret;
}

Project: udisks
File: device.c

luks_lock_completed_cb (DBusGMethodInvocation *context,
                        Device *device,
                        gboolean job_was_cancelled,
                        int status,
                        const char *stderr,
                        const char *stdout,
                        gpointer user_data)
{
  LockEncryptionData *data = user_data;

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      /* if device is already removed, just return */
      if (data->cleartext_device->priv->removed)
        {
          /* update and emit a Changed() signal on the holder since the luks-holder
           * property indicates the cleartext device
           */
          update_info (data->luks_device);
          drain_pending_changes (data->luks_device, FALSE);

          dbus_g_method_return (context);
        }
      else
        {
          /* otherwise sit and wait for the device to disappear */

          data->device_removed_signal_handler_id
            = g_signal_connect_after (device->priv->daemon,
                                      "device-removed",
                                      (GCallback) luks_lock_wait_for_cleartext_device_removed_cb,
                                      lock_encryption_data_ref (data));

          /* set up timeout for error reporting if waiting failed
           *
           * (the signal handler and the timeout handler share the ref to data
           * as one will cancel the other)
           */
          data->device_removed_timeout_id = g_timeout_add (10 * 1000,
                                                           luks_lock_wait_for_cleartext_device_not_seen_cb,
                                                           data);

          job_local_start (device, "LuksLock");
        }
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error locking device: cryptsetup exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

luks_lock_wait_for_cleartext_device_not_seen_cb (gpointer user_data)
{
  LockEncryptionData *data = user_data;

  job_local_end (data->luks_device);

  throw_error (data->context,
               ERROR_FAILED,
               "Error locking luks device: timeout (10s) waiting for cleartext device to be removed");

  g_signal_handler_disconnect (data->cleartext_device->priv->daemon, data->device_removed_signal_handler_id);
  lock_encryption_data_unref (data);
  return FALSE;
}

Project: udisks
File: device.c

luks_lock_wait_for_cleartext_device_removed_cb (Daemon *daemon,
                                                const char *object_path,
                                                gpointer user_data)
{
  Device *device;
  LockEncryptionData *data = user_data;

  device = daemon_local_find_by_object_path (daemon, object_path);
  if (device == data->cleartext_device)
    {

      job_local_end (data->luks_device);

      /* update and emit a Changed() signal on the holder since the luks-holder
       * property indicates the cleartext device
       */
      update_info (data->luks_device);
      drain_pending_changes (data->luks_device, FALSE);

      dbus_g_method_return (data->context);

      g_signal_handler_disconnect (daemon, data->device_removed_signal_handler_id);
      g_source_remove (data->device_removed_timeout_id);
      lock_encryption_data_unref (data);
    }
}

Project: udisks
File: device.c

luks_unlock_completed_cb (DBusGMethodInvocation *context,
                          Device *device,
                          gboolean job_was_cancelled,
                          int status,
                          const char *stderr,
                          const char *stdout,
                          gpointer user_data)
{
  UnlockEncryptionData *data = user_data;

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      luks_unlock_start_waiting_for_cleartext_device (unlock_encryption_data_ref (data));

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error unlocking device: cryptsetup exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
      if (data->hook_func != NULL)
        {
          data->hook_func (data->context, NULL, data->hook_user_data);
        }
    }
}

Project: udisks
File: device.c

luks_unlock_device_added_cb (Daemon *daemon,
                             const char *object_path,
                             gpointer user_data)
{
  UnlockEncryptionData *data = user_data;
  Device *device;

  /* check the device is a cleartext partition for us */
  device = daemon_local_find_by_object_path (daemon, object_path);

  if (device != NULL && device->priv->device_is_luks_cleartext && strcmp (device->priv->luks_cleartext_slave,
                                                                          data->device->priv->object_path) == 0)
    {

      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
      g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
      g_source_remove (data->device_added_timeout_id);

      /* update and emit a Changed() signal on the holder since the luks-holder
       * property indicates the cleartext device
       */
      update_info (data->device);
      drain_pending_changes (data->device, FALSE);

      if (data->hook_func != NULL)
        {
          data->hook_func (data->context, device, data->hook_user_data);
        }
      else
        {
          dbus_g_method_return (data->context, object_path);
        }

      unlock_encryption_data_unref (data);
    }
}

Project: udisks
File: device.c

luks_unlock_device_not_seen_cb (gpointer user_data)
{
  UnlockEncryptionData *data = user_data;

  g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id);
  g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);

  throw_error (data->context,
               ERROR_FAILED,
               "Error unlocking device: timeout (10s) waiting for cleartext device to show up");

  if (data->hook_func != NULL)
    {
      data->hook_func (data->context, NULL, data->hook_user_data);
    }

  unlock_encryption_data_unref (data);
  return FALSE;
}

Project: udisks
File: device.c

luks_unlock_start_waiting_for_cleartext_device (UnlockEncryptionData *data)
{
  Device *cleartext_device;

  cleartext_device = find_cleartext_device (data->device);
  if (cleartext_device != NULL)
    {
      /* update and emit a Changed() signal on the holder since the luks-holder
       * property indicates the cleartext device
       */
      update_info (data->device);
      drain_pending_changes (data->device, FALSE);

      if (data->hook_func != NULL)
        {
          data->hook_func (data->context, cleartext_device, data->hook_user_data);
        }
      else
        {
          dbus_g_method_return (data->context, cleartext_device->priv->object_path);
        }

      unlock_encryption_data_unref (data);
    }
  else
    {
      /* sit around wait for the cleartext device to appear */
      data->device_added_signal_handler_id = g_signal_connect_after (data->device->priv->daemon,
                                                                     "device-added",
                                                                     (GCallback) luks_unlock_device_added_cb,
                                                                     data);
      data->device_changed_signal_handler_id = g_signal_connect_after (data->device->priv->daemon,
                                                                       "device-changed",
                                                                       (GCallback) luks_unlock_device_added_cb,
                                                                       data);

      /* set up timeout for error reporting if waiting failed */
      data->device_added_timeout_id = g_timeout_add (15 * 1000, luks_unlock_device_not_seen_cb, data);

      /* Note that the signal and timeout handlers share the ref to data - one will cancel the other */
    }
}

Project: udisks
File: device.c

lvm2_lv_create_data_new (DBusGMethodInvocation *context,
                         Daemon *daemon,
                         const gchar *vg_uuid,
                         const gchar *lv_name,
                         const char *fstype,
                         char **fsoptions)
{
  CreateLvm2LVData *data;

  data = g_new0 (CreateLvm2LVData, 1);
  data->refcount = 1;

  data->context = context;
  data->daemon = g_object_ref (daemon);
  data->vg_uuid = g_strdup (vg_uuid);
  data->lv_name = g_strdup (lv_name);
  data->fstype = g_strdup (fstype);
  data->fsoptions = g_strdupv (fsoptions);

  return data;
}

Project: udisks
File: device.c

lvm2_lv_create_data_ref (CreateLvm2LVData *data)
{
  data->refcount++;
  return data;
}

Project: udisks
File: device.c

lvm2_lv_create_device_added_cb (Daemon *daemon,
                                const char *object_path,
                                gpointer user_data)
{
  CreateLvm2LVData *data = user_data;
  Device *device;

  g_debug ("added %s", object_path);

  device = lvm2_lv_create_has_lv (data);
  if (device != NULL)
    {
      /* yay! it is.. now create the file system if requested */
      lvm2_lv_create_found_device (device, data);

      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
      g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
      g_source_remove (data->device_added_timeout_id);
      lvm2_lv_create_data_unref (data);
    }
}

Project: udisks
File: device.c

lvm2_lv_create_device_changed_cb (Daemon *daemon,
                                  const char *object_path,
                                  gpointer user_data)
{
  CreateLvm2LVData *data = user_data;
  Device *device;

  g_debug ("changed %s", object_path);

  device = lvm2_lv_create_has_lv (data);
  if (device != NULL)
    {
      /* yay! it is.. now create the file system if requested */
      lvm2_lv_create_found_device (device, data);

      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
      g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
      g_source_remove (data->device_added_timeout_id);
      lvm2_lv_create_data_unref (data);
    }
}

Project: udisks
File: device.c

lvm2_lv_create_device_not_seen_cb (gpointer user_data)
{
  CreateLvm2LVData *data = user_data;

  throw_error (data->context,
               ERROR_FAILED,
               "Error creating Logical Volume: timeout (10s) waiting for LV to show up");

  g_signal_handler_disconnect (data->daemon, data->device_added_signal_handler_id);
  g_signal_handler_disconnect (data->daemon, data->device_changed_signal_handler_id);
  lvm2_lv_create_data_unref (data);

  return FALSE;
}

Project: udisks
File: device.c

lvm2_lv_create_filesystem_create_hook (DBusGMethodInvocation *context,
                                       Device *device,
                                       gboolean filesystem_create_succeeded,
                                       gpointer user_data)
{
  if (!filesystem_create_succeeded)
    {
      /* dang.. FilesystemCreate already reported an error */
    }
  else
    {
      /* it worked.. */
      dbus_g_method_return (context, device->priv->object_path);
    }
}

Project: udisks
File: device.c

lvm2_lv_create_found_device (Device *device,
                             CreateLvm2LVData *data)
{
  if (strlen (data->fstype) > 0)
    {
      device_filesystem_create_internal (device,
                                         data->fstype,
                                         data->fsoptions,
                                         lvm2_lv_create_filesystem_create_hook,
                                         NULL,
                                         data->context);
    }
  else
    {
      dbus_g_method_return (data->context, device->priv->object_path);
    }
}

Project: udisks
File: device.c

lvm2_lv_create_has_lv (CreateLvm2LVData *data)
{
  GList *devices;
  Device *ret;
  GList *l;

  ret = NULL;

  devices = daemon_local_get_all_devices (data->daemon);
  for (l = devices; l != NULL; l = l->next)
    {
      Device *d = DEVICE (l->data);
      if (d->priv->device_is_linux_lvm2_lv &&
          g_strcmp0 (d->priv->linux_lvm2_lv_group_uuid, data->vg_uuid) == 0 &&
          g_strcmp0 (d->priv->linux_lvm2_lv_name, data->lv_name) == 0)
        {
          GList *m;
          const gchar *lv_uuid;

          lv_uuid = d->priv->linux_lvm2_lv_uuid;

          /* OK, we've found the LV... now check that one of more PVs actually reference this LV */
          for (m = devices; m != NULL; m = m->next)
            {
              Device *pv = DEVICE (m->data);
              if (pv->priv->device_is_linux_lvm2_pv &&
                  g_strcmp0 (pv->priv->linux_lvm2_pv_group_uuid, data->vg_uuid) == 0)
                {
                  guint n;
                  for (n = 0; n < pv->priv->linux_lvm2_pv_group_logical_volumes->len; n++)
                    {
                      const gchar *str = pv->priv->linux_lvm2_pv_group_logical_volumes->pdata[n];
                      if (str_has_lv_uuid (str, lv_uuid))
                        {
                          /* Return the LV, not the PV */
                          ret = d;
                          break;
                        }
                    }
                }
            } /* for all PVs */

          break;
        } /* if (found LV) */
    }
  return ret;
}

Project: udisks
File: device.c

mkfs_data_unref (MkfsData *data)
{
  g_free (data);
}

Project: udisks
File: device.c

mkfse_data_ref (MkfsLuksData *data)
{
  data->refcount++;
  return data;
}

Project: udisks
File: device.c

mkfse_data_unref (MkfsLuksData *data)
{
  data->refcount--;
  if (data->refcount == 0)
    {
      if (data->passphrase != NULL)
        {
          memset (data->passphrase, '\0', strlen (data->passphrase));
          g_free (data->passphrase);
        }
      if (data->device != NULL)
        g_object_unref (data->device);
      g_strfreev (data->options);
      g_free (data->fstype);
      g_free (data);
    }
}

Project: udisks
File: device.c

partition_create_completed_cb (DBusGMethodInvocation *context,
                               Device *device,
                               gboolean job_was_cancelled,
                               int status,
                               const char *stderr,
                               const char *stdout,
                               gpointer user_data)
{
  CreatePartitionData *data = user_data;

  /* poke the kernel so we can reread the data */
  device_generate_kernel_change_event (device);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      int n;
      int m;
      guint64 offset;
      guint64 size;
      char **tokens;

      /* Find the
       *
       *   job-create-partition-offset:
       *   job-create-partition-size:
       *
       * lines and parse the new start and end. We need this
       * for waiting on the created partition (since the requested
       * start and size passed may not be honored due to disk/cylinder/sector
       * alignment reasons).
       */
      offset = 0;
      size = 0;
      m = 0;
      tokens = g_strsplit (stderr, "\n", 0);
      for (n = 0; tokens[n] != NULL; n++)
        {
          char *line = tokens[n];
          char *endp;

          if (m == 2)
            break;

          if (g_str_has_prefix (line, "job-create-partition-offset: "))
            {
              offset = strtoll (line + sizeof("job-create-partition-offset: ") - 1, &endp, 10);
              if (*endp == '\0')
                m++;
            }
          else if (g_str_has_prefix (line, "job-create-partition-size: "))
            {
              size = strtoll (line + sizeof("job-create-partition-size: ") - 1, &endp, 10);
              if (*endp == '\0')
                m++;
            }
        }
      g_strfreev (tokens);

      if (m != 2)
        {
          throw_error (context, ERROR_FAILED, "Error creating partition: internal error, expected to find new "
                       "start and end but m=%d", m);
        }
      else
        {
          gboolean found_device;
          GList *devices;
          GList *l;

          data->created_offset = offset;
          data->created_size = size;

          /* check if the device is already there */
          found_device = FALSE;
          devices = daemon_local_get_all_devices (device->priv->daemon);
          for (l = devices; l != NULL; l = l->next)
            {
              Device *d = DEVICE (l->data);

              if (d->priv->device_is_partition && strcmp (d->priv->partition_slave, data->device->priv->object_path)
                  == 0 && data->created_offset == d->priv->partition_offset && data->created_size
                  == d->priv->partition_size)
                {
                  /* yay! it is.. now create the file system if requested */
                  partition_create_found_device (d, data);
                  found_device = TRUE;
                  break;
                }
            }

          if (!found_device)
            {
              /* otherwise sit around and wait for the new partition to appear */
              data->device_added_signal_handler_id
                = g_signal_connect_after (device->priv->daemon,
                                          "device-added",
                                          (GCallback) partition_create_device_added_cb,
                                          partition_create_data_ref (data));

              /* set up timeout for error reporting if waiting failed
               *
               * (the signal handler and the timeout handler share the ref to data
               * as one will cancel the other)
               */
              data->device_added_timeout_id = g_timeout_add (10 * 1000, partition_create_device_not_seen_cb, data);
            }
        }
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error creating partition: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

partition_create_data_new (DBusGMethodInvocation *context,
                           Device *device,
                           guint64 offset,
                           guint64 size,
                           const char *fstype,
                           char **fsoptions)
{
  CreatePartitionData *data;

  data = g_new0 (CreatePartitionData, 1);
  data->refcount = 1;

  data->context = context;
  data->device = g_object_ref (device);
  data->offset = offset;
  data->size = size;
  data->fstype = g_strdup (fstype);
  data->fsoptions = g_strdupv (fsoptions);

  return data;
}

Project: udisks
File: device.c

partition_create_data_ref (CreatePartitionData *data)
{
  data->refcount++;
  return data;
}

Project: udisks
File: device.c

partition_create_data_unref (CreatePartitionData *data)
{
  data->refcount--;
  if (data->refcount == 0)
    {
      g_object_unref (data->device);
      g_free (data->fstype);
      g_strfreev (data->fsoptions);
      g_free (data);
    }
}

Project: udisks
File: device.c

partition_create_device_added_cb (Daemon *daemon,
                                  const char *object_path,
                                  gpointer user_data)
{
  CreatePartitionData *data = user_data;
  Device *device;

  /* check the device added is the partition we've created */
  device = daemon_local_find_by_object_path (daemon, object_path);
  if (device != NULL && device->priv->device_is_partition && strcmp (device->priv->partition_slave,
                                                                     data->device->priv->object_path) == 0
      && data->created_offset == device->priv->partition_offset && data->created_size == device->priv->partition_size)
    {

      /* yay! it is.. now create the file system if requested */
      partition_create_found_device (device, data);

      g_signal_handler_disconnect (daemon, data->device_added_signal_handler_id);
      g_source_remove (data->device_added_timeout_id);
      partition_create_data_unref (data);
    }
}

Project: udisks
File: device.c

partition_create_device_not_seen_cb (gpointer user_data)
{
  CreatePartitionData *data = user_data;

  throw_error (data->context, ERROR_FAILED, "Error creating partition: timeout (10s) waiting for partition to show up");

  g_signal_handler_disconnect (data->device->priv->daemon, data->device_added_signal_handler_id);
  partition_create_data_unref (data);

  return FALSE;
}

Project: udisks
File: device.c

partition_create_filesystem_create_hook (DBusGMethodInvocation *context,
                                         Device *device,
                                         gboolean filesystem_create_succeeded,
                                         gpointer user_data)
{
  if (!filesystem_create_succeeded)
    {
      /* dang.. FilesystemCreate already reported an error */
    }
  else
    {
      /* it worked.. */
      dbus_g_method_return (context, device->priv->object_path);
    }
}

Project: udisks
File: device.c

partition_create_found_device (Device *device,
                               CreatePartitionData *data)
{
  if (strlen (data->fstype) > 0)
    {
      device_filesystem_create_internal (device,
                                         data->fstype,
                                         data->fsoptions,
                                         partition_create_filesystem_create_hook,
                                         NULL,
                                         data->context);
    }
  else
    {
      dbus_g_method_return (data->context, device->priv->object_path);
    }
}

Project: udisks
File: device.c

partition_delete_completed_cb (DBusGMethodInvocation *context,
                               Device *device,
                               gboolean job_was_cancelled,
                               int status,
                               const char *stderr,
                               const char *stdout,
                               gpointer user_data)
{
  Device *enclosing_device = DEVICE (user_data);

  /* poke the kernel about the enclosing disk so we can reread the partitioning table */
  device_generate_kernel_change_event (enclosing_device);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      dbus_g_method_return (context);
    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error erasing: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

partition_modify_completed_cb (DBusGMethodInvocation *context,
                               Device *device,
                               gboolean job_was_cancelled,
                               int status,
                               const char *stderr,
                               const char *stdout,
                               gpointer user_data)
{
  ModifyPartitionData *data = user_data;

  /* poke the kernel so we can reread the data */
  device_generate_kernel_change_event (data->enclosing_device);
  device_generate_kernel_change_event (data->device);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {
      /* update local copy, don't wait for the kernel */

      device_set_partition_type (device, data->type);
      device_set_partition_label (device, data->label);
      device_set_partition_flags (device, data->flags);

      drain_pending_changes (device, FALSE);

      dbus_g_method_return (context);

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error modifying partition: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

partition_modify_data_new (DBusGMethodInvocation *context,
                           Device *device,
                           Device *enclosing_device,
                           const char *type,
                           const char *label,
                           char **flags)
{
  ModifyPartitionData *data;

  data = g_new0 (ModifyPartitionData, 1);

  data->context = context;
  data->device = g_object_ref (device);
  data->enclosing_device = g_object_ref (enclosing_device);
  data->type = g_strdup (type);
  data->label = g_strdup (label);
  data->flags = g_strdupv (flags);

  return data;
}

Project: udisks
File: device.c

partition_modify_data_unref (ModifyPartitionData *data)
{
  g_object_unref (data->device);
  g_object_unref (data->enclosing_device);
  g_free (data->type);
  g_free (data->label);
  g_free (data->flags);
  g_free (data);
}

Project: udisks
File: device.c

partition_table_create_completed_cb (DBusGMethodInvocation *context,
                                     Device *device,
                                     gboolean job_was_cancelled,
                                     int status,
                                     const char *stderr,
                                     const char *stdout,
                                     gpointer user_data)
{
  CreatePartitionTableData *data = user_data;

  /* poke the kernel so we can reread the data */
  device_generate_kernel_change_event (device);

  if (WEXITSTATUS (status) == 0 && !job_was_cancelled)
    {

      if (g_strcmp0 (device->priv->partition_table_scheme, data->scheme) == 0)
        {
          dbus_g_method_return (context);
        }
      else
        {
          /* sit around and wait for the new partition table to appear */
          data->device_changed_signal_handler_id
            = g_signal_connect_after (device->priv->daemon,
                                      "device-changed",
                                      (GCallback) partition_table_create_device_changed_cb,
                                      partition_table_create_data_ref (data));

          /* set up timeout for error reporting if waiting failed
           *
           * (the signal handler and the timeout handler share the ref to data
           * as one will cancel the other)
           */
          data->device_changed_timeout_id = g_timeout_add (10 * 1000,
                                                           partition_table_create_device_not_changed_cb,
                                                           data);
        }

    }
  else
    {
      if (job_was_cancelled)
        {
          throw_error (context, ERROR_CANCELLED, "Job was cancelled");
        }
      else
        {
          throw_error (context,
                       ERROR_FAILED,
                       "Error creating partition table: helper exited with exit code %d: %s",
                       WEXITSTATUS (status),
                       stderr);
        }
    }
}

Project: udisks
File: device.c

partition_table_create_data_new (DBusGMethodInvocation *context,
                                 Device *device,
                                 const char *scheme)
{
  CreatePartitionTableData *data;

  data = g_new0 (CreatePartitionTableData, 1);
  data->refcount = 1;

  data->context = context;
  data->device = g_object_ref (device);
  data->scheme = g_strdup (scheme);

  return data;
}

Project: udisks
File: device.c

partition_table_create_data_ref (CreatePartitionTableData *data)
{
  data->refcount++;
  return data;
}

Project: udisks
File: device.c

partition_table_create_data_unref (CreatePartitionTableData *data)
{
  data->refcount--;
  if (data->refcount == 0)
    {
      g_object_unref (data->device);
      g_free (data->scheme);
      g_free (data);
    }
}

Project: udisks
File: device.c

partition_table_create_device_changed_cb (Daemon *daemon,
                                          const char *object_path,
                                          gpointer user_data)
{
  CreatePartitionTableData *data = user_data;
  Device *device;

  device = daemon_local_find_by_object_path (daemon, object_path);
  if (device == data->device)
    {
      if (g_strcmp0 (device->priv->partition_table_scheme, data->scheme) == 0 || (device->priv->partition_table_scheme
                                                                                  == NULL && g_strcmp0 (data->scheme, "none") == 0))
        {
          dbus_g_method_return (data->context);

          g_signal_handler_disconnect (daemon, data->device_changed_signal_handler_id);
          g_source_remove (data->device_changed_timeout_id);
          partition_table_create_data_unref (data);
        }
    }
}

Project: udisks
File: device.c

partition_table_create_device_not_changed_cb (gpointer user_data)
{
  CreatePartitionTableData *data = user_data;

  throw_error (data->context, ERROR_FAILED, "Error creating partition table: timeout (10s) waiting for change");

  g_signal_handler_disconnect (data->device->priv->daemon, data->device_changed_signal_handler_id);
  partition_table_create_data_unref (data);

  return FALSE;
}

Project: udisks
File: device.c

poll_syncing_md_device (gpointer user_data)
{
  Device *device = DEVICE (user_data);

  g_print ("**** POLL SYNCING MD %s\n", device->priv->native_path);

  device->priv->linux_md_poll_timeout_id = 0;
  daemon_local_synthesize_changed (device->priv->daemon, device);
  return FALSE;
}

Project: udisks
File: device.c

polling_inhibitor_disconnected_cb (Inhibitor *inhibitor,
                                   Device *device)
{
  device->priv->polling_inhibitors = g_list_remove (device->priv->polling_inhibitors, inhibitor);
  g_signal_handlers_disconnect_by_func (inhibitor, polling_inhibitor_disconnected_cb, device);
  g_object_unref (inhibitor);

  update_info (device);
  drain_pending_changes (device, FALSE);
  daemon_local_update_poller (device->priv->daemon);
}

Project: udisks
File: device.c

prepend_default_mount_options (const FSMountOptions *fsmo,
                               uid_t caller_uid,
                               char **given_options)
{
  GPtrArray *options;
  int n;
  char *s;
  gid_t gid;

  options = g_ptr_array_new ();
  if (fsmo != NULL)
    {
      for (n = 0; fsmo->defaults != NULL && fsmo->defaults[n] != NULL; n++)
        {
          const char *option = fsmo->defaults[n];

          if (strcmp (option, "uid=") == 0)
            {
              s = g_strdup_printf ("uid=%d", caller_uid);
              g_ptr_array_add (options, s);
            }
          else if (strcmp (option, "gid=") == 0)
            {
              gid = find_primary_gid (caller_uid);
              if (gid != (gid_t) - 1)
                {
                  s = g_strdup_printf ("gid=%d", gid);
                  g_ptr_array_add (options, s);
                }
            }
          else
            {
              g_ptr_array_add (options, g_strdup (option));
            }
        }
    }
  for (n = 0; given_options[n] != NULL; n++)
    {
      g_ptr_array_add (options, g_strdup (given_options[n]));
    }

  g_ptr_array_add (options, NULL);

  return (char **) g_ptr_array_free (options, FALSE);
}

Project: udisks
File: device.c

ptr_array_has_string (GPtrArray *p, const gchar *str)
{
  guint n;
  gboolean ret;

  ret = FALSE;
  for (n = 0; n < p->len; n++)
    {
      if (g_strcmp0 (p->pdata[n], str) == 0)
        {
          ret = TRUE;
          goto out;
        }
    }

 out:
  return ret;
}

Project: udisks
File: device.c

ptr_str_array_compare (const gchar **a,
                       const gchar **b)
{
  return g_strcmp0 (*a, *b);
}

Project: udisks
File: device.c

register_disks_device (Device *device)
{
  DBusConnection *connection;
  GError *error = NULL;

  device->priv->system_bus_connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
  if (device->priv->system_bus_connection == NULL)
    {
      if (error != NULL)
        {
          g_critical ("error getting system bus: %s", error->message);
          g_error_free (error);
        }
      goto error;
    }
  connection = dbus_g_connection_get_connection (device->priv->system_bus_connection);

  device->priv->object_path = compute_object_path (device->priv->native_path);

  /* safety first */
  if (dbus_g_connection_lookup_g_object (device->priv->system_bus_connection, device->priv->object_path) != NULL)
    {
      g_error ("**** HACK: Wanting to register object at path `%s' but there is already an "
               "object there. This is an internal error in the daemon. Aborting.\n", device->priv->object_path);
    }

  dbus_g_connection_register_g_object (device->priv->system_bus_connection,
                                       device->priv->object_path,
                                       G_OBJECT (device));

  return TRUE;

 error:
  return FALSE;
}

Project: udisks
File: device.c

remove_component_data_new (DBusGMethodInvocation *context,
                           Device *slave,
                           char **options)
{
  RemoveComponentData *data;

  data = g_new0 (RemoveComponentData, 1);
  data->refcount = 1;

  data->context = context;
  data->slave = g_object_ref (slave);
  data->options = g_strdupv (options);
  return data;
}

Project: udisks
File: device.c

remove_component_data_ref (RemoveComponentData *data)
{
  data->refcount++;
  return data;
}

Project: udisks
File: device.c

remove_component_data_unref (RemoveComponentData *data)
{
  data->refcount--;
  if (data->refcount == 0)
    {
      g_object_unref (data->slave);
      g_free (data->options);
      g_free (data);
    }
}

Project: udisks
File: device.c

spindown_inhibitor_disconnected_cb (Inhibitor *inhibitor,
                                    Device *device)
{
  device->priv->spindown_inhibitors = g_list_remove (device->priv->spindown_inhibitors, inhibitor);
  g_signal_handlers_disconnect_by_func (inhibitor, spindown_inhibitor_disconnected_cb, device);
  g_object_unref (inhibitor);

  update_info (device);
  drain_pending_changes (device, FALSE);
  daemon_local_update_spindown (device->priv->daemon);
}

Project: udisks
File: device.c

str_has_lv_uuid (const gchar *str,
                 const gchar *lv_uuid)
{
  gchar **tokens;
  guint n;

  tokens = g_strsplit (str, ";", 0);
  for (n = 0; tokens != NULL && tokens[n] != NULL; n++)
    {
      if (g_str_has_prefix (tokens[n], "uuid=") && g_strcmp0 (tokens[n] + 5, lv_uuid) == 0)
        {
          return TRUE;
        }
    }

  return FALSE;
}

Project: udisks
File: device.c

sysfs_file_exists (const char *dir,
                   const char *attribute)
{
  gboolean result;
  char *filename;

  result = FALSE;
  filename = g_build_filename (dir, attribute, NULL);
  if (g_file_test (filename, G_FILE_TEST_EXISTS))
    {
      result = TRUE;
    }
  g_free (filename);

  return result;
}

Project: udisks
File: device.c

sysfs_get_double (const char *dir,
                  const char *attribute)
{
  double result;
  char *contents;
  char *filename;

  result = 0.0;
  filename = g_build_filename (dir, attribute, NULL);
  if (g_file_get_contents (filename, &contents, NULL, NULL))
    {
      result = atof (contents);
      g_free (contents);
    }
  g_free (filename);

  return result;
}

Project: udisks
File: device.c

sysfs_get_int (const char *dir,
               const char *attribute)
{
  int result;
  char *contents;
  char *filename;

  result = 0;
  filename = g_build_filename (dir, attribute, NULL);
  if (g_file_get_contents (filename, &contents, NULL, NULL))
    {
      result = strtol (contents, NULL, 0);
      g_free (contents);
    }
  g_free (filename);

  return result;
}

Project: udisks
File: device.c

sysfs_get_string (const char *dir,
                  const char *attribute)
{
  char *result;
  char *filename;

  result = NULL;
  filename = g_build_filename (dir, attribute, NULL);
  if (!g_file_get_contents (filename, &result, NULL, NULL))
    {
      result = g_strdup ("");
    }
  g_free (filename);

  return result;
}

Project: udisks
File: device.c

sysfs_get_uint64 (const char *dir,
                  const char *attribute)
{
  guint64 result;
  char *contents;
  char *filename;

  result = 0;
  filename = g_build_filename (dir, attribute, NULL);
  if (g_file_get_contents (filename, &contents, NULL, NULL))
    {
      result = strtoll (contents, NULL, 0);
      g_free (contents);
    }
  g_free (filename);

  return result;
}

Project: udisks

sysfs_resolve_link (const char *sysfs_path,
                    const char *name)
{
  char *full_path;
  char link_path[PATH_MAX];
  char resolved_path[PATH_MAX];
  ssize_t num;
  gboolean found_it;

  found_it = FALSE;

  full_path = g_build_filename (sysfs_path, name, NULL);

  num = readlink (full_path, link_path, sizeof(link_path) - 1);
  if (num != -1)
    {
      char *absolute_path;

      link_path[num] = '\0';

      absolute_path = g_build_filename (sysfs_path, link_path, NULL);
      if (realpath (absolute_path, resolved_path) != NULL)
        {
          found_it = TRUE;
        }
      g_free (absolute_path);
    }
  g_free (full_path);

  if (found_it)
    return g_strdup (resolved_path);
  else
    return NULL;
}

Project: udisks
File: device.c

throw_error (DBusGMethodInvocation *context,
             int error_code,
             const char *format,
             ...)
{
  GError *error;
  va_list args;
  char *message;

  if (context == NULL)
    return TRUE;

  va_start (args, format);
  message = g_strdup_vprintf (format, args);
  va_end (args);

  error = g_error_new (ERROR, error_code, "%s", message);
  dbus_g_method_return_error (context, error);
  g_error_free (error);
  g_free (message);
  return TRUE;
}

Project: udisks
File: device.c

unlock_cd_tray (Device *device)
{
  /* Unlock CD tray to keep the hardware eject button working */
  if (g_udev_device_has_property (device->priv->d, "ID_CDROM"))
    {
      gint fd;

      g_print ("**** Unlocking CD-ROM door for %s\n", device->priv->device_file);
      fd = open (device->priv->device_file, O_RDONLY);
      if (fd > 0)
        {
          if (ioctl (fd, CDROM_LOCKDOOR, 0) != 0)
            g_warning ("Could not unlock CD-ROM door: %s", strerror (errno));
          close (fd);
        }
      else
        {
          g_warning ("Could not open CD-ROM device: %s", strerror (errno));
        }
    }
}

Project: udisks
File: device.c

unlock_encryption_data_new (DBusGMethodInvocation *context,
                            Device *device,
                            UnlockEncryptionHookFunc hook_func,
                            gpointer hook_user_data)
{
  UnlockEncryptionData *data;

  data = g_new0 (UnlockEncryptionData, 1);
  data->refcount = 1;

  data->context = context;
  data->device = g_object_ref (device);
  data->hook_func = hook_func;
  data->hook_user_data = hook_user_data;
  return data;
}

Project: udisks
File: device.c

unlock_encryption_data_ref (UnlockEncryptionData *data)
{
  data->refcount++;
  return data;
}

Project: udisks
File: device.c

unlock_encryption_data_unref (UnlockEncryptionData *data)
{
  data->refcount--;
  if (data->refcount == 0)
    {
      g_object_unref (data->device);
      g_free (data);
    }
}

Project: udisks
File: device.c

update_drive_properties_from_sysfs (Device *device)
{
  char *s;
  char *p;
  char *q;
  char *model;
  char *vendor;
  char *subsystem;
  char *serial;
  char *revision;
  const char *connection_interface;
  guint64 connection_speed;

  connection_interface = NULL;
  connection_speed = 0;

  /* walk up the device tree to figure out the subsystem */
  s = g_strdup (device->priv->native_path);
  do
    {
      p = sysfs_resolve_link (s, "subsystem");
      if (p != NULL)
        {
          subsystem = g_path_get_basename (p);
          g_free (p);

          if (strcmp (subsystem, "scsi") == 0)
            {
              connection_interface = "scsi";
              connection_speed = 0;

              /* continue walking up the chain; we just use scsi as a fallback */

              /* grab the names from SCSI since the names from udev currently
               *  - replaces whitespace with _
               *  - is missing for e.g. Firewire
               */
              vendor = sysfs_get_string (s, "vendor");
              if (vendor != NULL)
                {
                  g_strstrip (vendor);
                  /* Don't overwrite what we set earlier from ID_VENDOR */
                  if (device->priv->drive_vendor == NULL)
                    {
                      q = _dupv8 (vendor);
                      device_set_drive_vendor (device, q);
                      g_free (q);
                    }
                  g_free (vendor);
                }

              model = sysfs_get_string (s, "model");
              if (model != NULL)
                {
                  g_strstrip (model);
                  /* Don't overwrite what we set earlier from ID_MODEL */
                  if (device->priv->drive_model == NULL)
                    {
                      q = _dupv8 (model);
                      device_set_drive_model (device, q);
                      g_free (q);
                    }
                  g_free (model);
                }

              /* TODO: need to improve this code; we probably need the kernel to export more
               *       information before we can properly get the type and speed.
               */

              if (device->priv->drive_vendor != NULL && strcmp (device->priv->drive_vendor, "ATA") == 0)
                {
                  connection_interface = "ata";
                  break;
                }

            }
          else if (strcmp (subsystem, "usb") == 0)
            {
              double usb_speed;

              /* both the interface and the device will be 'usb'. However only
               * the device will have the 'speed' property.
               */
              usb_speed = sysfs_get_double (s, "speed");
              if (usb_speed > 0)
                {
                  connection_interface = "usb";
                  connection_speed = usb_speed * (1000 * 1000);
                  break;

                }
            }
          else if (strcmp (subsystem, "firewire") == 0 || strcmp (subsystem, "ieee1394") == 0)
            {

              /* TODO: krh has promised a speed file in sysfs; theoretically, the speed can
               *       be anything from 100, 200, 400, 800 and 3200. Till then we just hardcode
               *       a resonable default of 400 Mbit/s.
               */

              connection_interface = "firewire";
              connection_speed = 400 * (1000 * 1000);
              break;

            }
          else if (strcmp (subsystem, "mmc") == 0)
            {

              /* TODO: what about non-SD, e.g. MMC? Is that another bus? */
              connection_interface = "sdio";

              /* Set vendor name. According to this MMC document
               *
               * http://www.mmca.org/membership/IAA_Agreement_10_12_06.pdf
               *
               *  - manfid: the manufacturer id
               *  - oemid: the customer of the manufacturer
               *
               * Apparently these numbers are kept secret. It would be nice
               * to map these into names for setting the manufacturer of the drive,
               * e.g. Panasonic, Sandisk etc.
               */

              model = sysfs_get_string (s, "name");
              if (model != NULL)
                {
                  g_strstrip (model);
                  /* Don't overwrite what we set earlier from ID_MODEL */
                  if (device->priv->drive_model == NULL)
                    {
                      q = _dupv8 (model);
                      device_set_drive_model (device, q);
                      g_free (q);
                    }
                  g_free (model);
                }

              serial = sysfs_get_string (s, "serial");
              if (serial != NULL)
                {
                  g_strstrip (serial);
                  /* Don't overwrite what we set earlier from ID_SERIAL */
                  if (device->priv->drive_serial == NULL)
                    {
                      /* this is formatted as a hexnumber; drop the leading 0x */
                      q = _dupv8 (serial + 2);
                      device_set_drive_serial (device, q);
                      g_free (q);
                    }
                  g_free (serial);
                }

              /* TODO: use hwrev and fwrev files? */
              revision = sysfs_get_string (s, "date");
              if (revision != NULL)
                {
                  g_strstrip (revision);
                  /* Don't overwrite what we set earlier from ID_REVISION */
                  if (device->priv->drive_revision == NULL)
                    {
                      q = _dupv8 (revision);
                      device_set_drive_revision (device, q);
                      g_free (q);
                    }
                  g_free (revision);
                }

              /* TODO: interface speed; the kernel driver knows; would be nice
               * if it could export it */

            }
          else if (strcmp (subsystem, "platform") == 0)
            {
              const gchar *sysfs_name;

              sysfs_name = g_strrstr (s, "/");
              if (g_str_has_prefix (sysfs_name + 1, "floppy."))
                {
                  device_set_drive_vendor (device, "Floppy Drive");
                  connection_interface = "platform";
                }
            }

          g_free (subsystem);
        }

      /* advance up the chain */
      p = g_strrstr (s, "/");
      if (p == NULL)
        break;
      *p = '\0';

      /* but stop at the root */
      if (strcmp (s, "/sys/devices") == 0)
        break;

    }
  while (TRUE);

  if (connection_interface != NULL)
    {
      device_set_drive_connection_interface (device, connection_interface);
      device_set_drive_connection_speed (device, connection_speed);
    }

  g_free (s);
}

Project: udisks

update_info (Device *device)
{
  char *s;
  guint n;
  gboolean ret;
  char *path;
  GDir *dir;
  const char *name;
  GList *l;
  GList *old_slaves_objpath;
  GList *old_holders_objpath;
  GList *cur_slaves_objpath;
  GList *cur_holders_objpath;
  GList *added_objpath;
  GList *removed_objpath;
  GPtrArray *symlinks_by_id;
  GPtrArray *symlinks_by_path;
  GPtrArray *slaves;
  GPtrArray *holders;
  gint major;
  gint minor;
  gboolean media_available;

  ret = FALSE;

  PROFILE ("update_info(device=%s) start", device->priv->native_path);

  g_print ("**** UPDATING %s\n", device->priv->native_path);

  /* need the slaves/holders to synthesize 'change' events if a device goes away (since the kernel
   * doesn't do generate these)
   */
  old_slaves_objpath = dup_list_from_ptrarray (device->priv->slaves_objpath);
  old_holders_objpath = dup_list_from_ptrarray (device->priv->holders_objpath);

  /* drive identification */
  if (sysfs_file_exists (device->priv->native_path, "range"))
    {
      device_set_device_is_drive (device, TRUE);
    }
  else
    {
      device_set_device_is_drive (device, FALSE);
    }

  if (!g_udev_device_has_property (device->priv->d, "MAJOR") || !g_udev_device_has_property (device->priv->d, "MINOR"))
    {
      g_warning ("No major/minor for %s", device->priv->native_path);
      goto out;
    }

  /* ignore dm devices that are suspended */
  if (g_str_has_prefix (g_udev_device_get_name (device->priv->d), "dm-"))
    {
      if (g_strcmp0 (g_udev_device_get_property (device->priv->d, "DM_SUSPENDED"), "1") == 0)
	goto out;
    }

  major = g_udev_device_get_property_as_int (device->priv->d, "MAJOR");
  minor = g_udev_device_get_property_as_int (device->priv->d, "MINOR");
  device->priv->dev = makedev (major, minor);

  device_set_device_file (device, g_udev_device_get_device_file (device->priv->d));
  if (device->priv->device_file == NULL)
    {
      g_warning ("No device file for %s", device->priv->native_path);
      goto out;
    }

  const char * const * symlinks;
  symlinks = g_udev_device_get_device_file_symlinks (device->priv->d);
  symlinks_by_id = g_ptr_array_new ();
  symlinks_by_path = g_ptr_array_new ();
  for (n = 0; symlinks[n] != NULL; n++)
    {
      if (g_str_has_prefix (symlinks[n], "/dev/disk/by-id/") || g_str_has_prefix (symlinks[n], "/dev/disk/by-uuid/"))
        {
          g_ptr_array_add (symlinks_by_id, (gpointer) symlinks[n]);
        }
      else if (g_str_has_prefix (symlinks[n], "/dev/disk/by-path/"))
        {
          g_ptr_array_add (symlinks_by_path, (gpointer) symlinks[n]);
        }
    }
  g_ptr_array_sort (symlinks_by_id, (GCompareFunc) ptr_str_array_compare);
  g_ptr_array_sort (symlinks_by_path, (GCompareFunc) ptr_str_array_compare);
  g_ptr_array_add (symlinks_by_id, NULL);
  g_ptr_array_add (symlinks_by_path, NULL);
  device_set_device_file_by_id (device, (GStrv) symlinks_by_id->pdata);
  device_set_device_file_by_path (device, (GStrv) symlinks_by_path->pdata);
  g_ptr_array_free (symlinks_by_id, TRUE);
  g_ptr_array_free (symlinks_by_path, TRUE);

  device_set_device_is_removable (device, (sysfs_get_int (device->priv->native_path, "removable") != 0));

  /* device_is_media_available and device_media_detection_time property */
  if (device->priv->device_is_removable)
    {
      media_available = FALSE;

      if (!g_udev_device_get_property_as_boolean (device->priv->d, "ID_CDROM"))
        {
          int fd;
          fd = open (device->priv->device_file, O_RDONLY);
          if (fd >= 0)
            {
              media_available = TRUE;
              close (fd);
            }
        }
      else
        {
          if (g_udev_device_get_property_as_boolean (device->priv->d, "ID_CDROM_MEDIA"))
            {
              media_available = TRUE;
            }
          else
            {
              media_available = FALSE;
            }
        }
    }
  else
    {
      media_available = TRUE;
    }
  device_set_device_is_media_available (device, media_available);
  if (media_available)
    {
      if (device->priv->device_media_detection_time == 0)
        device_set_device_media_detection_time (device, (guint64) time (NULL));
    }
  else
    {
      device_set_device_media_detection_time (device, 0);
    }

  /* device_size, device_block_size and device_is_read_only properties */
  if (device->priv->device_is_media_available)
    {
      guint64 block_size;

      device_set_device_size (device, sysfs_get_uint64 (device->priv->native_path, "size") * ((guint64) 512));
      device_set_device_is_read_only (device, (sysfs_get_int (device->priv->native_path, "ro") != 0));
      /* This is not available on all devices so fall back to 512 if unavailable.
       *
       * Another way to get this information is the BLKSSZGET ioctl but we don't want
       * to open the device. Ideally vol_id would export it.
       */
      block_size = sysfs_get_uint64 (device->priv->native_path, "queue/hw_sector_size");
      if (block_size == 0)
        block_size = 512;
      device_set_device_block_size (device, block_size);

    }
  else
    {
      device_set_device_size (device, 0);
      device_set_device_block_size (device, 0);
      device_set_device_is_read_only (device, FALSE);
    }

  /* Maintain (non-exported) properties holders and slaves for the holders resp. slaves
   * directories in sysfs. The entries in these arrays are object paths - we ignore
   * an entry unless it corresponds to an device in our local database.
   */
  path = g_build_filename (device->priv->native_path, "slaves", NULL);
  slaves = g_ptr_array_new ();
  if ((dir = g_dir_open (path, 0, NULL)) != NULL)
    {
      while ((name = g_dir_read_name (dir)) != NULL)
        {
          Device *device2;

          s = compute_object_path (name);

          device2 = daemon_local_find_by_object_path (device->priv->daemon, s);
          if (device2 != NULL)
            {
              g_ptr_array_add (slaves, s);
            }
          else
            {
              g_free (s);
            }
        }
      g_dir_close (dir);
    }
  g_free (path);
  g_ptr_array_sort (slaves, (GCompareFunc) ptr_str_array_compare);
  g_ptr_array_add (slaves, NULL);
  device_set_slaves_objpath (device, (GStrv) slaves->pdata);
  g_ptr_array_foreach (slaves, (GFunc) g_free, NULL);
  g_ptr_array_free (slaves, TRUE);

  path = g_build_filename (device->priv->native_path, "holders", NULL);
  holders = g_ptr_array_new ();
  if ((dir = g_dir_open (path, 0, NULL)) != NULL)
    {
      while ((name = g_dir_read_name (dir)) != NULL)
        {
          Device *device2;

          s = compute_object_path (name);
          device2 = daemon_local_find_by_object_path (device->priv->daemon, s);
          if (device2 != NULL)
            {
              g_ptr_array_add (holders, s);
            }
          else
            {
              g_free (s);
            }
        }
      g_dir_close (dir);
    }
  g_free (path);
  g_ptr_array_sort (holders, (GCompareFunc) ptr_str_array_compare);
  g_ptr_array_add (holders, NULL);
  device_set_holders_objpath (device, (GStrv) holders->pdata);
  g_ptr_array_foreach (holders, (GFunc) g_free, NULL);
  g_ptr_array_free (holders, TRUE);

  /* ------------------------------------- */
  /* Now set all properties from udev data */
  /* ------------------------------------- */

  /* at this point we have
   *
   *  - device_file
   *  - device_file_by_id
   *  - device_file_by_path
   *  - device_size
   *  - device_block_size
   *  - device_is_removable
   *  - device_is_read_only
   *  - device_is_drive
   *  - device_is_media_available
   *  - device_is_partition
   *  - device_is_partition_table
   *  - slaves_objpath
   *  - holders_objpath
   *
   *  - partition_number
   *  - partition_slave
   *
   */

  /* device_is_linux_loop and linux_loop_* properties */
  if (!update_info_linux_loop (device))
    goto out;

  /* partition_* properties */
  if (!update_info_partition (device))
    goto out;

  /* partition_table_* properties */
  if (!update_info_partition_table (device))
    goto out;

  /* device_presentation_hide, device_presentation_name and device_presentation_icon_name properties */
  if (!update_info_presentation (device))
    goto out;

  /* id_* properties */
  if (!update_info_id (device))
    goto out;

  /* drive_* properties */
  if (!update_info_drive (device))
    goto out;

  /* device_is_optical_disc and optical_disc_* properties */
  if (!update_info_optical_disc (device))
    goto out;

  /* device_is_luks and luks_holder */
  if (!update_info_luks (device))
    goto out;

  /* device_is_luks_cleartext and luks_cleartext_* properties */
  if (!update_info_luks_cleartext (device))
    goto out;

#ifdef HAVE_LVM2
  /* device_is_linux_lvm2_lv and linux_lvm2_lv_* properties */
  if (!update_info_linux_lvm2_lv (device))
    goto out;

  /* device_is_linux_lvm2_pv and linux_lvm2_pv_* properties */
  if (!update_info_linux_lvm2_pv (device))
    goto out;
#endif

#ifdef HAVE_DMMP
  /* device_is_linux_dmmp and linux_dmmp_* properties */
  if (!update_info_linux_dmmp (device))
    goto out;

  /* device_is_partition and partition_* properties for dm-0 "partitions" on a multi-path device  */
  if (!update_info_partition_on_linux_dmmp (device))
    goto out;

  /* device_is_linux_dmmp_component and linux_dmmp_component_* properties */
  if (!update_info_linux_dmmp_component (device))
    goto out;
#endif

  /* device_is_linux_md_component and linux_md_component_* properties */
  if (!update_info_linux_md_component (device))
    goto out;

  /* device_is_linux_md and linux_md_* properties */
  if (!update_info_linux_md (device))
    goto out;

  /* drive_ata_smart_* properties */
  if (!update_info_drive_ata_smart (device))
    goto out;

  /* drive_can_spindown property */
  if (!update_info_drive_can_spindown (device))
    goto out;

  /* device_is_system_internal property */
  if (!update_info_is_system_internal (device))
    goto out;

  /* device_is_mounted, device_mount, device_mounted_by_uid */
  if (!update_info_mount_state (device))
    goto out;

  /* device_is_media_change_detected, device_is_media_change_detection_* properties */
  if (!update_info_media_detection (device))
    goto out;

  /* drive_adapter proprety */
  if (!update_info_drive_adapter (device))
    goto out;

  /* drive_ports property */
  if (!update_info_drive_ports (device))
    goto out;

  /* drive_similar_devices property */
  if (!update_info_drive_similar_devices (device))
    goto out;

  ret = TRUE;

 out:

  /* Now check if holders/ or slaves/ has changed since last update. We compute
   * the delta and do update_info() on each holder/slave that has been
   * added/removed.
   *
   * Note that this won't trigger an endless loop since we look at the diffs.
   *
   * We have to do this because the kernel doesn't generate any 'change' event
   * when slaves/ or holders/ change. This is unfortunate because we *need* such
   * a change event to update properties devices (for example: luks_holder).
   *
   * We do the update in idle because the update may depend on the device
   * currently being processed being added.
   */

  cur_slaves_objpath = dup_list_from_ptrarray (device->priv->slaves_objpath);
  cur_holders_objpath = dup_list_from_ptrarray (device->priv->holders_objpath);

  old_slaves_objpath = g_list_sort (old_slaves_objpath, (GCompareFunc) g_strcmp0);
  old_holders_objpath = g_list_sort (old_holders_objpath, (GCompareFunc) g_strcmp0);
  cur_slaves_objpath = g_list_sort (cur_slaves_objpath, (GCompareFunc) g_strcmp0);
  cur_holders_objpath = g_list_sort (cur_holders_objpath, (GCompareFunc) g_strcmp0);

  diff_sorted_lists (old_slaves_objpath, cur_slaves_objpath, (GCompareFunc) g_strcmp0, &added_objpath, &removed_objpath);
  for (l = added_objpath; l != NULL; l = l->next)
    {
      const gchar *objpath2 = l->data;
      Device *device2;

      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
      if (device2 != NULL)
        {
          update_info_in_idle (device2);
        }
      else
        {
          g_print ("**** NOTE: %s added non-existant slave %s\n", device->priv->object_path, objpath2);
        }
    }
  for (l = removed_objpath; l != NULL; l = l->next)
    {
      const gchar *objpath2 = l->data;
      Device *device2;

      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
      if (device2 != NULL)
        {
          update_info_in_idle (device2);
        }
      else
        {
        }
    }
  g_list_free (added_objpath);
  g_list_free (removed_objpath);

  diff_sorted_lists (old_holders_objpath,
                     cur_holders_objpath,
                     (GCompareFunc) g_strcmp0,
                     &added_objpath,
                     &removed_objpath);
  for (l = added_objpath; l != NULL; l = l->next)
    {
      const gchar *objpath2 = l->data;
      Device *device2;

      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
      if (device2 != NULL)
        {
          update_info_in_idle (device2);
        }
      else
        {
          g_print ("**** NOTE: %s added non-existant holder %s\n", device->priv->object_path, objpath2);
        }
    }
  for (l = removed_objpath; l != NULL; l = l->next)
    {
      const gchar *objpath2 = l->data;
      Device *device2;

      device2 = daemon_local_find_by_object_path (device->priv->daemon, objpath2);
      if (device2 != NULL)
        {
          update_info_in_idle (device2);
        }
      else
        {
        }
    }
  g_list_free (added_objpath);
  g_list_free (removed_objpath);

  g_list_foreach (old_slaves_objpath, (GFunc) g_free, NULL);
  g_list_free (old_slaves_objpath);
  g_list_foreach (old_holders_objpath, (GFunc) g_free, NULL);
  g_list_free (old_holders_objpath);
  g_list_foreach (cur_slaves_objpath, (GFunc) g_free, NULL);
  g_list_free (cur_slaves_objpath);
  g_list_foreach (cur_holders_objpath, (GFunc) g_free, NULL);
  g_list_free (cur_holders_objpath);

  PROFILE ("update_info(device=%s) end", device->priv->native_path);
  return ret;
}

Project: udisks
File: device.c

update_info_drive (Device *device)
{
  GPtrArray *media_compat_array;
  const gchar *media_in_drive;
  gboolean drive_is_ejectable;
  gboolean drive_can_detach;
  gchar *decoded_string;
  guint n;

  if (g_udev_device_has_property (device->priv->d, "ID_VENDOR_ENC"))
    {
      decoded_string = decode_udev_encoded_string (g_udev_device_get_property (device->priv->d, "ID_VENDOR_ENC"));
      g_strstrip (decoded_string);
      device_set_drive_vendor (device, decoded_string);
      g_free (decoded_string);
    }
  else if (g_udev_device_has_property (device->priv->d, "ID_VENDOR"))
    {
      device_set_drive_vendor (device, g_udev_device_get_property (device->priv->d, "ID_VENDOR"));
    }

  if (g_udev_device_has_property (device->priv->d, "ID_MODEL_ENC"))
    {
      decoded_string = decode_udev_encoded_string (g_udev_device_get_property (device->priv->d, "ID_MODEL_ENC"));
      g_strstrip (decoded_string);
      device_set_drive_model (device, decoded_string);
      g_free (decoded_string);
    }
  else if (g_udev_device_has_property (device->priv->d, "ID_MODEL"))
    {
      device_set_drive_model (device, g_udev_device_get_property (device->priv->d, "ID_MODEL"));
    }

  if (g_udev_device_has_property (device->priv->d, "ID_REVISION"))
    device_set_drive_revision (device, g_udev_device_get_property (device->priv->d, "ID_REVISION"));
  if (g_udev_device_has_property (device->priv->d, "ID_SCSI_SERIAL"))
    {
      /* scsi_id sometimes use the WWN as the serial - annoying - see
       * http://git.kernel.org/?p=linux/hotplug/udev.git;a=commit;h=4e9fdfccbdd16f0cfdb5c8fa8484a8ba0f2e69d3
       * for details
       */
      device_set_drive_serial (device, g_udev_device_get_property (device->priv->d, "ID_SCSI_SERIAL"));
    }
  else if (g_udev_device_has_property (device->priv->d, "ID_SERIAL_SHORT"))
    {
      device_set_drive_serial (device, g_udev_device_get_property (device->priv->d, "ID_SERIAL_SHORT"));
    }

  if (g_udev_device_has_property (device->priv->d, "ID_WWN_WITH_EXTENSION"))
    device_set_drive_wwn (device, g_udev_device_get_property (device->priv->d, "ID_WWN_WITH_EXTENSION") + 2);
  else if (g_udev_device_has_property (device->priv->d, "ID_WWN"))
    device_set_drive_wwn (device, g_udev_device_get_property (device->priv->d, "ID_WWN") + 2);

  /* pick up some things (vendor, model, connection_interface, connection_speed)
   * not (yet) exported by udev helpers
   */
  update_drive_properties_from_sysfs (device);

  if (g_udev_device_has_property (device->priv->d, "ID_DRIVE_EJECTABLE"))
    {
      drive_is_ejectable = g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_EJECTABLE");
    }
  else
    {
      drive_is_ejectable = FALSE;
      drive_is_ejectable |= g_udev_device_has_property (device->priv->d, "ID_CDROM");
      drive_is_ejectable |= g_udev_device_has_property (device->priv->d, "ID_DRIVE_FLOPPY_ZIP");
      drive_is_ejectable |= g_udev_device_has_property (device->priv->d, "ID_DRIVE_FLOPPY_JAZ");
    }
  device_set_drive_is_media_ejectable (device, drive_is_ejectable);

  media_compat_array = g_ptr_array_new ();
  for (n = 0; drive_media_mapping[n].udev_property != NULL; n++)
    {
      if (!g_udev_device_has_property (device->priv->d, drive_media_mapping[n].udev_property))
        continue;

      g_ptr_array_add (media_compat_array, (gpointer) drive_media_mapping[n].media_name);
    }
  /* special handling for SDIO since we don't yet have a sdio_id helper in udev to set properties */
  if (g_strcmp0 (device->priv->drive_connection_interface, "sdio") == 0)
    {
      gchar *type;

      type = sysfs_get_string (device->priv->native_path, "../../type");
      g_strstrip (type);
      if (g_strcmp0 (type, "MMC") == 0)
        {
          g_ptr_array_add (media_compat_array, "flash_mmc");
        }
      else if (g_strcmp0 (type, "SD") == 0)
        {
          g_ptr_array_add (media_compat_array, "flash_sd");
        }
      else if (g_strcmp0 (type, "SDHC") == 0)
        {
          g_ptr_array_add (media_compat_array, "flash_sdhc");
        }
      g_free (type);
    }
  g_ptr_array_sort (media_compat_array, (GCompareFunc) ptr_str_array_compare);
  g_ptr_array_add (media_compat_array, NULL);
  device_set_drive_media_compatibility (device, (GStrv) media_compat_array->pdata);

  media_in_drive = NULL;

  if (device->priv->device_is_media_available)
    {
      for (n = 0; media_mapping[n].udev_property != NULL; n++)
        {
          if (!g_udev_device_has_property (device->priv->d, media_mapping[n].udev_property))
            continue;

          media_in_drive = drive_media_mapping[n].media_name;
          break;
        }
      /* If the media isn't set (from e.g. udev rules), just pick the first one in media_compat - note
       * that this may be NULL (if we don't know what media is compatible with the drive) which is OK.
       */
      if (media_in_drive == NULL)
        media_in_drive = ((const gchar **) media_compat_array->pdata)[0];
    }
  device_set_drive_media (device, media_in_drive);

  g_ptr_array_free (media_compat_array, TRUE);

  /* right now, we only offer to detach USB devices */
  drive_can_detach = FALSE;
  if (g_strcmp0 (device->priv->drive_connection_interface, "usb") == 0)
    {
      drive_can_detach = TRUE;
    }
  if (g_udev_device_has_property (device->priv->d, "ID_DRIVE_DETACHABLE"))
    {
      drive_can_detach = g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_DETACHABLE");
    }
  device_set_drive_can_detach (device, drive_can_detach);

  /* rotational is in sysfs */
  device_set_drive_is_rotational (device, g_udev_device_get_sysfs_attr_as_boolean (device->priv->d, "queue/rotational"));

  if (g_udev_device_has_property (device->priv->d, "ID_ATA_ROTATION_RATE_RPM"))
    {
      device_set_drive_rotation_rate (device, g_udev_device_get_property_as_int (device->priv->d,
                                                                                 "ID_ATA_ROTATION_RATE_RPM"));
    }

  if (g_udev_device_get_property_as_boolean (device->priv->d, "ID_ATA_WRITE_CACHE"))
    {
      if (g_udev_device_get_property_as_boolean (device->priv->d, "ID_ATA_WRITE_CACHE_ENABLED"))
        {
          device_set_drive_write_cache (device, "enabled");
        }
      else
        {
          device_set_drive_write_cache (device, "disabled");
        }
    }

  return TRUE;
}

Project: udisks
File: device.c

update_info_drive_adapter (Device *device)
{
  Adapter *adapter;
  const gchar *adapter_object_path;

  adapter_object_path = NULL;

  adapter = daemon_local_find_enclosing_adapter (device->priv->daemon, device->priv->native_path);
  if (adapter != NULL)
    {
      adapter_object_path = adapter_local_get_object_path (adapter);
    }

  device_set_drive_adapter (device, adapter_object_path);

  return TRUE;
}

Project: udisks
File: device.c

update_info_drive_ata_smart (Device *device)
{
  gboolean ata_smart_is_available;

  ata_smart_is_available = FALSE;
  if (device->priv->device_is_drive && g_udev_device_has_property (device->priv->d, "UDISKS_ATA_SMART_IS_AVAILABLE"))
    ata_smart_is_available = g_udev_device_get_property_as_boolean (device->priv->d, "UDISKS_ATA_SMART_IS_AVAILABLE");

  device_set_drive_ata_smart_is_available (device, ata_smart_is_available);

  /* NOTE: we don't collect ATA SMART data here, we only set whether the device is ATA SMART capable;
   *       collecting data is done in separate routines, see the
   *       device_drive_ata_smart_refresh_data() function for details.
   */

  return TRUE;
}

Project: udisks
File: device.c

update_info_drive_can_spindown (Device *device)
{
  gboolean drive_can_spindown;

  /* Right now we only know how to spin down ATA devices (including those USB devices
   * that can do ATA SMART)
   *
   * This would probably also work for SCSI devices (since the helper is doing SCSI
   * STOP (which translated in libata to ATA's STANDBY IMMEDIATE) - but that needs
   * testing...
   */
  drive_can_spindown = FALSE;
  if (g_strcmp0 (device->priv->drive_connection_interface, "ata") == 0 || device->priv->drive_ata_smart_is_available)
    {
      drive_can_spindown = TRUE;
    }
  if (g_udev_device_has_property (device->priv->d, "ID_DRIVE_CAN_SPINDOWN"))
    {
      drive_can_spindown = g_udev_device_get_property_as_boolean (device->priv->d, "ID_DRIVE_CAN_SPINDOWN");
    }
  device_set_drive_can_spindown (device, drive_can_spindown);

  return TRUE;
}

Project: udisks
File: device.c

update_info_drive_ports (Device *device)
{
  GList *ports;
  GList *l;
  GPtrArray *p;

  ports = daemon_local_find_enclosing_ports (device->priv->daemon, device->priv->native_path);

  p = g_ptr_array_new ();
  for (l = ports; l != NULL; l = l->next)
    {
      Port *port = PORT (l->data);

      g_ptr_array_add (p, (gpointer) port_local_get_object_path (port));
    }
  g_ptr_array_add (p, NULL);
  device_set_drive_ports (device, (GStrv) p->pdata);
  g_ptr_array_unref (p);

  g_list_free (ports);

  return TRUE;
}

Project: udisks

update_info_drive_similar_devices (Device *device)
{
  GList *devices;
  GList *l;
  GPtrArray *p;

  p = g_ptr_array_new ();

  if (!device->priv->device_is_drive)
    goto out;

  /* We need non-empty SERIAL and WWN for this to work */
  if ((device->priv->drive_serial == NULL || strlen (device->priv->drive_serial) == 0) ||
      (device->priv->drive_wwn == NULL || strlen (device->priv->drive_wwn) == 0))
    goto out;

  /* TODO: this might be slow - if so, use a hash on the Daemon class */
  devices = daemon_local_get_all_devices (device->priv->daemon);
  for (l = devices; l != NULL; l = l->next)
    {
      Device *d = DEVICE (l->data);

      if (!d->priv->device_is_drive)
        continue;

      if (d == device)
        continue;

#if 0
      g_debug ("looking at %s:\n"
               "  %s\n"
               "  %s\n"
               "    %s\n"
               "    %s\n",
               d->priv->device_file,
               d->priv->drive_serial,
               device->priv->drive_serial,
               d->priv->drive_wwn,
               device->priv->drive_wwn);
#endif

      /* current policy is that *both* SERIAL and WWN must match */
      if (g_strcmp0 (d->priv->drive_serial, device->priv->drive_serial) == 0 &&
          g_strcmp0 (d->priv->drive_wwn, device->priv->drive_wwn) == 0)
        {
          g_ptr_array_add (p, d->priv->object_path);

          /* ensure that the device we added also exists in its own drive_similar_devices property */
          if (!ptr_array_has_string (d->priv->drive_similar_devices, device->priv->object_path))
            {
              update_info_in_idle (d);
            }
          else
            {
            }
        }
    }

 out:
  g_ptr_array_add (p, NULL);
  device_set_drive_similar_devices (device, (GStrv) p->pdata);
  g_ptr_array_free (p, TRUE);
  return TRUE;
}

Project: udisks
File: device.c

update_info_id (Device *device)
{
  gchar *decoded_string;
  const gchar *partition_scheme;
  gint partition_type;

  partition_scheme = g_udev_device_get_property (device->priv->d, "UDISKS_PARTITION_SCHEME");
  partition_type = g_udev_device_get_property_as_int (device->priv->d, "UDISKS_PARTITION_TYPE");
  if (g_strcmp0 (partition_scheme, "mbr") == 0 && (partition_type == 0x05 || partition_type == 0x0f || partition_type
                                                   == 0x85))
    {
      device_set_id_usage (device, "");
      device_set_id_type (device, "");
      device_set_id_version (device, "");
      device_set_id_label (device, "");
      device_set_id_uuid (device, "");
      goto out;
    }

  device_set_id_usage (device, g_udev_device_get_property (device->priv->d, "ID_FS_USAGE"));
  device_set_id_type (device, g_udev_device_get_property (device->priv->d, "ID_FS_TYPE"));
  device_set_id_version (device, g_udev_device_get_property (device->priv->d, "ID_FS_VERSION"));
  if (g_udev_device_has_property (device->priv->d, "ID_FS_LABEL_ENC"))
    {
      decoded_string = decode_udev_encoded_string (g_udev_device_get_property (device->priv->d, "ID_FS_LABEL_ENC"));
      device_set_id_label (device, decoded_string);
      g_free (decoded_string);
    }
  else
    {
      device_set_id_label (device, g_udev_device_get_property (device->priv->d, "ID_FS_LABEL"));
    }
  device_set_id_uuid (device, g_udev_device_get_property (device->priv->d, "ID_FS_UUID"));

 out:
  return TRUE;
}

Project: udisks
File: device.c

update_info_in_idle (Device *device)
{
  UpdateInfoInIdleData *data;

  data = g_new0 (UpdateInfoInIdleData, 1);
  data->device = device;
  data->idle_id = g_idle_add_full (G_PRIORITY_HIGH_IDLE,
                                   update_info_in_idle_cb,
                                   data,
                                   (GDestroyNotify) update_info_in_idle_data_free);

  g_object_weak_ref (G_OBJECT (device), update_info_in_idle_device_unreffed, data);
}

Project: udisks
File: device.c

update_info_in_idle_cb (gpointer user_data)
{
  UpdateInfoInIdleData *data = user_data;

  /* this indirectly calls update_info and also removes the device
   * if it wants to be removed (e.g. if update_info() returns FALSE)
   */
  daemon_local_synthesize_changed (data->device->priv->daemon, data->device);

  return FALSE; /* remove source */
}

Project: udisks
File: device.c

update_info_in_idle_data_free (UpdateInfoInIdleData *data)
{
  g_object_weak_unref (G_OBJECT (data->device), update_info_in_idle_device_unreffed, data);
  g_free (data);
}

Project: udisks
File: device.c

update_info_in_idle_device_unreffed (gpointer user_data,
                                     GObject *where_the_object_was)
{
  UpdateInfoInIdleData *data = user_data;
  g_source_remove (data->idle_id);
}

Project: udisks
File: device.c

update_info_is_system_internal (Device *device)
{
  gboolean is_system_internal;

  /* TODO: make it possible to override this property from a udev property.
   */

  /* start out by assuming the device is system internal, then adjust depending on what kind of
   * device we are dealing with
   */
  is_system_internal = TRUE;

  /* A Linux MD device is system internal if, and only if
   *
   * - a single component is system internal
   * - there are no components
   */
  if (device->priv->device_is_linux_md)
    {
      is_system_internal = FALSE;

      if (device->priv->slaves_objpath->len == 0)
        {
          is_system_internal = TRUE;
        }
      else
        {
          guint n;

          for (n = 0; n < device->priv->slaves_objpath->len; n++)
            {
              const gchar *slave_objpath;
              Device *slave;

              slave_objpath = device->priv->slaves_objpath->pdata[n];
              slave = daemon_local_find_by_object_path (device->priv->daemon, slave_objpath);
              if (slave == NULL)
                continue;

              if (slave->priv->device_is_system_internal)
                {
                  is_system_internal = TRUE;
                  break;
                }
            }
        }

      goto determined;
    }

  /* a partition is system internal only if the drive it belongs to is system internal */
  if (device->priv->device_is_partition)
    {
      Device *enclosing_device;

      enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->partition_slave);
      if (enclosing_device != NULL)
        {
          is_system_internal = enclosing_device->priv->device_is_system_internal;
        }
      else
        {
          is_system_internal = TRUE;
        }

      goto determined;
    }

  /* a LUKS cleartext device is system internal only if the underlying crypto-text
   * device is system internal
   */
  if (device->priv->device_is_luks_cleartext)
    {
      Device *enclosing_device;
      enclosing_device = daemon_local_find_by_object_path (device->priv->daemon, device->priv->luks_cleartext_slave);
      if (enclosing_device != NULL)
        {
          is_system_internal = enclosing_device->priv->device_is_system_internal;
        }
      else
        {
          is_system_internal = TRUE;
        }

      goto determined;
    }

  /* devices with removable media are never system internal */
  if (device->priv->device_is_removable)
    {
      is_system_internal = FALSE;
      goto determined;
    }

  /* devices on certain buses are never system internal */
  if (device->priv->device_is_drive && device->priv->drive_connection_interface != NULL)
    {

      if (strcmp (device->priv->drive_connection_interface, "ata_serial_esata") == 0
          || strcmp (device->priv->drive_connection_interface, "sdio") == 0
          || strcmp (device->priv->drive_connection_interface, "usb") == 0
          || strcmp (device->priv->drive_connection_interface, "firewire") == 0)
        {
          is_system_internal = FALSE;
        }
      else
        {
          is_system_internal = TRUE;
        }
      goto determined;
    }

 determined:
  device_set_device_is_system_internal (device, is_system_internal);

  return TRUE;
}

Project: udisks
File: device.c

update_info_linux_dmmp (Device *device)
{
  const gchar *dm_name;
  const gchar* const *target_types;
  const gchar* const *target_parameters;
  gchar *decoded_params;
  gboolean is_dmmp;
  guint n;
  GPtrArray *p;
  Device *component;
  gchar *s;

  is_dmmp = FALSE;
  p = NULL;
  decoded_params = NULL;

  dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME");
  if (dm_name == NULL)
    goto out;

  target_types = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_TYPE");
  if (target_types == NULL || g_strcmp0 (target_types[0], "multipath") != 0)
    goto out;

  if (device->priv->slaves_objpath->len == 0)
    goto out;

  target_parameters = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_PARAMS");
  if (target_parameters == NULL || g_strv_length ((gchar **) target_parameters) != 1)
    goto out;
  decoded_params = decode_udev_encoded_string (target_parameters[0]);

  device_set_linux_dmmp_name (device, dm_name);

  device_set_linux_dmmp_parameters (device, decoded_params);

  p = g_ptr_array_new ();
  component = NULL;
  for (n = 0; n < device->priv->slaves_objpath->len; n++)
    {
      const gchar *component_objpath = device->priv->slaves_objpath->pdata[n];
      if (component == NULL)
        {
          component = daemon_local_find_by_object_path (device->priv->daemon, component_objpath);
        }
      g_ptr_array_add (p, (gpointer) component_objpath);
    }
  g_ptr_array_add (p, NULL);
  device_set_linux_dmmp_slaves (device, (GStrv) p->pdata);

  if (component == NULL)
    goto out;

  /* Copy only drive properties used for identification to the multipath device. Yes,
   * this means, we'll get serial/wwn clashes but this is already so for each path.
   *
   * Also, clients *should* be smart about things and special-handle linux_dmmp and
   * linux_dmmp_component devices.
   */
  device_set_drive_vendor (device, component->priv->drive_vendor);
  device_set_drive_model (device, component->priv->drive_model);
  device_set_drive_revision (device, component->priv->drive_revision);
  device_set_drive_serial (device, component->priv->drive_serial);
  device_set_drive_wwn (device, component->priv->drive_wwn);

  /* connection interface */
  device_set_drive_connection_interface (device, "virtual_multipath");
  device_set_drive_connection_speed (device, 0);

  s = g_strdup_printf ("/dev/mapper/%s", dm_name);
  device_set_device_file_presentation (device, s);
  g_free (s);

  is_dmmp = TRUE;

 out:
  g_free (decoded_params);
  if (p != NULL)
    g_ptr_array_free (p, TRUE);
  device_set_device_is_linux_dmmp (device, is_dmmp);
  return TRUE;
}

Project: udisks
File: device.c

update_info_linux_dmmp_component (Device *device)
{
  gboolean is_dmmp_component;

  is_dmmp_component = FALSE;

  if (device->priv->holders_objpath->len == 1)
    {
      Device *holder;

      holder = daemon_local_find_by_object_path (device->priv->daemon, device->priv->holders_objpath->pdata[0]);
      if (holder != NULL && holder->priv->device_is_linux_dmmp)
        {
          is_dmmp_component = TRUE;
          device_set_linux_dmmp_component_holder (device, holder->priv->object_path);
        }
    }

  device_set_device_is_linux_dmmp_component (device, is_dmmp_component);
  return TRUE;
}

Project: udisks
File: device.c

update_info_linux_loop (Device *device)
{
  gboolean ret;
  gint fd;
  struct loop_info64 loop_info_buf;
  gboolean is_loop;
  gchar *s;
  gchar *s2;

  is_loop = FALSE;
  ret = FALSE;
  fd = -1;

  if (!g_str_has_prefix (device->priv->native_path, "/sys/devices/virtual/block/loop"))
    {
      ret = TRUE;
      goto out;
    }

  fd = open (device->priv->device_file, O_RDONLY);
  if (fd < 0)
    goto out;

  if (ioctl (fd, LOOP_GET_STATUS64, &loop_info_buf) != 0)
    goto out;

  /* TODO: is lo_file_name really NUL-terminated? */
  device_set_linux_loop_filename (device, (const gchar *) loop_info_buf.lo_file_name);

  ret = TRUE;
  is_loop = TRUE;

  device_set_drive_vendor (device, "Linux");
  s2 = g_path_get_basename ((gchar *) loop_info_buf.lo_file_name);
  s = g_strdup_printf ("Loop: %s", s2);
  g_free (s2);
  device_set_drive_model (device, s);
  g_free (s);

 out:
  if (fd > 0)
    close (fd);
  device_set_device_is_linux_loop (device, is_loop);
  return ret;
}

Project: udisks
File: device.c

update_info_linux_lvm2_lv (Device *device)
{
  const gchar *lv_name;
  const gchar *vg_name;
  const gchar *uuid;
  gchar *lv_uuid;
  gchar *vg_uuid;
  gboolean is_lv;

  is_lv = FALSE;
  lv_uuid = NULL;
  vg_uuid = NULL;

  lv_name = g_udev_device_get_property (device->priv->d, "DM_LV_NAME");
  vg_name = g_udev_device_get_property (device->priv->d, "DM_VG_NAME");

  if (lv_name == NULL || vg_name == NULL)
    goto out;

  uuid = g_udev_device_get_sysfs_attr (device->priv->d, "dm/uuid");
  if (uuid == NULL || !g_str_has_prefix (uuid, "LVM-"))
    goto out;

  vg_uuid = extract_lvm_uuid (uuid + 4);
  if (vg_uuid == NULL)
    goto out;

  lv_uuid = extract_lvm_uuid (uuid + 4 + 32);
  if (lv_uuid == NULL)
    goto out;

  is_lv = TRUE;
  device_set_linux_lvm2_lv_name (device, lv_name);
  device_set_linux_lvm2_lv_uuid (device, lv_uuid);
  device_set_linux_lvm2_lv_group_name (device, vg_name);
  device_set_linux_lvm2_lv_group_uuid (device, vg_uuid);

  device_set_device_is_drive (device, FALSE);
  device_set_device_is_partition (device, FALSE);

 out:
  device_set_device_is_linux_lvm2_lv (device, is_lv);
  g_free (vg_uuid);
  g_free (lv_uuid);
  return TRUE;
}

Project: udisks
File: device.c

update_info_linux_lvm2_pv (Device *device)
{
  const gchar *pv_uuid;
  guint64 pv_num_mda;
  const gchar *vg_name;
  const gchar *vg_uuid;
  gboolean is_pv;
  guint64 vg_size;
  guint64 vg_unallocated_size;
  guint64 vg_extent_size;
  guint64 vg_seqnum;
  const gchar* const *vg_pvs;
  const gchar* const *vg_lvs;

  pv_uuid               = g_udev_device_get_property (device->priv->d, "UDISKS_LVM2_PV_UUID");
  pv_num_mda            = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_NUM_MDA");
  vg_name               = g_udev_device_get_property (device->priv->d, "UDISKS_LVM2_PV_VG_NAME");
  vg_uuid               = g_udev_device_get_property (device->priv->d, "UDISKS_LVM2_PV_VG_UUID");
  vg_size               = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_SIZE");
  vg_unallocated_size   = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_FREE_SIZE");
  vg_extent_size        = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_EXTENT_SIZE");
  vg_seqnum             = g_udev_device_get_property_as_uint64 (device->priv->d, "UDISKS_LVM2_PV_VG_SEQNUM");
  vg_pvs                = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_LVM2_PV_VG_PV_LIST");
  vg_lvs                = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_LVM2_PV_VG_LV_LIST");

  is_pv = FALSE;

  if (pv_uuid == NULL)
    goto out;

  is_pv = TRUE;
  device_set_linux_lvm2_pv_uuid (device, pv_uuid);
  device_set_linux_lvm2_pv_num_metadata_areas (device, pv_num_mda);
  device_set_linux_lvm2_pv_group_name (device, vg_name);
  device_set_linux_lvm2_pv_group_uuid (device, vg_uuid);
  device_set_linux_lvm2_pv_group_size (device, vg_size);
  device_set_linux_lvm2_pv_group_unallocated_size (device, vg_unallocated_size);
  device_set_linux_lvm2_pv_group_extent_size (device, vg_extent_size);
  device_set_linux_lvm2_pv_group_sequence_number (device, vg_seqnum);
  device_set_linux_lvm2_pv_group_physical_volumes (device, (GStrv) vg_pvs);
  device_set_linux_lvm2_pv_group_logical_volumes (device, (GStrv) vg_lvs);

 out:
  device_set_device_is_linux_lvm2_pv (device, is_pv);
  return TRUE;
}