dbutil.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. /*
  2. * Dropbear - a SSH2 server
  3. *
  4. * Copyright (c) 2002,2003 Matt Johnston
  5. * All rights reserved.
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE.
  24. *
  25. * strlcat() is copyright as follows:
  26. * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
  27. * All rights reserved.
  28. *
  29. * Redistribution and use in source and binary forms, with or without
  30. * modification, are permitted provided that the following conditions
  31. * are met:
  32. * 1. Redistributions of source code must retain the above copyright
  33. * notice, this list of conditions and the following disclaimer.
  34. * 2. Redistributions in binary form must reproduce the above copyright
  35. * notice, this list of conditions and the following disclaimer in the
  36. * documentation and/or other materials provided with the distribution.
  37. * 3. The name of the author may not be used to endorse or promote products
  38. * derived from this software without specific prior written permission.
  39. *
  40. * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  41. * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  42. * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  43. * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  44. * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  45. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
  46. * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  47. * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
  48. * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
  49. * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
  50. #include "config.h"
  51. #ifdef __linux__
  52. #define _GNU_SOURCE
  53. /* To call clock_gettime() directly */
  54. #include <sys/syscall.h>
  55. #endif /* __linux */
  56. #ifdef HAVE_MACH_MACH_TIME_H
  57. #include <mach/mach_time.h>
  58. #include <mach/mach.h>
  59. #endif
  60. #include "includes.h"
  61. #include "dbutil.h"
  62. #include "buffer.h"
  63. #include "session.h"
  64. #include "atomicio.h"
  65. #define MAX_FMT 100
  66. static void generic_dropbear_exit(int exitcode, const char* format,
  67. va_list param) ATTRIB_NORETURN;
  68. static void generic_dropbear_log(int priority, const char* format,
  69. va_list param);
  70. void (*_dropbear_exit)(int exitcode, const char* format, va_list param) ATTRIB_NORETURN
  71. = generic_dropbear_exit;
  72. void (*_dropbear_log)(int priority, const char* format, va_list param)
  73. = generic_dropbear_log;
  74. #ifdef DEBUG_TRACE
  75. int debug_trace = 0;
  76. #endif
  77. #ifndef DISABLE_SYSLOG
  78. void startsyslog(const char *ident) {
  79. openlog(ident, LOG_PID, LOG_AUTHPRIV);
  80. }
  81. #endif /* DISABLE_SYSLOG */
  82. /* the "format" string must be <= 100 characters */
  83. void dropbear_close(const char* format, ...) {
  84. va_list param;
  85. va_start(param, format);
  86. _dropbear_exit(EXIT_SUCCESS, format, param);
  87. va_end(param);
  88. }
  89. void dropbear_exit(const char* format, ...) {
  90. va_list param;
  91. va_start(param, format);
  92. _dropbear_exit(EXIT_FAILURE, format, param);
  93. va_end(param);
  94. }
  95. static void generic_dropbear_exit(int exitcode, const char* format,
  96. va_list param) {
  97. char fmtbuf[300];
  98. snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s", format);
  99. _dropbear_log(LOG_INFO, fmtbuf, param);
  100. exit(exitcode);
  101. }
  102. void fail_assert(const char* expr, const char* file, int line) {
  103. dropbear_exit("Failed assertion (%s:%d): `%s'", file, line, expr);
  104. }
  105. static void generic_dropbear_log(int UNUSED(priority), const char* format,
  106. va_list param) {
  107. char printbuf[1024];
  108. vsnprintf(printbuf, sizeof(printbuf), format, param);
  109. fprintf(stderr, "%s\n", printbuf);
  110. }
  111. /* this is what can be called to write arbitrary log messages */
  112. void dropbear_log(int priority, const char* format, ...) {
  113. va_list param;
  114. va_start(param, format);
  115. _dropbear_log(priority, format, param);
  116. va_end(param);
  117. }
  118. #ifdef DEBUG_TRACE
  119. static double debug_start_time = -1;
  120. void debug_start_net()
  121. {
  122. if (getenv("DROPBEAR_DEBUG_NET_TIMESTAMP"))
  123. {
  124. /* Timestamps start from first network activity */
  125. struct timeval tv;
  126. gettimeofday(&tv, NULL);
  127. debug_start_time = tv.tv_sec + (tv.tv_usec / 1000000.0);
  128. TRACE(("Resetting Dropbear TRACE timestamps"))
  129. }
  130. }
  131. static double time_since_start()
  132. {
  133. double nowf;
  134. struct timeval tv;
  135. gettimeofday(&tv, NULL);
  136. nowf = tv.tv_sec + (tv.tv_usec / 1000000.0);
  137. if (debug_start_time < 0)
  138. {
  139. debug_start_time = nowf;
  140. return 0;
  141. }
  142. return nowf - debug_start_time;
  143. }
  144. void dropbear_trace(const char* format, ...) {
  145. va_list param;
  146. if (!debug_trace) {
  147. return;
  148. }
  149. va_start(param, format);
  150. fprintf(stderr, "TRACE (%d) %f: ", getpid(), time_since_start());
  151. vfprintf(stderr, format, param);
  152. fprintf(stderr, "\n");
  153. va_end(param);
  154. }
  155. void dropbear_trace2(const char* format, ...) {
  156. static int trace_env = -1;
  157. va_list param;
  158. if (trace_env == -1) {
  159. trace_env = getenv("DROPBEAR_TRACE2") ? 1 : 0;
  160. }
  161. if (!(debug_trace && trace_env)) {
  162. return;
  163. }
  164. va_start(param, format);
  165. fprintf(stderr, "TRACE2 (%d) %f: ", getpid(), time_since_start());
  166. vfprintf(stderr, format, param);
  167. fprintf(stderr, "\n");
  168. va_end(param);
  169. }
  170. #endif /* DEBUG_TRACE */
  171. /* Connect to a given unix socket. The socket is blocking */
  172. #ifdef ENABLE_CONNECT_UNIX
  173. int connect_unix(const char* path) {
  174. struct sockaddr_un addr;
  175. int fd = -1;
  176. memset((void*)&addr, 0x0, sizeof(addr));
  177. addr.sun_family = AF_UNIX;
  178. strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
  179. fd = socket(PF_UNIX, SOCK_STREAM, 0);
  180. if (fd < 0) {
  181. TRACE(("Failed to open unix socket"))
  182. return -1;
  183. }
  184. if (connect(fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
  185. TRACE(("Failed to connect to '%s' socket", path))
  186. m_close(fd);
  187. return -1;
  188. }
  189. return fd;
  190. }
  191. #endif
  192. /* Sets up a pipe for a, returning three non-blocking file descriptors
  193. * and the pid. exec_fn is the function that will actually execute the child process,
  194. * it will be run after the child has fork()ed, and is passed exec_data.
  195. * If ret_errfd == NULL then stderr will not be captured.
  196. * ret_pid can be passed as NULL to discard the pid. */
  197. int spawn_command(void(*exec_fn)(void *user_data), void *exec_data,
  198. int *ret_writefd, int *ret_readfd, int *ret_errfd, pid_t *ret_pid) {
  199. int infds[2];
  200. int outfds[2];
  201. int errfds[2];
  202. pid_t pid;
  203. const int FDIN = 0;
  204. const int FDOUT = 1;
  205. /* redirect stdin/stdout/stderr */
  206. if (pipe(infds) != 0) {
  207. return DROPBEAR_FAILURE;
  208. }
  209. if (pipe(outfds) != 0) {
  210. return DROPBEAR_FAILURE;
  211. }
  212. if (ret_errfd && pipe(errfds) != 0) {
  213. return DROPBEAR_FAILURE;
  214. }
  215. #ifdef USE_VFORK
  216. pid = vfork();
  217. #else
  218. pid = fork();
  219. #endif
  220. if (pid < 0) {
  221. return DROPBEAR_FAILURE;
  222. }
  223. if (!pid) {
  224. /* child */
  225. TRACE(("back to normal sigchld"))
  226. /* Revert to normal sigchld handling */
  227. if (signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
  228. dropbear_exit("signal() error");
  229. }
  230. /* redirect stdin/stdout */
  231. if ((dup2(infds[FDIN], STDIN_FILENO) < 0) ||
  232. (dup2(outfds[FDOUT], STDOUT_FILENO) < 0) ||
  233. (ret_errfd && dup2(errfds[FDOUT], STDERR_FILENO) < 0)) {
  234. TRACE(("leave noptycommand: error redirecting FDs"))
  235. dropbear_exit("Child dup2() failure");
  236. }
  237. close(infds[FDOUT]);
  238. close(infds[FDIN]);
  239. close(outfds[FDIN]);
  240. close(outfds[FDOUT]);
  241. if (ret_errfd)
  242. {
  243. close(errfds[FDIN]);
  244. close(errfds[FDOUT]);
  245. }
  246. exec_fn(exec_data);
  247. /* not reached */
  248. return DROPBEAR_FAILURE;
  249. } else {
  250. /* parent */
  251. close(infds[FDIN]);
  252. close(outfds[FDOUT]);
  253. setnonblocking(outfds[FDIN]);
  254. setnonblocking(infds[FDOUT]);
  255. if (ret_errfd) {
  256. close(errfds[FDOUT]);
  257. setnonblocking(errfds[FDIN]);
  258. }
  259. if (ret_pid) {
  260. *ret_pid = pid;
  261. }
  262. *ret_writefd = infds[FDOUT];
  263. *ret_readfd = outfds[FDIN];
  264. if (ret_errfd) {
  265. *ret_errfd = errfds[FDIN];
  266. }
  267. return DROPBEAR_SUCCESS;
  268. }
  269. }
  270. /* Runs a command with "sh -c". Will close FDs (except stdin/stdout/stderr) and
  271. * re-enabled SIGPIPE. If cmd is NULL, will run a login shell.
  272. */
  273. void run_shell_command(const char* cmd, unsigned int maxfd, char* usershell) {
  274. char * argv[4];
  275. char * baseshell = NULL;
  276. unsigned int i;
  277. baseshell = basename(usershell);
  278. if (cmd != NULL) {
  279. argv[0] = baseshell;
  280. } else {
  281. /* a login shell should be "-bash" for "/bin/bash" etc */
  282. int len = strlen(baseshell) + 2; /* 2 for "-" */
  283. argv[0] = (char*)m_malloc(len);
  284. snprintf(argv[0], len, "-%s", baseshell);
  285. }
  286. if (cmd != NULL) {
  287. argv[1] = "-c";
  288. argv[2] = (char*)cmd;
  289. argv[3] = NULL;
  290. } else {
  291. /* construct a shell of the form "-bash" etc */
  292. argv[1] = NULL;
  293. }
  294. /* Re-enable SIGPIPE for the executed process */
  295. if (signal(SIGPIPE, SIG_DFL) == SIG_ERR) {
  296. dropbear_exit("signal() error");
  297. }
  298. /* close file descriptors except stdin/stdout/stderr
  299. * Need to be sure FDs are closed here to avoid reading files as root */
  300. for (i = 3; i <= maxfd; i++) {
  301. m_close(i);
  302. }
  303. execv(usershell, argv);
  304. }
  305. #ifdef DEBUG_TRACE
  306. void printhex(const char * label, const unsigned char * buf, int len) {
  307. int i;
  308. fprintf(stderr, "%s\n", label);
  309. for (i = 0; i < len; i++) {
  310. fprintf(stderr, "%02x", buf[i]);
  311. if (i % 16 == 15) {
  312. fprintf(stderr, "\n");
  313. }
  314. else if (i % 2 == 1) {
  315. fprintf(stderr, " ");
  316. }
  317. }
  318. fprintf(stderr, "\n");
  319. }
  320. void printmpint(const char *label, mp_int *mp) {
  321. buffer *buf = buf_new(1000);
  322. buf_putmpint(buf, mp);
  323. printhex(label, buf->data, buf->len);
  324. buf_free(buf);
  325. }
  326. #endif
  327. /* Strip all control characters from text (a null-terminated string), except
  328. * for '\n', '\r' and '\t'.
  329. * The result returned is a newly allocated string, this must be free()d after
  330. * use */
  331. char * stripcontrol(const char * text) {
  332. char * ret;
  333. int len, pos;
  334. int i;
  335. len = strlen(text);
  336. ret = m_malloc(len+1);
  337. pos = 0;
  338. for (i = 0; i < len; i++) {
  339. if ((text[i] <= '~' && text[i] >= ' ') /* normal printable range */
  340. || text[i] == '\n' || text[i] == '\r' || text[i] == '\t') {
  341. ret[pos] = text[i];
  342. pos++;
  343. }
  344. }
  345. ret[pos] = 0x0;
  346. return ret;
  347. }
  348. /* reads the contents of filename into the buffer buf, from the current
  349. * position, either to the end of the file, or the buffer being full.
  350. * Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */
  351. int buf_readfile(buffer* buf, const char* filename) {
  352. int fd = -1;
  353. int len;
  354. int maxlen;
  355. int ret = DROPBEAR_FAILURE;
  356. fd = open(filename, O_RDONLY);
  357. if (fd < 0) {
  358. goto out;
  359. }
  360. do {
  361. maxlen = buf->size - buf->pos;
  362. len = read(fd, buf_getwriteptr(buf, maxlen), maxlen);
  363. if (len < 0) {
  364. if (errno == EINTR || errno == EAGAIN) {
  365. continue;
  366. }
  367. goto out;
  368. }
  369. buf_incrwritepos(buf, len);
  370. } while (len < maxlen && len > 0);
  371. ret = DROPBEAR_SUCCESS;
  372. out:
  373. if (fd >= 0) {
  374. m_close(fd);
  375. }
  376. return ret;
  377. }
  378. /* get a line from the file into buffer in the style expected for an
  379. * authkeys file.
  380. * Will return DROPBEAR_SUCCESS if data is read, or DROPBEAR_FAILURE on EOF.*/
  381. /* Only used for ~/.ssh/known_hosts and ~/.ssh/authorized_keys */
  382. #if defined(DROPBEAR_CLIENT) || defined(ENABLE_SVR_PUBKEY_AUTH)
  383. int buf_getline(buffer * line, FILE * authfile) {
  384. int c = EOF;
  385. buf_setpos(line, 0);
  386. buf_setlen(line, 0);
  387. while (line->pos < line->size) {
  388. c = fgetc(authfile); /*getc() is weird with some uClibc systems*/
  389. if (c == EOF || c == '\n' || c == '\r') {
  390. goto out;
  391. }
  392. buf_putbyte(line, (unsigned char)c);
  393. }
  394. TRACE(("leave getauthline: line too long"))
  395. /* We return success, but the line length will be zeroed - ie we just
  396. * ignore that line */
  397. buf_setlen(line, 0);
  398. out:
  399. /* if we didn't read anything before EOF or error, exit */
  400. if (c == EOF && line->pos == 0) {
  401. return DROPBEAR_FAILURE;
  402. } else {
  403. buf_setpos(line, 0);
  404. return DROPBEAR_SUCCESS;
  405. }
  406. }
  407. #endif
  408. /* make sure that the socket closes */
  409. void m_close(int fd) {
  410. int val;
  411. if (fd == -1) {
  412. return;
  413. }
  414. do {
  415. val = close(fd);
  416. } while (val < 0 && errno == EINTR);
  417. if (val < 0 && errno != EBADF) {
  418. /* Linux says EIO can happen */
  419. dropbear_exit("Error closing fd %d, %s", fd, strerror(errno));
  420. }
  421. }
  422. void * m_malloc(size_t size) {
  423. void* ret;
  424. if (size == 0) {
  425. dropbear_exit("m_malloc failed");
  426. }
  427. ret = calloc(1, size);
  428. if (ret == NULL) {
  429. dropbear_exit("m_malloc failed");
  430. }
  431. return ret;
  432. }
  433. void * m_strdup(const char * str) {
  434. char* ret;
  435. ret = strdup(str);
  436. if (ret == NULL) {
  437. dropbear_exit("m_strdup failed");
  438. }
  439. return ret;
  440. }
  441. void * m_realloc(void* ptr, size_t size) {
  442. void *ret;
  443. if (size == 0) {
  444. dropbear_exit("m_realloc failed");
  445. }
  446. ret = realloc(ptr, size);
  447. if (ret == NULL) {
  448. dropbear_exit("m_realloc failed");
  449. }
  450. return ret;
  451. }
  452. void setnonblocking(int fd) {
  453. TRACE(("setnonblocking: %d", fd))
  454. if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) {
  455. if (errno == ENODEV) {
  456. /* Some devices (like /dev/null redirected in)
  457. * can't be set to non-blocking */
  458. TRACE(("ignoring ENODEV for setnonblocking"))
  459. } else {
  460. dropbear_exit("Couldn't set nonblocking");
  461. }
  462. }
  463. TRACE(("leave setnonblocking"))
  464. }
  465. void disallow_core() {
  466. struct rlimit lim;
  467. lim.rlim_cur = lim.rlim_max = 0;
  468. setrlimit(RLIMIT_CORE, &lim);
  469. }
  470. /* Returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE, with the result in *val */
  471. int m_str_to_uint(const char* str, unsigned int *val) {
  472. unsigned long l;
  473. errno = 0;
  474. l = strtoul(str, NULL, 10);
  475. /* The c99 spec doesn't actually seem to define EINVAL, but most platforms
  476. * I've looked at mention it in their manpage */
  477. if ((l == 0 && errno == EINVAL)
  478. || (l == ULONG_MAX && errno == ERANGE)
  479. || (l > UINT_MAX)) {
  480. return DROPBEAR_FAILURE;
  481. } else {
  482. *val = l;
  483. return DROPBEAR_SUCCESS;
  484. }
  485. }
  486. /* Returns malloced path. inpath beginning with '/' is returned as-is,
  487. otherwise home directory is prepended */
  488. char * expand_homedir_path(const char *inpath) {
  489. struct passwd *pw = NULL;
  490. if (inpath[0] != '/') {
  491. pw = getpwuid(getuid());
  492. if (pw && pw->pw_dir) {
  493. int len = strlen(inpath) + strlen(pw->pw_dir) + 2;
  494. char *buf = m_malloc(len);
  495. snprintf(buf, len, "%s/%s", pw->pw_dir, inpath);
  496. return buf;
  497. }
  498. }
  499. /* Fallback */
  500. return m_strdup(inpath);
  501. }
  502. int constant_time_memcmp(const void* a, const void *b, size_t n)
  503. {
  504. const char *xa = a, *xb = b;
  505. uint8_t c = 0;
  506. size_t i;
  507. for (i = 0; i < n; i++)
  508. {
  509. c |= (xa[i] ^ xb[i]);
  510. }
  511. return c;
  512. }
  513. #if defined(__linux__) && defined(SYS_clock_gettime)
  514. /* CLOCK_MONOTONIC_COARSE was added in Linux 2.6.32 but took a while to
  515. reach userspace include headers */
  516. #ifndef CLOCK_MONOTONIC_COARSE
  517. #define CLOCK_MONOTONIC_COARSE 6
  518. #endif
  519. static clockid_t get_linux_clock_source() {
  520. struct timespec ts;
  521. if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC_COARSE, &ts) == 0) {
  522. return CLOCK_MONOTONIC_COARSE;
  523. }
  524. if (syscall(SYS_clock_gettime, CLOCK_MONOTONIC, &ts) == 0) {
  525. return CLOCK_MONOTONIC;
  526. }
  527. return -1;
  528. }
  529. #endif
  530. time_t monotonic_now() {
  531. #if defined(__linux__) && defined(SYS_clock_gettime)
  532. static clockid_t clock_source = -2;
  533. if (clock_source == -2) {
  534. /* First run, find out which one works.
  535. -1 will fall back to time() */
  536. clock_source = get_linux_clock_source();
  537. }
  538. if (clock_source >= 0) {
  539. struct timespec ts;
  540. if (syscall(SYS_clock_gettime, clock_source, &ts) != 0) {
  541. /* Intermittent clock failures should not happen */
  542. dropbear_exit("Clock broke");
  543. }
  544. return ts.tv_sec;
  545. }
  546. #endif /* linux clock_gettime */
  547. #if defined(HAVE_MACH_ABSOLUTE_TIME)
  548. /* OS X, see https://developer.apple.com/library/mac/qa/qa1398/_index.html */
  549. static mach_timebase_info_data_t timebase_info;
  550. if (timebase_info.denom == 0) {
  551. mach_timebase_info(&timebase_info);
  552. }
  553. return mach_absolute_time() * timebase_info.numer / timebase_info.denom
  554. / 1e9;
  555. #endif /* osx mach_absolute_time */
  556. /* Fallback for everything else - this will sometimes go backwards */
  557. return time(NULL);
  558. }
  559. void fsync_parent_dir(const char* fn) {
  560. #ifdef HAVE_LIBGEN_H
  561. char *fn_dir = m_strdup(fn);
  562. char *dir = dirname(fn_dir);
  563. int dirfd = open(dir, O_RDONLY);
  564. if (dirfd != -1) {
  565. if (fsync(dirfd) != 0) {
  566. TRACE(("fsync of directory %s failed: %s", dir, strerror(errno)))
  567. }
  568. m_close(dirfd);
  569. } else {
  570. TRACE(("error opening directory %s for fsync: %s", dir, strerror(errno)))
  571. }
  572. free(fn_dir);
  573. #endif
  574. }