Line data Source code
1 : /* FreeTDS - Library of routines accessing Sybase and Microsoft databases
2 : * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 Brian Bruns
3 : * Copyright (C) 2005-2015 Frediano Ziglio
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Library General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2 of the License, or (at your option) any later version.
9 : *
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Library General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU Library General Public
16 : * License along with this library; if not, write to the
17 : * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 : * Boston, MA 02111-1307, USA.
19 : */
20 :
21 : #include <config.h>
22 :
23 : #include <stdarg.h>
24 : #include <stdio.h>
25 :
26 : #if HAVE_UNISTD_H
27 : #include <unistd.h>
28 : #endif /* HAVE_UNISTD_H */
29 :
30 : #include <freetds/time.h>
31 :
32 : #if defined(HAVE_GETUID) && defined(HAVE_GETPWUID)
33 : #include <pwd.h>
34 : #endif
35 :
36 : #if HAVE_STDLIB_H
37 : #include <stdlib.h>
38 : #endif /* HAVE_STDLIB_H */
39 :
40 : #if HAVE_STRING_H
41 : #include <string.h>
42 : #endif /* HAVE_STRING_H */
43 :
44 : #if HAVE_NETDB_H
45 : #include <netdb.h>
46 : #endif /* HAVE_NETDB_H */
47 :
48 : #if HAVE_ERRNO_H
49 : #include <errno.h>
50 : #endif /* HAVE_ERRNO_H */
51 :
52 : #if HAVE_SYS_SOCKET_H
53 : #include <sys/socket.h>
54 : #endif /* HAVE_SYS_SOCKET_H */
55 :
56 : #if HAVE_NETINET_IN_H
57 : #include <netinet/in.h>
58 : #endif /* HAVE_NETINET_IN_H */
59 :
60 : #if HAVE_ARPA_INET_H
61 : #include <arpa/inet.h>
62 : #endif /* HAVE_ARPA_INET_H */
63 :
64 : #if HAVE_ROKEN_H
65 : #include <roken.h>
66 : #endif /* HAVE_ROKEN_H */
67 :
68 : #if defined(_WIN32) || defined(_WIN64)
69 : #include <winsock2.h>
70 : #include <shlobj.h>
71 : #endif
72 :
73 : #include <freetds/sysdep_private.h>
74 : #include <freetds/utils.h>
75 : #include <freetds/thread.h>
76 : #include <freetds/replacements.h>
77 :
78 : struct tm *
79 66 : tds_localtime_r(const time_t *timep, struct tm *result)
80 : {
81 : struct tm *tm;
82 :
83 : #if defined(_REENTRANT) && !defined(_WIN32)
84 : #if HAVE_FUNC_LOCALTIME_R_TM
85 944 : tm = localtime_r(timep, result);
86 : #else
87 : tm = NULL;
88 : if (!localtime_r(timep, result))
89 : tm = result;
90 : #endif /* HAVE_FUNC_LOCALTIME_R_TM */
91 : #else
92 : tm = localtime(timep);
93 : if (tm) {
94 : memcpy(result, tm, sizeof(*result));
95 : tm = result;
96 : }
97 : #endif
98 66 : return tm;
99 : }
100 :
101 : char *
102 878 : tds_timestamp_str(char *str, int maxlen)
103 : {
104 : #if !defined(_WIN32) && !defined(_WIN64)
105 : struct tm *tm;
106 : struct tm res;
107 : time_t t;
108 :
109 : #if HAVE_GETTIMEOFDAY
110 : struct timeval tv;
111 : char usecs[10];
112 :
113 878 : gettimeofday(&tv, NULL);
114 878 : t = tv.tv_sec;
115 : #else
116 : /*
117 : * XXX Need to get a better time resolution for
118 : * systems that don't have gettimeofday().
119 : */
120 : time(&t);
121 : #endif
122 :
123 878 : tm = tds_localtime_r(&t, &res);
124 :
125 : /** strftime(str, maxlen - 6, "%Y-%m-%d %H:%M:%S", tm); **/
126 878 : strftime(str, maxlen - 6, "%H:%M:%S", tm);
127 :
128 : #if HAVE_GETTIMEOFDAY
129 878 : sprintf(usecs, ".%06lu", (long) tv.tv_usec);
130 878 : strcat(str, usecs);
131 : #endif
132 :
133 : #else /* _WIN32 */
134 : SYSTEMTIME st;
135 :
136 : GetLocalTime(&st);
137 : _snprintf(str, maxlen - 1, "%02u:%02u:%02u.%03u", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
138 : str[maxlen - 1] = 0;
139 : #endif
140 :
141 878 : return str;
142 : }
143 :
144 : /*
145 : * If reentrant code was not requested, we don't care reentrancy, so
146 : * just assume the standard BSD netdb interface is reentrant and use it.
147 : */
148 : #ifndef _REENTRANT
149 : # undef NETDB_REENTRANT
150 : # define NETDB_REENTRANT 1
151 : #endif /* _REENTRANT */
152 :
153 : #if 0
154 : #undef HAVE_GETADDRINFO
155 : #undef NETDB_REENTRANT
156 : #undef HAVE_FUNC_GETSERVBYNAME_R_6
157 : #undef HAVE_FUNC_GETSERVBYNAME_R_5
158 : #undef HAVE_FUNC_GETSERVBYNAME_R_4
159 : #undef TDS_NO_THREADSAFE
160 :
161 : # if 0
162 : # define HAVE_FUNC_GETSERVBYNAME_R_6 1
163 : int test_getservbyname_r(const char *name, const char *proto,
164 : struct servent *result_buf, char *buffer,
165 : size_t buflen, struct servent **result);
166 : # define getservbyname_r test_getservbyname_r
167 : # elif 0
168 : # define HAVE_FUNC_GETSERVBYNAME_R_5 1
169 : struct servent *
170 : test_getservbyname_r(const char *name, const char *proto,
171 : struct servent *result_buf, char *buffer,
172 : size_t buflen);
173 : # define getservbyname_r test_getservbyname_r
174 : # else
175 : # define HAVE_FUNC_GETSERVBYNAME_R_4 1
176 : struct servent_data { int dummy; };
177 : int
178 : test_getservbyname_r(const char *name, const char *proto,
179 : struct servent *result_buf,
180 : struct servent_data *data);
181 : # define getservbyname_r test_getservbyname_r
182 : # endif
183 : #endif
184 :
185 : /**
186 : * Return service port given the name
187 : */
188 : int
189 2 : tds_getservice(const char *name)
190 : {
191 : #if defined(HAVE_GETADDRINFO)
192 : /* new OSes should implement this in a proper way */
193 : struct addrinfo hints, *res;
194 : int result;
195 :
196 2 : memset(&hints, 0, sizeof(hints));
197 2 : hints.ai_family = AF_INET;
198 2 : hints.ai_socktype = SOCK_STREAM;
199 2 : hints.ai_flags = AI_PASSIVE;
200 2 : res = NULL;
201 2 : if (getaddrinfo(NULL, name, &hints, &res))
202 : return 0;
203 2 : if (res->ai_family != AF_INET || !res->ai_addr) {
204 0 : freeaddrinfo(res);
205 0 : return 0;
206 : }
207 2 : result = ntohs(((struct sockaddr_in *) res->ai_addr)->sin_port);
208 2 : freeaddrinfo(res);
209 2 : return result;
210 :
211 : #elif defined(NETDB_REENTRANT)
212 : /* HP-UX/Windows */
213 : struct servent *result = getservbyname(name, "tcp");
214 : return result ? ntohs(result->s_port) : 0;
215 :
216 : #elif defined(HAVE_FUNC_GETSERVBYNAME_R_6)
217 : /* Linux variant */
218 : struct servent *result = NULL;
219 : struct servent result_buf;
220 : char buffer[4096];
221 :
222 : if (!getservbyname_r(name, "tcp", &result_buf, buffer, sizeof(buffer), &result))
223 : return ntohs(result->s_port);
224 : return 0;
225 :
226 : #elif defined(HAVE_FUNC_GETSERVBYNAME_R_5)
227 : /* Solaris variant */
228 : struct servent result;
229 : char buffer[4096];
230 :
231 : if (getservbyname_r(name, "tcp", &result, buffer, sizeof(buffer)))
232 : return ntohs(result.s_port);
233 : return 0;
234 :
235 : #elif defined(HAVE_FUNC_GETSERVBYNAME_R_4)
236 : /* AIX/BSD variant */
237 : struct servent result;
238 : struct servent_data data;
239 :
240 : if (!getservbyname_r(name, "tcp", &result, &data))
241 : return ntohs(result.s_port);
242 : return 0;
243 :
244 : #elif defined(TDS_NO_THREADSAFE)
245 : struct servent *result = getservbyname(name, "tcp");
246 : return result ? ntohs(result->s_port) : 0;
247 : #else
248 : #error getservbyname_r style unknown
249 : #endif
250 : }
251 :
252 : /**
253 : * Get user home directory
254 : * @return home directory or NULL if error. Should be freed with free
255 : */
256 : char *
257 2974 : tds_get_homedir(void)
258 : {
259 : #ifndef _WIN32
260 : /* if is available getpwuid_r use it */
261 : #if defined(HAVE_GETUID) && defined(HAVE_GETPWUID_R)
262 : struct passwd *pw, bpw;
263 : char buf[1024];
264 :
265 : # if defined(HAVE_FUNC_GETPWUID_R_5)
266 : /* getpwuid_r can return 0 if uid is not found so check pw */
267 2974 : pw = NULL;
268 2974 : if (getpwuid_r(getuid(), &bpw, buf, sizeof(buf), &pw) || !pw)
269 : return NULL;
270 :
271 : # elif defined(HAVE_FUNC_GETPWUID_R_4_PW)
272 : if (!(pw = getpwuid_r(getuid(), &bpw, buf, sizeof(buf))))
273 : return NULL;
274 : # else /* !HAVE_FUNC_GETPWUID_R_4_PW */
275 : if (getpwuid_r(getuid(), &bpw, buf, sizeof(buf)))
276 : return NULL;
277 : pw = &bpw;
278 : # endif
279 :
280 2974 : return strdup(pw->pw_dir);
281 :
282 : /* if getpwuid is available use it for no reentrant (getpwuid is not reentrant) */
283 : #elif defined(HAVE_GETUID) && defined(HAVE_GETPWUID) && !defined(_REENTRANT)
284 : struct passwd *pw;
285 :
286 : pw = getpwuid(getuid());
287 : if (!pw)
288 : return NULL;
289 : return strdup(pw->pw_dir);
290 : #else
291 : char *home;
292 :
293 : home = getenv("HOME");
294 : if (!home || !home[0])
295 : return NULL;
296 : return strdup(home);
297 : #endif
298 : #else /* _WIN32 */
299 : /*
300 : * For win32 we return application data cause we use "HOME"
301 : * only to store configuration files
302 : */
303 : HRESULT hr;
304 : LPMALLOC pMalloc = NULL;
305 : char * res = NULL;
306 :
307 : hr = SHGetMalloc(&pMalloc);
308 : if (!FAILED(hr)) {
309 : LPITEMIDLIST pidl;
310 : hr = SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl);
311 : if (!FAILED(hr)) {
312 : /*
313 : * SHGetPathFromIDListA() tries to count the length of "path",
314 : * so we have to make sure that it has only zeros; otherwise,
315 : * invalid memory access is inevitable.
316 : */
317 : char path[MAX_PATH] = "";
318 : if (SHGetPathFromIDList(pidl, path))
319 : res = strdup(path);
320 : (*pMalloc->lpVtbl->Free)(pMalloc, pidl);
321 : }
322 : (*pMalloc->lpVtbl->Release)(pMalloc);
323 : }
324 : return res;
325 : #endif
326 : }
327 :
|