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

conf.c

Go to the documentation of this file.
00001 
00012 /* $Progeny: conf.c 4661 2004-11-18 22:52:00Z licquia $
00013  *
00014  * Copyright 2002 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     DIR *confdir;
00385     struct dirent *confent;
00386     char buf[512];
00387 
00388     assert(status != NULL);
00389 
00390     status->code = 0;
00391 
00392     if (conf_loaded) {
00393         return;
00394     }
00395 
00396     confdir = opendir(SYSCONFDIR "/discover.conf.d");
00397     while ((confent = readdir(confdir)) != NULL) {
00398         if (strchr(confent->d_name, '.') != NULL) {
00399             continue;
00400         }
00401 
00402         context.state = START;
00403         context.status = status;
00404         context.unknown_level = 0;
00405 
00406         parser = XML_ParserCreate(NULL);
00407         XML_SetElementHandler(parser, start_element, end_element);
00408         XML_SetUserData(parser, &context);
00409 
00410         strcpy(buf, "file:///" SYSCONFDIR "/discover.conf.d/");
00411         strncat(buf, confent->d_name, sizeof(buf));
00412         buf[sizeof(buf) - 1] = '\0';
00413 
00414         load_url_status = _discover_load_url(buf, parser);
00415 
00416         /* start_element may change status. */
00417         if (status->code != 0) {
00418             char *message = _discover_xmalloc(256);
00419             snprintf(message, 256, "Error parsing configuration file %s", buf);
00420             status->create_message(&status, message);
00421             XML_ParserFree(parser);
00422             return;
00423         }
00424 
00425         /* Ignore URL load errors because the conf file is not mandatory. */
00426         if (!load_url_status) {
00427             conf_load_error = 1;
00428             XML_ParserFree(parser);
00429             continue;
00430         }
00431 
00432         if (!XML_Parse(parser, "", 0, 1)) {
00433             char *message = _discover_xmalloc(256);
00434             snprintf(message, 256, "Error parsing configuration file %s", buf);
00435             status->create_message(&status, message);
00436             status->code = DISCOVER_EXML;
00437             XML_ParserFree(parser);
00438             return;
00439         }
00440 
00441 
00442         XML_ParserFree(parser);
00443     }
00444 
00445     if (conf_load_error) {
00446         char *message = _discover_xmalloc(256);
00447         snprintf(message, 256, 
00448                  "Failed loading one or more configuration files");
00449         status->create_message(&status, message);
00450     }
00451 
00452     conf_loaded = 1;
00453 
00454     return;
00455 }
00456 
00463 int
00464 discover_conf_name_to_bus(char *name, discover_error_t *status)
00465 {
00466     int i;
00467     for (i = 0; bus_map[i].name; i++) {
00468         if (strcmp(bus_map[i].name, name) == 0) {
00469             return i;
00470         }
00471     }
00472 
00473     status->code = DISCOVER_EBUSNOTFOUND;
00474     return -1;
00475 }
00476 
00482 discover_bus_map_t *
00483 discover_conf_get_full_bus_map(discover_error_t *status)
00484 {
00485     discover_conf_load(status);
00486     return bus_map;
00487 }
00488 
00495 discover_bus_map_t *
00496 discover_conf_get_bus_map_by_name(char *name, discover_error_t *status)
00497 {
00498     assert(status != NULL);
00499 
00500     discover_conf_load(status);
00501     if (status->code != 0) {
00502         return NULL;
00503     }
00504 
00505     /*
00506      * The "real" one won't call conf_load(), which will be useful
00507      * elsewhere.
00508      */
00509     return _real_discover_conf_get_bus_map_by_name(name, status);
00510 }
00511 
00518 discover_bus_map_t *
00519 discover_conf_get_bus_map(discover_bus_t bus, discover_error_t *status)
00520 {
00521     assert(status != NULL);
00522     assert(bus >= 0);
00523 
00524     if (bus >= BUS_COUNT) {
00525         status->code = DISCOVER_EBUSNOTFOUND;
00526     }
00527 
00528     discover_conf_load(status);
00529     if (status->code != 0) {
00530         return NULL;
00531     }
00532 
00533     return (discover_bus_map_t *)(bus_map + bus);
00534 }
00535 
00543 void
00544 discover_conf_insert_url(char *url, discover_error_t *status)
00545 {
00546     assert(status != NULL);
00547 
00548     discover_conf_load(status);
00549     if (status->code != 0) {
00550         return;
00551     }
00552 
00553     _real_discover_conf_insert_url(url, status);
00554 
00555     return;
00556 }
00557 
00565 void
00566 discover_conf_append_url(char *url, discover_error_t *status)
00567 {
00568     assert(status != NULL);
00569 
00570     discover_conf_load(status);
00571     if (status->code != 0) {
00572         return;
00573     }
00574 
00575     _real_discover_conf_append_url(url, status);
00576 
00577     return;
00578 }
00579 
00585 discover_xml_url_t *
00586 discover_conf_get_urls(discover_error_t *status)
00587 {
00588     discover_xml_url_t *new;
00589 
00590     assert(status != NULL);
00591 
00592     status->code = 0;
00593 
00594     if (!urls) {
00595         discover_conf_load(status);
00596 
00597         new = discover_xml_url_new();
00598         new->url = _discover_xstrdup(DISCOVER_DEFAULT_URL);
00599 
00600         if (pre_urls) {
00601             urls = pre_urls;
00602             if (urls->last) {
00603                 urls->last->next = new;
00604             } else {
00605                 urls->next = new;
00606             }
00607             urls->last = new;
00608         } else {
00609             urls = new;
00610         }
00611 
00612         if (post_urls) {
00613             if (urls->last) {
00614                 urls->last->next = post_urls;
00615             } else {
00616                 urls->next = post_urls;
00617             }
00618 
00619             if (post_urls->last) {
00620                 urls->last = post_urls->last;
00621             } else {
00622                 urls->last = post_urls;
00623             }
00624         }
00625 
00626         post_urls = pre_urls = NULL;
00627     }
00628 
00629     return urls;
00630 }
00631 
00636 void
00637 discover_conf_free(void)
00638 {
00639     conf_loaded = 0;
00640 
00641     if (urls) {
00642         discover_xml_url_free(urls);
00643         urls = NULL;
00644     }
00645 }
00646 
00652 char *
00653 discover_conf_get_bus_name(discover_bus_t bus)
00654 {
00655     assert(bus >= 0);
00656     if (bus >= BUS_COUNT) {
00657         return NULL;
00658     }
00659 
00660     return bus_map[bus].name;
00661 }
00662 
00668 char *
00669 discover_conf_get_filetype_name(discover_filetype_t filetype)
00670 {
00671     if (filetype >= 3) {
00672         return NULL;
00673     }
00674 
00675     return filetype_map[filetype];
00676 }
00677 
00680 /*
00681  * Local variables:
00682  * c-file-style: "progeny"
00683  * indent-tabs-mode: nil
00684  * End:
00685  */
00686 /* vim: set cin fo=tcroq sw=4 et sts=4 tw=75: */

Generated on Fri Nov 19 23:57:43 2004 for discover by  doxygen 1.3.9.1