From: Rusty Russell Date: Tue, 25 Jan 2011 00:27:42 +0000 (+1030) Subject: lca2011: slight insanity. X-Git-Url: https://git.ozlabs.org/?p=ccan-lca-2011.git;a=commitdiff_plain;h=6a2aa334ef54db63cce7635b916b7d0ef7408b95 lca2011: slight insanity. --- diff --git a/ccan/oserver/bin/update-parrot-to-oracle.c b/ccan/oserver/bin/update-parrot-to-oracle.c new file mode 100755 index 0000000..b62712f --- /dev/null +++ b/ccan/oserver/bin/update-parrot-to-oracle.c @@ -0,0 +1,175 @@ +#if 0 +set -e +OUT=`dirname "$0"`/.`basename "$0" .c` +CCAN=/home/rusty/devel/cvs/ccan +if [ ! -f "$OUT" ] || [ "$OUT" -ot "$0" ]; then + make -s -C $CCAN + 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" +fi +exec "$OUT" "$@" +#else +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static char *read_line(int fd) +{ + ssize_t len = 0; + char *buf = talloc_array(NULL, char, 1); + + while (read(fd, buf + len, 1) == 1) { + if (buf[len] == '\n') { + buf[len] = '\0'; + printf("%s\n", buf); + return buf; + } + buf = talloc_realloc(NULL, buf, char, ++len + 1); + } + err(1, "Reading output"); +} + +#define DUMP_FILE "/var/run/oserver/dump" + +int main(int argc, char *argv[]) +{ + int in[2], out[2], i, fd; + char *buf, *fdstr, *osnum, *str, c; + struct oserver *oserver = talloc(NULL, struct oserver); + FILE *gdbin; + + /* Control a gdb. */ + pipe(in); + pipe(out); + if (fork() == 0) { + close(in[1]); + close(out[0]); + dup2(in[0], STDIN_FILENO); + dup2(out[1], STDOUT_FILENO); + dup2(out[1], STDERR_FILENO); + execlp("gdb", "gdb", "-q", NULL); + exit(1); + } + close(in[0]); + close(out[1]); + + /* In case something goes wrong... */ + alarm(5); + + /* Line-at-a-time buffering makes the code easier. */ + gdbin = fdopen(in[1], "w"); + setvbuf(gdbin, NULL, _IOLBF, 0); + + /* Attach to the child, up stack, print something so we know you're + * done. */ + fprintf(gdbin, "attach %s\n" + "up 10000\n" + "p \"end-preamble\"\n", argv[1]); + + /* Throw away preamble */ + while (!strstr(read_line(out[0]), "end-preamble")); + + /* Walk ev->fd_events linked list, find add_client callback. */ + str = talloc_strdup(NULL, "p *ev->fd_events"); + do { + fprintf(gdbin, "%s\n", str); + buf = read_line(out[0]); + str = talloc_append_string(str, "->next"); + } while (!strreg(NULL, buf, ".*add_client")); + + /* ->private == oserver. */ + fprintf(gdbin, "p (struct oserver *)$.private_data\n"); + buf = read_line(out[0]); + if (!strreg(NULL, buf, "^.gdb. (\\$[0-9]+) = ", &osnum)) + errx(1, "Could not derive oserver from '%s'", buf); + + /* Populate a likely-looking oserver struct. */ + oserver->max_clients = 0; + oserver->clients = talloc_array(oserver, struct client *, 5); + oserver->dumpfile = DUMP_FILE; + /* On *next* SIGHUP, we want to run the new oserver. */ + oserver->argv_len = 3; + oserver->argv = talloc_array(oserver, char *, 3); + oserver->argv[0] = "/usr/local/bin/oserver"; + oserver->argv[1] = "--restore"; + oserver->argv[2] = NULL; + fprintf(gdbin, "p %s->fd\n", osnum); + buf = read_line(out[0]); + if (!strreg(buf, buf, "\\$[0-9]+ = ([0-9]+)", &fdstr)) + errx(1, "Didn't get oserver fd"); + oserver->fd = atoi(fdstr); + + /* Dump the client list. */ + for (i = 0; i < 5; i++) { + char *question, *answer, *sent; + struct client *c; + + /* Print the client struct, unless ptr is NULL. */ + fprintf(gdbin, "p %s->clients[%i] ? *%s->clients[%i] : 0\n", + osnum, i, osnum, i); + buf = read_line(out[0]); + if (!strreg(oserver, buf, "fd = ([0-9]+),", &fdstr)) { + oserver->clients[i] = NULL; + continue; + } + + /* Populate the client struct. */ + oserver->max_clients = i+1; + oserver->clients[i] = c = talloc_zero(oserver, struct client); + c->fd = atoi(fdstr); + c->id = i; + c->oracle = c->subclient = -1; + c->question = c->answer = ""; + + /* Translate the states. */ + if (strreg(buf, buf, "\\{state = SENDING_GREETING, .*bytes_sent = ([0-9]*)", &sent)) { + c->state = SENDING_GREETING; + c->bytes_sent = atoi(sent); + } else if (strreg(buf, buf, "\\{state = RECEIVING_USER_QUESTION, .*question = 0x[0-9a-f]* \"(.*)\", answer = ", &question)) { + c->state = RECEIVING_USER_QUESTION; + c->question = question; + } else if (strreg(buf, buf, "\\{state = SENDING_ANSWER_PREFIX, .*bytes_sent = ([0-9]*)", &sent)) { + c->state = SENDING_ANSWER_PREFIX; + c->bytes_sent = atoi(sent); + } else if (strreg(buf, buf, "\\{state = SENDING_ANSWER, .*answer = 0x[0-9a-f]* \"(.*)\", bytes_sent = ([0-9]*)", + &answer, &sent)) { + c->state = SENDING_ANSWER; + c->answer = answer; + c->bytes_sent = atoi(sent); + } else + errx(1, "Unexpected line for client %u: '%s'", i, buf); + } + + /* Bundle up this oserver and clients into the dump file */ + buf = cdump_bundle(NULL, cdump_struct_oserver, oserver); + fd = open(DUMP_FILE, O_WRONLY|O_TRUNC|O_CREAT, 0600); + if (fd < 0) + err(1, "Opening %s", DUMP_FILE); + write(fd, buf, strlen(buf)); + close(fd); + + /* If they didn't say --tesst, get gdb to break on main and run exec. */ + if (!argv[2] || !streq(argv[2], "--test")) { + /* GDB will complain about break inside gdb-called fun, but + * it'll do it. */ + fprintf(gdbin, "break main\n"); + fprintf(gdbin, "p execl(\"/usr/local/bin/oserver\"," + " \"/usr/local/bin/oserver\", \"--restore\", 0)\n"); + } + + /* Detach and kill gdb. */ + fprintf(gdbin, "detach\nquit\n"); + + /* Make sure it exited. */ + while (read(out[0], &c, 1) == 1); + exit(0); +} +#endif