fix possible crash on user deletion
[srvx.git] / src / compat.c
1 #undef gettimeofday
2 #undef memcpy
3 #undef memset
4 #undef strerror
5
6 #include "common.h"
7
8 #ifdef HAVE_SYS_TIMEB_H
9 # include <sys/timeb.h>
10 #endif
11 #ifdef HAVE_MEMORY_H
12 # include <memory.h>
13 #endif
14 #ifdef HAVE_ARPA_INET_H
15 # include <arpa/inet.h>
16 #endif
17
18 #if !defined(HAVE_GETTIMEOFDAY) && defined(HAVE_FTIME)
19 int gettimeofday(struct timeval * tv, struct timezone * tz)
20 {
21     if (!tv)
22     {
23         errno = EFAULT;
24         return -1;
25     }
26
27     struct timeb tb;
28
29     ftime(&tb); /* FIXME: some versions are void return others int */
30
31     tv->tv_sec  = tb.time;
32     tv->tv_usec = ((long)tb.millitm)*1000;
33
34     return 0; (void)tz;
35 }
36 #endif
37
38 #if !defined(HAVE_LOCALTIME_R) && defined(HAVE_LOCALTIME)
39 struct tm *localtime_r(const time_t *timep, struct tm *result)
40 {
41     memcpy(result, localtime(timep), sizeof(*result));
42     return result;
43 }
44 #endif
45
46 #ifndef HAVE_MEMCPY
47 void * memcpy(void * dest, void const * src, unsigned long n)
48 {
49 /* very slow, your fault for not having memcpy()*/
50     unsigned char * td=dest;
51     unsigned char * ts=src;
52     unsigned long   i;
53
54     if (!td || !ts)
55         return NULL;
56
57     for (i=0; i<n; i++)
58         td[i] = ts[i];
59     return dest;
60 }
61 #endif
62
63 #ifndef HAVE_MEMSET
64 /* very slow, deal with it */
65 void * memset(void * dest, int c, unsigned long n)
66 {
67     unsigned char * temp=dest;
68     unsigned long   i;
69
70     if (!temp)
71         return NULL;
72
73     for (i=0; i<n; i++)
74         temp[i] = (unsigned char)c;
75     return dest;
76 }
77 #endif
78
79 #ifndef HAVE_STRDUP
80 char * strdup(char const * str)
81 {
82     char * out;
83
84     if (!str)
85         return NULL;
86     if (!(out = malloc(strlen(str)+1)))
87         return NULL;
88     strcpy(out,str);
89     return out;
90 }
91 #endif
92
93 #ifndef HAVE_STRERROR
94 char const * strerror(int errornum)
95 {
96     if (errornum==0)
97         return "No error";
98 #ifdef EPERM
99     if (errornum==EPERM)
100         return "Operation not permitted";
101 #endif
102 #ifdef ENOENT
103     if (errornum==ENOENT)
104         return "No such file or directory";
105 #endif
106 #ifdef ESRCH
107     if (errornum==ESRCH)
108         return "No such process";
109 #endif
110 #ifdef EINTR
111     if (errornum==EINTR)
112         return "Interrupted system call";
113 #endif
114 #ifdef EIO
115     if (errornum==EIO)
116         return "I/O error";
117 #endif
118 #ifdef ENXIO
119     if (errornum==EIO)
120         return "No such device or address";
121 #endif
122 #ifdef EBADF
123     if (errornum==EBADF)
124         return "Bad file number";
125 #endif
126 #ifdef EAGAIN
127     if (errornum==EAGAIN)
128         return "Try again";
129 #endif
130 #ifdef ENOMEM
131     if (errornum==ENOMEM)
132         return "Out of memory";
133 #endif
134 #ifdef EACCES
135     if (errornum==EACCES)
136         return "Permission denied";
137 #endif
138 #ifdef EFAULT
139     if (errornum==EFAULT)
140         return "Bad address";
141 #endif
142 #ifdef EBUSY
143     if (errornum==EBUSY)
144         return "Device or resource busy";
145 #endif
146 #ifdef EEXIST
147     if (errornum==EEXIST)
148         return "File exists";
149 #endif
150 #ifdef EXDEV
151     if (errornum==EXDEV)
152         return "Cross-device link";
153 #endif
154 #ifdef EDEADLK
155     if (errornum==EXDEV)
156         return "Resource deadlock would occur";
157 #endif
158 #ifdef EDEADLOCK
159     if (errornum==EDEADLOCK)
160         return "Resource deadlock would occur";
161 #endif
162 #ifdef ENODEV
163     if (errornum==ENODEV)
164         return "No such device";
165 #endif
166 #ifdef ENOTDIR
167     if (errornum==ENOTDIR)
168         return "Not a directory";
169 #endif
170 #ifdef EISDIR
171     if (errornum==EISDIR)
172         return "Is a directory";
173 #endif
174 #ifdef EINVAL
175     if (errornum==EINVAL)
176         return "Invalid argument";
177 #endif
178 #ifdef ENFILE
179     if (errornum==ENFILE)
180         return "Too many open files in system";
181 #endif
182 #ifdef EMFILE
183     if (errornum==EMFILE)
184         return "Too many open files";
185 #endif
186 #ifdef ENOTTY
187     if (errornum==ENOTTY)
188         return "Not a typewriter";
189 #endif
190 #ifdef ETXTBSY
191     if (errornum==ETXTBSY)
192         return "Text file busy";
193 #endif
194 #ifdef EFBIG
195     if (errornum==EFBIG)
196         return "File too large";
197 #endif
198 #ifdef ENOSPC
199     if (errornum==ENOSPC)
200         return "No space left on device";
201 #endif
202 #ifdef ESPIPE
203     if (errornum==ESPIPE)
204         return "Illegal seek";
205 #endif
206 #ifdef EROFS
207     if (errornum==EROFS)
208         return "Read-only file system";
209 #endif
210 #ifdef EMLINK
211     if (errornum==EMLINK)
212         return "Too many links";
213 #endif
214 #ifdef EPIPE
215     if (errornum==EPIPE)
216         return "Broken pipe";
217 #endif
218 #ifdef EDOM
219     if (errornum==EDOM)
220         return "Math argument out of domain of func";
221 #endif
222 #ifdef ERANGE
223     if (errornum==ERANGE)
224         return "Math result not representable";
225 #endif
226 #ifdef ENAMETOOLONG
227     if (errornum==ENAMETOOLONG)
228         return "File name too long";
229 #endif
230 #ifdef ENOLCK
231     if (errornum==ENOLCK)
232         return "No record locks avaliable";
233 #endif
234 #ifdef ENOSYS
235     if (errornum==ENOSYS)
236         return "Function not implemented";
237 #endif
238 #ifdef ENOTEMPTY
239     if (errornum==ENOTEMPTY)
240         return "Directory not empty";
241 #endif
242 #ifdef ELOOP
243     if (errornum==ELOOP)
244         return "Too many symbolic links encountered";
245 #endif
246 #ifdef EHOSTDOWN
247     if (errornum==EHOSTDOWN)
248         return "Host is down";
249 #endif
250 #ifdef EHOSTUNREACH
251     if (errornum==EHOSTUNREACH)
252         return "No route to host";
253 #endif
254 #ifdef EALREADY
255     if (errornum==EALREADY)
256         return "Operation already in progress";
257 #endif
258 #ifdef EINPROGRESS
259     if (errornum==EINPROGRESS)
260         return "Operation now in progress";
261 #endif
262 #ifdef ESTALE
263     if (errornum==ESTALE)
264         return "Stale NFS filehandle";
265 #endif
266 #ifdef EDQUOT
267     if (errornum==EDQUOT)
268         return "Quota exceeded";
269 #endif
270 #ifdef EWOULDBLOCK
271     if (errornum==EWOULDBLOCK)
272         return "Operation would block";
273 #endif
274 #ifdef ECOMM
275     if (errornum==ECOMM)
276         return "Communication error on send";
277 #endif
278 #ifdef EPROTO
279     if (errornum==EPROTO)
280         return "Protocol error";
281 #endif
282 #ifdef EPROTONOSUPPORT
283     if (errornum==EPROTONOSUPPORT)
284         return "Protocol not supported";
285 #endif
286 #ifdef ESOCKTNOSUPPORT
287     if (errornum==ESOCKTNOSUPPORT)
288         return "Socket type not supported";
289 #endif
290 #ifdef ESOCKTNOSUPPORT
291     if (errornum==EOPNOTSUPP)
292         return "Operation not supported";
293 #endif
294 #ifdef EPFNOSUPPORT
295     if (errornum==EPFNOSUPPORT)
296         return "Protocol family not supported";
297 #endif
298 #ifdef EAFNOSUPPORT
299     if (errornum==EAFNOSUPPORT)
300         return "Address family not supported by protocol family";
301 #endif
302 #ifdef EADDRINUSE
303     if (errornum==EADDRINUSE)
304         return "Address already in use";
305 #endif
306 #ifdef EADDRNOTAVAIL
307     if (errornum==EADDRNOTAVAIL)
308         return "Cannot assign requested address";
309 #endif
310 #ifdef ENETDOWN
311     if (errornum==ENETDOWN)
312         return "Network is down";
313 #endif
314 #ifdef ENETUNREACH
315     if (errornum==ENETUNREACH)
316         return "Network is unreachable";
317 #endif
318 #ifdef ENETRESET
319     if (errornum==ENETRESET)
320         return "Network dropped connection on reset";
321 #endif
322 #ifdef ECONNABORTED
323     if (errornum==ECONNABORTED)
324         return "Software caused connection abort";
325 #endif
326 #ifdef ECONNRESET
327     if (errornum==ECONNRESET)
328         return " Connection reset by peer";
329 #endif
330 #ifdef ENOBUFS
331     if (errornum==ENOBUFS)
332         return "No buffer space available";
333 #endif
334 #ifdef EISCONN
335     if (errornum==EISCONN)
336         return "Socket is already connected";
337 #endif
338 #ifdef ENOTCONN
339     if (errornum==ENOTCONN)
340         return "Socket is not connected";
341 #endif
342 #ifdef ESHUTDOWN
343     if (errornum==ESHUTDOWN)
344         return " Cannot send after socket shutdown";
345 #endif
346 #ifdef ETIMEDOUT
347     if (errornum==ETIMEDOUT)
348         return "Connection timed out";
349 #endif
350 #ifdef ECONNREFUSED
351     if (errornum==ECONNREFUSED)
352         return "Connection refused";
353 #endif
354     return "Unknown error";
355 }
356 #endif
357
358 #ifndef HAVE_GETADDRINFO
359
360 int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res)
361 {
362     /* Only support IPv4 if OS doesn't provide this function. */
363     struct sockaddr_in sin;
364
365     if (hints && hints->ai_family != AF_INET)
366         return EAI_FAMILY;
367     memset(&sin, 0, sizeof(sin));
368     sin.sin_family = AF_INET;
369
370     if (node) {
371         if (hints && hints->ai_flags & AI_NUMERICHOST) {
372 #if HAVE_INET_ATON
373             if (!inet_aton(node, &sin.sin_addr))
374                 return EAI_NONAME;
375 #else
376             sin.sin_addr.s_addr = inet_addr(node);
377             if (sin.sin_addr.s_addr == INADDR_NONE)
378                 return EAI_NONAME;
379 #endif
380         } else {
381             struct hostent *he;
382             he = gethostbyname(node);
383             if (!he)
384                 return EAI_NONAME;
385             memcpy(&sin.sin_addr, he->h_addr, he->h_length);
386         }
387     } else if (hints && hints->ai_flags & AI_PASSIVE) {
388         /* leave it unspecifed */
389     } else {
390         inet_aton("127.0.0.1", &sin.sin_addr);
391     }
392
393     if (!service)
394         sin.sin_port = ntohs(0);
395     else if (!(sin.sin_port = ntohs(atoi(service))))
396         return EAI_NONAME;
397
398     *res = calloc(1, sizeof(**res) + sizeof(sin));
399     (*res)->ai_family = sin.sin_family;
400     (*res)->ai_socktype = hints && hints->ai_socktype ? hints->ai_socktype : SOCK_STREAM;
401     (*res)->ai_protocol = hints && hints->ai_socktype ? hints->ai_socktype : 0;
402     (*res)->ai_addrlen = sizeof(sin);
403     (*res)->ai_addr = (struct sockaddr*)(*res + 1);
404     memcpy((*res)->ai_addr, &sin, (*res)->ai_addrlen);
405     (*res)->ai_canonname = 0;
406     (*res)->ai_next = 0;
407     return 0;
408 }
409
410 void freeaddrinfo(struct addrinfo *res)
411 {
412     struct addrinfo *next;
413     for (; res; res = next) {
414         next = res->ai_next;
415         free(res);
416     }
417 }
418 #endif
419
420 #ifndef HAVE_GAI_STRERROR
421 const char *gai_strerror(int errcode)
422 {
423     switch (errcode) {
424 #if defined(EAI_ADDRFAMILY)
425     case EAI_ADDRFAMILY: return "Address family not supported.";
426 #endif
427 #if defined(EAI_AGAIN)
428     case EAI_AGAIN: return "A temporary failure occurred during name resolution.";
429 #endif
430 #if defined(EAI_BADFLAGS)
431     case EAI_BADFLAGS: return "Invalid flags hint.";
432 #endif
433 #if defined(EAI_FAIL)
434     case EAI_FAIL: return "An unrecoverable failure occurred during name resolution.";
435 #endif
436 #if defined(EAI_FAMILY)
437     case EAI_FAMILY: return "Address family not supported.";
438 #endif
439 #if defined(EAI_MEMORY)
440     case EAI_MEMORY: return "Not enough memory.";
441 #endif
442 #if defined(EAI_NODATA)
443     case EAI_NODATA: return "The name resolves to an empty record.";
444 #endif
445 #if defined(EAI_NONAME)
446     case EAI_NONAME: return "The name does not resolve.";
447 #endif
448 #if defined(EAI_OVERFLOW)
449     case EAI_OVERFLOW: return "Resolved name was too large for buffer.";
450 #endif
451 #if defined(EAI_SERVICE)
452     case EAI_SERVICE: return "The socket type does not support the requested service.";
453 #endif
454 #if defined(EAI_SOCKTYPE)
455     case EAI_SOCKTYPE: return "Unknown socket type.";
456 #endif
457 #if defined(EAI_SYSTEM)
458     case EAI_SYSTEM: return "A system error occurred during name resolution.";
459 #endif
460     }
461     return "Unknown GAI_* error";
462 }
463 #endif
464
465 #ifndef HAVE_GETNAMEINFO
466 int getnameinfo(const struct sockaddr *sa, socklen_t salen,
467                 char *host, size_t hostlen,
468                 char *serv, size_t servlen, int flags)
469 {
470     if (sa->sa_family == AF_INET) {
471         const struct sockaddr_in *sin;
472         int tmp;
473
474         /* This comparison is a bit screwy looking, but socklen_t is
475          * signed on some platforms and unsigned on others, so gcc
476          * will complain if we use "salen < 0".
477          */
478         if (salen < 1 || (size_t)salen < sizeof(*sin))
479             return EAI_FAMILY;
480         sin = (const struct sockaddr_in *)sa;
481         tmp = snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
482         if (tmp < 1 || (size_t)tmp >= servlen)
483             return EAI_OVERFLOW;
484         if (0 == (flags & NI_NUMERICHOST)) {
485             struct hostent *he;
486
487             /* Try to get host entry by address.
488              * The first argument should be void *, but Cygwin is
489              * apparently wandering around the pre-C89 era.
490              */
491             he = gethostbyaddr((const char*)&sin->sin_addr, sa->sa_family, SOCK_STREAM);
492             if (he != NULL) {
493                 if (servlen <= strlen(he->h_name))
494                     return EAI_OVERFLOW;
495                 safestrncpy(serv, he->h_name, servlen);
496                 return 0;
497             }
498
499             /* If we couldn't, why did we fail, and what should we do? */
500             switch (h_errno) {
501             case NO_RECOVERY:
502                 return EAI_FAIL;
503             case TRY_AGAIN:
504                 return EAI_AGAIN;
505             default:
506                 /* Fall through and out to inet_ntop() path. */
507                 break;
508             }
509         }
510
511         /* Try to get numeric representation of address. */
512         if (inet_ntop(sa->sa_family, &sin->sin_addr, host, hostlen) != NULL)
513             return 0;
514         else if (errno == ENOSPC)
515             return EAI_OVERFLOW;
516         else
517             return EAI_FAIL;
518     }
519     else
520         return EAI_FAMILY;
521 }
522 #endif