3 OUT=`dirname "$0"`/.`basename "$0" .c`
4 CCAN=/home/rusty/devel/cvs/ccan
5 if [ ! -f "$OUT" ] || [ "$OUT" -ot "$0" ]; then
7 gcc -Wall -I$CCAN -g -o "$OUT".$$ $CCAN/ccan/talloc.o $CCAN/ccan/str.o $CCAN/ccan/str_talloc.o $CCAN/ccan/grab_file.o $CCAN/ccan/read_write_all.o $CCAN/ccan/noerr.o $CCAN/ccan/oserver.o $CCAN/ccan/tevent.o $CCAN/ccan/cdump.o -x c "$0" && mv "$OUT".$$ "$OUT"
11 #include <ccan/talloc/talloc.h>
12 #include <ccan/str/str.h>
13 #include <ccan/str_talloc/str_talloc.h>
14 #include <ccan/grab_file/grab_file.h>
15 #include <ccan/oserver/oserver_types.h>
16 #include <ccan/oserver/oserver_cdump.h>
17 #include <ccan/noerr/noerr.h>
18 #include <sys/types.h>
24 static char *read_line(int fd)
27 char *buf = talloc_array(NULL, char, 1);
29 while (read(fd, buf + len, 1) == 1) {
30 if (buf[len] == '\n') {
35 buf = talloc_realloc(NULL, buf, char, ++len + 1);
37 err(1, "Reading output");
40 #define DUMP_FILE "/var/run/oserver/dump"
42 int main(int argc, char *argv[])
44 int in[2], out[2], i, fd;
45 char *buf, *fdstr, *osnum, *str, c;
46 struct oserver *oserver = talloc(NULL, struct oserver);
55 dup2(in[0], STDIN_FILENO);
56 dup2(out[1], STDOUT_FILENO);
57 dup2(out[1], STDERR_FILENO);
58 execlp("gdb", "gdb", "-q", NULL);
64 /* In case something goes wrong... */
67 /* Line-at-a-time buffering makes the code easier. */
68 gdbin = fdopen(in[1], "w");
69 setvbuf(gdbin, NULL, _IOLBF, 0);
71 /* Attach to the child, up stack, print something so we know you're
73 fprintf(gdbin, "attach %s\n"
75 "p \"end-preamble\"\n", argv[1]);
77 /* Throw away preamble */
78 while (!strstr(read_line(out[0]), "end-preamble"));
80 /* Walk ev->fd_events linked list, find add_client callback. */
81 str = talloc_strdup(NULL, "p *ev->fd_events");
83 fprintf(gdbin, "%s\n", str);
84 buf = read_line(out[0]);
85 str = talloc_append_string(str, "->next");
86 } while (!strreg(NULL, buf, ".*add_client"));
88 /* ->private == oserver. */
89 fprintf(gdbin, "p (struct oserver *)$.private_data\n");
90 buf = read_line(out[0]);
91 if (!strreg(NULL, buf, "^.gdb. (\\$[0-9]+) = ", &osnum))
92 errx(1, "Could not derive oserver from '%s'", buf);
94 /* Populate a likely-looking oserver struct. */
95 oserver->max_clients = 0;
96 oserver->clients = talloc_array(oserver, struct client *, 5);
97 oserver->dumpfile = DUMP_FILE;
98 /* On *next* SIGHUP, we want to run the new oserver. */
99 oserver->argv_len = 3;
100 oserver->argv = talloc_array(oserver, char *, 3);
101 oserver->argv[0] = "/usr/local/bin/oserver";
102 oserver->argv[1] = "--restore";
103 oserver->argv[2] = NULL;
104 fprintf(gdbin, "p %s->fd\n", osnum);
105 buf = read_line(out[0]);
106 if (!strreg(buf, buf, "\\$[0-9]+ = ([0-9]+)", &fdstr))
107 errx(1, "Didn't get oserver fd");
108 oserver->fd = atoi(fdstr);
110 /* Dump the client list. */
111 for (i = 0; i < 5; i++) {
112 char *question, *answer, *sent;
115 /* Print the client struct, unless ptr is NULL. */
116 fprintf(gdbin, "p %s->clients[%i] ? *%s->clients[%i] : 0\n",
118 buf = read_line(out[0]);
119 if (!strreg(oserver, buf, "fd = ([0-9]+),", &fdstr)) {
120 oserver->clients[i] = NULL;
124 /* Populate the client struct. */
125 oserver->max_clients = i+1;
126 oserver->clients[i] = c = talloc_zero(oserver, struct client);
129 c->oracle = c->subclient = -1;
130 c->question = c->answer = "";
132 /* Translate the states. */
133 if (strreg(buf, buf, "\\{state = SENDING_GREETING, .*bytes_sent = ([0-9]*)", &sent)) {
134 c->state = SENDING_GREETING;
135 c->bytes_sent = atoi(sent);
136 } else if (strreg(buf, buf, "\\{state = RECEIVING_USER_QUESTION, .*question = 0x[0-9a-f]* \"(.*)\", answer = ", &question)) {
137 c->state = RECEIVING_USER_QUESTION;
138 c->question = question;
139 } else if (strreg(buf, buf, "\\{state = SENDING_ANSWER_PREFIX, .*bytes_sent = ([0-9]*)", &sent)) {
140 c->state = SENDING_ANSWER_PREFIX;
141 c->bytes_sent = atoi(sent);
142 } else if (strreg(buf, buf, "\\{state = SENDING_ANSWER, .*answer = 0x[0-9a-f]* \"(.*)\", bytes_sent = ([0-9]*)",
144 c->state = SENDING_ANSWER;
146 c->bytes_sent = atoi(sent);
148 errx(1, "Unexpected line for client %u: '%s'", i, buf);
151 /* Bundle up this oserver and clients into the dump file */
152 buf = cdump_bundle(NULL, cdump_struct_oserver, oserver);
153 fd = open(DUMP_FILE, O_WRONLY|O_TRUNC|O_CREAT, 0600);
155 err(1, "Opening %s", DUMP_FILE);
156 write(fd, buf, strlen(buf));
159 /* If they didn't say --tesst, get gdb to break on main and run exec. */
160 if (!argv[2] || !streq(argv[2], "--test")) {
161 /* GDB will complain about break inside gdb-called fun, but
163 fprintf(gdbin, "break main\n");
164 fprintf(gdbin, "p execl(\"/usr/local/bin/oserver\","
165 " \"/usr/local/bin/oserver\", \"--restore\", 0)\n");
168 /* Detach and kill gdb. */
169 fprintf(gdbin, "detach\nquit\n");
171 /* Make sure it exited. */
172 while (read(out[0], &c, 1) == 1);