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

Generated by: LCOV version 1.13