Branch data Line data Source code
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 : :
17 : : /* $OpenBSD: modpipe.c,v 1.6 2013/11/21 03:16:47 djm Exp $ */
18 : :
19 : : #include "includes.h"
20 : :
21 : : #include <sys/types.h>
22 : : #include <unistd.h>
23 : : #include <stdio.h>
24 : : #include <string.h>
25 : : #include <stdarg.h>
26 : : #include <stdlib.h>
27 : : #include <errno.h>
28 : : #include "openbsd-compat/getopt_long.c"
29 : :
30 : : static void err(int, const char *, ...) __attribute__((format(printf, 2, 3)));
31 : : static void errx(int, const char *, ...) __attribute__((format(printf, 2, 3)));
32 : :
33 : : static void
34 : 0 : err(int r, const char *fmt, ...)
35 : : {
36 : : va_list args;
37 : :
38 : 0 : va_start(args, fmt);
39 : 0 : fprintf(stderr, "%s: ", strerror(errno));
40 : 0 : vfprintf(stderr, fmt, args);
41 : 0 : fputc('\n', stderr);
42 : 0 : va_end(args);
43 : 0 : exit(r);
44 : : }
45 : :
46 : : static void
47 : 0 : errx(int r, const char *fmt, ...)
48 : : {
49 : : va_list args;
50 : :
51 : 0 : va_start(args, fmt);
52 : 0 : vfprintf(stderr, fmt, args);
53 : 0 : fputc('\n', stderr);
54 : 0 : va_end(args);
55 : 0 : exit(r);
56 : : }
57 : :
58 : : static void
59 : 0 : usage(void)
60 : : {
61 : 0 : fprintf(stderr, "Usage: modpipe -w [-m modspec ...] < in > out\n");
62 : 0 : fprintf(stderr, "modspec is one of:\n");
63 : 0 : fprintf(stderr, " xor:offset:value - XOR \"value\" at \"offset\"\n");
64 : 0 : fprintf(stderr, " andor:offset:val1:val2 - AND \"val1\" then OR \"val2\" at \"offset\"\n");
65 : 0 : exit(1);
66 : : }
67 : :
68 : : #define MAX_MODIFICATIONS 256
69 : : struct modification {
70 : : enum { MOD_XOR, MOD_AND_OR } what;
71 : : unsigned long long offset;
72 : : u_int8_t m1, m2;
73 : : };
74 : :
75 : : static void
76 : 218 : parse_modification(const char *s, struct modification *m)
77 : : {
78 : : char what[16+1];
79 : : int n, m1, m2;
80 : :
81 : : bzero(m, sizeof(*m));
82 [ - + ]: 218 : if ((n = sscanf(s, "%16[^:]%*[:]%llu%*[:]%i%*[:]%i",
83 : : what, &m->offset, &m1, &m2)) < 3)
84 : 0 : errx(1, "Invalid modification spec \"%s\"", s);
85 [ + - ]: 218 : if (strcasecmp(what, "xor") == 0) {
86 [ - + ]: 218 : if (n > 3)
87 : 0 : errx(1, "Invalid modification spec \"%s\"", s);
88 [ - + ]: 218 : if (m1 < 0 || m1 > 0xff)
89 : 0 : errx(1, "Invalid XOR modification value");
90 : 218 : m->what = MOD_XOR;
91 : 218 : m->m1 = m1;
92 [ # # ]: 0 : } else if (strcasecmp(what, "andor") == 0) {
93 [ # # ]: 0 : if (n != 4)
94 : 0 : errx(1, "Invalid modification spec \"%s\"", s);
95 [ # # ]: 0 : if (m1 < 0 || m1 > 0xff)
96 : 0 : errx(1, "Invalid AND modification value");
97 [ # # ]: 0 : if (m2 < 0 || m2 > 0xff)
98 : 0 : errx(1, "Invalid OR modification value");
99 : 0 : m->what = MOD_AND_OR;
100 : 0 : m->m1 = m1;
101 : 0 : m->m2 = m2;
102 : : } else
103 : 0 : errx(1, "Invalid modification type \"%s\"", what);
104 : 218 : }
105 : :
106 : : int
107 : 218 : main(int argc, char **argv)
108 : : {
109 : : int ch;
110 : : u_char buf[8192];
111 : : size_t total;
112 : : ssize_t r, s, o;
113 : : struct modification mods[MAX_MODIFICATIONS];
114 : 218 : u_int i, wflag = 0, num_mods = 0;
115 : :
116 [ + + ]: 2187 : while ((ch = getopt(argc, argv, "wm:")) != -1) {
117 [ + - + ]: 436 : switch (ch) {
118 : : case 'm':
119 [ - + ]: 218 : if (num_mods >= MAX_MODIFICATIONS)
120 : 0 : errx(1, "Too many modifications");
121 : 218 : parse_modification(optarg, &(mods[num_mods++]));
122 : 436 : break;
123 : : case 'w':
124 : : wflag = 1;
125 : : break;
126 : : default:
127 : 0 : usage();
128 : : /* NOTREACHED */
129 : : }
130 : : }
131 : : for (total = 0;;) {
132 : 1533 : r = s = read(STDIN_FILENO, buf, sizeof(buf));
133 [ + + ]: 1533 : if (r == 0)
134 : : break;
135 [ + - ]: 1315 : if (r < 0) {
136 [ # # ]: 0 : if (errno == EAGAIN || errno == EINTR)
137 : 0 : continue;
138 : 0 : err(1, "read");
139 : : }
140 [ + + ]: 2630 : for (i = 0; i < num_mods; i++) {
141 [ + - ][ + + ]: 1315 : if (mods[i].offset < total ||
142 : 1315 : mods[i].offset >= total + s)
143 : 1097 : continue;
144 [ + - - ]: 218 : switch (mods[i].what) {
145 : : case MOD_XOR:
146 : 218 : buf[mods[i].offset - total] ^= mods[i].m1;
147 : 218 : break;
148 : : case MOD_AND_OR:
149 : 0 : buf[mods[i].offset - total] &= mods[i].m1;
150 : 0 : buf[mods[i].offset - total] |= mods[i].m2;
151 : 0 : break;
152 : : }
153 : : }
154 [ + + ]: 2630 : for (o = 0; o < s; o += r) {
155 : 1315 : r = write(STDOUT_FILENO, buf, s - o);
156 [ + - ]: 1315 : if (r == 0)
157 : : break;
158 [ - + ]: 1315 : if (r < 0) {
159 [ # # ]: 0 : if (errno == EAGAIN || errno == EINTR)
160 : 0 : continue;
161 : 0 : err(1, "write");
162 : : }
163 : : }
164 : 1315 : total += s;
165 : : }
166 : : /* Warn if modifications not reached in input stream */
167 : : r = 0;
168 [ + + ]: 436 : for (i = 0; wflag && i < num_mods; i++) {
169 [ + - ]: 218 : if (mods[i].offset < total)
170 : 218 : continue;
171 : 0 : r = 1;
172 : 0 : fprintf(stderr, "modpipe: warning - mod %u not reached\n", i);
173 : : }
174 : 218 : return r;
175 : : }
|