]> git.ozlabs.org Git - ccan/blob - ccan/io/_info
ccan/io: go linear for debugging.
[ccan] / ccan / io / _info
1 #include <stdio.h>
2 #include <string.h>
3 #include "config.h"
4
5 /**
6  * io - simple library for stateful io handling.
7  *
8  * io provides a simple mechanism to write I/O servers with multiple
9  * connections.  Handling of connections is multiplexed, and function
10  * indicate what they want written or read, and what follow-on
11  * function to call on success (or failure).
12  *
13  * Example:
14  * // Given tr A-Z a-z outputs tr a-z a-z
15  * #include <ccan/io/io.h>
16  * #include <ccan/err/err.h>
17  * #include <assert.h>
18  * #include <stdlib.h>
19  * #include <signal.h>
20  * #include <sys/types.h>
21  * #include <sys/wait.h>
22  *
23  * struct buffer {
24  *      size_t max, off, rlen;
25  *      char *buf;
26  * };
27  *
28  * struct stdin_buffer {
29  *      struct io_conn *reader, *writer;
30  *      size_t len;
31  *      char inbuf[4096];
32  * };
33  *
34  * // This reads from stdin.
35  * static struct io_plan wake_writer(struct io_conn *, struct stdin_buffer *);
36  * // This writes the stdin buffer to the child.
37  * static struct io_plan wake_reader(struct io_conn *, struct stdin_buffer *);
38  *
39  * static struct io_plan wake_writer(struct io_conn *c, struct stdin_buffer *b)
40  * {
41  *      assert(c == b->reader);
42  *      io_wake(b->writer, io_write(b->inbuf, b->len, wake_reader, b));
43  *      return io_idle();
44  * }
45  *
46  * static void reader_exit(struct io_conn *c, struct stdin_buffer *b)
47  * {
48  *      assert(c == b->reader);
49  *      io_wake(b->writer, io_close(b->writer, NULL));
50  *      b->reader = NULL;
51  * }
52  *
53  * static struct io_plan wake_reader(struct io_conn *c, struct stdin_buffer *b)
54  * {
55  *      assert(c == b->writer);
56  *      if (!b->reader)
57  *              return io_close(c, NULL);
58  *      b->len = sizeof(b->inbuf);
59  *      io_wake(b->reader, io_read_partial(b->inbuf, &b->len, wake_writer, b));
60  *      return io_idle();
61  * }
62  *
63  * static void fail_child_write(struct io_conn *conn, struct stdin_buffer *b)
64  * {
65  *      if (b->reader)
66  *              err(1, "Failed writing to child.");
67  * }
68  *
69  * // This reads from the child and saves it into buffer.
70  * static struct io_plan read_from_child(struct io_conn *conn,
71  *                                       struct buffer *b)
72  * {
73  *      b->off += b->rlen;
74  *
75  *      if (b->off == b->max)
76  *              b->buf = realloc(b->buf, b->max *= 2);
77  *
78  *      b->rlen = b->max - b->off;
79  *      return io_read_partial(b->buf + b->off, &b->rlen, read_from_child, b);
80  * }
81  *
82  * // Feed a program our stdin, gather its stdout, print that at end.
83  * int main(int argc, char *argv[])
84  * {
85  *      int tochild[2], fromchild[2];
86  *      struct buffer out;
87  *      struct stdin_buffer sbuf;
88  *      int status;
89  *      size_t off;
90  *      ssize_t ret;
91  *      struct io_conn *from_child;
92  *
93  *      if (argc == 1)
94  *              errx(1, "Usage: runner <cmdline>...");
95  *
96  *      if (pipe(tochild) != 0 || pipe(fromchild) != 0)
97  *              err(1, "Creating pipes");
98  *
99  *      if (!fork()) {
100  *              // Child runs command.
101  *              close(tochild[1]);
102  *              close(fromchild[0]);
103  *
104  *              dup2(tochild[0], STDIN_FILENO);
105  *              dup2(fromchild[1], STDOUT_FILENO);
106  *              execvp(argv[1], argv + 1);
107  *              exit(127);
108  *      }
109  *
110  *      close(tochild[0]);
111  *      close(fromchild[1]);
112  *      signal(SIGPIPE, SIG_IGN);
113  *
114  *      sbuf.len = sizeof(sbuf.inbuf);
115  *      sbuf.reader = io_new_conn(STDIN_FILENO,
116  *                                io_read_partial(sbuf.inbuf, &sbuf.len,
117  *                                                wake_writer, &sbuf),
118  *                                reader_exit, &sbuf);
119  *      sbuf.writer = io_new_conn(tochild[1], io_idle(), fail_child_write,
120  *                                &sbuf);
121  *
122  *      out.max = 128;
123  *      out.off = 0;
124  *      out.rlen = 128;
125  *      out.buf = malloc(out.max);
126  *      from_child = io_new_conn(fromchild[0],
127  *                               io_read_partial(out.buf, &out.rlen,
128  *                                               read_from_child, &out),
129  *                               NULL, NULL);
130  *      if (!sbuf.reader || !sbuf.writer || !from_child)
131  *              err(1, "Allocating connections");
132  *
133  *      io_loop();
134  *      wait(&status);
135  *
136  *      for (off = 0; off < out.off; off += ret) {
137  *              ret = write(STDOUT_FILENO, out.buf+off, out.off-off);
138  *              if (ret < 0)
139  *                      err(1, "Writing stdout");
140  *      }
141  *      free(out.buf);
142  *
143  *      return WIFEXITED(status) ? WEXITSTATUS(status) : 2;
144  * }
145  *
146  * License: LGPL (v2.1 or any later version)
147  * Author: Rusty Russell <rusty@rustcorp.com.au>
148  */
149 int main(int argc, char *argv[])
150 {
151         if (argc != 2)
152                 return 1;
153
154         if (strcmp(argv[1], "depends") == 0) {
155                 printf("ccan/time\n");
156                 printf("ccan/timer\n");
157                 return 0;
158         }
159
160         return 1;
161 }