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