123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778 |
- 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;
|