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