[arch-commits] Commit in udisks2/repos (8 files)

Felix Yan felixonmars at archlinux.org
Mon Dec 12 10:23:19 UTC 2016


    Date: Monday, December 12, 2016 @ 10:23:19
  Author: felixonmars
Revision: 283052

archrelease: copy trunk to extra-i686, extra-x86_64

Added:
  udisks2/repos/extra-i686/PKGBUILD
    (from rev 283051, udisks2/trunk/PKGBUILD)
  udisks2/repos/extra-i686/git-fixes.patch
    (from rev 283051, udisks2/trunk/git-fixes.patch)
  udisks2/repos/extra-x86_64/PKGBUILD
    (from rev 283051, udisks2/trunk/PKGBUILD)
  udisks2/repos/extra-x86_64/git-fixes.patch
    (from rev 283051, udisks2/trunk/git-fixes.patch)
Deleted:
  udisks2/repos/extra-i686/PKGBUILD
  udisks2/repos/extra-i686/git-fixes.patch
  udisks2/repos/extra-x86_64/PKGBUILD
  udisks2/repos/extra-x86_64/git-fixes.patch

------------------------------+
 /PKGBUILD                    |   82 ++
 /git-fixes.patch             | 1554 +++++++++++++++++++++++++++++++++++++++++
 extra-i686/PKGBUILD          |   41 -
 extra-i686/git-fixes.patch   |  777 --------------------
 extra-x86_64/PKGBUILD        |   41 -
 extra-x86_64/git-fixes.patch |  777 --------------------
 6 files changed, 1636 insertions(+), 1636 deletions(-)

