logo

utils-std

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

sha256sum.c (6155B)


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