os_unix.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. /*
  2. * OS specific functions for UNIX/POSIX systems
  3. * Copyright (c) 2005-2009, 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. #include "includes.h"
  9. #include <time.h>
  10. #include <sys/wait.h>
  11. #ifdef ANDROID
  12. #include <sys/capability.h>
  13. #include <sys/prctl.h>
  14. #include <private/android_filesystem_config.h>
  15. #endif /* ANDROID */
  16. #ifdef __MACH__
  17. #include <CoreServices/CoreServices.h>
  18. #include <mach/mach.h>
  19. #include <mach/mach_time.h>
  20. #endif /* __MACH__ */
  21. #include "os.h"
  22. #include "common.h"
  23. #ifdef WPA_TRACE
  24. #include "wpa_debug.h"
  25. #include "trace.h"
  26. #include "list.h"
  27. static struct dl_list alloc_list = DL_LIST_HEAD_INIT(alloc_list);
  28. #define ALLOC_MAGIC 0xa84ef1b2
  29. #define FREED_MAGIC 0x67fd487a
  30. struct os_alloc_trace {
  31. unsigned int magic;
  32. struct dl_list list;
  33. size_t len;
  34. WPA_TRACE_INFO
  35. } __attribute__((aligned(16)));
  36. #endif /* WPA_TRACE */
  37. void os_sleep(os_time_t sec, os_time_t usec)
  38. {
  39. if (sec)
  40. sleep(sec);
  41. if (usec)
  42. usleep(usec);
  43. }
  44. int os_get_time(struct os_time *t)
  45. {
  46. int res;
  47. struct timeval tv;
  48. res = gettimeofday(&tv, NULL);
  49. t->sec = tv.tv_sec;
  50. t->usec = tv.tv_usec;
  51. return res;
  52. }
  53. int os_get_reltime(struct os_reltime *t)
  54. {
  55. #ifndef __MACH__
  56. #if defined(CLOCK_BOOTTIME)
  57. static clockid_t clock_id = CLOCK_BOOTTIME;
  58. #elif defined(CLOCK_MONOTONIC)
  59. static clockid_t clock_id = CLOCK_MONOTONIC;
  60. #else
  61. static clockid_t clock_id = CLOCK_REALTIME;
  62. #endif
  63. struct timespec ts;
  64. int res;
  65. if (TEST_FAIL())
  66. return -1;
  67. while (1) {
  68. res = clock_gettime(clock_id, &ts);
  69. if (res == 0) {
  70. t->sec = ts.tv_sec;
  71. t->usec = ts.tv_nsec / 1000;
  72. return 0;
  73. }
  74. switch (clock_id) {
  75. #ifdef CLOCK_BOOTTIME
  76. case CLOCK_BOOTTIME:
  77. clock_id = CLOCK_MONOTONIC;
  78. break;
  79. #endif
  80. #ifdef CLOCK_MONOTONIC
  81. case CLOCK_MONOTONIC:
  82. clock_id = CLOCK_REALTIME;
  83. break;
  84. #endif
  85. case CLOCK_REALTIME:
  86. return -1;
  87. }
  88. }
  89. #else /* __MACH__ */
  90. uint64_t abstime, nano;
  91. static mach_timebase_info_data_t info = { 0, 0 };
  92. if (!info.denom) {
  93. if (mach_timebase_info(&info) != KERN_SUCCESS)
  94. return -1;
  95. }
  96. abstime = mach_absolute_time();
  97. nano = (abstime * info.numer) / info.denom;
  98. t->sec = nano / NSEC_PER_SEC;
  99. t->usec = (nano - (((uint64_t) t->sec) * NSEC_PER_SEC)) / NSEC_PER_USEC;
  100. return 0;
  101. #endif /* __MACH__ */
  102. }
  103. int os_mktime(int year, int month, int day, int hour, int min, int sec,
  104. os_time_t *t)
  105. {
  106. struct tm tm, *tm1;
  107. time_t t_local, t1, t2;
  108. os_time_t tz_offset;
  109. if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
  110. hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
  111. sec > 60)
  112. return -1;
  113. memset(&tm, 0, sizeof(tm));
  114. tm.tm_year = year - 1900;
  115. tm.tm_mon = month - 1;
  116. tm.tm_mday = day;
  117. tm.tm_hour = hour;
  118. tm.tm_min = min;
  119. tm.tm_sec = sec;
  120. t_local = mktime(&tm);
  121. /* figure out offset to UTC */
  122. tm1 = localtime(&t_local);
  123. if (tm1) {
  124. t1 = mktime(tm1);
  125. tm1 = gmtime(&t_local);
  126. if (tm1) {
  127. t2 = mktime(tm1);
  128. tz_offset = t2 - t1;
  129. } else
  130. tz_offset = 0;
  131. } else
  132. tz_offset = 0;
  133. *t = (os_time_t) t_local - tz_offset;
  134. return 0;
  135. }
  136. int os_gmtime(os_time_t t, struct os_tm *tm)
  137. {
  138. struct tm *tm2;
  139. time_t t2 = t;
  140. tm2 = gmtime(&t2);
  141. if (tm2 == NULL)
  142. return -1;
  143. tm->sec = tm2->tm_sec;
  144. tm->min = tm2->tm_min;
  145. tm->hour = tm2->tm_hour;
  146. tm->day = tm2->tm_mday;
  147. tm->month = tm2->tm_mon + 1;
  148. tm->year = tm2->tm_year + 1900;
  149. return 0;
  150. }
  151. #ifdef __APPLE__
  152. #include <fcntl.h>
  153. static int os_daemon(int nochdir, int noclose)
  154. {
  155. int devnull;
  156. if (chdir("/") < 0)
  157. return -1;
  158. devnull = open("/dev/null", O_RDWR);
  159. if (devnull < 0)
  160. return -1;
  161. if (dup2(devnull, STDIN_FILENO) < 0) {
  162. close(devnull);
  163. return -1;
  164. }
  165. if (dup2(devnull, STDOUT_FILENO) < 0) {
  166. close(devnull);
  167. return -1;
  168. }
  169. if (dup2(devnull, STDERR_FILENO) < 0) {
  170. close(devnull);
  171. return -1;
  172. }
  173. return 0;
  174. }
  175. #else /* __APPLE__ */
  176. #define os_daemon daemon
  177. #endif /* __APPLE__ */
  178. int os_daemonize(const char *pid_file)
  179. {
  180. #if defined(__uClinux__) || defined(__sun__)
  181. return -1;
  182. #else /* defined(__uClinux__) || defined(__sun__) */
  183. if (os_daemon(0, 0)) {
  184. perror("daemon");
  185. return -1;
  186. }
  187. if (pid_file) {
  188. FILE *f = fopen(pid_file, "w");
  189. if (f) {
  190. fprintf(f, "%u\n", getpid());
  191. fclose(f);
  192. }
  193. }
  194. return -0;
  195. #endif /* defined(__uClinux__) || defined(__sun__) */
  196. }
  197. void os_daemonize_terminate(const char *pid_file)
  198. {
  199. if (pid_file)
  200. unlink(pid_file);
  201. }
  202. int os_get_random(unsigned char *buf, size_t len)
  203. {
  204. FILE *f;
  205. size_t rc;
  206. if (TEST_FAIL())
  207. return -1;
  208. f = fopen("/dev/urandom", "rb");
  209. if (f == NULL) {
  210. printf("Could not open /dev/urandom.\n");
  211. return -1;
  212. }
  213. rc = fread(buf, 1, len, f);
  214. fclose(f);
  215. return rc != len ? -1 : 0;
  216. }
  217. unsigned long os_random(void)
  218. {
  219. return random();
  220. }
  221. char * os_rel2abs_path(const char *rel_path)
  222. {
  223. char *buf = NULL, *cwd, *ret;
  224. size_t len = 128, cwd_len, rel_len, ret_len;
  225. int last_errno;
  226. if (!rel_path)
  227. return NULL;
  228. if (rel_path[0] == '/')
  229. return os_strdup(rel_path);
  230. for (;;) {
  231. buf = os_malloc(len);
  232. if (buf == NULL)
  233. return NULL;
  234. cwd = getcwd(buf, len);
  235. if (cwd == NULL) {
  236. last_errno = errno;
  237. os_free(buf);
  238. if (last_errno != ERANGE)
  239. return NULL;
  240. len *= 2;
  241. if (len > 2000)
  242. return NULL;
  243. } else {
  244. buf[len - 1] = '\0';
  245. break;
  246. }
  247. }
  248. cwd_len = os_strlen(cwd);
  249. rel_len = os_strlen(rel_path);
  250. ret_len = cwd_len + 1 + rel_len + 1;
  251. ret = os_malloc(ret_len);
  252. if (ret) {
  253. os_memcpy(ret, cwd, cwd_len);
  254. ret[cwd_len] = '/';
  255. os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
  256. ret[ret_len - 1] = '\0';
  257. }
  258. os_free(buf);
  259. return ret;
  260. }
  261. int os_program_init(void)
  262. {
  263. #ifdef ANDROID
  264. /*
  265. * We ignore errors here since errors are normal if we
  266. * are already running as non-root.
  267. */
  268. #ifdef ANDROID_SETGROUPS_OVERRIDE
  269. gid_t groups[] = { ANDROID_SETGROUPS_OVERRIDE };
  270. #else /* ANDROID_SETGROUPS_OVERRIDE */
  271. gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
  272. #endif /* ANDROID_SETGROUPS_OVERRIDE */
  273. struct __user_cap_header_struct header;
  274. struct __user_cap_data_struct cap;
  275. setgroups(ARRAY_SIZE(groups), groups);
  276. prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
  277. setgid(AID_WIFI);
  278. setuid(AID_WIFI);
  279. header.version = _LINUX_CAPABILITY_VERSION;
  280. header.pid = 0;
  281. cap.effective = cap.permitted =
  282. (1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
  283. cap.inheritable = 0;
  284. capset(&header, &cap);
  285. #endif /* ANDROID */
  286. return 0;
  287. }
  288. void os_program_deinit(void)
  289. {
  290. #ifdef WPA_TRACE
  291. struct os_alloc_trace *a;
  292. unsigned long total = 0;
  293. dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
  294. total += a->len;
  295. if (a->magic != ALLOC_MAGIC) {
  296. wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
  297. "len %lu",
  298. a, a->magic, (unsigned long) a->len);
  299. continue;
  300. }
  301. wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
  302. a, (unsigned long) a->len);
  303. wpa_trace_dump("memleak", a);
  304. }
  305. if (total)
  306. wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
  307. (unsigned long) total);
  308. wpa_trace_deinit();
  309. #endif /* WPA_TRACE */
  310. }
  311. int os_setenv(const char *name, const char *value, int overwrite)
  312. {
  313. return setenv(name, value, overwrite);
  314. }
  315. int os_unsetenv(const char *name)
  316. {
  317. #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
  318. defined(__OpenBSD__)
  319. unsetenv(name);
  320. return 0;
  321. #else
  322. return unsetenv(name);
  323. #endif
  324. }
  325. char * os_readfile(const char *name, size_t *len)
  326. {
  327. FILE *f;
  328. char *buf;
  329. long pos;
  330. f = fopen(name, "rb");
  331. if (f == NULL)
  332. return NULL;
  333. if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
  334. fclose(f);
  335. return NULL;
  336. }
  337. *len = pos;
  338. if (fseek(f, 0, SEEK_SET) < 0) {
  339. fclose(f);
  340. return NULL;
  341. }
  342. buf = os_malloc(*len);
  343. if (buf == NULL) {
  344. fclose(f);
  345. return NULL;
  346. }
  347. if (fread(buf, 1, *len, f) != *len) {
  348. fclose(f);
  349. os_free(buf);
  350. return NULL;
  351. }
  352. fclose(f);
  353. return buf;
  354. }
  355. int os_file_exists(const char *fname)
  356. {
  357. return access(fname, F_OK) == 0;
  358. }
  359. int os_fdatasync(FILE *stream)
  360. {
  361. if (!fflush(stream)) {
  362. #ifdef __linux__
  363. return fdatasync(fileno(stream));
  364. #else /* !__linux__ */
  365. #ifdef F_FULLFSYNC
  366. /* OS X does not implement fdatasync(). */
  367. return fcntl(fileno(stream), F_FULLFSYNC);
  368. #else /* F_FULLFSYNC */
  369. return fsync(fileno(stream));
  370. #endif /* F_FULLFSYNC */
  371. #endif /* __linux__ */
  372. }
  373. return -1;
  374. }
  375. #ifndef WPA_TRACE
  376. void * os_zalloc(size_t size)
  377. {
  378. return calloc(1, size);
  379. }
  380. #endif /* WPA_TRACE */
  381. size_t os_strlcpy(char *dest, const char *src, size_t siz)
  382. {
  383. const char *s = src;
  384. size_t left = siz;
  385. if (left) {
  386. /* Copy string up to the maximum size of the dest buffer */
  387. while (--left != 0) {
  388. if ((*dest++ = *s++) == '\0')
  389. break;
  390. }
  391. }
  392. if (left == 0) {
  393. /* Not enough room for the string; force NUL-termination */
  394. if (siz != 0)
  395. *dest = '\0';
  396. while (*s++)
  397. ; /* determine total src string length */
  398. }
  399. return s - src - 1;
  400. }
  401. int os_memcmp_const(const void *a, const void *b, size_t len)
  402. {
  403. const u8 *aa = a;
  404. const u8 *bb = b;
  405. size_t i;
  406. u8 res;
  407. for (res = 0, i = 0; i < len; i++)
  408. res |= aa[i] ^ bb[i];
  409. return res;
  410. }
  411. void * os_memdup(const void *src, size_t len)
  412. {
  413. void *r = os_malloc(len);
  414. if (r)
  415. os_memcpy(r, src, len);
  416. return r;
  417. }
  418. #ifdef WPA_TRACE
  419. #if defined(WPA_TRACE_BFD) && defined(CONFIG_TESTING_OPTIONS)
  420. char wpa_trace_fail_func[256] = { 0 };
  421. unsigned int wpa_trace_fail_after;
  422. static int testing_fail_alloc(void)
  423. {
  424. const char *func[WPA_TRACE_LEN];
  425. size_t i, res, len;
  426. char *pos, *next;
  427. int match;
  428. if (!wpa_trace_fail_after)
  429. return 0;
  430. res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
  431. i = 0;
  432. if (i < res && os_strcmp(func[i], __func__) == 0)
  433. i++;
  434. if (i < res && os_strcmp(func[i], "os_malloc") == 0)
  435. i++;
  436. if (i < res && os_strcmp(func[i], "os_zalloc") == 0)
  437. i++;
  438. if (i < res && os_strcmp(func[i], "os_calloc") == 0)
  439. i++;
  440. if (i < res && os_strcmp(func[i], "os_realloc") == 0)
  441. i++;
  442. if (i < res && os_strcmp(func[i], "os_realloc_array") == 0)
  443. i++;
  444. if (i < res && os_strcmp(func[i], "os_strdup") == 0)
  445. i++;
  446. if (i < res && os_strcmp(func[i], "os_memdup") == 0)
  447. i++;
  448. pos = wpa_trace_fail_func;
  449. match = 0;
  450. while (i < res) {
  451. int allow_skip = 1;
  452. int maybe = 0;
  453. if (*pos == '=') {
  454. allow_skip = 0;
  455. pos++;
  456. } else if (*pos == '?') {
  457. maybe = 1;
  458. pos++;
  459. }
  460. next = os_strchr(pos, ';');
  461. if (next)
  462. len = next - pos;
  463. else
  464. len = os_strlen(pos);
  465. if (os_memcmp(pos, func[i], len) != 0) {
  466. if (maybe && next) {
  467. pos = next + 1;
  468. continue;
  469. }
  470. if (allow_skip) {
  471. i++;
  472. continue;
  473. }
  474. return 0;
  475. }
  476. if (!next) {
  477. match = 1;
  478. break;
  479. }
  480. pos = next + 1;
  481. i++;
  482. }
  483. if (!match)
  484. return 0;
  485. wpa_trace_fail_after--;
  486. if (wpa_trace_fail_after == 0) {
  487. wpa_printf(MSG_INFO, "TESTING: fail allocation at %s",
  488. wpa_trace_fail_func);
  489. for (i = 0; i < res; i++)
  490. wpa_printf(MSG_INFO, "backtrace[%d] = %s",
  491. (int) i, func[i]);
  492. return 1;
  493. }
  494. return 0;
  495. }
  496. char wpa_trace_test_fail_func[256] = { 0 };
  497. unsigned int wpa_trace_test_fail_after;
  498. int testing_test_fail(void)
  499. {
  500. const char *func[WPA_TRACE_LEN];
  501. size_t i, res, len;
  502. char *pos, *next;
  503. int match;
  504. if (!wpa_trace_test_fail_after)
  505. return 0;
  506. res = wpa_trace_calling_func(func, WPA_TRACE_LEN);
  507. i = 0;
  508. if (i < res && os_strcmp(func[i], __func__) == 0)
  509. i++;
  510. pos = wpa_trace_test_fail_func;
  511. match = 0;
  512. while (i < res) {
  513. int allow_skip = 1;
  514. int maybe = 0;
  515. if (*pos == '=') {
  516. allow_skip = 0;
  517. pos++;
  518. } else if (*pos == '?') {
  519. maybe = 1;
  520. pos++;
  521. }
  522. next = os_strchr(pos, ';');
  523. if (next)
  524. len = next - pos;
  525. else
  526. len = os_strlen(pos);
  527. if (os_memcmp(pos, func[i], len) != 0) {
  528. if (maybe && next) {
  529. pos = next + 1;
  530. continue;
  531. }
  532. if (allow_skip) {
  533. i++;
  534. continue;
  535. }
  536. return 0;
  537. }
  538. if (!next) {
  539. match = 1;
  540. break;
  541. }
  542. pos = next + 1;
  543. i++;
  544. }
  545. if (!match)
  546. return 0;
  547. wpa_trace_test_fail_after--;
  548. if (wpa_trace_test_fail_after == 0) {
  549. wpa_printf(MSG_INFO, "TESTING: fail at %s",
  550. wpa_trace_test_fail_func);
  551. for (i = 0; i < res; i++)
  552. wpa_printf(MSG_INFO, "backtrace[%d] = %s",
  553. (int) i, func[i]);
  554. return 1;
  555. }
  556. return 0;
  557. }
  558. #else
  559. static inline int testing_fail_alloc(void)
  560. {
  561. return 0;
  562. }
  563. #endif
  564. void * os_malloc(size_t size)
  565. {
  566. struct os_alloc_trace *a;
  567. if (testing_fail_alloc())
  568. return NULL;
  569. a = malloc(sizeof(*a) + size);
  570. if (a == NULL)
  571. return NULL;
  572. a->magic = ALLOC_MAGIC;
  573. dl_list_add(&alloc_list, &a->list);
  574. a->len = size;
  575. wpa_trace_record(a);
  576. return a + 1;
  577. }
  578. void * os_realloc(void *ptr, size_t size)
  579. {
  580. struct os_alloc_trace *a;
  581. size_t copy_len;
  582. void *n;
  583. if (ptr == NULL)
  584. return os_malloc(size);
  585. a = (struct os_alloc_trace *) ptr - 1;
  586. if (a->magic != ALLOC_MAGIC) {
  587. wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
  588. a, a->magic,
  589. a->magic == FREED_MAGIC ? " (already freed)" : "");
  590. wpa_trace_show("Invalid os_realloc() call");
  591. abort();
  592. }
  593. n = os_malloc(size);
  594. if (n == NULL)
  595. return NULL;
  596. copy_len = a->len;
  597. if (copy_len > size)
  598. copy_len = size;
  599. os_memcpy(n, a + 1, copy_len);
  600. os_free(ptr);
  601. return n;
  602. }
  603. void os_free(void *ptr)
  604. {
  605. struct os_alloc_trace *a;
  606. if (ptr == NULL)
  607. return;
  608. a = (struct os_alloc_trace *) ptr - 1;
  609. if (a->magic != ALLOC_MAGIC) {
  610. wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
  611. a, a->magic,
  612. a->magic == FREED_MAGIC ? " (already freed)" : "");
  613. wpa_trace_show("Invalid os_free() call");
  614. abort();
  615. }
  616. dl_list_del(&a->list);
  617. a->magic = FREED_MAGIC;
  618. wpa_trace_check_ref(ptr);
  619. free(a);
  620. }
  621. void * os_zalloc(size_t size)
  622. {
  623. void *ptr = os_malloc(size);
  624. if (ptr)
  625. os_memset(ptr, 0, size);
  626. return ptr;
  627. }
  628. char * os_strdup(const char *s)
  629. {
  630. size_t len;
  631. char *d;
  632. len = os_strlen(s);
  633. d = os_malloc(len + 1);
  634. if (d == NULL)
  635. return NULL;
  636. os_memcpy(d, s, len);
  637. d[len] = '\0';
  638. return d;
  639. }
  640. #endif /* WPA_TRACE */
  641. int os_exec(const char *program, const char *arg, int wait_completion)
  642. {
  643. pid_t pid;
  644. int pid_status;
  645. pid = fork();
  646. if (pid < 0) {
  647. perror("fork");
  648. return -1;
  649. }
  650. if (pid == 0) {
  651. /* run the external command in the child process */
  652. const int MAX_ARG = 30;
  653. char *_program, *_arg, *pos;
  654. char *argv[MAX_ARG + 1];
  655. int i;
  656. _program = os_strdup(program);
  657. _arg = os_strdup(arg);
  658. argv[0] = _program;
  659. i = 1;
  660. pos = _arg;
  661. while (i < MAX_ARG && pos && *pos) {
  662. while (*pos == ' ')
  663. pos++;
  664. if (*pos == '\0')
  665. break;
  666. argv[i++] = pos;
  667. pos = os_strchr(pos, ' ');
  668. if (pos)
  669. *pos++ = '\0';
  670. }
  671. argv[i] = NULL;
  672. execv(program, argv);
  673. perror("execv");
  674. os_free(_program);
  675. os_free(_arg);
  676. exit(0);
  677. return -1;
  678. }
  679. if (wait_completion) {
  680. /* wait for the child process to complete in the parent */
  681. waitpid(pid, &pid_status, 0);
  682. }
  683. return 0;
  684. }