diff -Nru udisks2-1.97.0/configure udisks2-1.98.0/configure --- udisks2-1.97.0/configure 2012-04-30 19:23:06.000000000 +0000 +++ udisks2-1.98.0/configure 2012-05-09 18:00:06.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.68 for udisks 1.97.0. +# Generated by GNU Autoconf 2.68 for udisks 1.98.0. # # Report bugs to . # @@ -571,8 +571,8 @@ # Identity of this package. PACKAGE_NAME='udisks' PACKAGE_TARNAME='udisks' -PACKAGE_VERSION='1.97.0' -PACKAGE_STRING='udisks 1.97.0' +PACKAGE_VERSION='1.98.0' +PACKAGE_STRING='udisks 1.98.0' PACKAGE_BUGREPORT='http://bugs.freedesktop.org/enter_bug.cgi?product=udisks' PACKAGE_URL='' @@ -1435,7 +1435,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures udisks 1.97.0 to adapt to many kinds of systems. +\`configure' configures udisks 1.98.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1505,7 +1505,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of udisks 1.97.0:";; + short | recursive ) echo "Configuration of udisks 1.98.0:";; esac cat <<\_ACEOF @@ -1656,7 +1656,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -udisks configure 1.97.0 +udisks configure 1.98.0 generated by GNU Autoconf 2.68 Copyright (C) 2010 Free Software Foundation, Inc. @@ -2025,7 +2025,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by udisks $as_me 1.97.0, which was +It was created by udisks $as_me 1.98.0, which was generated by GNU Autoconf 2.68. Invocation command line was $ $0 $@ @@ -2375,9 +2375,9 @@ UDISKS_MAJOR_VERSION=1 -UDISKS_MINOR_VERSION=97 +UDISKS_MINOR_VERSION=98 UDISKS_MICRO_VERSION=0 -UDISKS_VERSION=1.97.0 +UDISKS_VERSION=1.98.0 @@ -2850,7 +2850,7 @@ # Define the identity of the package. PACKAGE='udisks' - VERSION='1.97.0' + VERSION='1.98.0' cat >>confdefs.h <<_ACEOF @@ -14931,7 +14931,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by udisks $as_me 1.97.0, which was +This file was extended by udisks $as_me 1.98.0, which was generated by GNU Autoconf 2.68. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -14997,7 +14997,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -udisks config.status 1.97.0 +udisks config.status 1.98.0 configured by $0, generated by GNU Autoconf 2.68, with options \\"\$ac_cs_config\\" diff -Nru udisks2-1.97.0/configure.ac udisks2-1.98.0/configure.ac --- udisks2-1.97.0/configure.ac 2012-04-30 19:22:46.000000000 +0000 +++ udisks2-1.98.0/configure.ac 2012-05-09 17:59:58.000000000 +0000 @@ -1,6 +1,6 @@ m4_define([udisks_major_version], [1]) -m4_define([udisks_minor_version], [97]) +m4_define([udisks_minor_version], [98]) m4_define([udisks_micro_version], [0]) m4_define([udisks_version], [udisks_major_version.udisks_minor_version.udisks_micro_version]) diff -Nru udisks2-1.97.0/data/org.freedesktop.udisks2.policy.in udisks2-1.98.0/data/org.freedesktop.udisks2.policy.in --- udisks2-1.97.0/data/org.freedesktop.udisks2.policy.in 2012-04-30 21:56:24.000000000 +0000 +++ udisks2-1.98.0/data/org.freedesktop.udisks2.policy.in 2012-05-13 16:12:03.000000000 +0000 @@ -341,6 +341,17 @@ + + + <_description>Set SMART data from blob + <_message>Authentication is required to set SMART data from blob + + auth_admin + auth_admin + auth_admin_keep + + + <_description>Run SMART self-test diff -Nru udisks2-1.97.0/data/org.freedesktop.UDisks2.xml udisks2-1.98.0/data/org.freedesktop.UDisks2.xml --- udisks2-1.97.0/data/org.freedesktop.UDisks2.xml 2012-05-07 18:41:21.000000000 +0000 +++ udisks2-1.98.0/data/org.freedesktop.UDisks2.xml 2012-05-13 16:12:03.000000000 +0000 @@ -384,16 +384,8 @@ The option @atasmart_blob can be used to inject libatasmart compatible blobs for testing how clients react to different - kinds of SMART data. Only uid 0 may use this. This option may - be removed in the future with it being considered an ABI break - - it only exists for testing purposes. Example: - -# export ATA_SMART_BLOB=/usr/share/doc/libatasmart-devel-0.17/Maxtor_96147H8--BAC51KJ0--2 ; \ - gdbus call --system --dest org.freedesktop.UDisks2 \ - --object-path /org/freedesktop/UDisks2/drives/WDC_WD1002FAEX_00Y9A0_WD_WCAW30039835 \ - --method org.freedesktop.UDisks2.Drive.Ata.SmartUpdate \ - "{'atasmart_blob': <'$ATA_SMART_BLOB'>}" - + kinds of SMART data. This option may be removed in the future + with it being considered an ABI break. --> diff -Nru udisks2-1.97.0/data/udisks2.service.in udisks2-1.98.0/data/udisks2.service.in --- udisks2-1.97.0/data/udisks2.service.in 2012-02-22 22:53:08.000000000 +0000 +++ udisks2-1.98.0/data/udisks2.service.in 2012-05-14 15:06:51.000000000 +0000 @@ -1,5 +1,5 @@ [Unit] -Description=Storage Daemon +Description=Disk Manager [Service] Type=dbus diff -Nru udisks2-1.97.0/debian/changelog udisks2-1.98.0/debian/changelog --- udisks2-1.97.0/debian/changelog 2012-05-25 05:12:13.000000000 +0000 +++ udisks2-1.98.0/debian/changelog 2012-06-16 10:23:59.000000000 +0000 @@ -1,8 +1,32 @@ -udisks2 (1.97.0-1~precise1) precise; urgency=low +udisks2 (1.98.0-1~precise1) precise; urgency=low * Copied from debian - -- Rico Tzschichholz Fri, 25 May 2012 07:12:13 +0200 + -- Rico Tzschichholz Sat, 16 Jun 2012 12:23:59 +0200 + +udisks2 (1.98.0-1) experimental; urgency=low + + * New upstream release. + * debian/control: Drop ntfsprogs Recommends. It is a transitional package + for ntfs-3g now, which we already recommend. + * Add 00git_no_polkit_fallback.patch: Fix crash if polkit is not available. + Patch backported from current upstream git head. + * Add debian/local/integration-test: Latest integration test suite from + upstream git. 1.99 and later will ship that in the source tarball. + * Add debian/tests/control and debian/tests/upstream-system: DEP-8 + autopkgtest (adapted from udisks package). + * debian/control: Change suggestion of cryptsetup to cryptsetup-bin, as that + is sufficient for udisks' needs. + * debian/copyright: Fix duplicate copyright line, thanks lintian. + + -- Martin Pitt Wed, 13 Jun 2012 17:01:30 +0200 + +udisks2 (1.97.0-2) experimental; urgency=low + + * debian/control: Add udev build dependency, as configure.uc needs its + pkg-config file to check for the udev directory. Fixes FTBFS. + + -- Martin Pitt Wed, 23 May 2012 11:40:02 +0200 udisks2 (1.97.0-1) experimental; urgency=low diff -Nru udisks2-1.97.0/debian/control udisks2-1.98.0/debian/control --- udisks2-1.97.0/debian/control 2012-05-18 09:31:18.000000000 +0000 +++ udisks2-1.98.0/debian/control 2012-06-13 15:01:38.000000000 +0000 @@ -9,6 +9,7 @@ gtk-doc-tools, intltool (>= 0.40.0), libglib2.0-dev (>= 2.31.13), + udev (>= 147), libgudev-1.0-dev (>= 147), libpolkit-gobject-1-dev (>= 0.97), libpolkit-agent-1-dev (>= 0.97), @@ -26,8 +27,8 @@ Multi-Arch: foreign Depends: ${shlibs:Depends}, ${misc:Depends}, udev, dbus Pre-Depends: ${misc:Pre-Depends} -Recommends: policykit-1, dosfstools, mtools, ntfs-3g, ntfsprogs, eject -Suggests: xfsprogs, reiserfsprogs, mdadm, cryptsetup +Recommends: policykit-1, dosfstools, mtools, ntfs-3g, eject +Suggests: xfsprogs, reiserfsprogs, mdadm, cryptsetup-bin Description: D-BUS service to access and manipulate storage devices The udisks daemon serves as an interface to system block devices, implemented via D-Bus. It handles operations such as querying, mounting, diff -Nru udisks2-1.97.0/debian/copyright udisks2-1.98.0/debian/copyright --- udisks2-1.97.0/debian/copyright 2012-05-18 09:31:18.000000000 +0000 +++ udisks2-1.98.0/debian/copyright 2012-06-13 15:01:38.000000000 +0000 @@ -5,7 +5,7 @@ Files: * Copyright: 2007-2011 David Zeuthen -Copyright: 2011 Martin Pitt + 2011 Martin Pitt License: GPL-2+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff -Nru udisks2-1.97.0/debian/local/integration-test udisks2-1.98.0/debian/local/integration-test --- udisks2-1.97.0/debian/local/integration-test 1970-01-01 00:00:00.000000000 +0000 +++ udisks2-1.98.0/debian/local/integration-test 2012-06-13 15:01:38.000000000 +0000 @@ -0,0 +1,1209 @@ +#!/usr/bin/python3 +# +# udisks2 integration test suite +# +# Run in udisks built tree to test local built binaries (needs +# --localstatedir=/var), or from anywhere else to test system installed +# binaries. +# +# Usage: +# - Run all tests: +# src/tests/integration-test +# - Run only a particular class of tests: +# src/tests/integration-test Drive +# - Run only a single test: +# src/tests/integration-test FS.test_ext3 +# +# Copyright: (C) 2011 Martin Pitt +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# TODO: +# - add and test method for changing LUKS passphrase +# - test Format with take-ownership + +import sys +import os +import pwd + +srcdir = os.path.dirname(os.path.dirname(os.path.dirname(os.path.realpath(__file__)))) +libdir = os.path.join(srcdir, 'udisks', '.libs') + +# as we can't change LD_LIBRARY_PATH within a running program, and doing +# #!/usr/bin/env LD_LIBRARY_PATH=... python3 does not work either, do this +# nasty hack +if 'LD_LIBRARY_PATH' not in os.environ and os.path.isdir(libdir): + os.environ['LD_LIBRARY_PATH'] = libdir + os.environ['GI_TYPELIB_PATH'] = '%s/udisks:%s' % ( + srcdir, + os.environ.get('GI_TYPELIB_PATH', '')) + os.execv(sys.argv[0], sys.argv) + assert False, 'not expecting to land here' + +import subprocess +import unittest +import tempfile +import atexit +import time +import shutil +import signal +import argparse +import re +from glob import glob +from gi.repository import GLib, Gio, UDisks + +#GI_TYPELIB_PATH=udisks LD_LIBRARY_PATH=udisks/.libs +VDEV_SIZE = 300000000 # size of virtual test device + +# Those file systems are known to have a broken handling of permissions, in +# particular the executable bit +BROKEN_PERMISSIONS_FS = ['ntfs'] + +# Some D-BUS API methods cause properties to not be up to date yet when a +# method call finishes, thus we do an udevadm settle as a workaround. Those +# methods should eventually get fixed properly, but it's unnerving to have +# the tests fail on them when you are working on something else. This flag +# gets set by the --no-workarounds option to disable those syncs, so that these +# race conditions can be fixed. +workaround_syncs = False + +no_options = GLib.Variant('a{sv}', {}) + +# ---------------------------------------------------------------------------- + +class UDisksTestCase(unittest.TestCase): + '''Base class for udisks test cases. + + This provides static functions which are useful for all test cases. + ''' + tool_path = None + daemon = None + daemon_log = None + device = None + + client = None + manager = None + + @classmethod + def init(klass, logfile=None): + '''start daemon and set up test environment''' + + if os.geteuid() != 0: + print('this test suite needs to run as root', file=sys.stderr) + sys.exit(0) + + # run from local build tree if we are in one, otherwise use system instance + daemon_path = os.path.join(srcdir, 'src', 'udisksd') + if (os.access (daemon_path, os.X_OK)): + klass.tool_path = 'tools/.libs/udisksctl' + print('Testing binaries from local build tree') + klass.check_build_tree_config() + else: + print('Testing installed system binaries') + daemon_path = None + for l in open('/usr/share/dbus-1/system-services/org.freedesktop.UDisks2.service'): + if l.startswith('Exec='): + daemon_path = l.split('=', 1)[1].split()[0] + break + assert daemon_path, 'could not determine daemon path from D-BUS .service file' + + klass.tool_path = 'udisksctl' + print('daemon path: ' + daemon_path) + + for l in open('/usr/share/dbus-1/system-services/org.freedesktop.PolicyKit1.service'): + if l.startswith('Exec='): + klass.polkit_path = l.split('=', 1)[1].split()[0].strip() + break + assert klass.polkit_path, 'could not determine polkit path from D-BUS .service file' + print('polkitd path: ' + klass.polkit_path) + + klass.device = klass.setup_vdev() + + # use a D-BUS config which permits root and nobody + klass.dbus_conf = tempfile.NamedTemporaryFile() + klass.dbus_conf.write(b''' + + test + unix:tmpdir=/tmp + + + + + + + + +''') + klass.dbus_conf.flush() + + # start polkit and udisks on a private DBus + dbus = subprocess.Popen(['dbus-launch', '--config-file=' + klass.dbus_conf.name], + stdout=subprocess.PIPE, universal_newlines=True) + dbus_out = dbus.communicate()[0] + for l in dbus_out.splitlines(): + k, v = l.split('=', 1) + if k == 'DBUS_SESSION_BUS_PID': + klass.dbus_pid = int(v) + if k == 'DBUS_SESSION_BUS_ADDRESS': + os.environ['DBUS_SYSTEM_BUS_ADDRESS'] = v + # do not try to communicate with the current desktop session; this will + # confuse it, as it cannot see this D-BUS instance + try: + del os.environ['DISPLAY'] + except KeyError: + pass + if logfile: + klass.daemon_log = open(logfile, 'w') + else: + klass.daemon_log = tempfile.TemporaryFile() + klass.daemon = subprocess.Popen([daemon_path], + stdout=klass.daemon_log, stderr=subprocess.STDOUT) + assert klass.daemon.pid, 'daemon failed to start' + + atexit.register(klass.cleanup) + + # wait until the daemon has started up + timeout = 10 + while klass.manager is None and timeout > 0: + time.sleep(0.2) + klass.client = UDisks.Client.new_sync(None) + assert klass.client != None + klass.manager = klass.client.get_manager() + timeout -= 1 + assert klass.manager, 'daemon failed to start' + + klass.sync() + + @classmethod + def cleanup(klass): + '''stop daemon again and clean up test environment''' + + subprocess.call(['umount', klass.device], stderr=subprocess.PIPE) # if a test failed + + os.kill(klass.daemon.pid, signal.SIGTERM) + os.wait() + klass.daemon = None + + klass.teardown_vdev(klass.device) + klass.device = None + + klass.dbus_conf.close() + del os.environ['DBUS_SYSTEM_BUS_ADDRESS'] + os.kill(klass.dbus_pid, signal.SIGTERM) + + @classmethod + def sync(klass): + '''Wait until pending events finished processing. + + This should only be called for situations where we genuinely have an + asynchronous response, like invoking a CLI program and waiting for + udev/udisks to catch up on the change events. + ''' + subprocess.call(['udevadm', 'settle']) + klass.client.settle() + + @classmethod + def sync_workaround(klass): + '''Wait until pending events finished processing (bug workaround). + + This should be called for race conditions in the D-BUS API which cause + properties to not be up to date yet when a method call finishes. Those + should eventually get fixed properly, but it's unnerving to have the + tests fail on them when you are working on something else. + + This sync is not done if running with --no-workarounds. + ''' + if workaround_syncs: + klass.sync() + + @classmethod + def zero_device(klass): + subprocess.call(['dd', 'if=/dev/zero', 'of='+klass.device, 'bs=10M'], + stderr=subprocess.PIPE) + klass.sync() + + @classmethod + def devname(klass, partition=None): + '''Get name of test device or one of its partitions''' + + if partition: + if klass.device[-1].isdigit(): + return klass.device + 'p' + str(partition) + else: + return klass.device + str(partition) + else: + return klass.device + + @classmethod + def udisks_block(klass, partition=None): + '''Get UDisksBlock object for test device or partition''' + + assert klass.client + devname = klass.devname(partition) + dev_t = os.stat(devname).st_rdev + block = klass.client.get_block_for_dev(dev_t) + assert block, 'did not find an UDisksBlock object for %s' % devname + return block + + @classmethod + def udisks_filesystem(klass, partition=None): + '''Get UDisksFilesystem object for test device or partition + + Return None if there is no file system on that device. + ''' + block = klass.udisks_block(partition) + return klass.client.get_object(block.get_object_path()).get_property('filesystem') + + @classmethod + def blkid(klass, partition=None, device=None): + '''Call blkid and return dictionary of results.''' + + if not device: + device = klass.devname(partition) + result = {} + cmd = subprocess.Popen(['blkid', '-p', '-o', 'udev', device], stdout=subprocess.PIPE) + for l in cmd.stdout: + (key, value) = l.decode('UTF-8').split('=', 1) + result[key] = value.strip() + assert cmd.wait() == 0 + return result + + @classmethod + def is_mountpoint(klass, path): + '''Check if given path is a mount point.''' + + return subprocess.call(['mountpoint', path], stdout=subprocess.PIPE) == 0 + + @classmethod + def mkfs(klass, type, label=None, partition=None): + '''Create file system using mkfs.''' + + if type == 'minix': + assert label is None, 'minix does not support labels' + + # work around mkswap not properly cleaning up an existing reiserfs + # signature (mailed kzak about it) + if type == 'swap': + subprocess.check_call(['wipefs', '-a', klass.devname(partition)], + stdout=subprocess.PIPE) + + mkcmd = { 'swap': 'mkswap', + } + label_opt = { 'vfat': '-n', + 'reiserfs': '-l', + } + extra_opt = { 'vfat': [ '-I', '-F', '32'], + 'swap': ['-f'], + 'xfs': ['-f'], # XFS complains if there's an existing FS, so force + 'ext2': ['-F'], # ext* complains about using entire device, so force + 'ext3': ['-F'], + 'ext4': ['-F'], + 'ntfs': ['-F'], + 'reiserfs': ['-ff'], + } + + cmd = [mkcmd.get(type, 'mkfs.' + type)] + extra_opt.get(type, []) + if label: + cmd += [label_opt.get(type, '-L'), label] + cmd.append(klass.devname(partition)) + + subprocess.check_call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + + # kernel/udev generally detect those changes itself, but do not quite + # tell us when they are done; so do a little kludge here to know how + # long we need to wait + subprocess.call(['udevadm', 'trigger', '--action=change', + '--sysname-match=' + os.path.basename(klass.devname(partition))]) + klass.sync() + + @classmethod + def fs_create(klass, partition, type, options): + '''Create file system using udisks.''' + + block = klass.udisks_block(partition) + block.call_format_sync(type, options, None) + klass.sync_workaround() + + @classmethod + def retry_busy(klass, fn, *args): + '''Call a function until it does not fail with "Busy".''' + + timeout = 10 + while timeout >= 0: + try: + return fn(*args) + except GLib.GError as e: + if not 'UDisks2.Error.DeviceBusy' in e.message: + raise + sys.stderr.write('[busy] ') + time.sleep(0.3) + timeout -= 1 + + @classmethod + def check_build_tree_config(klass): + '''Check configuration of build tree''' + + # read make variables + make_vars = {} + var_re = re.compile('^([a-zA-Z_]+) = (.*)$') + make = subprocess.Popen(['make', '-p', '/dev/null'], + stdout=subprocess.PIPE) + for l in make.stdout: + l = l.decode('UTF-8') + m = var_re.match(l) + if m: + make_vars[m.group(1)] = m.group(2) + make.wait() + + # expand make variables + subst_re = re.compile('\${([a-zA-Z_]+)}') + for (k, v) in make_vars.items(): + while True: + m = subst_re.search(v) + if m: + v = subst_re.sub(make_vars.get(m.group(1), ''), v) + make_vars[k] = v + else: + break + + # check localstatedir + for d in (os.path.join(make_vars['localstatedir'], 'run', 'udisks2'), + os.path.join(make_vars['localstatedir'], 'lib', 'udisks2')): + if not os.path.exists(d): + sys.stderr.write('The directory %s does not exist; please create it before running these tests.\n' % d) + sys.exit(0) + + @classmethod + def setup_vdev(klass): + '''create virtual test device + + It is zeroed out initially. + + Return the device path. + ''' + # ensure that the scsi_debug module is loaded + if os.path.isdir('/sys/module/scsi_debug'): + sys.stderr.write('The scsi_debug module is already loaded; please remove before running this test.\n') + sys.exit(1) + + assert subprocess.call(['modprobe', 'scsi_debug', 'dev_size_mb=%i' % ( + VDEV_SIZE/1048576)]) == 0, 'Failure to modprobe scsi_debug' + + # wait until all drives are created + dirs = [] + while len(dirs) < 1: + dirs = glob('/sys/bus/pseudo/drivers/scsi_debug/adapter*/host*/target*/*:*/block') + time.sleep(0.1) + assert len(dirs) == 1 + + # determine the debug block devices + devs = os.listdir(dirs[0]) + assert len(devs) == 1 + dev = '/dev/' + devs[0] + assert os.path.exists(dev) + + # let's be 100% sure that we pick a virtual one + assert open('/sys/block/%s/device/model' % devs[0]).read().strip() == 'scsi_debug' + + print('Set up test device: ' + dev) + return dev + + @classmethod + def teardown_vdev(klass, device): + '''release and remove virtual test device''' + + klass.remove_device(device) + assert subprocess.call(['rmmod', 'scsi_debug']) == 0, \ + 'Failure to rmmod scsi_debug' + + @classmethod + def remove_device(klass, device): + '''remove virtual test device''' + + device = device.split('/')[-1] + if os.path.exists('/sys/block/' + device): + f = open('/sys/block/%s/device/delete' % device, 'w') + f.write('1') + f.close() + while os.path.exists(device): + time.sleep(0.1) + klass.sync() + time.sleep(0.5) # TODO + + @classmethod + def readd_devices(klass): + '''re-add virtual test devices after removal''' + + scan_files = glob('/sys/bus/pseudo/devices/adapter*/host*/scsi_host/host*/scan') + assert len(scan_files) > 0 + for f in scan_files: + open(f, 'w').write('- - -\n') + while not os.path.exists(klass.device): + time.sleep(0.1) + time.sleep(0.5) + klass.sync() + +# ---------------------------------------------------------------------------- + +class Manager(UDisksTestCase): + '''UDisksManager operations''' + + def test_version(self): + '''daemon version''' + + self.assertTrue(self.manager.get_property('version')[0].isdigit()) + + def test_loop_rw(self): + '''loop device R/W''' + + with tempfile.NamedTemporaryFile() as f: + f.truncate(100000000) + fd_list = Gio.UnixFDList.new_from_array([f.fileno()]) + + (path, out_fd_list) = self.manager.call_loop_setup_sync( + GLib.Variant('h', 0), # fd index + no_options, + fd_list, + None) + self.client.settle() + + obj = self.client.get_object(path) + loop = obj.get_property('loop') + block = obj.get_property('block') + self.assertNotEqual(block, None) + self.assertNotEqual(loop, None) + self.assertEqual(obj.get_property('filesystem'), None) + + try: + self.assertEqual(loop.get_property('backing-file'), f.name) + + options = GLib.Variant('a{sv}', {'label': GLib.Variant('s', 'foo')}) + block.call_format_sync('ext2', options, None) + self.client.settle() + self.assertNotEqual(obj.get_property('filesystem'), None) + + self.assertEqual(block.get_property('id-label'), 'foo') + self.assertEqual(block.get_property('id-usage'), 'filesystem') + self.assertEqual(block.get_property('id-type'), 'ext2') + finally: + loop.call_delete_sync(no_options, None) + + def test_loop_ro(self): + '''loop device R/O''' + + with tempfile.NamedTemporaryFile() as f: + f.truncate(100000000) + fd_list = Gio.UnixFDList.new_from_array([f.fileno()]) + + (path, out_fd_list) = self.manager.call_loop_setup_sync( + GLib.Variant('h', 0), # fd index + GLib.Variant('a{sv}', {'read-only': GLib.Variant('b', True)}), + fd_list, + None) + self.client.settle() + + obj = self.client.get_object(path) + loop = obj.get_property('loop') + block = obj.get_property('block') + self.assertNotEqual(block, None) + self.assertNotEqual(loop, None) + self.assertEqual(obj.get_property('filesystem'), None) + + try: + self.assertEqual(loop.get_property('backing-file'), f.name) + + # can't format due to permission error + self.assertRaises(GLib.GError, block.call_format_sync, 'ext2', + no_options, None) + + self.assertEqual(block.get_property('id-label'), '') + self.assertEqual(block.get_property('id-usage'), '') + self.assertEqual(block.get_property('id-type'), '') + finally: + self.client.settle() + loop.call_delete_sync(no_options, None) + +# ---------------------------------------------------------------------------- + +class Drive(UDisksTestCase): + '''UDisksDrive''' + + def setUp(self): + self.drive = self.client.get_drive_for_block(self.udisks_block()) + self.assertNotEqual(self.drive, None) + + def test_properties(self): + '''properties of UDisksDrive object''' + + self.assertEqual(self.drive.get_property('model'), 'scsi_debug') + self.assertEqual(self.drive.get_property('vendor'), 'Linux') + self.assertAlmostEqual(self.drive.get_property('size')/1.e6, VDEV_SIZE/1.e6, 0) + self.assertEqual(self.drive.get_property('media-available'), True) + self.assertEqual(self.drive.get_property('optical'), False) + + self.assertNotEqual(len(self.drive.get_property('serial')), 0) + self.assertNotEqual(len(self.drive.get_property('revision')), 0) + +# ---------------------------------------------------------------------------- + +class FS(UDisksTestCase): + '''Test detection of all supported file systems''' + + def setUp(self): + self.workdir = tempfile.mkdtemp() + self.block = self.udisks_block() + self.assertNotEqual(self.block, None) + + def tearDown(self): + if subprocess.call(['umount', self.device], stderr=subprocess.PIPE) == 0: + sys.stderr.write('[cleanup unmount] ') + shutil.rmtree (self.workdir) + + def test_zero(self): + '''properties of zeroed out device''' + + self.zero_device() + self.assertEqual(self.block.get_property('device'), self.device) + self.assertTrue('Linux_scsi_debug' in self.block.get_property('drive')) + self.assertEqual(self.block.get_property('hint-system'), True) + self.assertEqual(self.block.get_property('id-label'), '') + self.assertEqual(self.block.get_property('id-usage'), '') + self.assertEqual(self.block.get_property('id-type'), '') + self.assertEqual(self.block.get_property('id-uuid'), '') + self.assertAlmostEqual(self.block.get_property('size')/1.e6, VDEV_SIZE/1.e6, 0) + obj = self.client.get_object(self.block.get_object_path()) + self.assertEqual(obj.get_property('filesystem'), None) + self.assertEqual(obj.get_property('partition'), None) + self.assertEqual(obj.get_property('partition-table'), None) + + def test_ext2(self): + '''fs: ext2''' + self._do_fs_check('ext2') + + def test_ext3(self): + '''fs: ext3''' + self._do_fs_check('ext3') + + def test_ext4(self): + '''fs: ext4''' + self._do_fs_check('ext4') + + def test_btrfs(self): + '''fs: btrfs''' + self._do_fs_check('btrfs') + + def test_minix(self): + '''fs: minix''' + self._do_fs_check('minix') + + def test_xfs(self): + '''fs: XFS''' + self._do_fs_check('xfs') + + def test_ntfs(self): + '''fs: NTFS''' + self._do_fs_check('ntfs') + + def test_vfat(self): + '''fs: FAT''' + self._do_fs_check('vfat') + + def test_reiserfs(self): + '''fs: reiserfs''' + self._do_fs_check('reiserfs') + + def test_swap(self): + '''fs: swap''' + self._do_fs_check('swap') + + def test_nilfs2(self): + '''fs: nilfs2''' + self._do_fs_check('nilfs2') + + def test_empty(self): + '''fs: empty''' + + self.mkfs('ext4', 'foo') + block = self.udisks_block() + self.assertEqual(block.get_property('id-usage'), 'filesystem') + self.assertEqual(block.get_property('id-type'), 'ext4') + self.assertEqual(block.get_property('id-label'), 'foo') + self.assertNotEqual(self.udisks_filesystem(), None) + + self.fs_create(None, 'empty', no_options) + + self.assertEqual(block.get_property('id-usage'), '') + self.assertEqual(block.get_property('id-type'), '') + self.assertEqual(block.get_property('id-label'), '') + self.assertEqual(self.udisks_filesystem(), None) + + def test_create_fs_unknown_type(self): + '''Format() with unknown type''' + + try: + self.fs_create(None, 'bogus', no_options) + self.fail('Expected failure for bogus file system') + except GLib.GError as e: + self.assertTrue('UDisks2.Error.NotSupported' in e.message) + self.assertTrue('type bogus' in e.message) + + def test_create_fs_unsupported_label(self): + '''Format() with unsupported label''' + + options = GLib.Variant('a{sv}', {'label': GLib.Variant('s', 'foo')}) + try: + self.fs_create(None, 'minix', options) + self.fail('Expected failure for unsupported label') + except GLib.GError as e: + self.assertTrue('UDisks2.Error.NotSupported' in e.message) + + def test_force_removal(self): + '''fs: forced removal''' + + # create a fs and mount it + self.mkfs('ext4', 'udiskstest') + fs = self.udisks_filesystem() + mount_path = fs.call_mount_sync(no_options, None) + self.assertTrue(mount_path.endswith('udiskstest')) + self.assertTrue('/media/' in mount_path) + self.assertTrue(self.is_mountpoint(mount_path)) + + dev_t = os.stat(self.devname()).st_rdev + + # removal should clean up mounts + self.remove_device(self.device) + self.assertFalse(os.path.exists(mount_path)) + self.assertEqual(self.client.get_block_for_dev(dev_t), None) + + # after putting it back, it should be mountable again + self.readd_devices() + fs = self.udisks_filesystem() + self.assertEqual(fs.get_property('mount-points'), []) + + mount_path = fs.call_mount_sync(no_options, None) + self.assertTrue(mount_path.endswith('udiskstest')) + self.assertTrue('/media/' in mount_path) + self.assertTrue(self.is_mountpoint(mount_path)) + self.client.settle() + self.assertEqual(fs.get_property('mount-points'), [mount_path]) + + self.retry_busy(fs.call_unmount_sync, no_options, None) + self.client.settle() + self.assertEqual(fs.get_property('mount-points'), []) + + def _do_fs_check(self, type): + '''Run checks for a particular file system.''' + + if type != 'swap' and subprocess.call(['which', 'mkfs.' + type], + stdout=subprocess.PIPE) != 0: + sys.stderr.write('[no mkfs.%s, skip] ' % type) + + # check correct D-Bus exception + try: + self.fs_create(None, type, no_options) + self.fail('Expected failure for missing mkfs.' + type) + except GLib.GError as e: + self.assertTrue('UDisks2.Error.Failed' in e.message) + return + + # do checks with command line tools (mkfs/mount/umount) + sys.stderr.write('[cli] ') + sys.stderr.flush() + + self._do_cli_check(type) + if type != 'minix': + self._do_cli_check(type, 'test%stst' % type) + + # put a different fs here instead of zeroing, so that we verify that + # udisks overrides existing FS (e. g. XFS complains then), and does not + # leave traces of other FS around + if type == 'ext3': + self.mkfs('swap') + else: + self.mkfs('ext3') + + # do checks with udisks operations + sys.stderr.write('[ud] ') + self._do_udisks_check(type) + if type != 'minix': + self._do_udisks_check(type, 'test%stst' % type) + # also test fs_create with an empty label + self._do_udisks_check(type, '') + + def _do_cli_check(self, type, label=None): + '''udisks correctly picks up file system changes from command line tools''' + + self.mkfs(type, label) + + block = self.udisks_block() + + self.assertEqual(block.get_property('id-usage'), (type == 'swap') and 'other' or 'filesystem') + + self.assertEqual(block.get_property('id-type'), type) + self.assertEqual(block.get_property('id-label'), label or '') + self.assertEqual(block.get_property('hint-name'), '') + if type != 'minix': + self.assertEqual(block.get_property('id-uuid'), self.blkid()['ID_FS_UUID']) + + obj = self.client.get_object(self.block.get_object_path()) + self.assertEqual(obj.get_property('partition'), None) + self.assertEqual(obj.get_property('partition-table'), None) + + fs = obj.get_property('filesystem') + if type == 'swap': + self.assertEqual(fs, None) + else: + self.assertNotEqual(fs, None) + + if type == 'swap': + return + + # mount it + if type == 'ntfs' and subprocess.call(['which', 'mount.ntfs-3g'], + stdout=subprocess.PIPE) == 0: + # prefer mount.ntfs-3g if we have it (on Debian; Ubuntu + # defaults to ntfs-3g if installed); TODO: check other distros + mount_prog = 'mount.ntfs-3g' + else: + mount_prog = 'mount' + ret = subprocess.call([mount_prog, self.device, self.workdir]) + if ret == 32: + # missing fs driver + sys.stderr.write('[missing kernel driver, skip] ') + return + self.assertEqual(ret, 0) + + self.sync() + self.assertEqual(fs.get_property('mount-points'), [self.workdir]) + + # unmount it + subprocess.call(['umount', self.workdir]) + self.sync() + self.assertEqual(fs.get_property('mount-points'), []) + + def _do_udisks_check(self, type, label=None): + '''udisks API correctly changes file system''' + + # create fs + if label is not None: + options = GLib.Variant('a{sv}', {'label': GLib.Variant('s', label)}) + else: + options = no_options + self.fs_create(None, type, options) + + # properties + id = self.blkid() + self.assertEqual(id['ID_FS_USAGE'], type == 'swap' and 'other' or 'filesystem') + self.assertEqual(id['ID_FS_TYPE'], type) + self.assertEqual(id.get('ID_FS_LABEL', ''), label or '') + + block = self.udisks_block() + self.assertEqual(block.get_property('id-usage'), (type == 'swap') and 'other' or 'filesystem') + self.assertEqual(block.get_property('id-type'), type) + self.assertEqual(block.get_property('id-label'), label or '') + + if type == 'swap': + return + + obj = self.client.get_object(self.block.get_object_path()) + self.assertEqual(obj.get_property('partition'), None) + self.assertEqual(obj.get_property('partition-table'), None) + + fs = self.udisks_filesystem() + self.assertNotEqual(fs, None, 'no Filesystem interface for test device') + self.assertEqual(fs.get_property('mount-points'), []) + + # mount + mount_path = fs.call_mount_sync(no_options, None) + + self.assertTrue(mount_path.startswith('/run/media/'), mount_path) + if label: + self.assertTrue(mount_path.endswith(label)) + + self.sync() + self.assertEqual(fs.get_property('mount-points'), [mount_path]) + self.assertTrue(self.is_mountpoint(mount_path)) + + # no ownership taken, should be root owned + st = os.stat(mount_path) + self.assertEqual((st.st_uid, st.st_gid), (0, 0)) + + self._do_file_perms_checks(type, mount_path) + + # unmount + self.retry_busy(fs.call_unmount_sync, no_options, None) + self.assertFalse(os.path.exists(mount_path), 'mount point was not removed') + self.assertEqual(fs.get_property('mount-points'), [mount_path]) + + # create fs with taking ownership (daemon:mail == 1:8) + #if supports_unix_owners: + # options.append('take_ownership_uid=1') + # options.append('take_ownership_gid=8') + # self.fs_create(None, type, options) + # mount_path = iface.FilesystemMount('', []) + # st = os.stat(mount_path) + # self.assertEqual((st.st_uid, st.st_gid), (1, 8)) + # self.retry_busy(self.partition_iface().FilesystemUnmount, []) + # self.assertFalse(os.path.exists(mount_path), 'mount point was not removed') + + # change label + supported = True + l = 'n"a\m\\"e' + type + if type == 'vfat': + # VFAT does not support some characters + self.assertRaises(GLib.GError, fs.call_set_label_sync, l, + no_options, None) + l = "n@a$me" + try: + fs.call_set_label_sync(l, no_options, None) + except GLib.GError as e: + if 'UDisks2.Error.NotSupported' in e.message: + # these fses are known to not support relabeling + self.assertTrue(type in ['minix', 'btrfs']) + supported = False + else: + raise + + if supported: + block = self.udisks_block() + blkid_label = self.blkid().get('ID_FS_LABEL_ENC', '').replace('\\x22', '"').replace( + '\\x5c', '\\').replace('\\x24', '$') + self.sync_workaround() + if type == 'vfat': + # EXFAIL: often (but not always) the label appears in all upper case + self.assertEqual(blkid_label.upper(), l.upper()) + self.assertEqual(block.get_property('id-label').upper(), l.upper()) + else: + self.assertEqual(blkid_label, l) + self.assertEqual(block.get_property('id-label'), l) + + # test setting empty label + fs.call_set_label_sync('', no_options, None) + self.sync_workaround() + self.assertEqual(self.blkid().get('ID_FS_LABEL_ENC', ''), '') + self.assertEqual(block.get_property('id-label'), '') + + # check fs - Not implemented in udisks yet + #self.assertEqual(iface.FilesystemCheck([]), True) + + def _do_file_perms_checks(self, type, mount_point): + '''Check for permissions for data files and executables. + + This particularly checks sane and useful permissions on non-Unix file + systems like vfat. + ''' + if type in BROKEN_PERMISSIONS_FS: + return + + f = os.path.join(mount_point, 'simpledata.txt') + open(f, 'w').close() + self.assertTrue(os.access(f, os.R_OK)) + self.assertTrue(os.access(f, os.W_OK)) + self.assertFalse(os.access(f, os.X_OK)) + + f = os.path.join(mount_point, 'simple.exe') + shutil.copy('/bin/bash', f) + self.assertTrue(os.access(f, os.R_OK)) + self.assertTrue(os.access(f, os.W_OK)) + self.assertTrue(os.access(f, os.X_OK)) + + os.mkdir(os.path.join(mount_point, 'subdir')) + f = os.path.join(mount_point, 'subdir', 'subdirdata.txt') + open(f, 'w').close() + self.assertTrue(os.access(f, os.R_OK)) + self.assertTrue(os.access(f, os.W_OK)) + self.assertFalse(os.access(f, os.X_OK)) + + f = os.path.join(mount_point, 'subdir', 'subdir.exe') + shutil.copy('/bin/bash', f) + self.assertTrue(os.access(f, os.R_OK)) + self.assertTrue(os.access(f, os.W_OK)) + self.assertTrue(os.access(f, os.X_OK)) + +## ---------------------------------------------------------------------------- + +class Smart(UDisksTestCase): + '''Check SMART operation.''' + + def test_sda(self): + '''SMART status of first internal hard disk + + This is a best-effort readonly test. + ''' + hd = '/dev/sda' + + if not os.path.exists(hd): + sys.stderr.write('[skip] ') + return + + has_smart = subprocess.call(['skdump', '--can-smart', hd], + stdout=subprocess.PIPE, stderr=subprocess.STDOUT) == 0 + + block = self.client.get_block_for_dev(os.stat(hd).st_rdev) + self.assertNotEqual(block, None) + drive = self.client.get_drive_for_block(block) + ata = self.client.get_object(drive.get_object_path()).get_property('drive-ata') + self.assertEqual(ata != None, has_smart) + + if has_smart: + sys.stderr.write('[avail] ') + self.assertEqual(ata.get_property('smart-supported'), True) + self.assertEqual(ata.get_property('smart-enabled'), True) + + # wait for SMART data to be read + while ata.get_property('smart-updated') == 0: + sys.stderr.write('[wait for data] ') + time.sleep(0.5) + + # this is of course not truly correct for a test suite, but let's + # consider it a courtesy for developers :-) + self.assertEqual(ata.get_property('smart-failing'), False) + self.assertTrue(ata.get_property('smart-selftest-status') in ['success', 'inprogress']) + else: + sys.stderr.write('[N/A] ') + + +# ---------------------------------------------------------------------------- + +class Luks(UDisksTestCase): + '''Check LUKS.''' + + def tearDown(self): + '''clean up behind failed test cases''' + + crypt_obj = self.client.get_object(self.udisks_block().get_object_path()) + if crypt_obj: + encrypted = crypt_obj.get_property('encrypted') + if encrypted: + try: + encrypted.call_lock_sync(no_options, None) + sys.stderr.write('[cleanup lock] ') + except GLib.GError: + pass + + # needs to run before the other tests + def test_0_create_teardown(self): + '''LUKS create/teardown''' + + self.fs_create(None, 'ext4', GLib.Variant('a{sv}', { + 'encrypt.passphrase': GLib.Variant('s', 's3kr1t'), + 'label': GLib.Variant('s', 'treasure'), + })) + + try: + block = self.udisks_block() + obj = self.client.get_object(block.get_object_path()) + self.assertEqual(obj.get_property('filesystem'), None) + encrypted = obj.get_property('encrypted') + self.assertNotEqual(encrypted, None) + + # check crypted device info + self.assertEqual(block.get_property('id-type'), 'crypto_LUKS') + self.assertEqual(block.get_property('id-usage'), 'crypto') + self.assertEqual(block.get_property('id-label'), '') + self.assertEqual(block.get_property('id-uuid'), self.blkid()['ID_FS_UUID']) + self.assertEqual(block.get_property('device'), self.devname()) + + # check whether we can lock/unlock; we also need this to get the + # cleartext device + encrypted.call_lock_sync(no_options, None) + self.assertRaises(GLib.GError, encrypted.call_lock_sync, + no_options, None) + + # wrong password + self.assertRaises(GLib.GError, encrypted.call_unlock_sync, + 'h4ckpassword', no_options, None) + # right password + clear_path = encrypted.call_unlock_sync('s3kr1t', + no_options, None) + + # check cleartext device info + clear_obj = self.client.get_object(clear_path) + self.assertEqual(clear_obj.get_property('encrypted'), None) + clear_block = clear_obj.get_property('block') + self.assertEqual(clear_block.get_property('id-type'), 'ext4') + self.assertEqual(clear_block.get_property('id-usage'), 'filesystem') + self.assertEqual(clear_block.get_property('id-label'), 'treasure') + self.assertNotEqual(clear_block.get_property('crypto-backing-device'), None) + clear_dev = clear_block.get_property('device') + self.assertNotEqual(clear_dev, None) + self.assertEqual(clear_block.get_property('id-uuid'), + self.blkid(device=clear_dev)['ID_FS_UUID']) + + clear_fs = clear_obj.get_property('filesystem') + self.assertEqual(clear_fs.get_property('mount-points'), []) + + # check that we do not leak key information + udev_dump = subprocess.Popen(['udevadm', 'info', '--export-db'], + stdout=subprocess.PIPE) + out = udev_dump.communicate()[0] + self.assertFalse(b's3kr1t' in out, 'password in udev properties') + self.assertFalse(b'essiv:sha' in out, 'key information in udev properties') + + finally: + # tear down cleartext device + encrypted.call_lock_sync(no_options, None) + self.assertFalse(os.path.exists(clear_dev)) + + def test_luks_mount(self): + '''LUKS mount/unmount''' + + crypt_obj = self.client.get_object(self.udisks_block().get_object_path()) + encrypted = crypt_obj.get_property('encrypted') + + path = encrypted.call_unlock_sync('s3kr1t', + no_options, None) + self.client.settle() + obj = self.client.get_object(path) + fs = obj.get_property('filesystem') + self.assertNotEqual(fs, None) + + # mount + mount_path = fs.call_mount_sync(no_options, None) + + try: + self.assertTrue('/media/' in mount_path) + self.assertTrue(mount_path.endswith('treasure')) + self.assertTrue(self.is_mountpoint(mount_path)) + self.client.settle() + self.assertEqual(fs.get_property('mount-points'), [mount_path]) + + # can't lock, busy + try: + encrypted.call_lock_sync(no_options, None) + self.fail('Lock() unexpectedly succeeded on mounted file system') + except GLib.GError as e: + self.assertTrue('UDisks2.Error.Failed' in e.message) + finally: + # umount + self.retry_busy(fs.call_unmount_sync, no_options, None) + self.client.settle() + self.assertFalse(os.path.exists(mount_path), 'mount point was not removed') + self.assertEqual(fs.get_property('mount-points'), []) + + # lock + encrypted.call_lock_sync(no_options, None) + self.client.settle() + self.assertEqual(self.client.get_object(path), None) + + def test_luks_forced_removal(self): + '''LUKS forced removal''' + + # unlock and mount it + crypt_obj = self.client.get_object(self.udisks_block().get_object_path()) + path = crypt_obj.get_property('encrypted').call_unlock_sync('s3kr1t', + no_options, None) + try: + fs = self.client.get_object(path).get_property('filesystem') + mount_path = fs.call_mount_sync(no_options, None) + self.assertTrue('/media/' in mount_path) + self.assertTrue(mount_path.endswith('treasure')) + + # removal should clean up mounts + self.remove_device(self.device) + self.assertFalse(os.path.exists(mount_path)) + self.assertEqual(self.client.get_object(path), None) + + # after putting it back, it should be mountable again + self.readd_devices() + crypt_obj = self.client.get_object(self.udisks_block().get_object_path()) + path = crypt_obj.get_property('encrypted').call_unlock_sync('s3kr1t', + no_options, None) + self.client.settle() + fs = self.client.get_object(path).get_property('filesystem') + mount_path = fs.call_mount_sync(no_options, None) + self.assertTrue('/media/' in mount_path) + self.assertTrue(mount_path.endswith('treasure')) + + # umount + self.retry_busy(fs.call_unmount_sync, no_options, None) + self.client.settle() + self.assertFalse(os.path.exists(mount_path), 'mount point was not removed') + self.assertEqual(fs.get_property('mount-points'), []) + finally: + # lock + crypt_obj.get_property('encrypted').call_lock_sync( + no_options, None) + self.client.settle() + self.assertEqual(self.client.get_object(path), None) + +# ---------------------------------------------------------------------------- + +class Polkit(UDisksTestCase): + '''Check operation with polkit.''' + + def setUp(self): + env = os.environ.copy() + env['POLKIT_DEBUG'] = '1' + self.polkit = subprocess.Popen([self.polkit_path], + stdout=self.daemon_log, stderr=subprocess.STDOUT, env=env) + assert self.polkit.pid, 'polkitd failed to start' + + def tearDown(self): + os.kill(self.polkit.pid, signal.SIGTERM) + os.waitpid(self.polkit.pid, 0) + + def test_internal_fs_root(self): + '''Create FS on internal drive as root''' + + options = GLib.Variant('a{sv}', {'label': GLib.Variant('s', 'polkitext4')}) + self.fs_create(None, 'ext4', options) + block = self.udisks_block() + self.assertEqual(block.get_property('id-usage'), 'filesystem') + self.assertEqual(block.get_property('id-type'), 'ext4') + self.assertEqual(block.get_property('id-label'), 'polkitext4') + + def test_internal_fs_nobody(self): + '''Try to create FS on internal drive as nobody''' + + # ensure we have a mountable file system + self.fs_create(None, 'ext4', no_options) + + nobody = pwd.getpwnam('nobody') + assert nobody.pw_uid > 0 + + # we cannot just change euid and do the call, as polkit will remember + # our process which started out as root; so call the external tool + tool_mount = subprocess.Popen([self.tool_path, 'mount', + '--no-user-interaction', '-b', self.device], + stdout=subprocess.PIPE, stderr=subprocess.PIPE, + universal_newlines=True, + preexec_fn=lambda: (os.setgid(nobody.pw_gid), os.setuid(nobody.pw_uid))) + out, err = tool_mount.communicate() + self.assertTrue('Error.NotAuthorized' in err, err) + +# ---------------------------------------------------------------------------- + +if __name__ == '__main__': + argparser = argparse.ArgumentParser(description='udisks2 integration test suite') + argparser.add_argument('-l', '--log-file', dest='logfile', + help='write daemon log to a file') + argparser.add_argument('-w', '--no-workarounds', + action="store_true", default=False, + help='Disable workarounds for race conditions in the D-BUS API') + argparser.add_argument('testname', nargs='*', + help='name of test class or method (e. g. "Drive", "FS.test_ext2")') + args = argparser.parse_args() + + workaround_syncs = not args.no_workarounds + + UDisksTestCase.init(logfile=args.logfile) + if args.testname: + tests = unittest.TestLoader().loadTestsFromNames(args.testname, + __import__('__main__')) + else: + tests = unittest.TestLoader().loadTestsFromName('__main__') + if unittest.TextTestRunner(verbosity=2).run(tests).wasSuccessful(): + sys.exit(0) + else: + sys.exit(1) + diff -Nru udisks2-1.97.0/debian/patches/00git_no_polkit_fallback.patch udisks2-1.98.0/debian/patches/00git_no_polkit_fallback.patch --- udisks2-1.97.0/debian/patches/00git_no_polkit_fallback.patch 1970-01-01 00:00:00.000000000 +0000 +++ udisks2-1.98.0/debian/patches/00git_no_polkit_fallback.patch 2012-06-13 15:01:38.000000000 +0000 @@ -0,0 +1,53 @@ +commit f66346217c233f9689c3ad73312597821da94a82 +Author: David Zeuthen +Date: Fri Jun 8 13:43:35 2012 -0400 + + Catch up with latest polkit guidance + + See + + http://cgit.freedesktop.org/polkit/commit/?id=acf3a06e55f9ca8a7f7bfa012c24e8794d27c85f + https://bugzilla.gnome.org/show_bug.cgi?id=677718 + + for details. + + Signed-off-by: David Zeuthen + +diff --git a/src/udisksdaemonutil.c b/src/udisksdaemonutil.c +index 9a2e601..723cffe 100644 +--- a/src/udisksdaemonutil.c ++++ b/src/udisksdaemonutil.c +@@ -652,14 +652,25 @@ udisks_daemon_util_check_authorization_sync (UDisksDaemon *daemon, + &error); + if (result == NULL) + { +- g_dbus_method_invocation_return_error (invocation, +- UDISKS_ERROR, +- UDISKS_ERROR_FAILED, +- "Error checking authorization: %s (%s, %d)", +- error->message, +- g_quark_to_string (error->domain), +- error->code); +- g_error_free (error); ++ if (error->domain != POLKIT_ERROR) ++ { ++ /* assume polkit authority is not available (e.g. could be the service ++ * manager returning org.freedesktop.systemd1.Masked) ++ */ ++ g_error_free (error); ++ ret = check_authorization_no_polkit (daemon, object, action_id, options, message, invocation); ++ } ++ else ++ { ++ g_dbus_method_invocation_return_error (invocation, ++ UDISKS_ERROR, ++ UDISKS_ERROR_FAILED, ++ "Error checking authorization: %s (%s, %d)", ++ error->message, ++ g_quark_to_string (error->domain), ++ error->code); ++ g_error_free (error); ++ } + goto out; + } + if (!polkit_authorization_result_get_is_authorized (result)) diff -Nru udisks2-1.97.0/debian/patches/series udisks2-1.98.0/debian/patches/series --- udisks2-1.97.0/debian/patches/series 2012-05-18 09:31:18.000000000 +0000 +++ udisks2-1.98.0/debian/patches/series 2012-06-13 15:01:38.000000000 +0000 @@ -1 +1,2 @@ # Debian patches for udisks +00git_no_polkit_fallback.patch diff -Nru udisks2-1.97.0/debian/tests/control udisks2-1.98.0/debian/tests/control --- udisks2-1.97.0/debian/tests/control 1970-01-01 00:00:00.000000000 +0000 +++ udisks2-1.98.0/debian/tests/control 2012-06-13 15:01:38.000000000 +0000 @@ -0,0 +1,4 @@ +Tests: upstream-system +Depends: udisks2, python3, python3-gi, gir1.2-glib-2.0, gir1.2-udisks-2.0, reiserfsprogs, xfsprogs, ntfs-3g, mtools, lvm2, mdadm, cryptsetup-bin, kpartx, libatasmart-bin, policykit-1 +Restrictions: needs-root +Features: no-build-needed diff -Nru udisks2-1.97.0/debian/tests/upstream-system udisks2-1.98.0/debian/tests/upstream-system --- udisks2-1.97.0/debian/tests/upstream-system 1970-01-01 00:00:00.000000000 +0000 +++ udisks2-1.98.0/debian/tests/upstream-system 2012-06-13 15:01:38.000000000 +0000 @@ -0,0 +1,5 @@ +#!/bin/sh +set -e + +# succeeding test must not write anything to stderr, as per DEP-8 +debian/local/integration-test 2>&1 diff -Nru udisks2-1.97.0/doc/html/ch02.html udisks2-1.98.0/doc/html/ch02.html --- udisks2-1.97.0/doc/html/ch02.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/ch02.html 2012-06-07 18:39:06.000000000 +0000 @@ -21,7 +21,7 @@

