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 : void
41 40 : normalize_spaces(char *s)
42 : {
43 : char *p, *dest, prev;
44 :
45 : /* replace all tabs with spaces */
46 18038 : for (p = s; *p; ++p)
47 17998 : if (*p == '\t')
48 242 : *p = ' ';
49 :
50 : /* replace duplicate spaces with a single space */
51 : prev = 'x';
52 17998 : for (dest = s, p = s; *p; ++p) {
53 17998 : if (prev == ' ' && *p == ' ')
54 774 : continue;
55 17224 : *dest++ = prev = *p;
56 : }
57 40 : *dest = 0;
58 40 : }
59 :
60 : void
61 40 : cat(const char *fn, FILE *out)
62 : {
63 : char line[1024];
64 40 : FILE *f = fopen(fn, "r");
65 :
66 40 : assert(f);
67 582 : while (fgets(line, sizeof(line), f)) {
68 542 : fputs(" ", out);
69 542 : fputs(line, out);
70 : }
71 40 : fclose(f);
72 40 : }
73 :
74 : /* read a text file into memory, return it as a string */
75 : char *
76 40 : read_file(const char *fn)
77 : {
78 : long pos;
79 : char *buf;
80 : size_t readed, size;
81 :
82 40 : FILE *f = fopen(fn, "r");
83 :
84 40 : assert(f);
85 40 : assert(fseek(f, 0, SEEK_END) == 0);
86 40 : pos = ftell(f);
87 40 : assert(pos >= 0 && pos <= 0x1000000);
88 40 : size = (size_t) pos;
89 40 : assert(fseek(f, 0, SEEK_SET) == 0);
90 40 : buf = malloc(size + 10); /* allocate some more space */
91 40 : assert(buf);
92 40 : readed = fread(buf, 1, size + 1ul, f);
93 40 : assert(readed <= size);
94 40 : assert(feof(f));
95 40 : fclose(f);
96 40 : buf[readed] = 0;
97 40 : return buf;
98 : }
99 :
100 : #define CHECK(n) do {\
101 : if (dest + (n) > dest_end) \
102 : no_space(); \
103 : } while(0)
104 :
105 : char *
106 1170 : quote_arg(char *dest, char *const dest_end, const char *arg)
107 : {
108 : #ifndef _WIN32
109 1170 : CHECK(1);
110 1170 : *dest++ = '\'';
111 10528 : for (; *arg; ++arg) {
112 9358 : if (*arg == '\'') {
113 0 : CHECK(3);
114 0 : strcpy(dest, "'\\'");
115 0 : dest += 3;
116 : }
117 9358 : CHECK(1);
118 9358 : *dest++ = *arg;
119 : }
120 1170 : CHECK(1);
121 1170 : *dest++ = '\'';
122 : #else
123 : CHECK(1);
124 : *dest++ = '\"';
125 : for (; *arg; ++arg) {
126 : if (*arg == '\\' || *arg == '\"') {
127 : CHECK(1);
128 : *dest++ = '\\';
129 : }
130 : CHECK(1);
131 : *dest++ = *arg;
132 : }
133 : CHECK(1);
134 : *dest++ = '\"';
135 : #endif
136 1170 : return dest;
137 : }
138 :
139 : char *
140 2270 : add_string(char *dest, char *const dest_end, const char *str)
141 : {
142 2270 : size_t len = strlen(str);
143 :
144 2270 : CHECK(len);
145 2270 : memcpy(dest, str, len);
146 2270 : return dest + len;
147 : }
148 :
149 : #undef CHECK
150 :
151 : char *
152 270 : add_server(char *dest, char *const dest_end)
153 : {
154 270 : dest = add_string(dest, dest_end, " -S ");
155 270 : dest = quote_arg(dest, dest_end, common_pwd.server);
156 270 : dest = add_string(dest, dest_end, " -U ");
157 270 : dest = quote_arg(dest, dest_end, common_pwd.user);
158 270 : dest = add_string(dest, dest_end, " -P ");
159 270 : dest = quote_arg(dest, dest_end, common_pwd.password);
160 270 : if (common_pwd.database[0]) {
161 270 : dest = add_string(dest, dest_end, " -D ");
162 270 : dest = quote_arg(dest, dest_end, common_pwd.database);
163 : }
164 270 : return dest;
165 : }
166 :
167 : char *
168 10 : add_login(char *dest, char *const dest_end)
169 : {
170 10 : dest = add_string(dest, dest_end, " -S ");
171 10 : dest = quote_arg(dest, dest_end, common_pwd.server);
172 10 : dest = add_string(dest, dest_end, " -U ");
173 10 : dest = quote_arg(dest, dest_end, common_pwd.user);
174 10 : dest = add_string(dest, dest_end, " -P ");
175 10 : dest = quote_arg(dest, dest_end, common_pwd.password);
176 10 : return dest;
177 : }
178 :
179 : void
180 20 : update_path(void)
181 : {
182 : static const tds_dir_char name[] = TDS_DIR("PATH");
183 20 : tds_dir_char *path = tds_dir_getenv(name);
184 :
185 : #ifndef _WIN32
186 : int len;
187 :
188 20 : if (!path) {
189 0 : setenv(name, "..", 1);
190 0 : return;
191 : }
192 :
193 20 : len = asprintf(&path, "..:%s", path);
194 20 : assert(len > 0);
195 20 : setenv(name, path, 1);
196 : #else
197 : const tds_dir_char *only = L"PATH=..";
198 : const tds_dir_char *start = L"PATH=..;%s";
199 : tds_dir_char *p;
200 : size_t len;
201 :
202 : #ifdef CMAKE_INTDIR
203 : if (CMAKE_INTDIR[0]) {
204 : only = L"PATH=..\\" TDS_DIR(CMAKE_INTDIR);
205 : start = L"PATH=..\\" TDS_DIR(CMAKE_INTDIR) L";%s";
206 : }
207 : #endif
208 :
209 : if (!path) {
210 : _wputenv(only);
211 : return;
212 : }
213 :
214 : len = tds_dir_len(path) + 100;
215 : p = tds_new(tds_dir_char, len);
216 : assert(p);
217 : tds_dir_snprintf(p, len, start, path);
218 : path = p;
219 : _wputenv(path);
220 : #endif
221 20 : free(path);
222 : }
223 :
224 : static char *
225 230 : tsql_generic(const char *input_data, bool get_output)
226 : {
227 : char cmd[2048];
228 230 : char *const end = cmd + sizeof(cmd) - 1;
229 : char *p;
230 230 : char *output = NULL;
231 : FILE *f;
232 : bool success;
233 :
234 230 : f = fopen(input_fn(), "w");
235 230 : assert(f);
236 230 : fputs(input_data, f);
237 230 : fclose(f);
238 :
239 230 : strcpy(cmd, "tsql" EXE_SUFFIX " -o q");
240 230 : p = strchr(cmd, 0);
241 230 : p = add_server(p, end);
242 230 : p = add_string(p, end, "<");
243 230 : p = add_string(p, end, input_fn());
244 230 : p = add_string(p, end, " >");
245 230 : p = add_string(p, end, output_fn());
246 230 : *p = 0;
247 230 : printf("Executing: %s\n", cmd);
248 230 : success = (system(cmd) == 0);
249 230 : unlink(input_fn());
250 230 : if (!success) {
251 0 : printf("Output is:\n");
252 0 : cat(output_fn(), stdout);
253 0 : unlink(output_fn());
254 0 : fprintf(stderr, "Failed command\n");
255 0 : exit(1);
256 : }
257 230 : if (get_output)
258 0 : output = read_file(output_fn());
259 230 : unlink(output_fn());
260 230 : return output;
261 : }
262 :
263 : void
264 230 : tsql(const char *input_data)
265 : {
266 230 : tsql_generic(input_data, false);
267 230 : }
268 :
269 : char *
270 0 : tsql_out(const char *input_data)
271 : {
272 0 : return tsql_generic(input_data, true);
273 : }
274 :
275 : static const char *
276 1450 : get_fn(char *buf, const char *prefix)
277 : {
278 1450 : if (!buf[0])
279 40 : sprintf(buf, "%s.%d", prefix, (int) getpid());
280 1450 : return buf;
281 : }
282 :
283 : const char *
284 140 : input_fn(void)
285 : {
286 : static char buf[32] = { 0 };
287 :
288 830 : return get_fn(buf, "input");
289 : }
290 :
291 : const char *
292 160 : output_fn(void)
293 : {
294 : static char buf[32] = { 0 };
295 :
296 620 : return get_fn(buf, "output");
297 : }
|