LCOV - code coverage report
Current view: top level - src/dblib/unittests - common.c (source / functions) Hit Total Coverage
Test: FreeTDS coverage Lines: 113 180 62.8 %
Date: 2025-01-18 11:50:39 Functions: 8 8 100.0 %

          Line data    Source code
       1             : #include "common.h"
       2             : 
       3             : #if HAVE_UNISTD_H
       4             : #include <unistd.h>
       5             : #endif
       6             : 
       7             : #if HAVE_LIBGEN_H
       8             : #include <libgen.h>
       9             : #endif /* HAVE_LIBGEN_H */
      10             : 
      11             : #if HAVE_SYS_PARAM_H
      12             : #include <sys/param.h>
      13             : #endif /* HAVE_SYS_PARAM_H */
      14             : 
      15             : #include <freetds/time.h>
      16             : #include <freetds/bool.h>
      17             : 
      18             : #if HAVE_SYS_RESOURCE_H
      19             : #include <sys/resource.h>
      20             : #endif /* HAVE_SYS_RESOURCE_H */
      21             : 
      22             : #include <freetds/replacements.h>
      23             : 
      24             : #if !defined(PATH_MAX)
      25             : #define PATH_MAX 256
      26             : #endif
      27             : 
      28             : char USER[512];
      29             : char SERVER[512];
      30             : char PASSWORD[512];
      31             : char DATABASE[512];
      32             : 
      33             : static char sql_file[PATH_MAX];
      34             : static FILE* input_file = NULL;
      35             : 
      36             : static char *ARGV0 = NULL;
      37             : static char *ARGV0B = NULL;
      38             : static char *DIRNAME = NULL;
      39             : static const char *BASENAME = NULL;
      40             : 
      41             : #if HAVE_MALLOC_OPTIONS
      42             : extern const char *malloc_options;
      43             : #endif /* HAVE_MALLOC_OPTIONS */
      44             : 
      45             : void
      46         284 : set_malloc_options(void)
      47             : {
      48             : 
      49             : #if HAVE_MALLOC_OPTIONS
      50             :         /*
      51             :          * Options for malloc
      52             :          * A- all warnings are fatal
      53             :          * J- init memory to 0xD0
      54             :          * R- always move memory block on a realloc
      55             :          */
      56             :         malloc_options = "AJR";
      57             : #endif /* HAVE_MALLOC_OPTIONS */
      58         284 : }
      59             : 
      60             : #if defined(__MINGW32__) || defined(_MSC_VER)
      61             : static char *
      62             : tds_dirname(char* path)
      63             : {
      64             :         char *p, *p2;
      65             : 
      66             :         for (p = path + strlen(path); --p > path && (*p == '/' || *p == '\\');)
      67             :                 *p = '\0';
      68             : 
      69             :         p = strrchr(path, '/');
      70             :         if (!p)
      71             :                 p = path;
      72             :         p2 = strrchr(p, '\\');
      73             :         if (p2)
      74             :                 p = p2;
      75             :         if (p == path) {
      76             :                 if (*p == '/' || *p == '\\')
      77             :                         return "\\";
      78             :                 return ".";
      79             :         }
      80             :         *p = 0;
      81             :         return path;
      82             : }
      83             : #define dirname tds_dirname
      84             : 
      85             : #endif
      86             : 
      87             : static bool free_file_registered = false;
      88             : static void
      89         344 : free_file(void)
      90             : {
      91         344 :         if (input_file) {
      92         272 :                 fclose(input_file);
      93         272 :                 input_file = NULL;
      94             :         }
      95         344 :         if (ARGV0) {
      96         344 :                 DIRNAME = NULL;
      97         344 :                 BASENAME = NULL;
      98         344 :                 free(ARGV0);
      99         344 :                 ARGV0 = NULL;
     100         344 :                 free(ARGV0B);
     101         344 :                 ARGV0B = NULL;
     102             :         }
     103         344 : }
     104             : 
     105             : int
     106         356 : read_login_info(int argc, char **argv)
     107             : {
     108             :         int len;
     109         356 :         FILE *in = NULL;
     110             :         int ch;
     111             :         char *s1;
     112             :         char filename[PATH_MAX];
     113             :         static const char *PWD = "../../../PWD";
     114             :         struct { char *username, *password, *servername, *database; char fverbose; } options;
     115             : 
     116             : #if defined(HAVE_SETRLIMIT) && defined(RLIMIT_STACK)
     117             : #define MAX_STACK (8*1024*1024)
     118             : 
     119             :         struct rlimit rlim;
     120             : 
     121         356 :         if (!getrlimit(RLIMIT_STACK, &rlim) && (rlim.rlim_cur == RLIM_INFINITY || rlim.rlim_cur > MAX_STACK)) {
     122           0 :                 rlim.rlim_cur = MAX_STACK;
     123           0 :                 setrlimit(RLIMIT_STACK, &rlim);
     124             :         }
     125             : #endif
     126             : 
     127         356 :         setbuf(stdout, NULL);
     128         356 :         setbuf(stderr, NULL);
     129             : 
     130         356 :         free(ARGV0);
     131         356 :         free(ARGV0B);
     132             : #ifdef __VMS
     133             :         {
     134             :                 /* basename expects unix format */
     135             :                 s1 = strrchr(argv[0], ';'); /* trim version; extension trimmed later */
     136             :                 if (s1) *s1 = 0;
     137             :                 const char *unixspec = decc$translate_vms(argv[0]);
     138             :                 ARGV0 = strdup(unixspec);
     139             :         }
     140             : #else
     141         356 :         ARGV0 = strdup(argv[0]);
     142             : #endif
     143         356 :         ARGV0B = strdup(ARGV0);
     144             : 
     145         356 :         BASENAME = basename(ARGV0B);
     146             : #if defined(_WIN32) || defined(__VMS)
     147             :         s1 = strrchr(BASENAME, '.');
     148             :         if (s1) *s1 = 0;
     149             : #endif
     150         356 :         DIRNAME = dirname(ARGV0);
     151             : 
     152         356 :         memset(&options, 0, sizeof(options));
     153             : 
     154             :         /* process command line options (handy for manual testing) */
     155         712 :         while ((ch = getopt(argc, (char**)argv, "U:P:S:D:f:v")) != -1) {
     156           0 :                 switch (ch) {
     157           0 :                 case 'U':
     158           0 :                         options.username = strdup(optarg);
     159           0 :                         break;
     160           0 :                 case 'P':
     161           0 :                         options.password = strdup(optarg);
     162           0 :                         break;
     163           0 :                 case 'S':
     164           0 :                         options.servername = strdup(optarg);
     165           0 :                         break;
     166           0 :                 case 'D':
     167           0 :                         options.database = strdup(optarg);
     168           0 :                         break;
     169           0 :                 case 'f': /* override default PWD file */
     170           0 :                         PWD = strdup(optarg);
     171           0 :                         break;
     172           0 :                 case 'v':
     173           0 :                         options.fverbose = 1; /* doesn't normally do anything */
     174           0 :                         break;
     175           0 :                 case '?':
     176             :                 default:
     177           0 :                         fprintf(stderr, "usage:  %s \n"
     178             :                                         "        [-U username] [-P password]\n"
     179             :                                         "        [-S servername] [-D database]\n"
     180             :                                         "        [-i input filename] [-o output filename] "
     181             :                                         "[-e error filename]\n"
     182             :                                         , BASENAME);
     183           0 :                         exit(1);
     184             :                 }
     185             :         }
     186         356 :         strlcpy(filename, PWD, sizeof(filename));
     187             : 
     188         356 :         s1 = getenv("TDSPWDFILE");
     189         356 :         if (s1 && s1[0])
     190           0 :                 in = fopen(s1, "r");
     191           0 :         if (!in)
     192         356 :                 in = fopen(filename, "r");
     193         356 :         if (!in)
     194           0 :                 in = fopen("PWD", "r");
     195         356 :         if (!in) {
     196           0 :                 sprintf(filename, "%s/%s", (DIRNAME) ? DIRNAME : ".", PWD);
     197             : 
     198           0 :                 in = fopen(filename, "r");
     199             :         }
     200             : 
     201         356 :         if (!in) {
     202           0 :                 fprintf(stderr, "Can not open %s file\n\n", filename);
     203             :         } else {
     204             :                 char line[512];
     205             : 
     206        6748 :                 while (fgets(line, sizeof(line), in)) {
     207             :                         const char *value;
     208             : 
     209        6392 :                         s1 = strtok(line, "=");
     210        6392 :                         value = strtok(NULL, "\n");
     211        6392 :                         if (!s1 || !value)
     212        3814 :                                 continue;
     213        2578 :                         if (!strcmp(s1, "UID")) {
     214         356 :                                 strlcpy(USER, value, sizeof(USER));
     215        2222 :                         } else if (!strcmp(s1, "SRV")) {
     216         356 :                                 strlcpy(SERVER, value, sizeof(SERVER));
     217        1866 :                         } else if (!strcmp(s1, "PWD")) {
     218         356 :                                 strlcpy(PASSWORD, value, sizeof(PASSWORD));
     219        1510 :                         } else if (!strcmp(s1, "DB")) {
     220         356 :                                 strlcpy(DATABASE, value, sizeof(DATABASE));
     221             :                         }
     222             :                 }
     223         356 :                 fclose(in);
     224             :         }
     225             : 
     226             :         /* apply command-line overrides */
     227         356 :         if (options.username) {
     228           0 :                 strlcpy(USER, options.username, sizeof(USER));
     229           0 :                 free(options.username);
     230             :         }
     231         356 :         if (options.password) {
     232           0 :                 strlcpy(PASSWORD, options.password, sizeof(PASSWORD));
     233           0 :                 free(options.password);
     234             :         }
     235         356 :         if (options.servername) {
     236           0 :                 strlcpy(SERVER, options.servername, sizeof(SERVER));
     237           0 :                 free(options.servername);
     238             :         }
     239         356 :         if (options.database) {
     240           0 :                 strlcpy(DATABASE, options.database, sizeof(DATABASE));
     241           0 :                 free(options.database);
     242             :         }
     243             : 
     244         356 :         if (!*SERVER) {
     245           0 :                 fprintf(stderr, "no servername provided, quitting.\n");
     246           0 :                 exit(1);
     247             :         }
     248             : 
     249         356 :         printf("found %s.%s for %s in \"%s\"\n", SERVER, DATABASE, USER, filename);
     250             : 
     251             : #if 0
     252             :         dbrecftos(BASENAME);
     253             : #endif
     254         356 :         len = snprintf(sql_file, sizeof(sql_file), "%s/%s.sql", FREETDS_SRCDIR, BASENAME);
     255         356 :         assert(len >= 0 && len <= sizeof(sql_file));
     256             : 
     257         356 :         if (input_file)
     258          12 :                 fclose(input_file);
     259         356 :         if ((input_file = fopen(sql_file, "r")) == NULL) {
     260          64 :                 fflush(stdout);
     261          64 :                 fprintf(stderr, "could not open SQL input file \"%s\"\n", sql_file);
     262             :         }
     263             : 
     264         356 :         if (!free_file_registered)
     265         344 :                 atexit(free_file);
     266         356 :         free_file_registered = true;
     267             : 
     268         356 :         printf("SQL text will be read from %s\n", sql_file);
     269             : 
     270         356 :         return 0;
     271             : }
     272             : 
     273             : /*
     274             :  * Fill the command buffer from a file while echoing it to standard output.
     275             :  */
     276             : RETCODE
     277        5482 : sql_cmd(DBPROCESS *dbproc)
     278             : {
     279        5482 :         char line[2048], *p = line;
     280        5482 :         int i = 0;
     281        5482 :         RETCODE erc=SUCCEED;
     282             : 
     283        5482 :         if (!input_file) {
     284           0 :                 fprintf(stderr, "%s: error: SQL input file \"%s\" not opened\n", BASENAME, sql_file);
     285           0 :                 exit(1);
     286             :         }
     287             : 
     288       14468 :         while ((p = fgets(line, (int)sizeof(line), input_file)) != NULL && strcasecmp("go\n", p) != 0) {
     289        8986 :                 printf("\t%3d: %s", ++i, p);
     290        8986 :                 if ((erc = dbcmd(dbproc, p)) != SUCCEED) {
     291           0 :                         fprintf(stderr, "%s: error: could write \"%s\" to dbcmd()\n", BASENAME, p);
     292           0 :                         exit(1);
     293             :                 }
     294             :         }
     295             : 
     296        5482 :         if (ferror(input_file)) {
     297           0 :                 fprintf(stderr, "%s: error: could not read SQL input file \"%s\"\n", BASENAME, sql_file);
     298           0 :                 exit(1);
     299             :         }
     300             : 
     301        5482 :         return erc;
     302             : }
     303             : 
     304             : RETCODE
     305         192 : sql_rewind(void)
     306             : {
     307         192 :         if (!input_file)
     308             :                 return FAIL;
     309         192 :         rewind(input_file);
     310         192 :         return SUCCEED;
     311             : }
     312             : 
     313             : RETCODE
     314         120 : sql_reopen(const char *fn)
     315             : {
     316         120 :         int len = snprintf(sql_file, sizeof(sql_file), "%s/%s.sql", FREETDS_SRCDIR, fn);
     317         120 :         assert(len >= 0 && len <= sizeof(sql_file));
     318             : 
     319         120 :         if (input_file)
     320         120 :                 fclose(input_file);
     321         120 :         if ((input_file = fopen(sql_file, "r")) == NULL) {
     322           8 :                 fflush(stdout);
     323           8 :                 fprintf(stderr, "could not open SQL input file \"%s\"\n", sql_file);
     324           8 :                 sql_file[0] = 0;
     325           8 :                 return FAIL;
     326             :         }
     327             :         return SUCCEED;
     328             : }
     329             : 
     330             : int
     331        1300 : syb_msg_handler(DBPROCESS * dbproc, DBINT msgno, int msgstate, int severity, char *msgtext, char *srvname, char *procname, int line)
     332             : {
     333             :         int *pexpected_msgno;
     334             : 
     335             :         /*
     336             :          * Check for "database changed", or "language changed" messages from
     337             :          * the client.  If we get one of these, then we need to pull the
     338             :          * name of the database or charset from the message and set the
     339             :          * appropriate variable.
     340             :          */
     341        2600 :         if (msgno == 5701 ||    /* database context change */
     342        1364 :             msgno == 5703 ||    /* language changed */
     343             :             msgno == 5704) {    /* charset changed */
     344             : 
     345             :                 /* fprintf( stderr, "msgno = %d: %s\n", msgno, msgtext ) ; */
     346             :                 return 0;
     347             :         }
     348             : 
     349             :         /*
     350             :          * If the user data indicates this is an expected error message (because we're testing the
     351             :          * error propogation, say) then indicate this message was anticipated.
     352             :          */
     353          64 :         if (dbproc != NULL) {
     354          64 :                 pexpected_msgno = (int *) dbgetuserdata(dbproc);
     355          64 :                 if (pexpected_msgno && *pexpected_msgno == msgno) {
     356          42 :                         printf("OK: anticipated message arrived: %d %s\n", (int) msgno, msgtext);
     357          42 :                         *pexpected_msgno = 0;
     358          42 :                         return 0;
     359             :                 }
     360             :         }
     361             :         /*
     362             :          * If the severity is something other than 0 or the msg number is
     363             :          * 0 (user informational messages).
     364             :          */
     365          22 :         fflush(stdout);
     366          22 :         if (severity >= 0 || msgno == 0) {
     367             :                 /*
     368             :                  * If the message was something other than informational, and
     369             :                  * the severity was greater than 0, then print information to
     370             :                  * stderr with a little pre-amble information.
     371             :                  */
     372          22 :                 if (msgno > 0 && severity > 0) {
     373           0 :                         fprintf(stderr, "Msg %d, Level %d, State %d\n", (int) msgno, (int) severity, (int) msgstate);
     374           0 :                         fprintf(stderr, "Server '%s'", srvname);
     375           0 :                         if (procname != NULL && *procname != '\0')
     376           0 :                                 fprintf(stderr, ", Procedure '%s'", procname);
     377           0 :                         if (line > 0)
     378           0 :                                 fprintf(stderr, ", Line %d", line);
     379           0 :                         fprintf(stderr, "\n");
     380           0 :                         fprintf(stderr, "%s\n", msgtext);
     381           0 :                         fflush(stderr);
     382             :                 } else {
     383             :                         /*
     384             :                          * Otherwise, it is just an informational (e.g. print) message
     385             :                          * from the server, so send it to stdout.
     386             :                          */
     387          22 :                         printf("%s\n", msgtext);
     388          22 :                         fflush(stdout);
     389          22 :                         severity = 0;
     390             :                 }
     391             :         }
     392             : 
     393           0 :         if (severity) {
     394           0 :                 fprintf(stderr, "exit: no unanticipated messages allowed in unit tests\n");
     395           0 :                 exit(EXIT_FAILURE);
     396             :         }
     397             :         return 0;
     398             : }
     399             : 
     400             : int
     401         154 : syb_err_handler(DBPROCESS * dbproc, int severity, int dberr, int oserr, char *dberrstr, char *oserrstr)
     402             : {
     403             :         int *pexpected_dberr;
     404             : 
     405             :         /*
     406             :          * For server messages, cancel the query and rely on the
     407             :          * message handler to spew the appropriate error messages out.
     408             :          */
     409         154 :         if (dberr == SYBESMSG)
     410             :                 return INT_CANCEL;
     411             : 
     412             :         /*
     413             :          * If the user data indicates this is an expected error message (because we're testing the
     414             :          * error propogation, say) then indicate this message was anticipated.
     415             :          */
     416          98 :         if (dbproc != NULL) {
     417          98 :                 pexpected_dberr = (int *) dbgetuserdata(dbproc);
     418          98 :                 if (pexpected_dberr && *pexpected_dberr == dberr) {
     419          98 :                         printf("OK: anticipated error %d (%s) arrived\n", dberr, dberrstr);
     420          98 :                         *pexpected_dberr = 0;
     421          98 :                         return INT_CANCEL;
     422             :                 }
     423             :         }
     424             : 
     425           0 :         fflush(stdout);
     426           0 :         fprintf(stderr,
     427             :                 "DB-LIBRARY error (dberr %d (severity %d): \"%s\"; oserr %d: \"%s\")\n",
     428             :                 dberr, severity, dberrstr ? dberrstr : "(null)", oserr, oserrstr ? oserrstr : "(null)");
     429           0 :         fflush(stderr);
     430             : 
     431             :         /*
     432             :          * If the dbprocess is dead or the dbproc is a NULL pointer and
     433             :          * we are not in the middle of logging in, then we need to exit.
     434             :          * We can't do anything from here on out anyway.
     435             :          * It's OK to end up here in response to a dbconvert() that
     436             :          * resulted in overflow, so don't exit in that case.
     437             :          */
     438           0 :         if ((dbproc == NULL) || DBDEAD(dbproc)) {
     439           0 :                 if (dberr != SYBECOFL) {
     440           0 :                         exit(255);
     441             :                 }
     442             :         }
     443             : 
     444           0 :         if (severity) {
     445           0 :                 fprintf(stderr, "error: no unanticipated errors allowed in unit tests\n");
     446           0 :                 exit(EXIT_FAILURE);
     447             :         }
     448             : 
     449             :         return INT_CANCEL;
     450             : }

Generated by: LCOV version 1.13