Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals

conf.c

Go to the documentation of this file.
00001 
00012 /* $Progeny$
00013  *
00014  * Copyright 2002-2005 Progeny Linux Systems, Inc.
00015  * Copyright 2002 Hewlett-Packard Company
00016  *
00017  * Permission is hereby granted, free of charge, to any person obtaining a
00018  * copy of this software and associated documentation files (the "Software"),
00019  * to deal in the Software without restriction, including without limitation
00020  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
00021  * and/or sell copies of the Software, and to permit persons to whom the
00022  * Software is furnished to do so, subject to the following conditions:
00023  *
00024  * The above copyright notice and this permission notice shall be included in
00025  * all copies or substantial portions of the Software.
00026  *
00027  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00028  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00029  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
00030  * THE COPYRIGHT HOLDER(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00031  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00032  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00033  * DEALINGS IN THE SOFTWARE.
00034  */
00035 
00036 #include "config.h"
00037 
00038 #if HAVE_DIRENT_H
00039 #include <dirent.h>
00040 #define NAMLEN(d) strlen((d)->d_name)
00041 #else
00042 #define dirent direct
00043 #define NAMLEN(d) (d)->d_namlen
00044 #if HAVE_SYS_NDIR_H
00045 #include <sys/ndir.h>
00046 #endif
00047 #if HAVE_SYS_DIR_H
00048 #include <sys/dir.h>
00049 #endif
00050 #if HAVE_NDIR_H
00051 #include <ndir.h>
00052 #endif
00053 #endif
00054 
00055 #include <assert.h>
00056 #include <string.h>
00057 
00058 #include <expat.h>
00059 
00060 #include <discover/discover.h>
00061 #include <discover/discover-conf.h>
00062 #include <discover/discover-xml.h>
00063 
00064 #include <discover/load-url.h>
00065 #include <discover/url-xml.h>
00066 #include <discover/utils.h>
00067 
00068 /*Busmaps we understand
00069  */
00070 static discover_bus_map_t bus_map[] = {
00071     { "ata", 0, 0, NULL },
00072     { "pci", 0, 0, NULL },
00073     { "pcmcia", 0, 0, NULL },
00074     { "scsi", 0, 0, NULL },
00075     { "usb", 0, 0, NULL },
00076     { NULL }
00077 };
00078 
00079 static char * filetype_map[] = {
00080     "vendor", "busclass", "device"
00081 };
00082 
00083 static int conf_loaded = 0;
00084 
00085 static discover_xml_url_t *pre_urls = NULL;
00086 static discover_xml_url_t *post_urls = NULL;
00087 static discover_xml_url_t *urls = NULL;
00088 
00090 enum state { START, BUSSCAN, DATA_SOURCES };
00091 
00093 enum scan_flag { SCAN_NEVER, SCAN_DEFAULT };
00094 
00095 struct context {
00096     enum state state;
00097     enum scan_flag scan;
00098     discover_error_t *status;
00099 
00100     int unknown_level; 
00101 };
00102 
00103 static char *known_conf_elements[] = {
00104     "bus",
00105     "data-source",
00106     "busscan",
00107     "data-sources",
00108     "conffile",
00109     NULL
00110 };
00111 
00112 
00113 static bool
00114 unknown_conf_element(const XML_Char * const tag)
00115 {
00116     int i;
00117     for (i = 0; known_conf_elements[i] != NULL; i++) {
00118         if (strcmp(tag, known_conf_elements[i]) == 0)
00119             return false;
00120     }
00121     return true;
00122 }
00123 
00124 static enum scan_flag
00125 get_scan_flag(const XML_Char *attrs[])
00126 {
00127     int i;
00128     char *scan;
00129 
00130     assert(attrs != NULL);
00131 
00132     scan = NULL;
00133     for (i = 0; attrs[i]; i+= 2) {
00134         if (strcmp(attrs[i], "scan") == 0) {
00135             scan = (char *)attrs[i + 1];
00136         }
00137     }
00138 
00139     assert(scan != NULL);
00140 
00141     if (strcmp(scan, "default") == 0) {
00142         return SCAN_DEFAULT;
00143     } else {
00144         return SCAN_NEVER;
00145     }
00146 }
00147 
00153 discover_bus_map_t *
00154 _real_discover_conf_get_bus_map(discover_bus_t bus, discover_error_t *status)
00155 {
00156     assert(status != NULL);
00157     assert(bus >= 0);
00158 
00159     if (bus >= BUS_COUNT) {
00160         status->code = DISCOVER_EBUSNOTFOUND;
00161     }
00162 
00163     return (discover_bus_map_t *)(bus_map + bus);
00164 }
00165 
00167 discover_bus_map_t *
00168 _real_discover_conf_get_bus_map_by_name(char *name, discover_error_t *status)
00169 {
00170     discover_bus_t bus;
00171 
00172     assert(status != NULL);
00173 
00174     bus = discover_conf_name_to_bus(name, status);
00175 
00176     if (status->code != 0) {
00177         return NULL;
00178     }
00179 
00180     return _real_discover_conf_get_bus_map(bus, status);
00181 }
00182 
00183 static void
00184 _real_discover_conf_insert_url(char *url, discover_error_t *status)
00185 {
00186     discover_xml_url_t *new;
00187 
00188     assert(url != NULL);
00189     assert(status != NULL);
00190 
00191     status->code = 0;
00192 
00193     new = discover_xml_url_new();
00194     new->url = _discover_xstrdup(url);
00195 
00196     new->next = pre_urls;
00197     if (pre_urls) {
00198         if (pre_urls->last) {
00199             new->last = pre_urls->last;
00200         } else {
00201             new->last = pre_urls;
00202         }
00203     } else {
00204         new->last = NULL;
00205     }
00206 
00207     pre_urls = new;
00208 }
00209 
00210 static void
00211 _real_discover_conf_append_url(char *url, discover_error_t *status)
00212 {
00213     discover_xml_url_t *new;
00214 
00215     assert(url != NULL);
00216     assert(status != NULL);
00217 
00218     status->code = 0;
00219 
00220     new = discover_xml_url_new();
00221     new->url = _discover_xstrdup(url);
00222 
00223     if (post_urls) {
00224         if (post_urls->last) {
00225             post_urls->last->next = new;
00226         } else {
00227             post_urls->next = new;
00228         }
00229         post_urls->last = new;
00230     } else {
00231         post_urls = new;
00232         post_urls->next = NULL;
00233         post_urls->last = NULL;
00234     }
00235 }
00236 
00237 static void
00238 start_element(void *ctx, const XML_Char *name, const XML_Char *attrs[])
00239 {
00240     struct context *context = ctx;
00241     discover_bus_map_t *busmap;
00242     discover_error_t *status;
00243     char *busname;
00244     char *found_url;
00245     int prepend_url;
00246     int i;
00247 
00248     assert(context != NULL);
00249     assert(name != NULL);
00250 
00251     if (unknown_conf_element(name)) {
00252         context->unknown_level++;
00253         return;
00254     }
00255 
00256     if (context->unknown_level > 0) {
00257         return;
00258     }
00259 
00260     status = context->status;
00261 
00262     switch (context->state) {
00263     case START:
00264         if (strcmp(name, "busscan") == 0) {
00265             context->state = BUSSCAN;
00266             context->scan = get_scan_flag(attrs);
00267         } else if (strcmp(name, "data-sources") == 0) {
00268             context->state = DATA_SOURCES;
00269         }
00270         break;
00271 
00272     case BUSSCAN:
00273         if (strcmp(name, "bus") == 0) {
00274             assert(attrs != NULL);
00275 
00276             for (i = 0; attrs[i]; i += 2) {
00277                 if (strcmp(attrs[i], "name") == 0) {
00278                     busname = (char *)attrs[i + 1];
00279                     busmap = _real_discover_conf_get_bus_map_by_name(busname, status);
00280                     if (status->code != 0) {
00281                         return;
00282                     }
00283                     if (context->scan == SCAN_DEFAULT) {
00284                         busmap->scan_default = 1;
00285                     } else {
00286                         busmap->scan_never = 1;
00287                     }
00288                 }
00289             }
00290         }
00291         break;
00292 
00293     case DATA_SOURCES:
00294         if (strcmp(name, "data-source") == 0) {
00295             found_url = NULL;
00296             prepend_url = 0;
00297             for (i = 0; attrs[i]; i += 2) {
00298                 if (strcmp(attrs[i], "url") == 0) {
00299                     found_url = (char *)attrs[i + 1];
00300                 }
00301                 else if ((strcmp(attrs[i], "place") == 0) &&
00302                          (strcmp(attrs[i + 1], "before") == 0)) {
00303                     prepend_url = 1;
00304                 }
00305             }
00306             if (found_url != NULL) {
00307                 if (prepend_url != 0) {
00308                     _real_discover_conf_insert_url(found_url, status);
00309                 } else {
00310                     _real_discover_conf_append_url(found_url, status);
00311                 }
00312                 if (status->code != 0) {
00313                     return;
00314                 }
00315             }
00316         }
00317         break;
00318     }
00319 }
00320 
00321 static void
00322 end_element(void *ctx, const XML_Char *name)
00323 {
00324     struct context *context = ctx;
00325 
00326     assert(context != NULL);
00327     assert(name != NULL);
00328 
00329     if (unknown_conf_element(name)) {
00330         context->unknown_level--;
00331         return;
00332     }
00333 
00334     if (context->unknown_level > 0) {
00335         return;
00336     }
00337 
00338     switch (context->state) {
00339     case START:
00340     break;
00341 
00342     case BUSSCAN:
00343         if (strcmp(name, "busscan") == 0) {
00344             context->state = START;
00345         }
00346     break;
00347 
00348     case DATA_SOURCES:
00349         if (strcmp(name, "data-sources") == 0) {
00350             context->state = START;
00351         }
00352     break;
00353     }
00354 }
00355 
00377 void
00378 discover_conf_load(discover_error_t *status)
00379 {
00380     XML_Parser parser;
00381     struct context context;
00382     int load_url_status;
00383     int conf_load_error = 0;
00384     int conf_parse_error = 0;
00385     DIR *confdir;
00386     struct dirent *confent;
00387     char buf[512];
00388 
00389     assert(status != NULL);
00390 
00391     status->code = 0;
00392 
00393     if (conf_loaded) {
00394         return;
00395     }
00396 
00397     confdir = opendir(SYSCONFDIR "/discover.conf.d");
00398     if (confdir != NULL) {
00399         while ((confent = readdir(confdir)) != NULL) {
00400             if (strchr(confent->d_name, '.') != NULL) {
00401                 continue;
00402             }
00403 
00404             context.state = START;
00405             context.status = status;
00406             context.unknown_level = 0;
00407 
00408             parser = XML_ParserCreate(NULL);
00409             XML_SetElementHandler(parser, start_element, end_element);
00410             XML_SetUserData(parser, &context);
00411 
00412             strcpy(buf, "file:///" SYSCONFDIR "/discover.conf.d/");
00413             strncat(buf, confent->d_name, sizeof(buf));
00414             buf[sizeof(buf) - 1] = '\0';
00415 
00416             load_url_status = _discover_load_url(buf, parser);
00417 
00418             /* start_element may change status. */
00419             if (status->code != 0) {
00420                 char *message = _discover_xmalloc(256);
00421                 snprintf(message, 256, "Error parsing configuration file %s", 
00422                          buf);
00423                 status->create_message(&status, message);
00424                 XML_ParserFree(parser);
00425                 conf_parse_error = 1;
00426                 break;
00427             }
00428 
00429             /* Ignore URL load errors; the conf file is not mandatory. */
00430             if (!load_url_status) {
00431                 conf_load_error = 1;
00432                 XML_ParserFree(parser);
00433                 continue;
00434             }
00435 
00436             if (!XML_Parse(parser, "", 0, 1)) {
00437                 char *message = _discover_xmalloc(256);
00438                 snprintf(message, 256, "Error parsing configuration file %s", 
00439                          buf);
00440                 status->create_message(&status, message);
00441                 status->code = DISCOVER_EXML;
00442                 XML_ParserFree(parser);
00443                 conf_parse_error = 1;
00444                 break;
00445             }
00446 
00447 
00448             XML_ParserFree(parser);
00449         }
00450 
00451         closedir(confdir);
00452 
00453         if (conf_parse_error) {
00454             return;
00455         }
00456     }
00457 
00458     if (conf_load_error) {
00459         char *message = _discover_xmalloc(256);
00460         snprintf(message, 256, 
00461                  "Failed loading one or more configuration files");
00462         status->create_message(&status, message);
00463     }
00464 
00465     conf_loaded = 1;
00466 
00467     return;
00468 }
00469 
00476 int
00477 discover_conf_name_to_bus(char *name, discover_error_t *status)
00478 {
00479     int i;
00480     for (i = 0; bus_map[i].name; i++) {
00481         if (strcmp(bus_map[i].name, name) == 0) {
00482             return i;
00483         }
00484     }
00485 
00486     status->code = DISCOVER_EBUSNOTFOUND;
00487     return -1;
00488 }
00489 
00495 discover_bus_map_t *
00496 discover_conf_get_full_bus_map(discover_error_t *status)
00497 {
00498     discover_conf_load(status);
00499     return bus_map;
00500 }
00501 
00508 discover_bus_map_t *
00509 discover_conf_get_bus_map_by_name(char *name, discover_error_t *status)
00510 {
00511     assert(status != NULL);
00512 
00513     discover_conf_load(status);
00514     if (status->code != 0) {
00515         return NULL;
00516     }
00517 
00518     /*
00519      * The "real" one won't call conf_load(), which will be useful
00520      * elsewhere.
00521      */
00522     return _real_discover_conf_get_bus_map_by_name(name, status);
00523 }
00524 
00531 discover_bus_map_t *
00532 discover_conf_get_bus_map(discover_bus_t bus, discover_error_t *status)
00533 {
00534     assert(status != NULL);
00535     assert(bus >= 0);
00536 
00537     if (bus >= BUS_COUNT) {
00538         status->code = DISCOVER_EBUSNOTFOUND;
00539     }
00540 
00541     discover_conf_load(status);
00542     if (status->code != 0) {
00543         return NULL;
00544     }
00545 
00546     return (discover_bus_map_t *)(bus_map + bus);
00547 }
00548 
00556 void
00557 discover_conf_insert_url(char *url, discover_error_t *status)
00558 {
00559     assert(status != NULL);
00560 
00561     discover_conf_load(status);
00562     if (status->code != 0) {
00563         return;
00564     }
00565 
00566     _real_discover_conf_insert_url(url, status);
00567 
00568     return;
00569 }
00570 
00578 void
00579 discover_conf_append_url(char *url, discover_error_t *status)
00580 {
00581     assert(status != NULL);
00582 
00583     discover_conf_load(status);
00584     if (status->code != 0) {
00585         return;
00586     }
00587 
00588     _real_discover_conf_append_url(url, status);
00589 
00590     return;
00591 }
00592 
00598 discover_xml_url_t *
00599 discover_conf_get_urls(discover_error_t *status)
00600 {
00601     discover_xml_url_t *new;
00602 
00603     assert(status != NULL);
00604 
00605     status->code = 0;
00606 
00607     if (!urls) {
00608         discover_conf_load(status);
00609 
00610         new = discover_xml_url_new();
00611         new->url = _discover_xstrdup(DISCOVER_DEFAULT_URL);
00612 
00613         if (pre_urls) {
00614             urls = pre_urls;
00615             if (urls->last) {
00616                 urls->last->next = new;
00617             } else {
00618                 urls->next = new;
00619             }
00620             urls->last = new;
00621         } else {
00622             urls = new;
00623         }
00624 
00625         if (post_urls) {
00626             if (urls->last) {
00627                 urls->last->next = post_urls;
00628             } else {
00629                 urls->next = post_urls;
00630             }
00631 
00632             if (post_urls->last) {
00633                 urls->last = post_urls->last;
00634             } else {
00635                 urls->last = post_urls;
00636             }
00637         }
00638 
00639         post_urls = pre_urls = NULL;
00640     }
00641 
00642     return urls;
00643 }
00644 
00649 void
00650 discover_conf_free(void)
00651 {
00652     conf_loaded = 0;
00653 
00654     if (urls) {
00655         discover_xml_url_free(urls);
00656         urls = NULL;
00657     }
00658 }
00659 
00665 char *
00666 discover_conf_get_bus_name(discover_bus_t bus)
00667 {
00668     assert(bus >= 0);
00669     if (bus >= BUS_COUNT) {
00670         return NULL;
00671     }
00672 
00673     return bus_map[bus].name;
00674 }
00675 
00681 char *
00682 discover_conf_get_filetype_name(discover_filetype_t filetype)
00683 {
00684     if (filetype >= 3) {
00685         return NULL;
00686     }
00687 
00688     return filetype_map[filetype];
00689 }
00690 
00693 /*
00694  * Local variables:
00695  * c-file-style: "progeny"
00696  * indent-tabs-mode: nil
00697  * End:
00698  */
00699 /* vim: set cin fo=tcroq sw=4 et sts=4 tw=75: */

Generated on Thu Jul 28 03:38:00 2005 for discover by  doxygen 1.4.2