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 : }
|