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