Coverage Report

Created: 2025-04-24 06:18

/src/hostap/src/utils/os_unix.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * OS specific functions for UNIX/POSIX systems
3
 * Copyright (c) 2005-2019, Jouni Malinen <j@w1.fi>
4
 *
5
 * This software may be distributed under the terms of the BSD license.
6
 * See README for more details.
7
 */
8
9
#include "includes.h"
10
11
#include <time.h>
12
#include <sys/wait.h>
13
14
#ifdef ANDROID
15
#include <sys/capability.h>
16
#include <sys/prctl.h>
17
#include <private/android_filesystem_config.h>
18
#endif /* ANDROID */
19
20
#ifdef __MACH__
21
#include <CoreServices/CoreServices.h>
22
#include <mach/mach.h>
23
#include <mach/mach_time.h>
24
#endif /* __MACH__ */
25
26
#include "os.h"
27
#include "common.h"
28
29
#ifdef WPA_TRACE
30
31
#include "wpa_debug.h"
32
#include "trace.h"
33
#include "list.h"
34
35
static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
36
37
#define ALLOC_MAGIC 0xa84ef1b2
38
#define FREED_MAGIC 0x67fd487a
39
40
struct os_alloc_trace {
41
  unsigned int magic;
42
  struct dl_list list __attribute__((aligned(16)));
43
  size_t len;
44
  WPA_TRACE_INFO
45
} __attribute__((aligned(16)));
46
47
#endif /* WPA_TRACE */
48
49
50
void os_sleep(os_time_t sec, os_time_t usec)
51
0
{
52
0
#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L)
53
0
  const struct timespec req = { sec, usec * 1000 };
54
55
0
  nanosleep(&req, NULL);
56
#else
57
  if (sec)
58
    sleep(sec);
59
  if (usec)
60
    usleep(usec);
61
#endif
62
0
}
63
64
65
int os_get_time(struct os_time *t)
66
0
{
67
0
  int res;
68
0
  struct timeval tv;
69
0
  res = gettimeofday(&tv, NULL);
70
0
  t->sec = tv.tv_sec;
71
0
  t->usec = tv.tv_usec;
72
0
  return res;
73
0
}
74
75
76
int os_get_reltime(struct os_reltime *t)
77
7.57k
{
78
7.57k
#ifndef __MACH__
79
7.57k
#if defined(CLOCK_BOOTTIME)
80
7.57k
  static clockid_t clock_id = CLOCK_BOOTTIME;
81
#elif defined(CLOCK_MONOTONIC)
82
  static clockid_t clock_id = CLOCK_MONOTONIC;
83
#else
84
  static clockid_t clock_id = CLOCK_REALTIME;
85
#endif
86
7.57k
  struct timespec ts;
87
7.57k
  int res;
88
89
7.57k
  if (TEST_FAIL())
90
0
    return -1;
91
92
7.57k
  while (1) {
93
7.57k
    res = clock_gettime(clock_id, &ts);
94
7.57k
    if (res == 0) {
95
7.57k
      t->sec = ts.tv_sec;
96
7.57k
      t->usec = ts.tv_nsec / 1000;
97
7.57k
      return 0;
98
7.57k
    }
99
0
    switch (clock_id) {
100
0
#ifdef CLOCK_BOOTTIME
101
0
    case CLOCK_BOOTTIME:
102
0
      clock_id = CLOCK_MONOTONIC;
103
0
      break;
104
0
#endif
105
0
#ifdef CLOCK_MONOTONIC
106
0
    case CLOCK_MONOTONIC:
107
0
      clock_id = CLOCK_REALTIME;
108
0
      break;
109
0
#endif
110
0
    case CLOCK_REALTIME:
111
0
      return -1;
112
0
    }
113
0
  }
114
#else /* __MACH__ */
115
  uint64_t abstime, nano;
116
  static mach_timebase_info_data_t info = { 0, 0 };
117
118
  if (!info.denom) {
119
    if (mach_timebase_info(&info) != KERN_SUCCESS)
120
      return -1;
121
  }
122
123
  abstime = mach_absolute_time();
124
  nano = (abstime * info.numer) / info.denom;
125
126
  t->sec = nano / NSEC_PER_SEC;
127
  t->usec = (nano - (((uint64_t) t->sec) * NSEC_PER_SEC)) / NSEC_PER_USEC;
128
129
  return 0;
130
#endif /* __MACH__ */
131
7.57k
}
132
133
134
int os_mktime(int year, int month, int day, int hour, int min, int sec,
135
        os_time_t *t)
