Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

linux_common.c

00001 /***************************************************************************
00002  * CVSID: $Id: linux_common.c,v 1.8 2004/01/19 19:58:10 david Exp $
00003  *
00004  * linux_common.c : Common functionality used by Linux specific parts
00005  *
00006  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
00007  *
00008  * Licensed under the Academic Free License version 2.0
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00023  *
00024  **************************************************************************/
00025 
00026 #ifdef HAVE_CONFIG_H
00027 #  include <config.h>
00028 #endif
00029 
00030 #define _GNU_SOURCE 1 /* for strndup() */
00031 
00032 #include <ctype.h>
00033 #include <stdio.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <getopt.h>
00037 #include <assert.h>
00038 #include <unistd.h>
00039 #include <stdarg.h>
00040 #include <limits.h>
00041 
00042 #include <libhal/libhal.h> /* For HAL_STATE_* */
00043 
00044 #include "../logger.h"
00045 #include "../device_store.h"
00046 #include "../device_info.h"
00047 #include "linux_common.h"
00048 
00062 double parse_double(const char* str)
00063 {
00065     return atof(str);
00066 }
00067 
00074 dbus_int32_t parse_dec(const char* str)
00075 {
00076     dbus_int32_t value;
00077     value = strtol(str, NULL, 10);
00079     return value;
00080 }
00081 
00089 dbus_int32_t parse_hex(const char* str)
00090 {
00091     dbus_int32_t value;
00092     value = strtol(str, NULL, 16);
00094     return value;
00095 }
00096 
00108 long int find_num(char* pre, char* s, int base)
00109 {
00110     char* where;
00111     int result;
00112 
00113     where = strstr(s, pre);
00114     if( where==NULL )
00115     {
00116         /*DIE(("Didn't find '%s' in '%s'", pre, s));*/
00117         return LONG_MAX;
00118     }
00119     where += strlen(pre);
00120 
00121     result = strtol(where, NULL, base);
00123 /*
00124     if( result==LONG_MIN || result==LONG_MAX )
00125         DIE(("Error parsing value for '%s' in '%s'", pre, s));
00126 */
00127 
00128     return result;
00129 }
00130 
00141 double find_double(char* pre, char* s)
00142 {
00143     char* where;
00144     double result;
00145 
00146     where = strstr(s, pre);
00148     if( where==NULL )
00149         DIE(("Didn't find '%s' in '%s'", pre, s));
00150     where += strlen(pre);
00151 
00152     result = atof(where);
00153 
00154     return result;
00155 }
00156 
00167 int find_bcd2(char* pre, char* s)
00168 {
00169     int i;
00170     char c;
00171     int digit;
00172     int left, right, result;
00173     int len;
00174     char* str;
00175     dbus_bool_t passed_white_space;
00176     int num_prec;
00177 
00178     str = find_string(pre, s);
00179     if( str==NULL || strlen(str)==0 )
00180         return 0xffff;
00181 
00182 
00183     left = 0;
00184     len = strlen(str);
00185     passed_white_space = FALSE;
00186     for(i=0; i<len && str[i]!='.'; i++)
00187     {
00188         if( isspace(str[i]) )
00189         {
00190             if( passed_white_space )
00191                 break;
00192             else
00193                 continue;
00194         }
00195         passed_white_space = TRUE;
00196         left *= 16;
00197         c = str[i];
00198         digit = (int) (c-'0');
00199         left += digit;
00200     }
00201     i++;
00202     right=0;
00203     num_prec=0;
00204     for( ; i<len; i++)
00205     {
00206         if( isspace(str[i]) )
00207             break;
00208         if( num_prec==2 )       /* Only care about 2 digits of precision */
00209             break;
00210         right *= 16;
00211         c = str[i];
00212         digit = (int) (c-'0');
00213         right += digit;
00214         num_prec++;
00215     }
00216 
00217     for( ; num_prec<2; num_prec++)
00218         right*=16;
00219     
00220     result = left*256 + (right&255);
00221     return result;
00222 }
00223 
00234 char* find_string(char* pre, char* s)
00235 {
00236     char* where;
00237     static char buf[256];
00238     char* p;
00239 
00240     where = strstr(s, pre);
00241     if( where==NULL )
00242         return NULL;
00243     where += strlen(pre);
00244 
00245     p=buf;
00246     while( *where!='\n' && *where!='\r')
00247     {
00248         char c = *where;
00249 
00250         // ignoring char 63 fixes a problem with info from the Lexar CF Reader
00251         if( (isalnum(c) || isspace(c) || ispunct(c)) && c!=63 )
00252         {
00253             *p = c;
00254             ++p;
00255         }
00256 
00257         ++where;
00258     }
00259     *p = '\0';
00260 
00261     // remove trailing white space
00262     --p;
00263     while( isspace(*p) )
00264     {
00265         *p='\0';
00266         --p;
00267     }
00268 
00269     return buf;
00270 }
00271 
00279 char* read_single_line(char* filename_format,...)
00280 {
00281     FILE* f;
00282     int i;
00283     int len;
00284     char filename[512];
00285     static char buf[512];
00286     va_list args;
00287 
00288     va_start(args, filename_format);
00289     vsnprintf(filename, 512, filename_format, args);
00290     va_end(args);
00291 
00292     f = fopen(filename, "rb");
00293     if( f==NULL )
00294         return NULL;
00295 
00296     if( fgets(buf, 512, f)==NULL )
00297     {
00298         fclose(f);
00299         return NULL;
00300     }
00301 
00302     len = strlen(buf);
00303     for(i=len-1; i>0; --i )
00304     {
00305         if( buf[i]=='\n' || buf[i]=='\r' )
00306             buf[i]='\0';
00307         else
00308             break;
00309     }
00310 
00311     fclose(f);
00312     return buf;
00313 }
00314 
00321 const char* get_last_element(const char* s)
00322 {
00323     int len;
00324     const char* p;
00325     
00326     len = strlen(s);
00327     for(p=s+len-1; p>s; --p)
00328     {
00329         if( (*p)=='/' )
00330             return p+1;
00331     }
00332 
00333     return s;
00334 }
00335 
00336 
00363 char* rename_and_merge(HalDevice* d, 
00364                        ComputeFDI naming_func,
00365                        const char* namespace)
00366 {
00367     int append_num;
00368     char* computed_udi;
00369     HalDevice* computed_d;
00370 
00371     /* udi is a temporary udi */
00372 
00373     append_num = -1;
00374 tryagain:
00375     /* compute the udi for the device */
00376     computed_udi = (*naming_func)(d, append_num);
00377 
00378     /* See if a device with the computed udi already exist. It can exist
00379      * because the device-list is (can be) persistent across invocations 
00380      * of hald.
00381      *
00382      * If it does exist, note that it's udi is computed from only the same 
00383      * information as our just computed udi.. So if we match, and it's
00384      * unplugged, it's the same device!
00385      *
00386      * (of course assuming that our udi computing algorithm actually works!
00387      *  Which it might not, see discussions - but we can get close enough
00388      *  for it to be practical)
00389      */
00390     computed_d = ds_device_find(computed_udi);
00391     if( computed_d!=NULL )
00392     {
00393         
00394         if( (!ds_property_exists(computed_d, "info.not_available"))
00395             && (!ds_property_get_bool(computed_d, "info.not_available")) )
00396         {
00397             /* Danger, Will Robinson! Danger!
00398              *
00399              * Ok, this means that either
00400              *
00401              * a) The user plugged in two instances of the kind of
00402              *    of device; or
00403              *
00404              * b) The agent is invoked with --probe for the second
00405              *    time during the life of the HAL daemon
00406              *
00407              * We want to support b) otherwise we end up adding a lot
00408              * of devices which is a nuisance.. We also want to be able
00409              * to do b) when developing HAL agents.
00410              *
00411              * So, therefore we check if the non-unplugged device has 
00412              * the same bus information as our newly hotplugged one.
00413              */
00414             if( ds_device_matches(computed_d, d, namespace) )
00415             {
00416                 HAL_ERROR(("Found device already present as '%s'!\n",
00417                            computed_d->udi));
00418                 ds_print(d);
00419                 ds_print(computed_d);
00420                 /* indeed a match, must be b) ; ignore device */
00421                 ds_device_destroy(d);
00422                 /* and return */
00423                 return NULL;
00424             }
00425             
00428             append_num++; 
00429             goto tryagain;
00430         }
00431         
00432         /* It did exist! Merge our properties from the probed device
00433          * since some of the bus-specific properties are likely to be
00434          * different 
00435          *
00436          * (user may have changed port, #Dev is different etc.)
00437          *
00438          * Note that the probed device only contain bus-specific
00439          * properties - the other properties will remain..
00440          */
00441         ds_device_merge(computed_d, d);
00442         
00443         /* Remove temporary device */
00444         ds_device_destroy(d);
00445 
00446         /* Set that we are back in business! */
00447         ds_property_set_bool(computed_d, "info.not_available", FALSE);
00448 
00449         HAL_INFO(("Device %s is plugged in again", computed_d->udi));
00450 
00451     }
00452     else
00453     {
00454         /* Device is not in list... */
00455         
00456         /* assign the computed device name */
00457         ds_device_set_udi(d, computed_udi);
00458         ds_property_set_string(d, "info.udi", computed_udi);
00459 
00460         /* Search for device information file and attempt merge */
00461         if( di_search_and_merge(d) )
00462         {
00463             HAL_INFO(("Found a .fdi file for %s", d->udi));
00464         }
00465 
00466     }
00467 
00468     return computed_udi;
00469 }
00470 
00477 char* get_parent_sysfs_path(const char* path)
00478 {
00479     int i;
00480     int len;
00481     char* parent_path;
00482 
00483     /* Find parent device by truncating our own path */
00484     parent_path = strndup(path, SYSFS_PATH_MAX);
00485     if( parent_path==NULL )
00486         DIE(("No memory"));
00487     len = strlen(parent_path);
00488     for(i=len-1; parent_path[i]!='/'; --i)
00489     {
00490         parent_path[i]='\0';
00491     }
00492     parent_path[i]='\0';
00493 
00494     return parent_path;
00495 }
00496 
00505 void find_and_set_physical_device(HalDevice* device)
00506 {
00507     HalDevice* d;
00508     HalDevice* parent;
00509     const char* parent_udi;
00510 
00511     d = device;
00512     do
00513     {
00514         parent_udi = ds_property_get_string(d, "info.parent");
00515         if( parent_udi==NULL )
00516         {
00517             HAL_ERROR(("Error finding parent for %s\n", d->udi));
00518             return;
00519         }
00520 
00521         parent = ds_device_find(parent_udi);
00522         if( parent==NULL )
00523         {
00524             HAL_ERROR(("Error resolving UDI %s\n", parent_udi));
00525             return;
00526         }
00527 
00528         if( !ds_property_exists(parent, "info.physical_device") )
00529         {
00530             ds_property_set_string(device, "info.physical_device", parent_udi);
00531             return;
00532         }
00533 
00534         d = parent;
00535     } 
00536     while(TRUE);
00537 }
00538 
00539 
00540 /* Entry in bandaid driver database */
00541 struct driver_entry_s
00542 {
00543     char driver_name[SYSFS_NAME_LEN];  
00544     char device_path[SYSFS_PATH_MAX];  
00545     struct driver_entry_s* next;       
00547 };
00548 
00550 static struct driver_entry_s* drivers_table_head = NULL;
00551 
00557 static void drivers_add_entry(const char* driver_name, const char* device_path)
00558 {
00559     struct driver_entry_s* entry;
00560 
00561     entry = malloc(sizeof(struct driver_entry_s));
00562     if( entry==NULL )
00563         DIE(("Out of memory"));
00564     strncpy(entry->driver_name, driver_name, SYSFS_NAME_LEN);
00565     strncpy(entry->device_path, device_path, SYSFS_PATH_MAX);
00566     entry->next = drivers_table_head;
00567     drivers_table_head = entry;
00568 }
00569 
00577 const char* drivers_lookup(const char* device_path)
00578 {
00579     struct driver_entry_s* i;
00580 
00581     for(i=drivers_table_head; i!=NULL; i=i->next)
00582     {
00583         if( strcmp(device_path, i->device_path)==0 )
00584             return i->driver_name;
00585     }
00586     return NULL;
00587 }
00588 
00594 void drivers_collect(const char* bus_name)
00595 {
00596     char path[SYSFS_PATH_MAX];
00597     struct sysfs_directory* current;
00598     struct sysfs_link* current2;
00599     struct sysfs_directory* dir;
00600     struct sysfs_directory* dir2;
00601 
00602     /* traverse /sys/bus/<bus>/drivers */
00603     snprintf(path, SYSFS_PATH_MAX, "%s/bus/%s/drivers", sysfs_mount_path, bus_name);
00604     dir = sysfs_open_directory(path);
00605     if( dir==NULL )
00606     {
00607         HAL_WARNING(("Error opening sysfs directory at %s\n", path));
00608         goto out;
00609     }
00610     if( sysfs_read_directory(dir)!=0 )
00611     {
00612         HAL_WARNING(("Error reading sysfs directory at %s\n", path));
00613         goto out;
00614     }
00615     if( dir->subdirs!=NULL )
00616     {
00617         dlist_for_each_data(dir->subdirs, current, struct sysfs_directory)
00618         {
00619             /*printf("name=%s\n", current->name);*/
00620 
00621             dir2 = sysfs_open_directory(current->path);
00622             if( dir2==NULL )
00623                 DIE(("Error opening sysfs directory at %s\n", current->path));
00624             if( sysfs_read_directory(dir2)!=0 )
00625                 DIE(("Error reading sysfs directory at %s\n", current->path));
00626 
00627             if( dir2->links!=NULL )
00628             {
00629                 dlist_for_each_data(dir2->links, current2, 
00630                                     struct sysfs_link)
00631                 {
00632                     /*printf("  link=%s\n", current2->target);*/
00633                     drivers_add_entry(current->name, current2->target);
00634                 }
00635                 sysfs_close_directory(dir2);
00636             }
00637         }
00638     }
00639 out:
00640     if( dir!=NULL )
00641         sysfs_close_directory(dir);
00642 }
00643 

Generated on Sat Feb 7 22:11:47 2004 for HAL by doxygen 1.3.5