A clone of btpd with my configuration changes.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

287 lines
5.3 KiB

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <errno.h>
  4. #include <fcntl.h>
  5. #include <inttypes.h>
  6. #include <limits.h>
  7. #include <math.h>
  8. #include <pwd.h>
  9. #include <stdarg.h>
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <unistd.h>
  14. void
  15. set_bit(uint8_t *bits, unsigned long index)
  16. {
  17. bits[index / 8] |= (1 << (7 - index % 8));
  18. }
  19. void
  20. clear_bit(uint8_t *bits, unsigned long index)
  21. {
  22. bits[index / 8] &= ~(1 << (7 - index % 8));
  23. }
  24. int
  25. has_bit(const uint8_t *bits, unsigned long index)
  26. {
  27. return bits[index / 8] & (1 << (7 - index % 8));
  28. }
  29. uint8_t
  30. hex2i(char c)
  31. {
  32. if (c >= '0' && c <= '9')
  33. return c - '0';
  34. else if (c >= 'a' && c <= 'f')
  35. return 10 + c - 'a';
  36. else
  37. abort();
  38. }
  39. int
  40. ishex(char *str)
  41. {
  42. while (*str != '\0') {
  43. if (!((*str >= '0' && *str <= '9') || (*str >= 'a' && *str <= 'f')))
  44. return 0;
  45. str++;
  46. }
  47. return 1;
  48. }
  49. uint8_t *
  50. hex2bin(const char *hex, uint8_t *bin, size_t bsize)
  51. {
  52. for (size_t i = 0; i < bsize; i++)
  53. bin[i] = hex2i(hex[i * 2]) << 4 | hex2i(hex[i * 2 + 1]);
  54. return bin;
  55. }
  56. char *
  57. bin2hex(const uint8_t *bin, char *hex, size_t bsize)
  58. {
  59. size_t i;
  60. const char *hexc = "0123456789abcdef";
  61. for (i = 0; i < bsize; i++) {
  62. hex[i * 2] = hexc[(bin[i] >> 4) & 0xf];
  63. hex[i * 2 + 1] = hexc[bin[i] &0xf];
  64. }
  65. hex[i * 2] = '\0';
  66. return hex;
  67. }
  68. int
  69. set_nonblocking(int fd)
  70. {
  71. int oflags;
  72. if ((oflags = fcntl(fd, F_GETFL, 0)) == -1)
  73. return errno;
  74. if (fcntl(fd, F_SETFL, oflags | O_NONBLOCK) == -1)
  75. return errno;
  76. return 0;
  77. }
  78. int
  79. set_blocking(int fd)
  80. {
  81. int oflags;
  82. if ((oflags = fcntl(fd, F_GETFL, 0)) == -1)
  83. return errno;
  84. if (fcntl(fd, F_SETFL, oflags & ~O_NONBLOCK) == -1)
  85. return errno;
  86. return 0;
  87. }
  88. int
  89. mkdirs(char *path)
  90. {
  91. int err = 0;
  92. char *spos = strchr(path + 1, '/'); // Must ignore the root
  93. while (spos != NULL) {
  94. *spos = '\0';
  95. err = mkdir(path, 0777);
  96. *spos = '/';
  97. if (err != 0 && errno != EEXIST) {
  98. err = errno;
  99. break;
  100. }
  101. spos = strchr(spos + 1, '/');
  102. }
  103. return err;
  104. }
  105. int
  106. vaopen(int *res, int flags, const char *fmt, va_list ap)
  107. {
  108. int fd, didmkdirs;
  109. char path[PATH_MAX + 1];
  110. if (vsnprintf(path, PATH_MAX, fmt, ap) >= PATH_MAX)
  111. return ENAMETOOLONG;
  112. didmkdirs = 0;
  113. again:
  114. fd = open(path, flags, 0666);
  115. if (fd < 0 && errno == ENOENT && (flags & O_CREAT) != 0 && !didmkdirs) {
  116. if (mkdirs(path) == 0) {
  117. didmkdirs = 1;
  118. goto again;
  119. } else
  120. return errno;
  121. }
  122. if (fd >= 0) {
  123. *res = fd;
  124. return 0;
  125. } else
  126. return errno;
  127. }
  128. int
  129. vopen(int *res, int flags, const char *fmt, ...)
  130. {
  131. int err;
  132. va_list ap;
  133. va_start(ap, fmt);
  134. err = vaopen(res, flags, fmt, ap);
  135. va_end(ap);
  136. return err;
  137. }
  138. int
  139. vfsync(const char *fmt, ...)
  140. {
  141. int err, fd;
  142. va_list ap;
  143. va_start(ap, fmt);
  144. err = vaopen(&fd, O_RDONLY, fmt, ap);
  145. va_end(ap);
  146. if (err != 0)
  147. return err;
  148. if (fsync(fd) < 0)
  149. err = errno;
  150. close(fd);
  151. return err;
  152. }
  153. int
  154. vfopen(FILE **ret, const char *mode, const char *fmt, ...)
  155. {
  156. int err = 0;
  157. char path[PATH_MAX + 1];
  158. va_list ap;
  159. va_start(ap, fmt);
  160. if (vsnprintf(path, PATH_MAX, fmt, ap) >= PATH_MAX)
  161. err = ENAMETOOLONG;
  162. va_end(ap);
  163. if (err == 0)
  164. if ((*ret = fopen(path, mode)) == NULL)
  165. err = errno;
  166. return err;
  167. }
  168. long
  169. rand_between(long min, long max)
  170. {
  171. return min + (long)rint((double)random() * (max - min) / RAND_MAX);
  172. }
  173. int
  174. write_fully(int fd, const void *buf, size_t len)
  175. {
  176. ssize_t nw;
  177. size_t off = 0;
  178. while (off < len) {
  179. nw = write(fd, buf + off, len - off);
  180. if (nw == -1)
  181. return errno;
  182. off += nw;
  183. }
  184. return 0;
  185. }
  186. int
  187. read_fully(int fd, void *buf, size_t len)
  188. {
  189. ssize_t nread;
  190. size_t off = 0;
  191. while (off < len) {
  192. nread = read(fd, buf + off, len - off);
  193. if (nread == 0)
  194. return EIO;
  195. else if (nread == -1)
  196. return errno;
  197. off += nread;
  198. }
  199. return 0;
  200. }
  201. int
  202. read_whole_file(void **out, size_t *size, const char *fmt, ...)
  203. {
  204. int err, fd;
  205. int didmalloc = 0;
  206. struct stat sb;
  207. va_list ap;
  208. va_start(ap, fmt);
  209. err = vaopen(&fd, O_RDONLY, fmt, ap);
  210. va_end(ap);
  211. if (err != 0)
  212. return err;
  213. if (fstat(fd, &sb) != 0) {
  214. err = errno;
  215. goto error;
  216. }
  217. if (*size != 0 && *size < sb.st_size) {
  218. err = EFBIG;
  219. goto error;
  220. }
  221. *size = sb.st_size;
  222. if (*out == NULL) {
  223. if ((*out = malloc(*size)) == NULL) {
  224. err = errno;
  225. goto error;
  226. }
  227. didmalloc = 1;
  228. }
  229. if ((err = read_fully(fd, *out, *size)) != 0)
  230. goto error;
  231. close(fd);
  232. return 0;
  233. error:
  234. if (didmalloc)
  235. free(*out);
  236. close(fd);
  237. return err;
  238. }
  239. char *
  240. find_btpd_dir(void)
  241. {
  242. char *res = getenv("BTPD_HOME");
  243. if (res != NULL)
  244. return strdup(res);
  245. char *home = getenv("HOME");
  246. if (home == NULL) {
  247. struct passwd *pwent = getpwuid(getuid());
  248. endpwent();
  249. if (pwent != NULL)
  250. home = pwent->pw_dir;
  251. }
  252. if (home != NULL)
  253. asprintf(&res, "%s/.btpd", home);
  254. return res;
  255. }