136
0
{
137
0
  struct tm tm, *tm1;
138
0
  time_t t_local, t1, t2;
139
0
  os_time_t tz_offset;
140
141
0
  if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
142
0
      hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
143
0
      sec > 60)
144
0
    return -1;
145
146
0
  memset(&tm, 0, sizeof(tm));
147
0
  tm.tm_year = year - 1900;
148
0
  tm.tm_mon = month - 1;
149
0
  tm.tm_mday = day;
150
0
  tm.tm_hour = hour;
151
0
  tm.tm_min = min;
152
0
  tm.tm_sec = sec;
153
154
0
  t_local = mktime(&tm);
155
156
  /* figure out offset to UTC */
157
0
  tm1 = localtime(&t_local);
158
0
  if (tm1) {
159
0
    t1 = mktime(tm1);
160
0
    tm1 = gmtime(&t_local);
161
0
    if (tm1) {
162
0
      t2 = mktime(tm1);
163
0
      tz_offset = t2 - t1;
164
0
    } else
165
0
      tz_offset = 0;
166
0
  } else
167
0
    tz_offset = 0;
168
169
0
  *t = (os_time_t) t_local - tz_offset;
170
0
  return 0;
171
0
}
172
173
174
int os_gmtime(os_time_t t, struct os_tm *tm)
175
0
{
176
0
  struct tm *tm2;
177
0
  time_t t2 = t;
178
179
0
  tm2 = gmtime(&t2);
180
0
  if (tm2 == NULL)
181
0
    return -1;
182
0
  tm->sec = tm2->tm_sec;
183
0
  tm->min = tm2->tm_min;
184
0
  tm->hour = tm2->tm_hour;
185
0
  tm->day = tm2->tm_mday;
186
0
  tm->month = tm2->tm_mon + 1;
187
0
  tm->year = tm2->tm_year + 1900;
188
0
  return 0;
189
0
}
190
191
192
#ifdef __APPLE__
193
#include <fcntl.h>
194
static int os_daemon(int nochdir, int noclose)
195
{
196
  int devnull;
197
198
  if (chdir("/") < 0)
199
    return -1;
200
201
  devnull = open("/dev/null", O_RDWR);
202
  if (devnull < 0)
203
    return -1;
204
205
  if (dup2(devnull, STDIN_FILENO) < 0) {
206
    close(devnull);
207
    return -1;
208
  }
209
210
  if (dup2(devnull, STDOUT_FILENO) < 0) {
211
    close(devnull);
212
    return -1;
213
  }
214
215
  if (dup2(devnull, STDERR_FILENO) < 0) {
216
    close(devnull);
217
    return -1;
218
  }
219
220
  return 0;
221
}
222
#else /* __APPLE__ */
223
0
#define os_daemon daemon
224
#endif /* __APPLE__ */
225
226
227
int os_daemonize(const char *pid_file)
228
0
{
229
#if defined(__uClinux__) || defined(__sun__)
230
  return -1;
231
#else /* defined(__uClinux__) || defined(__sun__) */
232
0
  if (os_daemon(0, 0)) {
233
0
    perror("daemon");
234
0
    return -1;
235
0
  }
236
237
0
  if (pid_file) {
238
0
    FILE *f = fopen(pid_file, "w");
239
0
    if (f) {
240
0
      fprintf(f, "%u\n", getpid());
241
0
      fclose(f);
242
0
    }
243
0
  }
244
245
0
  return -0;
246
0
#endif /* defined(__uClinux__) || defined(__sun__) */
247
0
}
248
249
250
void os_daemonize_terminate(const char *pid_file)
251
0
{
252
0
  if (pid_file)
253
0
    unlink(pid_file);
254
0
}
255
256
257
int os_get_random(unsigned char *buf, size_t len)
258
1.43k
{
259
1.43k
#ifdef TEST_FUZZ
260
1.43k
  size_t i;
261
262
7.16k
  for (i = 0; i < len; i++)
263
5.72k
    buf[i] = i & 0xff;
264
1.43k
  return 0;
265
#else /* TEST_FUZZ */
266
  FILE *f;
267
  size_t rc;
268
269
  if (TEST_FAIL())
270
    return -1;
271
272
  f = fopen("/dev/urandom", "rb");
273
  if (f == NULL) {
274
    printf("Could not open /dev/urandom.\n");
275
    return -1;
276
  }
277
278
  rc = fread(buf, 1, len, f);
279
  fclose(f);
280
281
  return rc != len ? -1 : 0;
282
#endif /* TEST_FUZZ */
283
1.43k
}
284
285
286
unsigned long os_random(void)
287
0
{
288
0
  return random();
289
0
}
290
291
292
char * os_rel2abs_path(const char *rel_path)
293
0
{
294
0
  char *buf = NULL, *cwd, *ret;
295
0
  size_t len = 128, cwd_len, rel_len, ret_len;
296
0
  int last_errno;
297
298
0
  if (!rel_path)
299
0
    return NULL;
300
301
0
  if (rel_path[0] == '/')
302
0
    return os_strdup(rel_path);
303
304
0
  for (;;) {
305
0
    buf = os_malloc(len);
306
0
    if (buf == NULL)
307
0
      return NULL;
308
0
    cwd = getcwd(buf, len);
309
0
    if (cwd == NULL) {
310
0
      last_errno = errno;
311
0
      os_free(buf);
312
0
      if (last_errno != ERANGE)
313
0
        return NULL;
314
0
      len *= 2;
315
0
      if (len > 2000)
316
0
        return NULL;
317
0
    } else {
318
0
      buf[len - 1] = '\0';
319
0
      break;
320
0
    }
321
0
  }
322
323
0
  cwd_len = os_strlen(cwd);
324
0
  rel_len = os_strlen(rel_path);
325
0
  ret_len = cwd_len + 1 + rel_len + 1;
326
0
  ret = os_malloc(ret_len);
327
0
  if (ret) {
328
0
    os_memcpy(ret, cwd, cwd_len);
329
0
    ret[cwd_len] = '/';
330
0
    os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
331
0
    ret[ret_len - 1] = '\0';
332
0
  }
333
0
  os_free(buf);
334
0
  return ret;
335
0
}
336
337
338
int os_program_init(void)
339
1.43k
{
340
1.43k
  unsigned int seed;
341
342
#ifdef ANDROID
343
  /*
344
   * We ignore errors here since errors are normal if we
345
   * are already running as non-root.
346
   */
347
#ifdef ANDROID_SETGROUPS_OVERRIDE
348
  gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
349
#else /* ANDROID_SETGROUPS_OVERRIDE */
350
  gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
351
#endif /* ANDROID_SETGROUPS_OVERRIDE */
352
  struct __user_cap_header_struct header;
353
  struct __user_cap_data_struct cap;
354
355
  setgroups(ARRAY_SIZE(groups), groups);
356
357
  prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
358
359
  setgid(AID_WIFI);
360
  setuid(AID_WIFI);
361
362
  header.version = _LINUX_CAPABILITY_VERSION;
363
  header.pid = 0;
364
  cap.effective = cap.permitted =
365
    (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
366
  cap.inheritable = 0;
367
  capset(&header, &cap);
368
#endif /* ANDROID */
369
370
1.43k
  if (os_get_random((unsigned char *) &seed, sizeof(seed)) == 0)
371
1.43k
    srandom(seed);
372
373
1.43k
  return 0;
374
1.43k
}
375
376
377
void os_program_deinit(void)
378
1.43k
{
379
#ifdef WPA_TRACE
380
  struct os_alloc_trace *a;
381
  unsigned long total = 0;
382
  dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
383
    total += a->len;
384
    if (a->magic != ALLOC_MAGIC) {
385
      wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
386
           "len %lu",
387
           a, a->magic, (unsigned long) a->len);
388
      continue;
389
    }
390
    wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
391
         a, (unsigned long) a->len);
