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