-D-Bus Interfaces

+D-Bus Interfaces
org.freedesktop.UDisks2.Manager — Manager singleton diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Block.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Block.html --- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Block.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Block.html 2012-06-07 18:39:06.000000000 +0000 @@ -58,7 +58,7 @@
-

Properties

+

Properties

 Device               readable   ay
 PreferredDevice      readable   ay
diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Drive.Ata.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Drive.Ata.html
--- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Drive.Ata.html	2012-05-09 17:58:48.000000000 +0000
+++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Drive.Ata.html	2012-06-07 18:39:06.000000000 +0000
@@ -49,7 +49,7 @@
 
-

Properties

+

Properties

 SmartSupported                     readable   b
 SmartEnabled                       readable   b
@@ -86,18 +86,8 @@
 

The option atasmart_blob can be used to inject libatasmart compatible blobs for testing how clients react to different - kinds of SMART data. Only uid 0 may use this. This option may - be removed in the future with it being considered an ABI break - - it only exists for testing purposes. Example: -

-
-# export ATA_SMART_BLOB=/usr/share/doc/libatasmart-devel-0.17/Maxtor_96147H8--BAC51KJ0--2 ; \
-  gdbus call --system --dest org.freedesktop.UDisks2 \
-             --object-path /org/freedesktop/UDisks2/drives/WDC_WD1002FAEX_00Y9A0_WD_WCAW30039835 \
-             --method org.freedesktop.UDisks2.Drive.Ata.SmartUpdate \
-             "{'atasmart_blob': <'$ATA_SMART_BLOB'>}"
-
-