392
    wpa_trace_dump("memleak", a);
393
  }
394
  if (total)
395
    wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
396
         (unsigned long) total);
397
  wpa_trace_deinit();
398
#endif /* WPA_TRACE */
399
1.43k
}
400
401
402
int os_setenv(const char *name, const char *value, int overwrite)
403
0
{
404
0
  return setenv(name, value, overwrite);
405
0
}
406
407
408
int os_unsetenv(const char *name)
409
0
{
410
#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
411
    defined(__OpenBSD__)
412
  unsetenv(name);
413
  return 0;
414
#else
415
0
  return unsetenv(name);
416
0
#endif
417
0
}
418
419
420
char * os_readfile(const char *name, size_t *len)
421
0
{
422
0
  FILE *f;
423
0
  char *buf;
424
0
  long pos;
425
426
0
  f = fopen(name, "rb");
427
0
  if (f == NULL)
428
0
    return NULL;
429
430
0
  if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
431
0
    fclose(f);
432
0
    return NULL;
433
0
  }
434
0
  *len = pos;
435
0
  if (fseek(f, 0, SEEK_SET) < 0) {
436
0
    fclose(f);
437
0
    return NULL;
438
0
  }
439
440
0
  buf = os_malloc(*len);
441
0
  if (buf == NULL) {
442
0
    fclose(f);
443
0
    return NULL;
444
0
  }
