AC_SUBST(DBUS_CFLAGS)
AC_SUBST(DBUS_LIBS)
-PKG_CHECK_MODULES(DBUS_GLIB, [dbus-glib-1 >= 0.73])
+PKG_CHECK_MODULES(DBUS_GLIB, [dbus-glib-1 >= 0.75])
AC_SUBST(DBUS_GLIB_CFLAGS)
AC_SUBST(DBUS_GLIB_LIBS)
</defaults>
</action>
+ <action id="org.freedesktop.devicekit.disks.erase">
+ <_description>Erase a disk</_description>
+ <_message>Authentication is required to erase a disk</_message>
+ <defaults>
+ <allow_any>no</allow_any>
+ <allow_inactive>no</allow_inactive>
+ <allow_active>auth_admin</allow_active>
+ </defaults>
+ </action>
+
</policyconfig>
$(GLIB_CFLAGS) \
$(GIO_CFLAGS)
-BUILT_SOURCES = \
- devkit-disks-daemon-glue.h \
- devkit-disks-device-glue.h
+BUILT_SOURCES = \
+ devkit-disks-daemon-glue.h \
+ devkit-disks-device-glue.h \
+ devkit-disks-marshal.h devkit-disks-marshal.c
+
+devkit-disks-marshal.h: devkit-disks-marshal.list
+ glib-genmarshal $< --prefix=devkit_disks_marshal --header > $@
+
+devkit-disks-marshal.c: devkit-disks-marshal.list
+ echo "#include \"devkit-disks-marshal.h\"" > $@ && glib-genmarshal $< --prefix=devkit_disks_marshal --body >> $@
devkit-disks-daemon-glue.h: org.freedesktop.DeviceKit.Disks.xml Makefile.am
dbus-binding-tool --prefix=devkit_disks_daemon --mode=glib-server --output=devkit-disks-daemon-glue.h org.freedesktop.DeviceKit.Disks.xml
devkit-disks-device-glue.h: org.freedesktop.DeviceKit.Disks.Device.xml Makefile.am
dbus-binding-tool --prefix=devkit_disks_device --mode=glib-server --output=devkit-disks-device-glue.h org.freedesktop.DeviceKit.Disks.Device.xml
-libexec_PROGRAMS = devkit-disks-daemon
+libexec_PROGRAMS = devkit-disks-daemon devkit-disks-helper-erase devkit-disks-helper-mkfs
dbusifdir = $(datadir)/dbus-1/interfaces
dbusif_DATA = org.freedesktop.DeviceKit.Disks.xml org.freedesktop.DeviceKit.Disks.Device.xml
$(POLKIT_DBUS_LIBS) \
$(DEVKIT_LIBS)
+devkit_disks_helper_erase_SOURCES = job-shared.h job-erase.c
+devkit_disks_helper_erase_CPPFLAGS = $(AM_CPPFLAGS)
+devkit_disks_helper_erase_LDADD = $(GLIB_LIBS)
+
+devkit_disks_helper_mkfs_SOURCES = job-shared.h job-mkfs.c
+devkit_disks_helper_mkfs_CPPFLAGS = $(AM_CPPFLAGS)
+devkit_disks_helper_mkfs_LDADD = $(GLIB_LIBS)
+
servicedir = $(datadir)/dbus-1/system-services
service_in_files = org.freedesktop.DeviceKit.Disks.service.in
service_DATA = $(service_in_files:.service.in=.service)
#include "mounts-file.h"
#include "devkit-disks-daemon-glue.h"
+#include "devkit-disks-marshal.h"
/*--------------------------------------------------------------------------------------------------------------*/
DEVICE_ADDED_SIGNAL,
DEVICE_REMOVED_SIGNAL,
DEVICE_CHANGED_SIGNAL,
+ DEVICE_JOB_CHANGED_SIGNAL,
LAST_SIGNAL,
};
g_cclosure_marshal_VOID__STRING,
G_TYPE_NONE, 1, G_TYPE_STRING);
+ signals[DEVICE_JOB_CHANGED_SIGNAL] =
+ g_signal_new ("device-job-changed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ devkit_disks_marshal_VOID__STRING_BOOLEAN_STRING_BOOLEAN_INT_INT_STRING_DOUBLE,
+ G_TYPE_NONE,
+ 8,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_STRING,
+ G_TYPE_DOUBLE);
+
+
dbus_g_object_type_install_info (DEVKIT_TYPE_DISKS_DAEMON, &dbus_glib_devkit_disks_daemon_object_info);
dbus_g_error_domain_register (DEVKIT_DISKS_DAEMON_ERROR,
G_BEGIN_DECLS
+struct Job;
+typedef struct Job Job;
+
struct DevkitDisksDevicePrivate
{
DBusGConnection *system_bus_connection;
DBusGProxy *system_bus_proxy;
DevkitDisksDaemon *daemon;
- char *object_path;
+ Job *job;
+
+ char *object_path;
char *native_path;
+ gboolean job_in_progress;
+ char *job_id;
+ gboolean job_is_cancellable;
+ int job_num_tasks;
+ int job_cur_task;
+ char *job_cur_task_id;
+ double job_cur_task_percentage;
+
struct {
char *device_file;
GPtrArray *device_file_by_id;
#include <sys/time.h>
#include <sys/resource.h>
#include <fcntl.h>
-#include <signal.h>
#include <pwd.h>
#include <grp.h>
#include <linux/fs.h>
#include "devkit-disks-device.h"
#include "devkit-disks-device-private.h"
+#include "devkit-disks-marshal.h"
#include "mounts-file.h"
/*--------------------------------------------------------------------------------------------------------------*/
PROP_DEVICE_IS_MOUNTED,
PROP_DEVICE_MOUNT_PATH,
+ PROP_JOB_IN_PROGRESS,
+ PROP_JOB_ID,
+ PROP_JOB_IS_CANCELLABLE,
+ PROP_JOB_NUM_TASKS,
+ PROP_JOB_CUR_TASK,
+ PROP_JOB_CUR_TASK_ID,
+ PROP_JOB_CUR_TASK_PERCENTAGE,
+
PROP_ID_USAGE,
PROP_ID_TYPE,
PROP_ID_VERSION,
enum
{
CHANGED_SIGNAL,
+ JOB_CHANGED_SIGNAL,
LAST_SIGNAL,
};
ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_GENERAL, "GeneralError"),
ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_NOT_SUPPORTED, "NotSupported"),
ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_NOT_MOUNTABLE, "NotMountable"),
- ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_ALREADY_MOUNTED, "AlreadyMounted"),
+ ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_MOUNTED, "Mounted"),
ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_NOT_MOUNTED, "NotMounted"),
ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_NOT_MOUNTED_BY_DK, "NotMountedByDeviceKit"),
ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_FSTAB_ENTRY, "FstabEntry"),
ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_FILESYSTEM_BUSY, "FilesystemBusy"),
ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_CANNOT_REMOUNT, "CannotRemount"),
ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_UNMOUNT_OPTION_NOT_ALLOWED, "UnmountOptionNotAllowed"),
+ ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_NO_JOB_IN_PROGRESS, "NoJobInProgress"),
+ ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_JOB_ALREADY_IN_PROGRESS, "JobAlreadyInProgress"),
+ ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_JOB_CANNOT_BE_CANCELLED, "JobCannotBeCancelled"),
+ ENUM_ENTRY (DEVKIT_DISKS_DEVICE_ERROR_JOB_WAS_CANCELLED, "JobWasCancelled"),
{ 0, 0, 0 }
};
g_assert (DEVKIT_DISKS_DEVICE_NUM_ERRORS == G_N_ELEMENTS (values) - 1);
g_value_set_string (value, device->priv->info.device_mount_path);
break;
+ case PROP_JOB_IN_PROGRESS:
+ g_value_set_boolean (value, device->priv->job_in_progress);
+ break;
+ case PROP_JOB_ID:
+ g_value_set_string (value, device->priv->job_id);
+ break;
+ case PROP_JOB_IS_CANCELLABLE:
+ g_value_set_boolean (value, device->priv->job_is_cancellable);
+ break;
+ case PROP_JOB_NUM_TASKS:
+ g_value_set_int (value, device->priv->job_num_tasks);
+ break;
+ case PROP_JOB_CUR_TASK:
+ g_value_set_int (value, device->priv->job_cur_task);
+ break;
+ case PROP_JOB_CUR_TASK_ID:
+ g_value_set_string (value, device->priv->job_cur_task_id);
+ break;
+ case PROP_JOB_CUR_TASK_PERCENTAGE:
+ g_value_set_double (value, device->priv->job_cur_task_percentage);
+ break;
+
case PROP_ID_USAGE:
g_value_set_string (value, device->priv->info.id_usage);
break;
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+ signals[JOB_CHANGED_SIGNAL] =
+ g_signal_new ("job-changed",
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
+ 0,
+ NULL, NULL,
+ devkit_disks_marshal_VOID__BOOLEAN_STRING_BOOLEAN_INT_INT_STRING_DOUBLE,
+ G_TYPE_NONE,
+ 7,
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_STRING,
+ G_TYPE_DOUBLE);
+
dbus_g_object_type_install_info (DEVKIT_TYPE_DISKS_DEVICE, &dbus_glib_devkit_disks_device_object_info);
dbus_g_error_domain_register (DEVKIT_DISKS_DEVICE_ERROR,
g_object_class_install_property (
object_class,
+ PROP_JOB_IN_PROGRESS,
+ g_param_spec_boolean ("job-in-progress", NULL, NULL, FALSE, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_JOB_ID,
+ g_param_spec_string ("job-id", NULL, NULL, NULL, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_JOB_IS_CANCELLABLE,
+ g_param_spec_boolean ("job-is-cancellable", NULL, NULL, FALSE, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_JOB_NUM_TASKS,
+ g_param_spec_int ("job-num-tasks", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_JOB_CUR_TASK,
+ g_param_spec_int ("job-cur-task", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_JOB_CUR_TASK_ID,
+ g_param_spec_string ("job-cur-task-id", NULL, NULL, NULL, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_JOB_CUR_TASK_PERCENTAGE,
+ g_param_spec_double ("job-cur-task-percentage", NULL, NULL, -1, 100, -1, G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
PROP_ID_USAGE,
g_param_spec_string ("id-usage", NULL, NULL, NULL, G_PARAM_READABLE));
g_object_class_install_property (
}
static void
+devkit_device_emit_changed_to_kernel (DevkitDisksDevice *device)
+{
+ FILE *f;
+ char *filename;
+
+ filename = g_build_filename (device->priv->native_path, "uevent", NULL);
+ f = fopen (filename, "w");
+ if (f == NULL) {
+ g_warning ("error opening %s for writing: %m", filename);
+ } else {
+ /* TODO: change 'add' to 'change' when new udev rules are released */
+ if (fputs ("add", f) == EOF) {
+ g_warning ("error writing 'add' to %s: %m", filename);
+ }
+ fclose (f);
+ }
+ g_free (filename);
+}
+
+static void
free_info (DevkitDisksDevice *device)
{
g_free (device->priv->info.device_file);
}
static void
+emit_job_changed (DevkitDisksDevice *device)
+{
+ g_print ("emitting job-changed on %s\n", device->priv->native_path);
+ g_signal_emit_by_name (device->priv->daemon,
+ "device-job-changed",
+ device->priv->object_path,
+ device->priv->job_in_progress,
+ device->priv->job_id,
+ device->priv->job_is_cancellable,
+ device->priv->job_num_tasks,
+ device->priv->job_cur_task,
+ device->priv->job_cur_task_id,
+ device->priv->job_cur_task_percentage,
+ NULL);
+ g_signal_emit (device, signals[JOB_CHANGED_SIGNAL], 0,
+ device->priv->job_in_progress,
+ device->priv->job_id,
+ device->priv->job_is_cancellable,
+ device->priv->job_num_tasks,
+ device->priv->job_cur_task,
+ device->priv->job_cur_task_id,
+ device->priv->job_cur_task_percentage);
+}
+
+static void
emit_changed (DevkitDisksDevice *device)
{
g_print ("emitting changed on %s\n", device->priv->native_path);
typedef void (*JobCompletedFunc) (DBusGMethodInvocation *context,
DevkitDisksDevice *device,
PolKitCaller *caller,
+ gboolean was_cancelled,
int status,
const char *stderr,
gpointer user_data);
-typedef struct {
+struct Job {
DevkitDisksDevice *device;
PolKitCaller *pk_caller;
DBusGMethodInvocation *context;
GPid pid;
gpointer user_data;
GDestroyNotify user_data_destroy_func;
+ gboolean was_cancelled;
int stderr_fd;
GIOChannel *error_channel;
guint error_channel_source_id;
GString *error_string;
-} Job;
+
+ int stdout_fd;
+ GIOChannel *out_channel;
+ guint out_channel_source_id;
+};
static void
job_free (Job *job)
{
+ if (job->user_data_destroy_func != NULL)
+ job->user_data_destroy_func (job->user_data);
if (job->device != NULL)
g_object_unref (job->device);
if (job->pk_caller != NULL)
polkit_caller_unref (job->pk_caller);
if (job->stderr_fd >= 0)
close (job->stderr_fd);
+ if (job->stdout_fd >= 0)
+ close (job->stdout_fd);
g_source_remove (job->error_channel_source_id);
+ g_source_remove (job->out_channel_source_id);
g_io_channel_unref (job->error_channel);
+ g_io_channel_unref (job->out_channel);
g_string_free (job->error_string, TRUE);
g_free (job);
}
{
Job *job = user_data;
+ g_print ("helper(pid %5d): completed with exit code %d\n", job->pid, WEXITSTATUS (status));
+
job->job_completed_func (job->context,
job->device,
job->pk_caller,
+ job->was_cancelled,
status,
job->error_string->str,
job->user_data);
+
+ job->device->priv->job_in_progress = FALSE;
+ g_free (job->device->priv->job_id);
+ job->device->priv->job_id = NULL;
+ job->device->priv->job_is_cancellable = FALSE;
+ job->device->priv->job_num_tasks = 0;
+ job->device->priv->job_cur_task = 0;
+ g_free (job->device->priv->job_cur_task_id);
+ job->device->priv->job_cur_task_id = NULL;
+ job->device->priv->job_cur_task_percentage = -1.0;
+
+ job->device->priv->job = NULL;
+
+ emit_job_changed (job->device);
+
job_free (job);
}
+static void
+job_cancel (DevkitDisksDevice *device)
+{
+ g_return_if_fail (device->priv->job != NULL);
+
+ device->priv->job->was_cancelled = TRUE;
+
+ /* TODO: maybe wait and user a bigger hammer? (SIGKILL) */
+ kill (device->priv->job->pid, SIGTERM);
+}
+
static gboolean
job_read_error (GIOChannel *channel,
GIOCondition condition,
}
static gboolean
+job_read_out (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ char *str;
+ gsize str_len;
+ Job *job = user_data;
+
+ g_io_channel_read_line (channel, &str, &str_len, NULL, NULL);
+ g_print ("helper(pid %5d): %s", job->pid, str);
+
+ if (strlen (str) < 256) {
+ int cur_task;
+ int num_tasks;
+ double cur_task_percentage;;
+ char cur_task_id[256];
+
+ if (sscanf (str, "progress: %d %d %lg %s",
+ &cur_task,
+ &num_tasks,
+ &cur_task_percentage,
+ (char *) &cur_task_id) == 4) {
+ job->device->priv->job_num_tasks = num_tasks;
+ job->device->priv->job_cur_task = cur_task;
+ g_free (job->device->priv->job_cur_task_id);
+ job->device->priv->job_cur_task_id = g_strdup (cur_task_id);
+ job->device->priv->job_cur_task_percentage = cur_task_percentage;
+ emit_job_changed (job->device);
+ }
+ }
+
+ g_free (str);
+ return TRUE;
+}
+
+static gboolean
job_new (DBusGMethodInvocation *context,
- DevkitDisksDevice *device,
- PolKitCaller *pk_caller,
- char **argv,
- JobCompletedFunc job_completed_func,
- GError **error,
- gpointer user_data,
- GDestroyNotify user_data_destroy_func)
+ const char *job_id,
+ gboolean is_cancellable,
+ DevkitDisksDevice *device,
+ PolKitCaller *pk_caller,
+ char **argv,
+ JobCompletedFunc job_completed_func,
+ gpointer user_data,
+ GDestroyNotify user_data_destroy_func)
{
Job *job;
gboolean ret;
+ GError *error;
ret = FALSE;
+ job = NULL;
+
+ if (device->priv->job != NULL) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_JOB_ALREADY_IN_PROGRESS,
+ "There is already a job running");
+ goto out;
+ }
job = g_new0 (Job, 1);
job->context = context;
job->user_data = user_data;
job->user_data_destroy_func = user_data_destroy_func;
job->stderr_fd = -1;
+ job->stdout_fd = -1;
+ g_free (job->device->priv->job_id);
+ job->device->priv->job_id = g_strdup (job_id);
+ error = NULL;
if (!g_spawn_async_with_pipes (NULL,
argv,
NULL,
NULL,
&(job->pid),
NULL,
- NULL,
+ &(job->stdout_fd),
&(job->stderr_fd),
- error)) {
- job->user_data_destroy_func (job->user_data);
+ &error)) {
+ throw_error (context, DEVKIT_DISKS_DEVICE_ERROR_GENERAL, "Error starting job: %s", error->message);
+ g_error_free (error);
goto out;
}
job->error_channel = g_io_channel_unix_new (job->stderr_fd);
job->error_channel_source_id = g_io_add_watch (job->error_channel, G_IO_IN, job_read_error, job);
+ job->out_channel = g_io_channel_unix_new (job->stdout_fd);
+ job->out_channel_source_id = g_io_add_watch (job->out_channel, G_IO_IN, job_read_out, job);
+
ret = TRUE;
+ device->priv->job_in_progress = TRUE;
+ device->priv->job_is_cancellable = is_cancellable;
+ device->priv->job_num_tasks = 0;
+ device->priv->job_cur_task = 0;
+ g_free (device->priv->job_cur_task_id);
+ device->priv->job_cur_task_id = NULL;
+ device->priv->job_cur_task_percentage = -1.0;
+
+ device->priv->job = job;
+
+ emit_job_changed (device);
+
+ g_print ("helper(pid %5d): launched job %s on %s\n", job->pid, argv[0], device->priv->info.device_file);
+
out:
- if (!ret)
+ if (!ret && job != NULL)
job_free (job);
return ret;
}
mount_completed_cb (DBusGMethodInvocation *context,
DevkitDisksDevice *device,
PolKitCaller *pk_caller,
+ gboolean job_was_cancelled,
int status,
const char *stderr,
gpointer user_data)
if (pk_caller != NULL)
polkit_caller_get_uid (pk_caller, &uid);
- if (WEXITSTATUS (status) == 0) {
+ if (WEXITSTATUS (status) == 0 && !job_was_cancelled) {
if (!data->is_remount) {
devkit_disks_device_local_set_mounted (device, data->mount_point);
mounts_file_add (device, uid, data->remove_dir_on_unmount);
g_warning ("Error removing dir in late mount error path: %m");
}
}
- throw_error (context,
- DEVKIT_DISKS_DEVICE_ERROR_GENERAL,
- "Error mounting: mount exited with exit code %d: %s", WEXITSTATUS (status), stderr);
+
+ if (job_was_cancelled) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_JOB_WAS_CANCELLED,
+ "Job was cancelled");
+ } else {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_GENERAL,
+ "Error mounting: mount exited with exit code %d: %s",
+ WEXITSTATUS (status), stderr);
+ }
}
}
fsmo = find_mount_options_for_fs (fstype);
- /* always prepend some reasonable default mount options; these should be
- * chosen here so the user can override them later on.
+ /* always prepend some reasonable default mount options; these are
+ * chosen here; the user can override them if he wants to
*/
options = prepend_default_mount_options (fsmo, caller_uid, given_options);
if (device->priv->info.device_is_mounted) {
if (!is_remount) {
- throw_error (context, DEVKIT_DISKS_DEVICE_ERROR_ALREADY_MOUNTED,
+ throw_error (context, DEVKIT_DISKS_DEVICE_ERROR_MOUNTED,
"Device is already mounted");
goto out;
}
error = NULL;
if (!job_new (context,
+ "Mount",
+ FALSE,
device,
pk_caller,
argv,
mount_completed_cb,
- &error,
mount_data_new (mount_point, remove_dir_on_unmount, is_remount),
(GDestroyNotify) mount_data_free)) {
- throw_error (context, DEVKIT_DISKS_DEVICE_ERROR_GENERAL, "Error mounting: %s", error->message);
- g_error_free (error);
if (!is_remount) {
if (g_rmdir (mount_point) != 0) {
g_warning ("Error removing dir in early mount error path: %m");
unmount_completed_cb (DBusGMethodInvocation *context,
DevkitDisksDevice *device,
PolKitCaller *pk_caller,
+ gboolean job_was_cancelled,
int status,
const char *stderr,
gpointer user_data)
{
char *mount_path = user_data;
- if (WEXITSTATUS (status) == 0) {
+ if (WEXITSTATUS (status) == 0 && !job_was_cancelled) {
devkit_disks_device_local_set_unmounted (device);
mounts_file_remove (device, mount_path);
dbus_g_method_return (context);
} else {
- if (strstr (stderr, "device is busy") != NULL) {
+ if (job_was_cancelled) {
throw_error (context,
- DEVKIT_DISKS_DEVICE_ERROR_FILESYSTEM_BUSY,
- "Cannot unmount because file system on device is busy");
+ DEVKIT_DISKS_DEVICE_ERROR_JOB_WAS_CANCELLED,
+ "Job was cancelled");
} else {
- throw_error (context,
- DEVKIT_DISKS_DEVICE_ERROR_GENERAL,
- "Error unmounting: umount exited with exit code %d: %s",
- WEXITSTATUS (status),
- stderr);
+ if (strstr (stderr, "device is busy") != NULL) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_FILESYSTEM_BUSY,
+ "Cannot unmount because file system on device is busy");
+ } else {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_GENERAL,
+ "Error unmounting: umount exited with exit code %d: %s",
+ WEXITSTATUS (status),
+ stderr);
+ }
}
}
}
} else {
throw_error (context,
DEVKIT_DISKS_DEVICE_ERROR_UNMOUNT_OPTION_NOT_ALLOWED,
- "Device is not mounted by DeviceKit-disks");
+ "Unknown option %s", option);
}
}
error = NULL;
if (!job_new (context,
+ "Unmount",
+ FALSE,
device,
pk_caller,
argv,
unmount_completed_cb,
- &error,
g_strdup (device->priv->info.device_mount_path),
g_free)) {
- throw_error (context, DEVKIT_DISKS_DEVICE_ERROR_GENERAL, "Error unmounting: %s", error->message);
- g_error_free (error);
goto out;
}
return TRUE;
}
+/*--------------------------------------------------------------------------------------------------------------*/
+
+static void
+erase_completed_cb (DBusGMethodInvocation *context,
+ DevkitDisksDevice *device,
+ PolKitCaller *pk_caller,
+ gboolean job_was_cancelled,
+ int status,
+ const char *stderr,
+ gpointer user_data)
+{
+ /* either way, poke the kernel so we can reread the data */
+ devkit_device_emit_changed_to_kernel (device);
+
+ if (WEXITSTATUS (status) == 0 && !job_was_cancelled) {
+ dbus_g_method_return (context);
+ } else {
+ if (job_was_cancelled) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_JOB_WAS_CANCELLED,
+ "Job was cancelled");
+ } else {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_GENERAL,
+ "Error erasing: helper exited with exit code %d: %s",
+ WEXITSTATUS (status),
+ stderr);
+ }
+ }
+}
+
+gboolean
+devkit_disks_device_erase (DevkitDisksDevice *device,
+ char **options,
+ DBusGMethodInvocation *context)
+{
+ int n;
+ char *argv[16];
+ GError *error;
+ PolKitCaller *pk_caller;
+
+ if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon, context)) == NULL)
+ goto out;
+
+ if (device->priv->info.device_is_mounted) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_NOT_MOUNTED,
+ "Device is mounted");
+ goto out;
+ }
+
+ if (!devkit_disks_damon_local_check_auth (device->priv->daemon,
+ pk_caller,
+ /* TODO: revisit authorization */
+ "org.freedesktop.devicekit.disks.erase",
+ context))
+ goto out;
+
+ /* TODO: options: quick, full, secure_gutmann_35pass etc. */
+
+ n = 0;
+ argv[n++] = PACKAGE_LIBEXEC_DIR "/devkit-disks-helper-erase";
+ argv[n++] = device->priv->info.device_file;
+ argv[n++] = NULL;
+
+ error = NULL;
+ if (!job_new (context,
+ "Erase",
+ TRUE,
+ device,
+ pk_caller,
+ argv,
+ erase_completed_cb,
+ NULL,
+ NULL)) {
+ goto out;
+ }
+
+out:
+ if (pk_caller != NULL)
+ polkit_caller_unref (pk_caller);
+ return TRUE;
+}
+
+/*--------------------------------------------------------------------------------------------------------------*/
+
+static void
+create_filesystem_completed_cb (DBusGMethodInvocation *context,
+ DevkitDisksDevice *device,
+ PolKitCaller *pk_caller,
+ gboolean job_was_cancelled,
+ int status,
+ const char *stderr,
+ gpointer user_data)
+{
+ /* either way, poke the kernel so we can reread the data */
+ devkit_device_emit_changed_to_kernel (device);
+
+ if (WEXITSTATUS (status) == 0 && !job_was_cancelled) {
+ dbus_g_method_return (context);
+ } else {
+ if (job_was_cancelled) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_JOB_WAS_CANCELLED,
+ "Job was cancelled");
+ } else {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_GENERAL,
+ "Error creating file system: helper exited with exit code %d: %s",
+ WEXITSTATUS (status),
+ stderr);
+ }
+ }
+}
+
+gboolean
+devkit_disks_device_create_filesystem (DevkitDisksDevice *device,
+ const char *fstype,
+ char **options,
+ DBusGMethodInvocation *context)
+{
+ int n;
+ int m;
+ char *argv[128];
+ GError *error;
+ PolKitCaller *pk_caller;
+
+ if ((pk_caller = devkit_disks_damon_local_get_caller_for_context (device->priv->daemon, context)) == NULL)
+ goto out;
+
+ if (device->priv->info.device_is_mounted) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_NOT_MOUNTED,
+ "Device is mounted");
+ goto out;
+ }
+
+ if (!devkit_disks_damon_local_check_auth (device->priv->daemon,
+ pk_caller,
+ /* TODO: revisit authorization */
+ "org.freedesktop.devicekit.disks.erase",
+ context))
+ goto out;
+
+ if (strlen (fstype) == 0) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_GENERAL,
+ "fstype not specified");
+ goto out;
+ }
+
+ n = 0;
+ argv[n++] = PACKAGE_LIBEXEC_DIR "/devkit-disks-helper-mkfs";
+ argv[n++] = (char *) fstype;
+ argv[n++] = device->priv->info.device_file;
+ for (m = 0; options[m] != NULL; m++) {
+ if (n >= (int) sizeof (argv) - 1) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_GENERAL,
+ "Too many options");
+ goto out;
+ }
+ /* the helper will validate each option */
+ argv[n++] = (char *) options[m];
+ }
+ argv[n++] = NULL;
+
+ error = NULL;
+ if (!job_new (context,
+ "CreateFilesystem",
+ TRUE,
+ device,
+ pk_caller,
+ argv,
+ create_filesystem_completed_cb,
+ NULL,
+ NULL)) {
+ goto out;
+ }
+
+out:
+ if (pk_caller != NULL)
+ polkit_caller_unref (pk_caller);
+ return TRUE;
+}
+
+/*--------------------------------------------------------------------------------------------------------------*/
+
+gboolean
+devkit_disks_device_cancel_job (DevkitDisksDevice *device,
+ DBusGMethodInvocation *context)
+{
+ if (!device->priv->job_in_progress) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_NO_JOB_IN_PROGRESS,
+ "There is no job to cancel");
+ goto out;
+ }
+
+ if (!device->priv->job_is_cancellable) {
+ throw_error (context,
+ DEVKIT_DISKS_DEVICE_ERROR_JOB_CANNOT_BE_CANCELLED,
+ "Job cannot be cancelled");
+ goto out;
+ }
+
+ /* TODO: check authorization */
+
+ job_cancel (device);
+
+ /* TODO: wait returning once the job is actually cancelled? */
+ dbus_g_method_return (context);
+
+out:
+ return TRUE;
+}
DEVKIT_DISKS_DEVICE_ERROR_GENERAL,
DEVKIT_DISKS_DEVICE_ERROR_NOT_SUPPORTED,
DEVKIT_DISKS_DEVICE_ERROR_NOT_MOUNTABLE,
- DEVKIT_DISKS_DEVICE_ERROR_ALREADY_MOUNTED,
+ DEVKIT_DISKS_DEVICE_ERROR_MOUNTED,
DEVKIT_DISKS_DEVICE_ERROR_NOT_MOUNTED,
DEVKIT_DISKS_DEVICE_ERROR_NOT_MOUNTED_BY_DK,
DEVKIT_DISKS_DEVICE_ERROR_FSTAB_ENTRY,
DEVKIT_DISKS_DEVICE_ERROR_FILESYSTEM_BUSY,
DEVKIT_DISKS_DEVICE_ERROR_CANNOT_REMOUNT,
DEVKIT_DISKS_DEVICE_ERROR_UNMOUNT_OPTION_NOT_ALLOWED,
+ DEVKIT_DISKS_DEVICE_ERROR_NO_JOB_IN_PROGRESS,
+ DEVKIT_DISKS_DEVICE_ERROR_JOB_ALREADY_IN_PROGRESS,
+ DEVKIT_DISKS_DEVICE_ERROR_JOB_CANNOT_BE_CANCELLED,
+ DEVKIT_DISKS_DEVICE_ERROR_JOB_WAS_CANCELLED,
DEVKIT_DISKS_DEVICE_NUM_ERRORS
} DevkitDisksDeviceError;
/* exported methods */
+gboolean devkit_disks_device_cancel_job (DevkitDisksDevice *device,
+ DBusGMethodInvocation *context);
+
gboolean devkit_disks_device_mount (DevkitDisksDevice *device,
const char *filesystem_type,
char **options,
char **options,
DBusGMethodInvocation *context);
+gboolean devkit_disks_device_erase (DevkitDisksDevice *device,
+ char **options,
+ DBusGMethodInvocation *context);
+
+gboolean devkit_disks_device_create_filesystem (DevkitDisksDevice *device,
+ const char *fstype,
+ char **options,
+ DBusGMethodInvocation *context);
+
G_END_DECLS
#endif /* __DEVKIT_DISKS_DEVICE_H__ */
--- /dev/null
+VOID:BOOLEAN,STRING,BOOLEAN,INT,INT,STRING,DOUBLE
+VOID:STRING,BOOLEAN,STRING,BOOLEAN,INT,INT,STRING,DOUBLE
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <david@fubar.dk>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "job-shared.h"
+
+int
+main (int argc, char **argv)
+{
+ int ret;
+ int num_passes;
+ const char *device;
+
+ ret = 1;
+
+ if (argc != 2) {
+ g_printerr ("wrong usage\n");
+ goto out;
+ }
+ device = argv[1];
+
+ /* TODO: parse options etc. */
+ num_passes = 1;
+ if (!task_zero_device (device, num_passes, 0, 2))
+ goto out;
+
+ ret = 0;
+
+out:
+ return ret;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <david@fubar.dk>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+
+#include <glib.h>
+
+#include "job-shared.h"
+
+static gboolean
+validate_and_escape_label (char **label, int max_len)
+{
+ int n;
+ gboolean ret;
+ GString *s;
+
+ ret = FALSE;
+
+ if ((int) strlen (*label) > max_len) {
+ g_printerr ("given file system label exceeds %d characters\n", max_len);
+ goto out;
+ }
+
+ /* escape '"' */
+ s = g_string_new (*label);
+ for (n = 0; n < (int) s->len; n++) {
+ if (s->str[n] == '"') {
+ g_string_insert_c (s, n, '\\');
+ n++;
+ }
+ }
+ g_free (*label);
+ *label = g_string_free (s, FALSE);
+
+ ret = TRUE;
+out:
+ return ret;
+}
+
+int
+main (int argc, char **argv)
+{
+ int ret;
+ int exit_status;
+ GError *error;
+ const char *fstype;
+ const char *device;
+ char *command_line;
+ char *standard_error;
+ char **options;
+ GString *s;
+ char *label;
+ char *erase;
+ int num_erase_passes;
+ int n;
+
+ ret = 1;
+ command_line = NULL;
+ standard_error = NULL;
+ erase = NULL;
+
+ if (argc < 3) {
+ g_printerr ("wrong usage\n");
+ goto out;
+ }
+ fstype = argv[1];
+ device = argv[2];
+ options = argv + 3;
+
+ /* TODO: clean out metadata in start and beginning */
+
+ if (strcmp (fstype, "vfat") == 0) {
+ s = g_string_new ("mkfs.vfat");
+ for (n = 0; options[n] != NULL; n++) {
+ if (g_str_has_prefix (options[n], "label=")) {
+ label = strdup (options[n] + sizeof ("label=") - 1);
+ if (!validate_and_escape_label (&label, 11)) {
+ g_string_free (s, TRUE);
+ goto out;
+ }
+ g_string_append_printf (s, " -n \"%s\"", label);
+ g_free (label);
+ } else if (g_str_has_prefix (options[n], "erase=")) {
+ erase = strdup (options[n] + sizeof ("erase=") - 1);
+ } else {
+ g_printerr ("option %s not supported\n", options[n]);
+ goto out;
+ }
+ }
+ g_string_append_printf (s, " %s", device);
+ command_line = g_string_free (s, FALSE);
+ } else if (strcmp (fstype, "ext3") == 0) {
+
+ s = g_string_new ("mkfs.ext3");
+ for (n = 0; options[n] != NULL; n++) {
+ if (g_str_has_prefix (options[n], "label=")) {
+ label = strdup (options[n] + sizeof ("label=") - 1);
+ if (!validate_and_escape_label (&label, 16)) {
+ g_string_free (s, TRUE);
+ goto out;
+ }
+ g_string_append_printf (s, " -L \"%s\"", label);
+ g_free (label);
+ } else if (g_str_has_prefix (options[n], "erase=")) {
+ erase = strdup (options[n] + sizeof ("erase=") - 1);
+ } else {
+ g_printerr ("option %s not supported\n", options[n]);
+ goto out;
+ }
+ }
+ g_string_append_printf (s, " %s", device);
+ command_line = g_string_free (s, FALSE);
+
+ } else if (strcmp (fstype, "empty") == 0) {
+ command_line = NULL;
+ for (n = 0; options[n] != NULL; n++) {
+ if (g_str_has_prefix (options[n], "erase=")) {
+ erase = strdup (options[n] + sizeof ("erase=") - 1);
+ } else {
+ g_printerr ("option %s not supported\n", options[n]);
+ goto out;
+ }
+ }
+ } else {
+ g_printerr ("fstype %s not supported\n", fstype);
+ goto out;
+ }
+
+ /* TODO: do erase */
+ num_erase_passes = task_zero_device_parse_option (erase);
+ if (num_erase_passes == -1) {
+ g_printerr ("invalid erase=%s option\n", erase);
+ goto out;
+ }
+ if (!task_zero_device (device, num_erase_passes, 0, num_erase_passes + 2))
+ goto out;
+
+ g_print ("progress: %d %d -1 mkfs\n", num_erase_passes + 1, num_erase_passes + 2);
+
+ if (command_line != NULL) {
+ if (!g_spawn_command_line_sync (command_line,
+ NULL,
+ &standard_error,
+ &exit_status,
+ &error)) {
+ g_printerr ("cannot spawn '%s'\n", command_line);
+ goto out;
+ }
+ if (WEXITSTATUS (exit_status) != 0) {
+ g_printerr ("helper failed with:\n%s", standard_error);
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+out:
+ g_free (standard_error);
+ g_free (command_line);
+ g_free (erase);
+ return ret;
+}
--- /dev/null
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2008 David Zeuthen <david@fubar.dk>
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+
+#include <glib.h>
+
+#ifndef __JOB_SHARED_H__
+#define __JOB_SHARED_H__
+
+/* TODO: maybe move to private static library if there's a lot of shared stuff */
+
+#define ERASE_SIZE (128*1024)
+
+/**
+ * parse_passes_from_erase:
+ * @str: string to pass, e.g. #NULL, "none", "full", "full3pass",
+ * "full7pass", "full35pass".
+ *
+ * Parses an erase option string and returns the number of passes;
+ * #NULL and "none" maps into 0, "full" maps into 1, "full3pass" maps
+ * into 3, "full7pass" maps into 7, and "full35pass" maps into 35. If
+ * the string cannot be parsed, -1 is returned.
+ *
+ * Returns: Number of passes or -1 on error.
+ **/
+static inline int
+task_zero_device_parse_option (const char *str)
+{
+ int ret;
+
+ if (str == NULL) {
+ ret = 0;
+ } else if (strcmp (str, "none") == 0) {
+ ret = 0;
+ } else if (strcmp (str, "full") == 0) {
+ ret = 1;
+ } else if (strcmp (str, "full3pass") == 0) {
+ ret = 3;
+ } else if (strcmp (str, "full7pass") == 0) {
+ ret = 7;
+ } else if (strcmp (str, "full35pass") == 0) {
+ ret = 35;
+ } else {
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static inline gboolean
+do_write (int fd, void *buf, int num)
+{
+ gboolean ret;
+ ret = FALSE;
+again:
+ if (write (fd, buf, num) != (int) num) {
+ if (errno == EAGAIN) {
+ goto again;
+ } else {
+ g_printerr ("%d: error writing %d bytes: %m\n", getpid (), num);
+ goto out;
+ }
+ }
+ ret = TRUE;
+out:
+ return ret;
+}
+
+
+/**
+ * task_zero_device:
+ * @device: device to zero
+ * @num_passes: number of passes, 0, 1, 3, 7 and 35 supported. See
+ * the function task_zero_device_parse_option() for details.
+ * @cur_task: current task
+ * @num_tasks: number of tasks
+ *
+ * Zeroes (parts of) a device. If @num_passes is 0 then only the areas
+ * where file system signatures are normally stored are zeroed,
+ * otherwise the device is cleared @num_passes times using methods
+ * compliant with US DoD 5220.
+ *
+ * This task will use @num_passes + 1 task slots.
+ *
+ * See these websites.
+ *
+ * http://ask.metafilter.com/83005/How-long-does-a-7-Pass-US-DoD-5220-method-take
+ * http://en.wikipedia.org/wiki/Gutmann_method
+ * http://en.wikipedia.org/wiki/National_Industrial_Security_Program
+ *
+ * for more details on secure erase.
+ *
+ * Returns: #TRUE unless erasing failed or an incoming parameter was
+ * invalid.
+ **/
+static inline gboolean
+task_zero_device (const char *device, int num_passes, int cur_task, int num_tasks)
+{
+ int fd;
+ gboolean ret;
+ guint64 size;
+ guint64 cursor;
+ int percent;
+ int old_percent;
+ char buf[ERASE_SIZE];
+
+ fd = 0;
+ ret = FALSE;
+
+ fd = open (device, O_WRONLY);
+ if (fd < 0) {
+ g_printerr ("cannot open device: %m\n");
+ goto out;
+ }
+
+ if (ioctl (fd, BLKGETSIZE64, &size) != 0) {
+ g_printerr ("cannot determine size of device: %m\n");
+ goto out;
+ }
+
+ memset (buf, '\0', sizeof (buf));
+
+
+ if (num_passes == 0) {
+ guint64 wipe_size;
+
+ g_print ("progress: %d %d 0 zeroing\n", cur_task, num_tasks);
+
+ /* wipe first and last 16kb. TODO: check 16kb is the right number */
+ wipe_size = 16 * 1024;
+ g_assert (sizeof (buf) >= wipe_size);
+
+ if (wipe_size > size) {
+ wipe_size = size;
+ }
+
+ if (!do_write (fd, buf, wipe_size))
+ goto out;
+
+ if (lseek (fd, size - wipe_size, SEEK_SET) == (off_t) -1) {
+ g_printerr ("cannot seek to %lld: %m", size - wipe_size);
+ goto out;
+ }
+
+ if (!do_write (fd, buf, wipe_size))
+ goto out;
+
+ } else if (num_passes == 1) {
+ cursor = 0;
+ old_percent = 0;
+ g_print ("progress: %d %d 0 zeroing\n", cur_task, num_tasks);
+ while (cursor < size) {
+ guint64 num;
+
+ num = sizeof (buf);
+ if (size - cursor < num)
+ num = size - cursor;
+ if (!do_write (fd, buf, num))
+ goto out;
+
+ cursor += num;
+
+ percent = 100 * cursor / size;
+ if (percent > old_percent) {
+ g_print ("progress: %d %d %d zeroing\n", cur_task, num_tasks, percent);
+ old_percent = percent;
+ }
+ }
+ g_print ("progress: %d %d -1 sync\n", cur_task + 1, num_tasks);
+ fsync (fd);
+ } else if (num_passes == 3) {
+ g_printerr ("only 0 and 1 erase passes is implemented for now\n");
+ goto out;
+ } else if (num_passes == 7) {
+ g_printerr ("only 0 and 1 erase passes is implemented for now\n");
+ goto out;
+ } else if (num_passes == 35) {
+ g_printerr ("only 0 and 1 erase passes is implemented for now\n");
+ goto out;
+ }
+
+ ret = TRUE;
+
+out:
+ if (fd >= 0)
+ close (fd);
+ return ret;
+}
+
+
+#endif /* __JOB_SHARED_H__ */
</method>
<!-- TODO: docs -->
+ <method name="CancelJob">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ </method>
+
+ <!-- TODO: docs -->
<method name="Unmount">
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="options" direction="in" type="as"/>
</method>
+ <!-- TODO: docs -->
+ <method name="Erase">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="options" direction="in" type="as"/>
+ </method>
+
+ <!-- CreateFilesystem:
+ @fstype: the of file system to create. Pass "empty" to
+ not create a file system. Use @TODO@ to get
+ a list of file systems that can be created.
+
+ @options: List of options. Known options that are file system
+ independent are:
+ - label=: for setting the file system label
+ - erase=: whether to erase the device before
+ creating a file system. Valid values
+ include "none", "full", "full7pass" and
+ "full35pass".
+
+ Create a file system on a device.
+ -->
+ <method name="CreateFilesystem">
+ <annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
+ <arg name="fstype" direction="in" type="s"/>
+ <arg name="options" direction="in" type="as"/>
+ </method>
+
<!-- BEGIN LIST OF SIGNALS -->
- <!-- Something about the device changed -->
+ <!-- Something about the device changed. Changes in job state
+ wont trigger this signal; see the 'JobChanged' signal -->
<signal name="Changed"/>
+ <!-- Job state changed; clients should listen to this signal
+ to avoid polling the daemon for job state -->
+ <signal name="JobChanged">
+ <arg name="job-in-progress" type="b"/>
+ <arg name="job-is-cancellable" type="b"/>
+ <arg name="job-id" type="s"/>
+ <arg name="job-num-tasks" type="i"/>
+ <arg name="job-cur-task" type="i"/>
+ <arg name="job-cur-task-id" type="s"/>
+ <arg name="job-cur-task-percentage" type="d"/>
+ </signal>
+
<!-- BEGIN LIST OF PROPERTIES
A general note about properties: the set of values returned
<property name="device-size" type="t" access="read"/>
<property name="device-block-size" type="t" access="read"/>
+ <!-- The job properties specify if a job initiated via the
+ DeviceKit-disks daemon is currently in progress. A job may
+ be split into several sequential tasks; in that case
+ 'job-num-tasks' will be greater than zero. If it is 0 none
+ of the 'job-cur-*' properties will be set.
+
+ The 'job-id' property is used to identify the job and maps
+ 1-1 with the names of the method calls on this interface,
+ e.g. 'Erase', 'CreateFilesystem' and so on.
+
+ Note that the 'job-cur-task' percentage starts at 0. The
+ percentage is a number between -1 and 100. If set to -1 it
+ means the progress of the current is unknown. The task id is
+ a well-defined name defining the current subtask of the job;
+ known tasks id's are
+
+ - zeroing: zeroing data on the device
+ - sync: flushing data to the device
+ - mkfs: creating file system
+ -->
+ <property name="job-in-progress" type="b" access="read"/>
+ <property name="job-id" type="s" access="read"/>
+ <property name="job-is-cancellable" type="b" access="read"/>
+ <property name="job-num-tasks" type="i" access="read"/>
+ <property name="job-cur-task" type="i" access="read"/>
+ <property name="job-cur-task-id" type="s" access="read"/>
+ <property name="job-cur-task-percentage" type="d" access="read"/>
+
<!-- the usage is a result of probing for signatures on the block
device; known values are
<arg name="device" type="o"/>
</signal>
+ <!-- Job state on a device was changed -->
+ <signal name="DeviceJobChanged">
+ <arg name="device" type="o"/>
+ <arg name="job-in-progress" type="b"/>
+ <arg name="job-is-cancellable" type="b"/>
+ <arg name="job-id" type="s"/>
+ <arg name="job-num-tasks" type="i"/>
+ <arg name="job-cur-task" type="i"/>
+ <arg name="job-cur-task-id" type="s"/>
+ <arg name="job-cur-task-percentage" type="d"/>
+ </signal>
+
</interface>
</node>
$(POLKIT_DBUS_CFLAGS) \
$(GLIB_CFLAGS)
-BUILT_SOURCES = \
- devkit-disks-daemon-glue.h \
- devkit-disks-device-glue.h
+BUILT_SOURCES = \
+ devkit-disks-daemon-glue.h \
+ devkit-disks-device-glue.h \
+ devkit-disks-marshal.h devkit-disks-marshal.c
+
+devkit-disks-marshal.h: $(top_srcdir)/src/devkit-disks-marshal.list
+ glib-genmarshal $< --prefix=devkit_disks_marshal --header > $@
+
+devkit-disks-marshal.c: $(top_srcdir)/src/devkit-disks-marshal.list
+ echo "#include \"devkit-disks-marshal.h\"" > $@ && glib-genmarshal $< --prefix=devkit_disks_marshal --body >> $@
devkit-disks-daemon-glue.h: $(top_srcdir)/src/org.freedesktop.DeviceKit.Disks.xml Makefile.am
dbus-binding-tool --prefix=devkit_disks_daemon --mode=glib-client --output=devkit-disks-daemon-glue.h $(top_srcdir)/src/org.freedesktop.DeviceKit.Disks.xml
#include "devkit-disks-daemon-glue.h"
#include "devkit-disks-device-glue.h"
+#include "devkit-disks-marshal.h"
static DBusGConnection *bus = NULL;
static DBusGProxy *disks_proxy = NULL;
static GMainLoop *loop;
-static gboolean opt_inhibit = FALSE;
-static gboolean opt_enumerate = FALSE;
-static gboolean opt_monitor = FALSE;
-static gboolean opt_monitor_detail = FALSE;
-static char *opt_show_info = NULL;
-static char *opt_mount = NULL;
-static char *opt_mount_fstype = NULL;
-static char *opt_mount_options = NULL;
-static char *opt_unmount = NULL;
-static char *opt_unmount_options = NULL;
+static gboolean opt_inhibit = FALSE;
+static gboolean opt_enumerate = FALSE;
+static gboolean opt_monitor = FALSE;
+static gboolean opt_monitor_detail = FALSE;
+static char *opt_show_info = NULL;
+static char *opt_mount = NULL;
+static char *opt_mount_fstype = NULL;
+static char *opt_mount_options = NULL;
+static char *opt_unmount = NULL;
+static char *opt_unmount_options = NULL;
+static char *opt_erase = NULL;
+static char *opt_erase_options = NULL;
+static char *opt_create_fs = NULL;
+static char *opt_create_fs_type = NULL;
+static char *opt_create_fs_options = NULL;
static gboolean do_monitor (void);
static void do_show_info (const char *object_path);
}
static void
-device_added_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data)
+do_create_fs (const char *object_path,
+ const char *fs_type,
+ const char *options)
{
- g_print ("added: %s\n", object_path);
- if (opt_monitor_detail) {
- do_show_info (object_path);
- g_print ("\n");
- }
-}
-
-static void
-device_changed_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data)
-{
- g_print ("changed: %s\n", object_path);
- if (opt_monitor_detail) {
- /* TODO: would be nice to just show the diff */
- do_show_info (object_path);
- g_print ("\n");
- }
-}
+ DBusGProxy *proxy;
+ GError *error;
+ char **split_options;
-static void
-device_removed_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data)
-{
- g_print ("removed: %s\n", object_path);
-}
+ split_options = NULL;
+ if (options != NULL)
+ split_options = g_strsplit (options, ",", 0);
-/* --- SUCKY CODE BEGIN --- */
+ proxy = dbus_g_proxy_new_for_name (bus,
+ "org.freedesktop.DeviceKit.Disks",
+ object_path,
+ "org.freedesktop.DeviceKit.Disks.Device");
-/* This totally sucks; dbus-bindings-tool and dbus-glib should be able
- * to do this for us.
- *
- * TODO: keep in sync with code in tools/devkit-disks in DeviceKit-disks.
- */
+try_again:
+ error = NULL;
+ /* Stupid glue don't let me tweak the timeout */
+ if (!dbus_g_proxy_call_with_timeout (proxy,
+ "CreateFilesystem",
+ INT_MAX,
+ &error,
+ G_TYPE_STRING,
+ fs_type,
+ G_TYPE_STRV,
+ split_options,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID)) {
+ PolKitAction *pk_action;
+ PolKitResult pk_result;
-static char *
-get_property_object_path (DBusGConnection *bus,
- const char *svc_name,
- const char *obj_path,
- const char *if_name,
- const char *prop_name)
-{
- char *ret;
- DBusGProxy *proxy;
- GValue value = { 0 };
- GError *error = NULL;
+ if (polkit_dbus_gerror_parse (error, &pk_action, &pk_result)) {
+ if (pk_result != POLKIT_RESULT_NO) {
+ char *action_id;
+ DBusError d_error;
- ret = NULL;
- proxy = dbus_g_proxy_new_for_name (bus,
- svc_name,
- obj_path,
- "org.freedesktop.DBus.Properties");
- if (!dbus_g_proxy_call (proxy,
- "Get",
- &error,
- G_TYPE_STRING,
- if_name,
- G_TYPE_STRING,
- prop_name,
- G_TYPE_INVALID,
- G_TYPE_VALUE,
- &value,
- G_TYPE_INVALID)) {
- g_warning ("error: %s\n", error->message);
- g_error_free (error);
- goto out;
+ polkit_action_get_action_id (pk_action, &action_id);
+ dbus_error_init (&d_error);
+ if (polkit_auth_obtain (action_id,
+ 0,
+ getpid (),
+ &d_error)) {
+ polkit_action_unref (pk_action);
+ goto try_again;
+ } else {
+ g_print ("Obtaining authorization failed: %s: %s\n",
+ d_error.name, d_error.message);
+ dbus_error_free (&d_error);
+ goto out;
+ }
+ }
+ polkit_action_unref (pk_action);
+ g_error_free (error);
+ goto out;
+ } else {
+ g_print ("CreateFilesystem failed: %s\n", error->message);
+ g_error_free (error);
+ goto out;
+ }
}
-
- ret = (char *) g_value_get_boxed (&value);
-
out:
- g_object_unref (proxy);
- return ret;
+ g_strfreev (split_options);
}
-static char *
-get_property_string (DBusGConnection *bus,
- const char *svc_name,
- const char *obj_path,
- const char *if_name,
- const char *prop_name)
+static void
+do_erase (const char *object_path,
+ const char *options)
{
- char *ret;
DBusGProxy *proxy;
- GValue value = { 0 };
- GError *error = NULL;
+ GError *error;
+ char **split_options;
- ret = NULL;
- proxy = dbus_g_proxy_new_for_name (bus,
- svc_name,
- obj_path,
- "org.freedesktop.DBus.Properties");
- if (!dbus_g_proxy_call (proxy,
- "Get",
- &error,
- G_TYPE_STRING,
- if_name,
- G_TYPE_STRING,
- prop_name,
- G_TYPE_INVALID,
- G_TYPE_VALUE,
- &value,
- G_TYPE_INVALID)) {
- g_warning ("error: %s\n", error->message);
- g_error_free (error);
- goto out;
- }
+ split_options = NULL;
+ if (options != NULL)
+ split_options = g_strsplit (options, ",", 0);
- ret = (char *) g_value_get_string (&value);
+ proxy = dbus_g_proxy_new_for_name (bus,
+ "org.freedesktop.DeviceKit.Disks",
+ object_path,
+ "org.freedesktop.DeviceKit.Disks.Device");
-out:
- g_object_unref (proxy);
- return ret;
-}
+try_again:
+ error = NULL;
+ /* Stupid glue don't let me tweak the timeout */
+ if (!dbus_g_proxy_call_with_timeout (proxy,
+ "Erase",
+ INT_MAX,
+ &error,
+ G_TYPE_STRV,
+ split_options,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID)) {
+ PolKitAction *pk_action;
+ PolKitResult pk_result;
-static gboolean
-get_property_boolean (DBusGConnection *bus,
- const char *svc_name,
- const char *obj_path,
- const char *if_name,
- const char *prop_name)
-{
- gboolean ret;
- DBusGProxy *proxy;
- GValue value = { 0 };
- GError *error = NULL;
+ if (polkit_dbus_gerror_parse (error, &pk_action, &pk_result)) {
+ if (pk_result != POLKIT_RESULT_NO) {
+ char *action_id;
+ DBusError d_error;
- ret = FALSE;
- proxy = dbus_g_proxy_new_for_name (bus,
- svc_name,
- obj_path,
- "org.freedesktop.DBus.Properties");
- if (!dbus_g_proxy_call (proxy,
- "Get",
- &error,
- G_TYPE_STRING,
- if_name,
- G_TYPE_STRING,
- prop_name,
- G_TYPE_INVALID,
- G_TYPE_VALUE,
- &value,
- G_TYPE_INVALID)) {
- g_warning ("error: %s\n", error->message);
- g_error_free (error);
- goto out;
+ polkit_action_get_action_id (pk_action, &action_id);
+ dbus_error_init (&d_error);
+ if (polkit_auth_obtain (action_id,
+ 0,
+ getpid (),
+ &d_error)) {
+ polkit_action_unref (pk_action);
+ goto try_again;
+ } else {
+ g_print ("Obtaining authorization failed: %s: %s\n",
+ d_error.name, d_error.message);
+ dbus_error_free (&d_error);
+ goto out;
+ }
+ }
+ polkit_action_unref (pk_action);
+ g_error_free (error);
+ goto out;
+ } else {
+ g_print ("Erase failed: %s\n", error->message);
+ g_error_free (error);
+ goto out;
+ }
}
-
- ret = (gboolean) g_value_get_boolean (&value);
-
out:
- g_object_unref (proxy);
- return ret;
+ g_strfreev (split_options);
}
-static guint64
-get_property_uint64 (DBusGConnection *bus,
- const char *svc_name,
- const char *obj_path,
- const char *if_name,
- const char *prop_name)
+static void
+device_added_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data)
{
- guint64 ret;
- DBusGProxy *proxy;
- GValue value = { 0 };
- GError *error = NULL;
-
- ret = 0;
- proxy = dbus_g_proxy_new_for_name (bus,
- svc_name,
- obj_path,
- "org.freedesktop.DBus.Properties");
- if (!dbus_g_proxy_call (proxy,
- "Get",
- &error,
- G_TYPE_STRING,
- if_name,
- G_TYPE_STRING,
- prop_name,
- G_TYPE_INVALID,
- G_TYPE_VALUE,
- &value,
- G_TYPE_INVALID)) {
- g_warning ("error: %s\n", error->message);
- g_error_free (error);
- goto out;
- }
-
- ret = (guint64) g_value_get_uint64 (&value);
-
-out:
- g_object_unref (proxy);
- return ret;
+ g_print ("added: %s\n", object_path);
+ if (opt_monitor_detail) {
+ do_show_info (object_path);
+ g_print ("\n");
+ }
}
-static GArray *
-get_property_uint64_array (DBusGConnection *bus,
- const char *svc_name,
- const char *obj_path,
- const char *if_name,
- const char *prop_name)
+static void
+device_changed_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data)
{
- GArray *ret;
- DBusGProxy *proxy;
- GValue value = { 0 };
- GError *error = NULL;
-
- ret = 0;
- proxy = dbus_g_proxy_new_for_name (bus,
- svc_name,
- obj_path,
- "org.freedesktop.DBus.Properties");
- if (!dbus_g_proxy_call (proxy,
- "Get",
- &error,
- G_TYPE_STRING,
- if_name,
- G_TYPE_STRING,
- prop_name,
- G_TYPE_INVALID,
- G_TYPE_VALUE,
- &value,
- G_TYPE_INVALID)) {
- g_warning ("error: %s\n", error->message);
- g_error_free (error);
- goto out;
- }
-
- ret = (GArray*) g_value_get_boxed (&value);
-
-out:
- g_object_unref (proxy);
- return ret;
+ g_print ("changed: %s\n", object_path);
+ if (opt_monitor_detail) {
+ /* TODO: would be nice to just show the diff */
+ do_show_info (object_path);
+ g_print ("\n");
+ }
}
-static int
-get_property_int (DBusGConnection *bus,
- const char *svc_name,
- const char *obj_path,
- const char *if_name,
- const char *prop_name)
+static void
+print_job (gboolean job_in_progress,
+ const char *job_id,
+ gboolean job_is_cancellable,
+ int job_num_tasks,
+ int job_cur_task,
+ const char *job_cur_task_id,
+ double job_cur_task_percentage)
{
- int ret;
- DBusGProxy *proxy;
- GValue value = { 0 };
- GError *error = NULL;
-
- ret = 0;
- proxy = dbus_g_proxy_new_for_name (bus,
- svc_name,
- obj_path,
- "org.freedesktop.DBus.Properties");
- if (!dbus_g_proxy_call (proxy,
- "Get",
- &error,
- G_TYPE_STRING,
- if_name,
- G_TYPE_STRING,
- prop_name,
- G_TYPE_INVALID,
- G_TYPE_VALUE,
- &value,
- G_TYPE_INVALID)) {
- g_warning ("error: %s\n", error->message);
- g_error_free (error);
- goto out;
+ if (job_in_progress) {
+ if (job_num_tasks > 0) {
+ g_print (" job underway: %s: %d/%d tasks (%s",
+ job_id,
+ job_cur_task + 1,
+ job_num_tasks,
+ job_cur_task_id);
+ if (job_cur_task_percentage >= 0)
+ g_print (" @ %3.0lf%%", job_cur_task_percentage);
+ if (job_is_cancellable)
+ g_print (", cancellable");
+ g_print (")\n");
+ } else {
+ g_print (" job underway: %s: unknown progress", job_id);
+ if (job_is_cancellable)
+ g_print (", cancellable");
+ g_print ("\n");
+ }
+ } else {
+ g_print (" job underway: no\n");
}
-
- ret = (guint64) g_value_get_int (&value);
-
-out:
- g_object_unref (proxy);
- return ret;
}
-static char **
-get_property_strlist (DBusGConnection *bus,
- const char *svc_name,
- const char *obj_path,
- const char *if_name,
- const char *prop_name)
+static void
+device_job_changed_signal_handler (DBusGProxy *proxy,
+ const char *object_path,
+ gboolean job_in_progress,
+ const char *job_id,
+ gboolean job_is_cancellable,
+ int job_num_tasks,
+ int job_cur_task,
+ const char *job_cur_task_id,
+ double job_cur_task_percentage,
+ gpointer user_data)
{
- char **ret;
- DBusGProxy *proxy;
- GValue value = { 0 };
- GError *error = NULL;
-
- ret = NULL;
- proxy = dbus_g_proxy_new_for_name (bus,
- svc_name,
- obj_path,
- "org.freedesktop.DBus.Properties");
- if (!dbus_g_proxy_call (proxy,
- "Get",
- &error,
- G_TYPE_STRING,
- if_name,
- G_TYPE_STRING,
- prop_name,
- G_TYPE_INVALID,
- G_TYPE_VALUE,
- &value,
- G_TYPE_INVALID)) {
- g_warning ("error: %s\n", error->message);
- g_error_free (error);
- goto out;
- }
+ g_print ("job-changed: %s\n", object_path);
+ if (opt_monitor_detail) {
+ print_job (job_in_progress,
+ job_id,
+ job_is_cancellable,
+ job_num_tasks,
+ job_cur_task,
+ job_cur_task_id,
+ job_cur_task_percentage);
+ }
+}
- ret = (char **) g_value_get_boxed (&value);
+static void
+device_removed_signal_handler (DBusGProxy *proxy, const char *object_path, gpointer user_data)
+{
+ g_print ("removed: %s\n", object_path);
+}
-out:
- /* don't crash; return an empty list */
- if (ret == NULL) {
- ret = g_new0 (char *, 1);
- *ret = NULL;
- }
+/* --- SUCKY CODE BEGIN --- */
- g_object_unref (proxy);
- return ret;
-}
+/* This totally sucks; dbus-bindings-tool and dbus-glib should be able
+ * to do this for us.
+ *
+ * TODO: keep in sync with code in tools/devkit-disks in DeviceKit-disks.
+ */
typedef struct
{
guint64 device_size;
guint64 device_block_size;
+ gboolean job_in_progress;
+ char *job_id;
+ gboolean job_is_cancellable;
+ int job_num_tasks;
+ int job_cur_task;
+ char *job_cur_task_id;
+ double job_cur_task_percentage;
+
char *id_usage;
char *id_type;
char *id_version;
char *drive_serial;
} DeviceProperties;
+static void
+collect_props (const char *key, const GValue *value, DeviceProperties *props)
+{
+ gboolean handled = TRUE;
+
+ if (strcmp (key, "native-path") == 0)
+ props->native_path = g_strdup (g_value_get_string (value));
+
+ else if (strcmp (key, "device-file") == 0)
+ props->device_file = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "device-file-by-id") == 0)
+ props->device_file_by_id = g_strdupv (g_value_get_boxed (value));
+ else if (strcmp (key, "device-file-by-path") == 0)
+ props->device_file_by_path = g_strdupv (g_value_get_boxed (value));
+ else if (strcmp (key, "device-is-partition") == 0)
+ props->device_is_partition = g_value_get_boolean (value);
+ else if (strcmp (key, "device-is-partition-table") == 0)
+ props->device_is_partition_table = g_value_get_boolean (value);
+ else if (strcmp (key, "device-is-removable") == 0)
+ props->device_is_removable = g_value_get_boolean (value);
+ else if (strcmp (key, "device-is-media-available") == 0)
+ props->device_is_media_available = g_value_get_boolean (value);
+ else if (strcmp (key, "device-is-drive") == 0)
+ props->device_is_drive = g_value_get_boolean (value);
+ else if (strcmp (key, "device-is-mounted") == 0)
+ props->device_is_mounted = g_value_get_boolean (value);
+ else if (strcmp (key, "device-mount-path") == 0)
+ props->device_mount_path = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "device-size") == 0)
+ props->device_size = g_value_get_uint64 (value);
+ else if (strcmp (key, "device-block-size") == 0)
+ props->device_block_size = g_value_get_uint64 (value);
+
+ else if (strcmp (key, "job-in-progress") == 0)
+ props->job_in_progress = g_value_get_boolean (value);
+ else if (strcmp (key, "job-id") == 0)
+ props->job_id = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "job-is-cancellable") == 0)
+ props->job_is_cancellable = g_value_get_boolean (value);
+ else if (strcmp (key, "job-num-tasks") == 0)
+ props->job_num_tasks = g_value_get_int (value);
+ else if (strcmp (key, "job-cur-task") == 0)
+ props->job_cur_task = g_value_get_int (value);
+ else if (strcmp (key, "job-cur-task-id") == 0)
+ props->job_cur_task_id = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "job-cur-task-percentage") == 0)
+ props->job_cur_task_percentage = g_value_get_double (value);
+
+ else if (strcmp (key, "id-usage") == 0)
+ props->id_usage = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "id-type") == 0)
+ props->id_type = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "id-version") == 0)
+ props->id_version = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "id-uuid") == 0)
+ props->id_uuid = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "id-label") == 0)
+ props->id_label = g_strdup (g_value_get_string (value));
+
+ else if (strcmp (key, "partition-slave") == 0)
+ props->partition_slave = g_strdup (g_value_get_boxed (value));
+ else if (strcmp (key, "partition-scheme") == 0)
+ props->partition_scheme = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "partition-number") == 0)
+ props->partition_number = g_value_get_int (value);
+ else if (strcmp (key, "partition-type") == 0)
+ props->partition_type = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "partition-label") == 0)
+ props->partition_label = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "partition-uuid") == 0)
+ props->partition_uuid = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "partition-flags") == 0)
+ props->partition_flags = g_strdupv (g_value_get_boxed (value));
+ else if (strcmp (key, "partition-offset") == 0)
+ props->partition_offset = g_value_get_uint64 (value);
+ else if (strcmp (key, "partition-size") == 0)
+ props->partition_size = g_value_get_uint64 (value);
+
+ else if (strcmp (key, "partition-table-scheme") == 0)
+ props->partition_table_scheme = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "partition-table-count") == 0)
+ props->partition_table_count = g_value_get_int (value);
+ else if (strcmp (key, "partition-table-max-number") == 0)
+ props->partition_table_max_number = g_value_get_int (value);
+ else if (strcmp (key, "partition-table-offsets") == 0) {
+ GValue dest_value = {0,};
+ g_value_init (&dest_value, dbus_g_type_get_collection ("GArray", G_TYPE_UINT64));
+ g_value_copy (value, &dest_value);
+ props->partition_table_offsets = g_value_get_boxed (&dest_value);
+ } else if (strcmp (key, "partition-table-sizes") == 0) {
+ GValue dest_value = {0,};
+ g_value_init (&dest_value, dbus_g_type_get_collection ("GArray", G_TYPE_UINT64));
+ g_value_copy (value, &dest_value);
+ props->partition_table_sizes = g_value_get_boxed (&dest_value);
+ }
+
+ else if (strcmp (key, "drive-vendor") == 0)
+ props->drive_vendor = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "drive-model") == 0)
+ props->drive_model = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "drive-revision") == 0)
+ props->drive_revision = g_strdup (g_value_get_string (value));
+ else if (strcmp (key, "drive-serial") == 0)
+ props->drive_serial = g_strdup (g_value_get_string (value));
+
+ else
+ handled = FALSE;
+
+ if (!handled)
+ g_warning ("unhandled property '%s'", key);
+}
+
static DeviceProperties *
device_properties_get (DBusGConnection *bus,
const char *object_path)
{
DeviceProperties *props;
+ GError *error;
+ GHashTable *hash_table;
+ DBusGProxy *prop_proxy;
+ const char *ifname = "org.freedesktop.DeviceKit.Disks.Device";
props = g_new0 (DeviceProperties, 1);
- props->native_path = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "native-path");
-
- props->device_file = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-file");
- props->device_file_by_id = get_property_strlist (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-file-by-id");
- props->device_file_by_path = get_property_strlist (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-file-by-path");
- props->device_is_partition = get_property_boolean (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-is-partition");
- props->device_is_partition_table = get_property_boolean (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-is-partition-table");
- props->device_is_removable = get_property_boolean (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-is-removable");
- props->device_is_media_available = get_property_boolean (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-is-media-available");
- props->device_is_drive = get_property_boolean (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-is-drive");
- props->device_is_mounted = get_property_boolean (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-is-mounted");
- props->device_mount_path = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-mount-path");
- props->device_size = get_property_uint64 (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-size");
- props->device_block_size = get_property_uint64 (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "device-block-size");
-
- props->id_usage = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "id-usage");
- props->id_type = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "id-type");
- props->id_version = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "id-version");
- props->id_uuid = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "id-uuid");
- props->id_label = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "id-label");
-
- props->partition_slave = get_property_object_path (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-slave");
- props->partition_scheme = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-scheme");
- props->partition_number = get_property_int (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-number");
- props->partition_type = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-type");
- props->partition_label = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-label");
- props->partition_uuid = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-uuid");
- props->partition_flags = get_property_strlist (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-flags");
- props->partition_offset = get_property_uint64 (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-offset");
- props->partition_size = get_property_uint64 (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-size");
-
- props->partition_table_scheme = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-table-scheme");
- props->partition_table_count = get_property_int (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-table-count");
- props->partition_table_max_number = get_property_int (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-table-max-number");
- props->partition_table_offsets = get_property_uint64_array (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-table-offsets");
- props->partition_table_sizes = get_property_uint64_array (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "partition-table-sizes");
-
- props->drive_vendor = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "drive-vendor");
- props->drive_model = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "drive-model");
- props->drive_revision = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "drive-revision");
- props->drive_serial = get_property_string (
- bus,
- "org.freedesktop.DeviceKit.Disks",
- object_path,
- "org.freedesktop.DeviceKit.Disks.Device",
- "drive-serial");
+ prop_proxy = dbus_g_proxy_new_for_name (bus,
+ "org.freedesktop.DeviceKit.Disks",
+ object_path,
+ "org.freedesktop.DBus.Properties");
+ error = NULL;
+ if (!dbus_g_proxy_call (prop_proxy,
+ "GetAll",
+ &error,
+ G_TYPE_STRING,
+ ifname,
+ G_TYPE_INVALID,
+ dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
+ &hash_table,
+ G_TYPE_INVALID)) {
+ g_warning ("Couldn't call GetAll() to get properties for %s: %s", object_path, error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ g_hash_table_foreach (hash_table, (GHFunc) collect_props, props);
+
+ g_hash_table_unref (hash_table);
+
+out:
+ g_object_unref (prop_proxy);
return props;
}
g_strfreev (props->device_file_by_id);
g_strfreev (props->device_file_by_path);
g_free (props->device_mount_path);
+ g_free (props->job_id);
+ g_free (props->job_cur_task_id);
g_free (props->id_usage);
g_free (props->id_type);
g_free (props->id_version);
G_CALLBACK (device_removed_signal_handler), NULL, NULL);
dbus_g_proxy_connect_signal (disks_proxy, "DeviceChanged",
G_CALLBACK (device_changed_signal_handler), NULL, NULL);
+ dbus_g_proxy_connect_signal (disks_proxy, "DeviceJobChanged",
+ G_CALLBACK (device_job_changed_signal_handler), NULL, NULL);
g_main_loop_run (loop);
out:
g_print (" mount path: %s\n", props->device_mount_path);
g_print (" size: %lld\n", props->device_size);
g_print (" block size: %lld\n", props->device_block_size);
+
+ print_job (props->job_in_progress,
+ props->job_id,
+ props->job_is_cancellable,
+ props->job_num_tasks,
+ props->job_cur_task,
+ props->job_cur_task_id,
+ props->job_cur_task_percentage);
g_print (" usage: %s\n", props->id_usage);
g_print (" type: %s\n", props->id_type);
g_print (" version: %s\n", props->id_version);
{ "monitor", 0, 0, G_OPTION_ARG_NONE, &opt_monitor, "Monitor activity from the disk daemon", NULL },
{ "monitor-detail", 0, 0, G_OPTION_ARG_NONE, &opt_monitor_detail, "Monitor with detail", NULL },
{ "show-info", 0, 0, G_OPTION_ARG_STRING, &opt_show_info, "Show information about object path", NULL },
+
{ "mount", 0, 0, G_OPTION_ARG_STRING, &opt_mount, "Mount the device given by the object path", NULL },
{ "mount-fstype", 0, 0, G_OPTION_ARG_STRING, &opt_mount_fstype, "Specify file system type", NULL },
{ "mount-options", 0, 0, G_OPTION_ARG_STRING, &opt_mount_options, "Mount options separated by comma", NULL },
+
{ "unmount", 0, 0, G_OPTION_ARG_STRING, &opt_unmount, "Unmount the device given by the object path", NULL },
{ "unmount-options", 0, 0, G_OPTION_ARG_STRING, &opt_unmount_options, "Unmount options separated by comma", NULL },
+
+ { "erase", 0, 0, G_OPTION_ARG_STRING, &opt_erase, "Erase a device", NULL },
+ { "erase-options", 0, 0, G_OPTION_ARG_STRING, &opt_erase_options, "Erase options", NULL },
+
+ { "create-fs", 0, 0, G_OPTION_ARG_STRING, &opt_create_fs, "Create a file system", NULL },
+ { "create-fs-type", 0, 0, G_OPTION_ARG_STRING, &opt_create_fs_type, "File system type to create", NULL },
+ { "create-fs-options", 0, 0, G_OPTION_ARG_STRING, &opt_create_fs_options, "File system create options", NULL },
{ NULL }
};
goto out;
}
+ dbus_g_object_register_marshaller (
+ devkit_disks_marshal_VOID__STRING_BOOLEAN_STRING_BOOLEAN_INT_INT_STRING_DOUBLE,
+ G_TYPE_NONE,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_STRING,
+ G_TYPE_DOUBLE,
+ G_TYPE_INVALID);
+
disks_proxy = dbus_g_proxy_new_for_name (bus,
"org.freedesktop.DeviceKit.Disks",
"/",
dbus_g_proxy_add_signal (disks_proxy, "DeviceAdded", G_TYPE_STRING, G_TYPE_INVALID);
dbus_g_proxy_add_signal (disks_proxy, "DeviceRemoved", G_TYPE_STRING, G_TYPE_INVALID);
dbus_g_proxy_add_signal (disks_proxy, "DeviceChanged", G_TYPE_STRING, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal (disks_proxy,
+ "DeviceJobChanged",
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_STRING,
+ G_TYPE_BOOLEAN,
+ G_TYPE_INT,
+ G_TYPE_INT,
+ G_TYPE_STRING,
+ G_TYPE_DOUBLE,
+ G_TYPE_INVALID);
if (opt_inhibit) {
char *cookie;
do_mount (opt_mount, opt_mount_fstype, opt_mount_options);
} else if (opt_unmount != NULL) {
do_unmount (opt_unmount, opt_unmount_options);
+ } else if (opt_erase != NULL) {
+ do_erase (opt_erase, opt_erase_options);
+ } else if (opt_create_fs != NULL && opt_create_fs_type != NULL) {
+ do_create_fs (opt_create_fs, opt_create_fs_type, opt_create_fs_options);
}
ret = 0;