+ kinds of SMART data. This option may be removed in the future + with it being considered an ABI break.

diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Drive.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Drive.html --- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Drive.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Drive.html 2012-06-07 18:39:06.000000000 +0000 @@ -44,7 +44,7 @@
-

Properties

+

Properties

 Vendor                 readable   s
 Model                  readable   s
diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Filesystem.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Filesystem.html
--- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Filesystem.html	2012-05-09 17:58:48.000000000 +0000
+++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Filesystem.html	2012-06-07 18:39:06.000000000 +0000
@@ -48,7 +48,7 @@
 
-

Properties

+

Properties

 MountPoints  readable   aay
 
diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Job.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Job.html --- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Job.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Job.html 2012-06-07 18:39:06.000000000 +0000 @@ -46,14 +46,14 @@
-

Signals

+

Signals

 Completed (b success,
            s message);
 
-

Properties

+

Properties

 Progress         readable   d
 StartTime        readable   t
diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Loop.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Loop.html
--- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Loop.html	2012-05-09 17:58:48.000000000 +0000
+++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Loop.html	2012-06-07 18:39:06.000000000 +0000
@@ -46,7 +46,7 @@
 
-

Properties

+

Properties

 BackingFile  readable   ay
 Autoclear    readable   b
diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Manager.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Manager.html
--- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Manager.html	2012-05-09 17:58:48.000000000 +0000
+++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Manager.html	2012-06-07 18:39:06.000000000 +0000
@@ -46,7 +46,7 @@
 
