/check_syscalls.c

https://bitbucket.org/gfcstanford/rockstar · C · 271 lines · 240 code · 29 blank · 2 comment · 57 complexity · 9c937ab297bbba9efa74320fa6509f8e MD5 · raw file

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <inttypes.h>
  5. #include <sys/socket.h>
  6. #include <sys/wait.h>
  7. #include <sys/mman.h>
  8. #include <sys/stat.h>
  9. #include <sys/errno.h>
  10. #include <unistd.h>
  11. #include <signal.h>
  12. #include "check_syscalls.h"
  13. #ifdef __linux__
  14. #include <malloc.h>
  15. #endif /* __linux__ */
  16. //#define DEBUG_IO
  17. char *unread = NULL;
  18. int64_t unread_size = 0;
  19. FILE *syscall_logfile = NULL;
  20. #define SL ((syscall_logfile) ? syscall_logfile : stderr)
  21. void system_error(char *errmsg) {
  22. fprintf(SL, "[Error] %s\n", errmsg);
  23. fprintf(SL, "[Error] Reason: %s\n", strerror(errno));
  24. exit(EXIT_FAILURE);
  25. }
  26. pid_t check_waitpid(pid_t pid) {
  27. int stat_loc;
  28. pid_t res;
  29. do {
  30. res = waitpid(pid, &stat_loc, 0);
  31. } while ((res < 0) && (errno == EINTR));
  32. if (res < 0) system_error("Waiting for child process failed.");
  33. return res;
  34. }
  35. FILE *check_fopen(char *filename, char *mode) {
  36. FILE *res = fopen(filename, mode);
  37. if (res == NULL) {
  38. if (mode[0] == 'w')
  39. fprintf(SL, "[Error] Failed to open file %s for writing!\n", filename);
  40. else if (mode[0] == 'a')
  41. fprintf(SL, "[Error] Failed to open file %s for appending!\n", filename);
  42. else
  43. fprintf(SL, "[Error] Failed to open file %s for reading!\n", filename);
  44. exit(EXIT_FAILURE);
  45. }
  46. #ifdef DEBUG_IO
  47. fprintf(SL, "[Note] Opened file %s with mode '%s' in fileno %d.\n",
  48. filename, mode, fileno(res));
  49. #endif /* DEBUG_IO */
  50. return res;
  51. }
  52. FILE *check_popen(char *command, char *mode) {
  53. FILE *res = popen(command, mode);
  54. if (res == NULL) {
  55. fprintf(SL, "[Error] Failed to start command %s!\n", command);
  56. exit(EXIT_FAILURE);
  57. }
  58. #ifdef DEBUG_IO
  59. fprintf(SL, "[Note] Opened command %s with mode '%s' in fileno %d.\n",
  60. command, mode, fileno(res));
  61. #endif /* DEBUG_IO */
  62. return res;
  63. }
  64. FILE *check_rw_socket(char *command, pid_t *pid) {
  65. int sockets[2], status;
  66. pid_t wres;
  67. FILE *res;
  68. if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets)<0)
  69. system_error("Failed to create socket pair!");
  70. *pid = fork();
  71. if (*pid < 0) system_error("Failed to fork new process!");
  72. if (!*pid) {
  73. if (dup2(sockets[1], 0) < 0) system_error("Failed to reopen stdin!");
  74. if (dup2(sockets[1], 1) < 0) system_error("Failed to reopen stdout!");
  75. close(sockets[0]);
  76. if (execlp("sh", "sh", "-c", command, NULL) < 0)
  77. system_error("Failed to exec command!");
  78. }
  79. close(sockets[1]);
  80. res = fdopen(sockets[0], "r+");
  81. if (!res) system_error("Failed to convert socket to stream!");
  82. do {
  83. wres = waitpid(*pid, &status, WNOHANG);
  84. } while ((wres < 0) && (errno == EINTR));
  85. if (wres < 0) {
  86. fprintf(SL, "[Error] Failed to start child process: %s\n", command);
  87. exit(EXIT_FAILURE);
  88. }
  89. #ifdef DEBUG_IO
  90. fprintf(SL, "[Note] Started command %s with mode 'r+' in fileno %d.\n",
  91. command, fileno(res));
  92. #endif /* DEBUG_IO */
  93. return res;
  94. }
  95. void check_lseek(int fd, off_t offset, int whence) {
  96. int64_t res = lseek(fd, offset, whence);
  97. if (res<0) {
  98. fprintf(SL, "[Error] Lseek error in fileno %d: ", fd);
  99. fprintf(SL, "[Error] Reason: %s\n", strerror(errno));
  100. exit(EXIT_FAILURE);
  101. }
  102. }
  103. void rw_socket_close(FILE *res, pid_t pid) {
  104. fclose(res);
  105. kill(pid, 9);
  106. check_waitpid(pid);
  107. }
  108. void *check_realloc(void *ptr, size_t size, char *reason) {
  109. if (size > 0) {
  110. void *res = realloc(ptr, size);
  111. if (res == NULL) {
  112. fprintf(SL, "[Error] Failed to allocate memory (%s)!\n", reason);
  113. exit(EXIT_FAILURE);
  114. }
  115. return res;
  116. }
  117. if (ptr != NULL) free(ptr);
  118. return(NULL);
  119. }
  120. void _io_err(int rw, size_t size, size_t nitems, FILE *stream) {
  121. char *verb = (rw) ? "write" : "read";
  122. char *dir = (rw) ? "to" : "from";
  123. char *items = (nitems == 1) ? "item" : "items";
  124. fprintf(SL, "[Error] Failed to %s %"PRIu64" %s of size "
  125. "%"PRIu64" bytes %s fileno %d!\n",
  126. verb, (uint64_t)nitems, items, (uint64_t)size, dir, fileno(stream));
  127. if (feof(stream))
  128. fprintf(SL, "[Error] Reason: end of file (offset %"PRIu64").\n",
  129. (uint64_t)ftello(stream));
  130. else
  131. fprintf(SL, "[Error] Reason: %s\n", strerror(errno));
  132. exit(EXIT_FAILURE);
  133. }
  134. void check_fseeko(FILE *stream, off_t offset, int whence) {
  135. if (fseeko(stream, offset, whence) < 0) {
  136. fprintf(SL, "[Error] Seek error in fileno %d: ", fileno(stream));
  137. fprintf(SL, "[Error] Reason: %s\n", strerror(errno));
  138. exit(EXIT_FAILURE);
  139. }
  140. }
  141. //Works even for pipes
  142. void check_fskip(FILE *stream, off_t offset, char *buffer, size_t buf_size) {
  143. int64_t n = 0;
  144. while (n<offset) {
  145. int64_t to_read = offset-n;
  146. if (buf_size < to_read) to_read = buf_size;
  147. n += check_fread(buffer, 1, to_read, stream);
  148. }
  149. }
  150. void check_limited_funread(void *ptr, size_t size, size_t nitems) {
  151. if (unread_size) {
  152. fprintf(SL, "[Error] Tried to unread twice in a row\n");
  153. exit(EXIT_FAILURE);
  154. }
  155. check_realloc_s(unread, size, nitems);
  156. unread_size = size*nitems;
  157. memcpy(unread, ptr, unread_size);
  158. }
  159. size_t check_fread(void *ptr, size_t size, size_t nitems, FILE *stream) {
  160. size_t res = 1, nread = 0;
  161. if (unread_size) {
  162. if (unread_size != (size*nitems)) {
  163. fprintf(SL, "[Error] funread must be followed by identical fread!\n");
  164. exit(EXIT_FAILURE);
  165. }
  166. memcpy(ptr, unread, unread_size);
  167. check_realloc_s(unread, 0, 0);
  168. unread_size = 0;
  169. return nitems;
  170. }
  171. while (nread < nitems) {
  172. res = fread(ptr, size, nitems-nread, stream);
  173. if (res <= 0) _io_err(0, size, nitems, stream);
  174. nread += res;
  175. ptr = ((char *)ptr) + res*size;
  176. }
  177. return nread;
  178. }
  179. char *check_fgets(char *ptr, size_t size, FILE *stream) {
  180. char *res = fgets(ptr, size, stream);
  181. if (!res) _io_err(0, size, 1, stream);
  182. return res;
  183. }
  184. size_t check_fwrite(void *ptr, size_t size, size_t nitems, FILE *stream) {
  185. size_t res = 1, nwritten = 0;
  186. while (nwritten < nitems) {
  187. res = fwrite(ptr, size, nitems, stream);
  188. if (res <= 0) _io_err(1, size-1, nitems, stream);
  189. nwritten += res;
  190. }
  191. return nwritten;
  192. }
  193. void *check_mmap_file(char *filename, char mode, int64_t *length) {
  194. FILE *tf;
  195. int flags = MAP_SHARED, prot = PROT_READ;
  196. struct stat ts;
  197. if (mode == 'r') tf = check_fopen(filename, "rb");
  198. else if (mode == 'w') {
  199. tf = check_fopen(filename, "r+b");
  200. prot |= PROT_WRITE;
  201. }
  202. else {
  203. fprintf(SL, "[Error] Invalid mode %c passed to check_mmap_file!\n", mode);
  204. exit(EXIT_FAILURE);
  205. }
  206. int fd = fileno(tf);
  207. if (fstat(fd, &ts)!=0) {
  208. fprintf(SL, "[Error] Fstat failure on file %s!\n", filename);
  209. fprintf(SL, "[Error] Reason: %s\n", strerror(errno));
  210. exit(EXIT_FAILURE);
  211. }
  212. void *res = NULL;
  213. if (ts.st_size > 0) {
  214. res = mmap(NULL, ts.st_size, prot, flags, fd, 0);
  215. if (res == MAP_FAILED) {
  216. fprintf(SL, "[Error] Mmap failure on file %s, mode %c!\n", filename, mode);
  217. fprintf(SL, "[Error] Reason: %s\n", strerror(errno));
  218. exit(EXIT_FAILURE);
  219. }
  220. }
  221. fclose(tf);
  222. if (length) *length = ts.st_size;
  223. return res;
  224. }
  225. #ifndef MAP_ANONYMOUS
  226. #define MAP_ANONYMOUS MAP_ANON
  227. #endif /* MAP_ANONYMOUS */
  228. void *check_mmap_memory(int64_t length) {
  229. int flags = MAP_SHARED | MAP_ANONYMOUS, prot = PROT_READ | PROT_WRITE;
  230. void *res = mmap(NULL, length, prot, flags, -1, 0);
  231. if (res == MAP_FAILED) {
  232. fprintf(SL, "[Error] Mmap failure to allocate %"PRId64" bytes of memory!\n", length);
  233. fprintf(SL, "[Error] Reason: %s\n", strerror(errno));
  234. exit(EXIT_FAILURE);
  235. }
  236. return res;
  237. }
  238. void check_mtrim(void) {
  239. #ifdef __linux__
  240. malloc_trim(0);
  241. #endif /* __linux__ */
  242. }