chiark / gitweb /
Merge Peter Maydell's changes.
[chiark-utils.git] / backup / readbuffer.c
1 /*
2  * readbuffer.c
3  *
4  * Copyright (C) 1997,1998 Ian Jackson <ian@chiark.greenend.org.uk>
5  *
6  * This is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2,
9  * or (at your option) any later version.
10  *
11  * This is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this file; if not, write to the Free Software
18  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19  *
20  */
21
22 #include <sys/time.h>
23 #include <sys/types.h>
24 #include <assert.h>
25 #include <fcntl.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <unistd.h>
29
30 #define BUFFER 16*1024*1024
31 #define WAITEMPTY ((BUFFER*1)/4)
32
33 static inline int min(int a, int b) { return a<=b ? a : b; }
34
35 static void nonblock(int fd) {
36   int r;
37   r= fcntl(fd,F_GETFL,0); if (r == -1) { perror("fcntl getfl"); exit(1); }
38   r |= O_NDELAY;
39   if (fcntl(fd,F_SETFL,r) == -1) { perror("fcntl setfl"); exit(1); }
40 }
41
42 int main(int argc, const char *const *argv) {
43   static unsigned char buf[BUFFER];
44   
45   unsigned char *wp, *rp;
46   int used,r,reading,seeneof;
47   fd_set readfds;
48   fd_set writefds;
49
50   used=0; wp=rp=buf; reading=1; seeneof=0;
51   nonblock(0); nonblock(1);
52
53   if (argv[1] && !strcmp(argv[1],"--mlock")) {
54     if (mlock(buf,sizeof(buf))) { perror("mlock"); exit(1); }
55     argv++; argc--;
56   }
57   if (argv[1]) { fputs("usage: readbuffer [--mlock]\n",stderr); exit(1); }
58
59   while (!seeneof || used) {
60     FD_ZERO(&readfds);
61     if (reading) {
62       if (used<BUFFER-1) {
63         FD_SET(0,&readfds);
64       } else {
65 /*fprintf(stderr,"\t buffers full - stopping\n");*/
66         reading=0;
67       }
68     }
69     FD_ZERO(&writefds); if (used) FD_SET(1,&writefds);
70 /*fprintf(stderr,"used %6d reading %d seeneof %d wp %8lx rp %8lx read %d write %d\n",
71         used,reading,seeneof,(unsigned long)(wp-buf),(unsigned long)(rp-buf),
72         FD_ISSET(0,&readfds),FD_ISSET(1,&writefds));*/
73     r= select(2,&readfds,&writefds,0,0);
74 /*fprintf(stderr,"\t readable %d writeable %d\n",
75         FD_ISSET(0,&readfds),FD_ISSET(1,&writefds));*/
76     if (r == -1) {
77       if (errno == EINTR) continue;
78       perror("select"); exit(1);
79     }
80     if (FD_ISSET(0,&readfds)) {
81       r= read(0,rp,min(BUFFER-1-used,buf+BUFFER-rp));
82       if (!r) {
83 /*fprintf(stderr,"\t eof detected\n");*/
84         seeneof=1; reading=0;
85       } else if (r<0) {
86         if (!(errno == EAGAIN || errno == EINTR)) { perror("read"); exit(1); }
87 /*fprintf(stderr,"\t read transient error\n");*/
88       } else {
89 /*fprintf(stderr,"\t read %d\n",r);*/
90         used+= r;
91         rp+= r;
92         if (rp == buf+BUFFER) rp=buf;
93       }
94     }
95     if (FD_ISSET(1,&writefds)) {
96       assert(used);
97       r= write(1,wp,min(used,buf+BUFFER-wp));
98       if (r<=0) {
99         if (!(errno == EAGAIN || errno == EINTR)) { perror("write"); exit(1); }
100 /*fprintf(stderr,"\t write transient error\n");*/
101       } else {
102 /*fprintf(stderr,"\t wrote %d\n",r);*/
103         used-= r;
104         wp+= r;
105         if (wp == buf+BUFFER) wp=buf;
106       }
107       if (used < WAITEMPTY && !seeneof) {
108 /*fprintf(stderr,"\t starting writes\n");*/
109         reading=1;
110       }
111     }
112   }
113   exit(0);
114 }