-

Properties

+

Properties

 Version  readable   s
 
diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Partition.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Partition.html --- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Partition.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Partition.html 2012-06-07 18:39:06.000000000 +0000 @@ -50,7 +50,7 @@
-

Properties

+

Properties

 Number       readable   u
 Type         readable   s
diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.PartitionTable.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.PartitionTable.html
--- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.PartitionTable.html	2012-05-09 17:58:48.000000000 +0000
+++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.PartitionTable.html	2012-06-07 18:39:06.000000000 +0000
@@ -49,7 +49,7 @@
 
-

Properties

+

Properties

 Type  readable   s
 
diff -Nru udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Swapspace.html udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Swapspace.html --- udisks2-1.97.0/doc/html/gdbus-org.freedesktop.UDisks2.Swapspace.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/gdbus-org.freedesktop.UDisks2.Swapspace.html 2012-06-07 18:39:06.000000000 +0000 @@ -45,7 +45,7 @@
-

Properties

+

Properties

 Active  readable   b
 
diff -Nru udisks2-1.97.0/doc/html/index.html udisks2-1.98.0/doc/html/index.html --- udisks2-1.97.0/doc/html/index.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/index.html 2012-06-07 18:39:06.000000000 +0000 @@ -15,7 +15,7 @@

- For version 1.97.0 + For version 1.98.0 — the latest version of this documentation can be found at http://udisks.freedesktop.org/docs/latest/.

@@ -26,7 +26,7 @@
I. Manual pages and Overview
-udisks — Introduction to udisks +udisks — Disk Manager
udisksd — The udisks system daemon diff -Nru udisks2-1.97.0/doc/html/index.sgml udisks2-1.98.0/doc/html/index.sgml --- udisks2-1.97.0/doc/html/index.sgml 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/index.sgml 2012-06-07 18:39:06.000000000 +0000 @@ -1303,6 +1303,7 @@ + diff -Nru udisks2-1.97.0/doc/html/ix01.html udisks2-1.98.0/doc/html/ix01.html --- udisks2-1.97.0/doc/html/ix01.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/ix01.html 2012-06-07 18:39:06.000000000 +0000 @@ -21,7 +21,7 @@

-Index

+Index

B

@@ -1327,6 +1327,8 @@
udisks_linux_drive_object_housekeeping, udisks_linux_drive_object_housekeeping ()
+
udisks_linux_drive_object_is_not_in_use, udisks_linux_drive_object_is_not_in_use () +
udisks_linux_drive_object_new, udisks_linux_drive_object_new ()
udisks_linux_drive_object_uevent, udisks_linux_drive_object_uevent () diff -Nru udisks2-1.97.0/doc/html/overview.html udisks2-1.98.0/doc/html/overview.html --- udisks2-1.97.0/doc/html/overview.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/overview.html 2012-06-07 18:39:06.000000000 +0000 @@ -26,7 +26,7 @@

Table of Contents

-udisks — Introduction to udisks +udisks — Disk Manager
udisksd — The udisks system daemon diff -Nru udisks2-1.97.0/doc/html/udisks2.devhelp2 udisks2-1.98.0/doc/html/udisks2.devhelp2 --- udisks2-1.97.0/doc/html/udisks2.devhelp2 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/udisks2.devhelp2 2012-06-07 18:39:06.000000000 +0000 @@ -1019,6 +1019,7 @@ + diff -Nru udisks2-1.97.0/doc/html/udisks2-Utilities.html udisks2-1.98.0/doc/html/udisks2-Utilities.html --- udisks2-1.97.0/doc/html/udisks2-Utilities.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/udisks2-Utilities.html 2012-06-07 18:39:06.000000000 +0000 @@ -249,17 +249,25 @@ via invocation.

-The calling thread is blocked for the duration of the -authentication which may be a very long time unless -auth_no_user_interaction is TRUE. +The calling thread is blocked for the duration of the authorization +check which could be a very long time since it may involve +presenting an authentication dialog and having a human user use +it. If auth.no_user_interaction in options is TRUE +no authentication dialog will be presented and the check is not +expected to take a long time.

-The follow variables can be used in message -

-

-

-
  • udisks2.device - If object has a UDisksBlock interface, this property is set to the value of the "preferred-device" property.

-