445
446
0
  if (fread(buf, 1, *len, f) != *len) {
447
0
    fclose(f);
448
0
    os_free(buf);
449
0
    return NULL;
450
0
  }
451
452
0
  fclose(f);
453
454
0
  return buf;
455
0
}
456
457
458
int os_file_exists(const char *fname)
459
0
{
460
0
  return access(fname, F_OK) == 0;
461
0
}
462
463
464
int os_fdatasync(FILE *stream)
465
0
{
466
0
  if (!fflush(stream)) {
467
0
#if defined __FreeBSD__ || defined __linux__
468
0
    return fdatasync(fileno(stream));
469
#else /* !__linux__ && !__FreeBSD__ */
470
#ifdef F_FULLFSYNC
471
    /* OS X does not implement fdatasync(). */
472
    return fcntl(fileno(stream), F_FULLFSYNC);
473
#else /* F_FULLFSYNC */
474
    return fsync(fileno(stream));
475
#endif /* F_FULLFSYNC */
476
#endif /* __linux__ */
477
0
  }
478
479
0
  return -1;
480
0
}
481
482
483
#ifndef WPA_TRACE
484
void * os_zalloc(size_t size)
485
4.82k
{
486
4.82k
  return calloc(1, size);
487
4.82k
}
488
#endif /* WPA_TRACE */
489
490
491
size_t os_strlcpy(char *dest, const char *src, size_t siz)
492
0
{
493
0
  const char *s = src;
494
0
  size_t left = siz;
495
496
0
  if (left) {
497
    /* Copy string up to the maximum size of the dest buffer */
498
0
    while (--left != 0) {
499
0
      if ((*dest++ = *s++) == '\0')
500
0
        break;
501
0
    }
502
0
  }
503
504
0
  if (left == 0) {
505
    /* Not enough room for the string; force NUL-termination */
506
0
    if (siz != 0)
507
0
      *dest = '\0';
508
0
    while (*s++)
509
0
      ; /* determine total src string length */
510
0
  }
511
512
0
  return s - src - 1;
513
0
}
514
515
516
int os_memcmp_const(const void *a, const void *b, size_t len)
517
0
{
518
0
  const u8 *aa = a;
519
0
  const u8 *bb = b;
520
0
  size_t i;
521
0
  u8 res;
522
523
0
  for (res = 0, i = 0; i < len; i++)
524
0
    res |= aa[i] ^ bb[i];
525
526
0
  return res;
527
0
}
528
529
530
void * os_memdup(const void *src, size_t len)
531
0
{
532
0
  void *r = os_malloc(len);
533
534
0
  if (r && src)
535
0
    os_memcpy(r, src, len);
536
0
  return r;
537
0
}
538
539
540
#ifdef WPA_TRACE
541
542
#if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
543
static struct wpa_trace_test_fail {
544
  unsigned int fail_after;
545
  char pattern[256];
546
} wpa_trace_test_fail[5][4];
547
548
int testing_test_fail(const char *tag, bool is_alloc)
549
{
550
  const char *ignore_list[] = {
551
    "os_malloc", "os_zalloc", "os_calloc", "os_realloc",
552
    "os_realloc_array", "os_strdup", "os_memdup"
553
  };
554
  const char *func[WPA_TRACE_LEN];
555
  size_t i, j, res, len, idx;
556
  char *pos, *next;
557
  int match;
558
559
  is_alloc = !!is_alloc;
560
561
  for (idx = 0; idx < ARRAY_SIZE(wpa_trace_test_fail[is_alloc]); idx++) {
562
    if (wpa_trace_test_fail[is_alloc][idx].fail_after != 0)
563
      break;
564
  }
565
  if (idx >= ARRAY_SIZE(wpa_trace_test_fail[is_alloc]))
566
    return 0;
567
568
  res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
569
  i = 0;
570
571
  if (is_alloc) {
572
    /* Skip our own stack frame */
573
    i++;
574
575
    /* Skip allocation helpers */
576
    for (j = 0; j < ARRAY_SIZE(ignore_list) && i < res; j++) {
577
      if (os_strcmp(func[i], ignore_list[j]) == 0)
578
        i++;
579
    }
580
  } else {
581
    /* Not allocation, we might have a tag, if so, replace our
582
     * own stack frame with the tag, otherwise skip it.
583
     */
584
    if (tag)
585
      func[0] = tag;
586
    else
587
      i++;
588
  }
589
590
  pos = wpa_trace_test_fail[is_alloc][idx].pattern;
591
592
  /* The prefixes mean:
593
   * - '=': The function needs to be next in the backtrace
594
   * - '?': The function is optionally present in the backtrace
595
   */
596
597
  match = 0;
598
  while (i < res) {
599
    int allow_skip = 1;
600
    int maybe = 0;
601
    bool prefix = false;
602
603
    if (*pos == '=') {
604
      allow_skip = 0;
605
      pos++;
606
    } else if (*pos == '?') {
607
      maybe = 1;
608
      pos++;
609
    }
610
    next = os_strchr(pos, ';');
611
    if (next)
612
      len = next - pos;
613
    else
614
      len = os_strlen(pos);
615
    if (len >= 1 && pos[len - 1] == '*') {
616
      prefix = true;
617
      len -= 1;
618
    }
619
    if (os_strncmp(pos, func[i], len) != 0 ||
620
        (!prefix && func[i][len] != '\0')) {
621
      if (maybe && next) {
622
        pos = next + 1;
623
        continue;
624
      }
625
      if (allow_skip) {
626
        i++;
627
        continue;
628
      }
629
      return 0;
630
    }
631
    if (!next) {
632
      match = 1;
633
      break;
634
    }
635
    pos = next + 1;
636
    i++;
637
  }
638
  if (!match)
639
    return 0;
640
641
  wpa_trace_test_fail[is_alloc][idx].fail_after--;
642
  if (wpa_trace_test_fail[is_alloc][idx].fail_after == 0) {
643
    wpa_printf(MSG_INFO, "TESTING: fail at %s",
644
         wpa_trace_test_fail[is_alloc][idx].pattern);
645
    for (i = 0; i < res; i++)
646
      wpa_printf(MSG_INFO, "backtrace[%d] = %s",
647
           (int) i, func[i]);
648
    return 1;
649
  }
650
651
  return 0;
652
}
653
654
655
int testing_set_fail_pattern(bool is_alloc, char *patterns)
656
{
657
#ifdef WPA_TRACE_BFD
658
  char *token, *context = NULL;
659
  size_t idx;
660
661
  is_alloc = !!is_alloc;
662
663
  os_memset(wpa_trace_test_fail[is_alloc], 0,
664
      sizeof(wpa_trace_test_fail[is_alloc]));
665
666
  idx = 0;
667
  while ((token = str_token(patterns, " \n\r\t", &context)) &&
668
         idx < ARRAY_SIZE(wpa_trace_test_fail[is_alloc])) {
669
    wpa_trace_test_fail[is_alloc][idx].fail_after = atoi(token);
670
    token = os_strchr(token, ':');
671
    if (!token) {
672
      os_memset(wpa_trace_test_fail[is_alloc], 0,
673
          sizeof(wpa_trace_test_fail[is_alloc]));
674
      return -1;
675
    }
676
677
    os_strlcpy(wpa_trace_test_fail[is_alloc][idx].pattern,
678
         token + 1,
679
         sizeof(wpa_trace_test_fail[is_alloc][0].pattern));
680
    idx++;
681
  }
682
683
  return 0;
684
#else /* WPA_TRACE_BFD */
685
  return -1;
686
#endif /* WPA_TRACE_BFD */
687
}
688
689
690
int testing_get_fail_pattern(bool is_alloc, char *buf, size_t buflen)
691
{
692
#ifdef WPA_TRACE_BFD
693
  size_t idx, ret;
694
  char *pos = buf;
695
  char *end = buf + buflen;
696
697
  is_alloc = !!is_alloc;
698
699
  for (idx = 0; idx < ARRAY_SIZE(wpa_trace_test_fail[is_alloc]); idx++) {
700
    if (wpa_trace_test_fail[is_alloc][idx].pattern[0] == '\0')
701
      break;
702
703
    ret = os_snprintf(pos, end - pos, "%s%u:%s",
704
          pos == buf ? "" : " ",
705
          wpa_trace_test_fail[is_alloc][idx].fail_after,
706
          wpa_trace_test_fail[is_alloc][idx].pattern);
707
    if (os_snprintf_error(end - pos, ret))
708
      break;
709
    pos += ret;
710
  }
711
712
  return pos - buf;
713
#else /* WPA_TRACE_BFD */
714
  return -1;
715
#endif /* WPA_TRACE_BFD */
716
}
717
718
#else /* defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS) */
719
720
static inline int testing_test_fail(const char *tag, bool is_alloc)
721
{
722
  return 0;
723
}
724
725
#endif
726
727
void * os_malloc(size_t size)
728
{
729
  struct os_alloc_trace *a;
730
731
  if (testing_test_fail(NULL, true))
732
    return NULL;
733
734
  a = malloc(sizeof(*a) + size);
735
  if (a == NULL)
736
    return NULL;
737
  a->magic = ALLOC_MAGIC;
738
  dl_list_add(&alloc_list, &a->list);
739
  a->len = size;
740
  wpa_trace_record(a);
741
  return a + 1;
742
}
743
744
745
void * os_realloc(void *ptr, size_t size)
746
{
747
  struct os_alloc_trace *a;
748
  size_t copy_len;
749
  void *n;
750
751
  if (ptr == NULL)
752
    return os_malloc(size);
753
754
  a = (struct os_alloc_trace *) ptr - 1;
755
  if (a->magic != ALLOC_MAGIC) {
756
    wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
757
         a, a->magic,
758
         a->magic == FREED_MAGIC ? " (already freed)" : "");
759
    wpa_trace_show("Invalid os_realloc() call");
760
    abort();
761
  }
