src/dbapi/driver/ftds64/freetds/tds/config.c

Go to the documentation of this file.
00001 /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
00002  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005  Brian Bruns
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 #if HAVE_CONFIG_H
00021 #include <config.h>
00022 #endif
00023 
00024 #if HAVE_ERRNO_H
00025 #include <errno.h>
00026 #endif /* HAVE_ERRNO_H */
00027 
00028 #include <assert.h>
00029 #include <ctype.h>
00030 #include <stdio.h>
00031 
00032 #if HAVE_STDLIB_H
00033 #include <stdlib.h>
00034 #endif /* HAVE_STDLIB_H */
00035 
00036 #if HAVE_STRING_H
00037 #include <string.h>
00038 #endif /* HAVE_STRING_H */
00039 
00040 #if HAVE_UNISTD_H
00041 #include <unistd.h>
00042 #endif /* HAVE_UNISTD_H */
00043 
00044 #if HAVE_NETDB_H
00045 #include <netdb.h>
00046 #endif /* HAVE_NETDB_H */
00047 
00048 #if HAVE_SYS_SOCKET_H
00049 #include <sys/socket.h>
00050 #endif /* HAVE_SYS_SOCKET_H */
00051 
00052 #if HAVE_SYS_TYPES_H
00053 #include <sys/types.h>
00054 #endif /* HAVE_SYS_TYPES_H */
00055 
00056 #if HAVE_NETINET_IN_H
00057 #include <netinet/in.h>
00058 #endif /* HAVE_NETINET_IN_H */
00059 
00060 #if HAVE_ARPA_INET_H
00061 #include <arpa/inet.h>
00062 #endif /* HAVE_ARPA_INET_H */
00063 
00064 #ifdef WIN32
00065 #include <process.h>
00066 #endif
00067 
00068 #include "tds.h"
00069 #include "tds_configs.h"
00070 #include "tdsstring.h"
00071 #include "replacements.h"
00072 #ifdef DMALLOC
00073 #include <dmalloc.h>
00074 #endif
00075 
00076 TDS_RCSID(var, "$Id: config.c 122952 2008-03-26 21:16:10Z ivanovp $");
00077 
00078 
00079 static void tds_config_login(TDSCONNECTION * connection, TDSLOGIN * login);
00080 static void tds_config_env_tdsquery(TDSCONNECTION * connection);
00081 static void tds_config_env_tdsdump(TDSCONNECTION * connection);
00082 static void tds_config_env_tdsver(TDSCONNECTION * connection);
00083 static void tds_config_env_tdsport(TDSCONNECTION * connection);
00084 static void tds_config_env_tdshost(TDSCONNECTION * connection);
00085 static int tds_read_conf_sections(FILE * in, const char *server, TDSCONNECTION * connection);
00086 static void tds_parse_conf_section(const char *option, const char *value, void *param);
00087 static void tds_read_interfaces(const char *server, TDSCONNECTION * connection);
00088 static int tds_config_boolean(const char *value);
00089 static int parse_server_name_for_port(TDSCONNECTION * connection, TDSLOGIN * login);
00090 static int tds_lookup_port(const char *portname);
00091 
00092 extern int tds_g_append_mode;
00093 
00094 static char *interf_file = NULL;
00095 
00096 #define TDS_ISSPACE(c) isspace((unsigned char ) (c))
00097 
00098 /**
00099  * \ingroup libtds
00100  * \defgroup config Configuration
00101  * Handle reading of configuration
00102  */
00103 
00104 /**
00105  * \addtogroup config
00106  * \@{ 
00107  */
00108 
00109 /**
00110  * tds_read_config_info() will fill the tds connection structure based on configuration 
00111  * information gathered in the following order:
00112  * 1) Program specified in TDSLOGIN structure
00113  * 2) The environment variables TDSVER, TDSDUMP, TDSPORT, TDSQUERY, TDSHOST
00114  * 3) A config file with the following search order:
00115  *    a) a readable file specified by environment variable FREETDSCONF
00116  *    b) a readable file in ~/.freetds.conf
00117  *    c) a readable file in $prefix/etc/freetds.conf
00118  * 3) ~/.interfaces if exists
00119  * 4) $SYBASE/interfaces if exists
00120  * 5) TDS_DEF_* default values
00121  *
00122  * .tdsrc and freetds.conf have been added to make the package easier to 
00123  * integration with various Linux and *BSD distributions.
00124  */
00125 TDSCONNECTION *
00126 tds_read_config_info(TDSSOCKET * tds, TDSLOGIN * login, TDSLOCALE * locale)
00127 {
00128     TDSCONNECTION *connection;
00129     char *s;
00130     char *path;
00131     pid_t pid;
00132     int opened = 0;
00133 
00134     /* allocate a new structure with hard coded and build-time defaults */
00135     connection = tds_alloc_connection(locale);
00136     if (!connection)
00137         return NULL;
00138 
00139     s = getenv("TDSDUMPCONFIG");
00140     if (s) {
00141         if (*s) {
00142             opened = tdsdump_open(s);
00143         } else {
00144             pid = getpid();
00145 #if !defined(WIN32) && !defined(DOS32X)
00146             if (asprintf(&path, "/tmp/tdsconfig.log.%d", pid) >= 0) {
00147 #else
00148             if (asprintf(&path, "c:\\tdsconfig.log.%d", pid) >= 0) {
00149 #endif
00150                 if (*path) {
00151                     opened = tdsdump_open(path);
00152                 }
00153                 free(path);
00154             }
00155         }
00156     }
00157 
00158     tdsdump_log(TDS_DBG_INFO1, "Attempting to read conf files.\n");
00159     if (!tds_read_conf_file(connection, tds_dstr_cstr(&login->server_name))) {
00160         /* fallback to interfaces file */
00161         tdsdump_log(TDS_DBG_INFO1, "Failed in reading conf file.  Trying interface files.\n");
00162         tds_read_interfaces(tds_dstr_cstr(&login->server_name), connection);
00163     }
00164 
00165     if (parse_server_name_for_port(connection, login)) {
00166         tdsdump_log(TDS_DBG_INFO1, "Parsed servername, now %s on %d.\n", tds_dstr_cstr(&connection->server_name), login->port);
00167     }
00168 
00169     tds_fix_connection(connection);
00170 
00171     /* And finally the login structure */
00172     tds_config_login(connection, login);
00173 
00174     if (opened) {
00175         tdsdump_close();
00176     }
00177     return connection;
00178 }
00179 
00180 /**
00181  * Fix configuration after reading it. 
00182  * Currently this read some environment variables and replace some options.
00183  */
00184 void
00185 tds_fix_connection(TDSCONNECTION * connection)
00186 {
00187     /* Now check the environment variables */
00188     tds_config_env_tdsver(connection);
00189     tds_config_env_tdsdump(connection);
00190     tds_config_env_tdsport(connection);
00191     tds_config_env_tdsquery(connection);
00192     tds_config_env_tdshost(connection);
00193 }
00194 
00195 static int
00196 tds_try_conf_file(const char *path, const char *how, const char *server, TDSCONNECTION * connection)
00197 {
00198     int found = 0;
00199     FILE *in;
00200 
00201     if ((in = fopen(path, "r")) != NULL) {
00202         tdsdump_log(TDS_DBG_INFO1, "Found conf file '%s' %s. Reading section '%s'.\n", path, how, server);
00203         found = tds_read_conf_sections(in, server, connection);
00204 
00205         if (found) {
00206             tdsdump_log(TDS_DBG_INFO1, "...Success.\n");
00207         } else {
00208             tdsdump_log(TDS_DBG_INFO2, "...'%s' not found.\n", server);
00209         }
00210 
00211         fclose(in);
00212     }
00213     return found;
00214 }
00215 
00216 
00217 /**
00218  * Return filename from HOME directory
00219  * @return allocated string or NULL if error
00220  */
00221 static char *
00222 tds_get_home_file(const char *file)
00223 {
00224     char *home, *path;
00225 
00226     home = tds_get_homedir();
00227     if (!home)
00228         return NULL;
00229     if (asprintf(&path, "%s" TDS_SDIR_SEPARATOR "%s", home, file) < 0)
00230         path = NULL;
00231     free(home);
00232     return path;
00233 }
00234 
00235 /**
00236  * Read configuration info for given server
00237  * return 0 on error
00238  * @param connection where to store configuration
00239  * @param server       section of file configuration that hold 
00240  *                     configuration for a server
00241  */
00242 int
00243 tds_read_conf_file(TDSCONNECTION * connection, const char *server)
00244 {
00245     char *path = NULL;
00246     char *eptr = NULL;
00247     int found = 0;
00248 
00249     if (interf_file) {
00250         found = tds_try_conf_file(interf_file, "set programmatically", server, connection);
00251     }
00252 
00253     /* FREETDSCONF env var, pkleef@openlinksw.com 01/21/02 */
00254     if (!found) {
00255         path = getenv("FREETDSCONF");
00256         if (path) {
00257             found = tds_try_conf_file(path, "(from $FREETDSCONF)", server, connection);
00258         } else {
00259             tdsdump_log(TDS_DBG_INFO2, "...$FREETDSCONF not set.  Trying $FREETDS/etc.\n");
00260         }
00261     }
00262 
00263     /* FREETDS env var, Bill Thompson 16/07/03 */
00264     if (!found) {
00265         eptr = getenv("FREETDS");
00266         if (eptr) {
00267 #if !defined(WIN32) && !defined(DOS32X)
00268             asprintf(&path, "%s/etc/freetds.conf", eptr);
00269             found = tds_try_conf_file(path, "(from $FREETDS/etc)", server, connection);
00270 #else
00271             asprintf(&path, "%s\\freetds.conf", eptr);
00272             found = tds_try_conf_file(path, "(from $FREETDS)", server, connection);
00273 #endif
00274         } else {
00275             tdsdump_log(TDS_DBG_INFO2, "...$FREETDS not set.  Trying $HOME.\n");
00276         }
00277     }
00278 
00279     if (!found) {
00280         path = tds_get_home_file(".freetds.conf");
00281         if (path) {
00282             found = tds_try_conf_file(path, "(.freetds.conf)", server, connection);
00283             free(path);
00284         } else {
00285             tdsdump_log(TDS_DBG_INFO2, "...Error getting ~/.freetds.conf.  Trying %s.\n", FREETDS_SYSCONFFILE);
00286         }
00287     }
00288 
00289     if (!found) {
00290         found = tds_try_conf_file(FREETDS_SYSCONFFILE, "(default)", server, connection);
00291     }
00292 
00293     return found;
00294 }
00295 
00296 static int
00297 tds_read_conf_sections(FILE * in, const char *server, TDSCONNECTION * connection)
00298 {
00299     tds_read_conf_section(in, "global", tds_parse_conf_section, connection);
00300     rewind(in);
00301     return tds_read_conf_section(in, server, tds_parse_conf_section, connection);
00302 }
00303 
00304 static int
00305 tds_config_boolean(const char *value)
00306 {
00307     if (!strcmp(value, "yes") || !strcmp(value, "on") || !strcmp(value, "true") || !strcmp(value, "1")) {
00308         tdsdump_log(TDS_DBG_INFO1, "%s is a 'yes/on/true'.\n", value);
00309         return 1;
00310     } else {
00311         tdsdump_log(TDS_DBG_INFO1, "%s is a 'no/off/false'.\n", value);
00312         return 0;
00313     }
00314 }
00315 
00316 /**
00317  * Read a section of configuration file (INI style file)
00318  * @param in             configuration file
00319  * @param section        section to read
00320  * @param tds_conf_parse callback that receive every entry in section
00321  * @param param          parameter to pass to callback function
00322  */
00323 int
00324 tds_read_conf_section(FILE * in, const char *section, TDSCONFPARSE tds_conf_parse, void *param)
00325 {
00326     char line[256], option[256], value[256];
00327     char *s;
00328     char p;
00329     int i;
00330     int insection = 0;
00331     int found = 0;
00332 
00333     tdsdump_log(TDS_DBG_INFO1, "Looking for section %s.\n", section);
00334     while (fgets(line, 256, in)) {
00335         s = line;
00336 
00337         /* skip leading whitespace */
00338         while (*s && TDS_ISSPACE(*s))
00339             s++;
00340 
00341         /* skip it if it's a comment line */
00342         if (*s == ';' || *s == '#')
00343             continue;
00344 
00345         /* read up to the = ignoring duplicate spaces */
00346         p = 0;
00347         i = 0;
00348         while (*s && *s != '=') {
00349             if (!TDS_ISSPACE(*s) && TDS_ISSPACE(p))
00350                 option[i++] = ' ';
00351             if (!TDS_ISSPACE(*s))
00352                 option[i++] = tolower((unsigned char) *s);
00353             p = *s;
00354             s++;
00355         }
00356         option[i] = '\0';
00357 
00358         /* skip the = */
00359         if (*s)
00360             s++;
00361 
00362         /* skip leading whitespace */
00363         while (*s && TDS_ISSPACE(*s))
00364             s++;
00365 
00366         /* read up to a # ; or null ignoring duplicate spaces */
00367         p = 0;
00368         i = 0;
00369         while (*s && *s != ';' && *s != '#') {
00370             if (!TDS_ISSPACE(*s) && TDS_ISSPACE(p))
00371                 value[i++] = ' ';
00372             if (!TDS_ISSPACE(*s))
00373                 value[i++] = *s;
00374             p = *s;
00375             s++;
00376         }
00377         value[i] = '\0';
00378 
00379         if (!strlen(option))
00380             continue;
00381 
00382         if (option[0] == '[') {
00383             s = &option[1];
00384             while (*s) {
00385                 if (*s == ']')
00386                     *s = '\0';
00387                 *s = tolower((unsigned char) *s);
00388                 s++;
00389             }
00390             tdsdump_log(TDS_DBG_INFO1, "... Found section %s.\n", &option[1]);
00391 
00392             if (!strcasecmp(section, &option[1])) {
00393                 tdsdump_log(TDS_DBG_INFO1, "Got a match.\n");
00394                 insection = 1;
00395                 found = 1;
00396             } else {
00397                 insection = 0;
00398             }
00399         } else if (insection) {
00400             tds_conf_parse(option, value, param);
00401         }
00402 
00403     }
00404     return found;
00405 }
00406 
00407 static void
00408 tds_parse_conf_section(const char *option, const char *value, void *param)
00409 {
00410     TDSCONNECTION *connection = (TDSCONNECTION *) param;
00411     char tmp[256];
00412 
00413     tdsdump_log(TDS_DBG_INFO1, "option = '%s' value = '%s'.\n", option, value);
00414 
00415     if (!strcmp(option, TDS_STR_VERSION)) {
00416         tds_config_verstr(value, connection);
00417     } else if (!strcmp(option, TDS_STR_BLKSZ)) {
00418         if (atoi(value))
00419             connection->block_size = atoi(value);
00420     } else if (!strcmp(option, TDS_STR_SWAPDT)) {
00421         connection->broken_dates = tds_config_boolean(value);
00422     } else if (!strcmp(option, TDS_STR_SWAPMNY)) {
00423         connection->broken_money = tds_config_boolean(value);
00424     } else if (!strcmp(option, TDS_STR_DUMPFILE)) {
00425         tds_dstr_copy(&connection->dump_file, value);
00426     } else if (!strcmp(option, TDS_STR_DEBUGFLAGS)) {
00427         char *end;
00428         long l;
00429         errno = 0;
00430         l = strtol(value, &end, 0);
00431         if (errno == 0 && *end == 0)
00432             connection->debug_flags = l;
00433     } else if (!strcmp(option, TDS_STR_TIMEOUT) || !strcmp(option, TDS_STR_QUERY_TIMEOUT)) {
00434         if (atoi(value))
00435             connection->query_timeout = atoi(value);
00436     } else if (!strcmp(option, TDS_STR_CONNTIMEOUT)) {
00437         if (atoi(value))
00438             connection->connect_timeout = atoi(value);
00439     } else if (!strcmp(option, TDS_STR_HOST)) {
00440         tdsdump_log(TDS_DBG_INFO1, "Found host entry %s.\n", value);
00441         tds_lookup_host(value, tmp);
00442         tds_dstr_copy(&connection->ip_addr, tmp);
00443         tdsdump_log(TDS_DBG_INFO1, "IP addr is %s.\n", tds_dstr_cstr(&connection->ip_addr));
00444     } else if (!strcmp(option, TDS_STR_PORT)) {
00445         if (atoi(value))
00446             connection->port = atoi(value);
00447     } else if (!strcmp(option, TDS_STR_EMUL_LE)) {
00448         connection->emul_little_endian = tds_config_boolean(value);
00449     } else if (!strcmp(option, TDS_STR_TEXTSZ)) {
00450         if (atoi(value))
00451             connection->text_size = atoi(value);
00452     } else if (!strcmp(option, TDS_STR_CHARSET)) {
00453         tds_dstr_copy(&connection->server_charset, value);
00454         tdsdump_log(TDS_DBG_INFO1, "%s is %s.\n", option, tds_dstr_cstr(&connection->server_charset));
00455     } else if (!strcmp(option, TDS_STR_CLCHARSET)) {
00456         tds_dstr_copy(&connection->client_charset, value);
00457         tdsdump_log(TDS_DBG_INFO1, "tds_config_login: %s is %s.\n", option, tds_dstr_cstr(&connection->client_charset));
00458     } else if (!strcmp(option, TDS_STR_LANGUAGE)) {
00459         tds_dstr_copy(&connection->language, value);
00460     } else if (!strcmp(option, TDS_STR_APPENDMODE)) {
00461         tds_g_append_mode = tds_config_boolean(value);
00462     } else if (!strcmp(option, TDS_STR_INSTANCE)) {
00463         tds_dstr_copy(&connection->instance_name, value);
00464     } else {
00465         tdsdump_log(TDS_DBG_INFO1, "UNRECOGNIZED option '%s'...ignoring.\n", option);
00466     }
00467 }
00468 
00469 static void
00470 tds_config_login(TDSCONNECTION * connection, TDSLOGIN * login)
00471 {
00472     if (!tds_dstr_isempty(&login->server_name)) {
00473         tds_dstr_copy(&connection->server_name, tds_dstr_cstr(&login->server_name));
00474     }
00475     /*if (login->major_version || login->minor_version) {*/
00476         connection->major_version = login->major_version;
00477         connection->minor_version = login->minor_version;
00478     /*}*/
00479     if (!tds_dstr_isempty(&login->language)) {
00480         tds_dstr_copy(&connection->language, tds_dstr_cstr(&login->language));
00481     }
00482     if (!tds_dstr_isempty(&login->server_charset)) {
00483         tds_dstr_copy(&connection->server_charset, tds_dstr_cstr(&login->server_charset));
00484     }
00485     if (!tds_dstr_isempty(&login->client_charset)) {
00486         tds_dstr_copy(&connection->client_charset, tds_dstr_cstr(&login->client_charset));
00487         tdsdump_log(TDS_DBG_INFO1, "tds_config_login: %s is %s.\n", "client_charset",
00488                 tds_dstr_cstr(&connection->client_charset));
00489     }
00490     if (!tds_dstr_isempty(&login->client_host_name)) {
00491         tds_dstr_copy(&connection->client_host_name, tds_dstr_cstr(&login->client_host_name));
00492         /*
00493          * DBSETLHOST and it's equivilants are commentary fields
00494          * they don't affect connection->ip_addr (the server) but they show
00495          * up in an sp_who as the *clients* hostname.  (bsb, 11/10) 
00496          */
00497         /* should work with IP (mlilback, 11/7/01) */
00498         /*
00499          * if (connection->ip_addr) free(connection->ip_addr);
00500          * connection->ip_addr = calloc(sizeof(char),18);
00501          * tds_lookup_host(connection->host_name, NULL, connection->ip_addr, NULL);
00502          */
00503     }
00504     if (!tds_dstr_isempty(&login->app_name)) {
00505         tds_dstr_copy(&connection->app_name, tds_dstr_cstr(&login->app_name));
00506     }
00507     if (!tds_dstr_isempty(&login->user_name)) {
00508         tds_dstr_copy(&connection->user_name, tds_dstr_cstr(&login->user_name));
00509     }
00510     if (!tds_dstr_isempty(&login->password)) {
00511         /* for security reason clear memory */
00512         tds_dstr_zero(&connection->password);
00513         tds_dstr_copy(&connection->password, tds_dstr_cstr(&login->password));
00514     }
00515     if (!tds_dstr_isempty(&login->library)) {
00516         tds_dstr_copy(&connection->library, tds_dstr_cstr(&login->library));
00517     }
00518     if (login->encrypted) {
00519         connection->encrypted = 1;
00520     }
00521     if (login->suppress_language) {
00522         connection->suppress_language = 1;
00523     }
00524     if (login->bulk_copy) {
00525         connection->bulk_copy = 1;
00526     }
00527     if (login->block_size) {
00528         connection->block_size = login->block_size;
00529     }
00530     if (login->port) {
00531         connection->port = login->port;
00532         tds_dstr_copy(&connection->instance_name, "");
00533     }
00534     if (login->connect_timeout)
00535         connection->connect_timeout = login->connect_timeout;
00536 
00537     if (login->query_timeout)
00538         connection->query_timeout = login->query_timeout;
00539 
00540     /* copy other info not present in configuration file */
00541     memcpy(connection->capabilities, login->capabilities, TDS_MAX_CAPABILITY);
00542 }
00543 
00544 static void
00545 tds_config_env_tdsquery(TDSCONNECTION * connection)
00546 {
00547     char *s;
00548 
00549     if ((s = getenv("TDSQUERY")) != NULL && s[0]) {
00550         tds_dstr_copy(&connection->server_name, s);
00551         tdsdump_log(TDS_DBG_INFO1, "Setting 'server_name' to '%s' from $TDSQUERY.\n", s);
00552         return;
00553     }
00554     if ((s = getenv("DSQUERY")) != NULL && s[0]) {
00555         tds_dstr_copy(&connection->server_name, s);
00556         tdsdump_log(TDS_DBG_INFO1, "Setting 'server_name' to '%s' from $DSQUERY.\n", s);
00557     }
00558 }
00559 static void
00560 tds_config_env_tdsdump(TDSCONNECTION * connection)
00561 {
00562     char *s;
00563     char *path;
00564     pid_t pid = 0;
00565 
00566     if ((s = getenv("TDSDUMP"))) {
00567         if (!strlen(s)) {
00568             pid = getpid();
00569 #if !defined(WIN32) && !defined(DOS32X)
00570             if (asprintf(&path, "/tmp/freetds.log.%d", pid) >= 0)
00571 #else
00572             if (asprintf(&path, "c:\\freetds.log.%d", pid) >= 0)
00573 #endif
00574                 tds_dstr_set(&connection->dump_file, path);
00575         } else {
00576             tds_dstr_copy(&connection->dump_file, s);
00577         }
00578         tdsdump_log(TDS_DBG_INFO1, "Setting 'dump_file' to '%s' from $TDSDUMP.\n", tds_dstr_cstr(&connection->dump_file));
00579     }
00580 }
00581 static void
00582 tds_config_env_tdsport(TDSCONNECTION * connection)
00583 {
00584     char *s;
00585 
00586     if ((s = getenv("TDSPORT"))) {
00587         connection->port = tds_lookup_port(s);
00588         tds_dstr_copy(&connection->instance_name, "");
00589         tdsdump_log(TDS_DBG_INFO1, "Setting 'port' to %s from $TDSPORT.\n", s);
00590     }
00591     return;
00592 }
00593 static void
00594 tds_config_env_tdsver(TDSCONNECTION * connection)
00595 {
00596     char *tdsver;
00597 
00598     if ((tdsver = getenv("TDSVER"))) {
00599         tds_config_verstr(tdsver, connection);
00600         tdsdump_log(TDS_DBG_INFO1, "Setting 'tdsver' to %s from $TDSVER.\n", tdsver);
00601 
00602     }
00603     return;
00604 }
00605 
00606 /* TDSHOST env var, pkleef@openlinksw.com 01/21/02 */
00607 static void
00608 tds_config_env_tdshost(TDSCONNECTION * connection)
00609 {
00610     char *tdshost;
00611     char tmp[256];
00612 
00613     if ((tdshost = getenv("TDSHOST"))) {
00614         tds_lookup_host(tdshost, tmp);
00615         tds_dstr_copy(&connection->ip_addr, tmp);
00616         tdsdump_log(TDS_DBG_INFO1, "Setting 'ip_addr' to %s (%s) from $TDSHOST.\n", tmp, tdshost);
00617 
00618     }
00619     return;
00620 }
00621 
00622 /**
00623  * Set TDS version from given string
00624  * @param tdsver tds string version
00625  * @param connection where to store information
00626  */
00627 void
00628 tds_config_verstr(const char *tdsver, TDSCONNECTION * connection)
00629 {
00630     if (!strcmp(tdsver, "42") || !strcmp(tdsver, "4.2")) {
00631         connection->major_version = 4;
00632         connection->minor_version = 2;
00633         return;
00634     } else if (!strcmp(tdsver, "46") || !strcmp(tdsver, "4.6")) {
00635         connection->major_version = 4;
00636         connection->minor_version = 6;
00637         return;
00638     } else if (!strcmp(tdsver, "50") || !strcmp(tdsver, "5.0")) {
00639         connection->major_version = 5;
00640         connection->minor_version = 0;
00641         return;
00642     } else if (!strcmp(tdsver, "70") || !strcmp(tdsver, "7.0")) {
00643         connection->major_version = 7;
00644         connection->minor_version = 0;
00645         return;
00646     } else if (!strcmp(tdsver, "80") || !strcmp(tdsver, "8.0")) {
00647         connection->major_version = 8;
00648         connection->minor_version = 0;
00649         return;
00650     }
00651 }
00652 
00653 /**
00654  * Set the full name of interface file
00655  * @param interf file name
00656  */
00657 int
00658 tds_set_interfaces_file_loc(const char *interf)
00659 {
00660     /* Free it if already set */
00661     if (interf_file != NULL)
00662         TDS_ZERO_FREE(interf_file);
00663     /* If no filename passed, leave it NULL */
00664     if ((interf == NULL) || (interf[0] == '\0')) {
00665         return TDS_SUCCEED;
00666     }
00667     /* Set to new value */
00668     if ((interf_file = strdup(interf)) == NULL) {
00669         return TDS_FAIL;
00670     }
00671     return TDS_SUCCEED;
00672 }
00673 
00674 /**
00675  * Given a servername and port name or number, lookup the
00676  * hostname and service.  The server ip will be stored in the
00677  * string 'servername' in dotted-decimal notation.  The service port
00678  * number will be stored in string form in the 'port' parameter.
00679  *
00680  * If we can't determine both the IP address and port number then
00681  * 'ip' and 'port' will be set to empty strings.
00682  */
00683 /* TODO callers seem to set always connection info... change it */
00684 void
00685 tds_lookup_host(const char *servername, /* (I) name of the server                  */
00686         char *ip    /* (O) dotted-decimal ip address of server */
00687     )
00688 {               /* (O) port number of the service          */
00689     struct hostent *host = NULL;
00690     unsigned int ip_addr = 0;
00691 
00692     /* Storage for reentrant getaddrby* calls */
00693     struct hostent result;
00694     char buffer[4096];
00695     int h_errnop;
00696 
00697     /*
00698      * Only call gethostbyname if servername is not an ip address. 
00699      * This call take a while and is useless for an ip address.
00700      * mlilback 3/2/02
00701      */
00702     ip_addr = inet_addr(servername);
00703     if (ip_addr != INADDR_NONE) {
00704         tds_strlcpy(ip, servername, 17);
00705         return;
00706     }
00707 
00708     host = tds_gethostbyname_r(servername, &result, buffer, sizeof(buffer), &h_errnop);
00709 
00710     ip[0] = '\0';
00711     if (host) {
00712         struct in_addr *ptr = (struct in_addr *) host->h_addr;
00713 
00714         tds_inet_ntoa_r(*ptr, ip, 17);
00715     }
00716 }               /* tds_lookup_host()  */
00717 
00718 static int
00719 tds_lookup_port(const char *portname)
00720 {
00721     int num = 0;
00722 
00723     if (portname) {
00724         num = atoi(portname);
00725         if (!num) {
00726             char buffer[4096];
00727             struct servent serv_result;
00728             struct servent *service = tds_getservbyname_r(portname, "tcp", &serv_result, buffer, sizeof(buffer));
00729 
00730             if (service)
00731                 num = ntohs(service->s_port);
00732         }
00733     }
00734     return num;
00735 }
00736 
00737 /* TODO same code in convert.c ?? */
00738 static int
00739 hexdigit(char c)
00740 {
00741     if (c >= 'a' && c <= 'f') {
00742         return c - 'a' + 10;
00743     } else if (c >= 'A' && c <= 'F') {
00744         return c - 'A' + 10;
00745     } else if (c >= '0' && c <= '9') {
00746         return c - '0';
00747     } else {
00748         return 0;   /* bad hex digit */
00749     }
00750 }
00751 
00752 static int
00753 hex2num(char *hex)
00754 {
00755     return hexdigit(hex[0]) * 16 + hexdigit(hex[1]);
00756 }
00757 
00758 /**
00759  * Open and read the file 'file' searching for a logical server
00760  * by the name of 'host'.  If one is found then lookup
00761  * the IP address and port number and store them in 'connection'
00762  *
00763  * \param dir name of base directory for interface file
00764  * \param file name of the interface file
00765  * \param host logical host to search for
00766  * \return 0 if not fount 1 if found
00767  */
00768 static int
00769 search_interface_file(TDSCONNECTION * connection, const char *dir, const char *file, const char *host)
00770 {
00771     char *pathname;
00772     char line[255];
00773     char tmp_ip[sizeof(line)];
00774     char tmp_port[sizeof(line)];
00775     char tmp_ver[sizeof(line)];
00776     FILE *in;
00777     char *field;
00778     int found = 0;
00779     int server_found = 0;
00780     char *lasts;
00781 
00782     line[0] = '\0';
00783     tmp_ip[0] = '\0';
00784     tmp_port[0] = '\0';
00785     tmp_ver[0] = '\0';
00786 
00787     tdsdump_log(TDS_DBG_INFO1, "Searching interfaces file %s/%s.\n", dir, file);
00788     pathname = (char *) malloc(strlen(dir) + strlen(file) + 10);
00789     if (!pathname)
00790         return 0;
00791 
00792     /*
00793      * create the full pathname to the interface file
00794      */
00795     if (file[0] == '\0') {
00796         pathname[0] = '\0';
00797     } else {
00798         if (dir[0] == '\0') {
00799             pathname[0] = '\0';
00800         } else {
00801             strcpy(pathname, dir);
00802             strcat(pathname, TDS_SDIR_SEPARATOR);
00803         }
00804         strcat(pathname, file);
00805     }
00806 
00807 
00808     /*
00809      * parse the interfaces file and find the server and port
00810      */
00811     if ((in = fopen(pathname, "r")) == NULL) {
00812         tdsdump_log(TDS_DBG_INFO1, "Couldn't open %s.\n", pathname);
00813         free(pathname);
00814         return 0;
00815     }
00816     tdsdump_log(TDS_DBG_INFO1, "Interfaces file %s opened.\n", pathname);
00817 
00818     while (fgets(line, sizeof(line) - 1, in)) {
00819         if (line[0] == '#')
00820             continue;   /* comment */
00821 
00822         if (!TDS_ISSPACE(line[0])) {
00823             field = strtok_r(line, "\n\t ", &lasts);
00824             if (!strcmp(field, host)) {
00825                 found = 1;
00826                 tdsdump_log(TDS_DBG_INFO1, "Found matching entry for host %s.\n", host);
00827             } else
00828                 found = 0;
00829         } else if (found && TDS_ISSPACE(line[0])) {
00830             field = strtok_r(line, "\n\t ", &lasts);
00831             if (field != NULL && !strcmp(field, "query")) {
00832                 field = strtok_r(NULL, "\n\t ", &lasts);    /* tcp or tli */
00833                 if (!strcmp(field, "tli")) {
00834                     tdsdump_log(TDS_DBG_INFO1, "TLI service.\n");
00835                     field = strtok_r(NULL, "\n\t ", &lasts);    /* tcp */
00836                     field = strtok_r(NULL, "\n\t ", &lasts);    /* device */
00837                     field = strtok_r(NULL, "\n\t ", &lasts);    /* host/port */
00838                     if (strlen(field) >= 18) {
00839                         sprintf(tmp_port, "%d", hex2num(&field[6]) * 256 + hex2num(&field[8]));
00840                         sprintf(tmp_ip, "%d.%d.%d.%d", hex2num(&field[10]),
00841                             hex2num(&field[12]), hex2num(&field[14]), hex2num(&field[16]));
00842                         tdsdump_log(TDS_DBG_INFO1, "tmp_port = %s. tmp_ip = %s.\n", tmp_port, tmp_ip);
00843                     }
00844                 } else {
00845                     field = strtok_r(NULL, "\n\t ", &lasts);    /* ether */
00846                     strcpy(tmp_ver, field);
00847                     field = strtok_r(NULL, "\n\t ", &lasts);    /* host */
00848                     strcpy(tmp_ip, field);
00849                     tdsdump_log(TDS_DBG_INFO1, "host field %s.\n", tmp_ip);
00850                     field = strtok_r(NULL, "\n\t ", &lasts);    /* port */
00851                     strcpy(tmp_port, field);
00852                 }   /* else */
00853                 server_found = 1;
00854             }   /* if */
00855         }       /* else if */
00856     }           /* while */
00857     fclose(in);
00858     free(pathname);
00859 
00860 
00861     /*
00862      * Look up the host and service
00863      */
00864     if (server_found) {
00865         tds_lookup_host(tmp_ip, line);
00866         tdsdump_log(TDS_DBG_INFO1, "Resolved IP as '%s'.\n", line);
00867         tds_dstr_copy(&connection->ip_addr, line);
00868         if (tmp_port[0])
00869             connection->port = tds_lookup_port(tmp_port);
00870         if (tmp_ver[0])
00871             tds_config_verstr(tmp_ver, connection);
00872     }
00873     return server_found;
00874 }               /* search_interface_file()  */
00875 
00876 /**
00877  * Try to find the IP number and port for a (possibly) logical server name.
00878  *
00879  * @note This function uses only the interfaces file and is deprecated.
00880  */
00881 static void
00882 tds_read_interfaces(const char *server, TDSCONNECTION * connection)
00883 {
00884     int founded = 0;
00885 
00886     /* read $SYBASE/interfaces */
00887 
00888     if (!server || strlen(server) == 0) {
00889         server = getenv("TDSQUERY");
00890         if (!server || strlen(server) == 0) {
00891             server = "SYBASE";
00892         }
00893         tdsdump_log(TDS_DBG_INFO1, "Setting server to %s from $TDSQUERY.\n", server);
00894 
00895     }
00896     tdsdump_log(TDS_DBG_INFO1, "Looking for server %s....\n", server);
00897 
00898     /*
00899      * Look for the server in the interf_file iff interf_file has been set.
00900      */
00901     if (interf_file) {
00902         tdsdump_log(TDS_DBG_INFO1, "Looking for server in file %s.\n", interf_file);
00903         founded = search_interface_file(connection, "", interf_file, server);
00904     }
00905 
00906     /*
00907      * if we haven't found the server yet then look for a $HOME/.interfaces file
00908      */
00909     if (!founded) {
00910         char *path = tds_get_home_file(".interfaces");
00911 
00912         if (path) {
00913             tdsdump_log(TDS_DBG_INFO1, "Looking for server in %s.\n", path);
00914             founded = search_interface_file(connection, "", path, server);
00915             free(path);
00916         }
00917     }
00918 
00919     /*
00920      * if we haven't found the server yet then look in $SYBBASE/interfaces file
00921      */
00922     if (!founded) {
00923         const char *sybase = getenv("SYBASE");
00924 #ifdef __VMS
00925         /* We've got to be in unix syntax for later slash-joined concatenation. */
00926         #include <unixlib.h>
00927         const char *unixspec = decc$translate_vms(sybase);
00928         if ( (int)unixspec != 0 && (int)unixspec != -1 ) sybase = unixspec;
00929 #endif
00930         if (!sybase || !sybase[0])
00931 #if !defined(WIN32) && !defined(DOS32X)
00932             sybase = "/etc/freetds";
00933 #else
00934             sybase = "c:\\";
00935 #endif
00936         tdsdump_log(TDS_DBG_INFO1, "Looking for server in %s/interfaces.\n", sybase);
00937         founded = search_interface_file(connection, sybase, "interfaces", server);
00938     }
00939 
00940     /*
00941      * If we still don't have the server and port then assume the user
00942      * typed an actual server name.
00943      */
00944     if (!founded) {
00945         char ip_addr[255];
00946         int ip_port;
00947         const char *env_port;
00948 
00949         /*
00950          * Make a guess about the port number
00951          */
00952 
00953         if (connection->port == 0) {
00954             /*
00955              * Not set in the [global] section of the
00956              * configure file, take a guess.
00957              */
00958 #ifdef TDS50
00959             ip_port = 4000;
00960 #else
00961             ip_port = 1433;
00962 #endif
00963         } else {
00964             /*
00965              * Preserve setting from the [global] section
00966              * of the configure file.
00967              */
00968             ip_port = connection->port;
00969         }
00970         if ((env_port = getenv("TDSPORT")) != NULL) {
00971             ip_port = tds_lookup_port(env_port);
00972             tdsdump_log(TDS_DBG_INFO1, "Setting 'ip_port' to %s from $TDSPORT.\n", env_port);
00973         } else
00974             tdsdump_log(TDS_DBG_INFO1, "Setting 'ip_port' to %d as a guess.\n", ip_port);
00975 
00976         /*
00977          * lookup the host
00978          */
00979         tds_lookup_host(server, ip_addr);
00980         if (ip_addr[0])
00981             tds_dstr_copy(&connection->ip_addr, ip_addr);
00982         if (ip_port)
00983             connection->port = ip_port;
00984     }
00985 }
00986 
00987 /**
00988  * Check the server name to find port info first
00989  * Warning: connection-> & login-> are all modified when needed
00990  * \return 1 when found, else 0
00991  */
00992 static int
00993 parse_server_name_for_port(TDSCONNECTION * connection, TDSLOGIN * login)
00994 {
00995     char *pSep, *pEnd;
00996     char *server;
00997 
00998     /* seek the ':' in login server_name */
00999     server = tds_dstr_cstr(&login->server_name);
01000     pEnd = server + strlen(server);
01001     for (pSep = server; pSep < pEnd; pSep++)
01002         if (*pSep == ':')
01003             break;
01004 
01005     if ((pSep < pEnd) && (pSep != server)) {    /* yes, i found it! */
01006         if (!tds_dstr_copyn(&connection->server_name, server, pSep - server))   /* end the server_name before the ':' */
01007             return 0;   /* FALSE */
01008 
01009         /* modify connection-> && login->server_name & ->port */
01010         login->port = connection->port = atoi(pSep + 1);
01011         tds_dstr_copy(&connection->instance_name, "");
01012         *pSep = 0;
01013 
01014         /* connection->ip_addr needed */
01015         {
01016             char tmp[256];
01017 
01018             tds_lookup_host(tds_dstr_cstr(&connection->server_name), tmp);
01019             if (!tds_dstr_copy(&connection->ip_addr, tmp))
01020                 return 0;   /* FALSE */
01021         }
01022 
01023         return 1;   /* TRUE */
01024     } else
01025         return 0;   /* FALSE */
01026 }
01027 
01028 
01029 /**
01030  * Return a structure capturing the compile-time settings provided to the
01031  * configure script.  
01032  */
01033 
01034 const TDS_COMPILETIME_SETTINGS *
01035 tds_get_compiletime_settings(void)
01036 {
01037     static const TDS_COMPILETIME_SETTINGS settings = {
01038         TDS_VERSION_NO, "unknown"   /* need fancy script in makefile */
01039 #       ifdef MSDBLIB
01040             , 1
01041 #       else
01042             , 0
01043 #       endif
01044             , -1    /* unknown: sybase_compat only a makefile setting, so far. */
01045 #       ifdef _REENTRANT
01046             , 1
01047 #       else
01048             , 0
01049 #       endif
01050 #       ifdef HAVE_ICONV
01051             , 1
01052 #       else
01053             , 0
01054 #       endif
01055 #       ifdef TDS46
01056             , "4.6"
01057 #       else
01058 #       ifdef TDS50
01059             , "5.0"
01060 #       else
01061 #       ifdef TDS70
01062             , "7.0"
01063 #       else
01064 #       ifdef TDS80
01065             , "8.0"
01066 #       else
01067             , "4.2"
01068 #       endif
01069 #       endif
01070 #       endif
01071 #       endif
01072 #       ifdef IODBC
01073             , 1
01074 #       else
01075             , 0
01076 #       endif
01077 #       ifdef UNIXODBC
01078             , 1
01079 #       else
01080             , 0
01081 #       endif
01082     };
01083 
01084     assert(settings.tdsver);
01085 
01086     return &settings;
01087 }
01088 
01089 /** \@} */
01090 
01091 

Generated on Wed Dec 9 04:15:56 2009 for NCBI C++ ToolKit by  doxygen 1.4.6
Modified on Wed Dec 09 08:17:57 2009 by modify_doxy.py rev. 173732