+See Table 1, “Known polkit variables” for the variables that +can be used in message but note that not all variables can be used +in all checks. For example, any check involving a UDisksDrive or a +UDisksBlock object can safely include the fragment +$(drive) since it will always expand to the name of +the drive, e.g. INTEL SSDSA2MH080G1GC (/dev/sda1) or +the block device file e.g. /dev/vg_lucifer/lv_root +or /dev/sda1. However this won't work for operations +that isn't on a drive or block device, for example calls on the +Manager +object.

@@ -279,7 +287,7 @@ - diff -Nru udisks2-1.97.0/doc/html/udisks.8.html udisks2-1.98.0/doc/html/udisks.8.html --- udisks2-1.97.0/doc/html/udisks.8.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/udisks.8.html 2012-06-07 18:39:06.000000000 +0000 @@ -24,16 +24,16 @@

options :

A GVariant to check for the auth.no_user_interaction option or NULL. [allow-none] +A GVariant to check for the auth.no_user_interaction option or NULL. [allow-none]

udisks

-

udisks — Introduction to udisks

+

udisks — Disk Manager

-

DESCRIPTION

+

DESCRIPTION

udisks provides interfaces to enumerate and perform operations - on storage devices. Any application (including unprivileged - ones) can access the + on disks and storage devices. Any application (including + unprivileged ones) can access the udisksd(8) daemon via the name org.freedesktop.UDisks2 on the system message bus. In addition to the D-Bus API, a @@ -41,19 +41,14 @@ library can be used from C/C++ and any high-level language with GObjectIntrospection support such as Javascript and Python. -

-

- Except for providing a list of devices, support for udev - properties as well as routines used to present the devices to - the end user, udisks, as a system-level component, is not - involved with what a desktop user interface shows the user. For - GNOME see these GVfs - notes about what is shown in the desktop user interface - and how to influence it. + udisks is only indirectly involved in what devices and objects + are shown in the user interface. See these + notes + for what is shown in GNOME 3.

-

ACCESS CONTROL

+

ACCESS CONTROL

