modpipe.c 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. /*
  2. * Copyright (c) 2012 Damien Miller <djm@mindrot.org>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. /* $OpenBSD: modpipe.c,v 1.6 2013/11/21 03:16:47 djm Exp $ */
  17. #include "includes.h"
  18. #include <sys/types.h>
  19. #include <unistd.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <stdarg.h>
  23. #include <stdlib.h>
  24. #include <errno.h>
  25. #ifdef HAVE_ERR_H
  26. # include <err.h>
  27. #endif
  28. #include "openbsd-compat/getopt_long.c"
  29. static void
  30. usage(void)
  31. {
  32. fprintf(stderr, "Usage: modpipe -w [-m modspec ...] < in > out\n");
  33. fprintf(stderr, "modspec is one of:\n");
  34. fprintf(stderr, " xor:offset:value - XOR \"value\" at \"offset\"\n");
  35. fprintf(stderr, " andor:offset:val1:val2 - AND \"val1\" then OR \"val2\" at \"offset\"\n");
  36. exit(1);
  37. }
  38. #define MAX_MODIFICATIONS 256
  39. struct modification {
  40. enum { MOD_XOR, MOD_AND_OR } what;
  41. unsigned long long offset;
  42. u_int8_t m1, m2;
  43. };
  44. static void
  45. parse_modification(const char *s, struct modification *m)
  46. {
  47. char what[16+1];
  48. int n, m1, m2;
  49. bzero(m, sizeof(*m));
  50. if ((n = sscanf(s, "%16[^:]%*[:]%llu%*[:]%i%*[:]%i",
  51. what, &m->offset, &m1, &m2)) < 3)
  52. errx(1, "Invalid modification spec \"%s\"", s);
  53. if (strcasecmp(what, "xor") == 0) {
  54. if (n > 3)
  55. errx(1, "Invalid modification spec \"%s\"", s);
  56. if (m1 < 0 || m1 > 0xff)
  57. errx(1, "Invalid XOR modification value");
  58. m->what = MOD_XOR;
  59. m->m1 = m1;
  60. } else if (strcasecmp(what, "andor") == 0) {
  61. if (n != 4)
  62. errx(1, "Invalid modification spec \"%s\"", s);
  63. if (m1 < 0 || m1 > 0xff)
  64. errx(1, "Invalid AND modification value");
  65. if (m2 < 0 || m2 > 0xff)
  66. errx(1, "Invalid OR modification value");
  67. m->what = MOD_AND_OR;
  68. m->m1 = m1;
  69. m->m2 = m2;
  70. } else
  71. errx(1, "Invalid modification type \"%s\"", what);
  72. }
  73. int
  74. main(int argc, char **argv)
  75. {
  76. int ch;
  77. u_char buf[8192];
  78. size_t total;
  79. ssize_t r, s, o;
  80. struct modification mods[MAX_MODIFICATIONS];
  81. u_int i, wflag = 0, num_mods = 0;
  82. while ((ch = getopt(argc, argv, "wm:")) != -1) {
  83. switch (ch) {
  84. case 'm':
  85. if (num_mods >= MAX_MODIFICATIONS)
  86. errx(1, "Too many modifications");
  87. parse_modification(optarg, &(mods[num_mods++]));
  88. break;
  89. case 'w':
  90. wflag = 1;
  91. break;
  92. default:
  93. usage();
  94. /* NOTREACHED */
  95. }
  96. }
  97. for (total = 0;;) {
  98. r = s = read(STDIN_FILENO, buf, sizeof(buf));
  99. if (r == 0)
  100. break;
  101. if (r < 0) {
  102. if (errno == EAGAIN || errno == EINTR)
  103. continue;
  104. err(1, "read");
  105. }
  106. for (i = 0; i < num_mods; i++) {
  107. if (mods[i].offset < total ||
  108. mods[i].offset >= total + s)
  109. continue;
  110. switch (mods[i].what) {
  111. case MOD_XOR:
  112. buf[mods[i].offset - total] ^= mods[i].m1;
  113. break;
  114. case MOD_AND_OR:
  115. buf[mods[i].offset - total] &= mods[i].m1;
  116. buf[mods[i].offset - total] |= mods[i].m2;
  117. break;
  118. }
  119. }
  120. for (o = 0; o < s; o += r) {
  121. r = write(STDOUT_FILENO, buf, s - o);
  122. if (r == 0)
  123. break;
  124. if (r < 0) {
  125. if (errno == EAGAIN || errno == EINTR)
  126. continue;
  127. err(1, "write");
  128. }
  129. }
  130. total += s;
  131. }
  132. /* Warn if modifications not reached in input stream */
  133. r = 0;
  134. for (i = 0; wflag && i < num_mods; i++) {
  135. if (mods[i].offset < total)
  136. continue;
  137. r = 1;
  138. fprintf(stderr, "modpipe: warning - mod %u not reached\n", i);
  139. }
  140. return r;
  141. }