Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 2024-2026 Frediano Ziglio
3 : *
4 : * This library is free software; you can redistribute it and/or
5 : * modify it under the terms of the GNU Library General Public
6 : * License as published by the Free Software Foundation; either
7 : * version 2 of the License, or (at your option) any later version.
8 : *
9 : * This library is distributed in the hope that it will be useful,
10 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : * Library General Public License for more details.
13 : *
14 : * You should have received a copy of the GNU Library General Public
15 : * License along with this library; if not, write to the
16 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 : * Boston, MA 02111-1307, USA.
18 : */
19 :
20 : #include "common.h"
21 :
22 : #if HAVE_STRING_H
23 : #include <string.h>
24 : #endif /* HAVE_STRING_H */
25 :
26 : #ifdef HAVE_UNISTD_H
27 : #include <unistd.h>
28 : #endif
29 :
30 : #include <freetds/sysdep_private.h>
31 : #include <freetds/utils/path.h>
32 :
33 : static void
34 0 : no_space(void)
35 : {
36 0 : fprintf(stderr, "No space left on buffer\n");
37 0 : exit(1);
38 : }
39 :
40 : /* This is used when comparing defncopy output to expected output */
41 : void
42 160 : normalize_spaces(char *s)
43 : {
44 : char *p, *dest, prev;
45 :
46 : /* replace all tabs & newlines with spaces */
47 44936 : for (p = s; *p; ++p)
48 44776 : if (*p == '\t' || *p == '\n' || *p == '\r')
49 1510 : *p = ' ';
50 :
51 : /* replace duplicate spaces with a single space */
52 : prev = 'x';
53 44776 : for (dest = s, p = s; *p; ++p) {
54 44776 : if (prev == ' ' && *p == ' ')
55 1480 : continue;
56 43296 : *dest++ = prev = *p;
57 : }
58 :
59 : /* trailing space not significant */
60 300 : while (dest > s && dest[-1] == ' ')
61 140 : --dest;
62 160 : *dest = 0;
63 :
64 : /* spaces between , and ] not significant */
65 382 : while ((p = strstr(s, ", ]")) != NULL)
66 62 : memmove(p + 1, p + 2, strlen(p + 2) + 1);
67 160 : }
68 :
69 : void
70 40 : cat(const char *fn, FILE *out)
71 : {
72 : char line[1024];
73 40 : FILE *f = fopen(fn, "r");
74 :
75 40 : if (!f) {
76 : /* Can happen if e.g. .exe file not found, so no output */
77 0 : fputs("<output file not found>\n", out);
78 0 : return;
79 : }
80 :
81 432 : while (fgets(line, sizeof(line), f)) {
82 392 : fputs(" ", out);
83 392 : fputs(line, out);
84 : }
85 40 : fclose(f);
86 : }
87 :
88 : /* read a text file into memory, return it as a string */
89 : char *
90 80 : read_file(const char *fn)
91 : {
92 : long pos;
93 : char *buf;
94 : size_t readed, size;
95 :
96 80 : FILE *f = fopen(fn, "r");
97 :
98 80 : assert(f);
99 80 : assert(fseek(f, 0, SEEK_END) == 0);
100 80 : pos = ftell(f);
101 80 : assert(pos >= 0 && pos <= 0x1000000);
102 80 : size = (size_t) pos;
103 80 : assert(fseek(f, 0, SEEK_SET) == 0);
104 80 : buf = malloc(size + 10); /* allocate some more space */
105 80 : assert(buf);
106 80 : readed = fread(buf, 1, size + 1ul, f);
107 80 : assert(readed <= size);
108 80 : assert(feof(f));
109 80 : fclose(f);
110 80 : buf[readed] = 0;
111 80 : return buf;
112 : }
113 :
114 : #define CHECK(n) do {\
115 : if (dest + (n) > dest_end) \
116 : no_space(); \
117 : } while(0)
118 :
119 : char *
120 1690 : quote_arg(char *dest, char *const dest_end, const char *arg)
121 : {
122 : #if !defined(_WIN32) && !defined(__VMS)
123 1690 : CHECK(1);
124 1690 : *dest++ = '\'';
125 15840 : for (; *arg; ++arg) {
126 14150 : if (*arg == '\'') {
127 0 : CHECK(3);
128 0 : strcpy(dest, "'\\'");
129 0 : dest += 3;
130 : }
131 14150 : CHECK(1);
132 14150 : *dest++ = *arg;
133 : }
134 1690 : CHECK(1);
135 1690 : *dest++ = '\'';
136 : #else
137 : CHECK(1);
138 : *dest++ = '\"';
139 : for (; *arg; ++arg) {
140 : if (*arg == '\\' || *arg == '\"') {
141 : CHECK(1);
142 : *dest++ = '\\';
143 : }
144 : CHECK(1);
145 : *dest++ = *arg;
146 : }
147 : CHECK(1);
148 : *dest++ = '\"';
149 : #endif
150 1690 : return dest;
151 : }
152 :
153 : char *
154 3050 : add_string(char *dest, char *const dest_end, const char *str)
155 : {
156 3050 : size_t len = strlen(str);
157 :
158 3050 : CHECK(len);
159 3050 : memcpy(dest, str, len);
160 3050 : return dest + len;
161 : }
162 :
163 : #undef CHECK
164 :
165 : char *
166 350 : add_server(char *dest, char *const dest_end)
167 : {
168 350 : dest = add_string(dest, dest_end, " -S ");
169 350 : dest = quote_arg(dest, dest_end, common_pwd.server);
170 350 : dest = add_string(dest, dest_end, " -U ");
171 350 : dest = quote_arg(dest, dest_end, common_pwd.user);
172 350 : dest = add_string(dest, dest_end, " -P ");
173 350 : dest = quote_arg(dest, dest_end, common_pwd.password);
174 350 : if (common_pwd.database[0]) {
175 350 : dest = add_string(dest, dest_end, " -D ");
176 350 : dest = quote_arg(dest, dest_end, common_pwd.database);
177 : }
178 350 : return dest;
179 : }
180 :
181 : char *
182 50 : add_login(char *dest, char *const dest_end)
183 : {
184 50 : dest = add_string(dest, dest_end, " -S ");
185 50 : dest = quote_arg(dest, dest_end, common_pwd.server);
186 50 : dest = add_string(dest, dest_end, " -U ");
187 50 : dest = quote_arg(dest, dest_end, common_pwd.user);
188 50 : dest = add_string(dest, dest_end, " -P ");
189 50 : dest = quote_arg(dest, dest_end, common_pwd.password);
190 50 : return dest;
191 : }
192 :
193 : void
194 20 : update_path(void)
195 : {
196 : static const tds_dir_char name[] = TDS_DIR("PATH");
197 20 : tds_dir_char *path = tds_dir_getenv(name);
198 :
199 : #ifndef _WIN32
200 : int len;
201 :
202 20 : if (!path) {
203 0 : setenv(name, "..", 1);
204 0 : return;
205 : }
206 :
207 20 : len = asprintf(&path, "..:%s", path);
208 20 : assert(len > 0);
209 20 : setenv(name, path, 1);
210 : #else
211 : const tds_dir_char *only = L"PATH=..";
212 : const tds_dir_char *start = L"PATH=..;%s";
213 : tds_dir_char *p;
214 : size_t len;
215 :
216 : #ifdef CMAKE_INTDIR
217 : if (CMAKE_INTDIR[0]) {
218 : only = L"PATH=..\\" TDS_DIR(CMAKE_INTDIR);
219 : start = L"PATH=..\\" TDS_DIR(CMAKE_INTDIR) L";%s";
220 : }
221 : #endif
222 :
223 : if (!path) {
224 : _wputenv(only);
225 : return;
226 : }
227 :
228 : len = tds_dir_len(path) + 100;
229 : p = tds_new(tds_dir_char, len);
230 : assert(p);
231 : tds_dir_snprintf(p, len, start, path);
232 : path = p;
233 : _wputenv(path);
234 : #endif
235 20 : free(path);
236 : }
237 :
238 : static char *
239 270 : tsql_generic(const char *input_data, bool get_output)
240 : {
241 : char cmd[2048];
242 270 : char *const end = cmd + sizeof(cmd) - 1;
243 : char *p;
244 270 : char *output = NULL;
245 : FILE *f;
246 : bool success;
247 :
248 270 : f = fopen(input_fn(), "w");
249 270 : assert(f);
250 270 : fputs(input_data, f);
251 270 : fclose(f);
252 :
253 270 : strcpy(cmd, VMS_APP_EXE_INVOKE "tsql" EXE_SUFFIX " -o q");
254 270 : p = strchr(cmd, 0);
255 270 : p = add_server(p, end);
256 270 : p = add_string(p, end, " <");
257 270 : p = add_string(p, end, input_fn());
258 270 : p = add_string(p, end, " >");
259 270 : p = add_string(p, end, output_fn());
260 270 : *p = 0;
261 270 : printf("Executing: %s\n", cmd);
262 270 : success = (system(cmd) == 0);
263 270 : unlink(input_fn());
264 270 : if (!success) {
265 0 : printf("Output is:\n");
266 0 : cat(output_fn(), stdout);
267 0 : unlink(output_fn());
268 0 : fprintf(stderr, "Failed command\n");
269 0 : exit(1);
270 : }
271 270 : if (get_output)
272 0 : output = read_file(output_fn());
273 270 : unlink(output_fn());
274 270 : return output;
275 : }
276 :
277 : void
278 270 : tsql(const char *input_data)
279 : {
280 270 : tsql_generic(input_data, false);
281 270 : }
282 :
283 : char *
284 0 : tsql_out(const char *input_data)
285 : {
286 0 : return tsql_generic(input_data, true);
287 : }
288 :
289 : static const char *
290 1780 : get_fn(char *buf, const char *prefix)
291 : {
292 1780 : if (!buf[0])
293 40 : sprintf(buf, "%s.%d", prefix, (int) getpid());
294 1780 : return buf;
295 : }
296 :
297 : const char *
298 150 : input_fn(void)
299 : {
300 : static char buf[32] = { 0 };
301 :
302 960 : return get_fn(buf, "input");
303 : }
304 :
305 : const char *
306 280 : output_fn(void)
307 : {
308 : static char buf[32] = { 0 };
309 :
310 820 : return get_fn(buf, "output");
311 : }
|