Commit | Line | Data |
---|---|---|
ca51b51d MW |
1 | #include "cdb.h" |
2 | #include "stralloc.h" | |
3 | #include "byte.h" | |
4 | #include "str.h" | |
5 | #include "addrcheck.h" | |
6 | #include <errno.h> | |
7 | ||
8 | /* #define DEBUG */ | |
9 | #ifdef DEBUG | |
10 | # define D(x) x | |
11 | # include <stdio.h> | |
12 | # include <sys/types.h> | |
13 | # include <unistd.h> | |
14 | #else | |
15 | # define D(x) | |
16 | #endif | |
17 | ||
18 | #define STRALLOC_INIT { 0 } | |
19 | ||
20 | static int probe(int cdb, int prefix, const char *key, int len, | |
21 | const char *suffix, uint32 *dlen) | |
22 | { | |
23 | static stralloc k = STRALLOC_INIT; | |
24 | char ch = prefix; | |
25 | int rc; | |
26 | ||
27 | k.len = 0; | |
28 | if (!stralloc_append(&k, &ch) || | |
29 | !stralloc_catb(&k, key, len) || | |
30 | (suffix && !stralloc_cats(&k, suffix))) | |
31 | return (-1); | |
32 | D( fprintf(stderr, "*** `%.*s' -> ", k.len, k.s); ) | |
33 | rc = cdb_seek(cdb, k.s, k.len, dlen); | |
34 | D( if (rc == -1) | |
35 | fprintf(stderr, "error: %s\n", strerror(errno)); | |
36 | else if (rc == 0) | |
37 | fprintf(stderr, "not found\n"); | |
38 | else if (!*dlen) | |
39 | fprintf(stderr, "empty\n"); | |
40 | else { | |
41 | int n = *dlen; | |
42 | int nn; | |
43 | char buf[256]; | |
44 | off_t pos = lseek(cdb, 0, SEEK_CUR); | |
45 | fprintf(stderr, "`"); | |
46 | while (n) { | |
47 | nn = sizeof(buf); if (nn > n) nn = n; | |
48 | read(cdb, buf, nn); | |
49 | fwrite(buf, 1, nn, stderr); | |
50 | n -= nn; | |
51 | } | |
52 | fprintf(stderr, "'\n"); | |
53 | lseek(cdb, pos, SEEK_SET); | |
54 | } ) | |
55 | return (rc); | |
56 | } | |
57 | ||
58 | static int localprobe(int cdb, const char *key, int len, | |
59 | const char *suffix, int *rc) | |
60 | { | |
61 | int err; | |
62 | uint32 dlen; | |
63 | char ch; | |
64 | ||
65 | if ((err = probe(cdb, 'L', key, len, suffix, &dlen)) < 0) | |
66 | return (-1); | |
67 | if (!err) { *rc = 0; return (0); } | |
68 | if (dlen != 1) { errno = EINVAL; return (-1); } | |
69 | if (read(cdb, &ch, 1) != 1) { errno = EIO; return (-1); } | |
70 | *rc = ch; | |
71 | return (1); | |
72 | } | |
73 | ||
74 | static int local(int cdb, const char *l, int len, int *rc) | |
75 | { | |
76 | int code; | |
77 | int err = 0; | |
78 | int dash; | |
79 | ||
80 | if ((err = localprobe(cdb, l, len, 0, &code)) != 0) goto done; | |
81 | ||
82 | for (;;) { | |
83 | dash = byte_rchr(l, len, '-'); | |
84 | if (dash == len) break; | |
85 | if ((err = localprobe(cdb, l, dash, "-default", &code)) != 0) goto done; | |
86 | len = dash; | |
87 | } | |
88 | *rc = 0; | |
89 | return (0); | |
90 | ||
91 | done: | |
92 | if (err >= 0) { | |
93 | switch (code) { | |
94 | case '+': *rc = 1; break; | |
95 | case '-': *rc = 0; break; | |
96 | default: errno = EINVAL; err = -1; break; | |
97 | } | |
98 | } | |
99 | return (err); | |
100 | } | |
101 | ||
102 | static int virt(int cdb, const char *u, int ulen, | |
103 | const char *addr, int alen, int *rc) | |
104 | { | |
105 | static stralloc l = STRALLOC_INIT; | |
106 | uint32 dlen; | |
107 | int err; | |
108 | ||
109 | if ((err = probe(cdb, 'V', addr, alen, 0, &dlen)) <= 0) | |
110 | return (err); | |
111 | if (!stralloc_ready(&l, dlen + 1)) return (-1); | |
112 | if (read(cdb, l.s, dlen) != dlen) { errno = EIO; return (-1); } | |
113 | l.s[dlen] = '-'; | |
114 | l.len = dlen + 1; | |
115 | if (!stralloc_catb(&l, u, ulen)) return (-1); | |
116 | D( printf("*** virtual map -> `%.*s'\n", l.len, l.s); ) | |
117 | if (local(cdb, l.s, l.len, rc) < 0) return (-1); | |
118 | return (1); | |
119 | } | |
120 | ||
121 | int addrcheck(int cdb, const char *addr, int *rc) | |
122 | { | |
123 | int at, len, dot; | |
124 | int err = 0; | |
125 | uint32 dlen; | |
126 | ||
127 | len = str_len(addr); | |
128 | at = str_chr(addr, '@'); | |
129 | if (!addr[at]) | |
130 | return (local(cdb, addr, len, rc)); | |
131 | ||
132 | if ((err = virt(cdb, addr, at, addr, len, rc)) != 0) | |
133 | return (err); | |
134 | dot = at + 1; | |
135 | while (addr[dot]) { | |
136 | if ((err = virt(cdb, addr, at, addr + dot, len - dot, rc)) != 0) | |
137 | return (err); | |
138 | dot += byte_chr(addr + dot + 1, len - dot - 1, '.') + 1; | |
139 | } | |
140 | ||
141 | if ((err = probe(cdb, '@', addr + at + 1, len - at - 1, 0, &dlen)) < 0) | |
142 | return (-1); | |
143 | if (!err) { *rc = 1; return (0); } | |
144 | if (dlen != 0) { errno = EINVAL; return (-1); } | |
145 | ||
146 | return (local(cdb, addr, at, rc)); | |
147 | } | |
148 | ||
149 | #ifdef TEST | |
150 | #include <sys/types.h> | |
151 | #include <unistd.h> | |
152 | #include <fcntl.h> | |
153 | #include <stdio.h> | |
154 | #include <errno.h> | |
155 | #include <unistd.h> | |
156 | ||
157 | int main(int argc, char *argv[]) | |
158 | { | |
159 | int fd; | |
160 | int rc; | |
161 | int i; | |
162 | ||
163 | if (argc < 3) { | |
164 | fprintf(stderr, "usage: addrcheck CDB ADDR...\n"); | |
165 | return (1); | |
166 | } | |
167 | if ((fd = open(argv[1], O_RDONLY)) < 0) { | |
168 | perror(argv[1]); | |
169 | return (1); | |
170 | } | |
171 | for (i = 2; i < argc; i++) { | |
172 | if (addrcheck(fd, argv[i], &rc) < 0) { | |
173 | perror("checking"); | |
174 | return (1); | |
175 | } | |
176 | printf("%s: %s\n", argv[i], rc ? "ok" : "bad"); | |
177 | } | |
178 | return (0); | |
179 | } | |
180 | ||
181 | #endif |