By default, logged-in users in active log-in sessions are permitted to perform operations (for example, mounting, @@ -64,8 +59,6 @@ Checks” chapter in the udisks documentation for more information (available online here). -

-

Note that the x-udisks-auth option can be used in the /etc/fstab and /etc/crypttab files to specify that @@ -75,7 +68,7 @@

-

DEVICE INFORMATION

+

DEVICE INFORMATION

udisks relies on recent versions of udev(7) @@ -136,7 +129,7 @@

-

API STABILITY

+

API STABILITY

udisks guarantees a stable D-Bus API within the same major version and this guarantee also extends to the client-side @@ -172,7 +165,7 @@

-

AUDIENCE

+

AUDIENCE

The intended audience of udisks include operating system developers working on the higher-level parts of the operating @@ -221,14 +214,14 @@

-

AUTHOR

+

AUTHOR

Written by David Zeuthen with a lot of help from many others.

-

BUGS

+

BUGS

Please send bug reports to either the distribution bug tracker or the upstream bug tracker at @@ -236,7 +229,7 @@

-

SEE ALSO

+

SEE ALSO

udev(7), polkit(8), diff -Nru udisks2-1.97.0/doc/html/UDisksCleanup.html udisks2-1.98.0/doc/html/UDisksCleanup.html --- udisks2-1.97.0/doc/html/UDisksCleanup.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/UDisksCleanup.html 2012-06-07 18:39:06.000000000 +0000 @@ -103,7 +103,7 @@ The following files are used:

-

Table 2. Persistent information used for cleanup

+

Table 3. Persistent information used for cleanup

diff -Nru udisks2-1.97.0/doc/html/UDisksClient.html udisks2-1.98.0/doc/html/UDisksClient.html --- udisks2-1.97.0/doc/html/UDisksClient.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/UDisksClient.html 2012-06-07 18:39:06.000000000 +0000 @@ -190,7 +190,7 @@

UDISKS_MINOR_VERSION

-
#define UDISKS_MINOR_VERSION 97
+
#define UDISKS_MINOR_VERSION 98
 

The minor version of the libudisks2 header files. diff -Nru udisks2-1.97.0/doc/html/udisksctl.1.html udisks2-1.98.0/doc/html/udisksctl.1.html --- udisks2-1.97.0/doc/html/udisksctl.1.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/udisksctl.1.html 2012-06-07 18:39:06.000000000 +0000 @@ -35,12 +35,15 @@

udisksctl unmount { --object-path OBJECT | --block-device DEVICE } [--force] [--no-user-interaction]

udisksctl unlock { --object-path OBJECT | --block-device DEVICE } [--no-user-interaction]

udisksctl lock { --object-path OBJECT | --block-device DEVICE } [--no-user-interaction]

+

udisksctl loop-setup --file PATH [--read-only] [--offset OFFSET] [--size SIZE] [--no-user-interaction]

+

udisksctl loop-delete { --object-path OBJECT | --block-device DEVICE } [--no-user-interaction]

+

udisksctl smart-simulate --file PATH { --object-path OBJECT | --block-device DEVICE } [--no-user-interaction]

udisksctl monitor

udisksctl dump

udisksctl help

-

DESCRIPTION

+

DESCRIPTION

udisksctl is a command-line program used to interact with the @@ -49,7 +52,7 @@

-

COMMANDS

+

COMMANDS

@@ -77,11 +80,10 @@ @@ -96,8 +98,31 @@ + + + + + + + + + + + + @@ -122,7 +147,7 @@

unmount

- Unmounts a device previously mounted by - udisksd(8). - The option --force can be used to request - that the device is unmounted even if active references - exists. + Unmounts a device. This only works if the device is + mounted. The option --force can be used + to request that the device is unmounted even if active + references exists.

lock

- Locks a device previously unlocked by - udisksd(8). + Locks a device. This only works if the device is a + cleartext device backed by a cryptotext device. +

loop-setup

+ Sets up a loop device backed by FILE. +

loop-delete

+ Tears down a loop device. +

smart-simulate

+ Sets SMART data from the libatasmart blob given by + FILE - see + /usr/share/doc/libatasmart-devel-VERSION/ + for blobs shipped with libatasmart. This is a debugging + feature used to check that applications act correctly when + a disk is failing.

-

COMMON OPTIONS

+

COMMON OPTIONS

The option --no-user-interaction can be used to request that no interaction (such as the user being @@ -134,7 +159,7 @@

-

AUDIENCE

+

AUDIENCE

This program does not assume that the caller is the super user - it is intended to be used by unprivileged users and @@ -149,21 +174,21 @@

-

BASH COMPLETION

+

BASH COMPLETION

udisksctl ships with a bash completion script to complete commands, objects, block devices and some options.

-

AUTHOR

+

AUTHOR

Written by David Zeuthen with a lot of help from many others.

-

BUGS

+

BUGS

Please send bug reports to either the distribution bug tracker or the upstream bug tracker at @@ -171,7 +196,7 @@

-

SEE ALSO

+

SEE ALSO

udisks(8), udisksd(8), diff -Nru udisks2-1.97.0/doc/html/udisksd.8.html udisks2-1.98.0/doc/html/udisksd.8.html --- udisks2-1.97.0/doc/html/udisksd.8.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/udisksd.8.html 2012-06-07 18:39:06.000000000 +0000 @@ -33,7 +33,7 @@

udisksd [--help] [--replace] [--no-debug] [--no-sigint]

-

DESCRIPTION

+

DESCRIPTION

The udisksd program provides the org.freedesktop.UDisks2 name on the system @@ -51,7 +51,7 @@

-

OPTIONS

+

OPTIONS

@@ -86,14 +86,14 @@
-

AUTHOR

+

AUTHOR

Written by David Zeuthen with a lot of help from many others.

-

BUGS

+

BUGS

Please send bug reports to either the distribution bug tracker or the upstream bug tracker at @@ -101,7 +101,7 @@

-

SEE ALSO

+

SEE ALSO

udisks(8), udisksctl(1), diff -Nru udisks2-1.97.0/doc/html/UDisksDaemon.html udisks2-1.98.0/doc/html/UDisksDaemon.html --- udisks2-1.97.0/doc/html/UDisksDaemon.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/UDisksDaemon.html 2012-06-07 18:39:06.000000000 +0000 @@ -53,7 +53,7 @@ UDisksLinuxProvider * udisks_daemon_get_linux_provider (UDisksDaemon *daemon); UDisksPersistentStore * udisks_daemon_get_persistent_store (UDisksDaemon *daemon); -PolkitAuthority * udisks_daemon_get_authority (UDisksDaemon *daemon); +PolkitAuthority * udisks_daemon_get_authority (UDisksDaemon *daemon); UDisksCleanup * udisks_daemon_get_cleanup (UDisksDaemon *daemon); UDisksObject * (*UDisksDaemonWaitFunc) (UDisksDaemon *daemon, gpointer user_data); @@ -312,7 +312,7 @@


udisks_daemon_get_authority ()

-
PolkitAuthority *   udisks_daemon_get_authority         (UDisksDaemon *daemon);
+
PolkitAuthority *   udisks_daemon_get_authority         (UDisksDaemon *daemon);

Gets the PolicyKit authority used by daemon.

@@ -325,7 +325,7 @@

Returns :

-A PolkitAuthority instance. Do not free, the object is owned by daemon. +A PolkitAuthority instance. Do not free, the object is owned by daemon.
diff -Nru udisks2-1.97.0/doc/html/UDisksLinuxDriveObject.html udisks2-1.98.0/doc/html/UDisksLinuxDriveObject.html --- udisks2-1.97.0/doc/html/UDisksLinuxDriveObject.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/UDisksLinuxDriveObject.html 2012-06-07 18:39:06.000000000 +0000 @@ -64,6 +64,10 @@ guint secs_since_last, GCancellable *cancellable, GError **error); +gboolean udisks_linux_drive_object_is_not_in_use + (UDisksLinuxDriveObject *object, + GCancellable *cancellable, + GError **error);
@@ -311,6 +315,41 @@
+
+
+

udisks_linux_drive_object_is_not_in_use ()

+
gboolean            udisks_linux_drive_object_is_not_in_use
+                                                        (UDisksLinuxDriveObject *object,
+                                                         GCancellable *cancellable,
+                                                         GError **error);
+

+Checks if the drive represented by object is in use and sets +error if so. +

+
++ + + + + + + + + + + + + + + + + + +

object :

A UDisksLinuxDriveObject.

cancellable :

A GCancellable or NULL. [allow-none] +

error :

A GError or NULL.

Returns :

+TRUE if object is not is use, FALSE if error is set.
+

Property Details

diff -Nru udisks2-1.97.0/doc/html/udisks-polkit-actions.html udisks2-1.98.0/doc/html/udisks-polkit-actions.html --- udisks2-1.97.0/doc/html/udisks-polkit-actions.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/udisks-polkit-actions.html 2012-06-07 18:39:06.000000000 +0000 @@ -26,9 +26,8 @@ Many methods and operations offered by udisks requires the calling user to be sufficiently authorized. Whether the user is authorized is checked using polkit - and the administrator can configure polkit's - local authority (but note that the system may be - using another polkit authority implementation). + allowing the administrator to configure fine-grained permissions via + polkit authorization rules.

There is not necessarily a one-to-one relationship between @@ -62,9 +61,109 @@ The polkit actions are not considered stable and may change from release to release so administrators should take notice when upgrading from one version of udisks to another. For - example, .pkla files may need to be - updated to match an updated policy. - For reference, the polkit actions defined by udisks 1.97.0 + example, polkit authorization rules may need to be updated + to match an updated policy. +

+

+ See Table 1, “Known polkit variables” for the + variables that can be used to assist in determining if the + caller is authorized (note that each variable may not be set + for request). For example, a polkit authorization rule for + any of the + org.freedesktop.udisks2.filesystem-mount* + actions can use the device variable + to determine if the caller is authorized to mount a specific + block device. +

+
+

Table 1. Known polkit variables

+
++++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
keyvalue
deviceIf the object is a block device, this property is set to the value of the Block:PreferredDevice property. If set, this is guaranteed to be a device file, for example /dev/vg_lucifer/lv_root or /dev/sda1. If the object is not a block device, this is not set.
driveLike the device variable, but if the object is also a drive, this variable includes Vital Product Data about the drive such as the vendor and model identifiers (if available), for example INTEL SSDSA2MH080G1GC (/dev/sda1). Otherwise is just set to the same value as device. If the object is not a block device, this is not set (it is however set if the object is a block device but not a drive).
drive.wwnIf the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:WWN property.
drive.serialIf the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:Serial property.
drive.vendorIf the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:Vendor property.
drive.modelIf the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:Model property.
drive.revisionIf the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:Revision property.
drive.removableIf the object is a drive (or a block device that is part of a drive), this is set to the string true only if the value of the Drive:Removable property is TRUE.
id.typeIf the object is a block device, this property is set to the value of the Block:IdType property.
id.usageIf the object is a block device, this property is set to the value of the Block:IdUsage property.
id.versionIf the object is a block device, this property is set to the value of the Block:IdVersion property.
id.labelIf the object is a block device, this property is set to the value of the Block:IdLabel property.
id.uuidIf the object is a block device, this property is set to the value of the Block:IdUUID property.
partition.numberIf the object is a partition, this property is set to the value of the Partition:Number property.
partition.typeIf the object is a partition, this property is set to the value of the Partition:Type property.
partition.flagsIf the object is a partition, this property is set to the value of the Partition:Flags property.
partition.nameIf the object is a partition, this property is set to the value of the Partition:Name property.
partition.uuidIf the object is a partition, this property is set to the value of the Partition:UUID property.
+
+

+ For reference, the polkit actions defined by udisks 1.98.0 are included here:

@@ -412,6 +511,17 @@ </defaults> </action> + <!-- Set SMART data from blob --> + <action id="org.freedesktop.udisks2.ata-smart-simulate"> + <_description>Set SMART data from blob</_description> + <_message>Authentication is required to set SMART data from blob</_message> + <defaults> + <allow_any>auth_admin</allow_any> + <allow_inactive>auth_admin</allow_inactive> + <allow_active>auth_admin_keep</allow_active> + </defaults> + </action> + <!-- Start and abort SMART self-tests --> <action id="org.freedesktop.udisks2.ata-smart-selftest"> <_description>Run SMART self-test</_description> diff -Nru udisks2-1.97.0/doc/html/udisks-std-options.html udisks2-1.98.0/doc/html/udisks-std-options.html --- udisks2-1.97.0/doc/html/udisks-std-options.html 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/html/udisks-std-options.html 2012-06-07 18:39:06.000000000 +0000 @@ -29,7 +29,7 @@ The following table lists well-known options:

-

Table 1. Well-known options

+

Table 2. Well-known options

diff -Nru udisks2-1.97.0/doc/man/udisksctl.xml udisks2-1.98.0/doc/man/udisksctl.xml --- udisks2-1.97.0/doc/man/udisksctl.xml 2012-05-04 23:30:24.000000000 +0000 +++ udisks2-1.98.0/doc/man/udisksctl.xml 2012-05-13 16:12:03.000000000 +0000 @@ -73,6 +73,37 @@ udisksctl + loop-setup + --file PATH + --read-only + --offset OFFSET + --size SIZE + --no-user-interaction + + + + udisksctl + loop-delete + + --object-path OBJECT + --block-device DEVICE + + --no-user-interaction + + + + udisksctl + smart-simulate + --file PATH + + --object-path OBJECT + --block-device DEVICE + + --no-user-interaction + + + + udisksctl monitor @@ -126,11 +157,10 @@ - Unmounts a device previously mounted by - udisksd8. - The option can be used to request - that the device is unmounted even if active references - exists. + Unmounts a device. This only works if the device is + mounted. The option can be used + to request that the device is unmounted even if active + references exists. @@ -151,8 +181,40 @@ - Locks a device previously unlocked by - udisksd8. + Locks a device. This only works if the device is a + cleartext device backed by a cryptotext device. + + + + + + + + + Sets up a loop device backed by FILE. + + + + + + + + + Tears down a loop device. + + + + + + + + + Sets SMART data from the libatasmart blob given by + FILE - see + /usr/share/doc/libatasmart-devel-VERSION/ + for blobs shipped with libatasmart. This is a debugging + feature used to check that applications act correctly when + a disk is failing. diff -Nru udisks2-1.97.0/doc/man/udisks.xml udisks2-1.98.0/doc/man/udisks.xml --- udisks2-1.97.0/doc/man/udisks.xml 2012-04-30 18:11:58.000000000 +0000 +++ udisks2-1.98.0/doc/man/udisks.xml 2012-05-14 15:02:51.000000000 +0000 @@ -13,31 +13,26 @@ udisks - Introduction to udisks + Disk Manager DESCRIPTION udisks provides interfaces to enumerate and perform operations - on storage devices. Any application (including unprivileged - ones) can access the + on disks and storage devices. Any application (including + unprivileged ones) can access the udisksd8 daemon via the name org.freedesktop.UDisks2 on the system message bus. In addition to the D-Bus API, a library, libudisks2 is also provided. This library can be used from C/C++ and any high-level language with - GObjectIntrospection + GObjectIntrospection support such as Javascript and Python. - - - Except for providing a list of devices, support for udev - properties as well as routines used to present the devices to - the end user, udisks, as a system-level component, is not - involved with what a desktop user interface shows the user. For - GNOME see these GVfs - notes about what is shown in the desktop user interface - and how to influence it. + udisks is only indirectly involved in what devices and objects + are shown in the user interface. See these + notes + for what is shown in GNOME 3. @@ -54,8 +49,6 @@ more information (available online here). - - Note that the x-udisks-auth option can be used in the /etc/fstab and /etc/crypttab files to specify that diff -Nru udisks2-1.97.0/doc/tmpl/udiskslinuxdriveobject.sgml udisks2-1.98.0/doc/tmpl/udiskslinuxdriveobject.sgml --- udisks2-1.97.0/doc/tmpl/udiskslinuxdriveobject.sgml 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/tmpl/udiskslinuxdriveobject.sgml 2012-06-07 18:39:06.000000000 +0000 @@ -108,3 +108,14 @@ @Returns: + + + + + +@object: +@cancellable: +@error: +@Returns: + + diff -Nru udisks2-1.97.0/doc/udisks2-docs.xml udisks2-1.98.0/doc/udisks2-docs.xml --- udisks2-1.97.0/doc/udisks2-docs.xml 2012-04-30 18:18:36.000000000 +0000 +++ udisks2-1.98.0/doc/udisks2-docs.xml 2012-06-06 17:18:25.000000000 +0000 @@ -135,10 +135,8 @@ calling user to be sufficiently authorized. Whether the user is authorized is checked using polkit - and the administrator can configure polkit's - local authority (but note that the system may be - using another polkit authority implementation). + allowing the administrator to configure fine-grained permissions via + polkit authorization rules. There is not necessarily a one-to-one relationship between @@ -174,8 +172,112 @@ The polkit actions are not considered stable and may change from release to release so administrators should take notice when upgrading from one version of udisks to another. For - example, .pkla files may need to be - updated to match an updated policy. + example, polkit authorization rules may need to be updated + to match an updated policy. + + + See for the + variables that can be used to assist in determining if the + caller is authorized (note that each variable may not be set + for request). For example, a polkit authorization rule for + any of the + org.freedesktop.udisks2.filesystem-mount* + actions can use the device variable + to determine if the caller is authorized to mount a specific + block device. + + +
+ Known polkit variables + + + + key + value + + + + + device + If the object is a block device, this property is set to the value of the Block:PreferredDevice property. If set, this is guaranteed to be a device file, for example /dev/vg_lucifer/lv_root or /dev/sda1. If the object is not a block device, this is not set. + + + drive + Like the device variable, but if the object is also a drive, this variable includes Vital Product Data about the drive such as the vendor and model identifiers (if available), for example INTEL SSDSA2MH080G1GC (/dev/sda1). Otherwise is just set to the same value as device. If the object is not a block device, this is not set (it is however set if the object is a block device but not a drive). + + + + drive.wwn + If the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:WWN property. + + + drive.serial + If the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:Serial property. + + + drive.vendor + If the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:Vendor property. + + + drive.model + If the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:Model property. + + + drive.revision + If the object is a drive (or a block device that is part of a drive), this is set to the value of the Drive:Revision property. + + + drive.removable + If the object is a drive (or a block device that is part of a drive), this is set to the string true only if the value of the Drive:Removable property is TRUE. + + + + id.type + If the object is a block device, this property is set to the value of the Block:IdType property. + + + id.usage + If the object is a block device, this property is set to the value of the Block:IdUsage property. + + + id.version + If the object is a block device, this property is set to the value of the Block:IdVersion property. + + + id.label + If the object is a block device, this property is set to the value of the Block:IdLabel property. + + + id.uuid + If the object is a block device, this property is set to the value of the Block:IdUUID property. + + + + partition.number + If the object is a partition, this property is set to the value of the Partition:Number property. + + + partition.type + If the object is a partition, this property is set to the value of the Partition:Type property. + + + partition.flags + If the object is a partition, this property is set to the value of the Partition:Flags property. + + + partition.name + If the object is a partition, this property is set to the value of the Partition:Name property. + + + partition.uuid + If the object is a partition, this property is set to the value of the Partition:UUID property. + + + + +
+ + For reference, the polkit actions defined by udisks &version; are included here: FIXME: MISSING XINCLUDE CONTENT diff -Nru udisks2-1.97.0/doc/udisks2-sections.txt udisks2-1.98.0/doc/udisks2-sections.txt --- udisks2-1.97.0/doc/udisks2-sections.txt 2012-05-09 17:58:48.000000000 +0000 +++ udisks2-1.98.0/doc/udisks2-sections.txt 2012-06-07 18:39:06.000000000 +0000 @@ -184,6 +184,7 @@ udisks_linux_drive_object_get_device udisks_linux_drive_object_get_devices udisks_linux_drive_object_housekeeping +udisks_linux_drive_object_is_not_in_use UDISKS_TYPE_LINUX_DRIVE_OBJECT UDISKS_LINUX_DRIVE_OBJECT diff -Nru udisks2-1.97.0/NEWS udisks2-1.98.0/NEWS --- udisks2-1.97.0/NEWS 2012-05-09 17:56:39.000000000 +0000 +++ udisks2-1.98.0/NEWS 2012-06-07 18:36:11.000000000 +0000 @@ -1,4 +1,45 @@ ------------ +udisks 1.98.0 +------------ + +The udisks project provides a daemon, tools and libraries to access +and manipulate disks and storage devices. + +Changes since udisks 1.97.0: + +David Zeuthen (15): + Post-release version bump to 1.98.0 + udisksctl: add 'smart-simulate' verb + udisksctl: describe 'loop-setup' and 'loop-delete' verbs + Call it "Disk Manager" and reword some sections of udisks(8) man page + Bug 49842 – Unhandled rootfs on bind mount + Drive: Refuse to eject drives that appear to be in use + Add some documentation about polkit variables + Rename current polkit variables and also add some new ones + Move table with polkit variables to the "Authorization Checks" chapter + If a block device has ID_PATH set, consider it to be a drive + Use "device" instead of "block_device" in the polkit variables + Add id.* and partition.* polkit variables + Rework part of the polkit variable documentation + udisksd: work if polkitd is not available + Update NEWS for release + +Martin Pitt (8): + integration tests: Update expected mount points + integration tests: Suspend gvfs-udisks2-volume-monitor + integration-test: Update expected exception names + integration-test: Mitigate race after mounting + Wait for the correct device after formatting + integration-test: Update expected Luks mount points + integration-test: Quiesce wipefs output + integration-test: Run on temporary local DBus + +Thanks to all our contributors. + +David Zeuthen, +June 7, 2012 + +------------ udisks 1.97.0 ------------ diff -Nru udisks2-1.97.0/src/udisksdaemon.c udisks2-1.98.0/src/udisksdaemon.c --- udisks2-1.97.0/src/udisksdaemon.c 2012-05-04 20:48:27.000000000 +0000 +++ udisks2-1.98.0/src/udisksdaemon.c 2012-06-07 15:46:30.000000000 +0000 @@ -67,6 +67,7 @@ UDisksLinuxProvider *linux_provider; + /* may be NULL if polkit is masked */ PolkitAuthority *authority; UDisksCleanup *cleanup; @@ -101,7 +102,7 @@ udisks_cleanup_stop (daemon->cleanup); g_object_unref (daemon->cleanup); - g_object_unref (daemon->authority); + g_clear_object (&daemon->authority); g_object_unref (daemon->persistent_store); g_object_unref (daemon->object_manager); g_object_unref (daemon->linux_provider); @@ -195,7 +196,7 @@ daemon->authority = polkit_authority_get_sync (NULL, &error); if (daemon->authority == NULL) { - udisks_error ("Error initializing PolicyKit authority: %s (%s, %d)", + udisks_error ("Error initializing polkit authority: %s (%s, %d)", error->message, g_quark_to_string (error->domain), error->code); g_error_free (error); } @@ -433,7 +434,9 @@ * * Gets the PolicyKit authority used by @daemon. * - * Returns: A #PolkitAuthority instance. Do not free, the object is owned by @daemon. + * Returns: A #PolkitAuthority instance or %NULL if the polkit + * authority is not available. Do not free, the object is owned by + * @daemon. */ PolkitAuthority * udisks_daemon_get_authority (UDisksDaemon *daemon) diff -Nru udisks2-1.97.0/src/udisksdaemonutil.c udisks2-1.98.0/src/udisksdaemonutil.c --- udisks2-1.97.0/src/udisksdaemonutil.c 2012-05-04 18:57:50.000000000 +0000 +++ udisks2-1.98.0/src/udisksdaemonutil.c 2012-06-07 15:46:30.000000000 +0000 @@ -21,6 +21,8 @@ #include "config.h" #include +#include + #include #include #include @@ -398,12 +400,86 @@ return ret; } +/* Need this until we can depend on a libpolkit with this bugfix + * + * http://cgit.freedesktop.org/polkit/commit/?h=wip/js-rule-files&id=224f7b892478302dccbe7e567b013d3c73d376fd + */ +static void +_safe_polkit_details_insert (PolkitDetails *details, const gchar *key, const gchar *value) +{ + if (value != NULL && strlen (value) > 0) + polkit_details_insert (details, key, value); +} + +static void +_safe_polkit_details_insert_int (PolkitDetails *details, const gchar *key, gint value) +{ + gchar buf[32]; + snprintf (buf, sizeof buf, "%d", value); + polkit_details_insert (details, key, buf); +} + +static void +_safe_polkit_details_insert_uint64 (PolkitDetails *details, const gchar *key, guint64 value) +{ + gchar buf[32]; + snprintf (buf, sizeof buf, "0x%08llx", (unsigned long long int) value); + polkit_details_insert (details, key, buf); +} + +static gboolean +check_authorization_no_polkit (UDisksDaemon *daemon, + UDisksObject *object, + const gchar *action_id, + GVariant *options, + const gchar *message, + GDBusMethodInvocation *invocation) +{ + gboolean ret = FALSE; + uid_t caller_uid = -1; + GError *error = NULL; + + if (!udisks_daemon_util_get_caller_uid_sync (daemon, + invocation, + NULL, /* GCancellable* */ + &caller_uid, + NULL, /* gid_t *out_gid */ + NULL, /* gchar **out_user_name */ + &error)) + { + g_dbus_method_invocation_return_error (invocation, + UDISKS_ERROR, + UDISKS_ERROR_FAILED, + "Error getting uid for caller with bus name %s: %s (%s, %d)", + g_dbus_method_invocation_get_sender (invocation), + error->message, g_quark_to_string (error->domain), error->code); + g_clear_error (&error); + goto out; + } + + /* only allow root */ + if (caller_uid == 0) + { + ret = TRUE; + } + else + { + g_dbus_method_invocation_return_error_literal (invocation, + UDISKS_ERROR, + UDISKS_ERROR_NOT_AUTHORIZED, + "Not authorized to perform operation (polkit authority not available and caller is not uid 0)"); + } + + out: + return ret; +} + /** * udisks_daemon_util_check_authorization_sync: * @daemon: A #UDisksDaemon. * @object: (allow-none): The #GDBusObject that the call is on or %NULL. * @action_id: The action id to check for. - * @options: (allow-none): A #GVariant to check for the auth.no_user_interaction option or %NULL. + * @options: (allow-none): A #GVariant to check for the auth.no_user_interaction option or %NULL. * @message: The message to convey (use N_). * @invocation: The invocation to check for. * @@ -413,13 +489,24 @@ * authorized, the appropriate error is already returned to the caller * via @invocation. * - * The calling thread is blocked for the duration of the - * authentication which may be a very long time unless - * @auth_no_user_interaction is %TRUE. - * - * The follow variables can be used in @message - * - * - udisks2.device - If @object has a #UDisksBlock interface, this property is set to the value of the #UDisksBlock::preferred-device property. + * The calling thread is blocked for the duration of the authorization + * check which could be a very long time since it may involve + * presenting an authentication dialog and having a human user use + * it. If auth.no_user_interaction in @options is %TRUE + * no authentication dialog will be presented and the check is not + * expected to take a long time. + * + * See for the variables that + * can be used in @message but note that not all variables can be used + * in all checks. For example, any check involving a #UDisksDrive or a + * #UDisksBlock object can safely include the fragment + * $(drive) since it will always expand to the name of + * the drive, e.g. INTEL SSDSA2MH080G1GC (/dev/sda1) or + * the block device file e.g. /dev/vg_lucifer/lv_root + * or /dev/sda1. However this won't work for operations + * that isn't on a drive or block device, for example calls on the + * Manager + * object. * * Returns: %TRUE if caller is authorized, %FALSE if not. */ @@ -431,6 +518,7 @@ const gchar *message, GDBusMethodInvocation *invocation) { + PolkitAuthority *authority = NULL; PolkitSubject *subject = NULL; PolkitDetails *details = NULL; PolkitCheckAuthorizationFlags flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE; @@ -439,10 +527,19 @@ gboolean ret = FALSE; UDisksBlock *block = NULL; UDisksDrive *drive = NULL; + UDisksPartition *partition = NULL; UDisksObject *block_object = NULL; UDisksObject *drive_object = NULL; gboolean auth_no_user_interaction = FALSE; - gchar *details_udisks2_device = NULL; + const gchar *details_device = NULL; + gchar *details_drive = NULL; + + authority = udisks_daemon_get_authority (daemon); + if (authority == NULL) + { + ret = check_authorization_no_polkit (daemon, object, action_id, options, message, invocation); + goto out; + } subject = polkit_system_bus_name_new (g_dbus_method_invocation_get_sender (invocation)); if (options != NULL) @@ -470,8 +567,13 @@ if (drive_object != NULL) drive = udisks_object_get_drive (drive_object); } + + partition = udisks_object_get_partition (object); } + if (block != NULL) + details_device = udisks_block_get_preferred_device (block); + /* If we have a drive, use vendor/model in the message (in addition to Block:preferred-device) */ if (drive != NULL) { @@ -495,25 +597,53 @@ if (block != NULL) { - details_udisks2_device = g_strdup_printf ("%s (%s)", s, udisks_block_get_preferred_device (block)); + details_drive = g_strdup_printf ("%s (%s)", s, udisks_block_get_preferred_device (block)); } else { - details_udisks2_device = s; + details_drive = s; s = NULL; } g_free (s); + + _safe_polkit_details_insert (details, "drive.wwn", udisks_drive_get_wwn (drive)); + _safe_polkit_details_insert (details, "drive.serial", udisks_drive_get_serial (drive)); + _safe_polkit_details_insert (details, "drive.vendor", udisks_drive_get_vendor (drive)); + _safe_polkit_details_insert (details, "drive.model", udisks_drive_get_model (drive)); + _safe_polkit_details_insert (details, "drive.revision", udisks_drive_get_revision (drive)); + if (udisks_drive_get_removable (drive)) + polkit_details_insert (details, "drive.removable", "true"); + } + + if (block != NULL) + { + _safe_polkit_details_insert (details, "id.type", udisks_block_get_id_type (block)); + _safe_polkit_details_insert (details, "id.usage", udisks_block_get_id_usage (block)); + _safe_polkit_details_insert (details, "id.version", udisks_block_get_id_version (block)); + _safe_polkit_details_insert (details, "id.label", udisks_block_get_id_label (block)); + _safe_polkit_details_insert (details, "id.uuid", udisks_block_get_id_uuid (block)); + } + + if (partition != NULL) + { + _safe_polkit_details_insert_int (details, "partition.number", udisks_partition_get_number (partition)); + _safe_polkit_details_insert (details, "partition.type", udisks_partition_get_type_ (partition)); + _safe_polkit_details_insert_uint64 (details, "partition.flags", udisks_partition_get_flags (partition)); + _safe_polkit_details_insert (details, "partition.name", udisks_partition_get_name (partition)); + _safe_polkit_details_insert (details, "partition.uuid", udisks_partition_get_uuid (partition)); } /* Fall back to Block:preferred-device */ - if (details_udisks2_device == NULL && block != NULL) - details_udisks2_device = udisks_block_dup_preferred_device (block); + if (details_drive == NULL && block != NULL) + details_drive = udisks_block_dup_preferred_device (block); - if (details_udisks2_device != NULL) - polkit_details_insert (details, "udisks2.device", details_udisks2_device); + if (details_device != NULL) + polkit_details_insert (details, "device", details_device); + if (details_drive != NULL) + polkit_details_insert (details, "drive", details_drive); error = NULL; - result = polkit_authority_check_authorization_sync (udisks_daemon_get_authority (daemon), + result = polkit_authority_check_authorization_sync (authority, subject, action_id, details, @@ -552,10 +682,11 @@ ret = TRUE; out: - g_free (details_udisks2_device); + g_free (details_drive); g_clear_object (&block_object); g_clear_object (&drive_object); g_clear_object (&block); + g_clear_object (&partition); g_clear_object (&drive); g_clear_object (&subject); g_clear_object (&details); diff -Nru udisks2-1.97.0/src/udiskslinuxblock.c udisks2-1.98.0/src/udiskslinuxblock.c --- udisks2-1.97.0/src/udiskslinuxblock.c 2012-05-04 20:59:18.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxblock.c 2012-06-07 15:46:30.000000000 +0000 @@ -1880,10 +1880,10 @@ * device. This includes both creating a filesystem or partition * table. * - * Do not translate $(udisks2.device), it's a placeholder and will + * Do not translate $(drive), it's a placeholder and will * be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to format $(udisks2.device)"); + message = N_("Authentication is required to format $(drive)"); action_id = "org.freedesktop.udisks2.modify-device"; if (udisks_block_get_hint_system (block)) { @@ -2104,6 +2104,7 @@ * trigger an event here */ udisks_linux_block_object_trigger_uevent (UDISKS_LINUX_BLOCK_OBJECT (object_to_mkfs)); + wait_data->object = object_to_mkfs; if (udisks_daemon_wait_for_object_sync (daemon, wait_for_filesystem, wait_data, @@ -2243,10 +2244,10 @@ /* Translators: Shown in authentication dialog when creating a * disk image file. * - * Do not translate $(udisks2.device), it's a placeholder and will + * Do not translate $(drive), it's a placeholder and will * be replaced by the name of the drive/device in question */ - N_("Authentication is required to open $(udisks2.device) for reading"), + N_("Authentication is required to open $(drive) for reading"), invocation)) goto out; @@ -2307,10 +2308,10 @@ /* Translators: Shown in authentication dialog when restoring * from a disk image file. * - * Do not translate $(udisks2.device), it's a placeholder and will + * Do not translate $(drive), it's a placeholder and will * be replaced by the name of the drive/device in question */ - N_("Authentication is required to open $(udisks2.device) for writing"), + N_("Authentication is required to open $(drive) for writing"), invocation)) goto out; diff -Nru udisks2-1.97.0/src/udiskslinuxdriveata.c udisks2-1.98.0/src/udiskslinuxdriveata.c --- udisks2-1.97.0/src/udiskslinuxdriveata.c 2012-04-27 16:07:27.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxdriveata.c 2012-05-23 17:12:49.000000000 +0000 @@ -581,6 +581,8 @@ gboolean nowakeup = FALSE; const gchar *atasmart_blob = NULL; GError *error; + const gchar *message; + const gchar *action_id; daemon = NULL; @@ -606,42 +608,28 @@ g_variant_lookup (options, "nowakeup", "b", &nowakeup); g_variant_lookup (options, "atasmart_blob", "s", &atasmart_blob); + /* Translators: Shown in authentication dialog when the user + * refreshes SMART data from a disk. + * + * Do not translate $(drive), it's a placeholder and + * will be replaced by the name of the drive/device in question + */ + message = N_("Authentication is required to update SMART data from $(drive)"); + action_id = "org.freedesktop.udisks2.ata-smart-update"; + if (atasmart_blob != NULL) { - uid_t caller_uid; - error = NULL; - if (!udisks_daemon_util_get_caller_uid_sync (daemon, invocation, NULL /* GCancellable */, &caller_uid, NULL, NULL, &error)) - { - g_dbus_method_invocation_return_gerror (invocation, error); - g_error_free (error); - goto out; - } - if (caller_uid != 0) - { - g_dbus_method_invocation_return_error (invocation, - UDISKS_ERROR, - UDISKS_ERROR_FAILED, - "Only root can update SMART data from a blob"); - goto out; - } + /* Translators: Shown in authentication dialog when the user + * tries to simulate SMART data from a libatasmart blob. + * + * Do not translate $(drive), it's a placeholder and + * will be replaced by the name of the drive/device in question + */ + message = N_("Authentication is required to set SMART data from a blob on $(drive)"); + action_id = "org.freedesktop.udisks2.ata-smart-simulate"; } else { - /* Check that the user is actually authorized */ - if (!udisks_daemon_util_check_authorization_sync (daemon, - UDISKS_OBJECT (block_object), - "org.freedesktop.udisks2.ata-smart-update", - options, - /* Translators: Shown in authentication dialog when the user - * refreshes SMART data from a disk. - * - * Do not translate $(udisks2.device), it's a placeholder and - * will be replaced by the name of the drive/device in question - */ - N_("Authentication is required to update SMART data from $(udisks2.device)"), - invocation)) - goto out; - if (!udisks_drive_ata_get_smart_supported (UDISKS_DRIVE_ATA (drive))) { g_dbus_method_invocation_return_error (invocation, @@ -661,6 +649,15 @@ } } + /* Check that the user is authorized */ + if (!udisks_daemon_util_check_authorization_sync (daemon, + UDISKS_OBJECT (block_object), + action_id, + options, + message, + invocation)) + goto out; + error = NULL; if (!udisks_linux_drive_ata_refresh_smart_sync (drive, nowakeup, @@ -759,10 +756,10 @@ /* Translators: Shown in authentication dialog when the user * aborts a running SMART self-test. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - N_("Authentication is required to abort a SMART self-test on $(udisks2.device)"), + N_("Authentication is required to abort a SMART self-test on $(drive)"), invocation)) goto out; @@ -956,10 +953,10 @@ /* Translators: Shown in authentication dialog when the user * initiates a SMART self-test. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - N_("Authentication is required to start a SMART self-test on $(udisks2.device)"), + N_("Authentication is required to start a SMART self-test on $(drive)"), invocation)) goto out; diff -Nru udisks2-1.97.0/src/udiskslinuxdrive.c udisks2-1.98.0/src/udiskslinuxdrive.c --- udisks2-1.97.0/src/udiskslinuxdrive.c 2012-04-27 16:08:09.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxdrive.c 2012-05-23 17:11:06.000000000 +0000 @@ -706,17 +706,25 @@ } daemon = udisks_linux_drive_object_get_daemon (object); - block_object = udisks_linux_drive_object_get_block (object, TRUE); + block_object = udisks_linux_drive_object_get_block (object, FALSE); if (block_object == NULL) { g_dbus_method_invocation_return_error (invocation, UDISKS_ERROR, UDISKS_ERROR_FAILED, - "Unable to find physical block device for drive"); + "Unable to find block device for drive"); goto out; } block = udisks_object_peek_block (UDISKS_OBJECT (block_object)); + /* refuse to eject if drive appears to be in use */ + if (!udisks_linux_drive_object_is_not_in_use (object, NULL, &error)) + { + g_prefix_error (&error, "Cannot eject drive in use: "); + g_dbus_method_invocation_take_error (invocation, error); + goto out; + } + error = NULL; if (!udisks_daemon_util_get_caller_pid_sync (daemon, invocation, @@ -732,10 +740,10 @@ /* Translators: Shown in authentication dialog when the user * requests ejecting media from a drive. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to eject $(udisks2.device)"); + message = N_("Authentication is required to eject $(drive)"); action_id = "org.freedesktop.udisks2.eject-media"; if (udisks_block_get_hint_system (block)) { diff -Nru udisks2-1.97.0/src/udiskslinuxdriveobject.c udisks2-1.98.0/src/udiskslinuxdriveobject.c --- udisks2-1.97.0/src/udiskslinuxdriveobject.c 2012-04-20 21:35:13.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxdriveobject.c 2012-06-05 18:59:27.000000000 +0000 @@ -665,17 +665,17 @@ static gchar * check_for_vpd (GUdevDevice *device) { - gchar *ret; + gchar *ret = NULL; const gchar *serial; const gchar *wwn; + const gchar *path; g_return_val_if_fail (G_UDEV_IS_DEVICE (device), FALSE); - ret = NULL; - - /* prefer WWN to serial */ + /* order of preference: WWN, serial, path */ serial = g_udev_device_get_property (device, "ID_SERIAL"); wwn = g_udev_device_get_property (device, "ID_WWN_WITH_EXTENSION"); + path = g_udev_device_get_property (device, "ID_PATH"); if (wwn != NULL && strlen (wwn) > 0) { ret = g_strdup (wwn); @@ -684,6 +684,10 @@ { ret = g_strdup (serial); } + else if (path != NULL && strlen (path) > 0) + { + ret = g_strdup (path); + } return ret; } @@ -881,3 +885,106 @@ out: return ret; } + +static gboolean +is_block_unlocked (GList *objects, const gchar *crypto_object_path) +{ + gboolean ret = FALSE; + GList *l; + for (l = objects; l != NULL; l = l->next) + { + UDisksObject *object = UDISKS_OBJECT (l->data); + UDisksBlock *block; + block = udisks_object_peek_block (object); + if (block != NULL) + { + if (g_strcmp0 (udisks_block_get_crypto_backing_device (block), crypto_object_path) == 0) + { + ret = TRUE; + goto out; + } + } + } + out: + return ret; +} + +/** + * udisks_linux_drive_object_is_not_in_use: + * @object: A #UDisksLinuxDriveObject. + * @cancellable: (allow-none): A #GCancellable or %NULL. + * @error: A #GError or %NULL. + * + * Checks if the drive represented by @object is in use and sets + * @error if so. + * + * Returns: %TRUE if @object is not is use, %FALSE if @error is set. + */ +gboolean +udisks_linux_drive_object_is_not_in_use (UDisksLinuxDriveObject *object, + GCancellable *cancellable, + GError **error) +{ + GDBusObjectManagerServer *object_manager; + const gchar *drive_object_path; + gboolean ret = TRUE; + GList *objects = NULL; + GList *l; + + g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE_OBJECT (object), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + drive_object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (object)); + + object_manager = udisks_daemon_get_object_manager (object->daemon); + objects = g_dbus_object_manager_get_objects (G_DBUS_OBJECT_MANAGER (object_manager)); + + /* Visit all block devices related to the drive... */ + for (l = objects; l != NULL; l = l->next) + { + GDBusObjectSkeleton *iter_object = G_DBUS_OBJECT_SKELETON (l->data); + UDisksBlock *block; + UDisksFilesystem *filesystem; + + if (!UDISKS_IS_LINUX_BLOCK_OBJECT (iter_object)) + continue; + + block = udisks_object_peek_block (UDISKS_OBJECT (iter_object)); + filesystem = udisks_object_peek_filesystem (UDISKS_OBJECT (iter_object)); + + if (g_strcmp0 (udisks_block_get_drive (block), drive_object_path) != 0) + continue; + + /* bail if block device is mounted */ + if (filesystem != NULL) + { + if (g_strv_length ((gchar **) udisks_filesystem_get_mount_points (filesystem)) > 0) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_DEVICE_BUSY, + "Device %s is mounted", + udisks_block_get_preferred_device (block)); + ret = FALSE; + goto out; + } + } + + /* bail if block device is unlocked (LUKS) */ + if (is_block_unlocked (objects, g_dbus_object_get_object_path (G_DBUS_OBJECT (iter_object)))) + { + g_set_error (error, + UDISKS_ERROR, + UDISKS_ERROR_DEVICE_BUSY, + "Encrypted device %s is unlocked", + udisks_block_get_preferred_device (block)); + ret = FALSE; + goto out; + } + } + + out: + g_list_free_full (objects, g_object_unref); + return ret; +} diff -Nru udisks2-1.97.0/src/udiskslinuxdriveobject.h udisks2-1.98.0/src/udiskslinuxdriveobject.h --- udisks2-1.97.0/src/udiskslinuxdriveobject.h 2011-08-26 17:12:31.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxdriveobject.h 2012-05-15 14:47:22.000000000 +0000 @@ -48,6 +48,10 @@ GCancellable *cancellable, GError **error); +gboolean udisks_linux_drive_object_is_not_in_use (UDisksLinuxDriveObject *object, + GCancellable *cancellable, + GError **error); + gboolean udisks_linux_drive_object_should_include_device (GUdevClient *client, GUdevDevice *device, gchar **out_vpd); diff -Nru udisks2-1.97.0/src/udiskslinuxencrypted.c udisks2-1.98.0/src/udiskslinuxencrypted.c --- udisks2-1.97.0/src/udiskslinuxencrypted.c 2012-05-04 20:36:31.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxencrypted.c 2012-05-23 17:12:02.000000000 +0000 @@ -346,10 +346,10 @@ /* Translators: Shown in authentication dialog when the user * requests unlocking an encrypted device. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to unlock the encrypted device $(udisks2.device)"); + message = N_("Authentication is required to unlock the encrypted device $(drive)"); if (!udisks_daemon_util_setup_by_user (daemon, object, caller_uid)) { if (is_in_crypttab && has_option (crypttab_options, "x-udisks-auth")) @@ -577,10 +577,10 @@ * requests locking an encrypted device that was previously. * unlocked by another user. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - N_("Authentication is required to lock the encrypted device $(udisks2.device) unlocked by another user"), + N_("Authentication is required to lock the encrypted device $(drive) unlocked by another user"), invocation)) goto out; } @@ -698,10 +698,10 @@ /* Translators: Shown in authentication dialog when the user * requests unlocking an encrypted device. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - N_("Authentication is required to unlock the encrypted device $(udisks2.device)"), + N_("Authentication is required to unlock the encrypted device $(drive)"), invocation)) goto out; diff -Nru udisks2-1.97.0/src/udiskslinuxfilesystem.c udisks2-1.98.0/src/udiskslinuxfilesystem.c --- udisks2-1.97.0/src/udiskslinuxfilesystem.c 2012-05-04 23:30:24.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxfilesystem.c 2012-05-23 17:11:03.000000000 +0000 @@ -1216,10 +1216,10 @@ /* Translators: Shown in authentication dialog when the user * requests mounting a filesystem. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to mount $(udisks2.device)"); + message = N_("Authentication is required to mount $(drive)"); if (!udisks_daemon_util_setup_by_user (daemon, object, caller_uid)) { if (udisks_block_get_hint_system (block)) @@ -1281,13 +1281,13 @@ * user requests mounting a filesystem that is in * /etc/fstab file with the x-udisks-auth option. * - * Do not translate $(udisks2.device), it's a + * Do not translate $(drive), it's a * placeholder and will be replaced by the name of * the drive/device in question * * Do not translate /etc/fstab */ - N_("Authentication is required to mount $(udisks2.device) referenced in the /etc/fstab file"), + N_("Authentication is required to mount $(drive) referenced in the /etc/fstab file"), invocation)) goto out; mount_fstab_as_root = TRUE; @@ -1377,10 +1377,10 @@ /* Translators: Shown in authentication dialog when the user * requests mounting a filesystem. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to mount $(udisks2.device)"); + message = N_("Authentication is required to mount $(drive)"); if (!udisks_daemon_util_setup_by_user (daemon, object, caller_uid)) { if (udisks_block_get_hint_system (block)) @@ -1626,13 +1626,13 @@ * user requests unmounting a filesystem that is in * /etc/fstab file with the x-udisks-auth option. * - * Do not translate $(udisks2.device), it's a + * Do not translate $(drive), it's a * placeholder and will be replaced by the name of * the drive/device in question * * Do not translate /etc/fstab */ - N_("Authentication is required to unmount $(udisks2.device) referenced in the /etc/fstab file"), + N_("Authentication is required to unmount $(drive) referenced in the /etc/fstab file"), invocation)) goto out; unmount_fstab_as_root = TRUE; @@ -1676,10 +1676,10 @@ * requests unmounting a filesystem previously mounted by * another user. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to unmount $(udisks2.device) mounted by another user"); + message = N_("Authentication is required to unmount $(drive) mounted by another user"); if (!udisks_daemon_util_check_authorization_sync (daemon, object, @@ -1894,10 +1894,10 @@ /* Translators: Shown in authentication dialog when the user * requests changing the filesystem label. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to change the filesystem label on $(udisks2.device)"); + message = N_("Authentication is required to change the filesystem label on $(drive)"); if (udisks_block_get_hint_system (block)) { action_id = "org.freedesktop.udisks2.modify-device-system"; diff -Nru udisks2-1.97.0/src/udiskslinuxloop.c udisks2-1.98.0/src/udiskslinuxloop.c --- udisks2-1.97.0/src/udiskslinuxloop.c 2012-05-09 17:30:34.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxloop.c 2012-05-23 17:12:36.000000000 +0000 @@ -238,10 +238,10 @@ * requests deleting a loop device previously set up by * another user. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - N_("Authentication is required to delete the loop device $(udisks2.device)"), + N_("Authentication is required to delete the loop device $(drive)"), invocation)) goto out; } @@ -416,10 +416,10 @@ * requests changing autoclear on a loop device set up by * another user. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - N_("Authentication is required to modify the loop device $(udisks2.device)"), + N_("Authentication is required to modify the loop device $(drive)"), invocation)) goto out; } diff -Nru udisks2-1.97.0/src/udiskslinuxpartition.c udisks2-1.98.0/src/udiskslinuxpartition.c --- udisks2-1.97.0/src/udiskslinuxpartition.c 2012-04-27 16:18:45.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxpartition.c 2012-05-23 17:10:52.000000000 +0000 @@ -259,10 +259,10 @@ /* Translators: Shown in authentication dialog when the user * requests modifying a partition (changing type, flags, name etc.). * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to modify the partition on device $(udisks2.device)"); + message = N_("Authentication is required to modify the partition on device $(drive)"); if (udisks_block_get_hint_system (block)) { action_id = "org.freedesktop.udisks2.modify-device-system"; @@ -404,10 +404,10 @@ /* Translators: Shown in authentication dialog when the user * requests modifying a partition (changing type, flags, name etc.). * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to modify the partition on device $(udisks2.device)"); + message = N_("Authentication is required to modify the partition on device $(drive)"); if (udisks_block_get_hint_system (block)) { action_id = "org.freedesktop.udisks2.modify-device-system"; @@ -586,10 +586,10 @@ /* Translators: Shown in authentication dialog when the user * requests modifying a partition (changing type, flags, name etc.). * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to modify the partition on device $(udisks2.device)"); + message = N_("Authentication is required to modify the partition on device $(drive)"); if (udisks_block_get_hint_system (block)) { action_id = "org.freedesktop.udisks2.modify-device-system"; @@ -759,10 +759,10 @@ /* Translators: Shown in authentication dialog when the user * requests deleting a partition. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to delete the partition $(udisks2.device)"); + message = N_("Authentication is required to delete the partition $(drive)"); if (udisks_block_get_hint_system (block)) { action_id = "org.freedesktop.udisks2.modify-device-system"; diff -Nru udisks2-1.97.0/src/udiskslinuxpartitiontable.c udisks2-1.98.0/src/udiskslinuxpartitiontable.c --- udisks2-1.97.0/src/udiskslinuxpartitiontable.c 2012-05-04 20:39:56.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxpartitiontable.c 2012-05-23 17:11:52.000000000 +0000 @@ -326,10 +326,10 @@ /* Translators: Shown in authentication dialog when the user * requests creating a new partition. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - message = N_("Authentication is required to create a partition on $(udisks2.device)"); + message = N_("Authentication is required to create a partition on $(drive)"); if (udisks_block_get_hint_system (block)) { action_id = "org.freedesktop.udisks2.modify-device-system"; diff -Nru udisks2-1.97.0/src/udiskslinuxswapspace.c udisks2-1.98.0/src/udiskslinuxswapspace.c --- udisks2-1.97.0/src/udiskslinuxswapspace.c 2012-04-27 16:19:38.000000000 +0000 +++ udisks2-1.98.0/src/udiskslinuxswapspace.c 2012-05-23 17:10:45.000000000 +0000 @@ -179,10 +179,10 @@ /* Translators: Shown in authentication dialog when the user * requests activating a swap device. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - N_("Authentication is required to activate swapspace on $(udisks2.device)"), + N_("Authentication is required to activate swapspace on $(drive)"), invocation)) goto out; @@ -253,10 +253,10 @@ /* Translators: Shown in authentication dialog when the user * requests deactivating a swap device. * - * Do not translate $(udisks2.device), it's a placeholder and + * Do not translate $(drive), it's a placeholder and * will be replaced by the name of the drive/device in question */ - N_("Authentication is required to deactivate swapspace on $(udisks2.device)"), + N_("Authentication is required to deactivate swapspace on $(drive)"), invocation)) goto out; diff -Nru udisks2-1.97.0/src/udisksmountmonitor.c udisks2-1.98.0/src/udisksmountmonitor.c --- udisks2-1.97.0/src/udisksmountmonitor.c 2012-03-13 21:42:35.000000000 +0000 +++ udisks2-1.98.0/src/udisksmountmonitor.c 2012-05-15 14:16:34.000000000 +0000 @@ -433,10 +433,6 @@ continue; } - /* ignore mounts where only a subtree of a filesystem is mounted */ - if (g_strcmp0 (encoded_root, "/") != 0) - continue; - /* Temporary work-around for btrfs, see * * https://bugzilla.redhat.com/show_bug.cgi?id=495152#c31 diff -Nru udisks2-1.97.0/tools/udisksctl.c udisks2-1.98.0/tools/udisksctl.c --- udisks2-1.97.0/tools/udisksctl.c 2012-05-04 23:30:24.000000000 +0000 +++ udisks2-1.98.0/tools/udisksctl.c 2012-05-13 16:12:03.000000000 +0000 @@ -1728,6 +1728,287 @@ /* ---------------------------------------------------------------------------------------------------- */ +static gchar *opt_smart_simulate_file = NULL; +static gchar *opt_smart_simulate_object_path = NULL; +static gchar *opt_smart_simulate_device = NULL; +static gboolean opt_smart_simulate_no_user_interaction = FALSE; + +static const GOptionEntry command_smart_simulate_entries[] = +{ + { + "file", + 'f', + 0, + G_OPTION_ARG_FILENAME, + &opt_smart_simulate_file, + "File with libatasmart blob", + NULL + }, + { + "object-path", + 'p', + 0, + G_OPTION_ARG_STRING, + &opt_smart_simulate_object_path, + "Object path for ATA device", + NULL + }, + { + "block-device", + 'b', + 0, + G_OPTION_ARG_STRING, + &opt_smart_simulate_device, + "Device file for ATA device", + NULL + }, + { + "no-user-interaction", + 0, /* no short option */ + 0, + G_OPTION_ARG_NONE, + &opt_smart_simulate_no_user_interaction, + "Do not authenticate the user if needed", + NULL + }, + { + NULL + } +}; + +static gint +handle_command_smart_simulate (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; + gboolean complete_files; + GList *l; + GList *objects; + UDisksObject *object; + UDisksDriveAta *ata; + guint n; + GVariant *options; + GVariantBuilder builder; + GError *error; + + ret = 1; + opt_smart_simulate_object_path = NULL; + opt_smart_simulate_device = NULL; + object = NULL; + options = NULL; + + modify_argv0_for_command (argc, argv, "smart-simulate"); + + 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, "Set SMART data for drive."); + g_option_context_add_main_entries (o, + command_smart_simulate_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); + } + + complete_files = FALSE; + if (request_completion && (g_strcmp0 (completion_prev, "--file") == 0 || g_strcmp0 (completion_prev, "-f") == 0)) + { + complete_files = 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_smart_simulate_file == NULL && !complete_files && !complete_objects && !complete_devices) + { + g_print ("--file \n"); + } + + if (complete_files) + { + g_print ("@FILES@"); + goto out; + } + + if ((opt_smart_simulate_object_path == NULL && !complete_objects) && + (opt_smart_simulate_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; + } + + if (opt_smart_simulate_file == NULL) + { + s = g_option_context_get_help (o, FALSE, NULL); + g_printerr ("%s", s); + g_free (s); + goto out; + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + if (opt_smart_simulate_no_user_interaction) + { + g_variant_builder_add (&builder, + "{sv}", + "auth.no_user_interaction", g_variant_new_boolean (TRUE)); + } + g_variant_builder_add (&builder, + "{sv}", + "atasmart_blob", g_variant_new_string (opt_smart_simulate_file)); + options = g_variant_builder_end (&builder); + g_variant_ref_sink (options); + + if (opt_smart_simulate_object_path != NULL) + { + object = lookup_object_by_path (opt_smart_simulate_object_path); + if (object == NULL) + { + g_printerr ("Error looking up object with path %s\n", opt_smart_simulate_object_path); + goto out; + } + } + else if (opt_smart_simulate_device != NULL) + { + UDisksObject *block_object; + UDisksDrive *drive; + block_object = lookup_object_by_device (opt_smart_simulate_device); + if (block_object == NULL) + { + g_printerr ("Error looking up object for device %s\n", opt_smart_simulate_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; + } + + if (udisks_object_peek_drive_ata (object) == NULL) + { + g_printerr ("Device %s is not an ATA device\n", + udisks_block_get_device (udisks_object_peek_block (object))); + g_object_unref (object); + goto out; + } + + try_again: + error = NULL; + if (!udisks_drive_ata_call_smart_update_sync (udisks_object_peek_drive_ata (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 updating SMART data: %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_smart_simulate_file); + g_free (opt_smart_simulate_object_path); + g_free (opt_smart_simulate_device); + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + static gchar *opt_info_object = NULL; static gchar *opt_info_device = NULL; static gchar *opt_info_drive = NULL; @@ -2563,17 +2844,18 @@ g_option_context_parse (o, argc, argv, NULL); program_name = g_path_get_basename ((*argv)[0]); s = g_strdup_printf ("Commands:\n" - " help Shows this information\n" - " info Shows information about an object\n" - " dump Shows information about all objects\n" - " status Shows high-level status\n" - " monitor Monitor changes to objects\n" - " mount Mount a filesystem\n" - " unmount Unmount a filesystem\n" - " unlock Unlock an encrypted device\n" - " lock Lock an encrypted device\n" - " loop-setup Set-up a loop device\n" - " loop-delete Delete a loop device\n" + " help Shows this information\n" + " info Shows information about an object\n" + " dump Shows information about all objects\n" + " status Shows high-level status\n" + " monitor Monitor changes to objects\n" + " mount Mount a filesystem\n" + " unmount Unmount a filesystem\n" + " unlock Unlock an encrypted device\n" + " lock Lock an encrypted device\n" + " loop-setup Set-up a loop device\n" + " loop-delete Delete a loop device\n" + " smart-simulate Set SMART data for a drive\n" "\n" "Use \"%s COMMAND --help\" to get help on each command.\n", program_name); @@ -2762,6 +3044,15 @@ g_strcmp0 (command, "loop-setup") == 0); goto out; } + else if (g_strcmp0 (command, "smart-simulate") == 0) + { + ret = handle_command_smart_simulate (&argc, + &argv, + request_completion, + completion_cur, + completion_prev); + goto out; + } else if (g_strcmp0 (command, "dump") == 0) { ret = handle_command_dump (&argc, @@ -2865,6 +3156,7 @@ "unlock \n" "loop-setup \n" "loop-delete \n" + "smart-simulate \n" ); ret = 0; goto out;