logo

bootstrap-initrd

Linux initrd to bootstrap from a small binary seed git clone https://hacktivis.me/git/bootstrap-initrd.git

grep-stub.c (5397B)


  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. #define _GNU_SOURCE // strcasestr
  6. #include <assert.h>
  7. #include <errno.h>
  8. #include <regex.h>
  9. #include <stdbool.h>
  10. #include <stdio.h> // getline
  11. #include <stdlib.h> // free
  12. #include <string.h> // strstr, strerror
  13. #include <unistd.h> // getopt
  14. static char *argv0 = "grep";
  15. struct char_list
  16. {
  17. char *data;
  18. struct char_list *next;
  19. };
  20. static struct char_list *patterns;
  21. static struct char_list *files;
  22. static size_t patterns_r_len = 0;
  23. static regex_t *patterns_r = NULL;
  24. static bool fixed_str = false, invert = false, count_only = false, opt_n = false, quiet = false;
  25. static bool multiple_files = false;
  26. static char *(*find_substring)(const char *, const char *) = &strstr;
  27. static bool found_any = false;
  28. static int
  29. do_grep(FILE *stream, char *filename)
  30. {
  31. char *line = NULL;
  32. size_t len = 0;
  33. size_t ln = 0;
  34. int count = 0;
  35. ssize_t nread = 0;
  36. while((nread = getline(&line, &len, stream)) != -1)
  37. {
  38. ln++;
  39. if(line[nread - 1] == '\n') line[nread - 1] = 0;
  40. bool found = false;
  41. if(fixed_str)
  42. {
  43. for(struct char_list *pattern = patterns; pattern != NULL; pattern = pattern->next)
  44. {
  45. if(find_substring(line, pattern->data) != NULL)
  46. {
  47. found = true;
  48. break;
  49. }
  50. }
  51. }
  52. else
  53. {
  54. assert(patterns_r != NULL);
  55. assert(patterns_r_len != 0);
  56. for(size_t i = 0; i < patterns_r_len; i++)
  57. {
  58. if(regexec(&patterns_r[i], line, 0, 0, 0) == 0)
  59. {
  60. found = true;
  61. break;
  62. }
  63. }
  64. }
  65. if(found != invert)
  66. {
  67. found_any = true;
  68. count++;
  69. if(!quiet)
  70. {
  71. if(multiple_files) printf("%s:", filename);
  72. if(opt_n) printf("%zd:", ln);
  73. if(!count_only) printf("%s\n", line);
  74. }
  75. }
  76. }
  77. if(!quiet && count_only) printf("%d\n", count);
  78. free(line);
  79. if(ferror(stream))
  80. {
  81. fprintf(stderr, "%s: Error while reading '%s': %s\n", argv0, filename, strerror(errno));
  82. return -1;
  83. }
  84. return 0;
  85. }
  86. static void
  87. usage()
  88. {
  89. fprintf(stderr,
  90. "Usage: %s [-EFcilnqsvx] [-f patterns_file... | -e pattern... | pattern] [file...]\n",
  91. argv0);
  92. }
  93. int
  94. main(int argc, char *argv[])
  95. {
  96. argv0 = argv[0];
  97. bool opt_l = false;
  98. int regcomp_flags = REG_NOSUB;
  99. struct char_list *patterns_last = NULL;
  100. struct char_list *files_last = NULL;
  101. size_t patterns_len = 0;
  102. switch(argv0[0])
  103. {
  104. case 'e':
  105. regcomp_flags |= REG_EXTENDED;
  106. break;
  107. case 'f':
  108. fixed_str = true;
  109. break;
  110. }
  111. int c = -1;
  112. while((c = getopt(argc, argv, ":EFce:f:ilnqsvx")) != -1)
  113. {
  114. switch(c)
  115. {
  116. case 'E':
  117. regcomp_flags |= REG_EXTENDED;
  118. break;
  119. case 'F':
  120. fixed_str = true;
  121. break;
  122. case 'c':
  123. count_only = true;
  124. break;
  125. case 'e':
  126. if(patterns_last == NULL)
  127. {
  128. patterns = &(struct char_list){
  129. .data = optarg,
  130. .next = NULL,
  131. };
  132. patterns_last = patterns;
  133. patterns_len++;
  134. }
  135. else
  136. {
  137. patterns->next = &(struct char_list){
  138. .data = optarg,
  139. .next = NULL,
  140. };
  141. patterns_last = patterns->next;
  142. patterns_len++;
  143. }
  144. break;
  145. case 'f':
  146. if(files_last == NULL)
  147. {
  148. files = &(struct char_list){
  149. .data = optarg,
  150. .next = NULL,
  151. };
  152. files_last = files;
  153. }
  154. else
  155. {
  156. files->next = &(struct char_list){
  157. .data = optarg,
  158. .next = NULL,
  159. };
  160. files_last = files->next;
  161. }
  162. break;
  163. case 'i':
  164. regcomp_flags |= REG_ICASE;
  165. find_substring = &strcasestr;
  166. break;
  167. case 'l':
  168. // (standard input)
  169. opt_l = true;
  170. break;
  171. case 'n':
  172. opt_n = true;
  173. break;
  174. case 'q':
  175. quiet = true;
  176. break;
  177. case 's':
  178. //no_warn = true;
  179. break;
  180. case 'v':
  181. invert = true;
  182. break;
  183. case 'x':
  184. //whole_line = true;
  185. break;
  186. }
  187. }
  188. argc -= optind;
  189. argv += optind;
  190. if(patterns_last == NULL && files_last == NULL)
  191. {
  192. if(argc == 0)
  193. {
  194. fprintf(stderr, "%s: No pattern given\n", argv0);
  195. usage();
  196. return 2;
  197. }
  198. patterns = &(struct char_list){
  199. .data = argv[0],
  200. .next = NULL,
  201. };
  202. patterns_last = patterns;
  203. patterns_len++;
  204. argc -= 1;
  205. argv += 1;
  206. }
  207. int err = 0;
  208. if(!fixed_str)
  209. {
  210. patterns_r = calloc(patterns_len, sizeof(regex_t));
  211. if(patterns_r == NULL)
  212. {
  213. fprintf(stderr, "%s: Failed allocating memory for patterns: %s\n", argv0, strerror(errno));
  214. return 2;
  215. }
  216. for(struct char_list *pattern = patterns; pattern != NULL; pattern = pattern->next)
  217. {
  218. int ret = regcomp(&patterns_r[patterns_r_len], pattern->data, regcomp_flags);
  219. if(ret != 0)
  220. {
  221. char errbuf[100] = "";
  222. regerror(ret, &patterns_r[patterns_r_len], errbuf, sizeof(errbuf));
  223. fprintf(stderr, "%s: Error compiling regex /%s/: %s\n", pattern->data, errbuf, argv0);
  224. err = 1;
  225. goto cleanup;
  226. }
  227. patterns_r_len++;
  228. }
  229. }
  230. if(argc == 0)
  231. {
  232. if(do_grep(stdin, "(standard input)") < 0) return 2;
  233. goto cleanup;
  234. }
  235. if(argc > 1) multiple_files = true;
  236. for(int i = 0; i < argc; i++)
  237. {
  238. FILE *stream = fopen(argv[i], "r");
  239. if(stream == NULL)
  240. {
  241. fprintf(stderr, "%s: Failed opening '%s' for reading: %s\n", argv0, argv[i], strerror(errno));
  242. err = 1;
  243. goto cleanup;
  244. }
  245. if(do_grep(stream, argv[i]) < 0) return 2;
  246. }
  247. cleanup:
  248. if(!found_any) err++;
  249. for(size_t i = 0; i < patterns_r_len; i++)
  250. {
  251. regfree(&patterns_r[i]);
  252. }
  253. return err;
  254. }