logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/

sha512sum.c (5735B)


  1. // utils-std: Collection of commonly available Unix tools
  2. // SPDX-FileCopyrightText: 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
  3. // SPDX-License-Identifier: MPL-2.0
  4. #define _POSIX_C_SOURCE 200809L
  5. #include "../lib/sha512.h" // sha512_*
  6. #include "../lib/strconv.h" // bytes2hex
  7. #include <ctype.h> // isxdigit
  8. #include <errno.h>
  9. #include <fcntl.h> // open, O_*
  10. #include <stdbool.h>
  11. #include <stdio.h> // fprintf
  12. #include <stdlib.h> // free
  13. #include <string.h> // strerror
  14. #include <unistd.h> // read, write, close, getopt
  15. #define SHA512SUM_LEN SHA512_DIGEST_LENGTH * 2 + 1
  16. const char *argv0 = "sha512sum";
  17. static int
  18. sha512sum(int fd, const char *fdname, char sum[SHA512SUM_LEN])
  19. {
  20. struct sha512 ctx;
  21. sha512_init(&ctx);
  22. uint8_t buf[BUFSIZ];
  23. ssize_t nread = -1;
  24. while((nread = read(fd, buf, BUFSIZ)) > 0)
  25. {
  26. sha512_update(&ctx, buf, nread);
  27. }
  28. if(nread < 0)
  29. {
  30. fprintf(stderr,
  31. "%s: error: Failed reading file '%s': %s\n",
  32. argv0,
  33. fdname ? fdname : "<stdin>",
  34. strerror(errno));
  35. return -1;
  36. }
  37. uint8_t res[SHA512_DIGEST_LENGTH] = "";
  38. sha512_sum(&ctx, res);
  39. bytes2hex(res, SHA512_DIGEST_LENGTH, sum, SHA512SUM_LEN);
  40. return 0;
  41. }
  42. #define STR(s) #s
  43. #define XSTR(s) STR(s)
  44. static int
  45. check(FILE *file, const char *filename)
  46. {
  47. int err = 0;
  48. ssize_t nread = -1;
  49. char *line = NULL;
  50. size_t len = 0;
  51. errno = 0;
  52. while((nread = getline(&line, &len, file)) > 0)
  53. {
  54. if(line[nread - 1] == '\n') line[nread - 1] = '\0';
  55. ssize_t i = 0;
  56. for(; i < nread; i++)
  57. {
  58. if(isxdigit(line[i])) continue;
  59. if(line[i] == ' ')
  60. {
  61. line[i] = '\0';
  62. break;
  63. }
  64. fprintf(stderr,
  65. "%s: error: Invalid character '%c' while reading hash in line: %s\n",
  66. argv0,
  67. line[i],
  68. line);
  69. if(len > 0) free(line);
  70. return -1;
  71. }
  72. if(line[i++] != '\0')
  73. {
  74. fprintf(stderr, "%s: error: Invalid line: %s\n", argv0, line);
  75. if(len > 0) free(line);
  76. return -1;
  77. }
  78. if(i != SHA512SUM_LEN)
  79. {
  80. fprintf(stderr,
  81. "%s: error: Got %zd hexadecimal digits while expected %d for a SHA512\n",
  82. argv0,
  83. i,
  84. SHA512SUM_LEN);
  85. if(len > 0) free(line);
  86. return -1;
  87. }
  88. while(i < nread && line[i] == ' ')
  89. i++;
  90. if(i < nread && line[i] == '*') i++;
  91. char *target = line + i;
  92. int fd = open(target, O_RDONLY | O_NOCTTY);
  93. if(fd < 0)
  94. {
  95. fprintf(stderr, "%s: error: Failed opening file '%s': %s\n", argv0, target, strerror(errno));
  96. if(len > 0) free(line);
  97. return -1;
  98. }
  99. int ret = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
  100. if(ret != 0)
  101. fprintf(stderr,
  102. "%s: warning: posix_fadvise failed on file '%s': %s\n",
  103. argv0,
  104. target,
  105. strerror(ret));
  106. char got[SHA512SUM_LEN] = "";
  107. if(sha512sum(fd, target, got) < 0) err = 1;
  108. if(memcmp(line, got, SHA512SUM_LEN) == 0)
  109. {
  110. printf("%s: OK\n", target);
  111. }
  112. else
  113. {
  114. err = 1;
  115. printf("%s: FAILED\n", target);
  116. }
  117. if(close(fd) < 0)
  118. {
  119. fprintf(
  120. stderr, "%s: error: Failed closing file '%s': %s\n", argv0, filename, strerror(errno));
  121. if(len > 0) free(line);
  122. return -1;
  123. }
  124. }
  125. if(nread < 0 && errno != 0)
  126. {
  127. err = 1;
  128. fprintf(stderr,
  129. "%s: error: Failed reading line from file '%s': %s\n",
  130. argv0,
  131. filename,
  132. strerror(errno));
  133. }
  134. if(len > 0) free(line);
  135. return err;
  136. }
  137. int
  138. main(int argc, char *argv[])
  139. {
  140. bool opt_c = false;
  141. for(int c = -1; (c = getopt(argc, argv, ":c")) != -1;)
  142. {
  143. switch(c)
  144. {
  145. case 'c':
  146. opt_c = true;
  147. break;
  148. case ':':
  149. fprintf(stderr, "%s: error: Missing operand for option: '-%c'\n", argv0, optopt);
  150. return 1;
  151. case '?':
  152. fprintf(stderr, "%s: error: Unrecognised option: '-%c'\n", argv0, optopt);
  153. return 1;
  154. default:
  155. abort();
  156. }
  157. }
  158. argc -= optind;
  159. argv += optind;
  160. if(opt_c)
  161. {
  162. if(argc == 0)
  163. {
  164. if(check(stdin, "<stdin>") != 0) return 1;
  165. return 0;
  166. }
  167. int err = 0;
  168. for(int i = 0; i < argc; i++)
  169. {
  170. FILE *file = NULL;
  171. const char *filename = argv[i];
  172. if(filename[0] == '-' && filename[1] == '\0')
  173. {
  174. filename = "<stdin>";
  175. file = stdin;
  176. }
  177. else
  178. {
  179. file = fopen(filename, "rb");
  180. if(file == NULL)
  181. {
  182. fprintf(stderr,
  183. "%s: error: Failed opening file '%s': %s\n",
  184. argv0,
  185. filename,
  186. strerror(errno));
  187. return 1;
  188. }
  189. }
  190. if(check(file, filename) != 0) err = 1;
  191. if(fclose(file) < 0)
  192. {
  193. fprintf(
  194. stderr, "%s: error: Failed closing file '%s': %s\n", argv0, filename, strerror(errno));
  195. return 1;
  196. }
  197. }
  198. return err;
  199. }
  200. if(argc == 0)
  201. {
  202. char sum[SHA512SUM_LEN] = "";
  203. if(sha512sum(STDIN_FILENO, NULL, sum) < 0) return 1;
  204. puts(sum);
  205. return 0;
  206. }
  207. for(int i = 0; i < argc; i++)
  208. {
  209. int fd = -1;
  210. const char *filename = argv[i];
  211. if(filename[0] == '-' && filename[1] == '\0')
  212. {
  213. filename = "<stdin>";
  214. fd = STDIN_FILENO;
  215. }
  216. else
  217. {
  218. fd = open(filename, O_RDONLY | O_NOCTTY);
  219. if(fd < 0)
  220. {
  221. fprintf(
  222. stderr, "%s: error: Failed opening file '%s': %s\n", argv0, filename, strerror(errno));
  223. return 1;
  224. }
  225. int ret = posix_fadvise(fd, 0, 0, POSIX_FADV_SEQUENTIAL);
  226. if(ret != 0)
  227. fprintf(stderr,
  228. "%s: warning: posix_fadvise failed on file '%s': %s\n",
  229. argv0,
  230. filename,
  231. strerror(ret));
  232. }
  233. int err = 0;
  234. char sum[SHA512SUM_LEN] = "";
  235. if(sha512sum(fd, filename, sum) < 0) err = 1;
  236. printf("%s %s\n", sum, filename);
  237. if(close(fd) < 0)
  238. {
  239. fprintf(
  240. stderr, "%s: error: Failed closing file '%s': %s\n", argv0, filename, strerror(errno));
  241. return 1;
  242. }
  243. if(err == 1) return 1;
  244. }
  245. return 0;
  246. }