]> git.decadent.org.uk Git - nfs-utils.git/blob - support/nfs/cacheio.c
48292f8a5d49841c48f323c1b5977691396ef6be
[nfs-utils.git] / support / nfs / cacheio.c
1 /*
2  * support/nfs/cacheio.c
3  * support IO on the cache channel files in 2.5 and beyond.
4  * These use 'qwords' which are like words, but with a little quoting.
5  *
6  */
7
8
9 /*
10  * Support routines for text-based upcalls.
11  * Fields are separated by spaces.
12  * Fields are either mangled to quote space tab newline slosh with slosh
13  * or a hexified with a leading \x
14  * Record is terminated with newline.
15  *
16  */
17
18 #include <nfslib.h>
19 #include <stdio.h>
20 #include <stdio_ext.h>
21 #include <ctype.h>
22 #include <unistd.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <time.h>
27
28 void qword_add(char **bpp, int *lp, char *str)
29 {
30         char *bp = *bpp;
31         int len = *lp;
32         char c;
33
34         if (len < 0) return;
35
36         while ((c=*str++) && len)
37                 switch(c) {
38                 case ' ':
39                 case '\t':
40                 case '\n':
41                 case '\\':
42                         if (len >= 4) {
43                                 *bp++ = '\\';
44                                 *bp++ = '0' + ((c & 0300)>>6);
45                                 *bp++ = '0' + ((c & 0070)>>3);
46                                 *bp++ = '0' + ((c & 0007)>>0);
47                         }
48                         len -= 4;
49                         break;
50                 default:
51                         *bp++ = c;
52                         len--;
53                 }
54         if (c || len <1) len = -1;
55         else {
56                 *bp++ = ' ';
57                 len--;
58         }
59         *bpp = bp;
60         *lp = len;
61 }
62
63 void qword_addhex(char **bpp, int *lp, char *buf, int blen)
64 {
65         char *bp = *bpp;
66         int len = *lp;
67
68         if (len < 0) return;
69
70         if (len > 2) {
71                 *bp++ = '\\';
72                 *bp++ = 'x';
73                 len -= 2;
74                 while (blen && len >= 2) {
75                         unsigned char c = *buf++;
76                         *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
77                         *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
78                         len -= 2;
79                         blen--;
80                 }
81         }
82         if (blen || len<1) len = -1;
83         else {
84                 *bp++ = ' ';
85                 len--;
86         }
87         *bpp = bp;
88         *lp = len;
89 }
90
91 void qword_addint(char **bpp, int *lp, int n)
92 {
93         int len;
94
95         len = snprintf(*bpp, *lp, "%d ", n);
96         if (len > *lp)
97                 len = *lp;
98         *bpp += len;
99         *lp -= len;
100 }
101
102 void qword_adduint(char **bpp, int *lp, unsigned int n)
103 {
104         int len;
105
106         len = snprintf(*bpp, *lp, "%u ", n);
107         if (len > *lp)
108                 len = *lp;
109         *bpp += len;
110         *lp -= len;
111 }
112
113 void qword_addeol(char **bpp, int *lp)
114 {
115         if (*lp <= 0)
116                 return;
117         **bpp = '\n';
118         (*bpp)++;
119         (*lp)--;
120 }
121
122 static char qword_buf[8192];
123 void qword_print(FILE *f, char *str)
124 {
125         char *bp = qword_buf;
126         int len = sizeof(qword_buf);
127         qword_add(&bp, &len, str);
128         fwrite(qword_buf, bp-qword_buf, 1, f);
129 }
130
131 void qword_printhex(FILE *f, char *str, int slen)
132 {
133         char *bp = qword_buf;
134         int len = sizeof(qword_buf);
135         qword_addhex(&bp, &len, str, slen);
136         fwrite(qword_buf, bp-qword_buf, 1, f);
137 }
138
139 void qword_printint(FILE *f, int num)
140 {
141         fprintf(f, "%d ", num);
142 }
143
144 int qword_eol(FILE *f)
145 {
146         int err;
147
148         fprintf(f,"\n");
149         err = fflush(f);
150         /*
151          * We must send one line (and one line only) in a single write
152          * call.  In case of a write error, libc may accumulate the
153          * unwritten data and try to write it again later, resulting in a
154          * multi-line write.  So we must explicitly ask it to throw away
155          * any such cached data:
156          */
157         __fpurge(f);
158         return fflush(f);
159 }
160
161
162
163 #define isodigit(c) (isdigit(c) && c <= '7')
164 int qword_get(char **bpp, char *dest, int bufsize)
165 {
166         /* return bytes copied, or -1 on error */
167         char *bp = *bpp;
168         int len = 0;
169
170         while (*bp == ' ') bp++;
171
172         if (bp[0] == '\\' && bp[1] == 'x') {
173                 /* HEX STRING */
174                 bp += 2;
175                 while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
176                         int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
177                         bp++;
178                         byte <<= 4;
179                         byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
180                         *dest++ = byte;
181                         bp++;
182                         len++;
183                 }
184         } else {
185                 /* text with \nnn octal quoting */
186                 while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) {
187                         if (*bp == '\\' &&
188                             isodigit(bp[1]) && (bp[1] <= '3') &&
189                             isodigit(bp[2]) &&
190                             isodigit(bp[3])) {
191                                 int byte = (*++bp -'0');
192                                 bp++;
193                                 byte = (byte << 3) | (*bp++ - '0');
194                                 byte = (byte << 3) | (*bp++ - '0');
195                                 *dest++ = byte;
196                                 len++;
197                         } else {
198                                 *dest++ = *bp++;
199                                 len++;
200                         }
201                 }
202         }
203
204         if (*bp != ' ' && *bp != '\n' && *bp != '\0')
205                 return -1;
206         while (*bp == ' ') bp++;
207         *bpp = bp;
208         *dest = '\0';
209         return len;
210 }
211
212 int qword_get_int(char **bpp, int *anint)
213 {
214         char buf[50];
215         char *ep;
216         int rv;
217         int len = qword_get(bpp, buf, 50);
218         if (len < 0) return -1;
219         if (len ==0) return -1;
220         rv = strtol(buf, &ep, 0);
221         if (*ep) return -1;
222         *anint = rv;
223         return 0;
224 }
225
226 #define READLINE_BUFFER_INCREMENT 2048
227
228 int readline(int fd, char **buf, int *lenp)
229 {
230         /* read a line into *buf, which is malloced *len long
231          * realloc if needed until we find a \n
232          * nul out the \n and return
233          * 0 on eof, 1 on success
234          */
235         int len;
236
237         if (*lenp == 0) {
238                 char *b = malloc(READLINE_BUFFER_INCREMENT);
239                 if (b == NULL)
240                         return 0;
241                 *buf = b;
242                 *lenp = READLINE_BUFFER_INCREMENT;
243         }
244         len = read(fd, *buf, *lenp);
245         if (len <= 0)
246                 return 0;
247         while ((*buf)[len-1] != '\n') {
248         /* now the less common case.  There was no newline,
249          * so we have to keep reading after re-alloc
250          */
251                 char *new;
252                 int nl;
253                 *lenp += READLINE_BUFFER_INCREMENT;
254                 new = realloc(*buf, *lenp);
255                 if (new == NULL)
256                         return 0;
257                 *buf = new;
258                 nl = read(fd, *buf + len, *lenp - len);
259                 if (nl <= 0)
260                         return 0;
261                 len += nl;
262         }
263         (*buf)[len-1] = '\0';
264         return 1;
265 }
266
267
268 /* Check if we should use the new caching interface
269  * This succeeds iff the "nfsd" filesystem is mounted on
270  * /proc/fs/nfs
271  */
272 int
273 check_new_cache(void)
274 {
275         struct stat stb;
276         return  (stat("/proc/fs/nfs/filehandle", &stb) == 0) ||
277                 (stat("/proc/fs/nfsd/filehandle", &stb) == 0);
278 }       
279
280
281 /* flush the kNFSd caches.
282  * Set the flush time to the mtime of _PATH_ETAB or
283  * if force, to now.
284  * the caches to flush are:
285  *  auth.unix.ip nfsd.export nfsd.fh
286  */
287
288 void
289 cache_flush(int force)
290 {
291         struct stat stb;
292         int c;
293         char stime[20];
294         char path[200];
295         time_t now;
296         /* Note: the order of these caches is important.
297          * They need to be flushed in dependancy order. So
298          * a cache that references items in another cache,
299          * as nfsd.fh entries reference items in nfsd.export,
300          * must be flushed before the cache that it references.
301          */
302         static char *cachelist[] = {
303                 "auth.unix.ip",
304                 "auth.unix.gid",
305                 "nfsd.fh",
306                 "nfsd.export",
307                 NULL
308         };
309         now = time(0);
310         if (force ||
311             stat(_PATH_ETAB, &stb) != 0 ||
312             stb.st_mtime > now)
313                 stb.st_mtime = time(0);
314         
315         sprintf(stime, "%ld\n", stb.st_mtime);
316         for (c=0; cachelist[c]; c++) {
317                 int fd;
318                 sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]);
319                 fd = open(path, O_RDWR);
320                 if (fd >= 0) {
321                         write(fd, stime, strlen(stime));
322                         close(fd);
323                 }
324         }
325 }