# 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: */