| File: | plugins/udisks2/udisks2-plugin.c |
| Warning: | line 300, column 82 Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* |
| 2 | * Copyright (C) 2017 info-cppsp <info@cppsp.de> |
| 3 | * Copyright (C) 2005-2009 Alex Murray <murray.alex@gmail.com> |
| 4 | * |
| 5 | * This program is free software; you can redistribute it and/or modify |
| 6 | * it under the terms of the GNU General Public License as published by |
| 7 | * the Free Software Foundation; either version 2 of the License, or |
| 8 | * (at your option) any later version. |
| 9 | * |
| 10 | * This program is distributed in the hope that it will be useful, |
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 13 | * GNU General Public License for more details. |
| 14 | * |
| 15 | * You should have received a copy of the GNU General Public License |
| 16 | * along with this program; if not, write to the Free Software |
| 17 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| 18 | */ |
| 19 | |
| 20 | /* |
| 21 | Udisks2 plugin for the cafe-sensors-applet |
| 22 | |
| 23 | written using the structure and code of the previous version |
| 24 | from Pramod Dematagoda <pmd.lotr.gandalf@gmail.com> |
| 25 | |
| 26 | dbus-glib documentation |
| 27 | https://dbus.freedesktop.org/doc/dbus-glib/ |
| 28 | GDBUS documentation |
| 29 | https://developer.gnome.org/gio/stable/index.html |
| 30 | |
| 31 | */ |
| 32 | |
| 33 | |
| 34 | #ifdef HAVE_CONFIG_H1 |
| 35 | #include "config.h" |
| 36 | #endif /* HAVE_CONFIG_H */ |
| 37 | |
| 38 | #include <stdio.h> |
| 39 | #include <gio/gio.h> |
| 40 | #include "udisks2-plugin.h" |
| 41 | |
| 42 | |
| 43 | /* remove // from next line for syslog debug */ |
| 44 | //#define UD2PD 1 |
| 45 | |
| 46 | #ifdef UD2PD |
| 47 | #include <syslog.h> |
| 48 | #endif |
| 49 | |
| 50 | |
| 51 | #define UDISKS2_BUS_NAME"org.freedesktop.UDisks2" "org.freedesktop.UDisks2" |
| 52 | #define UDISKS2_INTERFACE_NAME"org.freedesktop.DBus.ObjectManager" "org.freedesktop.DBus.ObjectManager" |
| 53 | #define UDISKS2_DEVICE_INTERFACE_NAME"org.freedesktop.UDisks2.Drive" "org.freedesktop.UDisks2.Drive" |
| 54 | #define UDISKS2_DEVICE_INTERFACE2_NAME"org.freedesktop.UDisks2.Drive.Ata" "org.freedesktop.UDisks2.Drive.Ata" |
| 55 | |
| 56 | #define UDISKS2_PROPERTIES_INTERFACE"org.freedesktop.DBus.Properties" "org.freedesktop.DBus.Properties" |
| 57 | #define UDISKS2_OBJECT_PATH"/org/freedesktop/UDisks2" "/org/freedesktop/UDisks2" |
| 58 | |
| 59 | |
| 60 | /* Info about a single sensor */ |
| 61 | typedef struct _DevInfo { |
| 62 | gchar *path; |
| 63 | gchar *id; |
| 64 | gdouble temp; |
| 65 | GDBusProxy *sensor_proxy; /* dbus object */ |
| 66 | GError *error; |
| 67 | } DevInfo; |
| 68 | |
| 69 | |
| 70 | const gchar *plugin_name = "udisks2"; |
| 71 | |
| 72 | /* a container for the devices found to have smart enabled */ |
| 73 | GHashTable *devices = NULL((void*)0); |
| 74 | |
| 75 | /* This is a global variable for convenience */ |
| 76 | GDBusConnection *connection = NULL((void*)0); |
| 77 | |
| 78 | |
| 79 | static void update_device (DevInfo *info) { |
| 80 | GError *error = NULL((void*)0); |
| 81 | GVariant *tempgvar = NULL((void*)0); |
| 82 | GVariant *tempgvar2 = NULL((void*)0); |
| 83 | gdouble temp; |
| 84 | |
| 85 | /* check valid input parameter */ |
| 86 | g_return_if_fail (info != NULL)do { if ((info != ((void*)0))) { } else { g_return_if_fail_warning ("sensors-applet", ((const char*) (__func__)), "info != NULL" ); return; } } while (0); |
| 87 | |
| 88 | /* check connection too */ |
| 89 | g_return_if_fail (connection != NULL)do { if ((connection != ((void*)0))) { } else { g_return_if_fail_warning ("sensors-applet", ((const char*) (__func__)), "connection != NULL" ); return; } } while (0); |
| 90 | |
| 91 | g_clear_error (&info->error); |
| 92 | |
| 93 | /* check for sensor_proxy, which should exist at this point, make one if necessary and save it into DevInfo |
| 94 | * this is used to get the temp value the direct way */ |
| 95 | if (NULL((void*)0) == info->sensor_proxy) { |
| 96 | info->sensor_proxy = g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL((void*)0), |
| 97 | UDISKS2_BUS_NAME"org.freedesktop.UDisks2", |
| 98 | info->path, |
| 99 | UDISKS2_PROPERTIES_INTERFACE"org.freedesktop.DBus.Properties", |
| 100 | NULL((void*)0), &error); |
| 101 | |
| 102 | /* check, just to be sure */ |
| 103 | if (NULL((void*)0) == info->sensor_proxy) { |
| 104 | |
| 105 | #ifdef UD2PD |
| 106 | syslog(LOG_ERR, "Failed to get drive temperature 1"); |
| 107 | #endif |
| 108 | g_debug ("Failed to get drive temperature 1: %s", error->message); |
| 109 | g_clear_error (&error); |
| 110 | return; |
| 111 | } |
| 112 | } |
| 113 | |
| 114 | /* note on timing: |
| 115 | * it seems to me that smart updates occur automatically every 10 minutes |
| 116 | * cafe-sensor-applet has a default refresh of 2 seconds... |
| 117 | * it is possible to force a smart update with udisks2: SmartUpdate (IN a{sv} options); */ |
| 118 | |
| 119 | /* directly asking the device's DBus object for the temp */ |
| 120 | tempgvar = g_dbus_proxy_call_sync (info->sensor_proxy, "Get", |
| 121 | g_variant_new ("(ss)", |
| 122 | UDISKS2_DEVICE_INTERFACE2_NAME"org.freedesktop.UDisks2.Drive.Ata", |
| 123 | "SmartTemperature"), /* parameters */ |
| 124 | G_DBUS_CALL_FLAGS_NONE, /* flags */ |
| 125 | -1, /* timeout */ |
| 126 | NULL((void*)0), /* cancellable */ |
| 127 | &error); |
| 128 | |
| 129 | if (NULL((void*)0) == tempgvar) { |
| 130 | |
| 131 | #ifdef UD2PD |
| 132 | syslog(LOG_ERR, "Failed to get drive temperature 2"); |
| 133 | #endif |
| 134 | g_debug ("Failed to get drive temperature 2: %s", error->message); |
| 135 | g_clear_error (&error); |
| 136 | /* throw away proxy, maybe next time it will be better */ |
| 137 | g_clear_object (&info->sensor_proxy)do { _Static_assert (sizeof *((&info->sensor_proxy)) == sizeof (gpointer), "Expression evaluates to false"); __typeof__ (((&info->sensor_proxy))) _pp = ((&info->sensor_proxy )); __typeof__ (*((&info->sensor_proxy))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (0); |
| 138 | return; |
| 139 | |
| 140 | } else { |
| 141 | |
| 142 | #ifdef UD2PD |
| 143 | syslog(LOG_ERR, "tempgvar value: %s", g_variant_print(tempgvar, TRUE(!(0)))); |
| 144 | /* leaks memory! */ |
| 145 | //syslog(LOG_ERR, "tempgvar value: %s", g_variant_print(g_variant_get_variant(g_variant_get_child_value(tempgvar, 0)), TRUE)); |
| 146 | #endif |
| 147 | |
| 148 | /* tempgvar comes back as something along the lines of array(gvariant(tempasdouble)) |
| 149 | * hence unpacking |
| 150 | * need to free up every param / return value, so can't do it like: |
| 151 | * temp = g_variant_get_double(g_variant_get_variant(g_variant_get_child_value(tempgvar, 0))); */ |
| 152 | tempgvar2 = g_variant_get_child_value (tempgvar, 0); |
| 153 | g_variant_unref (tempgvar); |
| 154 | tempgvar = g_variant_get_variant (tempgvar2); |
| 155 | g_variant_unref (tempgvar2); |
| 156 | temp = g_variant_get_double (tempgvar); |
| 157 | g_variant_unref (tempgvar); |
| 158 | |
| 159 | /* temp in K */ |
| 160 | info->temp = temp - 273.15; |
| 161 | |
| 162 | #ifdef UD2PD |
| 163 | syslog(LOG_ERR, "Refresh udisks2 device temp: '%f'\n", info->temp); |
| 164 | #endif |
| 165 | |
| 166 | } |
| 167 | |
| 168 | } |
| 169 | |
| 170 | /* in this function we would like to get a list of device (hdd/ssd) paths |
| 171 | * then with each path we get the temperature |
| 172 | * it is possible with udisks2 to get all the above information in one g_dbus_proxy_call_sync(), so that is how I did it |
| 173 | * maybe a better version would be to use GDBusObjectManager Server + Client ?? */ |
| 174 | static void udisks2_plugin_get_sensors (GList **sensors) { |
| 175 | |
| 176 | #ifdef UD2PD |
| 177 | syslog(LOG_ERR, "fstart"); |
| 178 | #endif |
| 179 | |
| 180 | GDBusProxy *proxy = NULL((void*)0); |
| 181 | GError *error = NULL((void*)0); |
| 182 | |
| 183 | DevInfo *info; |
| 184 | |
| 185 | /* This connection will be used for everything, including the obtaining of sensor data */ |
| 186 | connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL((void*)0), &error); |
| 187 | if (NULL((void*)0) == connection) { |
| 188 | |
| 189 | #ifdef UD2PD |
| 190 | syslog(LOG_ERR, "dbus conn fail"); |
| 191 | #endif |
| 192 | |
| 193 | g_debug ("Failed to open connection to DBUS: %s", error->message); |
| 194 | g_clear_error (&error); |
| 195 | return; |
| 196 | } |
| 197 | |
| 198 | #ifdef UD2PD |
| 199 | syslog(LOG_ERR, "dbus conn success"); |
| 200 | #endif |
| 201 | |
| 202 | /* I use this proxy to get all info of all devices at once */ |
| 203 | proxy = g_dbus_proxy_new_sync (connection, G_DBUS_PROXY_FLAGS_NONE, NULL((void*)0), |
| 204 | UDISKS2_BUS_NAME"org.freedesktop.UDisks2", |
| 205 | UDISKS2_OBJECT_PATH"/org/freedesktop/UDisks2", |
| 206 | UDISKS2_INTERFACE_NAME"org.freedesktop.DBus.ObjectManager", |
| 207 | NULL((void*)0), &error); |
| 208 | |
| 209 | if (NULL((void*)0) == proxy) { |
| 210 | |
| 211 | #ifdef UD2PD |
| 212 | syslog(LOG_ERR, "dbus conn proxy fail"); |
| 213 | #endif |
| 214 | g_debug ("dbus conn proxy fail: %s", error->message); |
| 215 | g_clear_error (&error); |
| 216 | g_clear_object (&connection)do { _Static_assert (sizeof *((&connection)) == sizeof (gpointer ), "Expression evaluates to false"); __typeof__ (((&connection ))) _pp = ((&connection)); __typeof__ (*((&connection ))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref ) (_ptr); } while (0); |
| 217 | return; |
| 218 | } |
| 219 | |
| 220 | #ifdef UD2PD |
| 221 | syslog(LOG_ERR, "dbus conn proxy success"); |
| 222 | #endif |
| 223 | |
| 224 | /* The object paths of the disks are enumerated and placed in an array of object paths |
| 225 | * "GetManagedObjects" returns dict of (objectpath, (dict of (string [ie. if. name], dict of(string [ie. property name], variant [ie. prop. value])))) */ |
| 226 | |
| 227 | /* g_dbus_proxy_call_sync() returns NULL on error, GVariant * otherwise |
| 228 | * need second variable to prevent memory leak */ |
| 229 | GVariant *managed_objects = NULL((void*)0); |
| 230 | GVariant *managed_objects2 = NULL((void*)0); |
| 231 | |
| 232 | managed_objects2 = g_dbus_proxy_call_sync (proxy, "GetManagedObjects", |
| 233 | NULL((void*)0), /* parameters */ |
| 234 | G_DBUS_CALL_FLAGS_NONE, /* flags */ |
| 235 | -1, /* timeout */ |
| 236 | NULL((void*)0), /* cancellable */ |
| 237 | &error); |
| 238 | |
| 239 | if (NULL((void*)0) == managed_objects2) { |
| 240 | |
| 241 | #ifdef UD2PD |
| 242 | syslog(LOG_ERR, "Failed to enumerate disk devices"); |
| 243 | #endif |
| 244 | |
| 245 | g_debug ("Failed to enumerate disk devices: %s", error->message); |
| 246 | g_clear_error (&error); |
| 247 | g_clear_object (&proxy)do { _Static_assert (sizeof *((&proxy)) == sizeof (gpointer ), "Expression evaluates to false"); __typeof__ (((&proxy ))) _pp = ((&proxy)); __typeof__ (*((&proxy))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (0); |
| 248 | g_clear_object (&connection)do { _Static_assert (sizeof *((&connection)) == sizeof (gpointer ), "Expression evaluates to false"); __typeof__ (((&connection ))) _pp = ((&connection)); __typeof__ (*((&connection ))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref ) (_ptr); } while (0); |
| 249 | return; |
| 250 | } |
| 251 | |
| 252 | /* the result dictionary is enclosed in an array, unpack */ |
| 253 | managed_objects = g_variant_get_child_value (managed_objects2, 0); |
| 254 | g_variant_unref (managed_objects2); |
| 255 | |
| 256 | #ifdef UD2PD |
| 257 | //syslog(LOG_ERR, "managed_objects type: %s", g_variant_print(managed_objects, TRUE)); |
| 258 | syslog(LOG_ERR, "success to enumerate disk devices"); |
| 259 | #endif |
| 260 | |
| 261 | /* iterator for the result dictionary |
| 262 | * iterator code is based on the g_variant_iter_next() documentation |
| 263 | * iter is freed if the GVariant is, when using g_variant_iter_init() */ |
| 264 | GVariantIter iter; |
| 265 | gchar *key = NULL((void*)0); /* object path (like '/org/freedesktop/UDisks2/drives/Samsung_SSD_840_EVO_250GB_*insert drive serial nr.*') */ |
| 266 | GVariant *value = NULL((void*)0); |
| 267 | |
| 268 | #ifdef UD2PD |
| 269 | /* log collection size */ |
| 270 | syslog(LOG_ERR, "iter init count: %d", (int) g_variant_iter_init (&iter, managed_objects)); |
| 271 | #else |
| 272 | g_variant_iter_init (&iter, managed_objects); |
| 273 | #endif |
| 274 | |
| 275 | /* "{sv}" is a GVariant format string |
| 276 | * {} dictionary of, s string, v GVariant |
| 277 | * changed to "{oa{sa{sv}}}" on error message 'the GVariant format string '{sv}' has a type of '{sv}' but the given value has a type of 'a{oa{sa{sv}}}'' |
| 278 | * a is array, o is object path |
| 279 | * NOO!! the right format string is "{o@*}", which means get an object path into the 1st variable (key) |
| 280 | * and get 'everything else' (as a GVariant) into the 2nd variable (value) |
| 281 | * needs the & before the key and value params! */ |
| 282 | while (g_variant_iter_next (&iter, "{o@*}", &key, &value)) { |
| 283 | |
| 284 | #ifdef UD2PD |
| 285 | syslog(LOG_ERR, "in iter while loop"); |
| 286 | syslog(LOG_ERR, "key value: %s", key); |
| 287 | //syslog(LOG_ERR, "value type: %s", g_variant_print(value, TRUE)); |
| 288 | #endif |
| 289 | |
| 290 | /* level 2 |
| 291 | * create a dictionary of value |
| 292 | * the two interface names that we are searching for are known and defined |
| 293 | * can't use GVariantDict, it only supports '{sv}' but the given value has a type of '{sa{sv}}' |
| 294 | * using general lookup */ |
| 295 | |
| 296 | GVariant *propdict = NULL((void*)0); /* drive data */ |
| 297 | GVariant *propdict2 = NULL((void*)0); /* drive smart data */ |
| 298 | |
| 299 | /* make two dictionaries that contain the properties of the drive interfaces */ |
| 300 | propdict = g_variant_lookup_value (value, UDISKS2_DEVICE_INTERFACE_NAME"org.freedesktop.UDisks2.Drive", G_VARIANT_TYPE_DICTIONARY((const GVariantType *) "a{?*}")); |
Casting a non-structure type to a structure type and accessing a field can lead to memory access errors or data corruption | |
| 301 | propdict2 = g_variant_lookup_value (value, UDISKS2_DEVICE_INTERFACE2_NAME"org.freedesktop.UDisks2.Drive.Ata", G_VARIANT_TYPE_DICTIONARY((const GVariantType *) "a{?*}")); |
| 302 | |
| 303 | |
| 304 | /* do we have the right ifname keys? */ |
| 305 | if ((NULL((void*)0) != propdict) && (NULL((void*)0) != propdict2)) { |
| 306 | |
| 307 | #ifdef UD2PD |
| 308 | syslog(LOG_ERR, "propdict type: %s", g_variant_print(propdict, TRUE(!(0)))); |
| 309 | syslog(LOG_ERR, "propdict2 type: %s", g_variant_print(propdict2, TRUE(!(0)))); |
| 310 | #endif |
| 311 | |
| 312 | /* get data */ |
| 313 | const gchar *id = NULL((void*)0); |
| 314 | const gchar *model = NULL((void*)0); |
| 315 | |
| 316 | gboolean smartenabled; |
| 317 | gdouble temp; |
| 318 | |
| 319 | /* NULL, bc we don't care about the length of the string*/ |
| 320 | id = g_variant_get_string (g_variant_lookup_value (propdict, "Id", G_VARIANT_TYPE_STRING((const GVariantType *) "s")), NULL((void*)0)); |
| 321 | model = g_variant_get_string (g_variant_lookup_value (propdict, "Model", G_VARIANT_TYPE_STRING((const GVariantType *) "s")), NULL((void*)0)); |
| 322 | |
| 323 | smartenabled = g_variant_get_boolean (g_variant_lookup_value (propdict2, "SmartEnabled", G_VARIANT_TYPE_BOOLEAN((const GVariantType *) "b"))); |
| 324 | temp = g_variant_get_double (g_variant_lookup_value (propdict2, "SmartTemperature", G_VARIANT_TYPE_DOUBLE((const GVariantType *) "d"))); |
| 325 | |
| 326 | #ifdef UD2PD |
| 327 | syslog(LOG_ERR, "Found udisks2 device id: '%s'\n", id); |
| 328 | syslog(LOG_ERR, "Found udisks2 device model: '%s'\n", model); |
| 329 | syslog(LOG_ERR, "Found udisks2 device smartenabled: '%d'\n", smartenabled); |
| 330 | syslog(LOG_ERR, "Found udisks2 device temp: '%f'\n", temp); |
| 331 | #endif |
| 332 | |
| 333 | /* only go on if smart is enabled |
| 334 | * save data */ |
| 335 | if (smartenabled) { |
| 336 | |
| 337 | info = g_new0 (DevInfo, 1)((DevInfo *) g_malloc0_n ((1), sizeof (DevInfo))); |
| 338 | if (NULL((void*)0) == devices) { |
| 339 | devices = g_hash_table_new (g_str_hash, g_str_equal); |
| 340 | } |
| 341 | |
| 342 | info->id = g_strdup (id)g_strdup_inline (id); |
| 343 | info->path = g_strdup (key)g_strdup_inline (key); |
| 344 | |
| 345 | /* temp in K |
| 346 | * this could be left at 0.0, 2 seconds later it will be refreshed anyway */ |
| 347 | info->temp = (gdouble) temp - 273.15; |
| 348 | g_hash_table_insert (devices, info->id, info); |
| 349 | |
| 350 | /* Write the sensor data */ |
| 351 | sensors_applet_plugin_add_sensor (sensors, |
| 352 | id, |
| 353 | "Disk Temperature", |
| 354 | model, |
| 355 | TEMP_SENSOR, |
| 356 | FALSE(0), |
| 357 | HDD_ICON, |
| 358 | DEFAULT_GRAPH_COLOR"#ff0000"); |
| 359 | |
| 360 | g_debug ("Added %s", id); |
| 361 | |
| 362 | #ifdef UD2PD |
| 363 | syslog(LOG_ERR, "Added %s", id); |
| 364 | #endif |
| 365 | |
| 366 | } else { |
| 367 | |
| 368 | #ifdef UD2PD |
| 369 | syslog(LOG_ERR, "No temp data for device: %s\n", key); |
| 370 | #endif |
| 371 | |
| 372 | g_debug ("No temp data for device: %s\n", key); |
| 373 | } |
| 374 | } |
| 375 | |
| 376 | #ifdef UD2PD |
| 377 | syslog(LOG_ERR, "b4 free2"); |
| 378 | #endif |
| 379 | |
| 380 | /* free propdict, propdict2 |
| 381 | * g_variant_dict_unref() may not work a few times, gives error |
| 382 | * this one seems to do fine */ |
| 383 | if (NULL((void*)0) != propdict) {g_variant_unref (propdict);} |
| 384 | if (NULL((void*)0) != propdict2) {g_variant_unref (propdict2);} |
| 385 | |
| 386 | #ifdef UD2PD |
| 387 | syslog(LOG_ERR, "b4 free3"); |
| 388 | #endif |
| 389 | |
| 390 | g_free (key); |
| 391 | g_variant_unref (value); |
| 392 | |
| 393 | } /* end of while loop */ |
| 394 | |
| 395 | |
| 396 | g_variant_unref (managed_objects); |
| 397 | g_clear_object (&proxy)do { _Static_assert (sizeof *((&proxy)) == sizeof (gpointer ), "Expression evaluates to false"); __typeof__ (((&proxy ))) _pp = ((&proxy)); __typeof__ (*((&proxy))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref) (_ptr); } while (0); |
| 398 | if (NULL((void*)0) == devices) { |
| 399 | g_clear_object (&connection)do { _Static_assert (sizeof *((&connection)) == sizeof (gpointer ), "Expression evaluates to false"); __typeof__ (((&connection ))) _pp = ((&connection)); __typeof__ (*((&connection ))) _ptr = *_pp; *_pp = ((void*)0); if (_ptr) (g_object_unref ) (_ptr); } while (0); |
| 400 | } |
| 401 | } |
| 402 | |
| 403 | /* this function is called every refresh cycle */ |
| 404 | static gdouble udisks2_plugin_get_sensor_value (const gchar *path, |
| 405 | const gchar *id, |
| 406 | SensorType type, |
| 407 | GError **error) { |
| 408 | DevInfo *info = NULL((void*)0); |
| 409 | |
| 410 | /* get device stuct from data store */ |
| 411 | info = (DevInfo *) g_hash_table_lookup (devices, path); |
| 412 | if (NULL((void*)0) == info) { |
| 413 | g_set_error (error, SENSORS_APPLET_PLUGIN_ERROR(sensors_applet_plugin_error_quark()), 0, "Error finding disk with path %s", path); |
| 414 | return 0.0; |
| 415 | } |
| 416 | |
| 417 | if (info->error) { |
| 418 | *error = info->error; |
| 419 | info->error = NULL((void*)0); |
| 420 | return 0.0; |
| 421 | } |
| 422 | |
| 423 | /* refresh device temp */ |
| 424 | update_device (info); |
| 425 | return info->temp; |
| 426 | } |
| 427 | |
| 428 | |
| 429 | /* API functions */ |
| 430 | const gchar *sensors_applet_plugin_name (void) { |
| 431 | return plugin_name; |
| 432 | } |
| 433 | |
| 434 | static GList *udisks2_plugin_init (void) { |
| 435 | GList *sensors = NULL((void*)0); |
| 436 | |
| 437 | udisks2_plugin_get_sensors (&sensors); |
| 438 | |
| 439 | return sensors; |
| 440 | } |
| 441 | |
| 442 | GList *sensors_applet_plugin_init (void) { |
| 443 | return udisks2_plugin_init (); |
| 444 | } |
| 445 | |
| 446 | gdouble sensors_applet_plugin_get_sensor_value (const gchar *path, |
| 447 | const gchar *id, |
| 448 | SensorType type, |
| 449 | GError **error) { |
| 450 | |
| 451 | return udisks2_plugin_get_sensor_value (path, id, type, error); |
| 452 | } |