chiark / gitweb /
f2ec48da0e5a00086b8884e8e1afc0de36f8d6d7
[chiark-utils.git] / cprogs / rwbuffer.c
1 /*
2  * rwbuffer.c
3  * common definitions for readbuffer/writebuffer
4  *
5  * readbuffer and writebuffer are:
6  *  Copyright (C) 1997-1998,2000-2001 Ian Jackson <ian@chiark.greenend.org.uk>
7  *
8  * readbuffer is part of chiark backup, a system for backing up GNU/Linux and
9  * other UN*X-compatible machines, as used on chiark.greenend.org.uk.
10  * chiark backup is:
11  *  Copyright (C) 1997-1998,2000-2001 Ian Jackson <ian@chiark.greenend.org.uk>
12  *  Copyright (C) 1999 Peter Maydell <pmaydell@chiark.greenend.org.uk>
13  *
14  * This is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as
16  * published by the Free Software Foundation; either version 2,
17  * or (at your option) any later version.
18  *
19  * This is distributed in the hope that it will be useful, but
20  * WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public
25  * License along with this file; if not, write to the Free Software
26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27  *
28  */
29
30 #include "rwbuffer.h"
31
32 #ifndef RWBUFFER_SIZE_MB_DEF
33 #define RWBUFFER_SIZE_MB_DEF 16
34 #endif
35
36 #ifndef RWBUFFER_SIZE_MB_MAX
37 #define RWBUFFER_SIZE_MB_MAX 512
38 #endif
39
40 unsigned char *buf, *wp, *rp;
41 int used, seeneof, maxselfd;
42 size_t buffersize;
43 fd_set readfds;
44 fd_set writefds;
45
46 static int opt_mlock=0;
47
48 int min(int a, int b) { return a<=b ? a : b; }
49
50 static void usage(FILE *f) {
51   if (fprintf(f,"usage: %s [--mlock] [<megabytes>]\n",progname) < 0)
52     { perror("print usage"); exit(16); }
53 }
54
55 static void usageerr(const char *what) {
56   fprintf(stderr,"%s: bad usage: %s\n",progname,what);
57   usage(stderr);
58   exit(12);
59 }
60
61 void nonblock(int fd, int yesno) {
62   int r;
63   r= fcntl(fd,F_GETFL,0); if (r == -1) { perror("fcntl getfl"); exit(8); }
64   if (yesno) r |= O_NDELAY;
65   else r &= ~O_NDELAY;
66   if (fcntl(fd,F_SETFL,r) == -1) { perror("fcntl setfl"); exit(8); }
67 }
68
69 static void unnonblock(void) {
70   nonblock(0,0); nonblock(1,0);
71 }
72
73 void startupcore(void) {
74   buf= xmalloc(buffersize);
75
76   if (opt_mlock) {
77     if (mlock(buf,buffersize)) { perror("mlock"); exit(2); }
78   }
79
80   used=0; wp=rp=buf; seeneof=0;
81   if (atexit(unnonblock)) { perror("atexit"); exit(16); }
82 }
83
84 void startup(const char *const *argv) {
85   const char *arg;
86   char *ep;
87   unsigned long opt_buffersize=RWBUFFER_SIZE_MB_DEF;
88   
89   assert(argv[0]);
90   
91   while ((arg= *++argv)) {
92     if (!strcmp(arg,"--mlock")) {
93       opt_mlock= 1;
94     } else if (isdigit((unsigned char)arg[0])) {
95       opt_buffersize= strtoul(arg,&ep,0);
96       if (opt_buffersize > RWBUFFER_SIZE_MB_MAX)
97         usageerr("buffer size too big");
98     } else {
99       usageerr("invalid option");
100     }
101   }
102
103   buffersize= opt_buffersize*1024*1024;
104   startupcore();
105   nonblock(0,1); nonblock(1,1);
106 }
107
108 void *xmalloc(size_t sz) {
109   void *r= malloc(sz); if (!r) { perror("malloc"); exit(6); }; return r;
110 }
111
112 void callselect(void) {
113   int r;
114   
115   for (;;) {
116     r= select(maxselfd,&readfds,&writefds,0,0);
117     if (r != -1) return;
118     if (errno != EINTR) {
119       perror("select"); exit(4);
120     }
121   }
122 }