posix.c
Go to the documentation of this file.
1 /* ========================================================================== */
2 /*! \file
3  * \brief Intended to implement missing or buggy POSIX functionality of OS
4  *
5  * Copyright (c) 2012-2020 by the developers. See the LICENSE file for details.
6  */
7 
8 
9 /* ========================================================================== */
10 /* Include headers */
11 
12 #include "posix.h" /* Include this first because of feature test macros */
13 
14 #include "main.h"
15 
16 
17 /* ========================================================================== */
18 /*! \defgroup POSIX POSIX: Portable Operating System Interface
19  *
20  * This subsystem should hold away operating system issues from the rest of the
21  * program. If a C source file requires something that is not ISO C90, it should
22  * include "posix.h" as the first header file and this module should take care
23  * to provide the required functionality as specified by SUSv4.
24  * This allows to write cleaner code (that normally would only be accepted by
25  * much more recent operating systems) and nevertheless run it on old machines.
26  *
27  * This module is based on the POSIX.1-1990, POSIX.1b-1993, POSIX.1c-1996 and
28  * BSD socket APIs. This means it expects that the operating system provides
29  * these APIs.
30  * Workarounds for operating system bugs should be implemented here.
31  *
32  * Version numbers for Single Unix Specification (X/Open XSI extension):
33  * - SUS (Issue 4.2)
34  * - SUSv2 (Issue 5)
35  * - SUSv3 (Issue 6)
36  * - SUSv4 (Issue 7)
37  *
38  * This module can use the XSI extension for SUSv2, SUSv3 or SUSv4 respectively.
39  * POSIX Networking Services (XNS) are used instead of the BSD socket API for
40  * SUSv2 and POSIX.1-2001 (or later versions).
41  *
42  * \attention
43  * The random number generation functions provided by this module may use weak
44  * (or even trivial) algorithms and are not suited for cryptographic tasks!
45  *
46  * \attention
47  * Note that POSIX.1-1990 has no C++ binding, therefore a C++ file is not
48  * allowed to include "posix.h".
49  *
50  * The namespaces reserved for the XNS module of the OS are defined by SUSv2:
51  * <br>
52  * http://pubs.opengroup.org/onlinepubs/007908799/xns/namespace.html
53  * <br>
54  * For this module the "posix_" namespace is used. All elements provided by this
55  * module have a "posix_" (or "POSIX_") prefix.
56  *
57  * Functions not defined in POSIX.1-1990, POSIX.1b-1993, POSIX.1c-1996 or SUSv2,
58  * but defined in a later version should be implemented here in a POSIX
59  * conformant way but with a "posix_" prefix.
60  * For partial implementations the parts that are implemented should be POSIX
61  * or SUS conformant respectively.
62  *
63  * Currently the following functions are completely implemented:
64  * - \c posix_freeaddrinfo()
65  * - \c posix_fsync()
66  * - \c posix_getline()
67  * - \c posix_inet_pton()
68  * - \c posix_poll()
69  * - \c posix_random()
70  * - \c posix_scandir()
71  * - \c posix_srandom()
72  * - \c posix_mkstemp()
73  * - \c posix_gai_strerror()
74  *
75  * Currently the following functions are only partially implemented:
76  * - \c posix_getaddrinfo()
77  * - \c posix_inet_addr()
78  * - \c posix_snprintf()
79  * - \c posix_newlocale()
80  * - \c posix_freelocale()
81  * - \c posix_strcasecmp_l()
82  * - \c posix_strncasecmp_l()
83  *
84  * \attention
85  * \c struct \c sockaddr_storage is broken on AIX if POSIX or SUS mode is used:
86  * - The structure is not exposed at all if '_ALL_SOURCE' is not defined
87  * - The member 'ss_family' required by SUSv2 and POSIX.1-2001 is missing
88  * - At least on AIX 5.3 the structure is not large enough
89  * <br>
90  * Using this structure should be avoided. Using '_ALL_SOURCE' as workaround has
91  * unwanted side effects and would solve only the first problem.
92  */
93 
94 
95 /* ========================================================================== */
96 /* Constants */
97 
98 /*! \brief Message prefix for POSIX module */
99 #define MAIN_ERR_PREFIX "POSIX: "
100 
101 
102 /* ========================================================================== */
103 /* Variables */
104 
105 #if CFG_USE_POSIX_API >= 200809
106 /* Dummy variable to avoid warnings like "empty translation unit" */
107 extern int posix_dummy;
108 int posix_dummy = 0;
109 #endif /* CFG_USE_POSIX_API >= 200809 */
110 
111 
112 /* ========================================================================== */
113 /* Memory managment debugging
114  *
115  * This is a simple wrapper for the default memory manager that can detect
116  * invalid free() operations. It is always disabled by default.
117  *
118  * Only the parts of the program that use the memory manager API with "posix_"
119  * prefix are checked.
120  */
121 
122 #if CFG_USE_MEMDEBUG
123 # define MEMDEBUG_ARRAY_SIZE (size_t) 100000
124 static posix_pthread_mutex_t memdebug_mutex = POSIX_PTHREAD_MUTEX_INITIALIZER;
125 static void* memdebug_array[MEMDEBUG_ARRAY_SIZE];
126 static size_t memdebug_size[MEMDEBUG_ARRAY_SIZE];
127 static size_t memdebug_num = 0;
128 
129 /* Replacement for 'malloc()' */
130 void* posix_malloc(size_t len)
131 {
132  void* p = NULL;
133 
134  if(!posix_pthread_mutex_lock(&memdebug_mutex))
135  {
136  if(MEMDEBUG_ARRAY_SIZE <= memdebug_num + (size_t) 1)
137  {
138  PRINT_ERROR("malloc(): Debug array overflow");
139  return(NULL);
140  }
141  else
142  {
143  p = malloc(len);
144  printf("%s: %sMEMDBG: A: %p\n", CFG_NAME, MAIN_ERR_PREFIX, p);
145  if(p)
146  {
147  memdebug_array[memdebug_num] = p;
148  memdebug_size[memdebug_num] = len;
149  ++memdebug_num;
150  }
151  }
152  posix_pthread_mutex_unlock(&memdebug_mutex);
153  }
154 
155  return(p);
156 }
157 
158 
159 /* Replacement for 'free()' */
160 void posix_free(void* p)
161 {
162  size_t i, ii;
163 
164  if(!posix_pthread_mutex_lock(&memdebug_mutex))
165  {
166  if(NULL != p)
167  {
168  printf("%s: %sMEMDBG: F: %p\n", CFG_NAME, MAIN_ERR_PREFIX, p);
169  for(i = 0; i < memdebug_num; ++i)
170  {
171  if(memdebug_array[i] == p) { break; }
172  }
173  if(i >= memdebug_num)
174  {
175  PRINT_ERROR("free(): Invalid address (thread frozen)");
176  while(1);
177  }
178  else
179  {
180  for(ii = i; ii < memdebug_num; ++ii)
181  {
182  memdebug_array[ii] = memdebug_array[ii + 1];
183  memdebug_size[ii] = memdebug_size[ii + 1];
184  }
185  --memdebug_num;
186  }
187  }
188  posix_pthread_mutex_unlock(&memdebug_mutex);
189  }
190 
191  return(free(p));
192 }
193 
194 
195 /* Replacement for 'realloc()' */
196 void* posix_realloc(void* p, size_t len)
197 {
198  void* q = posix_malloc(len);
199  size_t i;
200  size_t oldlen;
201 
202  if(!posix_pthread_mutex_lock(&memdebug_mutex))
203  {
204  if(NULL != p)
205  {
206  printf("%s: %sMEMDBG: R: %p => %p\n", CFG_NAME, MAIN_ERR_PREFIX, p, q);
207  for(i = 0; i < memdebug_num; ++i)
208  {
209  if(memdebug_array[i] == p) { break; }
210  }
211  if(i >= memdebug_num)
212  {
213  PRINT_ERROR("realloc(): Invalid address (thread frozen)");
214  while(1);
215  }
216  else if(NULL != q)
217  {
218  /* Never copy more data than contained in the old memory block */
219  oldlen = memdebug_size[i];
220  if(len > oldlen) { len = oldlen; }
221  memcpy(q, p, len);
222  }
223  }
224  posix_pthread_mutex_unlock(&memdebug_mutex);
225  }
226 
227  /* Check for error */
228  if(NULL == q) { PRINT_ERROR("realloc(): Failed"); }
229  else { posix_free(p); }
230 
231  return(q);
232 }
233 #endif /* CFG_USE_MEMDEBUG */
234 
235 
236 /* ========================================================================== */
237 /* Random numbers
238  *
239  * \attention
240  * The POSIX RNG is not suitable for cryptographic purposes!
241  */
242 
243 #if !CFG_USE_XSI
244 static posix_pthread_mutex_t random_mutex = POSIX_PTHREAD_MUTEX_INITIALIZER;
245 static long int random_state = 1;
246 
247 void posix_srandom(unsigned int seed)
248 {
249  if(!posix_pthread_mutex_lock(&random_mutex))
250  {
251  random_state = (long int) (seed * 2U);
252  posix_pthread_mutex_unlock(&random_mutex);
253  }
254 }
255 
256 
257 long int posix_random(void)
258 {
259  long int res = 0;
260 
261  if(!posix_pthread_mutex_lock(&random_mutex))
262  {
263  res = random_state;
264 
265  /*
266  * Trivial increment implementation so that two sequential numbers can
267  * never have the same value.
268  */
269  if(POSIX_LONG_MAX > random_state) { ++random_state; }
270  else { random_state = 0; }
271  posix_pthread_mutex_unlock(&random_mutex);
272  }
273 
274  return(res);
275 }
276 #endif /* !CFG_USE_XSI */
277 
278 
279 /* ========================================================================== */
280 /* File & directory handling */
281 
282 #if !CFG_USE_FSC
283 /*
284  * 'fsync()' is part of the POSIX.1-2001 FSC option and X/Open XSI extension.
285  */
286 int posix_fsync(int fd)
287 {
288  /* NOP implementation is allowed */
289  return(0);
290 }
291 #endif /* !CFG_USE_FSC */
292 
293 
294 #if CFG_USE_POSIX_API < 200809
295 /*
296  * This implementation of 'scandir()' should be POSIX.1-2008 conformant.
297  *
298  * It is required that 'SSIZE_MAX' is at least 'INT_MAX' (must be checked by
299  * build system).
300  *
301  * Note:
302  * In theory, a system that provide threads should also provide 'readdir_r()',
303  * a thread safe version of 'readdir()'. In reality this is not always the case.
304  * In addition there may be a race condition that can lead to a buffer overflow:
305  * http://womble.decadent.org.uk/readdir_r-advisory.html
306  * Therefore we use our own function 'scandir_readentry()' to get the directory
307  * entries.
308  */
309 static posix_pthread_mutex_t scandir_mutex = POSIX_PTHREAD_MUTEX_INITIALIZER;
310 static int scandir_readentry(POSIX_DIR* dirp, struct_posix_dirent** entryp,
311  size_t* len)
312 {
313  int result = -1;
314  struct_posix_dirent* e;
315 
316  if(!posix_pthread_mutex_lock(&scandir_mutex))
317  {
318  /* Lock UI mutex */
319  if(ts_lock_ui()) { PRINT_ERROR("Locking UI mutex failed"); }
320  else
321  {
322  errno = 0;
323  e = posix_readdir(dirp);
324  if(NULL == e)
325  {
326  if(!errno)
327  {
328  /* No more entries in directory */
329  *entryp = NULL;
330  *len = 0;
331  result = 0;
332  }
333  }
334  else
335  {
336  /* Entry found, allocate local buffer */
337  *len = offsetof(struct_posix_dirent, d_name) + strlen(e->d_name)
338  + (size_t) 1;
339  *entryp = (struct_posix_dirent *) posix_malloc(*len);
340  if(NULL != *entryp)
341  {
342  memcpy((void*) *entryp, (void*) e, *len);
343  /* Force NUL termination at end of buffer */
344  ((char *) *entryp)[*len - (size_t) 1] = 0;
345  result = 0;
346  }
347  }
348  /* Unlock UI mutex */
349  if(ts_unlock_ui()) { PRINT_ERROR("Unlocking UI mutex failed"); }
350  }
351  /*
352  * In a multithreading environment the systems dirent buffer may be shared
353  * between all threads. Therefore the mutex must stay locked until we have
354  * copied the data to our thread local buffer.
355  */
356  posix_pthread_mutex_unlock(&scandir_mutex);
357  }
358 
359  return(result);
360 }
361 #define SCANDIR_ENTRIES_MIN (size_t) 32
362 int posix_scandir(const char* dir, struct_posix_dirent*** namelist,
363  int (*sel)(struct_posix_dirent*),
364  int (*compar)(const struct_posix_dirent**,
365  const struct_posix_dirent**))
366 {
367  int result = -1;
368  POSIX_DIR* dirp;
369  size_t len, num = 0;
370  size_t max = SCANDIR_ENTRIES_MIN;
371  struct_posix_dirent* entryp = NULL;
372  struct_posix_dirent** entries;
373  struct_posix_dirent** p;
374 
375  entries = (struct_posix_dirent**) posix_malloc(sizeof(*entries) * max);
376  if(NULL != entries)
377  {
378  /* Open directory 'dir' (and verify that it really is a directory) */
379  dirp = posix_opendir(dir);
380  if(NULL != dirp)
381  {
382  /* Read next directory entry */
383  while (!scandir_readentry(dirp, &entryp, &len))
384  {
385  if(NULL == entryp)
386  {
387  /* EOD => Return number of directory entries */
388  result = (int) num;
389  break;
390  }
391  /* Apply select function if there is one provided */
392  if(NULL != sel) { if(!sel(entryp)) continue; }
393  entries[num++] = entryp;
394  if(num >= max)
395  {
396  /* Allocate exponentially increasing sized memory chunks */
397  if(POSIX_INT_MAX / 2 >= (int) max) { max *= (size_t) 2; }
398  else
399  {
400  errno = ENOMEM;
401  break;
402  }
403  p = (struct_posix_dirent**) posix_realloc((void*) entries,
404  sizeof(*entries) * max);
405  if(NULL != p) { entries = p; }
406  else break;
407  }
408  }
409  posix_closedir(dirp);
410  /*
411  * A standard conformant 'closedir()' is allowed to fail with 'EINTR',
412  * but the state of the directory structure is undefined in this case.
413  * Therefore we ignore the return value because we can't call
414  * 'closedir()' again and must hope that the system has released all
415  * ressources.
416  */
417  }
418  /* Sort entries in array if there is a compare function provided */
419  if(NULL != compar)
420  {
421  qsort((void*) entries, num, sizeof(*entries),
422  (int (*)(const void*, const void*)) compar);
423  }
424  *namelist = entries;
425  }
426 
427  /* Check for error */
428  if(-1 == result)
429  {
430  /* Free all memory we have allocated */
431  while(num--) { posix_free((void*) entries[num]); }
432  posix_free((void*) entries);
433  }
434 
435  return(result);
436 }
437 #endif /* CFG_USE_POSIX_API < 200809 */
438 
439 
440 #if CFG_USE_POSIX_API < 200809 && !CFG_USE_XSI
441 static unsigned long int mkstemp_state = 0;
442 static posix_pthread_mutex_t mkstemp_mutex = POSIX_PTHREAD_MUTEX_INITIALIZER;
443 int posix_mkstemp(char* template)
444 {
445  const int oflag = POSIX_O_RDWR | POSIX_O_CREAT | POSIX_O_EXCL;
446  const posix_mode_t mode = POSIX_S_IRUSR | POSIX_S_IWUSR;
447  int res = -1;
448  unsigned long int unique;
449  int error = 0;
450  size_t pos;
451  char uni[7];
452  int rv;
453 
454  if(!posix_pthread_mutex_lock(&mkstemp_mutex))
455  {
456  if(999999UL > mkstemp_state) { ++mkstemp_state; }
457  else { mkstemp_state = 0; }
458  unique = mkstemp_state;
459  posix_pthread_mutex_unlock(&mkstemp_mutex);
460 
461  /* Check template */
462  pos = strlen(template);
463  if((size_t) 6 > pos) { error = 1; }
464  else
465  {
466  pos -= (size_t) 6;
467  if(strcmp("XXXXXX", &template[pos])) { error = 1; }
468  }
469  if(error) { posix_errno = POSIX_EINVAL; }
470  else
471  {
472  rv = posix_snprintf(uni, (size_t) 7, "%06lu", unique);
473  if(6 == rv)
474  {
475  strncpy(&template[pos], uni, (size_t) 7);
476  res = posix_open(template, oflag, mode);
477  }
478  }
479  }
480 
481  return(res);
482 }
483 #endif /* CFG_USE_POSIX_API < 200809 && CFG_USE_XSI */
484 
485 
486 /* ========================================================================== */
487 /* NLS */
488 
489 #if CFG_USE_POSIX_API < 200809
490 /*
491  * Only the following parameter set is supported:
492  * category_mask POSIX_LC_CTYPE_MASK
493  * locale "POSIX"
494  */
495 posix_locale_t posix_newlocale(int category_mask, const char* locale,
496  posix_locale_t base)
497 {
498  posix_locale_t res = 0;
499 
500  if(POSIX_LC_CTYPE_MASK != category_mask) { posix_errno = POSIX_EINVAL; }
501  else
502  {
503  if(strcmp(locale, "POSIX")) { posix_errno = POSIX_ENOENT; }
504  else { res = 1; }
505  }
506 
507  return(res);
508 }
509 
510 
511 void posix_freelocale(posix_locale_t locobj)
512 {
513  /* NOP (this implementation doesn't allocate memory for locale objects) */
514 
515  return;
516 }
517 
518 
519 /* 'locale' must always have its 'LC_CTYPE' element set to "POSIX" */
520 int posix_strncasecmp_l(const char* s1, const char* s2, size_t n,
521  posix_locale_t locale)
522 {
523  int res = 0;
524  size_t i;
525  int c1;
526  int c2;
527 
528  /* Compare in lower case */
529  for(i = 0; i < n; ++i)
530  {
531  c1 = (int) (unsigned char) s1[i];
532  c2 = (int) (unsigned char) s2[i];
533  /* Convert capital letters to lower case */
534  if(65 <= c1 && 90 >= c1) { c1 = (c1 - 65) + 97; }
535  if(65 <= c2 && 90 >= c2) { c2 = (c2 - 65) + 97; }
536  /* Check for end of strings and difference */
537  res = c1 - c2;
538  if(!c1 || !c2 || res) { break; }
539  }
540 
541  return(res);
542 }
543 
544 
545 int posix_strcasecmp_l(const char* s1, const char* s2,
546  posix_locale_t locale)
547 {
548  return(posix_strncasecmp_l(s1, s2, POSIX_SIZE_MAX, locale));
549 }
550 #endif /* CFG_USE_POSIX_API < 200809 */
551 
552 
553 /* ========================================================================== */
554 /* Standard I/O */
555 
556 #if CFG_USE_POSIX_API < 200112
557 /*
558  * Attention:
559  * The semantics for parameters s, n and return value in SUSv2 are different
560  * than in C99, POSIX.1-2001 and SUSv3!
561  *
562  * To avoid additional bloat, this implementation of 'snprintf()' contains
563  * only the subset of features that are required. What is present should be
564  * POSIX.1-2008 conformant.
565  *
566  * This function is thread safe.
567  *
568  * Supported conversions in the format string \e f :
569  * %% Literal percent character
570  * %s char* (string with NUL termination)
571  * %d signed int
572  * %u unsigned int
573  * %x unsigned int to hexadecimal (with small letters)
574  * %X unsigned int to hexadecimal (with capital letters)
575  *
576  * The integer conversions support the following modifiers:
577  * 0 Pad fields with minimum width using zeros instead of spaces
578  * [1-9] Minimum field width
579  * l Convert a long argument (signed long int, unsigned long int)
580  *
581  * If the return value is larger than \e n , the result was truncated to fit
582  * into the buffer pointed to by \e s .
583  *
584  * \attention
585  * The result string is only valid for locales that use the US-ASCII character
586  * set (or a superset of it).
587  *
588  * \note
589  * As a fallback, this function should be optimized for correctness, not speed.
590  * Calling 'realloc()' on the buffer for every integer conversion is very
591  * inefficient, but it's a safe solution for the problem how much buffer space
592  * is required for a number specified with a size of "at least" something.
593  */
594 # define SNPRINTF_RESET(c) \
595 { \
596  cn = 0; \
597  percent = c; \
598  mod_l = 0; \
599  mod_z = 0; \
600  mod_w = 0; \
601  lz = 1; \
602  ds = 0; \
603  conv = c; \
604 }
605 int posix_snprintf(char* s, size_t n, const char* f, ...)
606 {
607  va_list ap; /* Object for argument list handling */
608  int res; /* Result */
609  int err = 0; /* Error flag */
610  int err_no = POSIX_EINVAL; /* Error code */
611 
612  int conv; /* Conversion in progress flag */
613  int percent; /* Literal percent conversion flag */
614  int mod_l; /* Long modifier detected flag */
615  int mod_z; /* Leading zero modifier detected flag */
616  int mod_w; /* Minimum field width modifier if nonzero */
617  int hex_capital;
618 
619  const size_t fn = strlen(f); /* Length of format string */
620  size_t fi = 0; /* Index in format string */
621 
622  size_t sn = 0; /* Length of target string (not truncated) */
623  size_t si = 0; /* Index in target buffer */
624 
625  const char* c_s = ""; /* Pointer to string with conv. result */
626  size_t cn; /* Length of conversion result */
627  size_t ci; /* Index in conversion result */
628 
629  int lz; /* Leading zero flag */
630  int ds; /* Deferred sign flag */
631  size_t exp; /* Exponent */
632 
633  long int d; /* Parameter for signed int conversion */
634  long int d_p10 = 0; /* Greatest power of 10 */
635  long int d_lim; /* Limiting value */
636 
637  unsigned long int u; /* Parameter for unsigned int conversion */
638  unsigned long int u_p10 = 0; /* Greatest power of 10 */
639  unsigned long int u_lim; /* Limiting value */
640 
641  unsigned long int u_p16 = 0; /* Greatest power of 16 */
642  unsigned long int u_dig; /* Digit value */
643 
644  char b1[2]; /* Buffer for single character string */
645  char* b = NULL; /* Buffer for conversion results */
646  size_t bn = 0; /* Length of conversion buffer */
647 
648  long int i;
649  unsigned long int ui;
650  char cc;
651 
652  /* Init state */
653  SNPRINTF_RESET(0);
654  va_start(ap, f);
655 
656 #if 0 /* SUSv2 semantics */
657  /* Do not accept zero buffer length */
658  if(!n)
659  {
660  /* SUSv2 do not allow this, but C99 do => Reject it */
661  PRINT_ERROR("snprintf(): Calling with zero buffer size is not portable");
662  err_no = POSIX_EINVAL;
663  err = -1;
664  }
665 #else /* C99/POSIX.1-2001/SUSv3 semantics */
666  if (n && NULL == s)
667  {
668  PRINT_ERROR("snprintf(): NULL for buffer, but nonzero buffer size");
669  err_no = POSIX_EINVAL;
670  err = -1;
671  }
672 #endif
673  /* Check for size limit */
674  else if((unsigned int) POSIX_INT_MAX < n)
675  {
676  err_no = POSIX_EOVERFLOW;
677  err = -1;
678  }
679  else
680  {
681  /* Init output to empty string after it was checked that n is nonzero */
682  /* Attention: C99 allows (NULL == s) and (n == 0) */
683  if(n) { s[0] = 0; }
684  /* Parse format string */
685  while(fn > fi)
686  {
687  if (!conv)
688  {
689  /* Copy anything that is not a conversion specification literally */
690  c_s = &f[fi];
691  cn = strcspn(&f[fi], "%");
692  fi += cn;
693  conv = 1;
694  percent = 0;
695  }
696  else
697  {
698  /* Conversion */
699  cc = f[fi++];
700  hex_capital = 0;
701  switch(cc)
702  {
703  case '%': /* Conversion marker */
704  {
705  if(!percent)
706  {
707  /* Reset state for new conversion */
708  SNPRINTF_RESET(1);
709  }
710  else
711  {
712  /* Exec literal '%' conversion */
713  conv = 0;
714  b1[0] = '%';
715  b1[1] = 0;
716  c_s = b1;
717  cn = 1;
718  }
719  break;
720  }
721  case 'l': /* Long modifier */
722  {
723  mod_l = 1;
724  break;
725  }
726  case '0': /* Leading zero modifier */
727  {
728  mod_z = 1;
729  break;
730  }
731  case '1': /* Minimum field width modifier */
732  case '2': /* Minimum field width modifier */
733  case '3': /* Minimum field width modifier */
734  case '4': /* Minimum field width modifier */
735  case '5': /* Minimum field width modifier */
736  case '6': /* Minimum field width modifier */
737  case '7': /* Minimum field width modifier */
738  case '8': /* Minimum field width modifier */
739  case '9': /* Minimum field width modifier */
740  {
741  mod_w = (int) cc - 48;
742  break;
743  }
744  case 'd': /* Exec signed integer conversion */
745  {
746  conv = 0;
747  /* Calculate greatest power of 10 for signed integer */
748  if(mod_l) { d_lim = POSIX_LONG_MAX; }
749  else { d_lim = (long int) POSIX_INT_MAX; }
750  d_p10 = 10000L; exp = 4;
751  while(1)
752  {
753  if(10 > d_lim / d_p10) { break; }
754  d_p10 *= 10; ++exp;
755  }
756  /* Maximum required size: Sign + exponent + 1 + termination */
757  bn = exp + (size_t) 3;
758  /* Allocate buffer for conversion result */
759  b = (char*) posix_realloc((void*) b, bn);
760  if (NULL == b) { err_no = POSIX_ENOMEM; err = 1; break; }
761  /* Get signed value from stack */
762  if(mod_l) { d = va_arg(ap, long int); }
763  else { d = (long int) va_arg(ap, int); }
764  ci = 0;
765  /*
766  * Process sign
767  * Positive values are negated because on machines with 2's
768  * complement arithmetic the negative range is larger.
769  */
770  if(0L > d)
771  {
772  if(!mod_w) { b[ci++] = '-'; }
773  else
774  {
775  --mod_w;
776  if (mod_z) { b[ci++] = '-'; }
777  else { ds = 1; }
778  }
779  }
780  else { d = -d; }
781  /* Process digits */
782  i = -d_p10;
783  while(-1L >= i)
784  {
785  if(d <= i)
786  {
787  lz = 0;
788  if(ds) { b[ci++] = '-'; ds = 0; }
789  b[ci++] = (char) (48L + d / i);
790  d -= d / i * i;
791  }
792  else if(lz)
793  {
794  if(!d && -1L == i) { b[ci++] = '0'; }
795  else
796  {
797  /* Check minimum field width */
798  if(mod_w > exp)
799  {
800  if(!mod_z) { b[ci++] = ' '; }
801  else { b[ci++] = '0'; }
802  }
803  }
804  }
805  else { b[ci++] = '0'; }
806  i /= 10L; --exp;
807  if(ci >= bn) { break; }
808  }
809  /* Sanity check */
810  if(ci >= bn) { si = POSIX_SIZE_MAX; err = 1; break; }
811  /* Terminate conversion result */
812  b[ci] = 0;
813  c_s = b;
814  cn = ci;
815  break;
816  }
817  case 'u': /* Exec unsigned integer conversion */
818  {
819  conv = 0;
820  /* Calculate greatest power of 10 for unsigned integer */
821  if(mod_l) { u_lim = POSIX_ULONG_MAX; }
822  else { u_lim = (long int) POSIX_UINT_MAX; }
823  u_p10 = 10000UL; exp = 4;
824  while(1)
825  {
826  if(10 > u_lim / u_p10) { break; }
827  u_p10 *= 10; ++exp;
828  }
829  /* Maximum required size: exponent + 1 + termination */
830  bn = exp + (size_t) 2;
831  /* Allocate buffer for conversion result */
832  b = (char*) posix_realloc((void*) b, bn);
833  if (NULL == b) { err_no = POSIX_ENOMEM; err = 1; break; }
834  /* Get unsigned value from stack */
835  if(mod_l) { u = va_arg(ap, unsigned long int); }
836  else { u = (unsigned long int) va_arg(ap, unsigned int); }
837  ci = 0;
838  /* Process digits */
839  ui = u_p10;
840  while(1UL <= ui)
841  {
842  if(u >= ui)
843  {
844  lz = 0;
845  b[ci++] = (char) (48UL + u / ui);
846  u -= u / ui * ui;
847  }
848  else if(lz)
849  {
850  if(!u && 1UL == ui) { b[ci++] = '0'; }
851  else
852  {
853  /* Check minimum field width */
854  if(mod_w > exp)
855  {
856  if(!mod_z) { b[ci++] = ' '; }
857  else { b[ci++] = '0'; }
858  }
859  }
860  }
861  else { b[ci++] = '0'; }
862  ui /= 10UL; --exp;
863  if(ci >= bn) { break; }
864  }
865  /* Sanity check */
866  if(ci >= bn) { si = POSIX_SIZE_MAX; err = 1; break; }
867  /* Terminate conversion result */
868  b[ci] = 0;
869  c_s = b;
870  cn = ci;
871  break;
872  }
873  case 'X':
874  {
875  hex_capital = 1;
876  /* No break here is intended */
877  }
878  case 'x': /* Exec unsigned integer conversion to hexadecimal */
879  {
880  conv = 0;
881  /* Calculate greatest power of 16 for unsigned integer */
882  if(mod_l) { u_lim = POSIX_ULONG_MAX; }
883  else { u_lim = (long int) POSIX_UINT_MAX; }
884  u_p16 = 4096UL; exp = 3;
885  while(1)
886  {
887  if(16 > u_lim / u_p16) { break; }
888  u_p16 *= 16; ++exp;
889  }
890  /* Maximum required size: exponent + 1 + termination */
891  bn = exp + (size_t) 2;
892  /* Allocate buffer for conversion result */
893  b = (char*) posix_realloc((void*) b, bn);
894  if (NULL == b) { err_no = POSIX_ENOMEM; err = 1; break; }
895  /* Get unsigned value from stack */
896  if(mod_l) { u = va_arg(ap, unsigned long int); }
897  else { u = (unsigned long int) va_arg(ap, unsigned int); }
898  ci = 0;
899  /* Process digits */
900  ui = u_p16;
901  while(1UL <= ui)
902  {
903  if(u >= ui)
904  {
905  lz = 0;
906  u_dig = u / ui;
907  if(10UL > u_dig) { b[ci++] = (char) (48UL + u_dig); }
908  else
909  {
910  u_dig -= 10;
911  if(hex_capital) { b[ci++] = (char) (65UL + u_dig); }
912  else { b[ci++] = (char) (97UL + u_dig); }
913  }
914  u -= u / ui * ui;
915  }
916  else if(lz)
917  {
918  if(!u && 1UL == ui) { b[ci++] = '0'; }
919  else
920  {
921  /* Check minimum field width */
922  if(mod_w > exp)
923  {
924  if(!mod_z) { b[ci++] = ' '; }
925  else { b[ci++] = '0'; }
926  }
927  }
928  }
929  else { b[ci++] = '0'; }
930  ui /= 16UL; --exp;
931  if(ci >= bn) { break; }
932  }
933  /* Sanity check */
934  if(ci >= bn) { si = POSIX_SIZE_MAX; err = 1; break; }
935  /* Terminate conversion result */
936  b[ci] = 0;
937  c_s = b;
938  cn = ci;
939  break;
940  }
941  case 's': /* Exec string conversion */
942  {
943  if(mod_l)
944  {
945  PRINT_ERROR("snprintf(): Invalid modifier in conversion");
946  err = 1;
947  break;
948  }
949  conv = 0;
950  c_s = va_arg(ap, char*);
951  cn = strlen(c_s);
952  break;
953  }
954  default: /* Conversion type not supported */
955  {
956  PRINT_ERROR("snprintf(): Conversion type not supported");
957  /* Print a '?' to the output string */
958  b1[0] = '?';
959  b1[1] = 0;
960  c_s = b1;
961  cn = 1;
962  break;
963  }
964  }
965  if(err) break;
966  }
967  if(err) break;
968 
969  /* Add up size of conversions */
970  if(POSIX_SIZE_MAX - sn < cn) { sn = POSIX_SIZE_MAX; }
971  else { sn += cn; }
972 
973  /* Copy conversion data to buffer */
974  /* Attention: C99 allows (NULL == s) and (n == 0) */
975  if(n && (si < n - 1) && cn)
976  {
977  if(n - 1 - si < cn) { cn = n - 1 - si; }
978  memcpy(&s[si], c_s, cn);
979  si += cn;
980  s[si] = 0;
981  }
982  }
983  posix_free((void*) b);
984 
985  /* Sanity check */
986  if (si && si >= n)
987  {
988  /* This should really never happen! */
989  PRINT_ERROR("snprintf(): AAARGHHH, buffer overflow detected!");
990  /* Return error */
991  err = 1;
992  err_no = POSIX_EOVERFLOW;
993  }
994  }
995 
996  /* Set return value */
997  if(!err) { res = (int) sn; }
998  else
999  {
1000  posix_errno = err_no;
1001  res = -1;
1002  }
1003 
1004  va_end(ap);
1005 
1006  return(res);
1007 }
1008 #endif /* CFG_USE_POSIX_API < 200112 */
1009 
1010 
1011 #if CFG_USE_POSIX_API < 200809
1012 /*
1013  * This implementation of 'getline()' should be POSIX.1-2008 conformant.
1014  * This function is thread safe if the underlaying 'fgetc()' is thread safe.
1015  */
1016 #define GETLINE_BLOCKSIZE (size_t) 128
1017 posix_ssize_t posix_getline(char** lineptr, size_t* n, FILE* stream)
1018 {
1019  posix_ssize_t res = -1;
1020  size_t len = *n;
1021  size_t pos = 0;
1022  char* memp;
1023  size_t mems = GETLINE_BLOCKSIZE;
1024  int rv = EOF;
1025  char termreq = 0;
1026 
1027  /* Check whether parameters are valid */
1028  if(NULL == lineptr || NULL == n) { posix_errno = POSIX_EINVAL; }
1029  else
1030  {
1031  /* Allocate line buffer if *lineptr is NULL */
1032  if (NULL == *lineptr)
1033  {
1034  *lineptr = (char*) posix_malloc(GETLINE_BLOCKSIZE);
1035  if(NULL == *lineptr) { posix_errno = POSIX_ENOMEM; }
1036  else { len = *n = GETLINE_BLOCKSIZE; }
1037  }
1038 
1039  /* Check for line buffer */
1040  if(NULL != *lineptr)
1041  {
1042  /* Limit usable buffer size if required */
1043  if((size_t) POSIX_SSIZE_MAX < len) { len = (size_t) POSIX_SSIZE_MAX; }
1044 
1045  /* Read data */
1046  while((size_t) POSIX_SSIZE_MAX > pos && mems)
1047  {
1048  if(pos >= len)
1049  {
1050  /* Allocate more memory */
1051  if(GETLINE_BLOCKSIZE > POSIX_SIZE_MAX - len)
1052  {
1053  mems = POSIX_SIZE_MAX - len;
1054  if(!mems)
1055  {
1056  posix_errno = POSIX_ENOMEM;
1057  break;
1058  }
1059  }
1060  memp = posix_realloc(*lineptr, *n + mems);
1061  if(NULL == memp)
1062  {
1063  posix_errno = POSIX_ENOMEM;
1064  break;
1065  }
1066  else
1067  {
1068  *lineptr = memp;
1069  *n += mems;
1070  len = *n;
1071  }
1072  }
1073 
1074  /* Check for termination request */
1075  if(termreq)
1076  {
1077  /* Terminate result string */
1078  (*lineptr)[pos] = 0;
1079  res = (posix_ssize_t) pos;
1080  break;
1081  }
1082 
1083  /* Get next character */
1084  rv = posix_fgetc(stream);
1085  if(EOF == rv) break;
1086  (*lineptr)[pos++] = (char) rv;
1087  if('\n' == (char) rv)
1088  {
1089  /* EOL detected */
1090  termreq = 1;
1091  }
1092  }
1093 
1094  /* Check for error */
1095  if((size_t) POSIX_SSIZE_MAX <= pos)
1096  {
1097  posix_errno = POSIX_EOVERFLOW;
1098  }
1099  }
1100  }
1101 
1102  return(res);
1103 }
1104 #endif /* CFG_USE_POSIX_API < 200809 */
1105 
1106 
1107 /* ========================================================================== */
1108 /* Address information */
1109 
1110 #if CFG_USE_POSIX_API < 200112 && !CFG_USE_IP6
1111 /* This implementation of 'freeaddrinfo()' should be POSIX.1-2008 conformant */
1112 void posix_freeaddrinfo(struct_posix_addrinfo* info)
1113 {
1114  struct_posix_addrinfo* next;
1115 
1116  while(NULL != info)
1117  {
1118  /* Store pointer to next object */
1119  next = info->ai_next;
1120  /* Free memory for current object */
1121  posix_free((void*) info);
1122  /* Continue with next object */
1123  info = next;
1124  }
1125 }
1126 
1127 
1128 /*
1129  * This implementation of 'getaddrinfo()' should be POSIX.1-2008 conformant with
1130  * the following exceptions:
1131  * - A nodename must be specified, resolving a service name alone is not
1132  * supported
1133  * - Only the flag AI_ADDRCONFIG is supported
1134  *
1135  * \attention
1136  * This emulation is based on deprecated functions that are removed from
1137  * POSIX.1-2008, this means it can only be used for older API versions.
1138  */
1139 static posix_pthread_mutex_t getaddrinfo_mutex
1140  = POSIX_PTHREAD_MUTEX_INITIALIZER;
1141 int posix_getaddrinfo(const char* nodename, const char* servname,
1142  const struct_posix_addrinfo* hints,
1143  struct_posix_addrinfo** result)
1144 {
1145  int res = 0;
1146  struct_posix_addrinfo* info = NULL;
1147  struct_posix_addrinfo* tmp = NULL;
1148  struct_posix_servent* se;
1149  struct_posix_hostent* he;
1150  size_t num = 0;
1151  posix_in_port_t port = 0;
1152  unsigned int p;
1153  int family = hints->ai_family;
1154 
1155  *result = NULL;
1156 
1157  /* Only IPv4 is supported */
1158  if(POSIX_AF_UNSPEC == family) { family = POSIX_AF_INET; }
1159 
1160  /* This implementation can't resolve service names alone */
1161  if(NULL == nodename)
1162  {
1163  PRINT_ERROR("getaddrinfo(): Call without nodename not supported");
1164  res = POSIX_EAI_FAIL;
1165  }
1166  else if(POSIX_AF_INET != family)
1167  {
1168  /* Address family not supported */
1169  res = POSIX_EAI_FAMILY;
1170  }
1171  else if (POSIX_SOCK_STREAM != hints->ai_socktype)
1172  {
1173  /* Socket type not supported */
1174  res = POSIX_EAI_SOCKTYPE;
1175  }
1176  else
1177  {
1178  if(NULL != servname)
1179  {
1180  /* Resolve service name using BSD API */
1181  if(posix_pthread_mutex_lock(&getaddrinfo_mutex))
1182  {
1183  PRINT_ERROR("getaddrinfo(): Locking mutex failed");
1184  res = POSIX_EAI_AGAIN;
1185  }
1186  else
1187  {
1188  /* Lock UI mutex */
1189  if(ts_lock_ui())
1190  {
1191  PRINT_ERROR("Locking UI mutex failed");
1192  res = POSIX_EAI_AGAIN;
1193  }
1194  else
1195  {
1196  /* Check whether a number is specified */
1197  if(1 == sscanf(servname, "%u", &p))
1198  {
1199  port = (posix_in_port_t) posix_htons((posix_in_port_t) p);
1200  }
1201  else
1202  {
1203  se = posix_getservbyname(servname, NULL);
1204  if(NULL != se) { port = (posix_in_port_t) se->s_port; }
1205  }
1206  /* Unlock UI mutex */
1207  if(ts_unlock_ui())
1208  {
1209  PRINT_ERROR("Unlocking UI mutex failed");
1210  }
1211  }
1212  /*
1213  * In a multithreading environment the systems hostent buffer may be
1214  * shared between all threads. Therefore the mutex must stay locked
1215  * until we have copied the data to our thread local buffer.
1216  */
1217  posix_pthread_mutex_unlock(&getaddrinfo_mutex);
1218  }
1219  }
1220 
1221  /* Resolve hostname to IPv4 address using BSD API */
1222  if(NULL != servname && !port)
1223  {
1224  PRINT_ERROR("getaddrinfo(): Service resolution failed");
1225  res = POSIX_EAI_FAIL;
1226  }
1227  else if(posix_pthread_mutex_lock(&getaddrinfo_mutex))
1228  {
1229  PRINT_ERROR("getaddrinfo(): Locking mutex failed");
1230  res = POSIX_EAI_AGAIN;
1231  }
1232  else
1233  {
1234  /* Lock UI mutex */
1235  if(ts_lock_ui())
1236  {
1237  PRINT_ERROR("Locking UI mutex failed");
1238  res = POSIX_EAI_AGAIN;
1239  }
1240  else
1241  {
1242  he = posix_gethostbyname(nodename);
1243  if(NULL == he) { res = POSIX_EAI_NONAME; }
1244  else if(POSIX_AF_INET != he->h_addrtype || 4 != he->h_length)
1245  {
1246  PRINT_ERROR("getaddrinfo(): Address type not supported");
1247  res = POSIX_EAI_FAIL;
1248  }
1249  else
1250  {
1251  do
1252  {
1253  /* Allocate memory for result object */
1254  tmp = (struct_posix_addrinfo*)
1255  posix_malloc(sizeof(struct_posix_addrinfo)
1256  + sizeof(struct_posix_sockaddr_in));
1257  if(NULL == tmp) { res = POSIX_EAI_MEMORY; break; }
1258  else
1259  {
1260  if(NULL == info) { *result = info = tmp; }
1261  else { info = info->ai_next = tmp; }
1262  /* Populate information structure */
1263  memset((void*) info, 0, sizeof(struct_posix_addrinfo));
1264  info->ai_family = POSIX_AF_INET;
1265  info->ai_socktype = hints->ai_socktype;
1266  info->ai_protocol = hints->ai_protocol;
1267  info->ai_addrlen
1268  = (posix_socklen_t) sizeof(struct_posix_sockaddr_in);
1269  info->ai_addr
1270  = (struct_posix_sockaddr*) (void*)
1271  ((char*) (void*) info + sizeof(struct_posix_addrinfo));
1272  ((struct_posix_sockaddr_in*) info->ai_addr)->sin_family
1273  = (posix_sa_family_t) info->ai_family;
1274  ((struct_posix_sockaddr_in*) info->ai_addr)->sin_port
1275  = port;
1276  ((struct_posix_sockaddr_in*) info->ai_addr)
1277  ->sin_addr.s_addr
1278  = *((posix_in_addr_t*) he->h_addr_list[num++]);
1279  info->ai_next = NULL;
1280 #if 0
1281  /* For debugging */
1282  printf("%s: %sgetaddrinfo(): Resolve result: "
1283  "%s / %s -> %s:%u\n", CFG_NAME, MAIN_ERR_PREFIX,
1284  nodename, servname,
1285  inet_ntoa(((struct_posix_sockaddr_in*)info->ai_addr)
1286  ->sin_addr),
1287  (unsigned int) posix_ntohs(port));
1288 
1289 #endif
1290  }
1291  }
1292  while(NULL != he->h_addr_list[num]);
1293  }
1294  /* Unlock UI mutex */
1295  if(ts_unlock_ui())
1296  {
1297  PRINT_ERROR("Unlocking UI mutex failed");
1298  }
1299  }
1300  /*
1301  * In a multithreading environment the systems hostent buffer may be
1302  * shared between all threads. Therefore the mutex must stay locked
1303  * until we have copied the data to our thread local buffer.
1304  */
1305  posix_pthread_mutex_unlock(&getaddrinfo_mutex);
1306 #if 0
1307  printf("%s: %sgetaddrinfo(): %u result(s)\n",
1308  CFG_NAME, MAIN_ERR_PREFIX, (unsigned int) num);
1309 #endif
1310  }
1311  }
1312 
1313  /* Free memory on error */
1314 #if 0
1315  printf("%s: %sgetaddrinfo(): Result: %d\n",
1316  CFG_NAME, MAIN_ERR_PREFIX, res);
1317 #endif
1318  if(res) { posix_freeaddrinfo(*result); }
1319 
1320  return(res);
1321 }
1322 
1323 
1324 /* This implementation of 'gai_strerror()' should be POSIX.1-2008 conformant */
1325 const char* posix_gai_strerror(int ecode)
1326 {
1327  const char* res;
1328 
1329  switch(ecode)
1330  {
1331  case POSIX_EAI_AGAIN:
1332  {
1333  res = "Name could not be resolved at this time";
1334  break;
1335  }
1336  case POSIX_EAI_BADFLAGS:
1337  {
1338  res = "Parameter had an invalid value";
1339  break;
1340  }
1341  case POSIX_EAI_FAIL:
1342  {
1343  res = "Non-recoverable error occurred while resolving the name";
1344  break;
1345  }
1346  case POSIX_EAI_FAMILY:
1347  {
1348  res = "Address family was not recognized";
1349  break;
1350  }
1351  case POSIX_EAI_MEMORY:
1352  {
1353  res = "Memory allocation failed";
1354  break;
1355  }
1356  case POSIX_EAI_NONAME:
1357  {
1358  res = "Name does not resolve for the supplied parameters";
1359  break;
1360  }
1361  case POSIX_EAI_OVERFLOW:
1362  {
1363  res = "Argument buffer overflowed (passed buffer too small)";
1364  break;
1365  }
1366  case POSIX_EAI_SERVICE:
1367  {
1368  res = "Service passed not recognized for the specified socket type";
1369  break;
1370  }
1371  case POSIX_EAI_SOCKTYPE:
1372  {
1373  res = "Intended socket type was not recognized";
1374  break;
1375  }
1376  case POSIX_EAI_SYSTEM:
1377  {
1378  res = "System error occurred";
1379  break;
1380  }
1381  default:
1382  {
1383  res = "Unknown error occurred";
1384  break;
1385  }
1386  }
1387 
1388  return(res);
1389 }
1390 #endif /* CFG_USE_POSIX_API < 200112 && !CFG_USE_IP6 */
1391 
1392 
1393 /* ========================================================================== */
1394 /* BSD socket interface (XNS) */
1395 
1396 #if CFG_USE_POSIX_API < 200112
1397 int posix_inet_pton(int af, const char* src, void* dst)
1398 {
1399  int res = 1;
1400  posix_in_addr_t addr;
1401 
1402  switch(af)
1403  {
1404  case POSIX_AF_INET:
1405  {
1406  af = AF_INET;
1407  break;
1408  }
1409  default:
1410  {
1411  errno = EAFNOSUPPORT;
1412  res = -1;
1413  }
1414  }
1415 
1416  if(1 == res)
1417  {
1418  /* Typecast required if systems implementation is used */
1419  addr = (posix_in_addr_t) posix_inet_addr(src);
1420  if((posix_in_addr_t) -1 == addr) { res = 0; }
1421  else
1422  {
1423  /* The data in 'addr' is already in network byte order */
1424  *((unsigned char*) dst) = *((unsigned char*) &addr);
1425  *((unsigned char*) dst + 1) = *((unsigned char*) &addr + 1);
1426  *((unsigned char*) dst + 2) = *((unsigned char*) &addr + 2);
1427  *((unsigned char*) dst + 3) = *((unsigned char*) &addr + 3);
1428  }
1429  }
1430 
1431  return(res);
1432 }
1433 #endif /* CFG_USE_POSIX_API < 200112 */
1434 
1435 
1436 /* EOF */
MAIN_ERR_PREFIX
#define MAIN_ERR_PREFIX
Message prefix for POSIX module.
Definition: posix.c:99
PRINT_ERROR
#define PRINT_ERROR(s)
Prepend module prefix and print error message.
Definition: main.h:19
ts_unlock_ui
int ts_unlock_ui(void)
Unlock UI thread.
Definition: main.cxx:244
ts_lock_ui
int ts_lock_ui(void)
Lock UI thread.
Definition: main.cxx:217

Generated at 2024-04-27 using  doxygen