platform.linux.cpp 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * Copyright 2005 - 2016 Zarafa and its licensors
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU Affero General Public License, version 3,
  6. * as published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU Affero General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Affero General Public License
  14. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. *
  16. */
  17. #include <kopano/zcdefs.h>
  18. #include <kopano/platform.h>
  19. #include <kopano/ECLogger.h>
  20. #include <sys/select.h>
  21. #include <sys/time.h>
  22. #include <iconv.h>
  23. #include <cstring>
  24. #include <cstdio>
  25. #include <cctype>
  26. #include <ctime>
  27. #include <dirent.h>
  28. #include <mapicode.h> // return codes
  29. #include <unistd.h>
  30. #include <sys/stat.h>
  31. #include <sys/types.h>
  32. #include <fcntl.h>
  33. #include <cstdlib>
  34. #include <cerrno>
  35. #include <climits>
  36. #include <string>
  37. #include <map>
  38. #include <vector>
  39. #ifndef HAVE_UUID_CREATE
  40. # include <uuid/uuid.h>
  41. #else
  42. # include <uuid.h>
  43. #endif
  44. #if defined(__linux__) && defined(__GLIBC__)
  45. # include <cxxabi.h>
  46. # include <execinfo.h>
  47. #endif
  48. #include "TmpPath.h"
  49. #ifdef __APPLE__
  50. // bsd
  51. #define ICONV_CONST const
  52. #elif OPENBSD
  53. // bsd
  54. #define ICONV_CONST const
  55. #else
  56. // linux
  57. #define ICONV_CONST
  58. #endif
  59. static bool rand_init_done = false;
  60. bool operator!=(const GUID &a, const GUID &b)
  61. {
  62. return memcmp(&a, &b, sizeof(GUID)) != 0;
  63. }
  64. bool operator==(REFIID a, const GUID &b)
  65. {
  66. return memcmp(&a, &b, sizeof(GUID)) == 0;
  67. }
  68. HRESULT CoCreateGuid(LPGUID pNewGUID) {
  69. if (!pNewGUID)
  70. return MAPI_E_INVALID_PARAMETER;
  71. #if HAVE_UUID_CREATE
  72. #ifdef OPENBSD
  73. uuid_t *g = NULL;
  74. void *vp = NULL;
  75. size_t n = 0;
  76. // error codes are not checked!
  77. uuid_create(&g);
  78. uuid_make(g, UUID_MAKE_V1);
  79. uuid_export(g, UUID_FMT_BIN, &vp, &n);
  80. memcpy(pNewGUID, &vp, UUID_LEN_BIN);
  81. uuid_destroy(g);
  82. #else
  83. uuid_t g;
  84. uint32_t uid_ret;
  85. uuid_create(&g, &uid_ret);
  86. memcpy(pNewGUID, &g, sizeof(g));
  87. #endif // OPENBSD
  88. #else
  89. uuid_t g;
  90. uuid_generate(g);
  91. memcpy(pNewGUID, g, sizeof(g));
  92. #endif
  93. return S_OK;
  94. }
  95. void GetSystemTimeAsFileTime(FILETIME *ft) {
  96. struct timeval now;
  97. __int64_t l;
  98. gettimeofday(&now,NULL); // null==timezone
  99. l = ((__int64_t)now.tv_sec * 10000000) + ((__int64_t)now.tv_usec * 10) + (__int64_t)NANOSECS_BETWEEN_EPOCHS;
  100. ft->dwLowDateTime = (unsigned int)(l & 0xffffffff);
  101. ft->dwHighDateTime = l >> 32;
  102. }
  103. /**
  104. * copies the path of the temp directory, including trailing /, into
  105. * given buffer.
  106. *
  107. * @param[in] inLen size of buffer, inclusive \0 char
  108. * @param[in,out] lpBuffer buffer to place path in
  109. *
  110. * @return length used or what would've been required if it would fit in lpBuffer
  111. */
  112. DWORD GetTempPath(DWORD inLen, char *lpBuffer) {
  113. unsigned int outLen = snprintf(lpBuffer, inLen, "%s/", TmpPath::getInstance() -> getTempPath().c_str());
  114. if (outLen > inLen)
  115. return 0;
  116. return outLen;
  117. }
  118. void Sleep(unsigned int msec) {
  119. struct timespec ts;
  120. unsigned int rsec;
  121. ts.tv_sec = msec/1000;
  122. rsec = msec - (ts.tv_sec*1000);
  123. ts.tv_nsec = rsec*1000*1000;
  124. nanosleep(&ts, NULL);
  125. }
  126. namespace KC {
  127. static void rand_fail(void)
  128. {
  129. fprintf(stderr, "Cannot access/use /dev/urandom, this is fatal (%s)\n", strerror(errno));
  130. kill(0, SIGTERM);
  131. exit(1);
  132. }
  133. void rand_get(char *p, int n)
  134. {
  135. int fd = open("/dev/urandom", O_RDONLY);
  136. if (fd == -1)
  137. rand_fail();
  138. // handle EINTR
  139. while(n > 0)
  140. {
  141. int rc = read(fd, p, n);
  142. if (rc == 0)
  143. rand_fail();
  144. if (rc == -1)
  145. {
  146. if (errno == EINTR)
  147. continue;
  148. rand_fail();
  149. }
  150. p += rc;
  151. n -= rc;
  152. }
  153. close(fd);
  154. }
  155. void rand_init() {
  156. unsigned int seed = 0;
  157. rand_get((char *)&seed, sizeof(seed));
  158. srand(seed);
  159. rand_init_done = true;
  160. }
  161. int rand_mt() {
  162. int dummy = 0;
  163. rand_get((char *)&dummy, sizeof dummy);
  164. if (dummy == INT_MIN)
  165. dummy = INT_MAX;
  166. else
  167. dummy = abs(dummy);
  168. // this gives a slighly bias to the value 0
  169. // also RAND_MAX is never returned which the
  170. // regular rand() does do
  171. return dummy % RAND_MAX;
  172. }
  173. void rand_free() {
  174. //Nothing to free
  175. }
  176. char * get_password(const char *prompt) {
  177. return getpass(prompt);
  178. }
  179. } /* namespace */
  180. HGLOBAL GlobalAlloc(UINT uFlags, ULONG ulSize)
  181. {
  182. // always returns NULL, as required by CreateStreamOnHGlobal implementation in mapi4linux/src/mapiutil.cpp
  183. return NULL;
  184. }
  185. namespace KC {
  186. time_t GetProcessTime()
  187. {
  188. time_t t;
  189. time(&t);
  190. return t;
  191. }
  192. std::vector<std::string> get_backtrace(void)
  193. {
  194. #define BT_MAX 256
  195. std::vector<std::string> result;
  196. void *addrlist[BT_MAX];
  197. int addrlen = backtrace(addrlist, BT_MAX);
  198. if (addrlen == 0)
  199. return result;
  200. char **symbollist = backtrace_symbols(addrlist, addrlen);
  201. for (int i = 0; i < addrlen; ++i)
  202. result.push_back(symbollist[i]);
  203. free(symbollist);
  204. return result;
  205. #undef BT_MAX
  206. }
  207. static void dump_fdtable_summary(pid_t pid)
  208. {
  209. char procdir[64];
  210. snprintf(procdir, sizeof(procdir), "/proc/%ld/fd", static_cast<long>(pid));
  211. DIR *dh = opendir(procdir);
  212. if (dh == NULL)
  213. return;
  214. std::string msg;
  215. struct dirent *de;
  216. while ((de = readdir(dh)) != nullptr) {
  217. if (de->d_type != DT_LNK)
  218. continue;
  219. std::string de_name(std::string(procdir) + "/" + de->d_name);
  220. struct stat sb;
  221. if (stat(de_name.c_str(), &sb) < 0) {
  222. msg += " ?";
  223. } else switch (sb.st_mode & S_IFMT) {
  224. case S_IFREG: msg += " ."; break;
  225. case S_IFSOCK: msg += " s"; break;
  226. case S_IFDIR: msg += " d"; break;
  227. case S_IFIFO: msg += " p"; break;
  228. case S_IFCHR: msg += " c"; break;
  229. default: msg += " O"; break;
  230. }
  231. msg += de->d_name;
  232. }
  233. closedir(dh);
  234. ec_log_debug("FD map:%s", msg.c_str());
  235. }
  236. /* ALERT! Big hack!
  237. *
  238. * This function relocates an open file descriptor to a new file descriptor above 1024. The
  239. * reason we do this is because, although we support many open FDs up to FD_SETSIZE, libraries
  240. * that we use may not (most notably libldap). This means that if a new socket is allocated within
  241. * libldap as socket 1025, libldap will fail because it was compiled with FD_SETSIZE=1024. To fix
  242. * this problem, we make sure that most FDs under 1024 are free for use by external libraries, while
  243. * we use the range 1024 -> \infty.
  244. */
  245. int ec_relocate_fd(int fd)
  246. {
  247. static constexpr const int typical_limit = 1024;
  248. if (fd >= typical_limit)
  249. /* No action needed */
  250. return fd;
  251. int relocated = fcntl(fd, F_DUPFD, typical_limit);
  252. if (relocated >= 0) {
  253. close(fd);
  254. return relocated;
  255. }
  256. if (errno == EINVAL) {
  257. /*
  258. * The range start (typical_limit) was already >=RLIMIT_NOFILE.
  259. * Just stay silent.
  260. */
  261. static bool warned_once;
  262. if (warned_once)
  263. return fd;
  264. warned_once = true;
  265. ec_log_warn("F_DUPFD yielded EINVAL\n");
  266. return fd;
  267. }
  268. static time_t warned_last;
  269. time_t now = time(NULL);
  270. if (warned_last + 60 > now)
  271. return fd;
  272. ec_log_notice(
  273. "Relocation of FD %d into high range (%d+) could not be completed: "
  274. "%s. Keeping old number.\n", fd, typical_limit, strerror(errno));
  275. dump_fdtable_summary(getpid());
  276. return fd;
  277. }
  278. } /* namespace */