Deleted: extra-i686/PKGBUILD
===================================================================
--- extra-i686/PKGBUILD	2016-12-12 10:22:55 UTC (rev 283051)
+++ extra-i686/PKGBUILD	2016-12-12 10:23:19 UTC (rev 283052)
@@ -1,41 +0,0 @@
-# $Id$
-# Maintainer: Felix Yan <felixonmars at archlinux.org>
-# Contributor: Ionut Biru <ibiru at archlinux.org>
-
-pkgname=udisks2
-pkgver=2.1.7
-pkgrel=1
-pkgdesc="Disk Management Service, version 2"
-arch=('i686' 'x86_64')
-url="http://www.freedesktop.org/wiki/Software/udisks"
-license=('GPL2')
-depends=('glib2' 'systemd' 'polkit' 'libatasmart' 'util-linux' 'libgudev')
-makedepends=('intltool' 'docbook-xsl' 'gobject-introspection' 'python2')
-optdepends=('parted: partition management'
-            'gptfdisk: GUID partition table support'
-            'ntfs-3g: NTFS filesystem management support'
-            'dosfstools: VFAT filesystem management support')
-source=(http://udisks.freedesktop.org/releases/udisks-$pkgver.tar.bz2{,.sign})
-sha256sums=('abae2bb3bdc691ca13c1e4c244630b8c881c4f3b35c207299f1b39b7bec83785'
-            'SKIP')
-validpgpkeys=('3DB46B55EFA59D40E6232148D14EF15DAFE11347')  # Martin Pitt
-
-build() {
-  cd udisks-$pkgver
-  ./configure --prefix=/usr --sysconfdir=/etc \
-      --sbindir=/usr/bin --libexecdir=/usr/lib \
-      --with-systemdsystemunitdir=/usr/lib/systemd/system \
-      --localstatedir=/var --disable-static
-  make
-}
-
-check() {
-  cd udisks-$pkgver
-  make check
-}
-
-package() {
-  cd udisks-$pkgver
-  make DESTDIR="$pkgdir" install \
-    bash_completiondir=/usr/share/bash-completion/completions
-}

Copied: udisks2/repos/extra-i686/PKGBUILD (from rev 283051, udisks2/trunk/PKGBUILD)
===================================================================
--- extra-i686/PKGBUILD	                        (rev 0)
+++ extra-i686/PKGBUILD	2016-12-12 10:23:19 UTC (rev 283052)
@@ -0,0 +1,41 @@
+# $Id$
+# Maintainer: Felix Yan <felixonmars at archlinux.org>
+# Contributor: Ionut Biru <ibiru at archlinux.org>
+
+pkgname=udisks2
+pkgver=2.1.8
+pkgrel=1
+pkgdesc="Disk Management Service, version 2"
+arch=('i686' 'x86_64')
+url="http://www.freedesktop.org/wiki/Software/udisks"
+license=('GPL2')
+depends=('glib2' 'systemd' 'polkit' 'libatasmart' 'util-linux' 'libgudev')
+makedepends=('intltool' 'docbook-xsl' 'gobject-introspection' 'python2')
+optdepends=('parted: partition management'
+            'gptfdisk: GUID partition table support'
+            'ntfs-3g: NTFS filesystem management support'
+            'dosfstools: VFAT filesystem management support')
+source=(http://udisks.freedesktop.org/releases/udisks-$pkgver.tar.bz2{,.sign})
+sha256sums=('da416914812a77e5f4d82b81deb8c25799fd3228d27d52f7bf89a501b1857dda'
+            'SKIP')
+validpgpkeys=('3DB46B55EFA59D40E6232148D14EF15DAFE11347')  # Martin Pitt
+
+build() {
+  cd udisks-$pkgver
+  ./configure --prefix=/usr --sysconfdir=/etc \
+      --sbindir=/usr/bin --libexecdir=/usr/lib \
+      --with-systemdsystemunitdir=/usr/lib/systemd/system \
+      --localstatedir=/var --disable-static
+  make
+}
+
+check() {
+  cd udisks-$pkgver
+  make check
+}
+
+package() {
+  cd udisks-$pkgver
+  make DESTDIR="$pkgdir" install \
+    bash_completiondir=/usr/share/bash-completion/completions
+}

Deleted: extra-i686/git-fixes.patch
===================================================================
--- extra-i686/git-fixes.patch	2016-12-12 10:22:55 UTC (rev 283051)
+++ extra-i686/git-fixes.patch	2016-12-12 10:23:19 UTC (rev 283052)
@@ -1,777 +0,0 @@
-diff --git a/data/80-udisks2.rules b/data/80-udisks2.rules
-index ed093ee..7112db8 100644
---- a/data/80-udisks2.rules
-+++ b/data/80-udisks2.rules
-@@ -94,6 +94,9 @@ SUBSYSTEMS=="usb", ENV{ID_VENDOR}=="*SanDisk*", ENV{ID_MODEL}=="*Cruzer*", ENV{I
- SUBSYSTEMS=="usb", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="*v125w*", ENV{ID_DRIVE_THUMB}="1"
- SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="13fe", ENV{ID_MODEL}=="*Patriot*", ENV{ID_DRIVE_THUMB}="1"
- 
-+# SD-Card reader in Chromebook Pixel
-+SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="05e3", ENV{ID_MODEL_ID}=="0727", ENV{ID_DRIVE_FLASH_SD}="1"
-+
- # ------------------------------------------------------------------------
- # ------------------------------------------------------------------------
- # ------------------------------------------------------------------------
-diff --git a/doc/man/udisksctl.xml b/doc/man/udisksctl.xml
-index 8f38479..434a8fb 100644
---- a/doc/man/udisksctl.xml
-+++ b/doc/man/udisksctl.xml
-@@ -104,6 +104,16 @@
- 
-     <cmdsynopsis>
-       <command>udisksctl</command>
-+      <arg choice="plain">power-off </arg>
-+      <group choice="req">
-+        <arg choice="plain">--object-path <replaceable>OBJECT</replaceable></arg>
-+        <arg choice="plain">--block-device <replaceable>DEVICE</replaceable></arg>
-+      </group>
-+      <arg choice="opt">--no-user-interaction</arg>
-+    </cmdsynopsis>
-+
-+    <cmdsynopsis>
-+      <command>udisksctl</command>
-       <arg choice="plain">smart-simulate </arg>
-       <arg choice="plain">--file <replaceable>PATH</replaceable></arg>
-       <group choice="req">
-@@ -238,6 +248,31 @@
-       </varlistentry>
- 
-       <varlistentry>
-+        <term><option>power-off</option></term>
-+        <listitem>
-+          <para>
-+            Arranges for the drive to be safely removed and powered
-+            off. On the OS side this includes ensuring that no process
-+            is using the drive, then requesting that in-flight buffers
-+            and caches are committed to stable storage. The exact
-+            steps for powering off the drive depends on the drive
-+            itself and the interconnect used. For drives connected
-+            through USB, the effect is that the USB device will be
-+            deconfigured followed by disabling the upstream hub port
-+            it is connected to.
-+          </para>
-+          <para>
-+            Note that as some physical devices contain multiple drives
-+            (for example 4-in-1 flash card reader USB devices)
-+            powering off one drive may affect other drives. As such
-+            there are not a lot of guarantees associated with
-+            performing this action. Usually the effect is that the
-+            drive disappears as if it was unplugged.
-+          </para>
-+        </listitem>
-+      </varlistentry>
-+
-+      <varlistentry>
-         <term><option>smart-simulate</option></term>
-         <listitem>
-           <para>
-diff --git a/src/udisksdaemonutil.c b/src/udisksdaemonutil.c
-index 574bf2c..a588580 100644
---- a/src/udisksdaemonutil.c
-+++ b/src/udisksdaemonutil.c
-@@ -830,7 +830,7 @@ udisks_daemon_util_get_caller_uid_sync (UDisksDaemon            *daemon,
-     {
-       struct passwd pwstruct;
-       gchar pwbuf[8192];
--      static struct passwd *pw;
-+      struct passwd *pw = NULL;
-       int rc;
- 
-       rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-@@ -840,6 +840,7 @@ udisks_daemon_util_get_caller_uid_sync (UDisksDaemon            *daemon,
-                        UDISKS_ERROR,
-                        UDISKS_ERROR_FAILED,
-                        "User with uid %d does not exist", (gint) uid);
-+          goto out;
-         }
-       else if (pw == NULL)
-         {
-diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c
-index d619850..22bcfd0 100644
---- a/src/udiskslinuxblock.c
-+++ b/src/udiskslinuxblock.c
-@@ -804,12 +804,23 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
-       gchar *dm_name_dev_file = NULL;
-       const gchar *dm_name_dev_file_as_symlink = NULL;
- 
-+      const gchar *dm_vg_name;
-+      const gchar *dm_lv_name;
-+      gchar *dm_lvm_dev_file = NULL;
-+
-       dm_name = g_udev_device_get_property (device->udev_device, "DM_NAME");
-       if (dm_name != NULL)
-         dm_name_dev_file = g_strdup_printf ("/dev/mapper/%s", dm_name);
-+
-+      dm_vg_name = g_udev_device_get_property (device->udev_device, "DM_VG_NAME");
-+      dm_lv_name = g_udev_device_get_property (device->udev_device, "DM_LV_NAME");
-+      if (dm_vg_name != NULL && dm_lv_name != NULL)
-+        dm_lvm_dev_file =  g_strdup_printf ("/dev/%s/%s", dm_vg_name, dm_lv_name);
-+
-       for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
-         {
--          if (g_str_has_prefix (symlinks[n], "/dev/vg_"))
-+          if (g_str_has_prefix (symlinks[n], "/dev/vg_")
-+              || g_strcmp0 (symlinks[n], dm_lvm_dev_file) == 0)
-             {
-               /* LVM2 */
-               preferred_device_file = symlinks[n];
-@@ -824,6 +835,7 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
-       if (preferred_device_file == NULL && dm_name_dev_file_as_symlink != NULL)
-         preferred_device_file = dm_name_dev_file_as_symlink;
-       g_free (dm_name_dev_file);
-+      g_free (dm_lvm_dev_file);
-     }
-   else if (g_str_has_prefix (device_file, "/dev/md"))
-     {
-diff --git a/src/udiskslinuxdevice.c b/src/udiskslinuxdevice.c
-index 0b65a69..8c4a3ed 100644
---- a/src/udiskslinuxdevice.c
-+++ b/src/udiskslinuxdevice.c
-@@ -199,6 +199,7 @@ probe_ata (UDisksLinuxDevice  *device,
-     {
-       /* ATA8: 7.16 IDENTIFY DEVICE - ECh, PIO Data-In */
-       input.command = 0xec;
-+      input.count = 1;
-       output.buffer = g_new0 (guchar, 512);
-       output.buffer_size = 512;
-       if (!udisks_ata_send_command_sync (fd,
-@@ -221,6 +222,7 @@ probe_ata (UDisksLinuxDevice  *device,
-     {
-       /* ATA8: 7.17 IDENTIFY PACKET DEVICE - A1h, PIO Data-In */
-       input.command = 0xa1;
-+      input.count = 1;
-       output.buffer = g_new0 (guchar, 512);
-       output.buffer_size = 512;
-       if (!udisks_ata_send_command_sync (fd,
-diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c
-index 170ba27..ed541ff 100644
---- a/src/udiskslinuxdrive.c
-+++ b/src/udiskslinuxdrive.c
-@@ -25,6 +25,12 @@
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
-+#include <inttypes.h>
-+#include <errno.h>
-+#include <linux/bsg.h>
-+#include <scsi/scsi.h>
-+#include <scsi/sg.h>
-+#include <scsi/scsi_ioctl.h>
- 
- #include <pwd.h>
- #include <grp.h>
-@@ -1192,6 +1198,122 @@ handle_set_configuration (UDisksDrive           *_drive,
- 
- /* ---------------------------------------------------------------------------------------------------- */
- 
-+/* TODO: move to udisksscsi.[ch] similar what we do for ATA with udisksata.[ch] */
-+
-+static gboolean
-+send_scsi_command_sync (gint      fd,
-+                        guint8   *cdb,
-+                        gsize     cdb_len,
-+                        GError  **error)
-+{
-+  struct sg_io_v4 io_v4;
-+  uint8_t sense[32];
-+  gboolean ret = FALSE;
-+  gint rc;
-+  gint timeout_msec = 30000; /* 30 seconds */
-+
-+  g_return_val_if_fail (fd != -1, FALSE);
-+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-+
-+  /* See http://sg.danny.cz/sg/sg_io.html and http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/index.html
-+   * for detailed information about how the SG_IO ioctl work
-+   */
-+
-+  memset (sense, 0, sizeof (sense));
-+  memset (&io_v4, 0, sizeof (io_v4));
-+  io_v4.guard = 'Q';
-+  io_v4.protocol = BSG_PROTOCOL_SCSI;
-+  io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
-+  io_v4.request_len = cdb_len;
-+  io_v4.request = (uintptr_t) cdb;
-+  io_v4.max_response_len = sizeof (sense);
-+  io_v4.response = (uintptr_t) sense;
-+  io_v4.timeout = timeout_msec;
-+
-+  rc = ioctl (fd, SG_IO, &io_v4);
-+  if (rc != 0)
-+    {
-+      /* could be that the driver doesn't do version 4, try version 3 */
-+      if (errno == EINVAL)
-+        {
-+          struct sg_io_hdr io_hdr;
-+          memset (&io_hdr, 0, sizeof (struct sg_io_hdr));
-+          io_hdr.interface_id = 'S';
-+          io_hdr.cmdp = (unsigned char*) cdb;
-+          io_hdr.cmd_len = cdb_len;
-+          io_hdr.dxfer_direction = SG_DXFER_NONE;
-+          io_hdr.sbp = sense;
-+          io_hdr.mx_sb_len = sizeof (sense);
-+          io_hdr.timeout = timeout_msec;
-+
-+          rc = ioctl (fd, SG_IO, &io_hdr);
-+          if (rc != 0)
-+            {
-+              g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
-+                           "SGIO v3 ioctl failed (v4 not supported): %m");
-+              goto out;
-+            }
-+          else
-+            {
-+              if (!(io_hdr.status == 0 &&
-+                    io_hdr.host_status == 0 &&
-+                    io_hdr.driver_status == 0))
-+                {
-+                  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-+                               "Non-GOOD SCSI status from SGIO v3 ioctl: "
-+                               "status=%d host_status=%d driver_status=%d",
-+                               io_hdr.status,
-+                               io_hdr.host_status,
-+                               io_hdr.driver_status);
-+                  goto out;
-+                }
-+            }
-+        }
-+      else
-+        {
-+          g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
-+                       "SGIO v4 ioctl failed: %m");
-+          goto out;
-+        }
-+    }
-+  else
-+    {
-+      if (!(io_v4.device_status == 0 &&
-+            io_v4.transport_status == 0 &&
-+            io_v4.driver_status == 0))
-+        {
-+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-+                       "Non-GOOD SCSI status from SGIO v4 ioctl: "
-+                       "device_status=%d transport_status=%d driver_status=%d",
-+                       io_v4.device_status,
-+                       io_v4.transport_status,
-+                       io_v4.driver_status);
-+          goto out;
-+        }
-+    }
-+
-+  ret = TRUE;
-+
-+ out:
-+  return ret;
-+}
-+
-+static gboolean
-+send_scsi_start_stop_command_sync (gint      fd,
-+                                   GError  **error)
-+{
-+  uint8_t cdb[6];
-+
-+  /* SBC3 (SCSI Block Commands), 5.20 START STOP UNIT command
-+   */
-+  memset (cdb, 0, sizeof cdb);
-+  cdb[0] = 0x1b;                        /* OPERATION CODE: START STOP UNIT */
-+
-+  return send_scsi_command_sync (fd, cdb, sizeof cdb, error);
-+}
-+
-+/* ---------------------------------------------------------------------------------------------------- */
-+
- static gboolean
- handle_power_off (UDisksDrive           *_drive,
-                   GDBusMethodInvocation *invocation,
-@@ -1216,6 +1338,7 @@ handle_power_off (UDisksDrive           *_drive,
-   gid_t caller_gid;
-   pid_t caller_pid;
-   GList *sibling_objects = NULL, *l;
-+  gint fd = -1;
- 
-   object = udisks_daemon_util_dup_object (drive, &error);
-   if (object == NULL)
-@@ -1324,10 +1447,10 @@ handle_power_off (UDisksDrive           *_drive,
-     {
-       UDisksBlock *block_to_sync = UDISKS_BLOCK (l->data);
-       const gchar *device_file;
--      gint fd;
-+      gint device_fd;
-       device_file = udisks_block_get_device (block_to_sync);
--      fd = open (device_file, O_RDONLY|O_NONBLOCK|O_EXCL);
--      if (fd == -1)
-+      device_fd = open (device_file, O_RDONLY|O_NONBLOCK|O_EXCL);
-+      if (device_fd == -1)
-         {
-           g_dbus_method_invocation_return_error (invocation,
-                                                  UDISKS_ERROR,
-@@ -1336,7 +1459,7 @@ handle_power_off (UDisksDrive           *_drive,
-                                                  device_file);
-           goto out;
-         }
--      if (fsync (fd) != 0)
-+      if (fsync (device_fd) != 0)
-         {
-           g_dbus_method_invocation_return_error (invocation,
-                                                  UDISKS_ERROR,
-@@ -1345,7 +1468,7 @@ handle_power_off (UDisksDrive           *_drive,
-                                                  device_file);
-           goto out;
-         }
--      if (close (fd) != 0)
-+      if (close (device_fd) != 0)
-         {
-           g_dbus_method_invocation_return_error (invocation,
-                                                  UDISKS_ERROR,
-@@ -1356,9 +1479,45 @@ handle_power_off (UDisksDrive           *_drive,
-         }
-     }
- 
--  escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
-+  /* Send the "SCSI START STOP UNIT" command to request that the unit
-+   * be stopped but don't treat failure as fatal. In fact some
-+   * USB-attached hard-disks fails with this command, probably due to
-+   * the SCSI/SATA translation layer.
-+   */
-+  fd = open (udisks_block_get_device (block), O_RDONLY|O_NONBLOCK|O_EXCL);
-+  if (fd == -1)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             UDISKS_ERROR,
-+                                             UDISKS_ERROR_FAILED,
-+                                             "Error opening %s: %m",
-+                                             udisks_block_get_device (block));
-+      goto out;
-+    }
-+  if (!send_scsi_start_stop_command_sync (fd, &error))
-+    {
-+      udisks_warning ("Ignoring SCSI command START STOP UNIT failure (%s) on %s",
-+                      error->message,
-+                      udisks_block_get_device (block));
-+      g_clear_error (&error);
-+    }
-+  else
-+    {
-+      udisks_notice ("Powering off %s - successfully sent SCSI command START STOP UNIT",
-+                     udisks_block_get_device (block));
-+    }
-+  if (close (fd) != 0)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             UDISKS_ERROR,
-+                                             UDISKS_ERROR_FAILED,
-+                                             "Error closing %s: %m",
-+                                             udisks_block_get_device (block));
-+      goto out;
-+    }
-+  fd = -1;
- 
--  /* TODO: Send the eject? Send SCSI START STOP UNIT? */
-+  escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
-   device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
-   if (device == NULL)
-     {
-@@ -1405,10 +1564,20 @@ handle_power_off (UDisksDrive           *_drive,
-         }
-     }
-   fclose (f);
-+  udisks_notice ("Powered off %s - successfully wrote to sysfs path %s",
-+                 udisks_block_get_device (block),
-+                 remove_path);
- 
-   udisks_drive_complete_power_off (UDISKS_DRIVE (drive), invocation);
- 
-  out:
-+  if (fd != -1)
-+    {
-+      if (close (fd) != 0)
-+        {
-+          udisks_warning ("Error closing device: %m");
-+        }
-+    }
-   g_list_free_full (blocks_to_sync, g_object_unref);
-   g_list_free_full (sibling_objects, g_object_unref);
-   g_free (remove_path);
-diff --git a/src/udiskslinuxdriveata.c b/src/udiskslinuxdriveata.c
-index 48cc6e6..534ef4d 100644
---- a/src/udiskslinuxdriveata.c
-+++ b/src/udiskslinuxdriveata.c
-@@ -1943,7 +1943,7 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta     *drive,
-   /* First get the IDENTIFY data directly from the drive, for sanity checks */
-   {
-     /* ATA8: 7.16 IDENTIFY DEVICE - ECh, PIO Data-In */
--    UDisksAtaCommandInput input = {.command = 0xec};
-+    UDisksAtaCommandInput input = {.command = 0xec, .count = 1};
-     UDisksAtaCommandOutput output = {.buffer = identify.buf, .buffer_size = sizeof (identify.buf)};
-     if (!udisks_ata_send_command_sync (fd,
-                                        -1,
-diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c
-index 4c8d8aa..f243046 100644
---- a/src/udiskslinuxfilesystem.c
-+++ b/src/udiskslinuxfilesystem.c
-@@ -348,13 +348,16 @@ find_mount_options_for_fs (const gchar *fstype)
- static gid_t
- find_primary_gid (uid_t uid)
- {
--  struct passwd *pw;
-+  struct passwd *pw = NULL;
-+  struct passwd pwstruct;
-+  gchar pwbuf[8192];
-+  int rc;
-   gid_t gid;
- 
-   gid = (gid_t) - 1;
- 
--  pw = getpwuid (uid);
--  if (pw == NULL)
-+  rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-+  if (rc != 0 || pw == NULL)
-     {
-       udisks_warning ("Error looking up uid %d: %m", uid);
-       goto out;
-@@ -370,7 +373,10 @@ is_uid_in_gid (uid_t uid,
-                gid_t gid)
- {
-   gboolean ret;
--  struct passwd *pw;
-+  struct passwd *pw = NULL;
-+  struct passwd pwstruct;
-+  gchar pwbuf[8192];
-+  int rc;
-   static gid_t supplementary_groups[128];
-   int num_supplementary_groups = 128;
-   int n;
-@@ -379,8 +385,8 @@ is_uid_in_gid (uid_t uid,
- 
-   ret = FALSE;
- 
--  pw = getpwuid (uid);
--  if (pw == NULL)
-+  rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-+  if (rc != 0 || pw == NULL)
-     {
-       udisks_warning ("Error looking up uid %d: %m", uid);
-       goto out;
-diff --git a/src/udisksspawnedjob.c b/src/udisksspawnedjob.c
-index 802551f..b181933 100644
---- a/src/udisksspawnedjob.c
-+++ b/src/udisksspawnedjob.c
-@@ -371,22 +371,25 @@ static void
- child_setup (gpointer user_data)
- {
-   UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data);
--  struct passwd *pw;
-+  struct passwd pwstruct;
-+  gchar pwbuf[8192];
-+  struct passwd *pw = NULL;
-+  int rc;
-   gid_t egid;
- 
-   if (job->run_as_uid == getuid () && job->run_as_euid == geteuid ())
-     goto out;
- 
--  pw = getpwuid (job->run_as_euid);
--  if (pw == NULL)
-+  rc = getpwuid_r (job->run_as_euid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-+  if (rc != 0 || pw == NULL)
-    {
-      g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_euid);
-      abort ();
-    }
-   egid = pw->pw_gid;
- 
--  pw = getpwuid (job->run_as_uid);
--  if (pw == NULL)
-+  rc = getpwuid_r (job->run_as_uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-+  if (rc != 0 || pw == NULL)
-    {
-      g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_uid);
-      abort ();
-diff --git a/tools/udisksctl.c b/tools/udisksctl.c
-index 97b0f17..c87fe9f 100644
---- a/tools/udisksctl.c
-+++ b/tools/udisksctl.c
-@@ -1691,6 +1691,12 @@ handle_command_loop (gint        *argc,
-           goto out;
-         }
- 
-+      if (udisks_object_peek_loop (object) == NULL)
-+        {
-+          g_printerr ("Error: specified object is not a loop device\n");
-+          goto out;
-+        }
-+
-     delete_try_again:
-       error = NULL;
-       if (!udisks_loop_call_delete_sync (udisks_object_peek_loop (object),
-@@ -2009,6 +2015,238 @@ handle_command_smart_simulate (gint        *argc,
- 
- /* ---------------------------------------------------------------------------------------------------- */
- 
-+static gchar   *opt_power_off_object_path = NULL;
-+static gchar   *opt_power_off_device = NULL;
-+static gboolean opt_power_off_no_user_interaction = FALSE;
-+
-+static const GOptionEntry command_power_off_entries[] =
-+{
-+  {
-+    "object-path",
-+    'p',
-+    0,
-+    G_OPTION_ARG_STRING,
-+    &opt_power_off_object_path,
-+    "Object path for ATA device",
-+    NULL
-+  },
-+  {
-+    "block-device",
-+    'b',
-+    0,
-+    G_OPTION_ARG_STRING,
-+    &opt_power_off_device,
-+    "Device file for ATA device",
-+    NULL
-+  },
-+  {
-+    "no-user-interaction",
-+    0, /* no short option */
-+    0,
-+    G_OPTION_ARG_NONE,
-+    &opt_power_off_no_user_interaction,
-+    "Do not authenticate the user if needed",
-+    NULL
-+  },
-+  {
-+    NULL
-+  }
-+};
-+
-+static gint
-+handle_command_power_off (gint        *argc,
-+                          gchar      **argv[],
-+                          gboolean     request_completion,
-+                          const gchar *completion_cur,
-+                          const gchar *completion_prev)
-+{
-+  gint ret;
-+  GOptionContext *o;
-+  gchar *s;
-+  gboolean complete_objects;
-+  gboolean complete_devices;
-+  GList *l;
-+  GList *objects;
-+  UDisksObject *object;
-+  UDisksDriveAta *ata;
-+  guint n;
-+  GVariant *options;
-+  GVariantBuilder builder;
-+  GError *error;
-+
-+  ret = 1;
-+  opt_power_off_object_path = NULL;
-+  opt_power_off_device = NULL;
-+  object = NULL;
-+  options = NULL;
-+
-+  modify_argv0_for_command (argc, argv, "power-off");
-+
-+  o = g_option_context_new (NULL);
-+  if (request_completion)
-+    g_option_context_set_ignore_unknown_options (o, TRUE);
-+  g_option_context_set_help_enabled (o, FALSE);
-+  g_option_context_set_summary (o, "Safely power off a drive.");
-+  g_option_context_add_main_entries (o,
-+                                     command_power_off_entries,
-+                                     NULL /* GETTEXT_PACKAGE*/);
-+
-+  complete_objects = FALSE;
-+  if (request_completion && (g_strcmp0 (completion_prev, "--object-path") == 0 || g_strcmp0 (completion_prev, "-p") == 0))
-+    {
-+      complete_objects = TRUE;
-+      remove_arg ((*argc) - 1, argc, argv);
-+    }
-+
-+  complete_devices = FALSE;
-+  if (request_completion && (g_strcmp0 (completion_prev, "--block-device") == 0 || g_strcmp0 (completion_prev, "-b") == 0))
-+    {
-+      complete_devices = TRUE;
-+      remove_arg ((*argc) - 1, argc, argv);
-+    }
-+
-+  if (!g_option_context_parse (o, argc, argv, NULL))
-+    {
-+      if (!request_completion)
-+        {
-+          s = g_option_context_get_help (o, FALSE, NULL);
-+          g_printerr ("%s", s);
-+          g_free (s);
-+          goto out;
-+        }
-+    }
-+
-+  if (request_completion)
-+    {
-+      if ((opt_power_off_object_path == NULL && !complete_objects) &&
-+          (opt_power_off_device == NULL && !complete_devices))
-+        {
-+          g_print ("--object-path \n"
-+                   "--block-device \n");
-+        }
-+
-+      if (complete_objects)
-+        {
-+          const gchar *object_path;
-+          objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (client));
-+          for (l = objects; l != NULL; l = l->next)
-+            {
-+              object = UDISKS_OBJECT (l->data);
-+              ata = udisks_object_peek_drive_ata (object);
-+              if (ata != NULL)
-+                {
-+                  object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
-+                  g_assert (g_str_has_prefix (object_path, "/org/freedesktop/UDisks2/"));
-+                  g_print ("%s \n", object_path + sizeof ("/org/freedesktop/UDisks2/") - 1);
-+                }
-+            }
-+          g_list_foreach (objects, (GFunc) g_object_unref, NULL);
-+          g_list_free (objects);
-+        }
-+
-+      if (complete_devices)
-+        {
-+          objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (client));
-+          for (l = objects; l != NULL; l = l->next)
-+            {
-+              object = UDISKS_OBJECT (l->data);
-+              ata = udisks_object_peek_drive_ata (object);
-+              if (ata != NULL)
-+                {
-+                  const gchar * const *symlinks;
-+                  UDisksBlock *block;
-+                  block = udisks_client_get_block_for_drive (client, udisks_object_peek_drive (object), TRUE);
-+                  g_print ("%s \n", udisks_block_get_device (block));
-+                  symlinks = udisks_block_get_symlinks (block);
-+                  for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
-+                    g_print ("%s \n", symlinks[n]);
-+                }
-+            }
-+          g_list_foreach (objects, (GFunc) g_object_unref, NULL);
-+          g_list_free (objects);
-+        }
-+      goto out;
-+    }
-+
-+  g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
-+  if (opt_power_off_no_user_interaction)
-+    {
-+      g_variant_builder_add (&builder,
-+                             "{sv}",
-+                             "auth.no_user_interaction", g_variant_new_boolean (TRUE));
-+    }
-+  options = g_variant_builder_end (&builder);
-+  g_variant_ref_sink (options);
-+
-+  if (opt_power_off_object_path != NULL)
-+    {
-+      object = lookup_object_by_path (opt_power_off_object_path);
-+      if (object == NULL)
-+        {
-+          g_printerr ("Error looking up object with path %s\n", opt_power_off_object_path);
-+          goto out;
-+        }
-+    }
-+  else if (opt_power_off_device != NULL)
-+    {
-+      UDisksObject *block_object;
-+      UDisksDrive *drive;
-+      block_object = lookup_object_by_device (opt_power_off_device);
-+      if (block_object == NULL)
-+        {
-+          g_printerr ("Error looking up object for device %s\n", opt_power_off_device);
-+          goto out;
-+        }
-+      drive = udisks_client_get_drive_for_block (client, udisks_object_peek_block (block_object));
-+      object = (UDisksObject *) g_dbus_interface_dup_object (G_DBUS_INTERFACE (drive));
-+      g_object_unref (block_object);
-+    }
-+  else
-+    {
-+      s = g_option_context_get_help (o, FALSE, NULL);
-+      g_printerr ("%s", s);
-+      g_free (s);
-+      goto out;
-+    }
-+
-+ try_again:
-+  error = NULL;
-+  if (!udisks_drive_call_power_off_sync (udisks_object_peek_drive (object),
-+                                         options,
-+                                         NULL,                       /* GCancellable */
-+                                         &error))
-+    {
-+      if (error->domain == UDISKS_ERROR &&
-+          error->code == UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN &&
-+          setup_local_polkit_agent ())
-+        {
-+          g_error_free (error);
-+          goto try_again;
-+        }
-+      g_dbus_error_strip_remote_error (error);
-+      g_printerr ("Error powering off drive: %s (%s, %d)\n",
-+                  error->message, g_quark_to_string (error->domain), error->code);
-+      g_clear_error (&error);
-+      g_object_unref (object);
-+      goto out;
-+    }
-+
-+  g_object_unref (object);
-+
-+
-+  ret = 0;
-+
-+ out:
-+  if (options != NULL)
-+    g_variant_unref (options);
-+  g_option_context_free (o);
-+  g_free (opt_power_off_object_path);
-+  g_free (opt_power_off_device);
-+  return ret;
-+}
-+
-+/* ---------------------------------------------------------------------------------------------------- */
-+
- static gchar *opt_info_object = NULL;
- static gchar *opt_info_device = NULL;
- static gchar *opt_info_drive = NULL;
-@@ -2855,6 +3093,7 @@ usage (gint *argc, gchar **argv[], gboolean use_stdout)
-                        "  lock            Lock an encrypted device\n"
-                        "  loop-setup      Set-up a loop device\n"
-                        "  loop-delete     Delete a loop device\n"
-+                       "  power-off       Safely power off a drive\n"
-                        "  smart-simulate  Set SMART data for a drive\n"
-                        "\n"
-                        "Use \"%s COMMAND --help\" to get help on each command.\n",
-@@ -3053,6 +3292,15 @@ main (int argc,
-                                            completion_prev);
-       goto out;
-     }
-+  else if (g_strcmp0 (command, "power-off") == 0)
-+    {
-+      ret = handle_command_power_off (&argc,
-+                                      &argv,
-+                                      request_completion,
-+                                      completion_cur,
-+                                      completion_prev);
-+      goto out;
-+    }
-   else if (g_strcmp0 (command, "dump") == 0)
-     {
-       ret = handle_command_dump (&argc,
-@@ -3156,6 +3404,7 @@ main (int argc,
-                    "unlock \n"
-                    "loop-setup \n"
-                    "loop-delete \n"
-+                   "power-off \n"
-                    "smart-simulate \n"
-                    );
-           ret = 0;

Copied: udisks2/repos/extra-i686/git-fixes.patch (from rev 283051, udisks2/trunk/git-fixes.patch)
===================================================================
--- extra-i686/git-fixes.patch	                        (rev 0)
+++ extra-i686/git-fixes.patch	2016-12-12 10:23:19 UTC (rev 283052)
@@ -0,0 +1,777 @@
+diff --git a/data/80-udisks2.rules b/data/80-udisks2.rules
+index ed093ee..7112db8 100644
+--- a/data/80-udisks2.rules
++++ b/data/80-udisks2.rules
+@@ -94,6 +94,9 @@ SUBSYSTEMS=="usb", ENV{ID_VENDOR}=="*SanDisk*", ENV{ID_MODEL}=="*Cruzer*", ENV{I
+ SUBSYSTEMS=="usb", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="*v125w*", ENV{ID_DRIVE_THUMB}="1"
+ SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="13fe", ENV{ID_MODEL}=="*Patriot*", ENV{ID_DRIVE_THUMB}="1"
+ 
++# SD-Card reader in Chromebook Pixel
++SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="05e3", ENV{ID_MODEL_ID}=="0727", ENV{ID_DRIVE_FLASH_SD}="1"
++
+ # ------------------------------------------------------------------------
+ # ------------------------------------------------------------------------
+ # ------------------------------------------------------------------------
+diff --git a/doc/man/udisksctl.xml b/doc/man/udisksctl.xml
+index 8f38479..434a8fb 100644
+--- a/doc/man/udisksctl.xml
++++ b/doc/man/udisksctl.xml
+@@ -104,6 +104,16 @@
+ 
+     <cmdsynopsis>
+       <command>udisksctl</command>
++      <arg choice="plain">power-off </arg>
++      <group choice="req">
++        <arg choice="plain">--object-path <replaceable>OBJECT</replaceable></arg>
++        <arg choice="plain">--block-device <replaceable>DEVICE</replaceable></arg>
++      </group>
++      <arg choice="opt">--no-user-interaction</arg>
++    </cmdsynopsis>
++
++    <cmdsynopsis>
++      <command>udisksctl</command>
+       <arg choice="plain">smart-simulate </arg>
+       <arg choice="plain">--file <replaceable>PATH</replaceable></arg>
+       <group choice="req">
+@@ -238,6 +248,31 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term><option>power-off</option></term>
++        <listitem>
++          <para>
++            Arranges for the drive to be safely removed and powered
++            off. On the OS side this includes ensuring that no process
++            is using the drive, then requesting that in-flight buffers
++            and caches are committed to stable storage. The exact
++            steps for powering off the drive depends on the drive
++            itself and the interconnect used. For drives connected
++            through USB, the effect is that the USB device will be
++            deconfigured followed by disabling the upstream hub port
++            it is connected to.
++          </para>
++          <para>
++            Note that as some physical devices contain multiple drives
++            (for example 4-in-1 flash card reader USB devices)
++            powering off one drive may affect other drives. As such
++            there are not a lot of guarantees associated with
++            performing this action. Usually the effect is that the
++            drive disappears as if it was unplugged.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term><option>smart-simulate</option></term>
+         <listitem>
+           <para>
+diff --git a/src/udisksdaemonutil.c b/src/udisksdaemonutil.c
+index 574bf2c..a588580 100644
+--- a/src/udisksdaemonutil.c
++++ b/src/udisksdaemonutil.c
+@@ -830,7 +830,7 @@ udisks_daemon_util_get_caller_uid_sync (UDisksDaemon            *daemon,
+     {
+       struct passwd pwstruct;
+       gchar pwbuf[8192];
+-      static struct passwd *pw;
++      struct passwd *pw = NULL;
+       int rc;
+ 
+       rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
+@@ -840,6 +840,7 @@ udisks_daemon_util_get_caller_uid_sync (UDisksDaemon            *daemon,
+                        UDISKS_ERROR,
+                        UDISKS_ERROR_FAILED,
+                        "User with uid %d does not exist", (gint) uid);
++          goto out;
+         }
+       else if (pw == NULL)
+         {
+diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c
+index d619850..22bcfd0 100644
+--- a/src/udiskslinuxblock.c
++++ b/src/udiskslinuxblock.c
+@@ -804,12 +804,23 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
+       gchar *dm_name_dev_file = NULL;
+       const gchar *dm_name_dev_file_as_symlink = NULL;
+ 
++      const gchar *dm_vg_name;
++      const gchar *dm_lv_name;
++      gchar *dm_lvm_dev_file = NULL;
++
+       dm_name = g_udev_device_get_property (device->udev_device, "DM_NAME");
+       if (dm_name != NULL)
+         dm_name_dev_file = g_strdup_printf ("/dev/mapper/%s", dm_name);
++
++      dm_vg_name = g_udev_device_get_property (device->udev_device, "DM_VG_NAME");
++      dm_lv_name = g_udev_device_get_property (device->udev_device, "DM_LV_NAME");
++      if (dm_vg_name != NULL && dm_lv_name != NULL)
++        dm_lvm_dev_file =  g_strdup_printf ("/dev/%s/%s", dm_vg_name, dm_lv_name);
++
+       for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
+         {
+-          if (g_str_has_prefix (symlinks[n], "/dev/vg_"))
++          if (g_str_has_prefix (symlinks[n], "/dev/vg_")
++              || g_strcmp0 (symlinks[n], dm_lvm_dev_file) == 0)
+             {
+               /* LVM2 */
+               preferred_device_file = symlinks[n];
+@@ -824,6 +835,7 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
+       if (preferred_device_file == NULL && dm_name_dev_file_as_symlink != NULL)
+         preferred_device_file = dm_name_dev_file_as_symlink;
+       g_free (dm_name_dev_file);
++      g_free (dm_lvm_dev_file);
+     }
+   else if (g_str_has_prefix (device_file, "/dev/md"))
+     {
+diff --git a/src/udiskslinuxdevice.c b/src/udiskslinuxdevice.c
+index 0b65a69..8c4a3ed 100644
+--- a/src/udiskslinuxdevice.c
++++ b/src/udiskslinuxdevice.c
+@@ -199,6 +199,7 @@ probe_ata (UDisksLinuxDevice  *device,
+     {
+       /* ATA8: 7.16 IDENTIFY DEVICE - ECh, PIO Data-In */
+       input.command = 0xec;
++      input.count = 1;
+       output.buffer = g_new0 (guchar, 512);
+       output.buffer_size = 512;
+       if (!udisks_ata_send_command_sync (fd,
+@@ -221,6 +222,7 @@ probe_ata (UDisksLinuxDevice  *device,
+     {
+       /* ATA8: 7.17 IDENTIFY PACKET DEVICE - A1h, PIO Data-In */
+       input.command = 0xa1;
++      input.count = 1;
+       output.buffer = g_new0 (guchar, 512);
+       output.buffer_size = 512;
+       if (!udisks_ata_send_command_sync (fd,
+diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c
+index 170ba27..ed541ff 100644
+--- a/src/udiskslinuxdrive.c
++++ b/src/udiskslinuxdrive.c
+@@ -25,6 +25,12 @@
+ #include <sys/stat.h>
+ #include <sys/ioctl.h>
+ #include <fcntl.h>
++#include <inttypes.h>
++#include <errno.h>
++#include <linux/bsg.h>
++#include <scsi/scsi.h>
++#include <scsi/sg.h>
++#include <scsi/scsi_ioctl.h>
+ 
+ #include <pwd.h>
+ #include <grp.h>
+@@ -1192,6 +1198,122 @@ handle_set_configuration (UDisksDrive           *_drive,
+ 
+ /* ---------------------------------------------------------------------------------------------------- */
+ 
++/* TODO: move to udisksscsi.[ch] similar what we do for ATA with udisksata.[ch] */
++
++static gboolean
++send_scsi_command_sync (gint      fd,
++                        guint8   *cdb,
++                        gsize     cdb_len,
++                        GError  **error)
++{
++  struct sg_io_v4 io_v4;
++  uint8_t sense[32];
++  gboolean ret = FALSE;
++  gint rc;
++  gint timeout_msec = 30000; /* 30 seconds */
++
++  g_return_val_if_fail (fd != -1, FALSE);
++  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
++
++  /* See http://sg.danny.cz/sg/sg_io.html and http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/index.html
++   * for detailed information about how the SG_IO ioctl work
++   */
++
++  memset (sense, 0, sizeof (sense));
++  memset (&io_v4, 0, sizeof (io_v4));
++  io_v4.guard = 'Q';
++  io_v4.protocol = BSG_PROTOCOL_SCSI;
++  io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
++  io_v4.request_len = cdb_len;
++  io_v4.request = (uintptr_t) cdb;
++  io_v4.max_response_len = sizeof (sense);
++  io_v4.response = (uintptr_t) sense;
++  io_v4.timeout = timeout_msec;
++
++  rc = ioctl (fd, SG_IO, &io_v4);
++  if (rc != 0)
++    {
++      /* could be that the driver doesn't do version 4, try version 3 */
++      if (errno == EINVAL)
++        {
++          struct sg_io_hdr io_hdr;
++          memset (&io_hdr, 0, sizeof (struct sg_io_hdr));
++          io_hdr.interface_id = 'S';
++          io_hdr.cmdp = (unsigned char*) cdb;
++          io_hdr.cmd_len = cdb_len;
++          io_hdr.dxfer_direction = SG_DXFER_NONE;
++          io_hdr.sbp = sense;
++          io_hdr.mx_sb_len = sizeof (sense);
++          io_hdr.timeout = timeout_msec;
++
++          rc = ioctl (fd, SG_IO, &io_hdr);
++          if (rc != 0)
++            {
++              g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
++                           "SGIO v3 ioctl failed (v4 not supported): %m");
++              goto out;
++            }
++          else
++            {
++              if (!(io_hdr.status == 0 &&
++                    io_hdr.host_status == 0 &&
++                    io_hdr.driver_status == 0))
++                {
++                  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++                               "Non-GOOD SCSI status from SGIO v3 ioctl: "
++                               "status=%d host_status=%d driver_status=%d",
++                               io_hdr.status,
++                               io_hdr.host_status,
++                               io_hdr.driver_status);
++                  goto out;
++                }
++            }
++        }
++      else
++        {
++          g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
++                       "SGIO v4 ioctl failed: %m");
++          goto out;
++        }
++    }
++  else
++    {
++      if (!(io_v4.device_status == 0 &&
++            io_v4.transport_status == 0 &&
++            io_v4.driver_status == 0))
++        {
++          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++                       "Non-GOOD SCSI status from SGIO v4 ioctl: "
++                       "device_status=%d transport_status=%d driver_status=%d",
++                       io_v4.device_status,
++                       io_v4.transport_status,
++                       io_v4.driver_status);
++          goto out;
++        }
++    }
++
++  ret = TRUE;
++
++ out:
++  return ret;
++}
++
++static gboolean
++send_scsi_start_stop_command_sync (gint      fd,
++                                   GError  **error)
++{
++  uint8_t cdb[6];
++
++  /* SBC3 (SCSI Block Commands), 5.20 START STOP UNIT command
++   */
++  memset (cdb, 0, sizeof cdb);
++  cdb[0] = 0x1b;                        /* OPERATION CODE: START STOP UNIT */
++
++  return send_scsi_command_sync (fd, cdb, sizeof cdb, error);
++}
++
++/* ---------------------------------------------------------------------------------------------------- */
++
+ static gboolean
+ handle_power_off (UDisksDrive           *_drive,
+                   GDBusMethodInvocation *invocation,
+@@ -1216,6 +1338,7 @@ handle_power_off (UDisksDrive           *_drive,
+   gid_t caller_gid;
+   pid_t caller_pid;
+   GList *sibling_objects = NULL, *l;
++  gint fd = -1;
+ 
+   object = udisks_daemon_util_dup_object (drive, &error);
+   if (object == NULL)
+@@ -1324,10 +1447,10 @@ handle_power_off (UDisksDrive           *_drive,
+     {
+       UDisksBlock *block_to_sync = UDISKS_BLOCK (l->data);
+       const gchar *device_file;
+-      gint fd;
++      gint device_fd;
+       device_file = udisks_block_get_device (block_to_sync);
+-      fd = open (device_file, O_RDONLY|O_NONBLOCK|O_EXCL);
+-      if (fd == -1)
++      device_fd = open (device_file, O_RDONLY|O_NONBLOCK|O_EXCL);
++      if (device_fd == -1)
+         {
+           g_dbus_method_invocation_return_error (invocation,
+                                                  UDISKS_ERROR,
+@@ -1336,7 +1459,7 @@ handle_power_off (UDisksDrive           *_drive,
+                                                  device_file);
+           goto out;
+         }
+-      if (fsync (fd) != 0)
++      if (fsync (device_fd) != 0)
+         {
+           g_dbus_method_invocation_return_error (invocation,
+                                                  UDISKS_ERROR,
+@@ -1345,7 +1468,7 @@ handle_power_off (UDisksDrive           *_drive,
+                                                  device_file);
+           goto out;
+         }
+-      if (close (fd) != 0)
++      if (close (device_fd) != 0)
+         {
+           g_dbus_method_invocation_return_error (invocation,
+                                                  UDISKS_ERROR,
+@@ -1356,9 +1479,45 @@ handle_power_off (UDisksDrive           *_drive,
+         }
+     }
+ 
+-  escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
++  /* Send the "SCSI START STOP UNIT" command to request that the unit
++   * be stopped but don't treat failure as fatal. In fact some
++   * USB-attached hard-disks fails with this command, probably due to
++   * the SCSI/SATA translation layer.
++   */
++  fd = open (udisks_block_get_device (block), O_RDONLY|O_NONBLOCK|O_EXCL);
++  if (fd == -1)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             UDISKS_ERROR,
++                                             UDISKS_ERROR_FAILED,
++                                             "Error opening %s: %m",
++                                             udisks_block_get_device (block));
++      goto out;
++    }
++  if (!send_scsi_start_stop_command_sync (fd, &error))
++    {
++      udisks_warning ("Ignoring SCSI command START STOP UNIT failure (%s) on %s",
++                      error->message,
++                      udisks_block_get_device (block));
++      g_clear_error (&error);
++    }
++  else
++    {
++      udisks_notice ("Powering off %s - successfully sent SCSI command START STOP UNIT",
++                     udisks_block_get_device (block));
++    }
++  if (close (fd) != 0)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             UDISKS_ERROR,
++                                             UDISKS_ERROR_FAILED,
++                                             "Error closing %s: %m",
++                                             udisks_block_get_device (block));
++      goto out;
++    }
++  fd = -1;
+ 
+-  /* TODO: Send the eject? Send SCSI START STOP UNIT? */
++  escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
+   device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
+   if (device == NULL)
+     {
+@@ -1405,10 +1564,20 @@ handle_power_off (UDisksDrive           *_drive,
+         }
+     }
+   fclose (f);
++  udisks_notice ("Powered off %s - successfully wrote to sysfs path %s",
++                 udisks_block_get_device (block),
++                 remove_path);
+ 
+   udisks_drive_complete_power_off (UDISKS_DRIVE (drive), invocation);
+ 
+  out:
++  if (fd != -1)
++    {
++      if (close (fd) != 0)
++        {
++          udisks_warning ("Error closing device: %m");
++        }
++    }
+   g_list_free_full (blocks_to_sync, g_object_unref);
+   g_list_free_full (sibling_objects, g_object_unref);
+   g_free (remove_path);
+diff --git a/src/udiskslinuxdriveata.c b/src/udiskslinuxdriveata.c
+index 48cc6e6..534ef4d 100644
+--- a/src/udiskslinuxdriveata.c
++++ b/src/udiskslinuxdriveata.c
+@@ -1943,7 +1943,7 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta     *drive,
+   /* First get the IDENTIFY data directly from the drive, for sanity checks */
+   {
+     /* ATA8: 7.16 IDENTIFY DEVICE - ECh, PIO Data-In */
+-    UDisksAtaCommandInput input = {.command = 0xec};
++    UDisksAtaCommandInput input = {.command = 0xec, .count = 1};
+     UDisksAtaCommandOutput output = {.buffer = identify.buf, .buffer_size = sizeof (identify.buf)};
+     if (!udisks_ata_send_command_sync (fd,
+                                        -1,
+diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c
+index 4c8d8aa..f243046 100644
+--- a/src/udiskslinuxfilesystem.c
++++ b/src/udiskslinuxfilesystem.c
+@@ -348,13 +348,16 @@ find_mount_options_for_fs (const gchar *fstype)
+ static gid_t
+ find_primary_gid (uid_t uid)
+ {
+-  struct passwd *pw;
++  struct passwd *pw = NULL;
++  struct passwd pwstruct;
++  gchar pwbuf[8192];
++  int rc;
+   gid_t gid;
+ 
+   gid = (gid_t) - 1;
+ 
+-  pw = getpwuid (uid);
+-  if (pw == NULL)
++  rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
++  if (rc != 0 || pw == NULL)
+     {
+       udisks_warning ("Error looking up uid %d: %m", uid);
+       goto out;
+@@ -370,7 +373,10 @@ is_uid_in_gid (uid_t uid,
+                gid_t gid)
+ {
+   gboolean ret;
+-  struct passwd *pw;
++  struct passwd *pw = NULL;
++  struct passwd pwstruct;
++  gchar pwbuf[8192];
++  int rc;
+   static gid_t supplementary_groups[128];
+   int num_supplementary_groups = 128;
+   int n;
+@@ -379,8 +385,8 @@ is_uid_in_gid (uid_t uid,
+ 
+   ret = FALSE;
+ 
+-  pw = getpwuid (uid);
+-  if (pw == NULL)
++  rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
++  if (rc != 0 || pw == NULL)
+     {
+       udisks_warning ("Error looking up uid %d: %m", uid);
+       goto out;
+diff --git a/src/udisksspawnedjob.c b/src/udisksspawnedjob.c
+index 802551f..b181933 100644
+--- a/src/udisksspawnedjob.c
++++ b/src/udisksspawnedjob.c
+@@ -371,22 +371,25 @@ static void
+ child_setup (gpointer user_data)
+ {
+   UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data);
+-  struct passwd *pw;
++  struct passwd pwstruct;
++  gchar pwbuf[8192];
++  struct passwd *pw = NULL;
++  int rc;
+   gid_t egid;
+ 
+   if (job->run_as_uid == getuid () && job->run_as_euid == geteuid ())
+     goto out;
+ 
+-  pw = getpwuid (job->run_as_euid);
+-  if (pw == NULL)
++  rc = getpwuid_r (job->run_as_euid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
++  if (rc != 0 || pw == NULL)
+    {
+      g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_euid);
+      abort ();
+    }
+   egid = pw->pw_gid;
+ 
+-  pw = getpwuid (job->run_as_uid);
+-  if (pw == NULL)
++  rc = getpwuid_r (job->run_as_uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
++  if (rc != 0 || pw == NULL)
+    {
+      g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_uid);
+      abort ();
+diff --git a/tools/udisksctl.c b/tools/udisksctl.c
+index 97b0f17..c87fe9f 100644
+--- a/tools/udisksctl.c
++++ b/tools/udisksctl.c
+@@ -1691,6 +1691,12 @@ handle_command_loop (gint        *argc,
+           goto out;
+         }
+ 
++      if (udisks_object_peek_loop (object) == NULL)
++        {
++          g_printerr ("Error: specified object is not a loop device\n");
++          goto out;
++        }
++
+     delete_try_again:
+       error = NULL;
+       if (!udisks_loop_call_delete_sync (udisks_object_peek_loop (object),
+@@ -2009,6 +2015,238 @@ handle_command_smart_simulate (gint        *argc,
+ 
+ /* ---------------------------------------------------------------------------------------------------- */
+ 
++static gchar   *opt_power_off_object_path = NULL;
++static gchar   *opt_power_off_device = NULL;
++static gboolean opt_power_off_no_user_interaction = FALSE;
++
++static const GOptionEntry command_power_off_entries[] =
++{
++  {
++    "object-path",
++    'p',
++    0,
++    G_OPTION_ARG_STRING,
++    &opt_power_off_object_path,
++    "Object path for ATA device",
++    NULL
++  },
++  {
++    "block-device",
++    'b',
++    0,
++    G_OPTION_ARG_STRING,
++    &opt_power_off_device,
++    "Device file for ATA device",
++    NULL
++  },
++  {
++    "no-user-interaction",
++    0, /* no short option */
++    0,
++    G_OPTION_ARG_NONE,
++    &opt_power_off_no_user_interaction,
++    "Do not authenticate the user if needed",
++    NULL
++  },
++  {
++    NULL
++  }
++};
++
++static gint
++handle_command_power_off (gint        *argc,
++                          gchar      **argv[],
++                          gboolean     request_completion,
++                          const gchar *completion_cur,
++                          const gchar *completion_prev)
++{
++  gint ret;
++  GOptionContext *o;
++  gchar *s;
++  gboolean complete_objects;
++  gboolean complete_devices;
++  GList *l;
++  GList *objects;
++  UDisksObject *object;
++  UDisksDriveAta *ata;
++  guint n;
++  GVariant *options;
++  GVariantBuilder builder;
++  GError *error;
++
++  ret = 1;
++  opt_power_off_object_path = NULL;
++  opt_power_off_device = NULL;
++  object = NULL;
++  options = NULL;
++
++  modify_argv0_for_command (argc, argv, "power-off");
++
++  o = g_option_context_new (NULL);
++  if (request_completion)
++    g_option_context_set_ignore_unknown_options (o, TRUE);
++  g_option_context_set_help_enabled (o, FALSE);
++  g_option_context_set_summary (o, "Safely power off a drive.");
++  g_option_context_add_main_entries (o,
++                                     command_power_off_entries,
++                                     NULL /* GETTEXT_PACKAGE*/);
++
++  complete_objects = FALSE;
++  if (request_completion && (g_strcmp0 (completion_prev, "--object-path") == 0 || g_strcmp0 (completion_prev, "-p") == 0))
++    {
++      complete_objects = TRUE;
++      remove_arg ((*argc) - 1, argc, argv);
++    }
++
++  complete_devices = FALSE;
++  if (request_completion && (g_strcmp0 (completion_prev, "--block-device") == 0 || g_strcmp0 (completion_prev, "-b") == 0))
++    {
++      complete_devices = TRUE;
++      remove_arg ((*argc) - 1, argc, argv);
++    }
++
++  if (!g_option_context_parse (o, argc, argv, NULL))
++    {
++      if (!request_completion)
++        {
++          s = g_option_context_get_help (o, FALSE, NULL);
++          g_printerr ("%s", s);
++          g_free (s);
++          goto out;
++        }
++    }
++
++  if (request_completion)
++    {
++      if ((opt_power_off_object_path == NULL && !complete_objects) &&
++          (opt_power_off_device == NULL && !complete_devices))
++        {
++          g_print ("--object-path \n"
++                   "--block-device \n");
++        }
++
++      if (complete_objects)
++        {
++          const gchar *object_path;
++          objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (client));
++          for (l = objects; l != NULL; l = l->next)
++            {
++              object = UDISKS_OBJECT (l->data);
++              ata = udisks_object_peek_drive_ata (object);
++              if (ata != NULL)
++                {
++                  object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
++                  g_assert (g_str_has_prefix (object_path, "/org/freedesktop/UDisks2/"));
++                  g_print ("%s \n", object_path + sizeof ("/org/freedesktop/UDisks2/") - 1);
++                }
++            }
++          g_list_foreach (objects, (GFunc) g_object_unref, NULL);
++          g_list_free (objects);
++        }
++
++      if (complete_devices)
++        {
++          objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (client));
++          for (l = objects; l != NULL; l = l->next)
++            {
++              object = UDISKS_OBJECT (l->data);
++              ata = udisks_object_peek_drive_ata (object);
++              if (ata != NULL)
++                {
++                  const gchar * const *symlinks;
++                  UDisksBlock *block;
++                  block = udisks_client_get_block_for_drive (client, udisks_object_peek_drive (object), TRUE);
++                  g_print ("%s \n", udisks_block_get_device (block));
++                  symlinks = udisks_block_get_symlinks (block);
++                  for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
++                    g_print ("%s \n", symlinks[n]);
++                }
++            }
++          g_list_foreach (objects, (GFunc) g_object_unref, NULL);
++          g_list_free (objects);
++        }
++      goto out;
++    }
++
++  g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
++  if (opt_power_off_no_user_interaction)
++    {
++      g_variant_builder_add (&builder,
++                             "{sv}",
++                             "auth.no_user_interaction", g_variant_new_boolean (TRUE));
++    }
++  options = g_variant_builder_end (&builder);
++  g_variant_ref_sink (options);
++
++  if (opt_power_off_object_path != NULL)
++    {
++      object = lookup_object_by_path (opt_power_off_object_path);
++      if (object == NULL)
++        {
++          g_printerr ("Error looking up object with path %s\n", opt_power_off_object_path);
++          goto out;
++        }
++    }
++  else if (opt_power_off_device != NULL)
++    {
++      UDisksObject *block_object;
++      UDisksDrive *drive;
++      block_object = lookup_object_by_device (opt_power_off_device);
++      if (block_object == NULL)
++        {
++          g_printerr ("Error looking up object for device %s\n", opt_power_off_device);
++          goto out;
++        }
++      drive = udisks_client_get_drive_for_block (client, udisks_object_peek_block (block_object));
++      object = (UDisksObject *) g_dbus_interface_dup_object (G_DBUS_INTERFACE (drive));
++      g_object_unref (block_object);
++    }
++  else
++    {
++      s = g_option_context_get_help (o, FALSE, NULL);
++      g_printerr ("%s", s);
++      g_free (s);
++      goto out;
++    }
++
++ try_again:
++  error = NULL;
++  if (!udisks_drive_call_power_off_sync (udisks_object_peek_drive (object),
++                                         options,
++                                         NULL,                       /* GCancellable */
++                                         &error))
++    {
++      if (error->domain == UDISKS_ERROR &&
++          error->code == UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN &&
++          setup_local_polkit_agent ())
++        {
++          g_error_free (error);
++          goto try_again;
++        }
++      g_dbus_error_strip_remote_error (error);
++      g_printerr ("Error powering off drive: %s (%s, %d)\n",
++                  error->message, g_quark_to_string (error->domain), error->code);
++      g_clear_error (&error);
++      g_object_unref (object);
++      goto out;
++    }
++
++  g_object_unref (object);
++
++
++  ret = 0;
++
++ out:
++  if (options != NULL)
++    g_variant_unref (options);
++  g_option_context_free (o);
++  g_free (opt_power_off_object_path);
++  g_free (opt_power_off_device);
++  return ret;
++}
++
++/* ---------------------------------------------------------------------------------------------------- */
++
+ static gchar *opt_info_object = NULL;
+ static gchar *opt_info_device = NULL;
+ static gchar *opt_info_drive = NULL;
+@@ -2855,6 +3093,7 @@ usage (gint *argc, gchar **argv[], gboolean use_stdout)
+                        "  lock            Lock an encrypted device\n"
+                        "  loop-setup      Set-up a loop device\n"
+                        "  loop-delete     Delete a loop device\n"
++                       "  power-off       Safely power off a drive\n"
+                        "  smart-simulate  Set SMART data for a drive\n"
+                        "\n"
+                        "Use \"%s COMMAND --help\" to get help on each command.\n",
+@@ -3053,6 +3292,15 @@ main (int argc,
+                                            completion_prev);
+       goto out;
+     }
++  else if (g_strcmp0 (command, "power-off") == 0)
++    {
++      ret = handle_command_power_off (&argc,
++                                      &argv,
++                                      request_completion,
++                                      completion_cur,
++                                      completion_prev);
++      goto out;
++    }
+   else if (g_strcmp0 (command, "dump") == 0)
+     {
+       ret = handle_command_dump (&argc,
+@@ -3156,6 +3404,7 @@ main (int argc,
+                    "unlock \n"
+                    "loop-setup \n"
+                    "loop-delete \n"
++                   "power-off \n"
+                    "smart-simulate \n"
+                    );
+           ret = 0;

Deleted: extra-x86_64/PKGBUILD
===================================================================
--- extra-x86_64/PKGBUILD	2016-12-12 10:22:55 UTC (rev 283051)
+++ extra-x86_64/PKGBUILD	2016-12-12 10:23:19 UTC (rev 283052)
@@ -1,41 +0,0 @@
-# $Id$
-# Maintainer: Felix Yan <felixonmars at archlinux.org>
-# Contributor: Ionut Biru <ibiru at archlinux.org>
-
-pkgname=udisks2
-pkgver=2.1.7
-pkgrel=1
-pkgdesc="Disk Management Service, version 2"
-arch=('i686' 'x86_64')
-url="http://www.freedesktop.org/wiki/Software/udisks"
-license=('GPL2')
-depends=('glib2' 'systemd' 'polkit' 'libatasmart' 'util-linux' 'libgudev')
-makedepends=('intltool' 'docbook-xsl' 'gobject-introspection' 'python2')
-optdepends=('parted: partition management'
-            'gptfdisk: GUID partition table support'
-            'ntfs-3g: NTFS filesystem management support'
-            'dosfstools: VFAT filesystem management support')
-source=(http://udisks.freedesktop.org/releases/udisks-$pkgver.tar.bz2{,.sign})
-sha256sums=('abae2bb3bdc691ca13c1e4c244630b8c881c4f3b35c207299f1b39b7bec83785'
-            'SKIP')
-validpgpkeys=('3DB46B55EFA59D40E6232148D14EF15DAFE11347')  # Martin Pitt
-
-build() {
-  cd udisks-$pkgver
-  ./configure --prefix=/usr --sysconfdir=/etc \
-      --sbindir=/usr/bin --libexecdir=/usr/lib \
-      --with-systemdsystemunitdir=/usr/lib/systemd/system \
-      --localstatedir=/var --disable-static
-  make
-}
-
-check() {
-  cd udisks-$pkgver
-  make check
-}
-
-package() {
-  cd udisks-$pkgver
-  make DESTDIR="$pkgdir" install \
-    bash_completiondir=/usr/share/bash-completion/completions
-}

Copied: udisks2/repos/extra-x86_64/PKGBUILD (from rev 283051, udisks2/trunk/PKGBUILD)
===================================================================
--- extra-x86_64/PKGBUILD	                        (rev 0)
+++ extra-x86_64/PKGBUILD	2016-12-12 10:23:19 UTC (rev 283052)
@@ -0,0 +1,41 @@
+# $Id$
+# Maintainer: Felix Yan <felixonmars at archlinux.org>
+# Contributor: Ionut Biru <ibiru at archlinux.org>
+
+pkgname=udisks2
+pkgver=2.1.8
+pkgrel=1
+pkgdesc="Disk Management Service, version 2"
+arch=('i686' 'x86_64')
+url="http://www.freedesktop.org/wiki/Software/udisks"
+license=('GPL2')
+depends=('glib2' 'systemd' 'polkit' 'libatasmart' 'util-linux' 'libgudev')
+makedepends=('intltool' 'docbook-xsl' 'gobject-introspection' 'python2')
+optdepends=('parted: partition management'
+            'gptfdisk: GUID partition table support'
+            'ntfs-3g: NTFS filesystem management support'
+            'dosfstools: VFAT filesystem management support')
+source=(http://udisks.freedesktop.org/releases/udisks-$pkgver.tar.bz2{,.sign})
+sha256sums=('da416914812a77e5f4d82b81deb8c25799fd3228d27d52f7bf89a501b1857dda'
+            'SKIP')
+validpgpkeys=('3DB46B55EFA59D40E6232148D14EF15DAFE11347')  # Martin Pitt
+
+build() {
+  cd udisks-$pkgver
+  ./configure --prefix=/usr --sysconfdir=/etc \
+      --sbindir=/usr/bin --libexecdir=/usr/lib \
+      --with-systemdsystemunitdir=/usr/lib/systemd/system \
+      --localstatedir=/var --disable-static
+  make
+}
+
+check() {
+  cd udisks-$pkgver
+  make check
+}
+
+package() {
+  cd udisks-$pkgver
+  make DESTDIR="$pkgdir" install \
+    bash_completiondir=/usr/share/bash-completion/completions
+}

Deleted: extra-x86_64/git-fixes.patch
===================================================================
--- extra-x86_64/git-fixes.patch	2016-12-12 10:22:55 UTC (rev 283051)
+++ extra-x86_64/git-fixes.patch	2016-12-12 10:23:19 UTC (rev 283052)
@@ -1,777 +0,0 @@
-diff --git a/data/80-udisks2.rules b/data/80-udisks2.rules
-index ed093ee..7112db8 100644
---- a/data/80-udisks2.rules
-+++ b/data/80-udisks2.rules
-@@ -94,6 +94,9 @@ SUBSYSTEMS=="usb", ENV{ID_VENDOR}=="*SanDisk*", ENV{ID_MODEL}=="*Cruzer*", ENV{I
- SUBSYSTEMS=="usb", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="*v125w*", ENV{ID_DRIVE_THUMB}="1"
- SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="13fe", ENV{ID_MODEL}=="*Patriot*", ENV{ID_DRIVE_THUMB}="1"
- 
-+# SD-Card reader in Chromebook Pixel
-+SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="05e3", ENV{ID_MODEL_ID}=="0727", ENV{ID_DRIVE_FLASH_SD}="1"
-+
- # ------------------------------------------------------------------------
- # ------------------------------------------------------------------------
- # ------------------------------------------------------------------------
-diff --git a/doc/man/udisksctl.xml b/doc/man/udisksctl.xml
-index 8f38479..434a8fb 100644
---- a/doc/man/udisksctl.xml
-+++ b/doc/man/udisksctl.xml
-@@ -104,6 +104,16 @@
- 
-     <cmdsynopsis>
-       <command>udisksctl</command>
-+      <arg choice="plain">power-off </arg>
-+      <group choice="req">
-+        <arg choice="plain">--object-path <replaceable>OBJECT</replaceable></arg>
-+        <arg choice="plain">--block-device <replaceable>DEVICE</replaceable></arg>
-+      </group>
-+      <arg choice="opt">--no-user-interaction</arg>
-+    </cmdsynopsis>
-+
-+    <cmdsynopsis>
-+      <command>udisksctl</command>
-       <arg choice="plain">smart-simulate </arg>
-       <arg choice="plain">--file <replaceable>PATH</replaceable></arg>
-       <group choice="req">
-@@ -238,6 +248,31 @@
-       </varlistentry>
- 
-       <varlistentry>
-+        <term><option>power-off</option></term>
-+        <listitem>
-+          <para>
-+            Arranges for the drive to be safely removed and powered
-+            off. On the OS side this includes ensuring that no process
-+            is using the drive, then requesting that in-flight buffers
-+            and caches are committed to stable storage. The exact
-+            steps for powering off the drive depends on the drive
-+            itself and the interconnect used. For drives connected
-+            through USB, the effect is that the USB device will be
-+            deconfigured followed by disabling the upstream hub port
-+            it is connected to.
-+          </para>
-+          <para>
-+            Note that as some physical devices contain multiple drives
-+            (for example 4-in-1 flash card reader USB devices)
-+            powering off one drive may affect other drives. As such
-+            there are not a lot of guarantees associated with
-+            performing this action. Usually the effect is that the
-+            drive disappears as if it was unplugged.
-+          </para>
-+        </listitem>
-+      </varlistentry>
-+
-+      <varlistentry>
-         <term><option>smart-simulate</option></term>
-         <listitem>
-           <para>
-diff --git a/src/udisksdaemonutil.c b/src/udisksdaemonutil.c
-index 574bf2c..a588580 100644
---- a/src/udisksdaemonutil.c
-+++ b/src/udisksdaemonutil.c
-@@ -830,7 +830,7 @@ udisks_daemon_util_get_caller_uid_sync (UDisksDaemon            *daemon,
-     {
-       struct passwd pwstruct;
-       gchar pwbuf[8192];
--      static struct passwd *pw;
-+      struct passwd *pw = NULL;
-       int rc;
- 
-       rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-@@ -840,6 +840,7 @@ udisks_daemon_util_get_caller_uid_sync (UDisksDaemon            *daemon,
-                        UDISKS_ERROR,
-                        UDISKS_ERROR_FAILED,
-                        "User with uid %d does not exist", (gint) uid);
-+          goto out;
-         }
-       else if (pw == NULL)
-         {
-diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c
-index d619850..22bcfd0 100644
---- a/src/udiskslinuxblock.c
-+++ b/src/udiskslinuxblock.c
-@@ -804,12 +804,23 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
-       gchar *dm_name_dev_file = NULL;
-       const gchar *dm_name_dev_file_as_symlink = NULL;
- 
-+      const gchar *dm_vg_name;
-+      const gchar *dm_lv_name;
-+      gchar *dm_lvm_dev_file = NULL;
-+
-       dm_name = g_udev_device_get_property (device->udev_device, "DM_NAME");
-       if (dm_name != NULL)
-         dm_name_dev_file = g_strdup_printf ("/dev/mapper/%s", dm_name);
-+
-+      dm_vg_name = g_udev_device_get_property (device->udev_device, "DM_VG_NAME");
-+      dm_lv_name = g_udev_device_get_property (device->udev_device, "DM_LV_NAME");
-+      if (dm_vg_name != NULL && dm_lv_name != NULL)
-+        dm_lvm_dev_file =  g_strdup_printf ("/dev/%s/%s", dm_vg_name, dm_lv_name);
-+
-       for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
-         {
--          if (g_str_has_prefix (symlinks[n], "/dev/vg_"))
-+          if (g_str_has_prefix (symlinks[n], "/dev/vg_")
-+              || g_strcmp0 (symlinks[n], dm_lvm_dev_file) == 0)
-             {
-               /* LVM2 */
-               preferred_device_file = symlinks[n];
-@@ -824,6 +835,7 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
-       if (preferred_device_file == NULL && dm_name_dev_file_as_symlink != NULL)
-         preferred_device_file = dm_name_dev_file_as_symlink;
-       g_free (dm_name_dev_file);
-+      g_free (dm_lvm_dev_file);
-     }
-   else if (g_str_has_prefix (device_file, "/dev/md"))
-     {
-diff --git a/src/udiskslinuxdevice.c b/src/udiskslinuxdevice.c
-index 0b65a69..8c4a3ed 100644
---- a/src/udiskslinuxdevice.c
-+++ b/src/udiskslinuxdevice.c
-@@ -199,6 +199,7 @@ probe_ata (UDisksLinuxDevice  *device,
-     {
-       /* ATA8: 7.16 IDENTIFY DEVICE - ECh, PIO Data-In */
-       input.command = 0xec;
-+      input.count = 1;
-       output.buffer = g_new0 (guchar, 512);
-       output.buffer_size = 512;
-       if (!udisks_ata_send_command_sync (fd,
-@@ -221,6 +222,7 @@ probe_ata (UDisksLinuxDevice  *device,
-     {
-       /* ATA8: 7.17 IDENTIFY PACKET DEVICE - A1h, PIO Data-In */
-       input.command = 0xa1;
-+      input.count = 1;
-       output.buffer = g_new0 (guchar, 512);
-       output.buffer_size = 512;
-       if (!udisks_ata_send_command_sync (fd,
-diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c
-index 170ba27..ed541ff 100644
---- a/src/udiskslinuxdrive.c
-+++ b/src/udiskslinuxdrive.c
-@@ -25,6 +25,12 @@
- #include <sys/stat.h>
- #include <sys/ioctl.h>
- #include <fcntl.h>
-+#include <inttypes.h>
-+#include <errno.h>
-+#include <linux/bsg.h>
-+#include <scsi/scsi.h>
-+#include <scsi/sg.h>
-+#include <scsi/scsi_ioctl.h>
- 
- #include <pwd.h>
- #include <grp.h>
-@@ -1192,6 +1198,122 @@ handle_set_configuration (UDisksDrive           *_drive,
- 
- /* ---------------------------------------------------------------------------------------------------- */
- 
-+/* TODO: move to udisksscsi.[ch] similar what we do for ATA with udisksata.[ch] */
-+
-+static gboolean
-+send_scsi_command_sync (gint      fd,
-+                        guint8   *cdb,
-+                        gsize     cdb_len,
-+                        GError  **error)
-+{
-+  struct sg_io_v4 io_v4;
-+  uint8_t sense[32];
-+  gboolean ret = FALSE;
-+  gint rc;
-+  gint timeout_msec = 30000; /* 30 seconds */
-+
-+  g_return_val_if_fail (fd != -1, FALSE);
-+  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
-+
-+  /* See http://sg.danny.cz/sg/sg_io.html and http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/index.html
-+   * for detailed information about how the SG_IO ioctl work
-+   */
-+
-+  memset (sense, 0, sizeof (sense));
-+  memset (&io_v4, 0, sizeof (io_v4));
-+  io_v4.guard = 'Q';
-+  io_v4.protocol = BSG_PROTOCOL_SCSI;
-+  io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
-+  io_v4.request_len = cdb_len;
-+  io_v4.request = (uintptr_t) cdb;
-+  io_v4.max_response_len = sizeof (sense);
-+  io_v4.response = (uintptr_t) sense;
-+  io_v4.timeout = timeout_msec;
-+
-+  rc = ioctl (fd, SG_IO, &io_v4);
-+  if (rc != 0)
-+    {
-+      /* could be that the driver doesn't do version 4, try version 3 */
-+      if (errno == EINVAL)
-+        {
-+          struct sg_io_hdr io_hdr;
-+          memset (&io_hdr, 0, sizeof (struct sg_io_hdr));
-+          io_hdr.interface_id = 'S';
-+          io_hdr.cmdp = (unsigned char*) cdb;
-+          io_hdr.cmd_len = cdb_len;
-+          io_hdr.dxfer_direction = SG_DXFER_NONE;
-+          io_hdr.sbp = sense;
-+          io_hdr.mx_sb_len = sizeof (sense);
-+          io_hdr.timeout = timeout_msec;
-+
-+          rc = ioctl (fd, SG_IO, &io_hdr);
-+          if (rc != 0)
-+            {
-+              g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
-+                           "SGIO v3 ioctl failed (v4 not supported): %m");
-+              goto out;
-+            }
-+          else
-+            {
-+              if (!(io_hdr.status == 0 &&
-+                    io_hdr.host_status == 0 &&
-+                    io_hdr.driver_status == 0))
-+                {
-+                  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-+                               "Non-GOOD SCSI status from SGIO v3 ioctl: "
-+                               "status=%d host_status=%d driver_status=%d",
-+                               io_hdr.status,
-+                               io_hdr.host_status,
-+                               io_hdr.driver_status);
-+                  goto out;
-+                }
-+            }
-+        }
-+      else
-+        {
-+          g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
-+                       "SGIO v4 ioctl failed: %m");
-+          goto out;
-+        }
-+    }
-+  else
-+    {
-+      if (!(io_v4.device_status == 0 &&
-+            io_v4.transport_status == 0 &&
-+            io_v4.driver_status == 0))
-+        {
-+          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
-+                       "Non-GOOD SCSI status from SGIO v4 ioctl: "
-+                       "device_status=%d transport_status=%d driver_status=%d",
-+                       io_v4.device_status,
-+                       io_v4.transport_status,
-+                       io_v4.driver_status);
-+          goto out;
-+        }
-+    }
-+
-+  ret = TRUE;
-+
-+ out:
-+  return ret;
-+}
-+
-+static gboolean
-+send_scsi_start_stop_command_sync (gint      fd,
-+                                   GError  **error)
-+{
-+  uint8_t cdb[6];
-+
-+  /* SBC3 (SCSI Block Commands), 5.20 START STOP UNIT command
-+   */
-+  memset (cdb, 0, sizeof cdb);
-+  cdb[0] = 0x1b;                        /* OPERATION CODE: START STOP UNIT */
-+
-+  return send_scsi_command_sync (fd, cdb, sizeof cdb, error);
-+}
-+
-+/* ---------------------------------------------------------------------------------------------------- */
-+
- static gboolean
- handle_power_off (UDisksDrive           *_drive,
-                   GDBusMethodInvocation *invocation,
-@@ -1216,6 +1338,7 @@ handle_power_off (UDisksDrive           *_drive,
-   gid_t caller_gid;
-   pid_t caller_pid;
-   GList *sibling_objects = NULL, *l;
-+  gint fd = -1;
- 
-   object = udisks_daemon_util_dup_object (drive, &error);
-   if (object == NULL)
-@@ -1324,10 +1447,10 @@ handle_power_off (UDisksDrive           *_drive,
-     {
-       UDisksBlock *block_to_sync = UDISKS_BLOCK (l->data);
-       const gchar *device_file;
--      gint fd;
-+      gint device_fd;
-       device_file = udisks_block_get_device (block_to_sync);
--      fd = open (device_file, O_RDONLY|O_NONBLOCK|O_EXCL);
--      if (fd == -1)
-+      device_fd = open (device_file, O_RDONLY|O_NONBLOCK|O_EXCL);
-+      if (device_fd == -1)
-         {
-           g_dbus_method_invocation_return_error (invocation,
-                                                  UDISKS_ERROR,
-@@ -1336,7 +1459,7 @@ handle_power_off (UDisksDrive           *_drive,
-                                                  device_file);
-           goto out;
-         }
--      if (fsync (fd) != 0)
-+      if (fsync (device_fd) != 0)
-         {
-           g_dbus_method_invocation_return_error (invocation,
-                                                  UDISKS_ERROR,
-@@ -1345,7 +1468,7 @@ handle_power_off (UDisksDrive           *_drive,
-                                                  device_file);
-           goto out;
-         }
--      if (close (fd) != 0)
-+      if (close (device_fd) != 0)
-         {
-           g_dbus_method_invocation_return_error (invocation,
-                                                  UDISKS_ERROR,
-@@ -1356,9 +1479,45 @@ handle_power_off (UDisksDrive           *_drive,
-         }
-     }
- 
--  escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
-+  /* Send the "SCSI START STOP UNIT" command to request that the unit
-+   * be stopped but don't treat failure as fatal. In fact some
-+   * USB-attached hard-disks fails with this command, probably due to
-+   * the SCSI/SATA translation layer.
-+   */
-+  fd = open (udisks_block_get_device (block), O_RDONLY|O_NONBLOCK|O_EXCL);
-+  if (fd == -1)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             UDISKS_ERROR,
-+                                             UDISKS_ERROR_FAILED,
-+                                             "Error opening %s: %m",
-+                                             udisks_block_get_device (block));
-+      goto out;
-+    }
-+  if (!send_scsi_start_stop_command_sync (fd, &error))
-+    {
-+      udisks_warning ("Ignoring SCSI command START STOP UNIT failure (%s) on %s",
-+                      error->message,
-+                      udisks_block_get_device (block));
-+      g_clear_error (&error);
-+    }
-+  else
-+    {
-+      udisks_notice ("Powering off %s - successfully sent SCSI command START STOP UNIT",
-+                     udisks_block_get_device (block));
-+    }
-+  if (close (fd) != 0)
-+    {
-+      g_dbus_method_invocation_return_error (invocation,
-+                                             UDISKS_ERROR,
-+                                             UDISKS_ERROR_FAILED,
-+                                             "Error closing %s: %m",
-+                                             udisks_block_get_device (block));
-+      goto out;
-+    }
-+  fd = -1;
- 
--  /* TODO: Send the eject? Send SCSI START STOP UNIT? */
-+  escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
-   device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
-   if (device == NULL)
-     {
-@@ -1405,10 +1564,20 @@ handle_power_off (UDisksDrive           *_drive,
-         }
-     }
-   fclose (f);
-+  udisks_notice ("Powered off %s - successfully wrote to sysfs path %s",
-+                 udisks_block_get_device (block),
-+                 remove_path);
- 
-   udisks_drive_complete_power_off (UDISKS_DRIVE (drive), invocation);
- 
-  out:
-+  if (fd != -1)
-+    {
-+      if (close (fd) != 0)
-+        {
-+          udisks_warning ("Error closing device: %m");
-+        }
-+    }
-   g_list_free_full (blocks_to_sync, g_object_unref);
-   g_list_free_full (sibling_objects, g_object_unref);
-   g_free (remove_path);
-diff --git a/src/udiskslinuxdriveata.c b/src/udiskslinuxdriveata.c
-index 48cc6e6..534ef4d 100644
---- a/src/udiskslinuxdriveata.c
-+++ b/src/udiskslinuxdriveata.c
-@@ -1943,7 +1943,7 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta     *drive,
-   /* First get the IDENTIFY data directly from the drive, for sanity checks */
-   {
-     /* ATA8: 7.16 IDENTIFY DEVICE - ECh, PIO Data-In */
--    UDisksAtaCommandInput input = {.command = 0xec};
-+    UDisksAtaCommandInput input = {.command = 0xec, .count = 1};
-     UDisksAtaCommandOutput output = {.buffer = identify.buf, .buffer_size = sizeof (identify.buf)};
-     if (!udisks_ata_send_command_sync (fd,
-                                        -1,
-diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c
-index 4c8d8aa..f243046 100644
---- a/src/udiskslinuxfilesystem.c
-+++ b/src/udiskslinuxfilesystem.c
-@@ -348,13 +348,16 @@ find_mount_options_for_fs (const gchar *fstype)
- static gid_t
- find_primary_gid (uid_t uid)
- {
--  struct passwd *pw;
-+  struct passwd *pw = NULL;
-+  struct passwd pwstruct;
-+  gchar pwbuf[8192];
-+  int rc;
-   gid_t gid;
- 
-   gid = (gid_t) - 1;
- 
--  pw = getpwuid (uid);
--  if (pw == NULL)
-+  rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-+  if (rc != 0 || pw == NULL)
-     {
-       udisks_warning ("Error looking up uid %d: %m", uid);
-       goto out;
-@@ -370,7 +373,10 @@ is_uid_in_gid (uid_t uid,
-                gid_t gid)
- {
-   gboolean ret;
--  struct passwd *pw;
-+  struct passwd *pw = NULL;
-+  struct passwd pwstruct;
-+  gchar pwbuf[8192];
-+  int rc;
-   static gid_t supplementary_groups[128];
-   int num_supplementary_groups = 128;
-   int n;
-@@ -379,8 +385,8 @@ is_uid_in_gid (uid_t uid,
- 
-   ret = FALSE;
- 
--  pw = getpwuid (uid);
--  if (pw == NULL)
-+  rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-+  if (rc != 0 || pw == NULL)
-     {
-       udisks_warning ("Error looking up uid %d: %m", uid);
-       goto out;
-diff --git a/src/udisksspawnedjob.c b/src/udisksspawnedjob.c
-index 802551f..b181933 100644
---- a/src/udisksspawnedjob.c
-+++ b/src/udisksspawnedjob.c
-@@ -371,22 +371,25 @@ static void
- child_setup (gpointer user_data)
- {
-   UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data);
--  struct passwd *pw;
-+  struct passwd pwstruct;
-+  gchar pwbuf[8192];
-+  struct passwd *pw = NULL;
-+  int rc;
-   gid_t egid;
- 
-   if (job->run_as_uid == getuid () && job->run_as_euid == geteuid ())
-     goto out;
- 
--  pw = getpwuid (job->run_as_euid);
--  if (pw == NULL)
-+  rc = getpwuid_r (job->run_as_euid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-+  if (rc != 0 || pw == NULL)
-    {
-      g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_euid);
-      abort ();
-    }
-   egid = pw->pw_gid;
- 
--  pw = getpwuid (job->run_as_uid);
--  if (pw == NULL)
-+  rc = getpwuid_r (job->run_as_uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
-+  if (rc != 0 || pw == NULL)
-    {
-      g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_uid);
-      abort ();
-diff --git a/tools/udisksctl.c b/tools/udisksctl.c
-index 97b0f17..c87fe9f 100644
---- a/tools/udisksctl.c
-+++ b/tools/udisksctl.c
-@@ -1691,6 +1691,12 @@ handle_command_loop (gint        *argc,
-           goto out;
-         }
- 
-+      if (udisks_object_peek_loop (object) == NULL)
-+        {
-+          g_printerr ("Error: specified object is not a loop device\n");
-+          goto out;
-+        }
-+
-     delete_try_again:
-       error = NULL;
-       if (!udisks_loop_call_delete_sync (udisks_object_peek_loop (object),
-@@ -2009,6 +2015,238 @@ handle_command_smart_simulate (gint        *argc,
- 
- /* ---------------------------------------------------------------------------------------------------- */
- 
-+static gchar   *opt_power_off_object_path = NULL;
-+static gchar   *opt_power_off_device = NULL;
-+static gboolean opt_power_off_no_user_interaction = FALSE;
-+
-+static const GOptionEntry command_power_off_entries[] =
-+{
-+  {
-+    "object-path",
-+    'p',
-+    0,
-+    G_OPTION_ARG_STRING,
-+    &opt_power_off_object_path,
-+    "Object path for ATA device",
-+    NULL
-+  },
-+  {
-+    "block-device",
-+    'b',
-+    0,
-+    G_OPTION_ARG_STRING,
-+    &opt_power_off_device,
-+    "Device file for ATA device",
-+    NULL
-+  },
-+  {
-+    "no-user-interaction",
-+    0, /* no short option */
-+    0,
-+    G_OPTION_ARG_NONE,
-+    &opt_power_off_no_user_interaction,
-+    "Do not authenticate the user if needed",
-+    NULL
-+  },
-+  {
-+    NULL
-+  }
-+};
-+
-+static gint
-+handle_command_power_off (gint        *argc,
-+                          gchar      **argv[],
-+                          gboolean     request_completion,
-+                          const gchar *completion_cur,
-+                          const gchar *completion_prev)
-+{
-+  gint ret;
-+  GOptionContext *o;
-+  gchar *s;
-+  gboolean complete_objects;
-+  gboolean complete_devices;
-+  GList *l;
-+  GList *objects;
-+  UDisksObject *object;
-+  UDisksDriveAta *ata;
-+  guint n;
-+  GVariant *options;
-+  GVariantBuilder builder;
-+  GError *error;
-+
-+  ret = 1;
-+  opt_power_off_object_path = NULL;
-+  opt_power_off_device = NULL;
-+  object = NULL;
-+  options = NULL;
-+
-+  modify_argv0_for_command (argc, argv, "power-off");
-+
-+  o = g_option_context_new (NULL);
-+  if (request_completion)
-+    g_option_context_set_ignore_unknown_options (o, TRUE);
-+  g_option_context_set_help_enabled (o, FALSE);
-+  g_option_context_set_summary (o, "Safely power off a drive.");
-+  g_option_context_add_main_entries (o,
-+                                     command_power_off_entries,
-+                                     NULL /* GETTEXT_PACKAGE*/);
-+
-+  complete_objects = FALSE;
-+  if (request_completion && (g_strcmp0 (completion_prev, "--object-path") == 0 || g_strcmp0 (completion_prev, "-p") == 0))
-+    {
-+      complete_objects = TRUE;
-+      remove_arg ((*argc) - 1, argc, argv);
-+    }
-+
-+  complete_devices = FALSE;
-+  if (request_completion && (g_strcmp0 (completion_prev, "--block-device") == 0 || g_strcmp0 (completion_prev, "-b") == 0))
-+    {
-+      complete_devices = TRUE;
-+      remove_arg ((*argc) - 1, argc, argv);
-+    }
-+
-+  if (!g_option_context_parse (o, argc, argv, NULL))
-+    {
-+      if (!request_completion)
-+        {
-+          s = g_option_context_get_help (o, FALSE, NULL);
-+          g_printerr ("%s", s);
-+          g_free (s);
-+          goto out;
-+        }
-+    }
-+
-+  if (request_completion)
-+    {
-+      if ((opt_power_off_object_path == NULL && !complete_objects) &&
-+          (opt_power_off_device == NULL && !complete_devices))
-+        {
-+          g_print ("--object-path \n"
-+                   "--block-device \n");
-+        }
-+
-+      if (complete_objects)
-+        {
-+          const gchar *object_path;
-+          objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (client));
-+          for (l = objects; l != NULL; l = l->next)
-+            {
-+              object = UDISKS_OBJECT (l->data);
-+              ata = udisks_object_peek_drive_ata (object);
-+              if (ata != NULL)
-+                {
-+                  object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
-+                  g_assert (g_str_has_prefix (object_path, "/org/freedesktop/UDisks2/"));
-+                  g_print ("%s \n", object_path + sizeof ("/org/freedesktop/UDisks2/") - 1);
-+                }
-+            }
-+          g_list_foreach (objects, (GFunc) g_object_unref, NULL);
-+          g_list_free (objects);
-+        }
-+
-+      if (complete_devices)
-+        {
-+          objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (client));
-+          for (l = objects; l != NULL; l = l->next)
-+            {
-+              object = UDISKS_OBJECT (l->data);
-+              ata = udisks_object_peek_drive_ata (object);
-+              if (ata != NULL)
-+                {
-+                  const gchar * const *symlinks;
-+                  UDisksBlock *block;
-+                  block = udisks_client_get_block_for_drive (client, udisks_object_peek_drive (object), TRUE);
-+                  g_print ("%s \n", udisks_block_get_device (block));
-+                  symlinks = udisks_block_get_symlinks (block);
-+                  for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
-+                    g_print ("%s \n", symlinks[n]);
-+                }
-+            }
-+          g_list_foreach (objects, (GFunc) g_object_unref, NULL);
-+          g_list_free (objects);
-+        }
-+      goto out;
-+    }
-+
-+  g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
-+  if (opt_power_off_no_user_interaction)
-+    {
-+      g_variant_builder_add (&builder,
-+                             "{sv}",
-+                             "auth.no_user_interaction", g_variant_new_boolean (TRUE));
-+    }
-+  options = g_variant_builder_end (&builder);
-+  g_variant_ref_sink (options);
-+
-+  if (opt_power_off_object_path != NULL)
-+    {
-+      object = lookup_object_by_path (opt_power_off_object_path);
-+      if (object == NULL)
-+        {
-+          g_printerr ("Error looking up object with path %s\n", opt_power_off_object_path);
-+          goto out;
-+        }
-+    }
-+  else if (opt_power_off_device != NULL)
-+    {
-+      UDisksObject *block_object;
-+      UDisksDrive *drive;
-+      block_object = lookup_object_by_device (opt_power_off_device);
-+      if (block_object == NULL)
-+        {
-+          g_printerr ("Error looking up object for device %s\n", opt_power_off_device);
-+          goto out;
-+        }
-+      drive = udisks_client_get_drive_for_block (client, udisks_object_peek_block (block_object));
-+      object = (UDisksObject *) g_dbus_interface_dup_object (G_DBUS_INTERFACE (drive));
-+      g_object_unref (block_object);
-+    }
-+  else
-+    {
-+      s = g_option_context_get_help (o, FALSE, NULL);
-+      g_printerr ("%s", s);
-+      g_free (s);
-+      goto out;
-+    }
-+
-+ try_again:
-+  error = NULL;
-+  if (!udisks_drive_call_power_off_sync (udisks_object_peek_drive (object),
-+                                         options,
-+                                         NULL,                       /* GCancellable */
-+                                         &error))
-+    {
-+      if (error->domain == UDISKS_ERROR &&
-+          error->code == UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN &&
-+          setup_local_polkit_agent ())
-+        {
-+          g_error_free (error);
-+          goto try_again;
-+        }
-+      g_dbus_error_strip_remote_error (error);
-+      g_printerr ("Error powering off drive: %s (%s, %d)\n",
-+                  error->message, g_quark_to_string (error->domain), error->code);
-+      g_clear_error (&error);
-+      g_object_unref (object);
-+      goto out;
-+    }
-+
-+  g_object_unref (object);
-+
-+
-+  ret = 0;
-+
-+ out:
-+  if (options != NULL)
-+    g_variant_unref (options);
-+  g_option_context_free (o);
-+  g_free (opt_power_off_object_path);
-+  g_free (opt_power_off_device);
-+  return ret;
-+}
-+
-+/* ---------------------------------------------------------------------------------------------------- */
-+
- static gchar *opt_info_object = NULL;
- static gchar *opt_info_device = NULL;
- static gchar *opt_info_drive = NULL;
-@@ -2855,6 +3093,7 @@ usage (gint *argc, gchar **argv[], gboolean use_stdout)
-                        "  lock            Lock an encrypted device\n"
-                        "  loop-setup      Set-up a loop device\n"
-                        "  loop-delete     Delete a loop device\n"
-+                       "  power-off       Safely power off a drive\n"
-                        "  smart-simulate  Set SMART data for a drive\n"
-                        "\n"
-                        "Use \"%s COMMAND --help\" to get help on each command.\n",
-@@ -3053,6 +3292,15 @@ main (int argc,
-                                            completion_prev);
-       goto out;
-     }
-+  else if (g_strcmp0 (command, "power-off") == 0)
-+    {
-+      ret = handle_command_power_off (&argc,
-+                                      &argv,
-+                                      request_completion,
-+                                      completion_cur,
-+                                      completion_prev);
-+      goto out;
-+    }
-   else if (g_strcmp0 (command, "dump") == 0)
-     {
-       ret = handle_command_dump (&argc,
-@@ -3156,6 +3404,7 @@ main (int argc,
-                    "unlock \n"
-                    "loop-setup \n"
-                    "loop-delete \n"
-+                   "power-off \n"
-                    "smart-simulate \n"
-                    );
-           ret = 0;

Copied: udisks2/repos/extra-x86_64/git-fixes.patch (from rev 283051, udisks2/trunk/git-fixes.patch)
===================================================================
--- extra-x86_64/git-fixes.patch	                        (rev 0)
+++ extra-x86_64/git-fixes.patch	2016-12-12 10:23:19 UTC (rev 283052)
@@ -0,0 +1,777 @@
+diff --git a/data/80-udisks2.rules b/data/80-udisks2.rules
+index ed093ee..7112db8 100644
+--- a/data/80-udisks2.rules
++++ b/data/80-udisks2.rules
+@@ -94,6 +94,9 @@ SUBSYSTEMS=="usb", ENV{ID_VENDOR}=="*SanDisk*", ENV{ID_MODEL}=="*Cruzer*", ENV{I
+ SUBSYSTEMS=="usb", ENV{ID_VENDOR}=="HP", ENV{ID_MODEL}=="*v125w*", ENV{ID_DRIVE_THUMB}="1"
+ SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="13fe", ENV{ID_MODEL}=="*Patriot*", ENV{ID_DRIVE_THUMB}="1"
+ 
++# SD-Card reader in Chromebook Pixel
++SUBSYSTEMS=="usb", ENV{ID_VENDOR_ID}=="05e3", ENV{ID_MODEL_ID}=="0727", ENV{ID_DRIVE_FLASH_SD}="1"
++
+ # ------------------------------------------------------------------------
+ # ------------------------------------------------------------------------
+ # ------------------------------------------------------------------------
+diff --git a/doc/man/udisksctl.xml b/doc/man/udisksctl.xml
+index 8f38479..434a8fb 100644
+--- a/doc/man/udisksctl.xml
++++ b/doc/man/udisksctl.xml
+@@ -104,6 +104,16 @@
+ 
+     <cmdsynopsis>
+       <command>udisksctl</command>
++      <arg choice="plain">power-off </arg>
++      <group choice="req">
++        <arg choice="plain">--object-path <replaceable>OBJECT</replaceable></arg>
++        <arg choice="plain">--block-device <replaceable>DEVICE</replaceable></arg>
++      </group>
++      <arg choice="opt">--no-user-interaction</arg>
++    </cmdsynopsis>
++
++    <cmdsynopsis>
++      <command>udisksctl</command>
+       <arg choice="plain">smart-simulate </arg>
+       <arg choice="plain">--file <replaceable>PATH</replaceable></arg>
+       <group choice="req">
+@@ -238,6 +248,31 @@
+       </varlistentry>
+ 
+       <varlistentry>
++        <term><option>power-off</option></term>
++        <listitem>
++          <para>
++            Arranges for the drive to be safely removed and powered
++            off. On the OS side this includes ensuring that no process
++            is using the drive, then requesting that in-flight buffers
++            and caches are committed to stable storage. The exact
++            steps for powering off the drive depends on the drive
++            itself and the interconnect used. For drives connected
++            through USB, the effect is that the USB device will be
++            deconfigured followed by disabling the upstream hub port
++            it is connected to.
++          </para>
++          <para>
++            Note that as some physical devices contain multiple drives
++            (for example 4-in-1 flash card reader USB devices)
++            powering off one drive may affect other drives. As such
++            there are not a lot of guarantees associated with
++            performing this action. Usually the effect is that the
++            drive disappears as if it was unplugged.
++          </para>
++        </listitem>
++      </varlistentry>
++
++      <varlistentry>
+         <term><option>smart-simulate</option></term>
+         <listitem>
+           <para>
+diff --git a/src/udisksdaemonutil.c b/src/udisksdaemonutil.c
+index 574bf2c..a588580 100644
+--- a/src/udisksdaemonutil.c
++++ b/src/udisksdaemonutil.c
+@@ -830,7 +830,7 @@ udisks_daemon_util_get_caller_uid_sync (UDisksDaemon            *daemon,
+     {
+       struct passwd pwstruct;
+       gchar pwbuf[8192];
+-      static struct passwd *pw;
++      struct passwd *pw = NULL;
+       int rc;
+ 
+       rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
+@@ -840,6 +840,7 @@ udisks_daemon_util_get_caller_uid_sync (UDisksDaemon            *daemon,
+                        UDISKS_ERROR,
+                        UDISKS_ERROR_FAILED,
+                        "User with uid %d does not exist", (gint) uid);
++          goto out;
+         }
+       else if (pw == NULL)
+         {
+diff --git a/src/udiskslinuxblock.c b/src/udiskslinuxblock.c
+index d619850..22bcfd0 100644
+--- a/src/udiskslinuxblock.c
++++ b/src/udiskslinuxblock.c
+@@ -804,12 +804,23 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
+       gchar *dm_name_dev_file = NULL;
+       const gchar *dm_name_dev_file_as_symlink = NULL;
+ 
++      const gchar *dm_vg_name;
++      const gchar *dm_lv_name;
++      gchar *dm_lvm_dev_file = NULL;
++
+       dm_name = g_udev_device_get_property (device->udev_device, "DM_NAME");
+       if (dm_name != NULL)
+         dm_name_dev_file = g_strdup_printf ("/dev/mapper/%s", dm_name);
++
++      dm_vg_name = g_udev_device_get_property (device->udev_device, "DM_VG_NAME");
++      dm_lv_name = g_udev_device_get_property (device->udev_device, "DM_LV_NAME");
++      if (dm_vg_name != NULL && dm_lv_name != NULL)
++        dm_lvm_dev_file =  g_strdup_printf ("/dev/%s/%s", dm_vg_name, dm_lv_name);
++
+       for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
+         {
+-          if (g_str_has_prefix (symlinks[n], "/dev/vg_"))
++          if (g_str_has_prefix (symlinks[n], "/dev/vg_")
++              || g_strcmp0 (symlinks[n], dm_lvm_dev_file) == 0)
+             {
+               /* LVM2 */
+               preferred_device_file = symlinks[n];
+@@ -824,6 +835,7 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
+       if (preferred_device_file == NULL && dm_name_dev_file_as_symlink != NULL)
+         preferred_device_file = dm_name_dev_file_as_symlink;
+       g_free (dm_name_dev_file);
++      g_free (dm_lvm_dev_file);
+     }
+   else if (g_str_has_prefix (device_file, "/dev/md"))
+     {
+diff --git a/src/udiskslinuxdevice.c b/src/udiskslinuxdevice.c
+index 0b65a69..8c4a3ed 100644
+--- a/src/udiskslinuxdevice.c
++++ b/src/udiskslinuxdevice.c
+@@ -199,6 +199,7 @@ probe_ata (UDisksLinuxDevice  *device,
+     {
+       /* ATA8: 7.16 IDENTIFY DEVICE - ECh, PIO Data-In */
+       input.command = 0xec;
++      input.count = 1;
+       output.buffer = g_new0 (guchar, 512);
+       output.buffer_size = 512;
+       if (!udisks_ata_send_command_sync (fd,
+@@ -221,6 +222,7 @@ probe_ata (UDisksLinuxDevice  *device,
+     {
+       /* ATA8: 7.17 IDENTIFY PACKET DEVICE - A1h, PIO Data-In */
+       input.command = 0xa1;
++      input.count = 1;
+       output.buffer = g_new0 (guchar, 512);
+       output.buffer_size = 512;
+       if (!udisks_ata_send_command_sync (fd,
+diff --git a/src/udiskslinuxdrive.c b/src/udiskslinuxdrive.c
+index 170ba27..ed541ff 100644
+--- a/src/udiskslinuxdrive.c
++++ b/src/udiskslinuxdrive.c
+@@ -25,6 +25,12 @@
+ #include <sys/stat.h>
+ #include <sys/ioctl.h>
+ #include <fcntl.h>
++#include <inttypes.h>
++#include <errno.h>
++#include <linux/bsg.h>
++#include <scsi/scsi.h>
++#include <scsi/sg.h>
++#include <scsi/scsi_ioctl.h>
+ 
+ #include <pwd.h>
+ #include <grp.h>
+@@ -1192,6 +1198,122 @@ handle_set_configuration (UDisksDrive           *_drive,
+ 
+ /* ---------------------------------------------------------------------------------------------------- */
+ 
++/* TODO: move to udisksscsi.[ch] similar what we do for ATA with udisksata.[ch] */
++
++static gboolean
++send_scsi_command_sync (gint      fd,
++                        guint8   *cdb,
++                        gsize     cdb_len,
++                        GError  **error)
++{
++  struct sg_io_v4 io_v4;
++  uint8_t sense[32];
++  gboolean ret = FALSE;
++  gint rc;
++  gint timeout_msec = 30000; /* 30 seconds */
++
++  g_return_val_if_fail (fd != -1, FALSE);
++  g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
++
++  /* See http://sg.danny.cz/sg/sg_io.html and http://www.tldp.org/HOWTO/SCSI-Generic-HOWTO/index.html
++   * for detailed information about how the SG_IO ioctl work
++   */
++
++  memset (sense, 0, sizeof (sense));
++  memset (&io_v4, 0, sizeof (io_v4));
++  io_v4.guard = 'Q';
++  io_v4.protocol = BSG_PROTOCOL_SCSI;
++  io_v4.subprotocol = BSG_SUB_PROTOCOL_SCSI_CMD;
++  io_v4.request_len = cdb_len;
++  io_v4.request = (uintptr_t) cdb;
++  io_v4.max_response_len = sizeof (sense);
++  io_v4.response = (uintptr_t) sense;
++  io_v4.timeout = timeout_msec;
++
++  rc = ioctl (fd, SG_IO, &io_v4);
++  if (rc != 0)
++    {
++      /* could be that the driver doesn't do version 4, try version 3 */
++      if (errno == EINVAL)
++        {
++          struct sg_io_hdr io_hdr;
++          memset (&io_hdr, 0, sizeof (struct sg_io_hdr));
++          io_hdr.interface_id = 'S';
++          io_hdr.cmdp = (unsigned char*) cdb;
++          io_hdr.cmd_len = cdb_len;
++          io_hdr.dxfer_direction = SG_DXFER_NONE;
++          io_hdr.sbp = sense;
++          io_hdr.mx_sb_len = sizeof (sense);
++          io_hdr.timeout = timeout_msec;
++
++          rc = ioctl (fd, SG_IO, &io_hdr);
++          if (rc != 0)
++            {
++              g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
++                           "SGIO v3 ioctl failed (v4 not supported): %m");
++              goto out;
++            }
++          else
++            {
++              if (!(io_hdr.status == 0 &&
++                    io_hdr.host_status == 0 &&
++                    io_hdr.driver_status == 0))
++                {
++                  g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++                               "Non-GOOD SCSI status from SGIO v3 ioctl: "
++                               "status=%d host_status=%d driver_status=%d",
++                               io_hdr.status,
++                               io_hdr.host_status,
++                               io_hdr.driver_status);
++                  goto out;
++                }
++            }
++        }
++      else
++        {
++          g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno),
++                       "SGIO v4 ioctl failed: %m");
++          goto out;
++        }
++    }
++  else
++    {
++      if (!(io_v4.device_status == 0 &&
++            io_v4.transport_status == 0 &&
++            io_v4.driver_status == 0))
++        {
++          g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++                       "Non-GOOD SCSI status from SGIO v4 ioctl: "
++                       "device_status=%d transport_status=%d driver_status=%d",
++                       io_v4.device_status,
++                       io_v4.transport_status,
++                       io_v4.driver_status);
++          goto out;
++        }
++    }
++
++  ret = TRUE;
++
++ out:
++  return ret;
++}
++
++static gboolean
++send_scsi_start_stop_command_sync (gint      fd,
++                                   GError  **error)
++{
++  uint8_t cdb[6];
++
++  /* SBC3 (SCSI Block Commands), 5.20 START STOP UNIT command
++   */
++  memset (cdb, 0, sizeof cdb);
++  cdb[0] = 0x1b;                        /* OPERATION CODE: START STOP UNIT */
++
++  return send_scsi_command_sync (fd, cdb, sizeof cdb, error);
++}
++
++/* ---------------------------------------------------------------------------------------------------- */
++
+ static gboolean
+ handle_power_off (UDisksDrive           *_drive,
+                   GDBusMethodInvocation *invocation,
+@@ -1216,6 +1338,7 @@ handle_power_off (UDisksDrive           *_drive,
+   gid_t caller_gid;
+   pid_t caller_pid;
+   GList *sibling_objects = NULL, *l;
++  gint fd = -1;
+ 
+   object = udisks_daemon_util_dup_object (drive, &error);
+   if (object == NULL)
+@@ -1324,10 +1447,10 @@ handle_power_off (UDisksDrive           *_drive,
+     {
+       UDisksBlock *block_to_sync = UDISKS_BLOCK (l->data);
+       const gchar *device_file;
+-      gint fd;
++      gint device_fd;
+       device_file = udisks_block_get_device (block_to_sync);
+-      fd = open (device_file, O_RDONLY|O_NONBLOCK|O_EXCL);
+-      if (fd == -1)
++      device_fd = open (device_file, O_RDONLY|O_NONBLOCK|O_EXCL);
++      if (device_fd == -1)
+         {
+           g_dbus_method_invocation_return_error (invocation,
+                                                  UDISKS_ERROR,
+@@ -1336,7 +1459,7 @@ handle_power_off (UDisksDrive           *_drive,
+                                                  device_file);
+           goto out;
+         }
+-      if (fsync (fd) != 0)
++      if (fsync (device_fd) != 0)
+         {
+           g_dbus_method_invocation_return_error (invocation,
+                                                  UDISKS_ERROR,
+@@ -1345,7 +1468,7 @@ handle_power_off (UDisksDrive           *_drive,
+                                                  device_file);
+           goto out;
+         }
+-      if (close (fd) != 0)
++      if (close (device_fd) != 0)
+         {
+           g_dbus_method_invocation_return_error (invocation,
+                                                  UDISKS_ERROR,
+@@ -1356,9 +1479,45 @@ handle_power_off (UDisksDrive           *_drive,
+         }
+     }
+ 
+-  escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
++  /* Send the "SCSI START STOP UNIT" command to request that the unit
++   * be stopped but don't treat failure as fatal. In fact some
++   * USB-attached hard-disks fails with this command, probably due to
++   * the SCSI/SATA translation layer.
++   */
++  fd = open (udisks_block_get_device (block), O_RDONLY|O_NONBLOCK|O_EXCL);
++  if (fd == -1)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             UDISKS_ERROR,
++                                             UDISKS_ERROR_FAILED,
++                                             "Error opening %s: %m",
++                                             udisks_block_get_device (block));
++      goto out;
++    }
++  if (!send_scsi_start_stop_command_sync (fd, &error))
++    {
++      udisks_warning ("Ignoring SCSI command START STOP UNIT failure (%s) on %s",
++                      error->message,
++                      udisks_block_get_device (block));
++      g_clear_error (&error);
++    }
++  else
++    {
++      udisks_notice ("Powering off %s - successfully sent SCSI command START STOP UNIT",
++                     udisks_block_get_device (block));
++    }
++  if (close (fd) != 0)
++    {
++      g_dbus_method_invocation_return_error (invocation,
++                                             UDISKS_ERROR,
++                                             UDISKS_ERROR_FAILED,
++                                             "Error closing %s: %m",
++                                             udisks_block_get_device (block));
++      goto out;
++    }
++  fd = -1;
+ 
+-  /* TODO: Send the eject? Send SCSI START STOP UNIT? */
++  escaped_device = udisks_daemon_util_escape_and_quote (udisks_block_get_device (block));
+   device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
+   if (device == NULL)
+     {
+@@ -1405,10 +1564,20 @@ handle_power_off (UDisksDrive           *_drive,
+         }
+     }
+   fclose (f);
++  udisks_notice ("Powered off %s - successfully wrote to sysfs path %s",
++                 udisks_block_get_device (block),
++                 remove_path);
+ 
+   udisks_drive_complete_power_off (UDISKS_DRIVE (drive), invocation);
+ 
+  out:
++  if (fd != -1)
++    {
++      if (close (fd) != 0)
++        {
++          udisks_warning ("Error closing device: %m");
++        }
++    }
+   g_list_free_full (blocks_to_sync, g_object_unref);
+   g_list_free_full (sibling_objects, g_object_unref);
+   g_free (remove_path);
+diff --git a/src/udiskslinuxdriveata.c b/src/udiskslinuxdriveata.c
+index 48cc6e6..534ef4d 100644
+--- a/src/udiskslinuxdriveata.c
++++ b/src/udiskslinuxdriveata.c
+@@ -1943,7 +1943,7 @@ udisks_linux_drive_ata_secure_erase_sync (UDisksLinuxDriveAta     *drive,
+   /* First get the IDENTIFY data directly from the drive, for sanity checks */
+   {
+     /* ATA8: 7.16 IDENTIFY DEVICE - ECh, PIO Data-In */
+-    UDisksAtaCommandInput input = {.command = 0xec};
++    UDisksAtaCommandInput input = {.command = 0xec, .count = 1};
+     UDisksAtaCommandOutput output = {.buffer = identify.buf, .buffer_size = sizeof (identify.buf)};
+     if (!udisks_ata_send_command_sync (fd,
+                                        -1,
+diff --git a/src/udiskslinuxfilesystem.c b/src/udiskslinuxfilesystem.c
+index 4c8d8aa..f243046 100644
+--- a/src/udiskslinuxfilesystem.c
++++ b/src/udiskslinuxfilesystem.c
+@@ -348,13 +348,16 @@ find_mount_options_for_fs (const gchar *fstype)
+ static gid_t
+ find_primary_gid (uid_t uid)
+ {
+-  struct passwd *pw;
++  struct passwd *pw = NULL;
++  struct passwd pwstruct;
++  gchar pwbuf[8192];
++  int rc;
+   gid_t gid;
+ 
+   gid = (gid_t) - 1;
+ 
+-  pw = getpwuid (uid);
+-  if (pw == NULL)
++  rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
++  if (rc != 0 || pw == NULL)
+     {
+       udisks_warning ("Error looking up uid %d: %m", uid);
+       goto out;
+@@ -370,7 +373,10 @@ is_uid_in_gid (uid_t uid,
+                gid_t gid)
+ {
+   gboolean ret;
+-  struct passwd *pw;
++  struct passwd *pw = NULL;
++  struct passwd pwstruct;
++  gchar pwbuf[8192];
++  int rc;
+   static gid_t supplementary_groups[128];
+   int num_supplementary_groups = 128;
+   int n;
+@@ -379,8 +385,8 @@ is_uid_in_gid (uid_t uid,
+ 
+   ret = FALSE;
+ 
+-  pw = getpwuid (uid);
+-  if (pw == NULL)
++  rc = getpwuid_r (uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
++  if (rc != 0 || pw == NULL)
+     {
+       udisks_warning ("Error looking up uid %d: %m", uid);
+       goto out;
+diff --git a/src/udisksspawnedjob.c b/src/udisksspawnedjob.c
+index 802551f..b181933 100644
+--- a/src/udisksspawnedjob.c
++++ b/src/udisksspawnedjob.c
+@@ -371,22 +371,25 @@ static void
+ child_setup (gpointer user_data)
+ {
+   UDisksSpawnedJob *job = UDISKS_SPAWNED_JOB (user_data);
+-  struct passwd *pw;
++  struct passwd pwstruct;
++  gchar pwbuf[8192];
++  struct passwd *pw = NULL;
++  int rc;
+   gid_t egid;
+ 
+   if (job->run_as_uid == getuid () && job->run_as_euid == geteuid ())
+     goto out;
+ 
+-  pw = getpwuid (job->run_as_euid);
+-  if (pw == NULL)
++  rc = getpwuid_r (job->run_as_euid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
++  if (rc != 0 || pw == NULL)
+    {
+      g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_euid);
+      abort ();
+    }
+   egid = pw->pw_gid;
+ 
+-  pw = getpwuid (job->run_as_uid);
+-  if (pw == NULL)
++  rc = getpwuid_r (job->run_as_uid, &pwstruct, pwbuf, sizeof pwbuf, &pw);
++  if (rc != 0 || pw == NULL)
+    {
+      g_printerr ("No password record for uid %d: %m\n", (gint) job->run_as_uid);
+      abort ();
+diff --git a/tools/udisksctl.c b/tools/udisksctl.c
+index 97b0f17..c87fe9f 100644
+--- a/tools/udisksctl.c
++++ b/tools/udisksctl.c
+@@ -1691,6 +1691,12 @@ handle_command_loop (gint        *argc,
+           goto out;
+         }
+ 
++      if (udisks_object_peek_loop (object) == NULL)
++        {
++          g_printerr ("Error: specified object is not a loop device\n");
++          goto out;
++        }
++
+     delete_try_again:
+       error = NULL;
+       if (!udisks_loop_call_delete_sync (udisks_object_peek_loop (object),
+@@ -2009,6 +2015,238 @@ handle_command_smart_simulate (gint        *argc,
+ 
+ /* ---------------------------------------------------------------------------------------------------- */
+ 
++static gchar   *opt_power_off_object_path = NULL;
++static gchar   *opt_power_off_device = NULL;
++static gboolean opt_power_off_no_user_interaction = FALSE;
++
++static const GOptionEntry command_power_off_entries[] =
++{
++  {
++    "object-path",
++    'p',
++    0,
++    G_OPTION_ARG_STRING,
++    &opt_power_off_object_path,
++    "Object path for ATA device",
++    NULL
++  },
++  {
++    "block-device",
++    'b',
++    0,
++    G_OPTION_ARG_STRING,
++    &opt_power_off_device,
++    "Device file for ATA device",
++    NULL
++  },
++  {
++    "no-user-interaction",
++    0, /* no short option */
++    0,
++    G_OPTION_ARG_NONE,
++    &opt_power_off_no_user_interaction,
++    "Do not authenticate the user if needed",
++    NULL
++  },
++  {
++    NULL
++  }
++};
++
++static gint
++handle_command_power_off (gint        *argc,
++                          gchar      **argv[],
++                          gboolean     request_completion,
++                          const gchar *completion_cur,
++                          const gchar *completion_prev)
++{
++  gint ret;
++  GOptionContext *o;
++  gchar *s;
++  gboolean complete_objects;
++  gboolean complete_devices;
++  GList *l;
++  GList *objects;
++  UDisksObject *object;
++  UDisksDriveAta *ata;
++  guint n;
++  GVariant *options;
++  GVariantBuilder builder;
++  GError *error;
++
++  ret = 1;
++  opt_power_off_object_path = NULL;
++  opt_power_off_device = NULL;
++  object = NULL;
++  options = NULL;
++
++  modify_argv0_for_command (argc, argv, "power-off");
++
++  o = g_option_context_new (NULL);
++  if (request_completion)
++    g_option_context_set_ignore_unknown_options (o, TRUE);
++  g_option_context_set_help_enabled (o, FALSE);
++  g_option_context_set_summary (o, "Safely power off a drive.");
++  g_option_context_add_main_entries (o,
++                                     command_power_off_entries,
++                                     NULL /* GETTEXT_PACKAGE*/);
++
++  complete_objects = FALSE;
++  if (request_completion && (g_strcmp0 (completion_prev, "--object-path") == 0 || g_strcmp0 (completion_prev, "-p") == 0))
++    {
++      complete_objects = TRUE;
++      remove_arg ((*argc) - 1, argc, argv);
++    }
++
++  complete_devices = FALSE;
++  if (request_completion && (g_strcmp0 (completion_prev, "--block-device") == 0 || g_strcmp0 (completion_prev, "-b") == 0))
++    {
++      complete_devices = TRUE;
++      remove_arg ((*argc) - 1, argc, argv);
++    }
++
++  if (!g_option_context_parse (o, argc, argv, NULL))
++    {
++      if (!request_completion)
++        {
++          s = g_option_context_get_help (o, FALSE, NULL);
++          g_printerr ("%s", s);
++          g_free (s);
++          goto out;
++        }
++    }
++
++  if (request_completion)
++    {
++      if ((opt_power_off_object_path == NULL && !complete_objects) &&
++          (opt_power_off_device == NULL && !complete_devices))
++        {
++          g_print ("--object-path \n"
++                   "--block-device \n");
++        }
++
++      if (complete_objects)
++        {
++          const gchar *object_path;
++          objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (client));
++          for (l = objects; l != NULL; l = l->next)
++            {
++              object = UDISKS_OBJECT (l->data);
++              ata = udisks_object_peek_drive_ata (object);
++              if (ata != NULL)
++                {
++                  object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object));
++                  g_assert (g_str_has_prefix (object_path, "/org/freedesktop/UDisks2/"));
++                  g_print ("%s \n", object_path + sizeof ("/org/freedesktop/UDisks2/") - 1);
++                }
++            }
++          g_list_foreach (objects, (GFunc) g_object_unref, NULL);
++          g_list_free (objects);
++        }
++
++      if (complete_devices)
++        {
++          objects = g_dbus_object_manager_get_objects (udisks_client_get_object_manager (client));
++          for (l = objects; l != NULL; l = l->next)
++            {
++              object = UDISKS_OBJECT (l->data);
++              ata = udisks_object_peek_drive_ata (object);
++              if (ata != NULL)
++                {
++                  const gchar * const *symlinks;
++                  UDisksBlock *block;
++                  block = udisks_client_get_block_for_drive (client, udisks_object_peek_drive (object), TRUE);
++                  g_print ("%s \n", udisks_block_get_device (block));
++                  symlinks = udisks_block_get_symlinks (block);
++                  for (n = 0; symlinks != NULL && symlinks[n] != NULL; n++)
++                    g_print ("%s \n", symlinks[n]);
++                }
++            }
++          g_list_foreach (objects, (GFunc) g_object_unref, NULL);
++          g_list_free (objects);
++        }
++      goto out;
++    }
++
++  g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
++  if (opt_power_off_no_user_interaction)
++    {
++      g_variant_builder_add (&builder,
++                             "{sv}",
++                             "auth.no_user_interaction", g_variant_new_boolean (TRUE));
++    }
++  options = g_variant_builder_end (&builder);
++  g_variant_ref_sink (options);
++
++  if (opt_power_off_object_path != NULL)
++    {
++      object = lookup_object_by_path (opt_power_off_object_path);
++      if (object == NULL)
++        {
++          g_printerr ("Error looking up object with path %s\n", opt_power_off_object_path);
++          goto out;
++        }
++    }
++  else if (opt_power_off_device != NULL)
++    {
++      UDisksObject *block_object;
++      UDisksDrive *drive;
++      block_object = lookup_object_by_device (opt_power_off_device);
++      if (block_object == NULL)
++        {
++          g_printerr ("Error looking up object for device %s\n", opt_power_off_device);
++          goto out;
++        }
++      drive = udisks_client_get_drive_for_block (client, udisks_object_peek_block (block_object));
++      object = (UDisksObject *) g_dbus_interface_dup_object (G_DBUS_INTERFACE (drive));
++      g_object_unref (block_object);
++    }
++  else
++    {
++      s = g_option_context_get_help (o, FALSE, NULL);
++      g_printerr ("%s", s);
++      g_free (s);
++      goto out;
++    }
++
++ try_again:
++  error = NULL;
++  if (!udisks_drive_call_power_off_sync (udisks_object_peek_drive (object),
++                                         options,
++                                         NULL,                       /* GCancellable */
++                                         &error))
++    {
++      if (error->domain == UDISKS_ERROR &&
++          error->code == UDISKS_ERROR_NOT_AUTHORIZED_CAN_OBTAIN &&
++          setup_local_polkit_agent ())
++        {
++          g_error_free (error);
++          goto try_again;
++        }
++      g_dbus_error_strip_remote_error (error);
++      g_printerr ("Error powering off drive: %s (%s, %d)\n",
++                  error->message, g_quark_to_string (error->domain), error->code);
++      g_clear_error (&error);
++      g_object_unref (object);
++      goto out;
++    }
++
++  g_object_unref (object);
++
++
++  ret = 0;
++
++ out:
++  if (options != NULL)
++    g_variant_unref (options);
++  g_option_context_free (o);
++  g_free (opt_power_off_object_path);
++  g_free (opt_power_off_device);
++  return ret;
++}
++
++/* ---------------------------------------------------------------------------------------------------- */
++
+ static gchar *opt_info_object = NULL;
+ static gchar *opt_info_device = NULL;
+ static gchar *opt_info_drive = NULL;
+@@ -2855,6 +3093,7 @@ usage (gint *argc, gchar **argv[], gboolean use_stdout)
+                        "  lock            Lock an encrypted device\n"
+                        "  loop-setup      Set-up a loop device\n"
+                        "  loop-delete     Delete a loop device\n"
++                       "  power-off       Safely power off a drive\n"
+                        "  smart-simulate  Set SMART data for a drive\n"
+                        "\n"
+                        "Use \"%s COMMAND --help\" to get help on each command.\n",
+@@ -3053,6 +3292,15 @@ main (int argc,
+                                            completion_prev);
+       goto out;
+     }
++  else if (g_strcmp0 (command, "power-off") == 0)
++    {
++      ret = handle_command_power_off (&argc,
++                                      &argv,
++                                      request_completion,
++                                      completion_cur,
++                                      completion_prev);
++      goto out;
++    }
+   else if (g_strcmp0 (command, "dump") == 0)
+     {
+       ret = handle_command_dump (&argc,
+@@ -3156,6 +3404,7 @@ main (int argc,
+                    "unlock \n"
+                    "loop-setup \n"
+                    "loop-delete \n"
++                   "power-off \n"
+                    "smart-simulate \n"
+                    );
+           ret = 0;



More information about the arch-commits mailing list