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 : static const char *BASENAME = NULL;
11 :
12 : static const char *PWD = DEFAULT_PWD_PATH;
13 :
14 : int cslibmsg_cb_invoked = 0;
15 : int clientmsg_cb_invoked = 0;
16 : int servermsg_cb_invoked = 0;
17 : bool error_to_stdout = false;
18 :
19 : ct_message ct_last_message;
20 :
21 : static CS_RETCODE continue_logging_in(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose);
22 :
23 : CS_RETCODE
24 10 : read_login_info(void)
25 : {
26 1340 : const char *s = read_login_info_base(&common_pwd, DEFAULT_PWD_PATH);
27 :
28 1310 : return s ? CS_SUCCEED : CS_FAIL;
29 : }
30 :
31 : static CS_RETCODE
32 30 : establish_login(int argc, char **argv)
33 : {
34 : extern char *optarg;
35 : extern int optind;
36 : int ch;
37 :
38 30 : BASENAME = basename((char *)argv[0]);
39 :
40 : /* process command line options (handy for manual testing) */
41 60 : while ((ch = getopt(argc, argv, "U:P:S:D:f:m:v")) != -1) {
42 0 : switch (ch) {
43 0 : case 'U':
44 0 : strlcpy(common_pwd.user, optarg, sizeof(common_pwd.user));
45 0 : break;
46 0 : case 'P':
47 0 : strlcpy(common_pwd.password, optarg, sizeof(common_pwd.password));
48 0 : break;
49 0 : case 'S':
50 0 : strlcpy(common_pwd.server, optarg, sizeof(common_pwd.server));
51 0 : break;
52 0 : case 'D':
53 0 : strlcpy(common_pwd.database, optarg, sizeof(common_pwd.database));
54 0 : break;
55 0 : case 'f': /* override default PWD file */
56 0 : PWD = strdup(optarg);
57 0 : break;
58 0 : case 'm':
59 0 : common_pwd.maxlength = (CS_INT) strtol(optarg, NULL, 10);
60 0 : case 'v':
61 0 : common_pwd.fverbose = 1;
62 0 : break;
63 0 : case '?':
64 : default:
65 0 : fprintf(stderr, "usage: %s [-v] [-f PWD]\n"
66 : " [-U username] [-P password]\n"
67 : " [-S servername] [-D database]\n"
68 : , BASENAME);
69 0 : exit(1);
70 : }
71 : }
72 30 : read_login_info();
73 :
74 : /* user is not necessary for MSSQL trusted logins */
75 30 : return (*common_pwd.server && *common_pwd.database) ? CS_SUCCEED : CS_FAIL;
76 : }
77 :
78 : CS_RETCODE
79 30 : try_ctlogin_with_options(int argc, char **argv, CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
80 : {
81 : CS_RETCODE ret;
82 :
83 30 : if ((ret = establish_login(argc, argv)) != CS_SUCCEED) {
84 0 : if (verbose) {
85 0 : fprintf(stderr, "read_login_info() failed!\n");
86 : }
87 : return ret;
88 : }
89 30 : return continue_logging_in(ctx, conn, cmd, verbose);
90 : }
91 :
92 : /* old way: because I'm too lazy to change every unit test */
93 : CS_RETCODE
94 1300 : try_ctlogin(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
95 : {
96 : CS_RETCODE ret;
97 :
98 1300 : if ((ret = read_login_info()) != CS_SUCCEED) {
99 0 : if (verbose) {
100 0 : fprintf(stderr, "read_login_info() failed!\n");
101 : }
102 : return ret;
103 : }
104 1300 : return continue_logging_in(ctx, conn, cmd, verbose);
105 : }
106 :
107 : CS_RETCODE
108 1330 : continue_logging_in(CS_CONTEXT ** ctx, CS_CONNECTION ** conn, CS_COMMAND ** cmd, int verbose)
109 : {
110 : CS_RETCODE ret;
111 : char query[512+10];
112 1330 : CS_INT bulk_enabled = CS_TRUE;
113 1330 : CS_INT convfmt = CS_DATES_SHORT;
114 :
115 1330 : ret = cs_ctx_alloc(CS_VERSION_100, ctx);
116 1330 : if (ret != CS_SUCCEED) {
117 0 : if (verbose) {
118 0 : fprintf(stderr, "Context Alloc failed!\n");
119 : }
120 : return ret;
121 : }
122 :
123 1330 : ret = cs_dt_info(*ctx, CS_SET, NULL, CS_DT_CONVFMT, CS_UNUSED, &convfmt, sizeof(convfmt), NULL);
124 1330 : if (ret != CS_SUCCEED) {
125 0 : if (verbose) {
126 0 : fprintf(stderr, "Date format initialization failed\n");
127 : }
128 : return ret;
129 : }
130 :
131 1330 : ret = ct_init(*ctx, CS_VERSION_100);
132 1330 : if (ret != CS_SUCCEED) {
133 0 : if (verbose) {
134 0 : fprintf(stderr, "Library Init failed!\n");
135 : }
136 : return ret;
137 : }
138 1330 : if ((ret = ct_callback(*ctx, NULL, CS_SET, CS_CLIENTMSG_CB,
139 : (CS_VOID*) clientmsg_cb)) != CS_SUCCEED) {
140 0 : fprintf(stderr, "ct_callback() failed\n");
141 0 : return ret;
142 : }
143 1330 : if ((ret = ct_callback(*ctx, NULL, CS_SET, CS_SERVERMSG_CB, servermsg_cb)) != CS_SUCCEED) {
144 0 : fprintf(stderr, "ct_callback() failed\n");
145 0 : return ret;
146 : }
147 1330 : ret = ct_con_alloc(*ctx, conn);
148 1330 : if (ret != CS_SUCCEED) {
149 0 : if (verbose) {
150 0 : fprintf(stderr, "Connect Alloc failed!\n");
151 : }
152 : return ret;
153 : }
154 1330 : ret = ct_con_props(*conn, CS_SET, CS_USERNAME, common_pwd.user, CS_NULLTERM, NULL);
155 1330 : if (ret != CS_SUCCEED) {
156 0 : if (verbose) {
157 0 : fprintf(stderr, "ct_con_props() SET USERNAME failed!\n");
158 : }
159 : return ret;
160 : }
161 1330 : ret = ct_con_props(*conn, CS_SET, CS_PASSWORD, common_pwd.password, CS_NULLTERM, NULL);
162 1330 : if (ret != CS_SUCCEED) {
163 0 : if (verbose) {
164 0 : fprintf(stderr, "ct_con_props() SET PASSWORD failed!\n");
165 : }
166 : return ret;
167 : }
168 1330 : ret = ct_con_props(*conn, CS_SET, CS_BULK_LOGIN, &bulk_enabled, CS_UNUSED, NULL);
169 1330 : if (ret != CS_SUCCEED) {
170 0 : if (verbose) {
171 0 : fprintf(stderr, "ct_con_props() SET BULK failed!\n");
172 : }
173 : return ret;
174 : }
175 :
176 1330 : printf("connecting as %s to %s.%s\n", common_pwd.user, common_pwd.server, common_pwd.database);
177 :
178 1330 : ret = ct_connect(*conn, common_pwd.server, CS_NULLTERM);
179 1330 : if (ret != CS_SUCCEED) {
180 0 : if (verbose) {
181 0 : fprintf(stderr, "Connection failed!\n");
182 : }
183 0 : ct_con_drop(*conn);
184 0 : *conn = NULL;
185 0 : ct_exit(*ctx, CS_UNUSED);
186 0 : cs_ctx_drop(*ctx);
187 0 : *ctx = NULL;
188 0 : return ret;
189 : }
190 1330 : ret = ct_cmd_alloc(*conn, cmd);
191 1330 : if (ret != CS_SUCCEED) {
192 0 : if (verbose) {
193 0 : fprintf(stderr, "Command Alloc failed!\n");
194 : }
195 0 : ct_con_drop(*conn);
196 0 : *conn = NULL;
197 0 : ct_exit(*ctx, CS_UNUSED);
198 0 : cs_ctx_drop(*ctx);
199 0 : *ctx = NULL;
200 0 : return ret;
201 : }
202 :
203 1330 : sprintf(query, "use %s", common_pwd.database);
204 :
205 1330 : ret = run_command(*cmd, query);
206 1330 : if (ret != CS_SUCCEED)
207 : return ret;
208 :
209 1330 : return CS_SUCCEED;
210 : }
211 :
212 :
213 : CS_RETCODE
214 1330 : try_ctlogout(CS_CONTEXT * ctx, CS_CONNECTION * conn, CS_COMMAND * cmd, int verbose)
215 : {
216 : CS_RETCODE ret;
217 :
218 1330 : ret = ct_cancel(conn, NULL, CS_CANCEL_ALL);
219 1330 : if (ret != CS_SUCCEED) {
220 0 : if (verbose) {
221 0 : fprintf(stderr, "ct_cancel() failed!\n");
222 : }
223 : return ret;
224 : }
225 1330 : ct_cmd_drop(cmd);
226 1330 : ct_close(conn, CS_UNUSED);
227 1330 : ct_con_drop(conn);
228 1330 : ct_exit(ctx, CS_UNUSED);
229 1330 : cs_ctx_drop(ctx);
230 :
231 1330 : return CS_SUCCEED;
232 : }
233 :
234 : /* Run commands from which we expect no results returned */
235 : CS_RETCODE
236 2456 : run_command(CS_COMMAND * cmd, const char *sql)
237 : {
238 : CS_RETCODE ret, results_ret;
239 : CS_INT result_type;
240 :
241 2456 : if (cmd == NULL) {
242 : return CS_FAIL;
243 : }
244 :
245 2456 : ret = ct_command(cmd, CS_LANG_CMD, (void *) sql, CS_NULLTERM, CS_UNUSED);
246 2456 : if (ret != CS_SUCCEED) {
247 0 : fprintf(stderr, "ct_command() failed\n");
248 0 : return ret;
249 : }
250 2456 : ret = ct_send(cmd);
251 2456 : if (ret != CS_SUCCEED) {
252 2 : fprintf(stderr, "ct_send() failed\n");
253 2 : return ret;
254 : }
255 : ret = CS_SUCCEED;
256 7558 : while ((results_ret = ct_results(cmd, &result_type)) == CS_SUCCEED) {
257 5104 : switch (result_type) {
258 : case CS_CMD_SUCCEED:
259 : break;
260 : case CS_CMD_DONE:
261 : break;
262 68 : case CS_CMD_FAIL:
263 68 : fprintf(stderr, "ct_results() result_type CS_CMD_FAIL.\n");
264 68 : ret = CS_FAIL;
265 68 : break;
266 0 : default:
267 0 : fprintf(stderr, "ct_results() unexpected result_type.\n");
268 0 : return CS_FAIL;
269 : }
270 : }
271 2454 : switch (results_ret) {
272 : case CS_END_RESULTS:
273 : break;
274 0 : case CS_FAIL:
275 0 : fprintf(stderr, "ct_results() failed.\n");
276 0 : return CS_FAIL;
277 : break;
278 0 : default:
279 0 : fprintf(stderr, "ct_results() unexpected return.\n");
280 0 : return CS_FAIL;
281 : }
282 :
283 : return ret;
284 : }
285 :
286 : CS_INT
287 300 : cslibmsg_cb(CS_CONTEXT * connection TDS_UNUSED, CS_CLIENTMSG * errmsg)
288 : {
289 300 : cslibmsg_cb_invoked++;
290 :
291 : ct_reset_last_message();
292 300 : ct_last_message.type = CTMSG_CSLIB;
293 300 : ct_last_message.number = errmsg->msgnumber;
294 300 : strlcpy(ct_last_message.text, errmsg->msgstring, sizeof(ct_last_message.text));
295 :
296 300 : fprintf(stderr, "\nCS-Library Message:\n");
297 1200 : fprintf(stderr, "number %#x layer %d origin %d severity %d number %d\n",
298 : errmsg->msgnumber,
299 600 : (int) CS_LAYER(errmsg->msgnumber), (int) CS_ORIGIN(errmsg->msgnumber),
300 600 : (int) CS_SEVERITY(errmsg->msgnumber), (int) CS_NUMBER(errmsg->msgnumber));
301 300 : fprintf(stderr, "msgstring: %s\n", errmsg->msgstring);
302 300 : fprintf(stderr, "osstring: %s\n", (errmsg->osstringlen > 0)
303 : ? errmsg->osstring : "(null)");
304 300 : return CS_SUCCEED;
305 : }
306 :
307 :
308 :
309 : static CS_RETCODE
310 539 : clientmsg_gen_cb(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg,
311 : ct_message_type msg_type)
312 : {
313 539 : FILE *out = error_to_stdout ? stdout: stderr;
314 :
315 539 : clientmsg_cb_invoked++;
316 :
317 : ct_reset_last_message();
318 539 : ct_last_message.type = msg_type;
319 539 : ct_last_message.number = errmsg->msgnumber;
320 539 : strlcpy(ct_last_message.text, errmsg->msgstring, sizeof(ct_last_message.text));
321 :
322 539 : fprintf(out, "\nOpen Client Message%s: %p %p\n",
323 : msg_type == CTMSG_CLIENT ? "" : " #2", context, connection);
324 2156 : fprintf(out, "number %#x layer %d origin %d severity %d number %d\n",
325 : errmsg->msgnumber,
326 1078 : (int) CS_LAYER(errmsg->msgnumber), (int) CS_ORIGIN(errmsg->msgnumber),
327 1078 : (int) CS_SEVERITY(errmsg->msgnumber), (int) CS_NUMBER(errmsg->msgnumber));
328 539 : fprintf(out, "msgstring: %s\n", errmsg->msgstring);
329 539 : fprintf(out, "osstring: %s\n", (errmsg->osstringlen > 0)
330 : ? errmsg->osstring : "(null)");
331 539 : fflush(out);
332 539 : return CS_SUCCEED;
333 : }
334 :
335 : CS_RETCODE
336 89 : clientmsg_cb(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg)
337 : {
338 89 : return clientmsg_gen_cb(context, connection, errmsg, CTMSG_CLIENT);
339 : }
340 :
341 : CS_RETCODE
342 450 : clientmsg_cb2(CS_CONTEXT * context, CS_CONNECTION * connection, CS_CLIENTMSG * errmsg)
343 : {
344 450 : return clientmsg_gen_cb(context, connection, errmsg, CTMSG_CLIENT2);
345 : }
346 :
347 : CS_RETCODE
348 4116 : servermsg_cb(CS_CONTEXT * context TDS_UNUSED, CS_CONNECTION * connection TDS_UNUSED, CS_SERVERMSG * srvmsg)
349 : {
350 4116 : FILE *out = error_to_stdout ? stdout: stderr;
351 :
352 4116 : servermsg_cb_invoked++;
353 :
354 : ct_reset_last_message();
355 4116 : ct_last_message.type = CTMSG_SERVER;
356 4116 : ct_last_message.number = srvmsg->msgnumber;
357 4116 : strlcpy(ct_last_message.text, srvmsg->text, sizeof(ct_last_message.text));
358 :
359 4116 : if (srvmsg->msgnumber == 5701 || srvmsg->msgnumber == 5703) {
360 3724 : fprintf(out, "%s\n", srvmsg->text);
361 3724 : fflush(out);
362 3724 : return CS_SUCCEED;
363 : }
364 :
365 392 : fprintf(out, "\nServer message:\n");
366 784 : fprintf(out, "%s Message %d severity %d state %d line %d:\n",
367 392 : srvmsg->svrnlen > 0? srvmsg->svrname : "Server",
368 : srvmsg->msgnumber, srvmsg->severity, srvmsg->state, srvmsg->line);
369 392 : if (srvmsg->proclen > 0)
370 24 : fprintf(out, "proc %s: ", srvmsg->proc);
371 392 : fprintf(out, "\t\"%s\"\n", srvmsg->text);
372 :
373 392 : fflush(out);
374 392 : return CS_SUCCEED;
375 : }
376 :
377 : const char *
378 488 : res_type_str(CS_RETCODE ret)
379 : {
380 : static char str[4][32];
381 : static uint8_t last_used;
382 : uint8_t n;
383 :
384 : #define S(s) case s: return #s;
385 488 : switch ((int) ret) {
386 : S(CS_ROW_RESULT)
387 0 : S(CS_PARAM_RESULT)
388 82 : S(CS_STATUS_RESULT)
389 0 : S(CS_MSG_RESULT)
390 80 : S(CS_CMD_SUCCEED)
391 186 : S(CS_CMD_DONE)
392 12 : S(CS_CMD_FAIL)
393 24 : S(CS_COMPUTE_RESULT)
394 : #undef S
395 : }
396 :
397 0 : n = (last_used++) & 3;
398 0 : snprintf(str[n], sizeof(str[0]), "?? (%d)", (int) ret);
399 0 : return str[n];
400 : }
401 :
402 : void
403 12286 : _check_ret(const char *name, CS_RETCODE ret, int line)
404 : {
405 12286 : if (ret != CS_SUCCEED) {
406 0 : fprintf(stderr, "%s():%d: failed\n", name, line);
407 0 : exit(1);
408 : }
409 12286 : }
410 :
411 : void
412 830 : ct_reset_last_message(void)
413 : {
414 5785 : memset(&ct_last_message, 0, sizeof(ct_last_message));
415 830 : }
|