hal.c

Go to the documentation of this file.
00001 /*
00002  * File Name: hal.c
00003  */
00004 
00005 /*
00006  * This file is part of sysd.
00007  *
00008  * sysd is free software: you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation, either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * sysd is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with this program. If not, see <http://www.gnu.org/licenses/>.
00020  */
00021 
00022 /**
00023  * Copyright (C) 2008 iRex Technologies B.V.
00024  * All rights reserved.
00025  *
00026  * Parts used from halevt, Copyright (C) 2007  Patrice Dumas <pertusus at free dot fr>
00027  */
00028 
00029 //----------------------------------------------------------------------------
00030 // Include Files
00031 //----------------------------------------------------------------------------
00032 
00033 // system include files, between < >
00034 #include <glib.h>
00035 #include <hal/libhal.h>
00036 #include <stdio.h>
00037 #include <stdlib.h>
00038 #include <unistd.h>
00039 #include <string.h> 
00040 #include <errno.h>
00041 #include <sys/statvfs.h>
00042 
00043 // ereader include files, between < >
00044 #include <liberipc/eripc.h>
00045 
00046 // local include files, between " "
00047 #include "log.h"
00048 #include "conf.h"
00049 #include "devicelist.h"
00050 #include "hal.h"
00051 #include "ipc.h"
00052 #include "system.h"
00053 
00054 #define UNUSED(x) (void)(x)
00055 
00056 
00057 //----------------------------------------------------------------------------
00058 // Type Declarations
00059 //----------------------------------------------------------------------------
00060 
00061 
00062 //----------------------------------------------------------------------------
00063 // Constants
00064 //----------------------------------------------------------------------------
00065 
00066 static const gchar *UDI_MMC_HOST = "/org/freedesktop/Hal/devices/platform_mxcmci_0_mmc_host";
00067 static const gint SD_FREE_MB_ERROR_LEVEL  = 1;
00068 
00069 
00070 //----------------------------------------------------------------------------
00071 // Static Variables
00072 //----------------------------------------------------------------------------
00073 
00074 static LibHalContext *halContext        = NULL;
00075 static gboolean g_unmount_all_volumes   = FALSE;
00076 static gpointer g_unmount_callback_data = NULL;
00077 static void (*g_unmount_callback_func)(gpointer user_data);
00078 
00079 static gboolean g_remount_all_volumes   = FALSE;
00080 static gpointer g_remount_callback_data = NULL;
00081 static void (*g_remount_callback_func)(gpointer user_data);
00082 
00083 
00084 //============================================================================
00085 // Local Function Definitions
00086 //============================================================================
00087 
00088 static void hal_device_added            (LibHalContext *ctx, const char *udi);
00089 static void hal_device_removed          (LibHalContext *ctx, const char *udi);
00090 static void hal_device_property_modified(LibHalContext *ctx, const char *udi,
00091                                          const char *key, 
00092                                          dbus_bool_t is_removed, 
00093                                          dbus_bool_t is_added);
00094 static int  hal_property_matches_udi    (const char *property, const char *value,
00095                                          const char *udi);
00096 static char **hal_get_property_value    (LibHalPropertyType type, 
00097                                          const char *property, const char *udi, 
00098                                          DBusError *dbus_error_pointer);
00099 static char **hal_udi_property_value    (const char *property, const char *udi);
00100 //static char **hal_duplicate_str_list    (char** str_list);
00101 //static int hal_property_matches_device(const char *key, const char *value, const hal_device *device);
00102 static void volume_is_mounted           (LibHalContext *ctx, const char *udi);
00103 static void remount_next_volume         (void);
00104 
00105 static void unmount_volumes             (void);
00106 static void unmount_volume              (hal_device *device);
00107 static void unmount_volume_finished     (void);
00108 static gboolean device_is_internal_mmc_host(hal_device *device);
00109 static gboolean udi_is_internal_mmc_host(const char *udi);
00110 static void udi_mount_volume            (const char *udi);
00111 
00112 
00113 //============================================================================
00114 // Functions Implementation
00115 //============================================================================
00116 
00117 gboolean hal_set_services()
00118 {
00119     gboolean retval = FALSE;
00120     DBusConnection *dbus_connection;
00121     DBusError error;
00122 
00123     LOGPRINTF("entry");
00124 
00125     dbus_error_init (&error);
00126 
00127     halContext = libhal_ctx_new();
00128     if (halContext == NULL)
00129     {
00130         ERRORPRINTF("Failed to create HAL context");
00131         return FALSE;
00132     }
00133   
00134     dbus_connection = eripc_get_system_connection(eripcClient->context);
00135     
00136     retval = libhal_ctx_set_dbus_connection(halContext, dbus_connection);
00137     if (!retval)
00138     {
00139         ERRORPRINTF("Failed to setup dbus connection");
00140         return FALSE;
00141     }
00142 
00143     retval = libhal_ctx_set_device_added(halContext, hal_device_added);
00144     if (!retval)
00145     {
00146         ERRORPRINTF("Failed to set callback");
00147         return FALSE;
00148     }
00149     
00150     libhal_ctx_set_device_removed(halContext, hal_device_removed);
00151     libhal_ctx_set_device_property_modified(halContext, hal_device_property_modified);
00152 
00153     if (!libhal_ctx_init(halContext, NULL))
00154     {
00155         ERRORPRINTF("Failed to initialize HAL connection to daemon");
00156         libhal_ctx_free(halContext);
00157         halContext = NULL;
00158         return FALSE;
00159     }
00160     
00161     libhal_device_property_watch_all(halContext, &error);
00162     if (dbus_error_is_set (&error)) 
00163     {
00164         WARNPRINTF("Failed to watch all HAL properties: %s", error.message);
00165         dbus_error_free (&error);
00166         return FALSE;
00167     }
00168     
00169     return TRUE;
00170 }
00171 
00172 
00173 void hal_check_dbus_error(DBusError *error)
00174 {
00175     if (dbus_error_is_set(error)) 
00176     {
00177         ERRORPRINTF("DBus Error! %s: %s", error->name, error->message);
00178         dbus_error_free(error);
00179     }
00180 }
00181 
00182 
00183 void hal_device_print(const char *udi)
00184 {
00185     g_return_if_fail(halContext != NULL);
00186     
00187     libhal_device_print(halContext, udi, NULL);
00188 }
00189        
00190 
00191 void hal_add_devices()
00192 {
00193     LOGPRINTF("entry");
00194 
00195     g_return_if_fail(halContext != NULL);
00196     
00197     DBusError error;
00198     char **all_udi = NULL;
00199     char **current_udi = NULL;
00200     int num_device = 0;
00201     hal_device *device = NULL;
00202 
00203     dbus_error_init(&error);
00204     all_udi = libhal_get_all_devices(halContext, &num_device, &error);
00205     hal_check_dbus_error(&error);
00206 
00207     if (all_udi == NULL)
00208     {
00209        LOGPRINTF("No HAL devices. Out of memory or an error occured in HAL");
00210        return;
00211     }
00212 
00213     current_udi = all_udi;
00214 
00215     while ((*current_udi) != NULL)
00216     {
00217         // Here we match all the removable devices that aren't 
00218         // already mounted and mount and register them.
00219         char *storage_device = libhal_device_get_property_string(halContext, *current_udi, "block.storage_device", NULL);
00220         if (  
00221                libhal_device_property_exists(halContext, *current_udi, "block.device", NULL)
00222                &&
00223                hal_property_matches_udi("block.is_volume", "true", *current_udi) 
00224                &&
00225                hal_property_matches_udi("volume.is_mounted", "false", *current_udi) 
00226            )
00227         {
00228             udi_mount_volume(*current_udi);
00229         }
00230         else if (
00231                    libhal_device_property_exists(halContext, *current_udi, "block.device", NULL)
00232                    &&
00233                    hal_property_matches_udi("block.is_volume", "true", *current_udi) 
00234                    &&
00235                    hal_property_matches_udi("volume.is_mounted", "true", *current_udi) 
00236                 )
00237         {
00238             // register volumes already mounted at startup
00239             // this is mainly useful while testing
00240             volume_is_mounted(halContext, *current_udi);
00241         }
00242        
00243         device = hal_device_list_add_device(halContext, *current_udi);
00244         if (storage_device) libhal_free_string(storage_device);
00245         current_udi++;
00246     }
00247 }
00248 
00249 
00250 char **hal_get_iterator_value(const LibHalPropertyType type, LibHalPropertySetIterator *iter)
00251 {
00252     char **value = NULL;
00253     char tmp[256];
00254 
00255     if (type == LIBHAL_PROPERTY_TYPE_STRLIST)
00256     {
00257        return libhal_psi_get_strlist(iter);
00258     }
00259  
00260     value = g_try_malloc0(2*sizeof(char *));
00261     if (value == NULL) 
00262     { 
00263         return NULL; 
00264     }
00265     value[1] = NULL;
00266 
00267     if (type == DBUS_TYPE_STRING)
00268     {
00269         char *hal_value = libhal_psi_get_string(iter);
00270         if (hal_value != NULL)
00271         {
00272             value[0] = g_strdup(hal_value);
00273         }
00274     }
00275     else if (type == DBUS_TYPE_BOOLEAN)
00276     {
00277         dbus_bool_t value_b = libhal_psi_get_bool(iter);
00278         if (value_b == TRUE)
00279         {
00280             value[0] = g_strdup("true");
00281         }
00282         else
00283         {
00284             value[0] = g_strdup("false");
00285         }
00286     }
00287     else if (type == DBUS_TYPE_INT32)
00288     {
00289         dbus_int32_t int_value = libhal_psi_get_int(iter);
00290         snprintf(tmp, 255, "%d", int_value);
00291         tmp[255] = '\0';
00292         value[0] = g_strdup(tmp);
00293     }
00294     else if (type == DBUS_TYPE_UINT64)
00295     {
00296         dbus_uint64_t uint_value = libhal_psi_get_uint64(iter);
00297         snprintf(tmp, 255, "%llu", uint_value);
00298         tmp[255] = '\0';
00299         value[0] = g_strdup(tmp);
00300     }
00301     else if (type == DBUS_TYPE_DOUBLE)
00302     {
00303         double dble_value = libhal_psi_get_double(iter);
00304         snprintf(tmp, 255, "%g", dble_value);
00305         tmp[255] = '\0';
00306         value[0] = g_strdup(tmp);
00307     }
00308     else
00309     {
00310         LOGPRINTF("Unhandled HAL iterator type: %d", type);
00311     }
00312     return value;
00313 }
00314 
00315 
00316 char **hal_property_value(const char *key, const char *udi, const hal_device* device)
00317 {
00318     char **values;
00319 
00320     if ((udi == NULL) || (key == NULL))
00321     {
00322         LOGPRINTF("Warning: hal_property_value was called with a NULL value");
00323         return NULL;
00324     }
00325     if (!strcmp(key,"udi"))
00326     {
00327         char *new_udi = g_strdup(udi);
00328         if (new_udi == NULL) 
00329         { 
00330             return NULL; 
00331         }
00332         values = g_try_malloc0(2*sizeof(char*));
00333         if (values == NULL)
00334         {
00335             g_free(new_udi);
00336             return NULL;
00337         }
00338         values[0] = new_udi;
00339         values[1] = NULL;
00340         return values;
00341     }
00342 
00343     if (device != NULL) 
00344     { 
00345         hal_device_property *property = hal_device_list_get_property(key, device);
00346         return property->values;
00347     }
00348     return hal_udi_property_value(key, udi);
00349 }
00350 
00351 
00352 void hal_remount_all_volumes(gpointer callback_function, gpointer user_data)
00353 {
00354     LOGPRINTF("entry");
00355 
00356     if (g_remount_callback_func != NULL)        
00357     {
00358         WARNPRINTF("sorry, remounting already in progress");
00359     }
00360     else
00361     {
00362         // setup callback function
00363         g_remount_all_volumes = TRUE;
00364         g_remount_callback_func = callback_function;
00365         g_remount_callback_data = user_data;
00366     
00367         // start remounting
00368         remount_next_volume();
00369     }
00370 }
00371 
00372 
00373 // deprecated
00374 /*
00375 void hal_report_mounted_volumes(const char *ipc_service)
00376 {
00377     LOGPRINTF("entry");
00378     
00379     g_return_if_fail(ipc_service != NULL);
00380     
00381     hal_device *device = hal_device_list_get_root();
00382     hal_device_property *property;
00383 
00384     while (device != NULL)
00385     {
00386         property = hal_device_list_get_property("volume.is_mounted", device);
00387         if ((property != NULL) && (*property->values != NULL) && ((*property->values)[0] != '\0'))
00388         {
00389             if (strcmp(*property->values, "true") == 0)
00390             {
00391                 property = hal_device_list_get_property("volume.mount_point", device);
00392                 if ((property != NULL) && (*property->values != NULL) && ((*property->values)[0] != '\0'))
00393                 {
00394                     LOGPRINTF("report volumeMounted %s to %s", *property->values, ipc_service);
00395                     ipc_send_volume_mounted_to(ipc_service, *property->values);
00396                 }
00397             }
00398         }
00399         device = device->next;
00400     }
00401 }
00402 */
00403 
00404 void hal_unmount_all_volumes(gpointer callback_function, gpointer user_data)
00405 {
00406     LOGPRINTF("entry");
00407 
00408     if (g_unmount_callback_func != NULL)        
00409     {
00410         WARNPRINTF("sorry, unmounting already in progress");
00411     }
00412     else
00413     {
00414         // setup callback function
00415         g_unmount_all_volumes = TRUE;
00416         g_unmount_callback_func = callback_function;
00417         g_unmount_callback_data = user_data;
00418     
00419         // flush buffers to disk
00420         sync();
00421         
00422         // start unmounting
00423         unmount_volumes();
00424     }
00425 }
00426 
00427 
00428 gchar *hal_get_mountpoint_device()
00429 {
00430     LOGPRINTF("entry");
00431 
00432     gchar *dev_name = NULL;
00433     hal_device *device = hal_device_list_get_root();
00434     hal_device_property *property;
00435 
00436     while (device != NULL)
00437     {
00438         property = hal_device_list_get_property("volume.mount_point", device);
00439         if ((property != NULL) && (*property->values != NULL) && ((*property->values)[0] != '\0'))
00440         {
00441             if ((*property->values !=NULL) && (strcmp(*property->values, MOUNTPOINT_CARD) == 0))
00442             {
00443                 property = hal_device_list_get_property("block.device", device);
00444                 if ((property != NULL) && (*property->values != NULL) && ((*property->values)[0] != '\0'))
00445                 {
00446                     dev_name = *property->values;
00447                     break;
00448                 }
00449             }
00450         }
00451         device = device->next;
00452     }
00453     return dev_name;
00454 }
00455 
00456 
00457 //============================================================================
00458 // Local Functions Implementation
00459 //============================================================================
00460 
00461 static void hal_device_added(LibHalContext *ctx, const char *udi)
00462 {
00463     LOGPRINTF("entry: udi %s", udi);
00464 
00465     char *storage_device = libhal_device_get_property_string(ctx, udi, "block.storage_device", NULL);
00466     
00467     // This rule matches removable devices which have volume.policy.should_mount true
00468     // or don't have volume.policy.should_mount false.
00469     // Upon insertion, they are mounted and recorded.
00470     if ( libhal_device_property_exists(ctx, udi, "block.device", NULL)
00471          &&
00472          hal_property_matches_udi("block.is_volume", "true", udi) )
00473     {
00474         udi_mount_volume(udi);
00475     }     
00476     
00477     // sync the devices list
00478     hal_device_list_add_device(ctx, udi);
00479     
00480     if (storage_device) libhal_free_string(storage_device);
00481 }
00482 
00483 
00484 static void hal_device_removed(LibHalContext *ctx, const char *udi)
00485 {
00486     UNUSED(ctx);
00487     LOGPRINTF("entry: udi %s", udi);
00488 
00489     // use the device from the devices list since the 
00490     // properties will be right 
00491     hal_device *removed_device = NULL;
00492     removed_device = hal_device_list_find_device(udi);
00493     if (removed_device != NULL)
00494     {
00495         // When a device is removed, it is recorded.
00496         // Note that at that point the device is already out of hal, so we use
00497         // cannot match or get properties
00498         
00499         enum state_card state = sys_get_card();
00500         if (state != STATE_CARD_EJECTED)
00501         {
00502             if (device_is_internal_mmc_host(removed_device))
00503             {            
00504                 if (state == STATE_CARD_MOUNTED)
00505                 {
00506                     WARNPRINTF("card ejected before unmount, force unmount now");
00507                     
00508                     // force lazy unmount
00509                     sys_spawn_async("umount -lf " MOUNTPOINT_CARD);
00510                     
00511                     // report to applications
00512                     ipc_send_volume_unmounted(MOUNTPOINT_CARD);
00513                     
00514                     sys_set_card(STATE_CARD_UNMOUNTED);
00515                 }
00516                 else 
00517                 {
00518                     sys_set_card(STATE_CARD_EJECTED);
00519                 }
00520             }
00521         }
00522         
00523         // sync the devices list 
00524         hal_device_list_remove_device(udi);
00525     }
00526     else
00527     {
00528         WARNPRINTF("Cannot find device %s in hal list", udi);
00529         
00530         // FIXME resync devices list? 
00531         // FIXME try to run checks and commands on removed devices anyway
00532     }    
00533 }
00534 
00535 
00536 static gboolean udi_is_internal_mmc_host(const char *udi)
00537 {
00538     char *ip  = NULL;
00539     ip = libhal_device_get_property_string(halContext, udi, "info.parent", NULL);
00540     if (ip)
00541     {
00542         // on coldplug, the parent's parent is the mmc host as we don't appear to have the card device itself
00543         // this may be a HAL issue but we accept this for now
00544         if (hal_property_matches_udi("info.parent", UDI_MMC_HOST, ip))
00545         {
00546             libhal_free_string(ip);
00547             return TRUE;
00548         }
00549         else
00550         {
00551             char *ipp  = NULL;
00552             ipp = libhal_device_get_property_string(halContext, ip, "info.parent", NULL);
00553             libhal_free_string(ip);
00554             if (ipp)
00555             {
00556                 // on hotplug, the parent's parent's parent is the mmc host as one would expect
00557                 if (hal_property_matches_udi("info.parent", UDI_MMC_HOST, ipp))
00558                 {
00559                     libhal_free_string(ipp);
00560                     return TRUE;
00561                 }
00562             }
00563         }
00564     }
00565     return FALSE;
00566 }
00567 
00568 
00569 static void udi_mount_volume(const char *udi)
00570 {
00571     LOGPRINTF("entry udi [%s]", udi);
00572     
00573     char *command = NULL;
00574 
00575     if (udi_is_internal_mmc_host(udi))
00576     {
00577         // remove mountpoint just it case it still exists which causes mount to fail
00578         gint retval = rmdir(MOUNTPOINT_CARD);
00579         if ((retval == 0) || (errno == ENOENT))
00580         {
00581             // set mountpoint for internal MMC card
00582             char *dev_name = g_path_get_basename(MOUNTPOINT_CARD);
00583             command = g_strdup_printf("halevt-mount -u %s -p %s -m 002 -o %s", udi, dev_name, MOUNT_OPTIONS);
00584             g_free(dev_name);
00585         }
00586         else
00587         {
00588             ERRORPRINTF("mounting failed, %s is already occupied (%d, %s)", MOUNTPOINT_CARD, errno, strerror(errno));
00589         }                    
00590     }
00591     else
00592     {
00593         // default mountpoint is the volume label
00594         command = g_strdup_printf("halevt-mount -u %s -m 002 -o %s", udi, MOUNT_OPTIONS);
00595     }
00596         
00597     if (command)
00598     {
00599         sys_reset_idle_time();
00600         sys_spawn_async(command);
00601         g_free(command);
00602     }
00603 }
00604 
00605 
00606 static gboolean device_is_internal_mmc_host(hal_device *device)
00607 {
00608     LOGPRINTF("entry");
00609     hal_device_property *property = NULL;
00610     
00611     property = hal_device_list_get_property("info.parent", device);
00612     if (property  && (*property->values != NULL)) 
00613     {
00614         // on coldplug, the parent's parent is the mmc host as we don't appear to have the card device itself
00615         // this may be a HAL issue but we accept this for now
00616         property = hal_device_list_get_property("info.parent", hal_device_list_find_device(*property->values));
00617         if (property && (*property->values != NULL) && (strcmp(*property->values, UDI_MMC_HOST) == 0))
00618         {
00619             return TRUE;
00620         }
00621         else 
00622         {
00623             // on hotplug, the parent's parent's parent is the mmc host as one would expect
00624             property = hal_device_list_get_property("info.parent", hal_device_list_find_device(*property->values));
00625             if (property && (*property->values != NULL) && (strcmp(*property->values, UDI_MMC_HOST) == 0))
00626             {
00627                 return TRUE;
00628             }
00629         }
00630     }
00631     return FALSE;
00632 }
00633 
00634 
00635 static void hal_device_property_modified(LibHalContext *ctx, const char *udi,
00636                                          const char *key, dbus_bool_t is_removed, dbus_bool_t is_added)
00637 {
00638     UNUSED(is_added);
00639     LOGPRINTF("entry: udi %s, key %s, added:%d, removed:%d", udi, key, is_added, is_removed);
00640 
00641     g_return_if_fail(key!=NULL);
00642     
00643     if (strcmp(key,"volume.mount_point") == 0)
00644     { 
00645         char *mount_point = libhal_device_get_property_string(ctx, udi, "volume.mount_point", NULL);
00646         
00647         LOGPRINTF("volume.mount_point = %s", mount_point);
00648         
00649         if ((mount_point != NULL) && (mount_point[0] != '\0'))
00650         {
00651             LOGPRINTF("Filled volume.mount_point, wait for is_mounted callback");
00652             // mount point created, wait for is_mounted callback
00653         }
00654         else
00655         {
00656             LOGPRINTF("Cleared volume.mount_point, find in device list");
00657 
00658             // mount point removed, handle here because
00659             // in the is_mounted callback we don't know the mount point anymore
00660             
00661             hal_device *removed_device = NULL;
00662             hal_device_property *property = NULL;
00663             
00664             removed_device = hal_device_list_find_device(udi);
00665             
00666             if (removed_device != NULL)
00667             {
00668                 property = hal_device_list_get_property("volume.mount_point", removed_device);
00669                 if ((property != NULL) && (*property->values != NULL) && ((*property->values)[0] != '\0'))
00670                 {
00671                     LOGPRINTF("Mountpoint removed [%s]", *property->values);
00672 
00673                     sys_reset_idle_time();
00674 
00675                     // update mount information 
00676                     sys_spawn_async("halevt-mount -s");
00677                     
00678                     // report to applications
00679                     ipc_send_volume_unmounted(*property->values);
00680                     
00681                     if (strcmp(*property->values, MOUNTPOINT_CARD) == 0)
00682                     {
00683                         sys_set_card(STATE_CARD_UNMOUNTED);
00684                     }
00685 
00686                     // remove from device list before continuing with next volume
00687                     hal_device_list_remove_property(udi, key);               
00688                 }
00689             }
00690             else
00691             {
00692                 WARNPRINTF("mount point for %s not found", key);
00693             }
00694         }
00695         if (mount_point) libhal_free_string(mount_point);
00696     }
00697     else if (strcmp(key,"volume.is_mounted") == 0)
00698     {
00699         // When a device get a mount point, it is recorded.
00700         // When a device is unmounted, it is recorded.
00701         LOGPRINTF("volume.is_mounted");
00702         
00703         // DEBUG ONLY -- STRING SHOULD BE FREED
00704 /*
00705         LOGPRINTF("A: %d", libhal_device_property_exists(ctx, udi, "block.device", NULL));
00706         LOGPRINTF("B: %d", libhal_device_get_property_bool(ctx, udi, "block.is_volume", NULL));
00707         LOGPRINTF("C: %d", libhal_device_property_exists(ctx, udi, "volume.mount_point", NULL));
00708 */        
00709         if ( libhal_device_property_exists(ctx, udi, "block.device", NULL)
00710              &&
00711              libhal_device_get_property_bool(ctx, udi, "block.is_volume", NULL) ) 
00712         {
00713             // update mount information 
00714             sys_spawn_async("halevt-mount -s");
00715 
00716             if (libhal_device_get_property_bool(ctx, udi, "volume.is_mounted", NULL))
00717             {
00718                 // update before remounting next volume
00719                 hal_device_list_set_property(udi, key);
00720 
00721                 volume_is_mounted(ctx, udi);
00722             }
00723             else
00724             {
00725                 // unmount handled at mount_point as we don't know the mount point when we're here
00726             } 
00727         }
00728     }
00729     else if (strcmp(key,"irex.battery") == 0)
00730     {
00731         LOGPRINTF("irex.battery");
00732         
00733         char *battery = libhal_device_get_property_string(ctx, udi, "irex.battery", NULL);
00734         if (battery) 
00735         {
00736             sys_update_battery(battery);
00737             libhal_free_string(battery);
00738         }
00739     }
00740     else if (strcmp(key,"irex.hardware_state") == 0)
00741     {
00742         LOGPRINTF("irex.hardware_state");
00743         
00744         char *hw_sate = libhal_device_get_property_string(ctx, udi, "irex.hardware_state", NULL);
00745         if (hw_sate) 
00746         {
00747             sys_update_hardware(hw_sate);
00748             libhal_free_string(hw_sate);
00749         }
00750     }
00751 
00752     // now sync the properties in the devices list
00753     if (is_removed)
00754     {
00755         hal_device_list_remove_property(udi, key);
00756     }
00757     else
00758     {
00759         hal_device_list_set_property(udi, key);
00760     }
00761 }
00762 
00763 
00764 static char **hal_get_property_value(LibHalPropertyType type, const char *property, const char *udi, 
00765                                      DBusError *dbus_error_pointer)
00766 {
00767     char **value = NULL;
00768     char tmp[256];
00769 
00770     if (type == LIBHAL_PROPERTY_TYPE_STRLIST)
00771     {
00772        return libhal_device_get_property_strlist(halContext, udi, property, dbus_error_pointer);;
00773     }
00774  
00775     value = g_try_malloc0(2*sizeof(char *));
00776     if (value == NULL) 
00777     { 
00778         return NULL; 
00779     }
00780     value[1] = NULL;
00781 
00782     if (type == DBUS_TYPE_STRING)
00783     {
00784         char *hal_value = libhal_device_get_property_string(halContext, udi, property, dbus_error_pointer);
00785         if (hal_value != NULL)
00786         {
00787             value[0] = g_strdup(hal_value);
00788             libhal_free_string(hal_value);
00789         }
00790     }
00791     else if (type == DBUS_TYPE_BOOLEAN)
00792     {
00793         dbus_bool_t value_b = libhal_device_get_property_bool(halContext, udi, property, dbus_error_pointer);
00794         if (value_b == TRUE)
00795         {
00796             value[0] = g_strdup("true");
00797         }
00798         else
00799         {
00800             value[0] = g_strdup("false");
00801         }
00802     }
00803     else if (type == DBUS_TYPE_INT32)
00804     {
00805         dbus_int32_t int_value = libhal_device_get_property_int(halContext, udi, property, dbus_error_pointer);
00806         snprintf(tmp, 255, "%d", int_value);
00807         tmp[255] = '\0';
00808         value[0] = g_strdup(tmp);
00809     }
00810     else if (type == DBUS_TYPE_UINT64)
00811     {
00812         dbus_uint64_t uint_value = libhal_device_get_property_uint64(halContext, udi, property, dbus_error_pointer);
00813         snprintf(tmp, 255, "%llu", uint_value);
00814         tmp[255] = '\0';
00815         value[0] = g_strdup(tmp);
00816     }
00817     else if (type == DBUS_TYPE_DOUBLE)
00818     {
00819         double dble_value = libhal_device_get_property_double(halContext, udi, property, dbus_error_pointer);
00820         snprintf(tmp, 255, "%g", dble_value);
00821         tmp[255] = '\0';
00822         value[0] = g_strdup(tmp);
00823     }
00824     else
00825     {
00826         LOGPRINTF("Unhandled HAL type for property %s, device %s: %d", property, udi, type);
00827     }
00828     return value;
00829 }
00830 
00831 
00832 static int hal_property_matches_udi(const char *property, const char *value, const char *udi)
00833 {
00834    DBusError dbus_error;
00835    int result = 0;
00836     
00837    if ((udi == NULL) || (property == NULL) || (value == NULL))
00838    {
00839       LOGPRINTF("Warning: hal_property_matches called with a NULL value");
00840       return 0;
00841    }
00842 
00843    dbus_error_init(&dbus_error);
00844 
00845 //   LOGPRINTF("match %s, %s, %s", property, value, udi);
00846     
00847    if (libhal_device_property_exists(halContext, udi, property, &dbus_error))
00848    {
00849       LibHalPropertyType type;
00850        
00851 //      LOGPRINTF("property exists %s", property);
00852 
00853       hal_check_dbus_error(&dbus_error);
00854 
00855       if (value == NULL) 
00856       { 
00857            return 1; 
00858       }
00859 
00860       type = libhal_device_get_property_type(halContext, udi, property, &dbus_error);
00861       hal_check_dbus_error(&dbus_error);
00862        
00863 //      LOGPRINTF("property type %d", type);
00864 
00865       if (type == DBUS_TYPE_BOOLEAN)
00866       {
00867           dbus_bool_t val_bool = FALSE;
00868           if (!strcmp(value, "true")) 
00869           { 
00870               val_bool = TRUE; 
00871           }
00872           result = (libhal_device_get_property_bool(halContext, udi, property, &dbus_error) == val_bool);
00873       }
00874       else if (type == DBUS_TYPE_STRING)
00875       {
00876           char *str_val = libhal_device_get_property_string(halContext, udi, property, &dbus_error);
00877           if (str_val != NULL)
00878           {
00879              result = (!strcmp(value, str_val));
00880              libhal_free_string(str_val);
00881           }
00882       }
00883       else if (type == DBUS_TYPE_INT32)
00884       {
00885           result = (libhal_device_get_property_int(halContext, udi, property, &dbus_error) == atoi(value));
00886       } /* FIXME: LIBHAL_PROPERTY_TYPE_STRLIST */
00887       else if (type == LIBHAL_PROPERTY_TYPE_STRING)
00888       {
00889           char **cur_str;
00890           char **str_list = libhal_device_get_property_strlist(halContext, udi, property, &dbus_error);
00891           if (str_list != NULL)
00892           {
00893               cur_str = str_list;
00894               while ((*cur_str) != NULL)
00895               {
00896                   if (!strcmp((*cur_str), value))
00897                   {
00898                       result = 1;
00899                       break;
00900                   }
00901                   cur_str++;
00902               }
00903               libhal_free_string_array(str_list);
00904           }
00905       }
00906       else if (type == DBUS_TYPE_UINT64)
00907       {
00908           result = ( (guint64) libhal_device_get_property_int(halContext, udi, property, &dbus_error) == 
00909                   strtoull(value, NULL, 10) );
00910       }
00911       else if (type == DBUS_TYPE_DOUBLE)
00912       {
00913           result = (libhal_device_get_property_double(halContext, udi, property, &dbus_error) == 
00914                   strtod(value, NULL));
00915       }
00916       else
00917       {
00918          LOGPRINTF("HAL type not handled in match (%s,%s,%s): %d", property, value, udi, type);
00919          return 0;
00920       }
00921    }
00922 
00923    hal_check_dbus_error(&dbus_error);
00924 
00925    return result;
00926 }
00927 
00928 
00929 static char **hal_udi_property_value(const char *property, const char *udi)
00930 {
00931     char **values = NULL;
00932     DBusError dbus_error;
00933 
00934     if ((udi == NULL) || (property == NULL))
00935     {
00936         WARNPRINTF("hal_udi_property_value was called with a NULL value");
00937         return NULL;
00938     }
00939 
00940     dbus_error_init(&dbus_error);
00941 
00942     if (libhal_device_property_exists(halContext, udi, property, &dbus_error))
00943     {
00944         LibHalPropertyType type;
00945 
00946         hal_check_dbus_error(&dbus_error);
00947 
00948         type = libhal_device_get_property_type(halContext, udi, property, &dbus_error);
00949         hal_check_dbus_error(&dbus_error);
00950 
00951         values = hal_get_property_value(type, property, udi, &dbus_error);
00952     }
00953     hal_check_dbus_error(&dbus_error);
00954 
00955     return values;
00956 }
00957 
00958 /*
00959 static char **hal_duplicate_str_list(char** str_list)
00960 {
00961    char **value = NULL;
00962    char **cur_str;
00963 
00964    if (str_list != NULL)
00965    {
00966        char *cur_val;
00967        unsigned int total_value_nr;
00968        char **cur_value;
00969        total_value_nr = libhal_string_array_length(str_list);       
00970 
00971        value = g_try_malloc0((total_value_nr+1) * sizeof(char*));
00972        if (value == NULL)
00973        { 
00974            libhal_free_string_array(str_list);
00975            return NULL;
00976        }
00977        *value = NULL;
00978 
00979        cur_str = str_list;
00980        cur_value = value;
00981               
00982        while ((*cur_str) != NULL)
00983        {
00984            cur_val = g_strdup(*cur_str);
00985            if (cur_val == NULL)
00986            { 
00987                libhal_free_string_array (str_list);
00988                cur_value = value;
00989                while ((*cur_value) != NULL)
00990                {
00991                    g_free(*cur_value);
00992                    cur_value++;
00993                }
00994                g_free(value);
00995                return NULL;
00996            }
00997            *cur_value = cur_val;
00998            cur_value++;
00999            *cur_value = NULL;
01000            cur_str++;
01001        }
01002        libhal_free_string_array(str_list);
01003    }
01004    return value;
01005 }
01006 */
01007 
01008 static void volume_is_mounted(LibHalContext *ctx, const char *udi)
01009 {
01010     // report mount to applications
01011     char *mount_point = libhal_device_get_property_string(ctx, udi, "volume.mount_point", NULL);
01012     
01013     LOGPRINTF("entry udi [%s] mount_point [%s]", udi, mount_point);
01014     
01015     if (mount_point)
01016     {
01017         sys_reset_idle_time();
01018         
01019         // check available free space
01020         gint64     mbfree   = -1;
01021         gboolean  readonly = FALSE;
01022         gboolean  sdfull   = FALSE;
01023         
01024         struct statvfs s;
01025         if (statvfs(mount_point, &s) == 0) 
01026         {
01027             mbfree   = s.f_frsize * s.f_bavail >> 20;
01028             if (s.f_flag & ST_RDONLY)
01029             {
01030                 readonly = TRUE;
01031             }
01032         }
01033 
01034         LOGPRINTF("mbfree [%lld] readonly [%d]", mbfree, readonly);
01035         
01036         if (mbfree == -1)
01037         {
01038             ERRORPRINTF("failed to get free space from mount point [%s]", mount_point);
01039         }
01040         else if (readonly)
01041         {
01042             ipc_show_splash("sdreadonly");
01043         }
01044         else if (mbfree <= SD_FREE_MB_ERROR_LEVEL)
01045         {
01046             ipc_show_splash("sdfull");
01047             sdfull = TRUE;
01048         }
01049         
01050         if (!readonly)
01051         { 
01052             // continue mounting volume
01053             //
01054             if (sys_is_emulator())
01055             {
01056                 LOGPRINTF("EMULATOR Emulate mount at [%s]", MOUNTPOINT_CARD);
01057                 sys_set_card(STATE_CARD_INDEXING);
01058             }
01059             else
01060             {
01061                 if (strcmp(mount_point, MOUNTPOINT_CARD) == 0)
01062                 {
01063                     LOGPRINTF("Internal card found at [%s]", MOUNTPOINT_CARD);
01064                     if (sdfull)
01065                     {
01066                         // mount so it can be exported to USB but skip indexing
01067                         sys_set_card(STATE_CARD_MOUNTED);
01068                     }
01069                     else
01070                     {
01071                         sys_set_card(STATE_CARD_INDEXING);
01072                     }
01073                 }
01074                 else
01075                 {
01076                     LOGPRINTF("Volume found at [%s]", mount_point);
01077                     ipc_send_volume_mounted(mount_point);
01078                 }
01079             }
01080         }
01081         else
01082         {
01083             if (strcmp(mount_point, MOUNTPOINT_CARD) == 0)
01084             {
01085                 sys_set_card(STATE_CARD_INACCESSIBLE);
01086             }
01087             
01088             // unmount volume
01089             //
01090             hal_device *device = hal_device_list_find_device(udi);
01091             unmount_volume(device);
01092         }
01093 
01094         libhal_free_string(mount_point);
01095     }
01096     
01097     if (g_remount_all_volumes)
01098     {
01099         // look for next volume to remount
01100         remount_next_volume();
01101     }
01102 }
01103 
01104 
01105 static void unmount_volumes()
01106 {
01107     LOGPRINTF("entry");
01108     
01109     hal_device *device = hal_device_list_get_root();
01110     if (device != NULL)
01111     {
01112         unmount_volume(device);
01113     }
01114     else
01115     {
01116         LOGPRINTF("no volumes to unmount");
01117         unmount_volume_finished();
01118     }
01119 }
01120 
01121 
01122 static void on_volume_unmounted(GPid pid, gint status, gpointer data)
01123 {
01124     UNUSED(pid);
01125     UNUSED(status);
01126     LOGPRINTF("entry");
01127     
01128     hal_device *device = (hal_device *) data;
01129     if (device->next && g_unmount_all_volumes) 
01130     {
01131         // unmount next volume
01132         unmount_volume(device->next);
01133     }
01134     else
01135     {
01136         LOGPRINTF("no more volumes to unmount");
01137         unmount_volume_finished();
01138     }
01139 }
01140 
01141 
01142 static void unmount_volume_finished(void)
01143 {
01144     LOGPRINTF("entry");
01145     
01146     // unmounting finished, execute callback handler
01147     if (g_unmount_callback_func)
01148     {
01149         LOGPRINTF("call callback handler");
01150 
01151         (*g_unmount_callback_func)(g_unmount_callback_data);
01152 
01153         // reset
01154         g_unmount_callback_func = NULL;
01155         g_unmount_callback_data = NULL;
01156     }
01157     else
01158     {
01159         LOGPRINTF("no callback handler");
01160     }
01161 }
01162 
01163 
01164 static void unmount_volume(hal_device *device)
01165 {
01166     LOGPRINTF("entry");
01167     
01168     while (device != NULL)
01169     {
01170         hal_device_property *property = NULL;
01171         property = hal_device_list_get_property("volume.is_mounted", device);
01172         if ((property != NULL) && (*property->values != NULL) && ((*property->values)[0] != '\0'))
01173         {
01174             LOGPRINTF("udi %s, volume.is_mounted = %s", device->udi, *property->values);
01175             if (strcmp(*property->values, "true") == 0)
01176             {
01177                 property = hal_device_list_get_property("volume.mount_point", device);
01178                 if ((property != NULL) && (*property->values != NULL) && ((*property->values)[0] != '\0'))
01179                 {
01180                     gchar *command = NULL;
01181                     command = g_strconcat("unmount.sh ", *property->values, NULL);
01182                     LOGPRINTF("%s", command);
01183                     // late recurse
01184                     sys_spawn_async_with_callback(command, on_volume_unmounted, device);
01185                     g_free(command);
01186                     return;
01187                 }
01188             }
01189         }
01190         device = device->next;
01191     }
01192     
01193     LOGPRINTF("no more volumes to unmount");
01194     unmount_volume_finished();
01195 }
01196 
01197 
01198 static void remount_next_volume()
01199 {
01200     LOGPRINTF("entry");
01201     
01202     hal_device *device = hal_device_list_get_root();
01203     hal_device_property *property = NULL;
01204 
01205     while (device != NULL)
01206     {
01207         property = hal_device_list_get_property("volume.is_mounted", device);
01208         if ((property != NULL) && (*property->values != NULL) && ((*property->values)[0] != '\0'))
01209         {
01210             LOGPRINTF("udi %s, volume.is_mounted = %s", device->udi, *property->values);
01211             if (strcmp(*property->values, "false") == 0)
01212             {
01213                 udi_mount_volume(device->udi);
01214                 return;
01215             }
01216         }
01217         device = device->next;
01218     }
01219     
01220     // no unmounted volume found, stop trying
01221     LOGPRINTF("no more volume to remmount");
01222     g_remount_all_volumes = FALSE;
01223     
01224     // execute callback handler
01225     if (g_remount_callback_func)
01226     {
01227         LOGPRINTF("call callback handler");
01228 
01229         (*g_remount_callback_func)(g_remount_callback_data);
01230 
01231         // reset
01232         g_remount_callback_func = NULL;
01233         g_remount_callback_data = NULL;
01234     }
01235     else
01236     {
01237         LOGPRINTF("no callback handler");
01238     }        
01239 }
Generated by  doxygen 1.6.2-20100208