chiark / gitweb /
Found on anarres in /etc.
[chiark-utils.git] / backup / readbuffer.c
1 /**/
2
3 #include <sys/time.h>
4 #include <sys/types.h>
5 #include <assert.h>
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <errno.h>
9 #include <unistd.h>
10 #include <sys/mman.h>
11
12 #define BUFFER 16*1024*1024
13 #define WAITEMPTY ((BUFFER*1)/4)
14
15 static inline int min(int a, int b) { return a<=b ? a : b; }
16
17 static void nonblock(int fd) {
18   int r;
19   r= fcntl(fd,F_GETFL,0); if (r == -1) { perror("fcntl getfl"); exit(1); }
20   r |= O_NDELAY;
21   if (fcntl(fd,F_SETFL,r) == -1) { perror("fcntl setfl"); exit(1); }
22 }
23
24 int main(int argc, const char *const *argv) {
25   static unsigned char buf[BUFFER];
26   
27   unsigned char *wp, *rp;
28   int used,r,reading,seeneof;
29   fd_set readfds;
30   fd_set writefds;
31
32   used=0; wp=rp=buf; reading=1; seeneof=0;
33   nonblock(0); nonblock(1);
34   if (argv[1] && !strcmp(argv[1],"--mlock")) {
35     if (mlock(buf,sizeof(buf))) { perror("mlock"); exit(1); }
36     argv++; argc--;
37   }
38   if (argv[1]) { fputs("usage: readbuffer [--mlock]\n",stderr); exit(1); }
39   while (!seeneof || used) {
40     FD_ZERO(&readfds);
41     if (reading) {
42       if (used<BUFFER-1) {
43         FD_SET(0,&readfds);
44       } else {
45 /*fprintf(stderr,"\t buffers full - stopping\n");*/
46         reading=0;
47       }
48     }
49     FD_ZERO(&writefds); if (used) FD_SET(1,&writefds);
50 /*fprintf(stderr,"used %6d reading %d seeneof %d wp %8lx rp %8lx read %d write %d\n",
51         used,reading,seeneof,(unsigned long)(wp-buf),(unsigned long)(rp-buf),
52         FD_ISSET(0,&readfds),FD_ISSET(1,&writefds));*/
53     r= select(2,&readfds,&writefds,0,0);
54 /*fprintf(stderr,"\t readable %d writeable %d\n",
55         FD_ISSET(0,&readfds),FD_ISSET(1,&writefds));*/
56     if (r == -1) {
57       if (errno == EINTR) continue;
58       perror("select"); exit(1);
59     }
60     if (FD_ISSET(0,&readfds)) {
61       r= read(0,rp,min(BUFFER-1-used,buf+BUFFER-rp));
62       if (!r) {
63 /*fprintf(stderr,"\t eof detected\n");*/
64         seeneof=1; reading=0;
65       } else if (r<0) {
66         if (!(errno == EAGAIN || errno == EINTR)) { perror("read"); exit(1); }
67 /*fprintf(stderr,"\t read transient error\n");*/
68       } else {
69 /*fprintf(stderr,"\t read %d\n",r);*/
70         used+= r;
71         rp+= r;
72         if (rp == buf+BUFFER) rp=buf;
73       }
74     }
75     if (FD_ISSET(1,&writefds)) {
76       assert(used);
77       r= write(1,wp,min(used,buf+BUFFER-wp));
78       if (r<=0) {
79         if (!(errno == EAGAIN || errno == EINTR)) { perror("write"); exit(1); }
80 /*fprintf(stderr,"\t write transient error\n");*/
81       } else {
82 /*fprintf(stderr,"\t wrote %d\n",r);*/
83         used-= r;
84         wp+= r;
85         if (wp == buf+BUFFER) wp=buf;
86       }
87       if (used < WAITEMPTY && !seeneof) {
88 /*fprintf(stderr,"\t starting writes\n");*/
89         reading=1;
90       }
91     }
92   }
93   exit(0);
94 }