Wed Jan 8 2020 09:49:51

Asterisk developer's documentation


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