+
+ACTION!="add", GOTO="probe_parttable_end"
+SUBSYSTEM!="block", GOTO="probe_parttable_end"
+
+# ignore partitions that span the entire disk
+ATTR{whole_disk}=="*", GOTO="persistent_storage_end"
+
+# ignore non-cdrom ide drivers; these causes loops
+KERNEL=="hd*[!0-9]", ATTR{removable}=="1", DRIVERS=="ide-cs|ide-floppy", GOTO="probe_parttable_end"
+KERNEL=="hd*[0-9]", ATTR{removable}=="1", GOTO="probe_parttable_end"
+
+# scan for partition table only on if we're not a partition
+ATTR{range}=="[0-9]*", IMPORT{program}="part_id $tempnode"
+
+LABEL="probe_parttable_end"
+
# pass all events to the DeviceKit disks daemon
SUBSYSTEM=="block", RUN+="socket:/org/freedesktop/devicekit/disks/udev_event"
libexec_PROGRAMS = devkit-disks-daemon
+# TODO: move to udev
+udevhelper_PROGRAMS = part_id
+udevhelperdir = /lib/udev
+
+part_id_SOURCES = part-id.c partutil.c partutil.h
+part_id_CPPFLAGS = $(AM_CPPFLAGS)
+part_id_LDADD = $(GLIB_LIBS)
+# end move to udev
+
devkit_disks_daemon_SOURCES = \
devkit-disks-daemon.h devkit-disks-daemon.c \
devkit-disks-device.h devkit-disks-device.c \
GPtrArray *device_holders;
GPtrArray *device_slaves;
+ gboolean device_is_partition;
+ gboolean device_is_partition_table;
+
char *id_usage;
char *id_type;
char *id_version;
char *id_uuid;
char *id_label;
+
+ char *partition_slave;
+ char *partition_scheme;
+ char *partition_type;
+ char *partition_label;
+ char *partition_uuid;
+ GPtrArray *partition_flags;
+ int partition_number;
+ guint64 partition_offset;
+ guint64 partition_size;
+
+ char *partition_table_scheme;
+ int partition_table_count;
+ GPtrArray *partition_table_holders;
};
static void devkit_disks_device_class_init (DevkitDisksDeviceClass *klass);
static void devkit_disks_device_init (DevkitDisksDevice *seat);
static void devkit_disks_device_finalize (GObject *object);
+static void set_info_clear (DevkitDisksDevice *device);
+
enum
{
PROP_0,
PROP_DEVICE_HOLDERS,
PROP_DEVICE_SLAVES,
+ PROP_DEVICE_IS_PARTITION,
+ PROP_DEVICE_IS_PARTITION_TABLE,
+
PROP_ID_USAGE,
PROP_ID_TYPE,
PROP_ID_VERSION,
PROP_ID_UUID,
PROP_ID_LABEL,
+
+ PROP_PARTITION_SLAVE,
+ PROP_PARTITION_SCHEME,
+ PROP_PARTITION_TYPE,
+ PROP_PARTITION_LABEL,
+ PROP_PARTITION_UUID,
+ PROP_PARTITION_FLAGS,
+ PROP_PARTITION_NUMBER,
+ PROP_PARTITION_OFFSET,
+ PROP_PARTITION_SIZE,
+
+ PROP_PARTITION_TABLE_SCHEME,
+ PROP_PARTITION_TABLE_COUNT,
+ PROP_PARTITION_TABLE_HOLDERS,
};
G_DEFINE_TYPE (DevkitDisksDevice, devkit_disks_device, G_TYPE_OBJECT)
g_value_set_boxed (value, device->priv->device_slaves);
break;
+ case PROP_DEVICE_IS_PARTITION:
+ g_value_set_boolean (value, device->priv->device_is_partition);
+ break;
+ case PROP_DEVICE_IS_PARTITION_TABLE:
+ g_value_set_boolean (value, device->priv->device_is_partition_table);
+ break;
+
case PROP_ID_USAGE:
g_value_set_string (value, device->priv->id_usage);
break;
g_value_set_string (value, device->priv->id_label);
break;
+ case PROP_PARTITION_SLAVE:
+ g_value_set_string (value, device->priv->partition_slave);
+ break;
+ case PROP_PARTITION_SCHEME:
+ g_value_set_string (value, device->priv->partition_scheme);
+ break;
+ case PROP_PARTITION_TYPE:
+ g_value_set_string (value, device->priv->partition_type);
+ break;
+ case PROP_PARTITION_LABEL:
+ g_value_set_string (value, device->priv->partition_label);
+ break;
+ case PROP_PARTITION_UUID:
+ g_value_set_string (value, device->priv->partition_uuid);
+ break;
+ case PROP_PARTITION_FLAGS:
+ g_value_set_boxed (value, device->priv->partition_flags);
+ break;
+ case PROP_PARTITION_NUMBER:
+ g_value_set_int (value, device->priv->partition_number);
+ break;
+ case PROP_PARTITION_OFFSET:
+ g_value_set_uint64 (value, device->priv->partition_offset);
+ break;
+ case PROP_PARTITION_SIZE:
+ g_value_set_uint64 (value, device->priv->partition_size);
+ break;
+
+ case PROP_PARTITION_TABLE_SCHEME:
+ g_value_set_string (value, device->priv->partition_table_scheme);
+ break;
+ case PROP_PARTITION_TABLE_COUNT:
+ g_value_set_int (value, device->priv->partition_table_count);
+ break;
+ case PROP_PARTITION_TABLE_HOLDERS:
+ g_value_set_boxed (value, device->priv->partition_table_holders);
+ break;
+
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
g_object_class_install_property (
object_class,
+ PROP_DEVICE_IS_PARTITION,
+ g_param_spec_boolean ("device-is-partition", NULL, NULL, FALSE, G_PARAM_READABLE));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_DEVICE_IS_PARTITION_TABLE,
+ g_param_spec_boolean ("device-is-partition-table", NULL, NULL, FALSE, 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));
PROP_ID_LABEL,
g_param_spec_string ("id-label", NULL, NULL, NULL, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_SLAVE,
+ g_param_spec_string ("partition-slave", NULL, NULL, NULL, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_SCHEME,
+ g_param_spec_string ("partition-scheme", NULL, NULL, NULL, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_TYPE,
+ g_param_spec_string ("partition-type", NULL, NULL, NULL, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_LABEL,
+ g_param_spec_string ("partition-label", NULL, NULL, NULL, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_UUID,
+ g_param_spec_string ("partition-uuid", NULL, NULL, NULL, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_FLAGS,
+ g_param_spec_boxed ("partition-flags", NULL, NULL,
+ dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
+ G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_NUMBER,
+ g_param_spec_int ("partition-number", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_OFFSET,
+ g_param_spec_uint64 ("partition-offset", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_SIZE,
+ g_param_spec_uint64 ("partition-size", NULL, NULL, 0, G_MAXUINT64, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_TABLE_SCHEME,
+ g_param_spec_string ("partition-table-scheme", NULL, NULL, NULL, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_TABLE_COUNT,
+ g_param_spec_int ("partition-table-count", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READABLE));
+ g_object_class_install_property (
+ object_class,
+ PROP_PARTITION_TABLE_HOLDERS,
+ g_param_spec_boxed ("partition-table-holders", NULL, NULL,
+ dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING),
+ G_PARAM_READABLE));
}
static void
device->priv->device_file_by_path = g_ptr_array_new ();
device->priv->device_holders = g_ptr_array_new ();
device->priv->device_slaves = g_ptr_array_new ();
+ device->priv->partition_flags = g_ptr_array_new ();
+ device->priv->partition_table_holders = g_ptr_array_new ();
}
static void
g_free (device->priv->native_path);
- g_free (device->priv->device_file);
-
- g_ptr_array_foreach (device->priv->device_file_by_id, (GFunc) g_free, NULL);
- g_ptr_array_foreach (device->priv->device_file_by_path, (GFunc) g_free, NULL);
- g_ptr_array_foreach (device->priv->device_holders, (GFunc) g_free, NULL);
- g_ptr_array_foreach (device->priv->device_slaves, (GFunc) g_free, NULL);
- g_ptr_array_free (device->priv->device_file_by_id, TRUE);
- g_ptr_array_free (device->priv->device_file_by_path, TRUE);
- g_ptr_array_free (device->priv->device_holders, TRUE);
- g_ptr_array_free (device->priv->device_slaves, TRUE);
-
- g_free (device->priv->id_usage);
- g_free (device->priv->id_type);
- g_free (device->priv->id_version);
- g_free (device->priv->id_uuid);
- g_free (device->priv->id_label);
-
+ set_info_clear (device);
G_OBJECT_CLASS (devkit_disks_device_parent_class)->finalize (object);
}
return FALSE;
}
+static int
+sysfs_get_int (const char *dir, const char *attribute)
+{
+ int result;
+ char *contents;
+ char *filename;
+
+ result = 0;
+ filename = g_build_filename (dir, attribute, NULL);
+ if (g_file_get_contents (filename, &contents, NULL, NULL)) {
+ result = atoi (contents);
+ g_free (contents);
+ }
+ g_free (filename);
+
+
+ return result;
+}
+
+static void
+set_info_clear (DevkitDisksDevice *device)
+{
+ g_free (device->priv->device_file);
+
+ g_ptr_array_foreach (device->priv->device_file_by_id, (GFunc) g_free, NULL);
+ g_ptr_array_foreach (device->priv->device_file_by_path, (GFunc) g_free, NULL);
+ g_ptr_array_foreach (device->priv->device_holders, (GFunc) g_free, NULL);
+ g_ptr_array_foreach (device->priv->device_slaves, (GFunc) g_free, NULL);
+ g_ptr_array_free (device->priv->device_file_by_id, TRUE);
+ g_ptr_array_free (device->priv->device_file_by_path, TRUE);
+ g_ptr_array_free (device->priv->device_holders, TRUE);
+ g_ptr_array_free (device->priv->device_slaves, TRUE);
+
+ g_free (device->priv->id_usage);
+ g_free (device->priv->id_type);
+ g_free (device->priv->id_version);
+ g_free (device->priv->id_uuid);
+ g_free (device->priv->id_label);
+
+ g_free (device->priv->partition_slave);
+ g_free (device->priv->partition_scheme);
+ g_free (device->priv->partition_type);
+ g_free (device->priv->partition_label);
+ g_free (device->priv->partition_uuid);
+ g_ptr_array_foreach (device->priv->partition_flags, (GFunc) g_free, NULL);
+ g_ptr_array_free (device->priv->partition_flags, TRUE);
+
+ g_free (device->priv->partition_table_scheme);
+ g_ptr_array_foreach (device->priv->partition_table_holders, (GFunc) g_free, NULL);
+ g_ptr_array_free (device->priv->partition_table_holders, TRUE);
+}
+
static gboolean
set_info (DevkitDisksDevice *device)
{
char *standard_output;
char **lines;
unsigned int n;
+ unsigned int m;
GDir *dir;
char *path;
- gboolean is_partition;
char *s;
+ int range;
const char *name;
+ gboolean is_partitioned_by_kernel;
+ gboolean is_partitioned_by_kernel_and_is_partition;
ret = FALSE;
goto out;
}
- g_ptr_array_foreach (device->priv->device_file_by_id, (GFunc) g_free, NULL);
- g_ptr_array_foreach (device->priv->device_file_by_path, (GFunc) g_free, NULL);
- g_ptr_array_foreach (device->priv->device_holders, (GFunc) g_free, NULL);
- g_ptr_array_foreach (device->priv->device_slaves, (GFunc) g_free, NULL);
+ /* free all info and prepare arrays for new info */
+ set_info_clear (device);
device->priv->device_file_by_id = g_ptr_array_new ();
device->priv->device_file_by_path = g_ptr_array_new ();
device->priv->device_holders = g_ptr_array_new ();
device->priv->device_slaves = g_ptr_array_new ();
+ device->priv->partition_flags = g_ptr_array_new ();
+ device->priv->partition_table_holders = g_ptr_array_new ();
- lines = g_strsplit (standard_output, "\n", 0);
- for (n = 0; lines[n] != NULL; n++) {
- char *line = lines[n];
+ is_partitioned_by_kernel = FALSE;
+ is_partitioned_by_kernel_and_is_partition = FALSE;
- if (g_str_has_prefix (line, "N: ")) {
- g_free (device->priv->device_file);
- device->priv->device_file = g_build_filename ("/dev", line + 3, NULL);
- } else if (g_str_has_prefix (line, "S: ")) {
- if (g_str_has_prefix (line + 3, "disk/by-id/") ||
- g_str_has_prefix (line + 3, "disk/by-uuid/")) {
- g_ptr_array_add (device->priv->device_file_by_id,
- g_build_filename ("/dev", line + 3, NULL));
- } else if (g_str_has_prefix (line + 3, "disk/by-path/")) {
- g_ptr_array_add (device->priv->device_file_by_path,
- g_build_filename ("/dev", line + 3, NULL));
- }
-
- } else if (g_str_has_prefix (line, "E: ")) {
- if (g_str_has_prefix (line + 3, "ID_FS_USAGE=")) {
- g_free (device->priv->id_usage);
- device->priv->id_usage = g_strdup (line + 3 + sizeof ("ID_FS_USAGE=") - 1);
- } else if (g_str_has_prefix (line + 3, "ID_FS_TYPE=")) {
- g_free (device->priv->id_type);
- device->priv->id_type = g_strdup (line + 3 + sizeof ("ID_FS_TYPE=") - 1);
- } else if (g_str_has_prefix (line + 3, "ID_FS_VERSION=")) {
- g_free (device->priv->id_version);
- device->priv->id_version = g_strdup (line + 3 + sizeof ("ID_FS_VERSION=") - 1);
- } else if (g_str_has_prefix (line + 3, "ID_FS_UUID=")) {
- g_free (device->priv->id_uuid);
- device->priv->id_uuid = g_strdup (line + 3 + sizeof ("ID_FS_UUID=") - 1);
- } else if (g_str_has_prefix (line + 3, "ID_FS_LABEL=")) {
- g_free (device->priv->id_label);
- device->priv->id_label = g_strdup (line + 3 + sizeof ("ID_FS_LABEL=") - 1);
- }
- }
- }
- g_strfreev (lines);
+ /* devices partitioned by in-kernel partioning have range
+ * set to > 1 - that's how we identify them
+ */
+ range = sysfs_get_int (device->priv->native_path, "range");
+ if (range > 1)
+ is_partitioned_by_kernel = TRUE;
path = g_build_filename (device->priv->native_path, "holders", NULL);
dir = g_dir_open (path, 0, NULL);
}
g_free (path);
+ path = g_build_filename (device->priv->native_path, "slaves", NULL);
/* block devices created by in-kernel partioning don't have
- * the slaves/ directory; that's one way to identify them
+ * the slaves/ directory; that's how we identify them
*/
- path = g_build_filename (device->priv->native_path, "slaves", NULL);
dir = g_dir_open (path, 0, NULL);
- is_partition = (dir == NULL);
+ is_partitioned_by_kernel_and_is_partition = (dir == NULL);
while (dir != NULL && (name = g_dir_read_name (dir)) != NULL) {
g_ptr_array_add (device->priv->device_slaves, compute_object_path_from_basename (name));
}
* you do userspace partitioning, via kpartx(8), then you get
* these. So manually add this ourselves to be consistent.
*/
- if (is_partition) {
+ if (is_partitioned_by_kernel_and_is_partition) {
/* cut the number off */
s = g_path_get_basename (device->priv->native_path);
for (n = strlen (s) - 1; g_ascii_isdigit (s[n]) && n >= 0; n--)
s[n] = '\0';
- g_ptr_array_add (device->priv->device_slaves,
- compute_object_path_from_basename (s));
+ g_ptr_array_add (device->priv->device_slaves, compute_object_path_from_basename (s));
+ device->priv->partition_slave = compute_object_path_from_basename (s);
g_free (s);
- } else {
- char *s;
+
+ n = strlen (device->priv->native_path) - 1;
+ while (g_ascii_isdigit (device->priv->native_path[n]))
+ n--;
+ device->priv->partition_number = atoi (device->priv->native_path + n + 1);
+ device->priv->device_is_partition = TRUE;
+
+ } else if (is_partitioned_by_kernel) {
s = g_path_get_basename (device->priv->native_path);
dir = g_dir_open (device->priv->native_path, 0, NULL);
- is_partition = (dir != NULL);
while (dir != NULL && (name = g_dir_read_name (dir)) != NULL) {
if (g_str_has_prefix (name, s) && g_ascii_isdigit (name[strlen (s)])) {
g_ptr_array_add (device->priv->device_holders,
compute_object_path_from_basename (name));
+
+ g_ptr_array_add (device->priv->partition_table_holders,
+ compute_object_path_from_basename (name));
}
}
g_free (s);
+ device->priv->device_is_partition_table = TRUE;
+ }
+
+ /* TODO: right now we only support partitions and partition tables
+ * created by the kernel; it's a bit hard to determine in the
+ * general (kpartx) case
+ */
+ if (is_partitioned_by_kernel) {
+
+ } else if (is_partitioned_by_kernel_and_is_partition) {
+ }
+
+ /* set other properties from the udev database */
+ lines = g_strsplit (standard_output, "\n", 0);
+ for (n = 0; lines[n] != NULL; n++) {
+ char *line = lines[n];
+
+ if (g_str_has_prefix (line, "N: ")) {
+ g_free (device->priv->device_file);
+ device->priv->device_file = g_build_filename ("/dev", line + 3, NULL);
+ } else if (g_str_has_prefix (line, "S: ")) {
+ if (g_str_has_prefix (line + 3, "disk/by-id/") ||
+ g_str_has_prefix (line + 3, "disk/by-uuid/")) {
+ g_ptr_array_add (device->priv->device_file_by_id,
+ g_build_filename ("/dev", line + 3, NULL));
+ } else if (g_str_has_prefix (line + 3, "disk/by-path/")) {
+ g_ptr_array_add (device->priv->device_file_by_path,
+ g_build_filename ("/dev", line + 3, NULL));
+ }
+
+ } else if (g_str_has_prefix (line, "E: ")) {
+ if (g_str_has_prefix (line + 3, "ID_FS_USAGE=")) {
+ g_free (device->priv->id_usage);
+ device->priv->id_usage = g_strdup (line + 3 + sizeof ("ID_FS_USAGE=") - 1);
+ } else if (g_str_has_prefix (line + 3, "ID_FS_TYPE=")) {
+ g_free (device->priv->id_type);
+ device->priv->id_type = g_strdup (line + 3 + sizeof ("ID_FS_TYPE=") - 1);
+ } else if (g_str_has_prefix (line + 3, "ID_FS_VERSION=")) {
+ g_free (device->priv->id_version);
+ device->priv->id_version = g_strdup (line + 3 + sizeof ("ID_FS_VERSION=") - 1);
+ } else if (g_str_has_prefix (line + 3, "ID_FS_UUID=")) {
+ g_free (device->priv->id_uuid);
+ device->priv->id_uuid = g_strdup (line + 3 + sizeof ("ID_FS_UUID=") - 1);
+ } else if (g_str_has_prefix (line + 3, "ID_FS_LABEL=")) {
+ g_free (device->priv->id_label);
+ device->priv->id_label = g_strdup (line + 3 + sizeof ("ID_FS_LABEL=") - 1);
+ } else if (g_str_has_prefix (line + 3, "ID_PART_SCHEME")) {
+ if (device->priv->device_is_partition_table) {
+ device->priv->partition_table_scheme =
+ g_strdup (line + 3 + sizeof ("ID_PART_SCHEME=") - 1);
+ } else if (device->priv->device_is_partition) {
+ device->priv->partition_scheme =
+ g_strdup (line + 3 + sizeof ("ID_PART_SCHEME=") - 1);
+ }
+ } else if (g_str_has_prefix (line + 3, "ID_PART_COUNT")) {
+ if (device->priv->device_is_partition_table) {
+ device->priv->partition_table_count =
+ atoi (line + 3 + sizeof ("ID_PART_COUNT=") - 1);
+ }
+ } else if (device->priv->device_is_partition &&
+ g_str_has_prefix (line + 3, "ID_PART_P")) {
+ char *endp;
+ int given_part = strtol (line + 3 + sizeof ("ID_PART_P") - 1, &endp, 10);
+ if (given_part == device->priv->partition_number && *endp == '_') {
+ if (g_str_has_prefix (endp, "_TYPE="))
+ device->priv->partition_type =
+ g_strdup (endp + sizeof ("_TYPE=") - 1);
+ else if (g_str_has_prefix (endp, "_LABEL="))
+ device->priv->partition_label =
+ g_strdup (endp + sizeof ("_LABEL=") - 1);
+ else if (g_str_has_prefix (endp, "_UUID="))
+ device->priv->partition_uuid =
+ g_strdup (endp + sizeof ("_UUID=") - 1);
+ else if (g_str_has_prefix (endp, "_FLAGS=")) {
+ char **tokens;
+ tokens = g_strsplit (endp + sizeof ("_FLAGS=") - 1, " ", 0);
+ for (m = 0; tokens[m] != NULL; m++)
+ g_ptr_array_add (device->priv->partition_flags, tokens[m]);
+ g_free (tokens); /* ptrarray takes ownership of strings */
+ }
+ else if (g_str_has_prefix (endp, "_OFFSET="))
+ device->priv->partition_offset =
+ atoll (endp + sizeof ("_OFFSET=") - 1);
+ else if (g_str_has_prefix (endp, "_SIZE="))
+ device->priv->partition_size =
+ atoll (endp + sizeof ("_SIZE=") - 1);
+ /* TODO: slave */
+ }
+ }
+ }
}
+ g_strfreev (lines);
/* check for required keys */
<!-- holders -->
<property name="device-holders" type="as" access="read"/>
+ <!-- true if the device is a partition -->
+ <property name="device-is-partition" type="b" access="read"/>
+
+ <!-- true if the device contains a partition table -->
+ <property name="device-is-partition-table" type="b" access="read"/>
+
<!-- the usage is a result of probing for signatures on the block
device; known values are
other - other signature found on the device -->
<property name="id-usage" type="s" access="read"/>
- <!-- More detailed result of signature probing. The value depends
+ <!-- more detailed result of signature probing. The value depends
on the value of 'id-usage'
filesystem - the filesystem type e.g. vfat, ext3 and so forth
other - known types are: swap -->
<property name="id-type" type="s" access="read"/>
- <!-- If set, the version of the format specified by 'id-type' -->
+ <!-- the version of the format specified by 'id-type' -->
<property name="id-version" type="s" access="read"/>
- <!-- If set, an UUID for the format specified by 'id-type' -->
+ <!-- an UUID for the format specified by 'id-type' -->
<property name="id-uuid" type="s" access="read"/>
- <!-- If set, a label for the format specified by 'id-type' -->
+ <!-- a label for the format specified by 'id-type' -->
<property name="id-label" type="s" access="read"/>
+ <!-- the following properties are only set if the device is
+ a partition (see 'device-is-partition'). Known values
+ for the partitioning scheme are
+
+ mbr - Master Boot Record
+ embr - Extended Master Boot Record
+ apm - Apple Partitoning Map
+ gpt - GUID Partition Table
+
+ The 'partition-slave' property specifies what device
+ the device in question is a partition of. The property
+ 'partition-number' is the number of the partition starting
+ from 1 -->
+ <property name="partition-slave" type="s" access="read"/>
+ <property name="partition-scheme" type="s" access="read"/>
+ <property name="partition-type" type="s" access="read"/>
+ <property name="partition-label" type="s" access="read"/>
+ <property name="partition-uuid" type="s" access="read"/>
+ <property name="partition-flags" type="as" access="read"/>
+ <property name="partition-number" type="i" access="read"/>
+ <property name="partition-offset" type="t" access="read"/>
+ <property name="partition-size" type="t" access="read"/>
+
+ <!-- the type of partition table the deice contains; only set if
+ 'device-is-partition-table' is true. Known values are
+
+ mbr - Master Boot Record
+ embr - Extended Master Boot Record
+ apm - Apple Partitoning Map
+ gpt - GUID Partition Table
+
+ The 'partition-table-count' property specifies the number
+ of partitions in the partition table. The property
+ 'partition-table-holders' specifies what devices is
+ part of the device in question.
+ -->
+ <property name="partition-table-scheme" type="s" access="read"/>
+ <property name="partition-table-count" type="i" access="read"/>
+ <property name="partition-table-holders" type="as" access="read"/>
+
</interface>
</node>
--- /dev/null
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "partutil.h"
+
+static void
+usage (int argc, char *argv[])
+{
+ execlp ("man", "man", "part_id", NULL);
+ fprintf (stderr, "Cannot show man page: %m\n");
+ exit (1);
+}
+
+static void
+print_entry (PartitionTable *p, int entry, int print_number)
+{
+ char *type;
+ char *label;
+ char *uuid;
+ char **flags;
+ char *flags_combined;
+ guint64 offset;
+ guint64 size;
+
+ type = part_table_entry_get_type (p, entry);
+ label = part_table_entry_get_label (p, entry);
+ uuid = part_table_entry_get_uuid (p, entry);
+ flags = part_table_entry_get_flags (p, entry);
+ offset = part_table_entry_get_offset (p, entry);
+ size = part_table_entry_get_size (p, entry);
+
+ flags_combined = g_strjoinv (" ", flags);
+
+ printf ("ID_PART_P%d_TYPE=%s\n", print_number, type != NULL ? type : "");
+ printf ("ID_PART_P%d_OFFSET=%lld\n", print_number, offset);
+ printf ("ID_PART_P%d_SIZE=%lld\n", print_number, size);
+ printf ("ID_PART_P%d_LABEL=%s\n", print_number, label != NULL ? label : "");
+ printf ("ID_PART_P%d_UUID=%s\n", print_number, uuid != NULL ? uuid : "");
+ printf ("ID_PART_P%d_FLAGS=%s\n", print_number, flags_combined);
+
+ g_free (type);
+ g_free (label);
+ g_free (uuid);
+ g_strfreev (flags);
+ g_free (flags_combined);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int n;
+ int ret;
+ char *device_file;
+ PartitionTable *table;
+ PartitionTable *nested_table;
+ int num_entries;
+ int num_nested_entries;
+
+ ret = 1;
+
+ device_file = NULL;
+ for (n = 1; n < argc; n++) {
+ if (strcmp (argv[n], "--help") == 0) {
+ usage (argc, argv);
+ return 0;
+ } else {
+ if (device_file != NULL)
+ usage (argc, argv);
+ device_file = argv[n];
+ }
+ }
+
+ if (device_file == NULL) {
+ fprintf (stderr, "no device\n");
+ goto out;
+ }
+
+ table = part_table_load_from_disk (device_file);
+ if (table == NULL) {
+ fprintf (stderr, "%s: unknown partition table type\n", device_file);
+ goto out;
+ }
+
+ num_entries = part_table_get_num_entries (table);
+
+ /* we only support a single nested partition table */
+ num_nested_entries = 0;
+ for (n = 0; n < num_entries; n++) {
+ nested_table = part_table_entry_get_nested (table, n);
+ if (nested_table != NULL) {
+ num_nested_entries = part_table_get_num_entries (nested_table);
+ break;
+ }
+ }
+
+
+ printf ("ID_PART_SCHEME=%s\n", part_get_scheme_name (part_table_get_scheme (table)));
+ printf ("ID_PART_COUNT=%d\n", num_entries + num_nested_entries);
+
+ for (n = 0; n < num_entries; n++) {
+ print_entry (table, n, n + 1);
+ }
+
+ for (n = 0; n < num_nested_entries; n++) {
+ print_entry (nested_table, n, n + 5);
+ }
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
--- /dev/null
+/***************************************************************************
+ *
+ * part.c : library for reading and writing partition tables - uses
+ * libparted for the heavy lifting
+ *
+ * Copyright (C) 2006 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 <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <errno.h>
+#include <sys/ioctl.h>
+#include <ctype.h>
+
+#include <linux/hdreg.h>
+
+#define BLKGETSIZE64 _IOR(0x12,114,size_t)
+
+#include "partutil.h"
+
+static void
+DEBUG (const gchar *essage, ...)
+{
+#if 0
+ va_list args;
+ va_start (args, message);
+ g_vfprintf (stderr, message, args);
+ va_end (args);
+ g_fprintf (stderr, "\n");
+ fflush (stderr);
+#endif
+}
+
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#ifdef USE_PARTED
+#include <parted/parted.h>
+#endif
+
+const char *
+part_get_scheme_name (PartitionScheme scheme)
+{
+ const char *s;
+
+ switch (scheme) {
+ case PART_TYPE_GPT:
+ s = "gpt";
+ break;
+ case PART_TYPE_MSDOS:
+ s = "mbr";
+ break;
+ case PART_TYPE_MSDOS_EXTENDED:
+ s = "embr";
+ break;
+ case PART_TYPE_APPLE:
+ s = "apm";
+ break;
+ default:
+ s = NULL;
+ break;
+ }
+
+ return s;
+}
+
+struct PartitionEntry_s;
+typedef struct PartitionEntry_s PartitionEntry;
+
+struct PartitionEntry_s
+{
+ gboolean is_part_table;
+
+ /* NULL iff is_part_table==FALSE */
+ PartitionTable *part_table;
+
+ /* these are always set */
+ guint8 *data;
+ int length;
+
+ /* offset _on disk_ where the entry starts */
+ guint64 offset;
+};
+
+struct PartitionTable_s
+{
+ /* partitioning scheme used */
+ PartitionScheme scheme;
+
+ /* offset of table on disk */
+ guint64 offset;
+ guint64 size;
+
+ /* entries in partition table */
+ GSList *entries;
+};
+
+void
+part_table_find (PartitionTable *p, guint64 offset,
+ PartitionTable **out_part_table, int *out_entry)
+{
+ int n;
+ int num_entries;
+
+ *out_part_table = p;
+ *out_entry = -1;
+
+ num_entries = part_table_get_num_entries (p);
+ for (n = 0; n < num_entries; n++) {
+ guint64 pe_offset;
+ guint64 pe_size;
+
+ pe_offset = part_table_entry_get_offset (p, n);
+ pe_size = part_table_entry_get_size (p, n);
+
+ if ((offset >= pe_offset) && (offset < pe_offset + pe_size)) {
+ PartitionTable *part_table_nested;
+
+ part_table_nested = part_table_entry_get_nested (p, n);
+ /* return the extended partition only if the offset points to it - otherwise
+ * look for a logical partition
+ */
+ if (part_table_nested != NULL && offset > pe_offset) {
+ part_table_find (part_table_nested, offset, out_part_table, out_entry);
+ } else {
+ *out_entry = n;
+ }
+
+ /* and we're done... */
+ break;
+ }
+ }
+}
+
+
+static guint16
+get_le16 (const void *buf)
+{
+ return GUINT16_FROM_LE ( * ((guint16 *) buf) );
+}
+
+
+static guint32
+get_le32 (const void *buf)
+{
+ return GUINT32_FROM_LE ( * ((guint32 *) buf) );
+}
+
+static guint64
+get_le64 (const void *buf)
+{
+ return GUINT64_FROM_LE ( * ((guint64 *) buf) );
+}
+
+
+static guint32
+get_be32 (const void *buf)
+{
+ return GUINT32_FROM_BE ( * ((guint32 *) buf) );
+}
+
+/* see http://en.wikipedia.org/wiki/Globally_Unique_Identifier - excerpt
+ *
+ * Guids are most commonly written in text as a sequence of hexadecimal digits as such:
+ *
+ * 3F2504E0-4F89-11D3-9A0C-0305E82C3301
+ *
+ * This text notation follows from the data structure defined above. The sequence is
+ *
+ * 1. Data1 (8 characters)
+ * 2. Hyphen
+ * 3. Data2 (4 characters)
+ * 4. Hyphen
+ * 5. Data3 (4 characters)
+ * 6. Hyphen
+ * 7. Initial two items from Data4 (4 characters)
+ * 8. Hyphen
+ * 9. Remaining six items from Data4 (12 characters)
+ *
+ * Often braces are added to enclose the above format, as such:
+ *
+ * {3F2504E0-4F89-11D3-9A0C-0305E82C3301}
+ *
+ * When printing fewer characters is desired guids are sometimes encoded
+ * into a base64 string of 22 to 24 characters (depending on
+ * padding). For instance:
+ *
+ * 7QDBkvCA1+B9K/U0vrQx1A
+ * 7QDBkvCA1+B9K/U0vrQx1A==
+ */
+
+typedef struct efi_guid_s {
+ guint32 data1;
+ guint16 data2;
+ guint16 data3;
+ guint8 data4[8];
+} __attribute__ ((packed)) efi_guid;
+
+static char *
+get_le_guid (const guint8 *buf)
+{
+ efi_guid *guid = (efi_guid *) buf;
+
+ return g_strdup_printf("%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
+ get_le32 (&(guid->data1)),
+ get_le16 (&(guid->data2)),
+ get_le16 (&(guid->data3)),
+ guid->data4[0],
+ guid->data4[1],
+ guid->data4[2],
+ guid->data4[3],
+ guid->data4[4],
+ guid->data4[5],
+ guid->data4[6],
+ guid->data4[7]);
+}
+
+#ifdef USE_PARTED
+static gboolean
+set_le_guid (guint8 *buf, const char *source)
+{
+ efi_guid *guid = (efi_guid *) buf;
+ guint32 __attribute__((__unused__)) data1;
+ guint16 __attribute__((__unused__)) data2;
+ guint16 __attribute__((__unused__)) data3;
+ guint8 __attribute__((__unused__)) data4[8];
+ gboolean ret;
+ int n;
+
+ n = sscanf (source, "%x-%hx-%hx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx",
+ &guid->data1,
+ &guid->data2,
+ &guid->data3,
+ &(guid->data4[0]),
+ &(guid->data4[1]),
+ &(guid->data4[2]),
+ &(guid->data4[3]),
+ &(guid->data4[4]),
+ &(guid->data4[5]),
+ &(guid->data4[6]),
+ &(guid->data4[7]));
+
+ if (n != 11) {
+ DEBUG ("guid '%s' is not valid", source);
+ goto out;
+ }
+
+#if 0
+ DEBUG ("source = %s", source));
+ DEBUG ("data1 = %08x", guid->data1));
+ DEBUG ("data2 = %04x", guid->data2));
+ DEBUG ("data3 = %04x", guid->data3));
+ DEBUG ("data4[0] = %02x", guid->data4[0]));
+ DEBUG ("data4[1] = %02x", guid->data4[1]));
+ DEBUG ("data4[2] = %02x", guid->data4[2]));
+ DEBUG ("data4[3] = %02x", guid->data4[3]));
+ DEBUG ("data4[4] = %02x", guid->data4[4]));
+ DEBUG ("data4[5] = %02x", guid->data4[5]));
+ DEBUG ("data4[6] = %02x", guid->data4[6]));
+ DEBUG ("data4[7] = %02x", guid->data4[7]));
+#endif
+
+ guid->data1 = GUINT32_TO_LE (guid->data1);
+ guid->data2 = GUINT16_TO_LE (guid->data2);
+ guid->data3 = GUINT16_TO_LE (guid->data3);
+
+ ret = TRUE;
+
+out:
+ return ret;
+}
+#endif
+
+static PartitionEntry *
+part_entry_new (PartitionTable *e_part_table, const guint8 *data, int length, guint64 offset)
+{
+ PartitionEntry *pe;
+
+ pe = g_new0 (PartitionEntry, 1);
+ pe->is_part_table = (e_part_table != NULL);
+ pe->part_table = e_part_table;
+ pe->offset = offset;
+ pe->length = length;
+ pe->data = g_new0 (guint8, length);
+ memcpy (pe->data, data, length);
+
+ return pe;
+}
+
+static void
+part_entry_free (PartitionEntry *pe)
+{
+ if (pe->part_table != NULL) {
+ part_table_free (pe->part_table);
+ }
+ g_free (pe->data);
+ g_free (pe);
+}
+
+static PartitionTable *
+part_table_new_empty (PartitionScheme scheme)
+{
+ PartitionTable *p;
+
+ p = g_new0 (PartitionTable, 1);
+ p->scheme = scheme;
+ p->offset = 0;
+ p->entries = NULL;
+
+ return p;
+}
+
+void
+part_table_free (PartitionTable *p)
+{
+ GSList *i;
+
+ if (p == NULL)
+ return;
+
+ for (i = p->entries; i != NULL; i = i->next) {
+ PartitionEntry *pe = i->data;
+ part_entry_free (pe);
+ }
+ g_slist_free (p->entries);
+ g_free (p);
+}
+
+#if 0
+static PartitionTable *
+part_table_parse_bsd (int fd, guint64 offset, guint64 size)
+{
+ PartitionTable *p;
+
+ p = NULL;
+
+ /* TODO */
+
+ return p;
+}
+#endif
+
+
+#define MSDOS_MAGIC "\x55\xaa"
+#define MSDOS_PARTTABLE_OFFSET 0x1be
+#define MSDOS_SIG_OFF 0x1fe
+
+#if 1
+static void
+hexdump (const guint8 *mem, int size)
+{
+ int i;
+ int j;
+ int n;
+ const guint8 *buf = (const guint8 *) mem;
+
+ n = 0;
+ printf ("Dumping %d=0x%x bytes\n", size, size);
+ while (n < size) {
+
+ printf ("0x%04x: ", n);
+
+ j = n;
+ for (i = 0; i < 16; i++) {
+ if (j >= size)
+ break;
+ printf ("%02x ", buf[j]);
+ j++;
+ }
+
+ for ( ; i < 16; i++) {
+ printf (" ");
+ }
+
+ printf (" ");
+
+ j = n;
+ for (i = 0; i < 16; i++) {
+ if (j >= size)
+ break;
+ printf ("%c", isprint(buf[j]) ? buf[j] : '.');
+ j++;
+ }
+
+ printf ("\n");
+
+ n += 16;
+ }
+}
+#endif
+
+static PartitionTable *
+part_table_parse_msdos_extended (int fd, guint64 offset, guint64 size)
+{
+ int n;
+ PartitionTable *p;
+ guint64 next;
+
+ DEBUG ("Entering MS-DOS extended parser (offset=%lld, size=%lld)", offset, size);
+
+ p = NULL;
+
+ next = offset;
+
+ while (next != 0) {
+ guint64 readfrom;
+ const guint8 embr[512];
+
+ readfrom = next;
+ next = 0;
+
+ DEBUG ("readfrom = %lld", readfrom);
+
+ if (lseek (fd, readfrom, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, &embr, sizeof (embr)) != sizeof (embr)) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+
+ //hexdump (embr, 512);
+
+ if (memcmp (&embr[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0) {
+ DEBUG ("No MSDOS_MAGIC found");
+ goto out;
+ }
+
+ DEBUG ("MSDOS_MAGIC found");
+
+ if (p == NULL) {
+ p = part_table_new_empty (PART_TYPE_MSDOS_EXTENDED);
+ p->offset = offset;
+ p->size = size;
+ }
+
+
+ for (n = 0; n < 2; n++) {
+ PartitionEntry *pe;
+ guint64 pstart;
+ guint64 psize;
+
+ pstart = 0x200 * ((guint64) get_le32 (&(embr[MSDOS_PARTTABLE_OFFSET + n * 16 + 8])));
+ psize = 0x200 * ((guint64) get_le32 (&(embr[MSDOS_PARTTABLE_OFFSET + n * 16 + 12])));
+
+ if (psize == 0)
+ continue;
+
+ pe = NULL;
+
+ if (n == 0) {
+ //DEBUG ("part %d (offset %lld, size %lld, type 0x%02x)",
+ // n, readfrom + pstart, psize, ptype));
+
+ //DEBUG ("pstart = %lld", pstart));
+
+ //hexdump (&(embr[MSDOS_PARTTABLE_OFFSET + n * 16]), 16);
+
+ pe = part_entry_new (NULL,
+ &(embr[MSDOS_PARTTABLE_OFFSET + n * 16]),
+ 16,
+ readfrom + MSDOS_PARTTABLE_OFFSET + n * 16);
+ } else {
+ if (pstart != 0) {
+ //DEBUG ("found chain at offset %lld", offset + pstart);
+ next = offset + pstart;
+ }
+ }
+
+ //DEBUG ("pe = %p", pe));
+
+ if (pe != NULL) {
+ p->entries = g_slist_append (p->entries, pe);
+ }
+ }
+
+ }
+
+out:
+ DEBUG ("Exiting MS-DOS extended parser");
+ return p;
+}
+
+static PartitionTable *
+part_table_parse_msdos (int fd, guint64 offset, guint64 size, gboolean *found_gpt)
+{
+ int n;
+ const guint8 mbr[512] __attribute__ ((aligned));
+ PartitionTable *p;
+
+ DEBUG ("Entering MS-DOS parser (offset=%lld, size=%lld)", offset, size);
+
+ *found_gpt = FALSE;
+
+ p = NULL;
+
+ if (lseek (fd, offset, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, &mbr, sizeof (mbr)) != sizeof (mbr)) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+
+ //hexdump (mbr, 512);
+
+ if (memcmp (&mbr[MSDOS_SIG_OFF], MSDOS_MAGIC, 2) != 0) {
+ DEBUG ("No MSDOS_MAGIC found");
+ goto out;
+ }
+
+ DEBUG ("MSDOS_MAGIC found");
+
+ /* sanity checks */
+ for (n = 0; n < 4; n++) {
+ if (mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 0] != 0 &&
+ mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 0] != 0x80) {
+ DEBUG ("partitioning flag for part %d is not 0x00 or 0x80", n);
+ goto out;
+ }
+ /* protective MBR for GPT => GPT, not MS-DOS */
+ if (mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 4] == 0xee) {
+ DEBUG ("found partition type 0xee => protective MBR for GPT");
+ *found_gpt = TRUE;
+ goto out;
+ }
+ }
+
+ p = part_table_new_empty (PART_TYPE_MSDOS);
+ p->offset = offset;
+ p->size = size;
+
+ /* we _always_ want to create four partitions */
+ for (n = 0; n < 4; n++) {
+ PartitionEntry *pe;
+ guint64 pstart;
+ guint64 psize;
+ guint8 ptype;
+ PartitionTable *e_part_table;
+
+ pstart = 0x200 * ((guint64) get_le32 (&(mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 8])));
+ psize = 0x200 * ((guint64) get_le32 (&(mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 12])));
+ ptype = mbr[MSDOS_PARTTABLE_OFFSET + n * 16 + 4];
+
+ DEBUG ("looking at part %d (offset %lld, size %lld, type 0x%02x)", n, pstart, psize, ptype);
+
+ pe = NULL;
+ e_part_table = NULL;
+
+ /* look for embedded partition tables */
+ switch (ptype) {
+
+ /* extended partitions */
+ case 0x05: /* MS-DOS */
+ case 0x0f: /* Win95 */
+ case 0x85: /* Linux */
+ e_part_table = part_table_parse_msdos_extended (fd, pstart, psize);
+ if (e_part_table != NULL) {
+ pe = part_entry_new (e_part_table,
+ &(mbr[MSDOS_PARTTABLE_OFFSET + n * 16]),
+ 16,
+ offset + MSDOS_PARTTABLE_OFFSET + n * 16);
+ }
+ break;
+
+ case 0xa5: /* FreeBSD */
+ case 0xa6: /* OpenBSD */
+ case 0xa9: /* NetBSD */
+ //e_part_table = part_table_parse_bsd (fd, pstart, psize);
+ //break;
+
+ default:
+ DEBUG ("new part entry");
+ pe = part_entry_new (NULL,
+ &(mbr[MSDOS_PARTTABLE_OFFSET + n * 16]),
+ 16,
+ offset + MSDOS_PARTTABLE_OFFSET + n * 16);
+ break;
+ }
+
+ //DEBUG ("pe = %p", pe));
+
+ if (pe != NULL) {
+ p->entries = g_slist_append (p->entries, pe);
+ }
+ }
+
+out:
+ DEBUG ("Exiting MS-DOS parser");
+ return p;
+}
+
+#define GPT_MAGIC "EFI PART"
+
+#define GPT_PART_TYPE_GUID_EMPTY "00000000-0000-0000-0000-000000000000"
+
+static PartitionTable *
+part_table_parse_gpt (int fd, guint64 offset, guint64 size)
+{
+ int n;
+ PartitionTable *p;
+ guint8 buf[16];
+ guint64 partition_entry_lba;
+ int num_entries;
+ int size_of_entry;
+
+ DEBUG ("Entering EFI GPT parser");
+
+ /* by way of getting here, we've already checked for a protective MBR */
+
+ p = NULL;
+
+ /* Check GPT signature */
+ if (lseek (fd, offset + 512 + 0, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, buf, 8) != 8) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (memcmp (buf, GPT_MAGIC, 8) != 0) {
+ DEBUG ("No GPT_MAGIC found");
+ goto out;
+ }
+
+ DEBUG ("GPT magic found");
+
+ /* Disk UUID */
+ if (lseek (fd, offset + 512 + 56, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, buf, 16) != 16) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+ //hexdump ((guint8*) buf, 16);
+
+ if (lseek (fd, offset + 512 + 72, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, buf, 8) != 8) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+ partition_entry_lba = get_le64 (buf);
+
+ if (lseek (fd, offset + 512 + 80, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, buf, 4) != 4) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+ num_entries = get_le32 (buf);
+
+ if (lseek (fd, offset + 512 + 84, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, buf, 4) != 4) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+ size_of_entry = get_le32(buf);
+
+
+ p = part_table_new_empty (PART_TYPE_GPT);
+ p->offset = offset;
+ p->size = size;
+
+ DEBUG ("partition_entry_lba=%lld", partition_entry_lba);
+ DEBUG ("num_entries=%d", num_entries);
+ DEBUG ("size_of_entry=%d", size_of_entry);
+
+ for (n = 0; n < num_entries; n++) {
+ PartitionEntry *pe;
+ struct {
+ guint8 partition_type_guid[16];
+ guint8 partition_guid[16];
+ guint8 starting_lba[8];
+ guint8 ending_lba[8];
+ guint8 attributes[8];
+ guint8 partition_name[72];
+ } gpt_part_entry;
+ char *partition_type_guid;
+
+ if (lseek (fd, offset + partition_entry_lba * 512 + n * size_of_entry, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, &gpt_part_entry, 128) != 128) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+
+ partition_type_guid = get_le_guid (gpt_part_entry.partition_type_guid);
+
+ if (strcmp (partition_type_guid, GPT_PART_TYPE_GUID_EMPTY) == 0)
+ continue;
+
+ pe = part_entry_new (NULL,
+ (guint8*) &gpt_part_entry,
+ 128,
+ offset + partition_entry_lba * 512 + n * size_of_entry);
+ p->entries = g_slist_append (p->entries, pe);
+
+ g_free (partition_type_guid);
+
+ //hexdump ((guint8 *) &gpt_part_entry, 128);
+
+ }
+
+
+out:
+ DEBUG ("Leaving EFI GPT parser");
+ return p;
+}
+
+#define MAC_MAGIC "ER"
+#define MAC_PART_MAGIC "PM"
+
+static PartitionTable *
+part_table_parse_apple (int fd, guint64 offset, guint64 size)
+{
+ int n;
+ PartitionTable *p;
+ struct {
+ guint16 signature;
+ guint16 block_size;
+ guint32 block_count;
+ /* more stuff */
+ } __attribute__ ((packed)) mac_header;
+ struct {
+ guint16 signature;
+ guint16 res1;
+ guint32 map_count;
+ guint32 start_block;
+ guint32 block_count;
+ char name[32];
+ char type[32];
+ guint32 data_start;
+ guint32 data_count;
+ guint32 status;
+ guint32 boot_start;
+ guint32 boot_size;
+ guint32 boot_load;
+ guint32 boot_load2;
+ guint32 boot_entry;
+ guint32 boot_entry2;
+ guint32 boot_cksum;
+ char processor[16]; /* identifies ISA of boot */
+ /* more stuff */
+ } __attribute__ ((packed)) mac_part;
+ int block_size;
+ int block_count;
+ int map_count;
+
+ DEBUG ("Entering Apple parser");
+
+ p = NULL;
+
+ /* Check Mac start of disk signature */
+ if (lseek (fd, offset + 0, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, &mac_header, sizeof (mac_header)) != sizeof (mac_header)) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (memcmp (&(mac_header.signature), MAC_MAGIC, 2) != 0) {
+ DEBUG ("No MAC_MAGIC found");
+ goto out;
+ }
+
+ block_size = GUINT16_FROM_BE (mac_header.block_size);
+ block_count = GUINT32_FROM_BE (mac_header.block_count); /* num blocks on whole disk */
+
+ DEBUG ("Mac MAGIC found, block_size=%d", block_size);
+
+ p = part_table_new_empty (PART_TYPE_APPLE);
+ p->offset = offset;
+ p->size = size;
+
+ /* get number of entries from first entry */
+ if (lseek (fd, offset + block_size, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, &mac_part, sizeof (mac_part)) != sizeof (mac_part)) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+ map_count = GUINT32_FROM_BE (mac_part.map_count); /* num blocks in part map */
+
+ DEBUG ("map_count = %d", map_count);
+
+ for (n = 0; n < map_count; n++) {
+ PartitionEntry *pe;
+
+ if (memcmp (&(mac_part.signature), MAC_PART_MAGIC, 2) != 0) {
+ DEBUG ("No MAC_PART_MAGIC found");
+ break;
+ }
+
+ if (lseek (fd, offset + (n + 1) * block_size, SEEK_SET) < 0) {
+ DEBUG ("lseek failed (%s)", strerror (errno));
+ goto out;
+ }
+ if (read (fd, &mac_part, sizeof (mac_part)) != sizeof (mac_part)) {
+ DEBUG ("read failed (%s)", strerror (errno));
+ goto out;
+ }
+
+ pe = part_entry_new (NULL,
+ (guint8*) &mac_part,
+ sizeof (mac_part),
+ offset + (n + 1) * block_size);
+ p->entries = g_slist_append (p->entries, pe);
+
+ }
+
+out:
+ DEBUG ("Leaving Apple parser");
+ return p;
+}
+
+PartitionTable *
+part_table_load_from_disk (char *device)
+{
+ int fd;
+ guint64 size;
+ PartitionTable *p;
+ gboolean found_gpt;
+
+ p = NULL;
+
+ fd = open (device, O_RDONLY);
+ if (fd < 0) {
+ DEBUG ("Cannot open device %s", device);
+ goto out;
+ }
+
+ if (ioctl (fd, BLKGETSIZE64, &size) != 0) {
+ DEBUG ("Cannot determine size of device");
+ goto out;
+ }
+
+ p = part_table_parse_msdos (fd, 0, size, &found_gpt);
+ if (p != NULL) {
+ DEBUG ("MSDOS partition table detected");
+ goto out;
+ }
+
+ if (found_gpt) {
+ p = part_table_parse_gpt (fd, 0, size);
+ if (p != NULL) {
+ DEBUG ("EFI GPT partition table detected");
+ goto out;
+ }
+ }
+
+ p = part_table_parse_apple (fd, 0, size);
+ if (p != NULL) {
+ DEBUG ("Apple partition table detected");
+ goto out;
+ }
+
+ DEBUG ("No known partition table found");
+
+
+out:
+ if (fd >= 0)
+ close (fd);
+
+ return p;
+}
+
+
+
+PartitionScheme
+part_table_get_scheme (PartitionTable *p)
+{
+ return p->scheme;
+}
+
+int
+part_table_get_num_entries (PartitionTable *p)
+{
+ return g_slist_length (p->entries);
+}
+
+guint64
+part_table_get_offset (PartitionTable *p)
+{
+ return p->offset;
+}
+
+guint64
+part_table_get_size (PartitionTable *p)
+{
+ return p->size;
+}
+
+PartitionTable *
+part_table_entry_get_nested (PartitionTable *p, int entry)
+{
+ PartitionEntry *pe;
+
+ if (p == NULL)
+ return NULL;
+
+ if ((pe = g_slist_nth_data (p->entries, entry)) == NULL)
+ return NULL;
+
+ if (pe->is_part_table)
+ return pe->part_table;
+ else
+ return NULL;
+}
+
+/**************************************************************************/
+
+char *
+part_table_entry_get_type (PartitionTable *p, int entry)
+{
+ char *s = NULL;
+ PartitionEntry *pe;
+
+ if (p == NULL)
+ goto out;
+
+ if ((pe = g_slist_nth_data (p->entries, entry)) == NULL)
+ goto out;
+
+ switch (p->scheme) {
+ case PART_TYPE_GPT:
+ s = get_le_guid (&(pe->data[0]));
+ break;
+ case PART_TYPE_MSDOS:
+ case PART_TYPE_MSDOS_EXTENDED:
+ s = g_strdup_printf ("0x%02x", pe->data[4]);
+ break;
+ case PART_TYPE_APPLE:
+ s = g_strdup ((char *) pe->data + 2*2 + 3*4 + 32);
+ g_strchomp (s);
+ break;
+ default:
+ break;
+ }
+out:
+ if (s != NULL) {
+ g_strchomp (s);
+ }
+ return s;
+}
+
+char *
+part_table_entry_get_uuid (PartitionTable *p, int entry)
+{
+ char *s = NULL;
+ PartitionEntry *pe;
+
+ if (p == NULL)
+ goto out;
+
+ if ((pe = g_slist_nth_data (p->entries, entry)) == NULL)
+ goto out;
+
+ switch (p->scheme) {
+ case PART_TYPE_GPT:
+ s = get_le_guid (&(pe->data[16]));
+ break;
+ default:
+ break;
+ }
+out:
+ if (s != NULL) {
+ g_strchomp (s);
+ }
+ return s;
+}
+
+char *
+part_table_entry_get_label (PartitionTable *p, int entry)
+{
+ char *s = NULL;
+ PartitionEntry *pe;
+
+ if (p == NULL)
+ goto out;
+
+ if ((pe = g_slist_nth_data (p->entries, entry)) == NULL)
+ goto out;
+
+ switch (p->scheme) {
+ case PART_TYPE_GPT:
+ s = g_utf16_to_utf8 ((const gunichar2 *) &(pe->data[56]), 36, NULL, NULL, NULL);
+ break;
+ case PART_TYPE_APPLE:
+ s = g_strdup ((char *) pe->data + 2*2 + 3*4);
+ g_strchomp (s);
+ break;
+ default:
+ break;
+ }
+out:
+ if (s != NULL) {
+ g_strchomp (s);
+ }
+ return s;
+}
+
+char **
+part_table_entry_get_flags (PartitionTable *p, int entry)
+{
+ int n;
+ char **ss = NULL;
+ guint32 apm_status;
+ guint64 gpt_attributes;
+ PartitionEntry *pe;
+
+ if (p == NULL)
+ goto out;
+
+ if ((pe = g_slist_nth_data (p->entries, entry)) == NULL)
+ goto out;
+
+ ss = g_new0 (char*, 6 + 1); /* hard coded to max items we'll return */
+ ss[0] = NULL;
+ n = 0;
+
+ switch (p->scheme) {
+ case PART_TYPE_GPT:
+ gpt_attributes = get_le64 (&(pe->data[48]));
+
+ /* From Table 16 of EFI 2.0 spec, bit zero means:
+ *
+ * "Required for the platform to function. The system
+ * cannot function normally if this partition is
+ * removed. This partition should be considered as
+ * part of the hardware of the system, and if it is
+ * removed the system may not boot. It may contain
+ * diagnostics, recovery tools, or other code or data
+ * that is critical to the functioning of a system
+ * independent of any OS."
+ *
+ */
+ if (gpt_attributes & (1<<0)) {
+ ss[n++] = g_strdup ("required");
+ }
+
+ /* TODO: handle partition type specific attributes
+ *
+ * Found on the Internet: "For basic data partitions, the following attribute is
+ * defined:0x8000000000000000 prevents the partition from having a drive letter automatically
+ * assigned. By default, each partition is assigned a new drive letter. Setting this
+ * attribute ensures that when a disk is moved to a new computer, a new drive letter
+ * will not be automatically generated. Instead, the user can manually assign drive
+ * letters. Note: Other attributes can be added at any time."
+ */
+ break;
+
+ case PART_TYPE_MSDOS:
+ case PART_TYPE_MSDOS_EXTENDED:
+ if (pe->data[0] == 0x80) {
+ ss[n++] = g_strdup ("boot");
+ }
+ break;
+
+ case PART_TYPE_APPLE:
+ apm_status = get_be32 (&(pe->data[2*2 + 3*4 + 2*32 + 2*4]));
+ if (apm_status&(1<<1))
+ ss[n++] = g_strdup ("allocated");
+ if (apm_status&(1<<2))
+ ss[n++] = g_strdup ("in_use");
+ if (apm_status&(1<<3))
+ ss[n++] = g_strdup ("boot");
+ if (apm_status&(1<<4))
+ ss[n++] = g_strdup ("allow_read");
+ if (apm_status&(1<<5))
+ ss[n++] = g_strdup ("allow_write");
+ if (apm_status&(1<<6))
+ ss[n++] = g_strdup ("boot_code_is_pic");
+ break;
+ default:
+ break;
+ }
+ ss[n] = NULL;
+
+out:
+ return ss;
+}
+
+guint64
+part_table_entry_get_offset (PartitionTable *p, int entry)
+{
+ guint64 val;
+ PartitionEntry *pe;
+
+ val = G_MAXUINT64;
+ if (p == NULL)
+ goto out;
+
+ if ((pe = g_slist_nth_data (p->entries, entry)) == NULL)
+ goto out;
+
+ switch (p->scheme) {
+ case PART_TYPE_GPT:
+ val = 0x200 * ((guint64) get_le64 (pe->data + 32));
+ break;
+
+ case PART_TYPE_MSDOS:
+ val = 0x200 * ((guint64) get_le32 (pe->data + 8));
+ break;
+ case PART_TYPE_MSDOS_EXTENDED:
+ /* tricky here.. the offset in the EMBR is from the start of the EMBR and they are
+ * scattered around the ext partition... Hence, just use the entry's offset and subtract
+ * it's offset from the EMBR..
+ */
+ val = 0x200 * ((guint64) get_le32 (pe->data + 8)) + pe->offset - MSDOS_PARTTABLE_OFFSET;
+ break;
+ case PART_TYPE_APPLE:
+ val = 0x200 * ((guint64) get_be32 (pe->data + 2*2 + 1*4));
+ break;
+ default:
+ break;
+ }
+out:
+ return val;
+}
+
+guint64
+part_table_entry_get_size (PartitionTable *p, int entry)
+{
+ guint64 val;
+ PartitionEntry *pe;
+
+ val = G_MAXUINT64;
+ if (p == NULL)
+ goto out;
+
+ if ((pe = g_slist_nth_data (p->entries, entry)) == NULL)
+ goto out;
+
+ switch (p->scheme) {
+ case PART_TYPE_GPT:
+ val = 0x200 * (((guint64) get_le64 (pe->data + 40)) - ((guint64) get_le64 (pe->data + 32)) + 1);
+ break;
+ case PART_TYPE_MSDOS:
+ case PART_TYPE_MSDOS_EXTENDED:
+ val = 0x200 * ((guint64) get_le32 (pe->data + 12));
+ break;
+ case PART_TYPE_APPLE:
+ val = 0x200 * ((guint64) get_be32 (pe->data + 2*2 + 2*4));
+ break;
+ default:
+ break;
+ }
+out:
+ return val;
+}
+
+/**************************************************************************/
+
+#ifdef USE_PARTED
+
+/* internal function to both add OR change a partition - if size==0,
+ * then we're changing, otherwise we're adding
+ */
+
+static gboolean
+part_add_change_partition (char *device_file,
+ guint64 start, guint64 size,
+ guint64 new_start, guint64 new_size,
+ guint64 *out_start, guint64 *out_size,
+ char *type, char *label, char **flags,
+ int geometry_hps, int geometry_spt)
+{
+ int n;
+ gboolean is_change;
+ gboolean res;
+ PedDevice *device;
+ PedDisk *disk;
+ PedPartition *part;
+ PedConstraint* constraint;
+ PedPartitionType ped_type;
+ guint64 start_sector;
+ guint64 end_sector;
+ guint64 new_start_sector;
+ guint64 new_end_sector;
+ PartitionTable *p;
+ PartitionTable *container_p;
+ int container_entry;
+ PartitionScheme scheme;
+ guint8 mbr_flags = 0;
+ guint8 mbr_part_type = 0;
+ char *endp;
+ guint64 gpt_attributes = 0;
+ guint32 apm_status = 0;
+
+ res = FALSE;
+
+ is_change = FALSE;
+ if (size == 0) {
+ is_change = TRUE;
+ }
+
+ if (is_change) {
+ DEBUG ("In part_change_partition: device_file=%s, start=%lld, new_start=%lld, new_size=%lld, type=%s", device_file, start, new_start, new_size, type);
+ } else {
+ DEBUG ("In part_add_partition: device_file=%s, start=%lld, size=%lld, type=%s", device_file, start, size, type);
+ }
+
+ /* first, find the kind of (embedded) partition table the new partition is going to be part of */
+ p = part_table_load_from_disk (device_file);
+ if (p == NULL) {
+ DEBUG ("Cannot load partition table from %s", device_file);
+ goto out;
+ }
+
+ part_table_find (p, start + 512, &container_p, &container_entry);
+ scheme = part_table_get_scheme (container_p);
+
+ if (is_change) {
+ /* if changing, make sure there is a partition to change */
+ if (container_entry < 0) {
+ DEBUG ("Couldn't find partition to change");
+ goto out;
+ }
+ } else {
+ /* if adding, make sure there is no partition in the way... */
+ if (container_entry >= 0) {
+ char *part_type;
+
+ /* this might be Apple_Free if we're on PART_TYPE_APPLE */
+ part_type = part_table_entry_get_type (p, container_entry);
+ if (! (p->scheme == PART_TYPE_APPLE && part_type != NULL && (strcmp (part_type, "Apple_Free") == 0))) {
+ part_table_free (p);
+ DEBUG ("There is a partition in the way on %s", device_file);
+ goto out;
+ }
+ }
+ }
+
+ DEBUG ("containing partition table scheme = %d", scheme);
+
+ part_table_free (p);
+ p = NULL;
+
+ if (!is_change) {
+ if (type == NULL) {
+ DEBUG ("No type specified");
+ goto out;
+ }
+ }
+
+ /* now that we know the partitoning scheme, sanity check type and flags */
+ switch (scheme) {
+ case PART_TYPE_MSDOS:
+ case PART_TYPE_MSDOS_EXTENDED:
+ mbr_flags = 0;
+ if (flags != NULL) {
+ for (n = 0; flags[n] != NULL; n++) {
+ if (strcmp (flags[n], "boot") == 0) {
+ mbr_flags |= 0x80;
+ } else {
+ DEBUG ("unknown flag '%s'", flags[n]);
+ goto out;
+ }
+ }
+ }
+
+ if (type != NULL) {
+ mbr_part_type = (guint8) (strtol (type, &endp, 0));
+ if (*endp != '\0') {
+ DEBUG ("invalid type '%s' given", type);
+ goto out;
+ }
+ }
+
+ if (label != NULL) {
+ DEBUG ("labeled partitions not supported on MSDOS or MSDOS_EXTENDED");
+ goto out;
+ }
+
+ break;
+
+ case PART_TYPE_GPT:
+ gpt_attributes = 0;
+ if (flags != NULL) {
+ for (n = 0; flags[n] != NULL; n++) {
+ if (strcmp (flags[n], "required") == 0) {
+ gpt_attributes |= 1;
+ } else {
+ DEBUG ("unknown flag '%s'", flags[n]);
+ goto out;
+ }
+ }
+ }
+ break;
+
+ case PART_TYPE_APPLE:
+ apm_status = 0;
+ if (flags != NULL) {
+ for (n = 0; flags[n] != NULL; n++) {
+ if (strcmp (flags[n], "allocated") == 0) {
+ apm_status |= (1<<1);
+ } else if (strcmp (flags[n], "in_use") == 0) {
+ apm_status |= (1<<2);
+ } else if (strcmp (flags[n], "boot") == 0) {
+ apm_status |= (1<<3);
+ } else if (strcmp (flags[n], "allow_read") == 0) {
+ apm_status |= (1<<4);
+ } else if (strcmp (flags[n], "allow_write") == 0) {
+ apm_status |= (1<<5);
+ } else if (strcmp (flags[n], "boot_code_is_pic") == 0) {
+ apm_status |= (1<<6);
+ } else {
+ DEBUG ("unknown flag '%s'", flags[n]);
+ goto out;
+ }
+ }
+ }
+ break;
+
+ default:
+ DEBUG ("partitioning scheme %d not supported", scheme);
+ goto out;
+ }
+
+ switch (scheme) {
+ case PART_TYPE_MSDOS:
+ if (mbr_part_type == 0x05 || mbr_part_type == 0x85 || mbr_part_type == 0x0f) {
+ ped_type = PED_PARTITION_EXTENDED;
+ } else {
+ ped_type = PED_PARTITION_NORMAL;
+ }
+ break;
+
+ case PART_TYPE_MSDOS_EXTENDED:
+ ped_type = PED_PARTITION_LOGICAL;
+ if (mbr_part_type == 0x05 || mbr_part_type == 0x85 || mbr_part_type == 0x0f) {
+ DEBUG ("Cannot create an extended partition inside an extended partition");
+ goto out;
+ }
+ break;
+
+ default:
+ ped_type = PED_PARTITION_NORMAL;
+ break;
+ }
+
+ /* now, create the partition */
+
+ start_sector = start / 512;
+ end_sector = (start + size) / 512 - 1;
+ new_start_sector = new_start / 512;
+ new_end_sector = (new_start + new_size) / 512 - 1;
+
+ device = ped_device_get (device_file);
+ if (device == NULL) {
+ DEBUG ("ped_device_get() failed");
+ goto out;
+ }
+ DEBUG ("got it");
+
+ /* set drive geometry on libparted object if the user requested it */
+ if (geometry_hps > 0 && geometry_spt > 0 ) {
+ /* not sure this is authorized use of libparted, but, eh, it seems to work */
+ device->hw_geom.cylinders = device->bios_geom.cylinders = device->length / geometry_hps / geometry_spt;
+ device->hw_geom.heads = device->bios_geom.heads = geometry_hps;
+ device->hw_geom.sectors = device->bios_geom.sectors = geometry_spt;
+ }
+
+ disk = ped_disk_new (device);
+ if (disk == NULL) {
+ DEBUG ("ped_disk_new() failed");
+ goto out_ped_device;
+ }
+ DEBUG ("got disk");
+
+ if (!is_change) {
+ part = ped_partition_new (disk,
+ ped_type,
+ NULL,
+ start_sector,
+ end_sector);
+ if (part == NULL) {
+ DEBUG ("ped_partition_new() failed");
+ goto out_ped_disk;
+ }
+ DEBUG ("new partition");
+ } else {
+ part = ped_disk_get_partition_by_sector (disk,
+ start_sector);
+ if (part == NULL) {
+ DEBUG ("ped_partition_get_by_sector() failed");
+ goto out_ped_disk;
+ }
+ DEBUG ("got partition");
+ }
+
+
+ /* TODO HACK XXX FIXME UGLY BAD: This is super ugly abuse of
+ * libparted - we poke at their internal data structures - but
+ * there ain't nothing we can do about it until libparted
+ * provides API for this...
+ */
+ if (scheme == PART_TYPE_GPT) {
+ struct {
+ efi_guid type;
+ efi_guid uuid;
+ char name[37];
+ int lvm;
+ int raid;
+ int boot;
+ int hp_service;
+ int hidden;
+ /* more stuff */
+ } *gpt_data = (void *) part->disk_specific;
+
+ if (type != NULL) {
+ if (!set_le_guid ((guint8*) &gpt_data->type, type)) {
+ DEBUG ("type '%s' for GPT appear to be malformed", type);
+ goto out_ped_partition;
+ }
+ }
+
+ if (flags != NULL) {
+ if (gpt_attributes & 1) {
+ gpt_data->hidden = 1;
+ } else {
+ gpt_data->hidden = 0;
+ }
+ }
+
+ } else if (scheme == PART_TYPE_MSDOS || scheme == PART_TYPE_MSDOS_EXTENDED) {
+ struct {
+ unsigned char system;
+ int boot;
+ /* more stuff */
+ } *dos_data = (void *) part->disk_specific;
+
+ if (type != NULL) {
+ dos_data->system = mbr_part_type;
+ }
+ if (flags != NULL) {
+ if (mbr_flags & 0x80) {
+ dos_data->boot = 1;
+ } else {
+ dos_data->boot = 0;
+ }
+ }
+
+ } else if (scheme == PART_TYPE_APPLE) {
+ struct {
+ char volume_name[33]; /* eg: "Games" */
+ char system_name[33]; /* eg: "Apple_Unix_SVR2" */
+ char processor_name[17];
+ int is_boot;
+ int is_driver;
+ int has_driver;
+ int is_root;
+ int is_swap;
+ int is_lvm;
+ int is_raid;
+ PedSector data_region_length;
+ PedSector boot_region_length;
+ guint32 boot_base_address;
+ guint32 boot_entry_address;
+ guint32 boot_checksum;
+ guint32 status;
+ /* more stuff */
+ } *mac_data = (void *) part->disk_specific;
+
+ if (type != NULL) {
+ memset (mac_data->system_name, 0, 33);
+ strncpy (mac_data->system_name, type, 32);
+ }
+
+ if (flags != NULL) {
+ mac_data->status = apm_status;
+ }
+ }
+
+ if (label != NULL) {
+ ped_partition_set_name (part, label);
+ }
+
+ if (geometry_hps > 0 && geometry_spt > 0 ) {
+ /* respect drive geometry */
+ constraint = ped_constraint_any (device);
+ } else if (geometry_hps == -1 && geometry_spt == -1 ) {
+
+ /* undocumented (or is it?) libparted usage again.. it appears that
+ * the probed geometry is stored in hw_geom
+ */
+ device->bios_geom.cylinders = device->hw_geom.cylinders;
+ device->bios_geom.heads = device->hw_geom.heads;
+ device->bios_geom.sectors = device->hw_geom.sectors;
+
+ constraint = ped_constraint_any (device);
+ } else {
+ PedGeometry *geo_start;
+ PedGeometry *geo_end;
+
+ /* ignore drive geometry */
+ if (is_change) {
+ geo_start = ped_geometry_new (device, new_start_sector, 1);
+ geo_end = ped_geometry_new (device, new_end_sector, 1);
+ } else {
+ geo_start = ped_geometry_new (device, start_sector, 1);
+ geo_end = ped_geometry_new (device, end_sector, 1);
+ }
+
+ constraint = ped_constraint_new (ped_alignment_any, ped_alignment_any,
+ geo_start, geo_end, 1, device->length);
+ }
+
+try_change_again:
+ if (is_change) {
+ if (ped_disk_set_partition_geom (disk,
+ part,
+ constraint,
+ new_start_sector, new_end_sector) == 0) {
+ DEBUG ("ped_disk_set_partition_geom() failed");
+ goto out_ped_constraint;
+ }
+ } else {
+ if (ped_disk_add_partition (disk,
+ part,
+ constraint) == 0) {
+ DEBUG ("ped_disk_add_partition() failed");
+ goto out_ped_constraint;
+ }
+ }
+
+ *out_start = part->geom.start * 512;
+ *out_size = part->geom.length * 512;
+
+ if (is_change) {
+ /* make sure the resulting size is never smaller than requested
+ * (this is because one will resize the FS and *then* change the partition table)
+ */
+ if (*out_size < new_size) {
+ DEBUG ("new_size=%lld but resulting size, %lld, smaller than requested", new_size, *out_size);
+ new_end_sector++;
+ goto try_change_again;
+ } else {
+ DEBUG ("changed partition to start=%lld size=%lld", *out_start, *out_size);
+ }
+ } else {
+ DEBUG ("added partition start=%lld size=%lld", *out_start, *out_size);
+ }
+
+
+ /* hmm, if we don't do this libparted crashes.. I assume that
+ * ped_disk_add_partition assumes ownership of the
+ * PedPartition when adding it... sadly this is not documented
+ * anywhere.. sigh..
+ */
+ part = NULL;
+
+ /* use commit_to_dev rather than just commit to avoid
+ * libparted sending BLKRRPART to the kernel - we want to do
+ * this ourselves...
+ */
+ if (ped_disk_commit_to_dev (disk) == 0) {
+ DEBUG ("ped_disk_commit_to_dev() failed");
+ goto out_ped_constraint;
+ }
+ DEBUG ("committed to disk");
+
+ res = TRUE;
+
+ ped_constraint_destroy (constraint);
+ ped_disk_destroy (disk);
+ ped_device_destroy (device);
+ goto out;
+
+out_ped_constraint:
+ ped_constraint_destroy (constraint);
+
+out_ped_partition:
+ if (part != NULL) {
+ ped_partition_destroy (part);
+ }
+
+out_ped_disk:
+ ped_disk_destroy (disk);
+
+out_ped_device:
+ ped_device_destroy (device);
+
+out:
+ return res;
+}
+
+gboolean
+part_add_partition (char *device_file,
+ guint64 start, guint64 size,
+ guint64 *out_start, guint64 *out_size,
+ char *type, char *label, char **flags,
+ int geometry_hps, int geometry_spt)
+{
+ return part_add_change_partition (device_file,
+ start, size,
+ 0, 0,
+ out_start, out_size,
+ type, label, flags,
+ geometry_hps, geometry_spt);
+}
+
+gboolean
+part_change_partition (char *device_file,
+ guint64 start,
+ guint64 new_start, guint64 new_size,
+ guint64 *out_start, guint64 *out_size,
+ char *type, char *label, char **flags,
+ int geometry_hps, int geometry_spt)
+{
+ return part_add_change_partition (device_file,
+ start, 0,
+ new_start, new_size,
+ out_start, out_size,
+ type, label, flags,
+ geometry_hps, geometry_spt);
+}
+
+gboolean
+part_del_partition (char *device_file, guint64 offset)
+{
+ gboolean ret;
+ PedDevice *device;
+ PedDisk *disk;
+ PedPartition *part;
+ PartitionTable *p;
+ gboolean is_extended;
+ int n;
+
+ DEBUG ("In part_del_partition: device_file=%s, offset=%lld", device_file, offset);
+ ret = FALSE;
+
+
+ /* sigh.. one would think that if you passed the sector of where the
+ * the beginning of the extended partition starts, then _by_sector
+ * would return the same as _extended_partition.
+ *
+ * Sadly it's not so..
+ *
+ * So, check if the passed offset actually corresponds to a nested
+ * partition table...
+ */
+ is_extended = FALSE;
+ p = part_table_load_from_disk (device_file);
+ if (p == NULL) {
+ DEBUG ("Cannot load partition table from %s", device_file);
+ goto out;
+ }
+ for (n = 0; n < part_table_get_num_entries (p); n++) {
+ PartitionTable *nested;
+ nested = part_table_entry_get_nested (p, n);
+ if (nested != NULL) {
+ if (part_table_get_offset (nested) == offset) {
+ DEBUG ("partition to delete is an extended partition");
+ is_extended = TRUE;
+ }
+ }
+ }
+ part_table_free (p);
+
+ device = ped_device_get (device_file);
+ if (device == NULL) {
+ DEBUG ("ped_device_get() failed");
+ goto out;
+ }
+ DEBUG ("got it");
+
+ disk = ped_disk_new (device);
+ if (disk == NULL) {
+ DEBUG ("ped_disk_new() failed");
+ goto out_ped_device;
+ }
+ DEBUG ("got disk");
+
+ if (is_extended) {
+ part = ped_disk_extended_partition (disk);
+ } else {
+ part = ped_disk_get_partition_by_sector (disk, offset / 512);
+ }
+
+ if (part == NULL) {
+ DEBUG ("ped_disk_get_partition_by_sector() failed");
+ goto out_ped_disk;
+ }
+
+ DEBUG ("got partition - part->type=%d", part->type);
+ /* allow only to delete primary, logical and extended partitions */
+ if (! ((part->type == PED_PARTITION_NORMAL) ||
+ (part->type == PED_PARTITION_LOGICAL) ||
+ (part->type == PED_PARTITION_EXTENDED))) {
+ DEBUG ("no data partition at given offset %lld for device %s", offset, device_file);
+ goto out_ped_disk;
+ }
+
+ if (ped_disk_delete_partition (disk, part) == 0) {
+ DEBUG ("ped_disk_delete_partition() failed");
+ goto out_ped_disk;
+ }
+
+ /* use commit_to_dev rather than just commit to avoid
+ * libparted sending BLKRRPART to the kernel - we want to do
+ * this ourselves...
+ */
+
+ if (ped_disk_commit_to_dev (disk) == 0) {
+ DEBUG ("ped_disk_commit_to_dev() failed");
+ goto out_ped_disk;
+ }
+ DEBUG ("committed to disk");
+
+ ret = TRUE;
+
+ ped_disk_destroy (disk);
+ ped_device_destroy (device);
+ goto out;
+
+out_ped_disk:
+ ped_disk_destroy (disk);
+
+out_ped_device:
+ ped_device_destroy (device);
+
+out:
+ return ret;
+}
+
+gboolean
+part_create_partition_table (char *device_file, PartitionScheme scheme)
+{
+ PedDevice *device;
+ PedDisk *disk;
+ PedDiskType *disk_type;
+ gboolean ret;
+
+ ret = FALSE;
+
+ DEBUG ("In part_create_partition_table: device_file=%s, scheme=%d", device_file, scheme);
+
+ device = ped_device_get (device_file);
+ if (device == NULL) {
+ DEBUG ("ped_device_get() failed");
+ goto out;
+ }
+ DEBUG ("got it");
+
+ switch (scheme) {
+ case PART_TYPE_MSDOS:
+ disk_type = ped_disk_type_get ("msdos");
+ break;
+ case PART_TYPE_APPLE:
+ disk_type = ped_disk_type_get ("mac");
+ break;
+ case PART_TYPE_GPT:
+ disk_type = ped_disk_type_get ("gpt");
+ break;
+ default:
+ disk_type = NULL;
+ break;
+ }
+
+ if (disk_type == NULL) {
+ DEBUG ("Unknown or unsupported partitioning scheme %d", scheme);
+ goto out;
+ }
+
+ disk = ped_disk_new_fresh (device, disk_type);
+ if (disk == NULL) {
+ DEBUG ("ped_disk_new_fresh() failed");
+ goto out_ped_device;
+ }
+ DEBUG ("got disk");
+
+ if (ped_disk_commit_to_dev (disk) == 0) {
+ DEBUG ("ped_disk_commit_to_dev() failed");
+ goto out_ped_disk;
+ }
+ DEBUG ("committed to disk");
+
+ ret = TRUE;
+
+ ped_disk_destroy (disk);
+ ped_device_destroy (device);
+ goto out;
+
+out_ped_disk:
+ ped_disk_destroy (disk);
+
+out_ped_device:
+ ped_device_destroy (device);
+
+out:
+ return ret;
+}
+
+#endif /* USE_PARTED */
+
+/**************************************************************************/
--- /dev/null
+/***************************************************************************
+ *
+ * part.h : library for reading and writing partition tables - uses
+ * libparted for the heavy lifting
+ *
+ * Copyright (C) 2006 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
+ *
+ **************************************************************************/
+
+#ifndef PARTUTIL_H
+#define PARTUTIL_H
+
+#include <stdio.h>
+#include <glib.h>
+
+/* Partition schemes understood by this library */
+typedef enum {
+ PART_TYPE_MSDOS = 0,
+ PART_TYPE_MSDOS_EXTENDED = 1,
+ PART_TYPE_APPLE = 2,
+ PART_TYPE_GPT = 3
+} PartitionScheme;
+
+/**
+ * part_get_scheme_name:
+ * @scheme: the partitioning scheme
+ *
+ * Get a name for the partitioning scheme. The current mapping is used
+ *
+ * PART_TYPE_MSDOS -> mbr
+ * PART_TYPE_MSDOS_EXTENDED -> embr
+ * PART_TYPE_APPLE -> apm
+ * PART_TYPE_GPT -> gpt
+ *
+ * Returns: Name of scheme or NULL for unknown scheme. Caller shall not free this string.
+ */
+const char *part_get_scheme_name (PartitionScheme scheme);
+
+struct PartitionTable_s;
+typedef struct PartitionTable_s PartitionTable;
+
+
+/**
+ * part_table_load_from_disk:
+ * @device: name of device file for entire disk, e.g. /dev/sda
+ *
+ * Scans a disk and collect all partition entries and nested partition tables.
+ *
+ * Returns: A partition table object. Use part_table_free() to free this object.
+ */
+PartitionTable *part_table_load_from_disk (char *device);
+
+/**
+ * part_table_free:
+ * @part_table: the partition table
+ *
+ * Frees the partition table returned from part_table_load_from_disk().
+ */
+void part_table_free (PartitionTable *part_table);
+
+/* partition table inspection */
+
+/**
+ * part_table_get_scheme:
+ * @part_table: the partition table
+ *
+ * Get partitioning scheme.
+ *
+ * Returns: The partitioning scheme.
+ */
+PartitionScheme part_table_get_scheme (PartitionTable *part_table);
+
+/**
+ * part_table_get_num_entries:
+ * @part_table: the partition table
+ *
+ * Get number of entries in partition table.
+ *
+ * Returns: Number of entries.
+ */
+int part_table_get_num_entries (PartitionTable *part_table);
+
+/**
+ * part_table_get_offset:
+ * @part_table: the partition table
+ *
+ * Get offset from start of disk where partition table starts (as
+ * referenced in the partition table entry if it's an embedded
+ * partition table, otherwise zero for the full disk)
+ *
+ * Returns: offset, from start of disk, in bytes
+ */
+guint64 part_table_get_offset (PartitionTable *part_table);
+
+/**
+ * part_table_get_size:
+ * @part_table: the partition table
+ *
+ * Get size of partition table (as referenced in the partition table
+ * entry if it's an embedded partition table, otherwise the size of
+ * the full disk)
+ *
+ * Returns: size of partition, in bytes
+ */
+guint64 part_table_get_size (PartitionTable *part_table);
+
+/**
+ * part_table_find:
+ * @part_table: the partition table
+ * @offset: the offset to test for
+ * @out_part_table: where the (embedded) enclosing the entry will be stored
+ * @out_entry: there the partition table entry number will be stored
+ *
+ * This function finds the entry that a certain byte of the disk belongs to.
+ * As partition tables can be embedded (think MS-DOS extended partitions)
+ * the returned partition table (out_part_table) might be different from
+ * the one passed. If the offset belongs to a primary partition then the
+ * return partition_table will be the same as the passed one.
+ *
+ * If there is no partition at the given offset (might be free space),
+ * out_entry will be set to -1. Note that out_part_table will always
+ * be set though and free space in the primary disk space and the
+ * extended partition space differs.
+ *
+ * This is a convenience function.
+ */
+void part_table_find (PartitionTable *part_table,
+ guint64 offset,
+ PartitionTable **out_part_table,
+ int *out_entry);
+
+
+/**
+ * part_table_entry_get_nested:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * If the partition table entry points to an embedded partition table this
+ * function will return a PartitionTable object representing it.
+ *
+ * Returns: NULL if the entry does not point to a an embedded partition table.
+ * Do not free with part_table_free() - the object will be freed when
+ * freeing the root object.
+ */
+PartitionTable *part_table_entry_get_nested (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_type:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Get the partition table type - the type itself is partitioning scheme
+ * specific as described below.
+ *
+ * For PART_TYPE_MSDOS and PART_TYPE_MSDOS_EXTENDED, the type is an integer
+ * encoded in a string, e.g. 0x83 is Linux. Use atoi() to convert back to
+ * an integer. See http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
+ * for details.
+ *
+ * For PART_TYPE_GPT, this is the GUID encoded as a string, see
+ * http://en.wikipedia.org/wiki/GUID_Partition_Table for details.
+ *
+ * For PART_TYPE_APPLE, this is a string as defined in
+ * http://developer.apple.com/documentation/mac/Devices/Devices-126.html.
+ * For FAT file systems, it appears that "DOS_FAT_32", "DOS_FAT_16" and
+ * "DOS_FAT_12" are also recognized under Mac OS X (I've tested this too) cf.
+ * http://lists.apple.com/archives/Darwin-drivers/2003/May/msg00021.html
+ *
+ * Returns: The partition table type. Caller shall free this with g_free().
+ */
+char *part_table_entry_get_type (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_label:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Label of the partition. This is only supported for PART_TYPE_APPLE and
+ * PART_TYPE_GPT. Note that this is not the same as the file system label
+ * in a file system in the partition.
+ *
+ * Returns: The label or NULL if the partitioning scheme does not support
+ * labels. Caller shall free this with g_free().
+ */
+char *part_table_entry_get_label (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_uuid:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Some UUID/GUID of the partition. This is only supported for PART_TYPE_GPT.
+ *
+ * Returns: The UUID or NULL if the partitioning scheme does not support
+ * UUID/GUID. Caller shall free this with g_free().
+ */
+char *part_table_entry_get_uuid (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_flags:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Get flags of partition table entry. This is dependent on the partitioning
+ * scheme.
+ *
+ * For PART_TYPE_MSDOS and PART_TYPE_MSDOS_EXTENDED the following flags are
+ * recognized:
+ * - "boot"; meaning that the bootable flag is set. This is used by some
+ * BIOS'es and boot loaders to populate a boot menu.
+ *
+ * For PART_TYPE_GPT the following flags are recognized:
+ * - "required" which corresponds to bit 0 of the attibutes
+ * (offset 48), meaning "Required for the platform to function. The
+ * system cannot function normally if this partition is removed. This
+ * partition should be considered as part of the hardware of the
+ * system, and if it is removed the system may not boot. It may
+ * contain diagnostics, recovery tools, or other code or data that is
+ * critical to the functioning of a system independent of any OS."
+ *
+ *
+ * For PART_TYPE_APPLE the following flags are recognized:
+ * - "allocated"; if the partition is already allocated
+ * - "in_use"; if the partition is in use; may be cleared after a system reset
+ * - "boot"; if partition contains valid boot information
+ * - "allow_read"; if partition allows reading
+ * - "allow_write"; if partition allows writing
+ * - "boot_code_is_pic"; if boot code is position independent
+ *
+ * Returns: An array of strings, one per flag, terminated by NULL. Caller
+ * shall free this with g_strfreev().
+ */
+char **part_table_entry_get_flags (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_offset:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Get offset from start of disk where partition starts (as referenced in the
+ * partition table entry)
+ *
+ * Returns: offset, from start of disk, in bytes
+ */
+guint64 part_table_entry_get_offset (PartitionTable *part_table, int entry);
+
+/**
+ * part_table_entry_get_size:
+ * @part_table: the partition table
+ * @entry: zero-based index of entry in partition table
+ *
+ * Get size of partition (as referenced in the partition table entry)
+ *
+ * Returns: size of partition, in bytes
+ */
+guint64 part_table_entry_get_size (PartitionTable *part_table, int entry);
+
+
+/**
+ * part_create_partition_table:
+ * @device: name of device file for entire disk, e.g. /dev/sda
+ * @scheme: the partitioning scheme
+ *
+ * Create a new fresh partition on a disk.
+ *
+ * Returns: TRUE if the operation was succesful, otherwise FALSE
+ */
+gboolean part_create_partition_table (char *device, PartitionScheme scheme);
+
+
+/**
+ * part_add_partition:
+ * @device: name of device file for entire disk, e.g. /dev/sda
+ * @start: start offset of partition, in bytes
+ * @size: size of partition, in bytes
+ * @out_start: where partition will start, after satisfying disk geometry constraints
+ * @out_size: size of partition, after satisfying disk geometry constraints
+ * @type: the partition type as defined in part_table_entry_get_type()
+ * @flags: the partition flags as defined in part_table_entry_get_flags()
+ * @label: the partition label as defined in part_table_entry_get_label()
+ * @geometry_hps: heads-per-sector used for LBA<->CHS conversions
+ * @geometry_spt: sectors-per-track used for LBA<->CHS conversions
+ *
+ * Adds a new partition to a disk.
+ *
+ * If geometry_hps and geomtry_spt are both positive, they will be
+ * used as the geometry of the disk for CHS<->LBA conversions. Notably
+ * this is only applicable for MSDOS / MSDOS_EXTENDED partition
+ * tables. Also, in this case, geometry is enforced to ensure that
+ * partitions start and end at cylinder boundaries.
+ *
+ * If either geometry_hps or geomtry_spt are zero, geometry is
+ * simply ignored and partitions will only be aligned to blocks, e.g.
+ * normally 512 byte boundaries.
+ *
+ * If both geometry_hps or geomtry_spt are -1, then geometry information
+ * probed from existing partition table entries / file systems on the
+ * disk. This is not always reliable.
+ *
+ * As such, the caller cannot always expect that the partition created
+ * will be at the requested offset and size due to e.g. geometry and
+ * block boundary alignment. Therefore, the start and size where the
+ * partition ends up is passed in the out_start and out_size
+ * arguments.
+ *
+ * As embedded partition tables are supported, the caller should use
+ * part_table_find() in advance to make sure that the passed type,
+ * label and flags match the (embedded) partition table that this
+ * partition will be part of.
+ *
+ * To create an MSDOS extended partition table in a MSDOS partition
+ * table, simply pass 0x05, 0x0f or 0x85 as the partition type.
+ *
+ * In order for changes to take effect, the caller needs to poke the
+ * OS kernel himself to make it reload the partition table. It is not
+ * automatically done by this function.
+ *
+ * NOTE: After calling this function you need to discard any partition table
+ * obtained with part_table_load_from_disk() since the in-memory data structure
+ * is not updated.
+ *
+ * Returns: TRUE if the operation was succesful, otherwise FALSE
+ */
+gboolean part_add_partition (char *device,
+ guint64 start, guint64 size,
+ guint64 *out_start, guint64 *out_size,
+ char *type, char *label, char **flags,
+ int geometry_hps, int geometry_spt);
+
+/**
+ * part_change_partition:
+ * @device_file: name of device file for entire disk, e.g. /dev/sda
+ * @start: start offset of existing partition, in bytes
+ * @new_start: new start offset of partition, in bytes
+ * @new_size: new size of partition, in bytes
+ * @out_start: where partition will start, after satisfying disk geometry constraints
+ * @out_size: size of partition, after satisfying disk geometry constraints
+ * @type: the partition type as defined in part_table_entry_get_type() or NULL to not change
+ * @flags: the partition flags as defined in part_table_entry_get_flags() or NULL to not change
+ * @label: the partition label as defined in part_table_entry_get_label() or NULL to not change
+ * @geometry_hps: heads-per-sector used for LBA<->CHS conversions
+ * @geometry_spt: sectors-per-track used for LBA<->CHS conversions
+ *
+ * Changes an existing partition table entry on disk. The contents of
+ * the partition will not be touched.
+ *
+ * XXX TODO FIXME: probably be careful with overlapping partitions as
+ * e.g. extended MS-DOS partitions have the partition information just
+ * before the partition data itself. Need to look into this.
+ *
+ * If new_start and new_size matches the existing start and size, only
+ * flags, label and type are changed. Any of flags, label and type can
+ * be set to NULL to signal there should be no change. Thus, this
+ * function serves two purposes. It can be used to both change offset and/or
+ * size and it can be used to change type and/or flags and/or label.
+ *
+ * See part_add_partition() for information about geometry_hps and
+ * geometry_spt and how it affects the resulting partition offset and
+ * size. This function gives one guarantee though: the resulting size
+ * will never be smaller than the requested size. This is useful for
+ * two-step operations by which a file system is first shrinked and
+ * then the partition table is updated.
+ *
+ * In order for changes to take effect, the caller needs to poke the
+ * OS kernel himself to make it reload the partition table. It is not
+ * automatically done by this function.
+ *
+ * NOTE: After calling this function you need to discard any partition
+ * table obtained with part_table_load_from_disk() since the in-memory
+ * data structure is not updated.
+ *
+ * Returns: TRUE if the operation was succesful, otherwise FALSE
+ */
+gboolean part_change_partition (char *device_file,
+ guint64 start,
+ guint64 new_start, guint64 new_size,
+ guint64 *out_start, guint64 *out_size,
+ char *type, char *label, char **flags,
+ int geometry_hps, int geometry_spt);
+
+/**
+ * part_del_partition:
+ * @device: name of device file for entire disk, e.g. /dev/sda
+ * @offset: offset of somewhere within the partition to delete, in bytes
+ *
+ * Deletes a partition. Just pass the offset of the partition. If you
+ * delete an extended partition all logical partitions will be deleted
+ * too.
+ *
+ * NOTE: After calling this function you need to discard any partition table
+ * obtained with part_table_load_from_disk() since the in-memory data structure
+ * is not updated.
+ *
+ * Returns: TRUE if the operation was succesful, otherwise FALSE
+ */
+gboolean part_del_partition (char *device, guint64 offset);
+
+
+#endif /* PARTUTIL_H */
g_print ("removed: %s\n", object_path);
}
+/* --- SUCKY CODE BEGIN --- */
+
+/* This totally sucks; dbus-bindings-tool and dbus-glib should be able
+ * to do this for us.
+ */
+
static char *
get_property_string (DBusGConnection *bus,
const char *svc_name,
return ret;
}
+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;
+
+ 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;
+ }
+
+ ret = (gboolean) g_value_get_boolean (&value);
+
+out:
+ g_object_unref (proxy);
+ return ret;
+}
+
+static guint64
+get_property_uint64 (DBusGConnection *bus,
+ const char *svc_name,
+ const char *obj_path,
+ const char *if_name,
+ const char *prop_name)
+{
+ 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;
+}
+
+static int
+get_property_int (DBusGConnection *bus,
+ const char *svc_name,
+ const char *obj_path,
+ const char *if_name,
+ const char *prop_name)
+{
+ 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;
+ }
+
+ 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,
{
char *native_path;
- char *device_file;
- char **device_file_by_id;
- char **device_file_by_path;
- char **device_holders;
- char **device_slaves;
-
- char *id_usage;
- char *id_type;
- char *id_version;
- char *id_uuid;
- char *id_label;
+ char *device_file;
+ char **device_file_by_id;
+ char **device_file_by_path;
+ char **device_holders;
+ char **device_slaves;
+ gboolean device_is_partition;
+ gboolean device_is_partition_table;
+
+ char *id_usage;
+ char *id_type;
+ char *id_version;
+ char *id_uuid;
+ char *id_label;
+
+ char *partition_slave;
+ char *partition_scheme;
+ int partition_number;
+ char *partition_type;
+ char *partition_label;
+ char *partition_uuid;
+ char **partition_flags;
+ guint64 partition_offset;
+ guint64 partition_size;
+
+ char *partition_table_scheme;
+ int partition_table_count;
+ char **partition_table_holders;
} DeviceProperties;
static DeviceProperties *
object_path,
"org.freedesktop.DeviceKit.Disks.Device",
"device-slaves");
+ 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->id_usage = get_property_string (
bus,
object_path,
"org.freedesktop.DeviceKit.Disks.Device",
"id-label");
+
+ props->partition_slave = get_property_string (
+ 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_holders = get_property_strlist (
+ bus,
+ "org.freedesktop.DeviceKit.Disks",
+ object_path,
+ "org.freedesktop.DeviceKit.Disks.Device",
+ "partition-table-holders");
return props;
}
g_free (props->id_version);
g_free (props->id_uuid);
g_free (props->id_label);
+ g_free (props->partition_slave);
+ g_free (props->partition_type);
+ g_free (props->partition_label);
+ g_free (props->partition_uuid);
+ g_strfreev (props->partition_flags);
+ g_free (props->partition_table_scheme);
+ g_strfreev (props->partition_table_holders);
g_free (props);
}
+/* --- SUCKY CODE END --- */
+
int
main (int argc, char **argv)
{
props = device_properties_get (bus, show_info);
g_print ("Showing information for %s\n", show_info);
- g_print (" native-path: %s\n", props->native_path);
+ g_print (" native-path: %s\n", props->native_path);
for (n = 0; props->device_holders[n] != NULL; n++)
- g_print (" holder: %s\n", (char *) props->device_holders[n]);
+ g_print (" holder: %s\n", (char *) props->device_holders[n]);
for (n = 0; props->device_slaves[n] != NULL; n++)
- g_print (" slave: %s\n", (char *) props->device_slaves[n]);
- g_print (" device-file: %s\n", props->device_file);
+ g_print (" slave: %s\n", (char *) props->device_slaves[n]);
+ g_print (" device-file: %s\n", props->device_file);
for (n = 0; props->device_file_by_id[n] != NULL; n++)
- g_print (" by-id: %s\n", (char *) props->device_file_by_id[n]);
+ g_print (" by-id: %s\n", (char *) props->device_file_by_id[n]);
for (n = 0; props->device_file_by_path[n] != NULL; n++)
- g_print (" by-path: %s\n", (char *) props->device_file_by_path[n]);
- g_print (" id-usage: %s\n", props->id_usage);
- g_print (" id-type: %s\n", props->id_type);
- g_print (" id-version: %s\n", props->id_version);
- g_print (" id-uuid: %s\n", props->id_uuid);
- g_print (" id-label: %s\n", props->id_label);
+ g_print (" by-path: %s\n", (char *) props->device_file_by_path[n]);
+ g_print (" usage: %s\n", props->id_usage);
+ g_print (" type: %s\n", props->id_type);
+ g_print (" version: %s\n", props->id_version);
+ g_print (" uuid: %s\n", props->id_uuid);
+ g_print (" label: %s\n", props->id_label);
+ if (props->device_is_partition_table) {
+ g_print (" partition table:\n");
+ g_print (" scheme: %s\n", props->partition_table_scheme);
+ g_print (" count: %d\n", props->partition_table_count);
+ for (n = 0; props->partition_table_holders[n] != NULL; n++)
+ g_print (" partition: %s\n", (char *) props->partition_table_holders[n]);
+
+ }
+ if (props->device_is_partition) {
+ g_print (" partition:\n");
+ g_print (" part of: %s\n", props->partition_slave);
+ g_print (" scheme: %s\n", props->partition_scheme);
+ g_print (" number: %d\n", props->partition_number);
+ g_print (" type: %s\n", props->partition_type);
+ g_print (" flags: ");
+ for (n = 0; props->partition_flags[n] != NULL; n++)
+ g_print (" %s", (char *) props->partition_flags[n]);
+ g_print ("\n");
+ g_print (" offset: %lld\n", props->partition_offset);
+ g_print (" size: %lld\n", props->partition_size);
+ g_print (" label: %s\n", props->partition_label);
+ g_print (" uuid: %s\n", props->partition_uuid);
+
+ }
device_properties_free (props);
}