762
  n = os_malloc(size);
763
  if (n == NULL)
764
    return NULL;
765
  copy_len = a->len;
766
  if (copy_len > size)
767
    copy_len = size;
768
  os_memcpy(n, a + 1, copy_len);
769
  os_free(ptr);
770
  return n;
771
}
772
773
774
void os_free(void *ptr)
775
{
776
  struct os_alloc_trace *a;
777
778
  if (ptr == NULL)
779
    return;
780
  a = (struct os_alloc_trace *) ptr - 1;
781
  if (a->magic != ALLOC_MAGIC) {
782
    wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
783
         a, a->magic,
784
         a->magic == FREED_MAGIC ? " (already freed)" : "");
785
    wpa_trace_show("Invalid os_free() call");
786
    abort();
787
  }
788
  dl_list_del(&a->list);
789
  a->magic = FREED_MAGIC;
790
791
  wpa_trace_check_ref(ptr);
792
  free(a);
793
}
794
795
796
void * os_zalloc(size_t size)
797
{
798
  void *ptr = os_malloc(size);
799
  if (ptr)
800
    os_memset(ptr, 0, size);
801
  return ptr;
802
}
803
804
805
char * os_strdup(const char *s)
806
{
807
  size_t len;
808
  char *d;
809
  len = os_strlen(s);
810
  d = os_malloc(len + 1);
811
  if (d == NULL)
812
    return NULL;
813
  os_memcpy(d, s, len);
814
  d[len] = '\0';
815
  return d;
816
}
817
818
#endif /* WPA_TRACE */
819
820
821
int os_exec(const char *program, const char *arg, int wait_completion)
822
0
{
823
0
  pid_t pid;
824
0
  int pid_status;
825
826
0
  pid = fork();
827
0
  if (pid < 0) {
828
0
    perror("fork");
829
0
    return -1;
830
0
  }
831
832
0
  if (pid == 0) {
833
    /* run the external command in the child process */
834
0
    const int MAX_ARG = 30;
835
0
    char *_program, *_arg, *pos;
836
0
    char *argv[MAX_ARG + 1];
837
0
    int i;
838
839
0
    _program = os_strdup(program);
840
0
    _arg = os_strdup(arg);
841
842
0
    argv[0] = _program;
843
844
0
    i = 1;
845
0
    pos = _arg;
846
0
    while (i < MAX_ARG && pos && *pos) {
847
0
      while (*pos == ' ')
848
0
        pos++;
849
0
      if (*pos == '\0')
850
0
        break;
851
0
      argv[i++] = pos;
852
0
      pos = os_strchr(pos, ' ');
853
0
      if (pos)
854
0
        *pos++ = '\0';
855
0
    }
856
0
    argv[i] = NULL;
857
858
0
    execv(program, argv);
859
0
    perror("execv");
860
0
    os_free(_program);
861
0
    os_free(_arg);
862
0
    exit(0);
863
0
    return -1;
864
0
  }
865
866
0
  if (wait_completion) {
867
    /* wait for the child process to complete in the parent */
868
0
    waitpid(pid, &pid_status, 0);
869
0
  }
870
871
0
  return 0;
872
0
}