cgpt_nor.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264
  1. /* Copyright 2015 The Chromium OS Authors. All rights reserved.
  2. * Use of this source code is governed by a BSD-style license that can be
  3. * found in the LICENSE file.
  4. */
  5. #include <err.h>
  6. #include <errno.h>
  7. #include <fcntl.h>
  8. #include <ftw.h>
  9. #include <inttypes.h>
  10. #include <linux/major.h>
  11. #include <stdbool.h>
  12. #include <stdarg.h>
  13. #include <stdlib.h>
  14. #include <stdint.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <sys/stat.h>
  18. #include <sys/types.h>
  19. #include <sys/wait.h>
  20. #include <unistd.h>
  21. #include "cgpt.h"
  22. #include "cgpt_nor.h"
  23. static const char FLASHROM_PATH[] = "/usr/sbin/flashrom";
  24. // Obtain the MTD size from its sysfs node.
  25. int GetMtdSize(const char *mtd_device, uint64_t *size) {
  26. mtd_device = strrchr(mtd_device, '/');
  27. if (mtd_device == NULL) {
  28. errno = EINVAL;
  29. return 1;
  30. }
  31. char *sysfs_name;
  32. if (asprintf(&sysfs_name, "/sys/class/mtd%s/size", mtd_device) == -1) {
  33. return 1;
  34. }
  35. FILE *fp = fopen(sysfs_name, "r");
  36. free(sysfs_name);
  37. if (fp == NULL) {
  38. return 1;
  39. }
  40. int ret = (fscanf(fp, "%" PRIu64 "\n", size) != 1);
  41. fclose(fp);
  42. return ret;
  43. }
  44. int ForkExecV(const char *cwd, const char *const argv[]) {
  45. pid_t pid = fork();
  46. if (pid == -1) {
  47. return -1;
  48. }
  49. int status = -1;
  50. if (pid == 0) {
  51. if (cwd && chdir(cwd) != 0) {
  52. return -1;
  53. }
  54. execv(argv[0], (char *const *)argv);
  55. // If this is reached, execv fails.
  56. err(-1, "Cannot exec %s in %s.", argv[0], cwd);
  57. } else {
  58. if (waitpid(pid, &status, 0) != -1 && WIFEXITED(status))
  59. return WEXITSTATUS(status);
  60. }
  61. return status;
  62. }
  63. int ForkExecL(const char *cwd, const char *cmd, ...) {
  64. int argc;
  65. va_list ap;
  66. va_start(ap, cmd);
  67. for (argc = 1; va_arg(ap, char *) != NULL; ++argc);
  68. va_end(ap);
  69. va_start(ap, cmd);
  70. const char **argv = calloc(argc + 1, sizeof(char *));
  71. if (argv == NULL) {
  72. errno = ENOMEM;
  73. va_end(ap);
  74. return -1;
  75. }
  76. argv[0] = cmd;
  77. int i;
  78. for (i = 1; i < argc; ++i) {
  79. argv[i] = va_arg(ap, char *);
  80. }
  81. va_end(ap);
  82. int ret = ForkExecV(cwd, argv);
  83. free(argv);
  84. return ret;
  85. }
  86. static int read_write(int source_fd,
  87. uint64_t size,
  88. const char *src_name,
  89. int idx) {
  90. int ret = 1;
  91. const int bufsize = 4096;
  92. char *buf = malloc(bufsize);
  93. if (buf == NULL) {
  94. goto clean_exit;
  95. }
  96. ret++;
  97. char *dest;
  98. if (asprintf(&dest, "%s_%d", src_name, idx) == -1) {
  99. goto free_buf;
  100. }
  101. ret++;
  102. int dest_fd = open(dest, O_WRONLY | O_CLOEXEC | O_CREAT, 0600);
  103. if (dest_fd < 0) {
  104. goto free_dest;
  105. }
  106. ret++;
  107. uint64_t copied = 0;
  108. ssize_t nr_read;
  109. ssize_t nr_write;
  110. while (copied < size) {
  111. size_t to_read = size - copied;
  112. if (to_read > bufsize) {
  113. to_read = bufsize;
  114. }
  115. nr_read = read(source_fd, buf, to_read);
  116. if (nr_read < 0) {
  117. goto close_dest_fd;
  118. }
  119. nr_write = 0;
  120. while (nr_write < nr_read) {
  121. ssize_t s = write(dest_fd, buf + nr_write, nr_read - nr_write);
  122. if (s < 0) {
  123. goto close_dest_fd;
  124. }
  125. nr_write += s;
  126. }
  127. copied += nr_read;
  128. }
  129. ret = 0;
  130. close_dest_fd:
  131. close(dest_fd);
  132. free_dest:
  133. free(dest);
  134. free_buf:
  135. free(buf);
  136. clean_exit:
  137. return ret;
  138. }
  139. static int split_gpt(const char *dir_name, const char *file_name) {
  140. int ret = 1;
  141. char *source;
  142. if (asprintf(&source, "%s/%s", dir_name, file_name) == -1) {
  143. goto clean_exit;
  144. }
  145. ret++;
  146. int fd = open(source, O_RDONLY | O_CLOEXEC);
  147. if (fd < 0) {
  148. goto free_source;
  149. }
  150. ret++;
  151. struct stat stat;
  152. if (fstat(fd, &stat) != 0 || (stat.st_size & 1) != 0) {
  153. goto close_fd;
  154. }
  155. uint64_t half_size = stat.st_size / 2;
  156. ret++;
  157. if (read_write(fd, half_size, source, 1) != 0 ||
  158. read_write(fd, half_size, source, 2) != 0) {
  159. goto close_fd;
  160. }
  161. ret = 0;
  162. close_fd:
  163. close(fd);
  164. free_source:
  165. free(source);
  166. clean_exit:
  167. return ret;
  168. }
  169. static int remove_file_or_dir(const char *fpath, const struct stat *sb,
  170. int typeflag, struct FTW *ftwbuf) {
  171. return remove(fpath);
  172. }
  173. int RemoveDir(const char *dir) {
  174. return nftw(dir, remove_file_or_dir, 20, FTW_DEPTH | FTW_PHYS);
  175. }
  176. // Read RW_GPT from NOR flash to "rw_gpt" in a temp dir |temp_dir_template|.
  177. // |temp_dir_template| is passed to mkdtemp() so it must satisfy all
  178. // requirements by mkdtemp.
  179. int ReadNorFlash(char *temp_dir_template) {
  180. int ret = 0;
  181. // Create a temp dir to work in.
  182. ret++;
  183. if (mkdtemp(temp_dir_template) == NULL) {
  184. Error("Cannot create a temporary directory.\n");
  185. return ret;
  186. }
  187. // Read RW_GPT section from NOR flash to "rw_gpt".
  188. ret++;
  189. int fd_flags = fcntl(1, F_GETFD);
  190. // Close stdout on exec so that flashrom does not muck up cgpt's output.
  191. if (0 != fcntl(1, F_SETFD, FD_CLOEXEC))
  192. Warning("Can't stop flashrom from mucking up our output\n");
  193. if (ForkExecL(temp_dir_template, FLASHROM_PATH, "-i", "RW_GPT:rw_gpt", "-r",
  194. NULL) != 0) {
  195. Error("Cannot exec flashrom to read from RW_GPT section.\n");
  196. RemoveDir(temp_dir_template);
  197. } else {
  198. ret = 0;
  199. }
  200. // Restore stdout flags
  201. if (0 != fcntl(1, F_SETFD, fd_flags))
  202. Warning("Can't restore stdout flags\n");
  203. return ret;
  204. }
  205. // Write "rw_gpt" back to NOR flash. We write the file in two parts for safety.
  206. int WriteNorFlash(const char *dir) {
  207. int ret = 0;
  208. ret++;
  209. if (split_gpt(dir, "rw_gpt") != 0) {
  210. Error("Cannot split rw_gpt in two.\n");
  211. return ret;
  212. }
  213. ret++;
  214. int nr_fails = 0;
  215. int fd_flags = fcntl(1, F_GETFD);
  216. // Close stdout on exec so that flashrom does not muck up cgpt's output.
  217. if (0 != fcntl(1, F_SETFD, FD_CLOEXEC))
  218. Warning("Can't stop flashrom from mucking up our output\n");
  219. if (ForkExecL(dir, FLASHROM_PATH, "-i", "RW_GPT_PRIMARY:rw_gpt_1",
  220. "-w", "--fast-verify", NULL) != 0) {
  221. Warning("Cannot write the 1st half of rw_gpt back with flashrom.\n");
  222. nr_fails++;
  223. }
  224. if (ForkExecL(dir, FLASHROM_PATH, "-i", "RW_GPT_SECONDARY:rw_gpt_2",
  225. "-w", "--fast-verify", NULL) != 0) {
  226. Warning("Cannot write the 2nd half of rw_gpt back with flashrom.\n");
  227. nr_fails++;
  228. }
  229. if (0 != fcntl(1, F_SETFD, fd_flags))
  230. Warning("Can't restore stdout flags\n");
  231. switch (nr_fails) {
  232. case 0: ret = 0; break;
  233. case 1: Warning("It might still be okay.\n"); break;
  234. case 2: Error("Cannot write both parts back with flashrom.\n"); break;
  235. }
  236. return ret;
  237. }