Line data Source code
1 : #include "common.h"
2 :
3 : #if HAVE_UNISTD_H
4 : #include <unistd.h>
5 : #endif
6 :
7 : #include <freetds/replacements.h>
8 : #include <freetds/macros.h>
9 :
10 : #ifdef TDS_STATIC_CAST
11 : #include "ctlib.h"
12 : #endif
13 :
14 : char USER[512];
15 : char SERVER[512];
16 : char PASSWORD[512];
17 : char DATABASE[512];
18 :
19 : COMMON_PWD common_pwd = {0};
20 :
21 : static const char *BASENAME = NULL;
22 :
23 : static const char *PWD = "../../../PWD";
24 :
25 : int cslibmsg_cb_invoked = 0;
26 : int clientmsg_cb_invoked = 0;
27 : int servermsg_cb_invoked = 0;
28 : bool error_to_stdout = false;
29 :
30 : ct_message ct_last_message;
31 :
32 : static CS_RETCODE continue_logging_in(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose);
33 :
34 : CS_RETCODE
35 1072 : read_login_info(void)
36 : {
37 1072 : FILE *in = NULL;
38 : char line[512];
39 : char *s1, *s2;
40 :
41 1072 : if (common_pwd.initialized) {
42 0 : strcpy(USER, common_pwd.USER);
43 0 : strcpy(PASSWORD, common_pwd.PASSWORD);
44 0 : strcpy(SERVER, common_pwd.SERVER);
45 0 : strcpy(DATABASE, common_pwd.DATABASE);
46 0 : return CS_SUCCEED;
47 : }
48 :
49 1072 : s1 = getenv("TDSPWDFILE");
50 1072 : if (s1 && s1[0])
51 0 : in = fopen(s1, "r");
52 0 : if (!in)
53 1072 : in = fopen(PWD, "r");
54 1072 : if (!in) {
55 0 : fprintf(stderr, "Can not open PWD file \"%s\"\n\n", PWD);
56 0 : return CS_FAIL;
57 : }
58 :
59 20368 : while (fgets(line, sizeof(line), in)) {
60 19296 : s1 = strtok(line, "=");
61 19296 : s2 = strtok(NULL, "\n");
62 19296 : if (!s1 || !s2) {
63 11524 : continue;
64 : }
65 7772 : if (!strcmp(s1, "UID")) {
66 1072 : strcpy(USER, s2);
67 6700 : } else if (!strcmp(s1, "SRV")) {
68 1072 : strcpy(SERVER, s2);
69 5628 : } else if (!strcmp(s1, "PWD")) {
70 1072 : strcpy(PASSWORD, s2);
71 4556 : } else if (!strcmp(s1, "DB")) {
72 1072 : strcpy(DATABASE, s2);
73 : }
74 : }
75 1072 : fclose(in);
76 1072 : return CS_SUCCEED;
77 : }
78 :
79 : static CS_RETCODE
80 24 : establish_login(int argc, char **argv)
81 : {
82 : extern char *optarg;
83 : extern int optind;
84 24 : COMMON_PWD options = {0};
85 : int ch;
86 :
87 24 : BASENAME = basename((char *)argv[0]);
88 :
89 : /* process command line options (handy for manual testing) */
90 48 : while ((ch = getopt(argc, argv, "U:P:S:D:f:m:v")) != -1) {
91 0 : switch (ch) {
92 0 : case 'U':
93 0 : strcpy(options.USER, optarg);
94 0 : break;
95 0 : case 'P':
96 0 : strcpy(options.PASSWORD, optarg);
97 0 : break;
98 0 : case 'S':
99 0 : strcpy(options.SERVER, optarg);
100 0 : break;
101 0 : case 'D':
102 0 : strcpy(options.DATABASE, optarg);
103 0 : break;
104 0 : case 'f': /* override default PWD file */
105 0 : PWD = strdup(optarg);
106 0 : break;
107 0 : case 'm':
108 0 : common_pwd.maxlength = strtol(optarg, NULL, 10);
109 0 : case 'v':
110 0 : common_pwd.fverbose = 1;
111 0 : break;
112 0 : case '?':
113 : default:
114 0 : fprintf(stderr, "usage: %s [-v] [-f PWD]\n"
115 : " [-U username] [-P password]\n"
116 : " [-S servername] [-D database]\n"
117 : , BASENAME);
118 0 : exit(1);
119 : }
120 : }
121 24 : read_login_info();
122 :
123 : /* override PWD file with command-line options */
124 :
125 24 : if (*options.USER)
126 0 : strcpy(USER, options.USER);
127 24 : if (*options.PASSWORD)
128 0 : strcpy(PASSWORD, options.PASSWORD);
129 24 : if (*options.SERVER)
130 0 : strcpy(SERVER, options.SERVER);
131 24 : if (*options.DATABASE)
132 0 : strcpy(DATABASE, options.DATABASE);
133 :
134 24 : return (*USER && *SERVER && *DATABASE)? CS_SUCCEED : CS_FAIL;
135 : }
136 :
137 : CS_RETCODE
138 24 : try_ctlogin_with_options(int argc, char **argv, CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
139 : {
140 : CS_RETCODE ret;
141 :
142 24 : if ((ret = establish_login(argc, argv)) != CS_SUCCEED) {
143 0 : if (verbose) {
144 0 : fprintf(stderr, "read_login_info() failed!\n");
145 : }
146 : return ret;
147 : }
148 24 : return continue_logging_in(ctx, conn, cmd, verbose);
149 : }
150 :
151 : /* old way: because I'm too lazy to change every unit test */
152 : CS_RETCODE
153 1040 : try_ctlogin(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
154 : {
155 : CS_RETCODE ret;
156 :
157 1040 : if ((ret = read_login_info()) != CS_SUCCEED) {
158 0 : if (verbose) {
159 0 : fprintf(stderr, "read_login_info() failed!\n");
160 : }
161 : return ret;
162 : }
163 1040 : return continue_logging_in(ctx, conn, cmd, verbose);
164 : }
165 :
166 : CS_RETCODE
167 1064 : continue_logging_in(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
168 : {
169 : CS_RETCODE ret;
170 : char query[512+10];
171 1064 : CS_INT bulk_enabled = CS_TRUE;
172 : #ifdef TDS_STATIC_CAST
173 : TDSCONTEXT *tds_ctx;
174 : #endif
175 :
176 1064 : ret = cs_ctx_alloc(CS_VERSION_100, ctx);
177 1064 : if (ret != CS_SUCCEED) {
178 0 : if (verbose) {
179 0 : fprintf(stderr, "Context Alloc failed!\n");
180 : }
181 : return ret;
182 : }
183 :
184 : #ifdef TDS_STATIC_CAST
185 : /* Force default date format, some tests rely on it */
186 1064 : tds_ctx = (TDSCONTEXT *) (*ctx)->tds_ctx;
187 1064 : if (tds_ctx && tds_ctx->locale && tds_ctx->locale->datetime_fmt) {
188 1064 : free(tds_ctx->locale->datetime_fmt);
189 1064 : tds_ctx->locale->datetime_fmt = strdup("%b %d %Y %I:%M%p");
190 : }
191 : #endif
192 :
193 1064 : ret = ct_init(*ctx, CS_VERSION_100);
194 1064 : if (ret != CS_SUCCEED) {
195 0 : if (verbose) {
196 0 : fprintf(stderr, "Library Init failed!\n");
197 : }
198 : return ret;
199 : }
200 1064 : if ((ret = ct_callback(*ctx, NULL, CS_SET, CS_CLIENTMSG_CB,
201 : (CS_VOID*) clientmsg_cb)) != CS_SUCCEED) {
202 0 : fprintf(stderr, "ct_callback() failed\n");
203 0 : return ret;
204 : }
205 1064 : if ((ret = ct_callback(*ctx, NULL, CS_SET, CS_SERVERMSG_CB, servermsg_cb)) != CS_SUCCEED) {
206 0 : fprintf(stderr, "ct_callback() failed\n");
207 0 : return ret;
208 : }
209 1064 : ret = ct_con_alloc(*ctx, conn);
210 1064 : if (ret != CS_SUCCEED) {
211 0 : if (verbose) {
212 0 : fprintf(stderr, "Connect Alloc failed!\n");
213 : }
214 : return ret;
215 : }
216 1064 : ret = ct_con_props(*conn, CS_SET, CS_USERNAME, USER, CS_NULLTERM, NULL);
217 1064 : if (ret != CS_SUCCEED) {
218 0 : if (verbose) {
219 0 : fprintf(stderr, "ct_con_props() SET USERNAME failed!\n");
220 : }
221 : return ret;
222 : }
223 1064 : ret = ct_con_props(*conn, CS_SET, CS_PASSWORD, PASSWORD, CS_NULLTERM, NULL);
224 1064 : if (ret != CS_SUCCEED) {
225 0 : if (verbose) {
226 0 : fprintf(stderr, "ct_con_props() SET PASSWORD failed!\n");
227 : }
228 : return ret;
229 : }
230 1064 : ret = ct_con_props(*conn, CS_SET, CS_BULK_LOGIN, &bulk_enabled, CS_UNUSED, NULL);
231 1064 : if (ret != CS_SUCCEED) {
232 0 : if (verbose) {
233 0 : fprintf(stderr, "ct_con_props() SET BULK failed!\n");
234 : }
235 : return ret;
236 : }
237 :
238 1064 : printf("connecting as %s to %s.%s\n", USER, SERVER, DATABASE);
239 :
240 1064 : ret = ct_connect(*conn, SERVER, CS_NULLTERM);
241 1064 : if (ret != CS_SUCCEED) {
242 0 : if (verbose) {
243 0 : fprintf(stderr, "Connection failed!\n");
244 : }
245 0 : ct_con_drop(*conn);
246 0 : *conn = NULL;
247 0 : ct_exit(*ctx, CS_UNUSED);
248 0 : cs_ctx_drop(*ctx);
249 0 : *ctx = NULL;
250 0 : return ret;
251 : }
252 1064 : ret = ct_cmd_alloc(*conn, cmd);
253 1064 : if (ret != CS_SUCCEED) {
254 0 : if (verbose) {
255 0 : fprintf(stderr, "Command Alloc failed!\n");
256 : }
257 0 : ct_con_drop(*conn);
258 0 : *conn = NULL;
259 0 : ct_exit(*ctx, CS_UNUSED);
260 0 : cs_ctx_drop(*ctx);
261 0 : *ctx = NULL;
262 0 : return ret;
263 : }
264 :
265 1064 : sprintf(query, "use %s", DATABASE);
266 :
267 1064 : ret = run_command(*cmd, query);
268 1064 : if (ret != CS_SUCCEED)
269 : return ret;
270 :
271 1064 : return CS_SUCCEED;
272 : }
273 :
274 :
275 : CS_RETCODE
276 1064 : try_ctlogout(CS_CONTEXT * ctx, CS_CONNECTION * conn, CS_COMMAND * cmd, int verbose)
277 : {
278 : CS_RETCODE ret;
279 :
280 1064 : ret = ct_cancel(conn, NULL, CS_CANCEL_ALL);
281 1064 : if (ret != CS_SUCCEED) {
282 0 : if (verbose) {
283 0 : fprintf(stderr, "ct_cancel() failed!\n");
284 : }
285 : return ret;
286 : }
287 1064 : ct_cmd_drop(cmd);
288 1064 : ct_close(conn, CS_UNUSED);
289 1064 : ct_con_drop(conn);
290 1064 : ct_exit(ctx, CS_UNUSED);
291 1064 : cs_ctx_drop(ctx);
292 :
293 1064 : return CS_SUCCEED;
294 : }
295 :
296 : /* Run commands from which we expect no results returned */
297 : CS_RETCODE
298 1916 : run_command(CS_COMMAND * cmd, const char *sql)
299 : {
300 : CS_RETCODE ret, results_ret;
301 : CS_INT result_type;
302 :
303 1916 : if (cmd == NULL) {
304 : return CS_FAIL;
305 : }
306 :
307 1916 : ret = ct_command(cmd, CS_LANG_CMD, (void *) sql, CS_NULLTERM, CS_UNUSED);
308 1916 : if (ret != CS_SUCCEED) {
309 0 : fprintf(stderr, "ct_command() failed\n");
310 0 : return ret;
311 : }
312 1916 : ret = ct_send(cmd);
313 1916 : if (ret != CS_SUCCEED) {
314 2 : fprintf(stderr, "ct_send() failed\n");
315 2 : return ret;
316 : }
317 5862 : while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
318 3948 : switch ((int) result_type) {
319 : case CS_CMD_SUCCEED:
320 : break;
321 : case CS_CMD_DONE:
322 : break;
323 46 : case CS_CMD_FAIL:
324 46 : fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
325 : /* return CS_FAIL; */
326 46 : break;
327 0 : default:
328 0 : fprintf(stderr, "ct_results() unexpected result_type.\n");
329 0 : return CS_FAIL;
330 : }
331 : }
332 1914 : switch ((int) results_ret) {
333 : case CS_END_RESULTS:
334 : break;
335 0 : case CS_FAIL:
336 0 : fprintf(stderr, "ct_results() failed.\n");
337 0 : return CS_FAIL;
338 : break;
339 0 : default:
340 0 : fprintf(stderr, "ct_results() unexpected return.\n");
341 0 : return CS_FAIL;
342 : }
343 :
344 : return CS_SUCCEED;
345 : }
346 :
347 : CS_INT
348 200 : cslibmsg_cb(CS_CONTEXT * connection TDS_UNUSED, CS_CLIENTMSG * errmsg)
349 : {
350 200 : cslibmsg_cb_invoked++;
351 :
352 : ct_reset_last_message();
353 200 : ct_last_message.type = CTMSG_CSLIB;
354 200 : ct_last_message.number = errmsg->msgnumber;
355 200 : strlcpy(ct_last_message.text, errmsg->msgstring, sizeof(ct_last_message.text));
356 :
357 200 : fprintf(stderr, "\nCS-Library Message:\n");
358 800 : fprintf(stderr, "number %#x layer %d origin %d severity %d number %d\n",
359 : errmsg->msgnumber,
360 400 : (int) CS_LAYER(errmsg->msgnumber), (int) CS_ORIGIN(errmsg->msgnumber),
361 400 : (int) CS_SEVERITY(errmsg->msgnumber), (int) CS_NUMBER(errmsg->msgnumber));
362 200 : fprintf(stderr, "msgstring: %s\n", errmsg->msgstring);
363 200 : fprintf(stderr, "osstring: %s\n", (errmsg->osstringlen > 0)
364 : ? errmsg->osstring : "(null)");
365 200 : return CS_SUCCEED;
366 : }
367 :
368 :
369 :
370 : static CS_RETCODE
371 264 : clientmsg_gen_cb(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg,
372 : ct_message_type msg_type)
373 : {
374 264 : FILE *out = error_to_stdout ? stdout: stderr;
375 :
376 264 : clientmsg_cb_invoked++;
377 :
378 : ct_reset_last_message();
379 264 : ct_last_message.type = msg_type;
380 264 : ct_last_message.number = errmsg->msgnumber;
381 264 : strlcpy(ct_last_message.text, errmsg->msgstring, sizeof(ct_last_message.text));
382 :
383 264 : fprintf(out, "\nOpen Client Message%s: %p %p\n",
384 : msg_type == CTMSG_CLIENT ? "" : " #2", context, connection);
385 1056 : fprintf(out, "number %#x layer %d origin %d severity %d number %d\n",
386 : errmsg->msgnumber,
387 528 : (int) CS_LAYER(errmsg->msgnumber), (int) CS_ORIGIN(errmsg->msgnumber),
388 528 : (int) CS_SEVERITY(errmsg->msgnumber), (int) CS_NUMBER(errmsg->msgnumber));
389 264 : fprintf(out, "msgstring: %s\n", errmsg->msgstring);
390 264 : fprintf(out, "osstring: %s\n", (errmsg->osstringlen > 0)
391 : ? errmsg->osstring : "(null)");
392 264 : fflush(out);
393 264 : return CS_SUCCEED;
394 : }
395 :
396 : CS_RETCODE
397 72 : clientmsg_cb(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg)
398 : {
399 72 : return clientmsg_gen_cb(context, connection, errmsg, CTMSG_CLIENT);
400 : }
401 :
402 : CS_RETCODE
403 192 : clientmsg_cb2(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg)
404 : {
405 192 : return clientmsg_gen_cb(context, connection, errmsg, CTMSG_CLIENT2);
406 : }
407 :
408 : CS_RETCODE
409 3286 : servermsg_cb(CS_CONTEXT * context TDS_UNUSED, CS_CONNECTION * connection TDS_UNUSED, CS_SERVERMSG * srvmsg)
410 : {
411 3286 : FILE *out = error_to_stdout ? stdout: stderr;
412 :
413 3286 : servermsg_cb_invoked++;
414 :
415 : ct_reset_last_message();
416 3286 : ct_last_message.type = CTMSG_SERVER;
417 3286 : ct_last_message.number = srvmsg->msgnumber;
418 3286 : strlcpy(ct_last_message.text, srvmsg->text, sizeof(ct_last_message.text));
419 :
420 3286 : if (srvmsg->msgnumber == 5701 || srvmsg->msgnumber == 5703) {
421 2926 : fprintf(out, "%s\n", srvmsg->text);
422 2926 : fflush(out);
423 2926 : return CS_SUCCEED;
424 : }
425 :
426 360 : fprintf(out, "\nServer message:\n");
427 720 : fprintf(out, "%s Message %d severity %d state %d line %d:\n",
428 360 : srvmsg->svrnlen > 0? srvmsg->svrname : "Server",
429 : srvmsg->msgnumber, srvmsg->severity, srvmsg->state, srvmsg->line);
430 360 : if (srvmsg->proclen > 0)
431 20 : fprintf(out, "proc %s: ", srvmsg->proc);
432 360 : fprintf(out, "\t\"%s\"\n", srvmsg->text);
433 :
434 360 : fflush(out);
435 360 : return CS_SUCCEED;
436 : }
437 :
438 : const char *
439 398 : res_type_str(CS_RETCODE ret)
440 : {
441 : static char str[64];
442 :
443 : #define S(s) case s: return #s;
444 398 : switch ((int) ret) {
445 : S(CS_ROW_RESULT)
446 0 : S(CS_PARAM_RESULT)
447 66 : S(CS_STATUS_RESULT)
448 0 : S(CS_MSG_RESULT)
449 64 : S(CS_CMD_SUCCEED)
450 150 : S(CS_CMD_DONE)
451 8 : S(CS_CMD_FAIL)
452 24 : S(CS_COMPUTE_RESULT)
453 : #undef S
454 : }
455 :
456 0 : sprintf(str, "?? (%d)", (int) ret);
457 0 : return str;
458 : }
459 :
460 : void
461 6200 : _check_ret(const char *name, CS_RETCODE ret, int line)
462 : {
463 6200 : if (ret != CS_SUCCEED) {
464 0 : fprintf(stderr, "%s():%d: failed\n", name, line);
465 0 : exit(1);
466 : }
467 6200 : }
468 :
469 : void
470 448 : ct_reset_last_message(void)
471 : {
472 4198 : memset(&ct_last_message, 0, sizeof(ct_last_message));
473 448 : }
|