1457 lines
53 KiB
C
1457 lines
53 KiB
C
/* *************************************************************************
|
|
* device-info.c GPL v3 Copyright 2012
|
|
* contains code excerpts from udisks v1.0.4
|
|
************************************************************************** */
|
|
|
|
#include "device-info.h"
|
|
|
|
static char *
|
|
_dupv8 (const char *s)
|
|
{
|
|
const char *end_valid;
|
|
|
|
if (!g_utf8_validate (s, -1, &end_valid))
|
|
{
|
|
g_print ("**** NOTE: The string '%s' is not valid UTF-8. Invalid characters begins at '%s'\n", s, end_valid);
|
|
return g_strndup (s, end_valid - s);
|
|
}
|
|
else
|
|
{
|
|
return g_strdup (s);
|
|
}
|
|
}
|
|
|
|
/* unescapes things like \x20 to " " and ensures the returned string is valid UTF-8.
|
|
*
|
|
* see volume_id_encode_string() in extras/volume_id/lib/volume_id.c in the
|
|
* udev tree for the encoder
|
|
*/
|
|
static gchar *
|
|
decode_udev_encoded_string (const gchar *str)
|
|
{
|
|
GString *s;
|
|
gchar *ret;
|
|
const gchar *end_valid;
|
|
guint n;
|
|
|
|
s = g_string_new (NULL);
|
|
for (n = 0; str[n] != '\0'; n++)
|
|
{
|
|
if (str[n] == '\\')
|
|
{
|
|
gint val;
|
|
|
|
if (str[n + 1] != 'x' || str[n + 2] == '\0' || str[n + 3] == '\0')
|
|
{
|
|
g_print ("**** NOTE: malformed encoded string '%s'\n", str);
|
|
break;
|
|
}
|
|
|
|
val = (g_ascii_xdigit_value (str[n + 2]) << 4) | g_ascii_xdigit_value (str[n + 3]);
|
|
|
|
g_string_append_c (s, val);
|
|
|
|
n += 3;
|
|
}
|
|
else
|
|
{
|
|
g_string_append_c (s, str[n]);
|
|
}
|
|
}
|
|
|
|
if (!g_utf8_validate (s->str, -1, &end_valid))
|
|
{
|
|
g_print ("**** NOTE: The string '%s' is not valid UTF-8. Invalid characters begins at '%s'\n", s->str, end_valid);
|
|
ret = g_strndup (s->str, end_valid - s->str);
|
|
g_string_free (s, TRUE);
|
|
}
|
|
else
|
|
{
|
|
ret = g_string_free (s, FALSE);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static gint
|
|
ptr_str_array_compare (const gchar **a,
|
|
const gchar **b)
|
|
{
|
|
return g_strcmp0 (*a, *b);
|
|
}
|
|
|
|
static double
|
|
sysfs_get_double (const char *dir,
|
|
const char *attribute)
|
|
{
|
|
double result;
|
|
char *contents;
|
|
char *filename;
|
|
|
|
result = 0.0;
|
|
filename = g_build_filename (dir, attribute, NULL);
|
|
if (g_file_get_contents (filename, &contents, NULL, NULL))
|
|
{
|
|
result = atof (contents);
|
|
g_free (contents);
|
|
}
|
|
g_free (filename);
|
|
|
|
return result;
|
|
}
|
|
|
|
static char *
|
|
sysfs_get_string (const char *dir,
|
|
const char *attribute)
|
|
{
|
|
char *result;
|
|
char *filename;
|
|
|
|
result = NULL;
|
|
filename = g_build_filename (dir, attribute, NULL);
|
|
if (!g_file_get_contents (filename, &result, NULL, NULL))
|
|
{
|
|
result = g_strdup ("");
|
|
}
|
|
g_free (filename);
|
|
|
|
return result;
|
|
}
|
|
|
|
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 = strtol (contents, NULL, 0);
|
|
g_free (contents);
|
|
}
|
|
g_free (filename);
|
|
|
|
return result;
|
|
}
|
|
|
|
static guint64
|
|
sysfs_get_uint64 (const char *dir,
|
|
const char *attribute)
|
|
{
|
|
guint64 result;
|
|
char *contents;
|
|
char *filename;
|
|
|
|
result = 0;
|
|
filename = g_build_filename (dir, attribute, NULL);
|
|
if (g_file_get_contents (filename, &contents, NULL, NULL))
|
|
{
|
|
result = strtoll (contents, NULL, 0);
|
|
g_free (contents);
|
|
}
|
|
g_free (filename);
|
|
|
|
return result;
|
|
}
|
|
|
|
static gboolean
|
|
sysfs_file_exists (const char *dir,
|
|
const char *attribute)
|
|
{
|
|
gboolean result;
|
|
char *filename;
|
|
|
|
result = FALSE;
|
|
filename = g_build_filename (dir, attribute, NULL);
|
|
if (g_file_test (filename, G_FILE_TEST_EXISTS))
|
|
{
|
|
result = TRUE;
|
|
}
|
|
g_free (filename);
|
|
|
|
return result;
|
|
}
|
|
|
|
static char *
|
|
sysfs_resolve_link (const char *sysfs_path,
|
|
const char *name)
|
|
{
|
|
char *full_path;
|
|
char link_path[PATH_MAX];
|
|
char resolved_path[PATH_MAX];
|
|
ssize_t num;
|
|
gboolean found_it;
|
|
|
|
found_it = FALSE;
|
|
|
|
full_path = g_build_filename (sysfs_path, name, NULL);
|
|
|
|
//g_debug ("name='%s'", name);
|
|
//g_debug ("full_path='%s'", full_path);
|
|
num = readlink (full_path, link_path, sizeof(link_path) - 1);
|
|
if (num != -1)
|
|
{
|
|
char *absolute_path;
|
|
|
|
link_path[num] = '\0';
|
|
|
|
//g_debug ("link_path='%s'", link_path);
|
|
absolute_path = g_build_filename (sysfs_path, link_path, NULL);
|
|
//g_debug ("absolute_path='%s'", absolute_path);
|
|
if (realpath (absolute_path, resolved_path) != NULL)
|
|
{
|
|
//g_debug ("resolved_path='%s'", resolved_path);
|
|
found_it = TRUE;
|
|
}
|
|
g_free (absolute_path);
|
|
}
|
|
g_free (full_path);
|
|
|
|
if (found_it)
|
|
return g_strdup (resolved_path);
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
gboolean info_is_system_internal( device_t *device )
|
|
{
|
|
const char *value;
|
|
|
|
if ( value = udev_device_get_property_value( device->udevice, "UDISKS_SYSTEM_INTERNAL" ) )
|
|
return atoi( value ) != 0;
|
|
|
|
/* A Linux MD device is system internal if, and only if
|
|
*
|
|
* - a single component is system internal
|
|
* - there are no components
|
|
* SKIP THIS TEST
|
|
*/
|
|
|
|
/* a partition is system internal only if the drive it belongs to is system internal */
|
|
//TODO
|
|
|
|
/* a LUKS cleartext device is system internal only if the underlying crypto-text
|
|
* device is system internal
|
|
* SKIP THIS TEST
|
|
*/
|
|
|
|
// devices with removable media are never system internal
|
|
if ( device->device_is_removable )
|
|
return FALSE;
|
|
|
|
/* devices on certain buses are never system internal */
|
|
if ( device->drive_connection_interface != NULL )
|
|
{
|
|
if (strcmp (device->drive_connection_interface, "ata_serial_esata") == 0
|
|
|| strcmp (device->drive_connection_interface, "sdio") == 0
|
|
|| strcmp (device->drive_connection_interface, "usb") == 0
|
|
|| strcmp (device->drive_connection_interface, "firewire") == 0)
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
void info_drive_connection( device_t *device )
|
|
{
|
|
char *s;
|
|
char *p;
|
|
char *q;
|
|
char *model;
|
|
char *vendor;
|
|
char *subsystem;
|
|
char *serial;
|
|
char *revision;
|
|
const char *connection_interface;
|
|
guint64 connection_speed;
|
|
|
|
connection_interface = NULL;
|
|
connection_speed = 0;
|
|
|
|
/* walk up the device tree to figure out the subsystem */
|
|
s = g_strdup (device->native_path);
|
|
do
|
|
{
|
|
p = sysfs_resolve_link (s, "subsystem");
|
|
if ( !device->device_is_removable && sysfs_get_int( s, "removable") != 0 )
|
|
device->device_is_removable = TRUE;
|
|
if (p != NULL)
|
|
{
|
|
subsystem = g_path_get_basename (p);
|
|
g_free (p);
|
|
|
|
if (strcmp (subsystem, "scsi") == 0)
|
|
{
|
|
connection_interface = "scsi";
|
|
connection_speed = 0;
|
|
|
|
/* continue walking up the chain; we just use scsi as a fallback */
|
|
|
|
/* grab the names from SCSI since the names from udev currently
|
|
* - replaces whitespace with _
|
|
* - is missing for e.g. Firewire
|
|
*/
|
|
vendor = sysfs_get_string (s, "vendor");
|
|
if (vendor != NULL)
|
|
{
|
|
g_strstrip (vendor);
|
|
/* Don't overwrite what we set earlier from ID_VENDOR */
|
|
if (device->drive_vendor == NULL)
|
|
{
|
|
device->drive_vendor = _dupv8 (vendor);
|
|
}
|
|
g_free (vendor);
|
|
}
|
|
|
|
model = sysfs_get_string (s, "model");
|
|
if (model != NULL)
|
|
{
|
|
g_strstrip (model);
|
|
/* Don't overwrite what we set earlier from ID_MODEL */
|
|
if (device->drive_model == NULL)
|
|
{
|
|
device->drive_model = _dupv8 (model);
|
|
}
|
|
g_free (model);
|
|
}
|
|
|
|
/* TODO: need to improve this code; we probably need the kernel to export more
|
|
* information before we can properly get the type and speed.
|
|
*/
|
|
|
|
if (device->drive_vendor != NULL && strcmp (device->drive_vendor, "ATA") == 0)
|
|
{
|
|
connection_interface = "ata";
|
|
break;
|
|
}
|
|
|
|
}
|
|
else if (strcmp (subsystem, "usb") == 0)
|
|
{
|
|
double usb_speed;
|
|
|
|
/* both the interface and the device will be 'usb'. However only
|
|
* the device will have the 'speed' property.
|
|
*/
|
|
usb_speed = sysfs_get_double (s, "speed");
|
|
if (usb_speed > 0)
|
|
{
|
|
connection_interface = "usb";
|
|
connection_speed = usb_speed * (1000 * 1000);
|
|
break;
|
|
|
|
}
|
|
}
|
|
else if (strcmp (subsystem, "firewire") == 0 || strcmp (subsystem, "ieee1394") == 0)
|
|
{
|
|
|
|
/* TODO: krh has promised a speed file in sysfs; theoretically, the speed can
|
|
* be anything from 100, 200, 400, 800 and 3200. Till then we just hardcode
|
|
* a resonable default of 400 Mbit/s.
|
|
*/
|
|
|
|
connection_interface = "firewire";
|
|
connection_speed = 400 * (1000 * 1000);
|
|
break;
|
|
|
|
}
|
|
else if (strcmp (subsystem, "mmc") == 0)
|
|
{
|
|
|
|
/* TODO: what about non-SD, e.g. MMC? Is that another bus? */
|
|
connection_interface = "sdio";
|
|
|
|
/* Set vendor name. According to this MMC document
|
|
*
|
|
* http://www.mmca.org/membership/IAA_Agreement_10_12_06.pdf
|
|
*
|
|
* - manfid: the manufacturer id
|
|
* - oemid: the customer of the manufacturer
|
|
*
|
|
* Apparently these numbers are kept secret. It would be nice
|
|
* to map these into names for setting the manufacturer of the drive,
|
|
* e.g. Panasonic, Sandisk etc.
|
|
*/
|
|
|
|
model = sysfs_get_string (s, "name");
|
|
if (model != NULL)
|
|
{
|
|
g_strstrip (model);
|
|
/* Don't overwrite what we set earlier from ID_MODEL */
|
|
if (device->drive_model == NULL)
|
|
{
|
|
device->drive_model = _dupv8 (model);
|
|
}
|
|
g_free (model);
|
|
}
|
|
|
|
serial = sysfs_get_string (s, "serial");
|
|
if (serial != NULL)
|
|
{
|
|
g_strstrip (serial);
|
|
/* Don't overwrite what we set earlier from ID_SERIAL */
|
|
if (device->drive_serial == NULL)
|
|
{
|
|
/* this is formatted as a hexnumber; drop the leading 0x */
|
|
device->drive_serial = _dupv8 (serial + 2);
|
|
}
|
|
g_free (serial);
|
|
}
|
|
|
|
/* TODO: use hwrev and fwrev files? */
|
|
revision = sysfs_get_string (s, "date");
|
|
if (revision != NULL)
|
|
{
|
|
g_strstrip (revision);
|
|
/* Don't overwrite what we set earlier from ID_REVISION */
|
|
if (device->drive_revision == NULL)
|
|
{
|
|
device->drive_revision = _dupv8 (revision);
|
|
}
|
|
g_free (revision);
|
|
}
|
|
|
|
/* TODO: interface speed; the kernel driver knows; would be nice
|
|
* if it could export it */
|
|
|
|
}
|
|
else if (strcmp (subsystem, "platform") == 0)
|
|
{
|
|
const gchar *sysfs_name;
|
|
|
|
sysfs_name = g_strrstr (s, "/");
|
|
if (g_str_has_prefix (sysfs_name + 1, "floppy.")
|
|
&& device->drive_vendor == NULL )
|
|
{
|
|
device->drive_vendor = g_strdup( "Floppy Drive" );
|
|
connection_interface = "platform";
|
|
}
|
|
}
|
|
|
|
g_free (subsystem);
|
|
}
|
|
|
|
/* advance up the chain */
|
|
p = g_strrstr (s, "/");
|
|
if (p == NULL)
|
|
break;
|
|
*p = '\0';
|
|
|
|
/* but stop at the root */
|
|
if (strcmp (s, "/sys/devices") == 0)
|
|
break;
|
|
|
|
}
|
|
while (TRUE);
|
|
|
|
if (connection_interface != NULL)
|
|
{
|
|
device->drive_connection_interface = g_strdup( connection_interface );
|
|
device->drive_connection_speed = connection_speed;
|
|
}
|
|
|
|
g_free (s);
|
|
}
|
|
|
|
static const struct
|
|
{
|
|
const char *udev_property;
|
|
const char *media_name;
|
|
} drive_media_mapping[] =
|
|
{
|
|
{ "ID_DRIVE_FLASH", "flash" },
|
|
{ "ID_DRIVE_FLASH_CF", "flash_cf" },
|
|
{ "ID_DRIVE_FLASH_MS", "flash_ms" },
|
|
{ "ID_DRIVE_FLASH_SM", "flash_sm" },
|
|
{ "ID_DRIVE_FLASH_SD", "flash_sd" },
|
|
{ "ID_DRIVE_FLASH_SDHC", "flash_sdhc" },
|
|
{ "ID_DRIVE_FLASH_MMC", "flash_mmc" },
|
|
{ "ID_DRIVE_FLOPPY", "floppy" },
|
|
{ "ID_DRIVE_FLOPPY_ZIP", "floppy_zip" },
|
|
{ "ID_DRIVE_FLOPPY_JAZ", "floppy_jaz" },
|
|
{ "ID_CDROM", "optical_cd" },
|
|
{ "ID_CDROM_CD_R", "optical_cd_r" },
|
|
{ "ID_CDROM_CD_RW", "optical_cd_rw" },
|
|
{ "ID_CDROM_DVD", "optical_dvd" },
|
|
{ "ID_CDROM_DVD_R", "optical_dvd_r" },
|
|
{ "ID_CDROM_DVD_RW", "optical_dvd_rw" },
|
|
{ "ID_CDROM_DVD_RAM", "optical_dvd_ram" },
|
|
{ "ID_CDROM_DVD_PLUS_R", "optical_dvd_plus_r" },
|
|
{ "ID_CDROM_DVD_PLUS_RW", "optical_dvd_plus_rw" },
|
|
{ "ID_CDROM_DVD_PLUS_R_DL", "optical_dvd_plus_r_dl" },
|
|
{ "ID_CDROM_DVD_PLUS_RW_DL", "optical_dvd_plus_rw_dl" },
|
|
{ "ID_CDROM_BD", "optical_bd" },
|
|
{ "ID_CDROM_BD_R", "optical_bd_r" },
|
|
{ "ID_CDROM_BD_RE", "optical_bd_re" },
|
|
{ "ID_CDROM_HDDVD", "optical_hddvd" },
|
|
{ "ID_CDROM_HDDVD_R", "optical_hddvd_r" },
|
|
{ "ID_CDROM_HDDVD_RW", "optical_hddvd_rw" },
|
|
{ "ID_CDROM_MO", "optical_mo" },
|
|
{ "ID_CDROM_MRW", "optical_mrw" },
|
|
{ "ID_CDROM_MRW_W", "optical_mrw_w" },
|
|
{ NULL, NULL }, };
|
|
|
|
static const struct
|
|
{
|
|
const char *udev_property;
|
|
const char *media_name;
|
|
} media_mapping[] =
|
|
{
|
|
{ "ID_DRIVE_MEDIA_FLASH", "flash" },
|
|
{ "ID_DRIVE_MEDIA_FLASH_CF", "flash_cf" },
|
|
{ "ID_DRIVE_MEDIA_FLASH_MS", "flash_ms" },
|
|
{ "ID_DRIVE_MEDIA_FLASH_SM", "flash_sm" },
|
|
{ "ID_DRIVE_MEDIA_FLASH_SD", "flash_sd" },
|
|
{ "ID_DRIVE_MEDIA_FLASH_SDHC", "flash_sdhc" },
|
|
{ "ID_DRIVE_MEDIA_FLASH_MMC", "flash_mmc" },
|
|
{ "ID_DRIVE_MEDIA_FLOPPY", "floppy" },
|
|
{ "ID_DRIVE_MEDIA_FLOPPY_ZIP", "floppy_zip" },
|
|
{ "ID_DRIVE_MEDIA_FLOPPY_JAZ", "floppy_jaz" },
|
|
{ "ID_CDROM_MEDIA_CD", "optical_cd" },
|
|
{ "ID_CDROM_MEDIA_CD_R", "optical_cd_r" },
|
|
{ "ID_CDROM_MEDIA_CD_RW", "optical_cd_rw" },
|
|
{ "ID_CDROM_MEDIA_DVD", "optical_dvd" },
|
|
{ "ID_CDROM_MEDIA_DVD_R", "optical_dvd_r" },
|
|
{ "ID_CDROM_MEDIA_DVD_RW", "optical_dvd_rw" },
|
|
{ "ID_CDROM_MEDIA_DVD_RAM", "optical_dvd_ram" },
|
|
{ "ID_CDROM_MEDIA_DVD_PLUS_R", "optical_dvd_plus_r" },
|
|
{ "ID_CDROM_MEDIA_DVD_PLUS_RW", "optical_dvd_plus_rw" },
|
|
{ "ID_CDROM_MEDIA_DVD_PLUS_R_DL", "optical_dvd_plus_r_dl" },
|
|
{ "ID_CDROM_MEDIA_DVD_PLUS_RW_DL", "optical_dvd_plus_rw_dl" },
|
|
{ "ID_CDROM_MEDIA_BD", "optical_bd" },
|
|
{ "ID_CDROM_MEDIA_BD_R", "optical_bd_r" },
|
|
{ "ID_CDROM_MEDIA_BD_RE", "optical_bd_re" },
|
|
{ "ID_CDROM_MEDIA_HDDVD", "optical_hddvd" },
|
|
{ "ID_CDROM_MEDIA_HDDVD_R", "optical_hddvd_r" },
|
|
{ "ID_CDROM_MEDIA_HDDVD_RW", "optical_hddvd_rw" },
|
|
{ "ID_CDROM_MEDIA_MO", "optical_mo" },
|
|
{ "ID_CDROM_MEDIA_MRW", "optical_mrw" },
|
|
{ "ID_CDROM_MEDIA_MRW_W", "optical_mrw_w" },
|
|
{ NULL, NULL }, };
|
|
|
|
void info_drive_properties ( device_t *device )
|
|
{
|
|
GPtrArray *media_compat_array;
|
|
const char *media_in_drive;
|
|
gboolean drive_is_ejectable;
|
|
gboolean drive_can_detach;
|
|
char *decoded_string;
|
|
guint n;
|
|
const char *value;
|
|
|
|
// drive identification
|
|
device->device_is_drive = sysfs_file_exists( device->native_path, "range" );
|
|
|
|
// vendor
|
|
if ( value = udev_device_get_property_value( device->udevice, "ID_VENDOR_ENC" ) )
|
|
{
|
|
decoded_string = decode_udev_encoded_string ( value );
|
|
g_strstrip (decoded_string);
|
|
device->drive_vendor = decoded_string;
|
|
}
|
|
else if ( value = udev_device_get_property_value( device->udevice, "ID_VENDOR" ) )
|
|
{
|
|
device->drive_vendor = g_strdup( value );
|
|
}
|
|
|
|
// model
|
|
if ( value = udev_device_get_property_value( device->udevice, "ID_MODEL_ENC" ) )
|
|
{
|
|
decoded_string = decode_udev_encoded_string ( value );
|
|
g_strstrip (decoded_string);
|
|
device->drive_model = decoded_string;
|
|
}
|
|
else if ( value = udev_device_get_property_value( device->udevice, "ID_MODEL" ) )
|
|
{
|
|
device->drive_model = g_strdup( value );
|
|
}
|
|
|
|
// revision
|
|
device->drive_revision = g_strdup( udev_device_get_property_value(
|
|
device->udevice, "ID_REVISION" ) );
|
|
|
|
// serial
|
|
if ( value = udev_device_get_property_value( device->udevice, "ID_SCSI_SERIAL" ) )
|
|
{
|
|
/* scsi_id sometimes use the WWN as the serial - annoying - see
|
|
* http://git.kernel.org/?p=linux/hotplug/udev.git;a=commit;h=4e9fdfccbdd16f0cfdb5c8fa8484a8ba0f2e69d3
|
|
* for details
|
|
*/
|
|
device->drive_serial = g_strdup( value );
|
|
}
|
|
else if ( value = udev_device_get_property_value( device->udevice, "ID_SERIAL_SHORT" ) )
|
|
{
|
|
device->drive_serial = g_strdup( value );
|
|
}
|
|
|
|
// wwn
|
|
if ( value = udev_device_get_property_value( device->udevice, "ID_WWN_WITH_EXTENSION" ) )
|
|
{
|
|
device->drive_wwn = g_strdup( value + 2 );
|
|
}
|
|
else if ( value = udev_device_get_property_value( device->udevice, "ID_WWN" ) )
|
|
{
|
|
device->drive_wwn = g_strdup( value + 2 );
|
|
}
|
|
|
|
/* pick up some things (vendor, model, connection_interface, connection_speed)
|
|
* not (yet) exported by udev helpers
|
|
*/
|
|
//update_drive_properties_from_sysfs (device);
|
|
info_drive_connection( device );
|
|
|
|
// is_ejectable
|
|
if ( value = udev_device_get_property_value( device->udevice, "ID_DRIVE_EJECTABLE" ) )
|
|
{
|
|
drive_is_ejectable = atoi( value ) != 0;
|
|
}
|
|
else
|
|
{
|
|
drive_is_ejectable = FALSE;
|
|
drive_is_ejectable |= ( udev_device_get_property_value(
|
|
device->udevice, "ID_CDROM" ) != NULL );
|
|
drive_is_ejectable |= ( udev_device_get_property_value(
|
|
device->udevice, "ID_DRIVE_FLOPPY_ZIP" ) != NULL );
|
|
drive_is_ejectable |= ( udev_device_get_property_value(
|
|
device->udevice, "ID_DRIVE_FLOPPY_JAZ" ) != NULL );
|
|
}
|
|
device->drive_is_media_ejectable = drive_is_ejectable;
|
|
|
|
// drive_media_compatibility
|
|
media_compat_array = g_ptr_array_new ();
|
|
for (n = 0; drive_media_mapping[n].udev_property != NULL; n++)
|
|
{
|
|
if ( udev_device_get_property_value( device->udevice,
|
|
drive_media_mapping[n].udev_property ) == NULL )
|
|
continue;
|
|
|
|
g_ptr_array_add (media_compat_array, (gpointer) drive_media_mapping[n].media_name);
|
|
}
|
|
/* special handling for SDIO since we don't yet have a sdio_id helper in udev to set properties */
|
|
if (g_strcmp0 (device->drive_connection_interface, "sdio") == 0)
|
|
{
|
|
gchar *type;
|
|
|
|
type = sysfs_get_string (device->native_path, "../../type");
|
|
g_strstrip (type);
|
|
if (g_strcmp0 (type, "MMC") == 0)
|
|
{
|
|
g_ptr_array_add (media_compat_array, "flash_mmc");
|
|
}
|
|
else if (g_strcmp0 (type, "SD") == 0)
|
|
{
|
|
g_ptr_array_add (media_compat_array, "flash_sd");
|
|
}
|
|
else if (g_strcmp0 (type, "SDHC") == 0)
|
|
{
|
|
g_ptr_array_add (media_compat_array, "flash_sdhc");
|
|
}
|
|
g_free (type);
|
|
}
|
|
g_ptr_array_sort (media_compat_array, (GCompareFunc) ptr_str_array_compare);
|
|
g_ptr_array_add (media_compat_array, NULL);
|
|
device->drive_media_compatibility = g_strjoinv( " ", (gchar**)media_compat_array->pdata );
|
|
|
|
// drive_media
|
|
media_in_drive = NULL;
|
|
if (device->device_is_media_available)
|
|
{
|
|
for (n = 0; media_mapping[n].udev_property != NULL; n++)
|
|
{
|
|
if ( udev_device_get_property_value( device->udevice,
|
|
media_mapping[n].udev_property ) == NULL )
|
|
continue;
|
|
// should this be media_mapping[n] ? doesn't matter, same?
|
|
media_in_drive = drive_media_mapping[n].media_name;
|
|
break;
|
|
}
|
|
/* If the media isn't set (from e.g. udev rules), just pick the first one in media_compat - note
|
|
* that this may be NULL (if we don't know what media is compatible with the drive) which is OK.
|
|
*/
|
|
if (media_in_drive == NULL)
|
|
media_in_drive = ((const gchar **) media_compat_array->pdata)[0];
|
|
}
|
|
device->drive_media = g_strdup( media_in_drive );
|
|
g_ptr_array_free (media_compat_array, TRUE);
|
|
|
|
// drive_can_detach
|
|
// right now, we only offer to detach USB devices
|
|
drive_can_detach = FALSE;
|
|
if (g_strcmp0 (device->drive_connection_interface, "usb") == 0)
|
|
{
|
|
drive_can_detach = TRUE;
|
|
}
|
|
if ( value = udev_device_get_property_value( device->udevice, "ID_DRIVE_DETACHABLE" ) )
|
|
{
|
|
drive_can_detach = atoi( value ) != 0;
|
|
}
|
|
device->drive_can_detach = drive_can_detach;
|
|
}
|
|
|
|
void info_device_properties( device_t *device )
|
|
{
|
|
const char* value;
|
|
|
|
device->native_path = g_strdup( udev_device_get_syspath( device->udevice ) );
|
|
device->devnode = g_strdup( udev_device_get_devnode( device->udevice ) );
|
|
device->major = g_strdup( udev_device_get_property_value( device->udevice, "MAJOR") );
|
|
device->minor = g_strdup( udev_device_get_property_value( device->udevice, "MINOR") );
|
|
if ( !device->native_path || !device->devnode || !device->major || !device->minor )
|
|
{
|
|
if ( device->native_path )
|
|
g_free( device->native_path );
|
|
device->native_path = NULL;
|
|
return;
|
|
}
|
|
|
|
//by id - would need to read symlinks in /dev/disk/by-id
|
|
|
|
// is_removable may also be set in info_drive_connection walking up sys tree
|
|
device->device_is_removable = sysfs_get_int( device->native_path, "removable");
|
|
|
|
device->device_presentation_hide = g_strdup( udev_device_get_property_value(
|
|
device->udevice, "UDISKS_PRESENTATION_HIDE") );
|
|
device->device_presentation_nopolicy = g_strdup( udev_device_get_property_value(
|
|
device->udevice, "UDISKS_PRESENTATION_NOPOLICY") );
|
|
device->device_presentation_name = g_strdup( udev_device_get_property_value(
|
|
device->udevice, "UDISKS_PRESENTATION_NAME") );
|
|
device->device_presentation_icon_name = g_strdup( udev_device_get_property_value(
|
|
device->udevice, "UDISKS_PRESENTATION_ICON_NAME") );
|
|
device->device_automount_hint = g_strdup( udev_device_get_property_value(
|
|
device->udevice, "UDISKS_AUTOMOUNT_HINT") );
|
|
|
|
// filesystem properties
|
|
gchar *decoded_string;
|
|
const gchar *partition_scheme;
|
|
gint partition_type = 0;
|
|
|
|
partition_scheme = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_SCHEME");
|
|
if ( value = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_TYPE") )
|
|
partition_type = atoi( value );
|
|
if (g_strcmp0 (partition_scheme, "mbr") == 0 && (partition_type == 0x05 ||
|
|
partition_type == 0x0f ||
|
|
partition_type == 0x85))
|
|
{
|
|
}
|
|
else
|
|
{
|
|
device->id_usage = g_strdup( udev_device_get_property_value( device->udevice,
|
|
"ID_FS_USAGE" ) );
|
|
device->id_type = g_strdup( udev_device_get_property_value( device->udevice,
|
|
"ID_FS_TYPE" ) );
|
|
device->id_version = g_strdup( udev_device_get_property_value( device->udevice,
|
|
"ID_FS_VERSION" ) );
|
|
device->id_uuid = g_strdup( udev_device_get_property_value( device->udevice,
|
|
"ID_FS_UUID" ) );
|
|
|
|
if ( value = udev_device_get_property_value( device->udevice, "ID_FS_LABEL_ENC" ) )
|
|
{
|
|
decoded_string = decode_udev_encoded_string ( value );
|
|
g_strstrip (decoded_string);
|
|
device->id_label = decoded_string;
|
|
}
|
|
else if ( value = udev_device_get_property_value( device->udevice, "ID_FS_LABEL" ) )
|
|
{
|
|
device->id_label = g_strdup( value );
|
|
}
|
|
}
|
|
|
|
// device_is_media_available
|
|
gboolean media_available = FALSE;
|
|
|
|
if ( ( device->id_usage && device->id_usage[0] != '\0' ) ||
|
|
( device->id_type && device->id_type[0] != '\0' ) ||
|
|
( device->id_uuid && device->id_uuid[0] != '\0' ) ||
|
|
( device->id_label && device->id_label[0] != '\0' ) )
|
|
{
|
|
media_available = TRUE;
|
|
}
|
|
else if ( g_str_has_prefix( device->devnode, "/dev/loop" ) )
|
|
media_available = FALSE;
|
|
else if ( device->device_is_removable )
|
|
{
|
|
gboolean is_cd, is_floppy;
|
|
if ( value = udev_device_get_property_value( device->udevice, "ID_CDROM" ) )
|
|
is_cd = atoi( value ) != 0;
|
|
else
|
|
is_cd = FALSE;
|
|
|
|
if ( value = udev_device_get_property_value( device->udevice, "ID_DRIVE_FLOPPY" ) )
|
|
is_floppy = atoi( value ) != 0;
|
|
else
|
|
is_floppy = FALSE;
|
|
|
|
if ( !is_cd && !is_floppy )
|
|
{
|
|
// this test is limited for non-root - user may not have read
|
|
// access to device file even if media is present
|
|
int fd;
|
|
fd = open( device->devnode, O_RDONLY );
|
|
if ( fd >= 0 )
|
|
{
|
|
media_available = TRUE;
|
|
close( fd );
|
|
}
|
|
}
|
|
else if ( value = udev_device_get_property_value( device->udevice, "ID_CDROM_MEDIA" ) )
|
|
media_available = ( atoi( value ) == 1 );
|
|
}
|
|
else if ( value = udev_device_get_property_value( device->udevice, "ID_CDROM_MEDIA" ) )
|
|
media_available = ( atoi( value ) == 1 );
|
|
else
|
|
media_available = TRUE;
|
|
device->device_is_media_available = media_available;
|
|
|
|
/* device_size, device_block_size and device_is_read_only properties */
|
|
if (device->device_is_media_available)
|
|
{
|
|
guint64 block_size;
|
|
|
|
device->device_size = sysfs_get_uint64( device->native_path, "size")
|
|
* ((guint64) 512);
|
|
device->device_is_read_only = (sysfs_get_int (device->native_path,
|
|
"ro") != 0);
|
|
/* This is not available on all devices so fall back to 512 if unavailable.
|
|
*
|
|
* Another way to get this information is the BLKSSZGET ioctl but we don't want
|
|
* to open the device. Ideally vol_id would export it.
|
|
*/
|
|
block_size = sysfs_get_uint64 (device->native_path, "queue/hw_sector_size");
|
|
if (block_size == 0)
|
|
block_size = 512;
|
|
device->device_block_size = block_size;
|
|
}
|
|
else
|
|
{
|
|
device->device_size = device->device_block_size = 0;
|
|
device->device_is_read_only = FALSE;
|
|
}
|
|
|
|
// links
|
|
struct udev_list_entry *entry = udev_device_get_devlinks_list_entry(
|
|
device->udevice );
|
|
while ( entry )
|
|
{
|
|
const char *entry_name = udev_list_entry_get_name( entry );
|
|
if ( entry_name && ( g_str_has_prefix( entry_name, "/dev/disk/by-id/" )
|
|
|| g_str_has_prefix( entry_name, "/dev/disk/by-uuid/" ) ) )
|
|
{
|
|
device->device_by_id = g_strdup( entry_name );
|
|
break;
|
|
}
|
|
entry = udev_list_entry_get_next( entry );
|
|
}
|
|
}
|
|
|
|
gchar* info_mount_points( device_t *device, GList* devmounts )
|
|
{
|
|
gchar *contents;
|
|
gchar **lines;
|
|
GError *error;
|
|
guint n;
|
|
GList* mounts = NULL;
|
|
|
|
if ( !device->major || !device->minor )
|
|
return NULL;
|
|
guint dmajor = atoi( device->major );
|
|
guint dminor = atoi( device->minor );
|
|
|
|
// if we have the mount point list, use this instead of reading mountinfo
|
|
if ( devmounts )
|
|
{
|
|
GList* l;
|
|
for ( l = devmounts; l; l = l->next )
|
|
{
|
|
if ( ((devmount_t*)l->data)->major == dmajor &&
|
|
((devmount_t*)l->data)->minor == dminor )
|
|
{
|
|
return g_strdup( ((devmount_t*)l->data)->mount_points );
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
contents = NULL;
|
|
lines = NULL;
|
|
|
|
error = NULL;
|
|
if (!g_file_get_contents ("/proc/self/mountinfo", &contents, NULL, &error))
|
|
{
|
|
g_warning ("Error reading /proc/self/mountinfo: %s", error->message);
|
|
g_error_free (error);
|
|
return NULL;
|
|
}
|
|
|
|
/* See Documentation/filesystems/proc.txt for the format of /proc/self/mountinfo
|
|
*
|
|
* Note that things like space are encoded as \020.
|
|
*/
|
|
|
|
lines = g_strsplit (contents, "\n", 0);
|
|
for (n = 0; lines[n] != NULL; n++)
|
|
{
|
|
guint mount_id;
|
|
guint parent_id;
|
|
guint major, minor;
|
|
gchar encoded_root[PATH_MAX];
|
|
gchar encoded_mount_point[PATH_MAX];
|
|
gchar *mount_point;
|
|
//dev_t dev;
|
|
|
|
if (strlen (lines[n]) == 0)
|
|
continue;
|
|
|
|
if (sscanf (lines[n],
|
|
"%d %d %d:%d %s %s",
|
|
&mount_id,
|
|
&parent_id,
|
|
&major,
|
|
&minor,
|
|
encoded_root,
|
|
encoded_mount_point) != 6)
|
|
{
|
|
g_warning ("Error reading /proc/self/mountinfo: Error parsing line '%s'", lines[n]);
|
|
continue;
|
|
}
|
|
|
|
/* ignore mounts where only a subtree of a filesystem is mounted */
|
|
if (g_strcmp0 (encoded_root, "/") != 0)
|
|
continue;
|
|
|
|
/* Temporary work-around for btrfs, see
|
|
*
|
|
* https://github.com/IgnorantGuru/spacefm/issues/165
|
|
* http://article.gmane.org/gmane.comp.file-systems.btrfs/2851
|
|
* https://bugzilla.redhat.com/show_bug.cgi?id=495152#c31
|
|
*/
|
|
if ( major == 0 )
|
|
{
|
|
const gchar *sep;
|
|
sep = strstr( lines[n], " - " );
|
|
if ( sep != NULL )
|
|
{
|
|
gchar typebuf[PATH_MAX];
|
|
gchar mount_source[PATH_MAX];
|
|
struct stat statbuf;
|
|
|
|
if ( sscanf( sep + 3, "%s %s", typebuf, mount_source ) == 2 &&
|
|
!g_strcmp0( typebuf, "btrfs" ) &&
|
|
g_str_has_prefix( mount_source, "/dev/" ) &&
|
|
stat( mount_source, &statbuf ) == 0 &&
|
|
S_ISBLK( statbuf.st_mode ) )
|
|
{
|
|
major = major( statbuf.st_rdev );
|
|
minor = minor( statbuf.st_rdev );
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( major != dmajor || minor != dminor )
|
|
continue;
|
|
|
|
mount_point = g_strcompress (encoded_mount_point);
|
|
if ( mount_point && mount_point[0] != '\0' )
|
|
{
|
|
if ( !g_list_find( mounts, mount_point ) )
|
|
{
|
|
mounts = g_list_prepend( mounts, mount_point );
|
|
}
|
|
else
|
|
g_free (mount_point);
|
|
}
|
|
|
|
}
|
|
g_free (contents);
|
|
g_strfreev (lines);
|
|
|
|
if ( mounts )
|
|
{
|
|
gchar *points, *old_points;
|
|
GList* l;
|
|
// Sort the list to ensure that shortest mount paths appear first
|
|
mounts = g_list_sort( mounts, (GCompareFunc) g_strcmp0 );
|
|
points = g_strdup( (gchar*)mounts->data );
|
|
l = mounts;
|
|
while ( l = l->next )
|
|
{
|
|
old_points = points;
|
|
points = g_strdup_printf( "%s, %s", old_points, (gchar*)l->data );
|
|
g_free( old_points );
|
|
}
|
|
g_list_foreach( mounts, (GFunc)g_free, NULL );
|
|
g_list_free( mounts );
|
|
return points;
|
|
}
|
|
else
|
|
return NULL;
|
|
}
|
|
|
|
void info_partition_table( device_t *device )
|
|
{
|
|
gboolean is_partition_table = FALSE;
|
|
const char* value;
|
|
|
|
/* Check if udisks-part-id identified the device as a partition table.. this includes
|
|
* identifying partition tables set up by kpartx for multipath etc.
|
|
*/
|
|
if ( ( value = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_TABLE" ) )
|
|
&& atoi( value ) == 1 )
|
|
{
|
|
device->partition_table_scheme = g_strdup( udev_device_get_property_value(
|
|
device->udevice,
|
|
"UDISKS_PARTITION_TABLE_SCHEME" ) );
|
|
device->partition_table_count = g_strdup( udev_device_get_property_value(
|
|
device->udevice,
|
|
"UDISKS_PARTITION_TABLE_COUNT" ) );
|
|
is_partition_table = TRUE;
|
|
}
|
|
|
|
/* Note that udisks-part-id might not detect all partition table
|
|
* formats.. so in the negative case, also double check with
|
|
* information in sysfs.
|
|
*
|
|
* The kernel guarantees that all childs are created before the
|
|
* uevent for the parent is created. So if we have childs, we must
|
|
* be a partition table.
|
|
*
|
|
* To detect a child we check for the existance of a subdir that has
|
|
* the parents name as a prefix (e.g. for parent sda then sda1,
|
|
* sda2, sda3 ditto md0, md0p1 etc. etc. will work).
|
|
*/
|
|
if (!is_partition_table)
|
|
{
|
|
gchar *s;
|
|
GDir *dir;
|
|
|
|
s = g_path_get_basename (device->native_path);
|
|
if ((dir = g_dir_open (device->native_path, 0, NULL)) != NULL)
|
|
{
|
|
guint partition_count;
|
|
const gchar *name;
|
|
|
|
partition_count = 0;
|
|
while ((name = g_dir_read_name (dir)) != NULL)
|
|
{
|
|
if (g_str_has_prefix (name, s))
|
|
{
|
|
partition_count++;
|
|
}
|
|
}
|
|
g_dir_close (dir);
|
|
|
|
if (partition_count > 0)
|
|
{
|
|
device->partition_table_scheme = g_strdup( "" );
|
|
device->partition_table_count = g_strdup_printf( "%d", partition_count );
|
|
is_partition_table = TRUE;
|
|
}
|
|
}
|
|
g_free (s);
|
|
}
|
|
|
|
device->device_is_partition_table = is_partition_table;
|
|
if (!is_partition_table)
|
|
{
|
|
if ( device->partition_table_scheme )
|
|
g_free( device->partition_table_scheme );
|
|
device->partition_table_scheme = NULL;
|
|
if ( device->partition_table_count )
|
|
g_free( device->partition_table_count );
|
|
device->partition_table_count = NULL;
|
|
}
|
|
}
|
|
|
|
void info_partition( device_t *device )
|
|
{
|
|
gboolean is_partition = FALSE;
|
|
|
|
/* Check if udisks-part-id identified the device as a partition.. this includes
|
|
* identifying partitions set up by kpartx for multipath
|
|
*/
|
|
if ( udev_device_get_property_value( device->udevice,"UDISKS_PARTITION" ) )
|
|
{
|
|
const gchar *size;
|
|
const gchar *scheme;
|
|
const gchar *type;
|
|
const gchar *label;
|
|
const gchar *uuid;
|
|
const gchar *flags;
|
|
const gchar *offset;
|
|
const gchar *alignment_offset;
|
|
const gchar *slave_sysfs_path;
|
|
const gchar *number;
|
|
|
|
scheme = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_SCHEME");
|
|
size = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_SIZE");
|
|
type = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_TYPE");
|
|
label = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_LABEL");
|
|
uuid = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_UUID");
|
|
flags = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_FLAGS");
|
|
offset = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_OFFSET");
|
|
alignment_offset = udev_device_get_property_value( device->udevice,
|
|
"UDISKS_PARTITION_ALIGNMENT_OFFSET");
|
|
number = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_NUMBER");
|
|
slave_sysfs_path = udev_device_get_property_value( device->udevice, "UDISKS_PARTITION_SLAVE");
|
|
|
|
if (slave_sysfs_path != NULL && scheme != NULL && number != NULL && atoi( number ) > 0)
|
|
{
|
|
device->partition_scheme = g_strdup( scheme );
|
|
device->partition_size = g_strdup( size );
|
|
device->partition_type = g_strdup( type );
|
|
device->partition_label = g_strdup( label );
|
|
device->partition_uuid = g_strdup( uuid );
|
|
device->partition_flags = g_strdup( flags );
|
|
device->partition_offset = g_strdup( offset );
|
|
device->partition_alignment_offset = g_strdup( alignment_offset );
|
|
device->partition_number = g_strdup( number );
|
|
is_partition = TRUE;
|
|
}
|
|
}
|
|
|
|
/* Also handle the case where we are partitioned by the kernel and don't have
|
|
* any UDISKS_PARTITION_* properties.
|
|
*
|
|
* This works without any udev UDISKS_PARTITION_* properties and is
|
|
* there for maximum compatibility since udisks-part-id only knows a
|
|
* limited set of partition table formats.
|
|
*/
|
|
if (!is_partition && sysfs_file_exists (device->native_path, "start"))
|
|
{
|
|
guint64 size;
|
|
guint64 offset;
|
|
guint64 alignment_offset;
|
|
gchar *s;
|
|
guint n;
|
|
|
|
size = sysfs_get_uint64 (device->native_path, "size");
|
|
alignment_offset = sysfs_get_uint64 (device->native_path, "alignment_offset");
|
|
|
|
device->partition_size = g_strdup_printf( "%lu", size * 512 );
|
|
device->partition_alignment_offset = g_strdup_printf( "%lu", alignment_offset );
|
|
|
|
offset = sysfs_get_uint64 (device->native_path, "start") * device->device_block_size;
|
|
device->partition_offset = g_strdup_printf( "%lu", offset );
|
|
|
|
s = device->native_path;
|
|
for (n = strlen (s) - 1; n >= 0 && g_ascii_isdigit (s[n]); n--)
|
|
;
|
|
device->partition_number = g_strdup_printf( "%ld", strtol (s + n + 1, NULL, 0) );
|
|
/*
|
|
s = g_strdup (device->priv->native_path);
|
|
for (n = strlen (s) - 1; n >= 0 && s[n] != '/'; n--)
|
|
s[n] = '\0';
|
|
s[n] = '\0';
|
|
device_set_partition_slave (device, compute_object_path (s));
|
|
g_free (s);
|
|
*/
|
|
is_partition = TRUE;
|
|
}
|
|
|
|
device->device_is_partition = is_partition;
|
|
|
|
if (!is_partition)
|
|
{
|
|
device->partition_scheme = NULL;
|
|
device->partition_size = NULL;
|
|
device->partition_type = NULL;
|
|
device->partition_label = NULL;
|
|
device->partition_uuid = NULL;
|
|
device->partition_flags = NULL;
|
|
device->partition_offset = NULL;
|
|
device->partition_alignment_offset = NULL;
|
|
device->partition_number = NULL;
|
|
}
|
|
else
|
|
{
|
|
device->device_is_drive = FALSE;
|
|
}
|
|
}
|
|
|
|
void info_optical_disc( device_t *device )
|
|
{
|
|
const char *cdrom_disc_state;
|
|
|
|
const char* optical_state = udev_device_get_property_value( device->udevice,
|
|
"ID_CDROM");
|
|
if ( optical_state && atoi( optical_state ) != 0 )
|
|
{
|
|
device->device_is_optical_disc = TRUE;
|
|
|
|
device->optical_disc_num_tracks = g_strdup( udev_device_get_property_value(
|
|
device->udevice, "ID_CDROM_MEDIA_TRACK_COUNT") );
|
|
device->optical_disc_num_audio_tracks = g_strdup( udev_device_get_property_value(
|
|
device->udevice, "ID_CDROM_MEDIA_TRACK_COUNT_AUDIO") );
|
|
device->optical_disc_num_sessions = g_strdup( udev_device_get_property_value(
|
|
device->udevice, "ID_CDROM_MEDIA_SESSION_COUNT") );
|
|
|
|
cdrom_disc_state = udev_device_get_property_value( device->udevice, "ID_CDROM_MEDIA_STATE");
|
|
|
|
device->optical_disc_is_blank = ( g_strcmp0( cdrom_disc_state,
|
|
"blank" ) == 0);
|
|
device->optical_disc_is_appendable = ( g_strcmp0( cdrom_disc_state,
|
|
"appendable" ) == 0);
|
|
device->optical_disc_is_closed = ( g_strcmp0( cdrom_disc_state,
|
|
"complete" ) == 0);
|
|
}
|
|
else
|
|
device->device_is_optical_disc = FALSE;
|
|
}
|
|
|
|
void device_free( device_t *device )
|
|
{
|
|
if ( !device )
|
|
return;
|
|
|
|
g_free( device->native_path );
|
|
g_free( device->major );
|
|
g_free( device->minor );
|
|
g_free( device->mount_points );
|
|
g_free( device->devnode );
|
|
|
|
g_free( device->device_presentation_hide );
|
|
g_free( device->device_presentation_nopolicy );
|
|
g_free( device->device_presentation_name );
|
|
g_free( device->device_presentation_icon_name );
|
|
g_free( device->device_automount_hint );
|
|
g_free( device->device_by_id );
|
|
g_free( device->id_usage );
|
|
g_free( device->id_type );
|
|
g_free( device->id_version );
|
|
g_free( device->id_uuid );
|
|
g_free( device->id_label );
|
|
|
|
g_free( device->drive_vendor );
|
|
g_free( device->drive_model );
|
|
g_free( device->drive_revision );
|
|
g_free( device->drive_serial );
|
|
g_free( device->drive_wwn );
|
|
g_free( device->drive_connection_interface );
|
|
g_free( device->drive_media_compatibility );
|
|
g_free( device->drive_media );
|
|
|
|
g_free( device->partition_scheme );
|
|
g_free( device->partition_number );
|
|
g_free( device->partition_type );
|
|
g_free( device->partition_label );
|
|
g_free( device->partition_uuid );
|
|
g_free( device->partition_flags );
|
|
g_free( device->partition_offset );
|
|
g_free( device->partition_size );
|
|
g_free( device->partition_alignment_offset );
|
|
|
|
g_free( device->partition_table_scheme );
|
|
g_free( device->partition_table_count );
|
|
|
|
g_free( device->optical_disc_num_tracks );
|
|
g_free( device->optical_disc_num_audio_tracks );
|
|
g_free( device->optical_disc_num_sessions );
|
|
g_slice_free( device_t, device );
|
|
}
|
|
|
|
device_t *device_alloc( struct udev_device *udevice )
|
|
{
|
|
device_t *device = g_slice_new0( device_t );
|
|
device->udevice = udevice;
|
|
|
|
device->native_path = NULL;
|
|
device->major = NULL;
|
|
device->minor = NULL;
|
|
device->mount_points = NULL;
|
|
device->devnode = NULL;
|
|
|
|
device->device_is_system_internal = TRUE;
|
|
device->device_is_partition = FALSE;
|
|
device->device_is_partition_table = FALSE;
|
|
device->device_is_removable = FALSE;
|
|
device->device_is_media_available = FALSE;
|
|
device->device_is_read_only = FALSE;
|
|
device->device_is_drive = FALSE;
|
|
device->device_is_optical_disc = FALSE;
|
|
device->device_is_mounted = FALSE;
|
|
device->device_presentation_hide = NULL;
|
|
device->device_presentation_nopolicy = NULL;
|
|
device->device_presentation_name = NULL;
|
|
device->device_presentation_icon_name = NULL;
|
|
device->device_automount_hint = NULL;
|
|
device->device_by_id = NULL;
|
|
device->device_size = 0;
|
|
device->device_block_size = 0;
|
|
device->id_usage = NULL;
|
|
device->id_type = NULL;
|
|
device->id_version = NULL;
|
|
device->id_uuid = NULL;
|
|
device->id_label = NULL;
|
|
|
|
device->drive_vendor = NULL;
|
|
device->drive_model = NULL;
|
|
device->drive_revision = NULL;
|
|
device->drive_serial = NULL;
|
|
device->drive_wwn = NULL;
|
|
device->drive_connection_interface = NULL;
|
|
device->drive_connection_speed = 0;
|
|
device->drive_media_compatibility = NULL;
|
|
device->drive_media = NULL;
|
|
device->drive_is_media_ejectable = FALSE;
|
|
device->drive_can_detach = FALSE;
|
|
|
|
device->partition_scheme = NULL;
|
|
device->partition_number = NULL;
|
|
device->partition_type = NULL;
|
|
device->partition_label = NULL;
|
|
device->partition_uuid = NULL;
|
|
device->partition_flags = NULL;
|
|
device->partition_offset = NULL;
|
|
device->partition_size = NULL;
|
|
device->partition_alignment_offset = NULL;
|
|
|
|
device->partition_table_scheme = NULL;
|
|
device->partition_table_count = NULL;
|
|
|
|
device->optical_disc_is_blank = FALSE;
|
|
device->optical_disc_is_appendable = FALSE;
|
|
device->optical_disc_is_closed = FALSE;
|
|
device->optical_disc_num_tracks = NULL;
|
|
device->optical_disc_num_audio_tracks = NULL;
|
|
device->optical_disc_num_sessions = NULL;
|
|
|
|
return device;
|
|
}
|
|
|
|
gboolean device_get_info( device_t *device, GList* devmounts )
|
|
{
|
|
info_device_properties( device );
|
|
if ( !device->native_path )
|
|
return FALSE;
|
|
info_drive_properties( device );
|
|
device->device_is_system_internal = info_is_system_internal( device );
|
|
device->mount_points = info_mount_points( device, devmounts );
|
|
device->device_is_mounted = ( device->mount_points != NULL );
|
|
info_partition_table( device );
|
|
info_partition( device );
|
|
info_optical_disc( device );
|
|
return TRUE;
|
|
}
|
|
|
|
char* device_show_info( device_t *device )
|
|
{ // no translate
|
|
gchar* line[140];
|
|
int i = 0;
|
|
|
|
//line[i++] = g_strdup_printf("Showing information for %s\n", device->devnode );
|
|
char* bdev = g_path_get_basename( device->devnode );
|
|
line[i++] = g_strdup_printf("Showing information for /org/freedesktop/UDisks/devices/%s\n", bdev );
|
|
g_free( bdev );
|
|
line[i++] = g_strdup_printf(" native-path: %s\n", device->native_path );
|
|
line[i++] = g_strdup_printf(" device: %s:%s\n", device->major, device->minor );
|
|
line[i++] = g_strdup_printf(" device-file: %s\n", device->devnode );
|
|
line[i++] = g_strdup_printf(" presentation: %s\n", device->devnode );
|
|
if ( device->device_by_id )
|
|
line[i++] = g_strdup_printf(" by-id: %s\n", device->device_by_id );
|
|
line[i++] = g_strdup_printf(" system internal: %d\n", device->device_is_system_internal );
|
|
line[i++] = g_strdup_printf(" removable: %d\n", device->device_is_removable);
|
|
line[i++] = g_strdup_printf(" has media: %d\n", device->device_is_media_available);
|
|
line[i++] = g_strdup_printf(" is read only: %d\n", device->device_is_read_only );
|
|
line[i++] = g_strdup_printf(" is mounted: %d\n", device->device_is_mounted );
|
|
line[i++] = g_strdup_printf(" mount paths: %s\n", device->mount_points ? device->mount_points : "" );
|
|
line[i++] = g_strdup_printf(" presentation hide: %s\n", device->device_presentation_hide ?
|
|
device->device_presentation_hide : "0" );
|
|
line[i++] = g_strdup_printf(" presentation nopolicy: %s\n", device->device_presentation_nopolicy ?
|
|
device->device_presentation_nopolicy : "0" );
|
|
line[i++] = g_strdup_printf(" presentation name: %s\n", device->device_presentation_name ?
|
|
device->device_presentation_name : "" );
|
|
line[i++] = g_strdup_printf(" presentation icon: %s\n", device->device_presentation_icon_name ?
|
|
device->device_presentation_icon_name : "" );
|
|
line[i++] = g_strdup_printf(" automount hint: %s\n", device->device_automount_hint ?
|
|
device->device_automount_hint : "" );
|
|
line[i++] = g_strdup_printf(" size: %" G_GUINT64_FORMAT "\n", device->device_size);
|
|
line[i++] = g_strdup_printf(" block size: %" G_GUINT64_FORMAT "\n", device->device_block_size);
|
|
line[i++] = g_strdup_printf(" usage: %s\n", device->id_usage ? device->id_usage : "" );
|
|
line[i++] = g_strdup_printf(" type: %s\n", device->id_type ? device->id_type : "" );
|
|
line[i++] = g_strdup_printf(" version: %s\n", device->id_version ? device->id_version : "" );
|
|
line[i++] = g_strdup_printf(" uuid: %s\n", device->id_uuid ? device->id_uuid : "" );
|
|
line[i++] = g_strdup_printf(" label: %s\n", device->id_label ? device->id_label : "" );
|
|
if (device->device_is_partition_table)
|
|
{
|
|
line[i++] = g_strdup_printf(" partition table:\n");
|
|
line[i++] = g_strdup_printf(" scheme: %s\n", device->partition_table_scheme ?
|
|
device->partition_table_scheme : "" );
|
|
line[i++] = g_strdup_printf(" count: %s\n", device->partition_table_count ?
|
|
device->partition_table_count : "0" );
|
|
}
|
|
if (device->device_is_partition)
|
|
{
|
|
line[i++] = g_strdup_printf(" partition:\n");
|
|
line[i++] = g_strdup_printf(" scheme: %s\n", device->partition_scheme ?
|
|
device->partition_scheme : "" );
|
|
line[i++] = g_strdup_printf(" number: %s\n", device->partition_number ?
|
|
device->partition_number : "" );
|
|
line[i++] = g_strdup_printf(" type: %s\n", device->partition_type ?
|
|
device->partition_type : "" );
|
|
line[i++] = g_strdup_printf(" flags: %s\n", device->partition_flags ?
|
|
device->partition_flags : "" );
|
|
line[i++] = g_strdup_printf(" offset: %s\n", device->partition_offset ?
|
|
device->partition_offset : "" );
|
|
line[i++] = g_strdup_printf(" alignment offset: %s\n", device->partition_alignment_offset ?
|
|
device->partition_alignment_offset : "" );
|
|
line[i++] = g_strdup_printf(" size: %s\n", device->partition_size ?
|
|
device->partition_size : "" );
|
|
line[i++] = g_strdup_printf(" label: %s\n", device->partition_label ?
|
|
device->partition_label : "" );
|
|
line[i++] = g_strdup_printf(" uuid: %s\n", device->partition_uuid ?
|
|
device->partition_uuid : "" );
|
|
}
|
|
if (device->device_is_optical_disc)
|
|
{
|
|
line[i++] = g_strdup_printf(" optical disc:\n");
|
|
line[i++] = g_strdup_printf(" blank: %d\n", device->optical_disc_is_blank);
|
|
line[i++] = g_strdup_printf(" appendable: %d\n", device->optical_disc_is_appendable);
|
|
line[i++] = g_strdup_printf(" closed: %d\n", device->optical_disc_is_closed);
|
|
line[i++] = g_strdup_printf(" num tracks: %s\n", device->optical_disc_num_tracks ?
|
|
device->optical_disc_num_tracks : "0" );
|
|
line[i++] = g_strdup_printf(" num audio tracks: %s\n", device->optical_disc_num_audio_tracks ?
|
|
device->optical_disc_num_audio_tracks : "0" );
|
|
line[i++] = g_strdup_printf(" num sessions: %s\n", device->optical_disc_num_sessions ?
|
|
device->optical_disc_num_sessions : "0" );
|
|
}
|
|
if (device->device_is_drive)
|
|
{
|
|
line[i++] = g_strdup_printf(" drive:\n");
|
|
line[i++] = g_strdup_printf(" vendor: %s\n", device->drive_vendor ?
|
|
device->drive_vendor : "" );
|
|
line[i++] = g_strdup_printf(" model: %s\n", device->drive_model ?
|
|
device->drive_model : "" );
|
|
line[i++] = g_strdup_printf(" revision: %s\n", device->drive_revision ?
|
|
device->drive_revision : "" );
|
|
line[i++] = g_strdup_printf(" serial: %s\n", device->drive_serial ?
|
|
device->drive_serial : "" );
|
|
line[i++] = g_strdup_printf(" WWN: %s\n", device->drive_wwn ?
|
|
device->drive_wwn : "" );
|
|
line[i++] = g_strdup_printf(" detachable: %d\n", device->drive_can_detach);
|
|
line[i++] = g_strdup_printf(" ejectable: %d\n", device->drive_is_media_ejectable);
|
|
line[i++] = g_strdup_printf(" media: %s\n", device->drive_media ?
|
|
device->drive_media : "" );
|
|
line[i++] = g_strdup_printf(" compat: %s\n", device->drive_media_compatibility ?
|
|
device->drive_media_compatibility : "" );
|
|
if ( device->drive_connection_interface == NULL ||
|
|
strlen (device->drive_connection_interface) == 0 )
|
|
line[i++] = g_strdup_printf(" interface: (unknown)\n");
|
|
else
|
|
line[i++] = g_strdup_printf(" interface: %s\n", device->drive_connection_interface);
|
|
if (device->drive_connection_speed == 0)
|
|
line[i++] = g_strdup_printf(" if speed: (unknown)\n");
|
|
else
|
|
line[i++] = g_strdup_printf(" if speed: %" G_GINT64_FORMAT " bits/s\n",
|
|
device->drive_connection_speed);
|
|
}
|
|
line[i] = NULL;
|
|
gchar* output = g_strjoinv( NULL, line );
|
|
i = 0;
|
|
while ( line[i] )
|
|
g_free( line[i++] );
|
|
return output;
|
|
}
|
|
|