b62712fce84fd1808f769a1501f7a91164385ed9
[ccan-lca-2011.git] / ccan / oserver / bin / update-parrot-to-oracle.c
1 #if 0
2 set -e
3 OUT=`dirname "$0"`/.`basename "$0" .c`
4 CCAN=/home/rusty/devel/cvs/ccan
5 if [ ! -f "$OUT" ] || [ "$OUT" -ot "$0" ]; then
6     make -s -C $CCAN 
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"
8 fi
9 exec "$OUT" "$@"
10 #else
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>
19 #include <sys/stat.h>
20 #include <fcntl.h>
21 #include <unistd.h>
22 #include <err.h>
23
24 static char *read_line(int fd)
25 {
26         ssize_t len = 0;
27         char *buf = talloc_array(NULL, char, 1);
28
29         while (read(fd, buf + len, 1) == 1) {
30                 if (buf[len] == '\n') {
31                         buf[len] = '\0';
32                         printf("%s\n", buf);
33                         return buf;
34                 }
35                 buf = talloc_realloc(NULL, buf, char, ++len + 1);
36         }
37         err(1, "Reading output");
38 }
39
40 #define DUMP_FILE "/var/run/oserver/dump"
41
42 int main(int argc, char *argv[])
43 {
44         int in[2], out[2], i, fd;
45         char *buf, *fdstr, *osnum, *str, c;
46         struct oserver *oserver = talloc(NULL, struct oserver);
47         FILE *gdbin;
48
49         /* Control a gdb. */
50         pipe(in);
51         pipe(out);
52         if (fork() == 0) {
53                 close(in[1]);
54                 close(out[0]);
55                 dup2(in[0], STDIN_FILENO);
56                 dup2(out[1], STDOUT_FILENO);
57                 dup2(out[1], STDERR_FILENO);
58                 execlp("gdb", "gdb", "-q", NULL);
59                 exit(1);
60         }
61         close(in[0]);
62         close(out[1]);
63
64         /* In case something goes wrong... */
65         alarm(5);
66
67         /* Line-at-a-time buffering makes the code easier. */
68         gdbin = fdopen(in[1], "w");
69         setvbuf(gdbin, NULL, _IOLBF, 0);
70
71         /* Attach to the child, up stack, print something so we know you're
72          * done. */
73         fprintf(gdbin, "attach %s\n"
74                 "up 10000\n"
75                 "p \"end-preamble\"\n", argv[1]);
76
77         /* Throw away preamble */
78         while (!strstr(read_line(out[0]), "end-preamble"));
79
80         /* Walk ev->fd_events linked list, find add_client callback. */
81         str = talloc_strdup(NULL, "p *ev->fd_events");
82         do {
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"));
87
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);
93
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);
109
110         /* Dump the client list. */
111         for (i = 0; i < 5; i++) {
112                 char *question, *answer, *sent;
113                 struct client *c;
114
115                 /* Print the client struct, unless ptr is NULL. */
116                 fprintf(gdbin, "p %s->clients[%i] ? *%s->clients[%i] : 0\n",
117                         osnum, i, osnum, i);
118                 buf = read_line(out[0]);
119                 if (!strreg(oserver, buf, "fd = ([0-9]+),", &fdstr)) {
120                         oserver->clients[i] = NULL;
121                         continue;
122                 }
123
124                 /* Populate the client struct. */
125                 oserver->max_clients = i+1;
126                 oserver->clients[i] = c = talloc_zero(oserver, struct client);
127                 c->fd = atoi(fdstr);
128                 c->id = i;
129                 c->oracle = c->subclient = -1;
130                 c->question = c->answer = "";
131
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]*)",
143                                   &answer, &sent)) {
144                         c->state = SENDING_ANSWER;
145                         c->answer = answer;
146                         c->bytes_sent = atoi(sent);
147                 } else
148                         errx(1, "Unexpected line for client %u: '%s'", i, buf);
149         }
150
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);
154         if (fd < 0)
155                 err(1, "Opening %s", DUMP_FILE);
156         write(fd, buf, strlen(buf));
157         close(fd);
158
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
162                  * it'll do it. */
163                 fprintf(gdbin, "break main\n");
164                 fprintf(gdbin, "p execl(\"/usr/local/bin/oserver\","
165                         " \"/usr/local/bin/oserver\", \"--restore\", 0)\n");
166         }
167
168         /* Detach and kill gdb. */
169         fprintf(gdbin, "detach\nquit\n");
170
171         /* Make sure it exited. */ 
172         while (read(out[0], &c, 1) == 1);
173         exit(0);
174 }
175 #endif