os_unix.c 14 KB

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