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/utils/path.h>
76 : #include <freetds/thread.h>
77 : #include <freetds/replacements.h>
78 :
79 : struct tm *
80 66 : tds_localtime_r(const time_t *timep, struct tm *result)
81 : {
82 : struct tm *tm;
83 :
84 : #if defined(_REENTRANT) && !defined(_WIN32)
85 : #if HAVE_FUNC_LOCALTIME_R_TM
86 944 : tm = localtime_r(timep, result);
87 : #else
88 : tm = NULL;
89 : if (!localtime_r(timep, result))
90 : tm = result;
91 : #endif /* HAVE_FUNC_LOCALTIME_R_TM */
92 : #else
93 : tm = localtime(timep);
94 : if (tm) {
95 : memcpy(result, tm, sizeof(*result));
96 : tm = result;
97 : }
98 : #endif
99 66 : return tm;
100 : }
101 :
102 : char *
103 878 : tds_timestamp_str(char *str, int maxlen)
104 : {
105 : #if !defined(_WIN32) && !defined(_WIN64)
106 : struct tm *tm;
107 : struct tm res;
108 : time_t t;
109 :
110 : #if HAVE_GETTIMEOFDAY
111 : struct timeval tv;
112 : char usecs[10];
113 :
114 878 : gettimeofday(&tv, NULL);
115 878 : t = tv.tv_sec;
116 : #else
117 : /*
118 : * XXX Need to get a better time resolution for
119 : * systems that don't have gettimeofday().
120 : */
121 : time(&t);
122 : #endif
123 :
124 878 : tm = tds_localtime_r(&t, &res);
125 :
126 : /** strftime(str, maxlen - 6, "%Y-%m-%d %H:%M:%S", tm); **/
127 878 : strftime(str, maxlen - 6, "%H:%M:%S", tm);
128 :
129 : #if HAVE_GETTIMEOFDAY
130 878 : sprintf(usecs, ".%06lu", (long) tv.tv_usec);
131 878 : strcat(str, usecs);
132 : #endif
133 :
134 : #else /* _WIN32 */
135 : SYSTEMTIME st;
136 :
137 : GetLocalTime(&st);
138 : _snprintf(str, maxlen - 1, "%02u:%02u:%02u.%03u", st.wHour, st.wMinute, st.wSecond, st.wMilliseconds);
139 : str[maxlen - 1] = 0;
140 : #endif
141 :
142 878 : return str;
143 : }
144 :
145 : /*
146 : * If reentrant code was not requested, we don't care reentrancy, so
147 : * just assume the standard BSD netdb interface is reentrant and use it.
148 : */
149 : #ifndef _REENTRANT
150 : # undef NETDB_REENTRANT
151 : # define NETDB_REENTRANT 1
152 : #endif /* _REENTRANT */
153 :
154 : #if 0
155 : #undef HAVE_GETADDRINFO
156 : #undef NETDB_REENTRANT
157 : #undef HAVE_FUNC_GETSERVBYNAME_R_6
158 : #undef HAVE_FUNC_GETSERVBYNAME_R_5
159 : #undef HAVE_FUNC_GETSERVBYNAME_R_4
160 : #undef TDS_NO_THREADSAFE
161 :
162 : # if 0
163 : # define HAVE_FUNC_GETSERVBYNAME_R_6 1
164 : int test_getservbyname_r(const char *name, const char *proto,
165 : struct servent *result_buf, char *buffer,
166 : size_t buflen, struct servent **result);
167 : # define getservbyname_r test_getservbyname_r
168 : # elif 0
169 : # define HAVE_FUNC_GETSERVBYNAME_R_5 1
170 : struct servent *
171 : test_getservbyname_r(const char *name, const char *proto,
172 : struct servent *result_buf, char *buffer,
173 : size_t buflen);
174 : # define getservbyname_r test_getservbyname_r
175 : # else
176 : # define HAVE_FUNC_GETSERVBYNAME_R_4 1
177 : struct servent_data { int dummy; };
178 : int
179 : test_getservbyname_r(const char *name, const char *proto,
180 : struct servent *result_buf,
181 : struct servent_data *data);
182 : # define getservbyname_r test_getservbyname_r
183 : # endif
184 : #endif
185 :
186 : /**
187 : * Return service port given the name
188 : */
189 : int
190 2 : tds_getservice(const char *name)
191 : {
192 : #if defined(HAVE_GETADDRINFO)
193 : /* new OSes should implement this in a proper way */
194 : struct addrinfo hints, *res;
195 : int result;
196 :
197 2 : memset(&hints, 0, sizeof(hints));
198 2 : hints.ai_family = AF_INET;
199 2 : hints.ai_socktype = SOCK_STREAM;
200 2 : hints.ai_flags = AI_PASSIVE;
201 2 : res = NULL;
202 2 : if (getaddrinfo(NULL, name, &hints, &res))
203 : return 0;
204 2 : if (res->ai_family != AF_INET || !res->ai_addr) {
205 0 : freeaddrinfo(res);
206 0 : return 0;
207 : }
208 2 : result = ntohs(((struct sockaddr_in *) res->ai_addr)->sin_port);
209 2 : freeaddrinfo(res);
210 2 : return result;
211 :
212 : #elif defined(NETDB_REENTRANT)
213 : /* HP-UX/Windows */
214 : struct servent *result = getservbyname(name, "tcp");
215 : return result ? ntohs(result->s_port) : 0;
216 :
217 : #elif defined(HAVE_FUNC_GETSERVBYNAME_R_6)
218 : /* Linux variant */
219 : struct servent *result = NULL;
220 : struct servent result_buf;
221 : char buffer[4096];
222 :
223 : if (!getservbyname_r(name, "tcp", &result_buf, buffer, sizeof(buffer), &result))
224 : return ntohs(result->s_port);
225 : return 0;
226 :
227 : #elif defined(HAVE_FUNC_GETSERVBYNAME_R_5)
228 : /* Solaris variant */
229 : struct servent result;
230 : char buffer[4096];
231 :
232 : if (getservbyname_r(name, "tcp", &result, buffer, sizeof(buffer)))
233 : return ntohs(result.s_port);
234 : return 0;
235 :
236 : #elif defined(HAVE_FUNC_GETSERVBYNAME_R_4)
237 : /* AIX/BSD variant */
238 : struct servent result;
239 : struct servent_data data;
240 :
241 : if (!getservbyname_r(name, "tcp", &result, &data))
242 : return ntohs(result.s_port);
243 : return 0;
244 :
245 : #elif defined(TDS_NO_THREADSAFE)
246 : struct servent *result = getservbyname(name, "tcp");
247 : return result ? ntohs(result->s_port) : 0;
248 : #else
249 : #error getservbyname_r style unknown
250 : #endif
251 : }
252 :
253 : /**
254 : * Get user home directory
255 : * @return home directory or NULL if error. Should be freed with free
256 : */
257 : tds_dir_char *
258 3023 : tds_get_homedir(void)
259 : {
260 : #ifndef _WIN32
261 : /* if is available getpwuid_r use it */
262 : #if defined(HAVE_GETUID) && defined(HAVE_GETPWUID_R)
263 : struct passwd *pw, bpw;
264 : char buf[1024];
265 :
266 : # if defined(HAVE_FUNC_GETPWUID_R_5)
267 : /* getpwuid_r can return 0 if uid is not found so check pw */
268 3023 : pw = NULL;
269 3023 : if (getpwuid_r(getuid(), &bpw, buf, sizeof(buf), &pw) || !pw)
270 : return NULL;
271 :
272 : # elif defined(HAVE_FUNC_GETPWUID_R_4_PW)
273 : if (!(pw = getpwuid_r(getuid(), &bpw, buf, sizeof(buf))))
274 : return NULL;
275 : # else /* !HAVE_FUNC_GETPWUID_R_4_PW */
276 : if (getpwuid_r(getuid(), &bpw, buf, sizeof(buf)))
277 : return NULL;
278 : pw = &bpw;
279 : # endif
280 :
281 3023 : return strdup(pw->pw_dir);
282 :
283 : /* if getpwuid is available use it for no reentrant (getpwuid is not reentrant) */
284 : #elif defined(HAVE_GETUID) && defined(HAVE_GETPWUID) && !defined(_REENTRANT)
285 : struct passwd *pw;
286 :
287 : pw = getpwuid(getuid());
288 : if (!pw)
289 : return NULL;
290 : return strdup(pw->pw_dir);
291 : #else
292 : char *home;
293 :
294 : home = getenv("HOME");
295 : if (!home || !home[0])
296 : return NULL;
297 : return strdup(home);
298 : #endif
299 : #else /* _WIN32 */
300 : /*
301 : * For win32 we return application data cause we use "HOME"
302 : * only to store configuration files
303 : */
304 : HRESULT hr;
305 : LPMALLOC pMalloc = NULL;
306 : tds_dir_char* res = NULL;
307 :
308 : hr = SHGetMalloc(&pMalloc);
309 : if (!FAILED(hr)) {
310 : LPITEMIDLIST pidl;
311 : hr = SHGetSpecialFolderLocation(NULL, CSIDL_APPDATA, &pidl);
312 : if (!FAILED(hr)) {
313 : /*
314 : * SHGetPathFromIDListA() tries to count the length of "path",
315 : * so we have to make sure that it has only zeros; otherwise,
316 : * invalid memory access is inevitable.
317 : */
318 : tds_dir_char path[MAX_PATH] = TDS_DIR("");
319 : if (SHGetPathFromIDListW(pidl, path))
320 : res = tds_dir_dup(path);
321 : (*pMalloc->lpVtbl->Free)(pMalloc, pidl);
322 : }
323 : (*pMalloc->lpVtbl->Release)(pMalloc);
324 : }
325 : return res;
326 : #endif
327 : }
|