Merged revisions 301263 via svnmerge from
[asterisk/asterisk.git] / main / strcompat.c
1 /*
2  * Asterisk -- An open source telephony toolkit.
3  *
4  * Copyright (C) 1999 - 2006, Digium, Inc.
5  *
6  * See http://www.asterisk.org for more information about
7  * the Asterisk project. Please do not directly contact
8  * any of the maintainers of this project for assistance;
9  * the project provides a web site, mailing lists and IRC
10  * channels for your use.
11  *
12  * This program is free software, distributed under the terms of
13  * the GNU General Public License Version 2. See the LICENSE file
14  * at the top of the source tree.
15  */
16
17 /*! \file
18  *
19  * \brief Compatibility functions for strsep and strtoq missing on Solaris 
20  */
21
22 #include "asterisk.h"
23
24 #include <ctype.h>
25 #include <sys/time.h>       /* for getrlimit(2) */
26 #include <sys/resource.h>   /* for getrlimit(2) */
27 #include <sys/types.h>      /* for opendir(3) */
28 #include <dirent.h>         /* for opendir(3) */
29 #include <unistd.h>         /* for fcntl(2) */
30 #include <fcntl.h>          /* for fcntl(2) */
31
32 #include "asterisk/utils.h"
33
34 #ifndef HAVE_STRSEP
35 char *strsep(char **str, const char *delims)
36 {
37         char *token;
38
39         if (!*str) {
40                 /* No more tokens */
41                 return NULL;
42         }
43
44         token = *str;
45         while (**str != '\0') {
46                 if (strchr(delims, **str)) {
47                         **str = '\0';
48                         (*str)++;
49                         return token;
50                 }
51                 (*str)++;
52         }
53
54         /* There is no other token */
55         *str = NULL;
56
57         return token;
58 }
59 #endif
60
61 #ifndef HAVE_SETENV
62 int setenv(const char *name, const char *value, int overwrite)
63 {
64         unsigned char *buf;
65         int buflen;
66
67         buflen = strlen(name) + strlen(value) + 2;
68         buf = alloca(buflen);
69
70         if (!overwrite && getenv(name))
71                 return 0;
72
73         snprintf(buf, buflen, "%s=%s", name, value);
74
75         return putenv(buf);
76 }
77 #endif
78
79 #ifndef HAVE_UNSETENV
80 int unsetenv(const char *name)
81 {
82         return setenv(name, "", 0);
83 }
84 #endif
85
86 #ifndef HAVE_STRCASESTR
87 static char *upper(const char *orig, char *buf, int bufsize)
88 {
89         int i = 0;
90
91         while (i < (bufsize - 1) && orig[i]) {
92                 buf[i] = toupper(orig[i]);
93                 i++;
94         }
95
96         buf[i] = '\0';
97
98         return buf;
99 }
100
101 char *strcasestr(const char *haystack, const char *needle)
102 {
103         char *u1, *u2;
104         int u1len = strlen(haystack) + 1, u2len = strlen(needle) + 1;
105
106         u1 = alloca(u1len);
107         u2 = alloca(u2len);
108         if (u1 && u2) {
109                 char *offset;
110                 if (u2len > u1len) {
111                         /* Needle bigger than haystack */
112                         return NULL;
113                 }
114                 offset = strstr(upper(haystack, u1, u1len), upper(needle, u2, u2len));
115                 if (offset) {
116                         /* Return the offset into the original string */
117                         return ((char *)((unsigned long)haystack + (unsigned long)(offset - u1)));
118                 } else {
119                         return NULL;
120                 }
121         } else {
122                 return NULL;
123         }
124 }
125 #endif /* !HAVE_STRCASESTR */
126
127 #ifndef HAVE_STRNLEN
128 size_t strnlen(const char *s, size_t n)
129 {
130         size_t len;
131
132         for (len = 0; len < n; len++)
133                 if (s[len] == '\0')
134                         break;
135
136         return len;
137 }
138 #endif /* !HAVE_STRNLEN */
139
140 #if !defined(HAVE_STRNDUP) && !defined(__AST_DEBUG_MALLOC)
141 char *strndup(const char *s, size_t n)
142 {
143         size_t len = strnlen(s, n);
144         char *new = malloc(len + 1);
145
146         if (!new)
147                 return NULL;
148
149         new[len] = '\0';
150         return memcpy(new, s, len);
151 }
152 #endif /* !defined(HAVE_STRNDUP) && !defined(__AST_DEBUG_MALLOC) */
153
154 #if !defined(HAVE_VASPRINTF) && !defined(__AST_DEBUG_MALLOC)
155 int vasprintf(char **strp, const char *fmt, va_list ap)
156 {
157         int size;
158         va_list ap2;
159         char s;
160
161         *strp = NULL;
162         va_copy(ap2, ap);
163         size = vsnprintf(&s, 1, fmt, ap2);
164         va_end(ap2);
165         *strp = malloc(size + 1);
166         if (!*strp)
167                 return -1;
168         vsnprintf(*strp, size + 1, fmt, ap);
169
170         return size;
171 }
172 #endif /* !defined(HAVE_VASPRINTF) && !defined(__AST_DEBUG_MALLOC) */
173
174 #ifndef HAVE_TIMERSUB
175 void timersub(struct timeval *tvend, struct timeval *tvstart, struct timeval *tvdiff)
176 {
177         tvdiff->tv_sec = tvend->tv_sec - tvstart->tv_sec;
178         tvdiff->tv_usec = tvend->tv_usec - tvstart->tv_usec;
179         if (tvdiff->tv_usec < 0) {
180                 tvdiff->tv_sec --;
181                 tvdiff->tv_usec += 1000000;
182         }
183
184 }
185 #endif
186
187 /*
188  * Based on Code from bsd-asprintf from OpenSSH
189  * Copyright (c) 2004 Darren Tucker.
190  *
191  * Based originally on asprintf.c from OpenBSD:
192  * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
193  *
194  * Permission to use, copy, modify, and distribute this software for any
195  * purpose with or without fee is hereby granted, provided that the above
196  * copyright notice and this permission notice appear in all copies.
197  *
198  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
199  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
200  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
201  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
202  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
203  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
204  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
205  */
206 #if !defined(HAVE_ASPRINTF) && !defined(__AST_DEBUG_MALLOC) 
207 int asprintf(char **str, const char *fmt, ...)
208 {
209         va_list ap;
210         int ret;
211
212         *str = NULL;
213         va_start(ap, fmt);
214         ret = vasprintf(str, fmt, ap);
215         va_end(ap);
216
217         return ret;
218 }
219 #endif /* !defined(HAVE_ASPRINTF) && !defined(__AST_DEBUG_MALLOC) */
220
221 #ifndef HAVE_STRTOQ
222 #ifndef LONG_MIN
223 #define LONG_MIN        (-9223372036854775807L-1L)
224                                          /* min value of a "long int" */
225 #endif
226 #ifndef LONG_MAX
227 #define LONG_MAX        9223372036854775807L
228                                          /* max value of a "long int" */
229 #endif
230
231 /*! \brief
232  * Convert a string to a quad integer.
233  *
234  * \note Ignores `locale' stuff.  Assumes that the upper and lower case
235  * alphabets and digits are each contiguous.
236  */
237 uint64_t strtoq(const char *nptr, char **endptr, int base)
238 {
239          const char *s;
240          uint64_t acc;
241          unsigned char c;
242          uint64_t qbase, cutoff;
243          int neg, any, cutlim;
244
245          /*
246           * Skip white space and pick up leading +/- sign if any.
247           * If base is 0, allow 0x for hex and 0 for octal, else
248           * assume decimal; if base is already 16, allow 0x.
249           */
250          s = nptr;
251          do {
252                  c = *s++;
253          } while (isspace(c));
254          if (c == '-') {
255                  neg = 1;
256                  c = *s++;
257          } else {
258                  neg = 0;
259                  if (c == '+')
260                          c = *s++;
261          }
262          if ((base == 0 || base == 16) &&
263              c == '\0' && (*s == 'x' || *s == 'X')) {
264                  c = s[1];
265                  s += 2;
266                  base = 16;
267          }
268          if (base == 0)
269                  base = c == '\0' ? 8 : 10;
270
271          /*
272           * Compute the cutoff value between legal numbers and illegal
273           * numbers.  That is the largest legal value, divided by the
274           * base.  An input number that is greater than this value, if
275           * followed by a legal input character, is too big.  One that
276           * is equal to this value may be valid or not; the limit
277           * between valid and invalid numbers is then based on the last
278           * digit.  For instance, if the range for quads is
279           * [-9223372036854775808..9223372036854775807] and the input base
280           * is 10, cutoff will be set to 922337203685477580 and cutlim to
281           * either 7 (neg==0) or 8 (neg==1), meaning that if we have
282           * accumulated a value > 922337203685477580, or equal but the
283           * next digit is > 7 (or 8), the number is too big, and we will
284           * return a range error.
285           *
286           * Set any if any `digits' consumed; make it negative to indicate
287           * overflow.
288           */
289          qbase = (unsigned)base;
290          cutoff = neg ? (uint64_t)-(LONG_MIN + LONG_MAX) + LONG_MAX : LONG_MAX;
291          cutlim = cutoff % qbase;
292          cutoff /= qbase;
293          for (acc = 0, any = 0;; c = *s++) {
294                  if (!isascii(c))
295                          break;
296                  if (isdigit(c))
297                          c -= '\0';
298                  else if (isalpha(c))
299                          c -= isupper(c) ? 'A' - 10 : 'a' - 10;
300                  else
301                          break;
302                  if (c >= base)
303                          break;
304                  if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim))
305                          any = -1;
306                  else {
307                          any = 1;
308                          acc *= qbase;
309                          acc += c;
310                  }
311          }
312          if (any < 0) {
313                  acc = neg ? LONG_MIN : LONG_MAX;
314          } else if (neg)
315                  acc = -acc;
316          if (endptr != 0)
317                  *((const char **)endptr) = any ? s - 1 : nptr;
318          return acc;
319 }
320 #endif /* !HAVE_STRTOQ */
321
322 #ifndef HAVE_GETLOADAVG
323 #ifdef linux
324 /*! \brief Alternative method of getting load avg on Linux only */
325 int getloadavg(double *list, int nelem)
326 {
327         FILE *LOADAVG;
328         double avg[3] = { 0.0, 0.0, 0.0 };
329         int i, res = -1;
330
331         if ((LOADAVG = fopen("/proc/loadavg", "r"))) {
332                 fscanf(LOADAVG, "%lf %lf %lf", &avg[0], &avg[1], &avg[2]);
333                 res = 0;
334                 fclose(LOADAVG);
335         }
336
337         for (i = 0; (i < nelem) && (i < 3); i++) {
338                 list[i] = avg[i];
339         }
340
341         return res;
342 }
343 #else /* !linux */
344 /*! \brief Return something that won't cancel the call, but still return -1, in case
345  * we correct the implementation to check return value */
346 int getloadavg(double *list, int nelem)
347 {
348         int i;
349
350         for (i = 0; i < nelem; i++) {
351                 list[i] = 0.1;
352         }
353         return -1;
354 }
355 #endif /* linux */
356 #endif /* !HAVE_GETLOADAVG */
357
358 #ifndef HAVE_NTOHLL
359 uint64_t ntohll(uint64_t net64)
360 {
361 #if BYTE_ORDER == BIG_ENDIAN
362         return net64;
363 #elif BYTE_ORDER == LITTLE_ENDIAN
364         union {
365                 unsigned char c[8];
366                 uint64_t u;
367         } number;
368         number.u = net64;
369         return
370                 (((uint64_t) number.c[0]) << 56) |
371                 (((uint64_t) number.c[1]) << 48) |
372                 (((uint64_t) number.c[2]) << 40) |
373                 (((uint64_t) number.c[3]) << 32) |
374                 (((uint64_t) number.c[4]) << 24) |
375                 (((uint64_t) number.c[5]) << 16) |
376                 (((uint64_t) number.c[6]) <<  8) |
377                 (((uint64_t) number.c[7]) <<  0);
378 #else
379         #error "Unknown byte order"
380 #endif
381 }
382 #endif
383
384 #ifndef HAVE_HTONLL
385 uint64_t htonll(uint64_t host64)
386 {
387 #if BYTE_ORDER == BIG_ENDIAN
388         return host64;
389 #elif BYTE_ORDER == LITTLE_ENDIAN
390         union {
391                 unsigned char c[8];
392                 uint64_t u;
393         } number;
394         number.u = host64;
395         return
396                 (((uint64_t) number.c[0]) << 56) |
397                 (((uint64_t) number.c[1]) << 48) |
398                 (((uint64_t) number.c[2]) << 40) |
399                 (((uint64_t) number.c[3]) << 32) |
400                 (((uint64_t) number.c[4]) << 24) |
401                 (((uint64_t) number.c[5]) << 16) |
402                 (((uint64_t) number.c[6]) <<  8) |
403                 (((uint64_t) number.c[7]) <<  0);
404 #else
405         #error "Unknown byte order"
406 #endif
407 }
408 #endif
409
410 #ifndef HAVE_FFSLL
411 int ffsll(long long n)
412 {
413         int i;
414         for (i = 0; i < 64; i++) {
415                 if ((1LL << i) & n) {
416                         return i + 1;
417                 }
418         }
419         return 0;
420 }
421 #endif
422
423 #ifndef HAVE_CLOSEFROM
424 void closefrom(int n)
425 {
426         long x;
427         struct rlimit rl;
428         DIR *dir;
429         char path[16], *result;
430         struct dirent *entry;
431
432         snprintf(path, sizeof(path), "/proc/%d/fd", (int) getpid());
433         if ((dir = opendir(path))) {
434                 while ((entry = readdir(dir))) {
435                         /* Skip . and .. */
436                         if (entry->d_name[0] == '.') {
437                                 continue;
438                         }
439                         if ((x = strtol(entry->d_name, &result, 10)) && x >= n) {
440 #ifdef STRICT_COMPAT
441                                 close(x);
442 #else
443                                 /* This isn't strictly compatible, but it's actually faster
444                                  * for our purposes to set the CLOEXEC flag than to close
445                                  * file descriptors.
446                                  */
447                                 long flags = fcntl(x, F_GETFD);
448                                 if (flags == -1 && errno == EBADF) {
449                                         continue;
450                                 }
451                                 fcntl(x, F_SETFD, flags | FD_CLOEXEC);
452 #endif
453                         }
454                 }
455                 closedir(dir);
456         } else {
457                 getrlimit(RLIMIT_NOFILE, &rl);
458                 if (rl.rlim_cur > 65535) {
459                         /* A more reasonable value.  Consider that the primary source of
460                          * file descriptors in Asterisk are UDP sockets, of which we are
461                          * limited to 65,535 per address.  We additionally limit that down
462                          * to about 10,000 sockets per protocol.  While the kernel will
463                          * allow us to set the fileno limit higher (up to 4.2 billion),
464                          * there really is no practical reason for it to be that high.
465                          */
466                         rl.rlim_cur = 65535;
467                 }
468                 for (x = n; x < rl.rlim_cur; x++) {
469 #ifdef STRICT_COMPAT
470                         close(x);
471 #else
472                         long flags = fcntl(x, F_GETFD);
473                         if (flags == -1 && errno == EBADF) {
474                                 continue;
475                         }
476                         fcntl(x, F_SETFD, flags | FD_CLOEXEC);
477 #endif
478                 }
479         }
480 }
481 #endif
482
483 #ifndef HAVE_MKDTEMP
484 /*      $OpenBSD: mktemp.c,v 1.30 2010/03/21 23:09:30 schwarze Exp $ */
485 /*
486  * Copyright (c) 1996-1998, 2008 Theo de Raadt
487  * Copyright (c) 1997, 2008-2009 Todd C. Miller
488  *
489  * Permission to use, copy, modify, and distribute this software for any
490  * purpose with or without fee is hereby granted, provided that the above
491  * copyright notice and this permission notice appear in all copies.
492  *
493  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
494  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
495  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
496  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
497  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
498  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
499  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
500  */
501
502 #define MKTEMP_NAME     0
503 #define MKTEMP_FILE     1
504 #define MKTEMP_DIR      2
505
506 #define TEMPCHARS       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_."
507 #define NUM_CHARS       (sizeof(TEMPCHARS) - 1)
508
509 static int mktemp_internal(char *path, int slen, int mode)
510 {
511         char *start, *cp, *ep;
512         const char *tempchars = TEMPCHARS;
513         unsigned int r, tries;
514         struct stat sb;
515         size_t len;
516         int fd;
517
518         len = strlen(path);
519         if (len == 0 || slen >= len) {
520                 errno = EINVAL;
521                 return(-1);
522         }
523         ep = path + len - slen;
524
525         tries = 1;
526         for (start = ep; start > path && start[-1] == 'X'; start--) {
527                 if (tries < INT_MAX / NUM_CHARS) {
528                         tries *= NUM_CHARS;
529                 }
530         }
531         tries *= 2;
532
533         do {
534                 for (cp = start; cp != ep; cp++) {
535                         r = ast_random() % NUM_CHARS;
536                         *cp = tempchars[r];
537                 }
538
539                 switch (mode) {
540                 case MKTEMP_NAME:
541                         if (lstat(path, &sb) != 0) {
542                                 return (errno == ENOENT ? 0 : -1);
543                         }
544                         break;
545                 case MKTEMP_FILE:
546                         fd = open(path, O_CREAT | O_EXCL | O_RDWR, S_IRUSR | S_IWUSR);
547                         if (fd != -1 || errno != EEXIST) {
548                                 return (fd);
549                         }
550                         break;
551                 case MKTEMP_DIR:
552                         if (mkdir(path, S_IRUSR | S_IWUSR | S_IXUSR) == 0) {
553                                 return (0);
554                         }
555                         if (errno != EEXIST) {
556                                 return (-1);
557                         }
558                         break;
559                 }
560         } while (--tries);
561
562         errno = EEXIST;
563         return(-1);
564 }
565
566 char *mkdtemp(char *path)
567 {
568         return mktemp_internal(path, 0, MKTEMP_DIR) ? NULL : path;
569 }
570 #endif