]> git.decadent.org.uk Git - nfs-utils.git/blob - support/nfs/cacheio.c
9d271cd4733d77328a6f2b3e5ec8a80b5da8a73b
[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 static char qword_buf[8192];
92 void qword_print(FILE *f, char *str)
93 {
94         char *bp = qword_buf;
95         int len = sizeof(qword_buf);
96         qword_add(&bp, &len, str);
97         fwrite(qword_buf, bp-qword_buf, 1, f);
98 }
99
100 void qword_printhex(FILE *f, char *str, int slen)
101 {
102         char *bp = qword_buf;
103         int len = sizeof(qword_buf);
104         qword_addhex(&bp, &len, str, slen);
105         fwrite(qword_buf, bp-qword_buf, 1, f);
106 }
107
108 void qword_printint(FILE *f, int num)
109 {
110         fprintf(f, "%d ", num);
111 }
112
113 int qword_eol(FILE *f)
114 {
115         int err;
116
117         fprintf(f,"\n");
118         err = fflush(f);
119         /*
120          * We must send one line (and one line only) in a single write
121          * call.  In case of a write error, libc may accumulate the
122          * unwritten data and try to write it again later, resulting in a
123          * multi-line write.  So we must explicitly ask it to throw away
124          * any such cached data:
125          */
126         __fpurge(f);
127         return fflush(f);
128 }
129
130
131
132 #define isodigit(c) (isdigit(c) && c <= '7')
133 int qword_get(char **bpp, char *dest, int bufsize)
134 {
135         /* return bytes copied, or -1 on error */
136         char *bp = *bpp;
137         int len = 0;
138
139         while (*bp == ' ') bp++;
140
141         if (bp[0] == '\\' && bp[1] == 'x') {
142                 /* HEX STRING */
143                 bp += 2;
144                 while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
145                         int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
146                         bp++;
147                         byte <<= 4;
148                         byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
149                         *dest++ = byte;
150                         bp++;
151                         len++;
152                 }
153         } else {
154                 /* text with \nnn octal quoting */
155                 while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) {
156                         if (*bp == '\\' &&
157                             isodigit(bp[1]) && (bp[1] <= '3') &&
158                             isodigit(bp[2]) &&
159                             isodigit(bp[3])) {
160                                 int byte = (*++bp -'0');
161                                 bp++;
162                                 byte = (byte << 3) | (*bp++ - '0');
163                                 byte = (byte << 3) | (*bp++ - '0');
164                                 *dest++ = byte;
165                                 len++;
166                         } else {
167                                 *dest++ = *bp++;
168                                 len++;
169                         }
170                 }
171         }
172
173         if (*bp != ' ' && *bp != '\n' && *bp != '\0')
174                 return -1;
175         while (*bp == ' ') bp++;
176         *bpp = bp;
177         *dest = '\0';
178         return len;
179 }
180
181 int qword_get_int(char **bpp, int *anint)
182 {
183         char buf[50];
184         char *ep;
185         int rv;
186         int len = qword_get(bpp, buf, 50);
187         if (len < 0) return -1;
188         if (len ==0) return -1;
189         rv = strtol(buf, &ep, 0);
190         if (*ep) return -1;
191         *anint = rv;
192         return 0;
193 }
194
195 int readline(int fd, char **buf, int *lenp)
196 {
197         /* read a line into *buf, which is malloced *len long
198          * realloc if needed until we find a \n
199          * nul out the \n and return
200          * 0 of eof, 1 of success 
201          */
202         int len = *lenp;
203
204         if (len == 0) {
205                 char *b = malloc(128);
206                 if (b == NULL)
207                         return 0;
208                 *buf = b;
209                 *lenp = 128;
210         }
211         len = read(fd, *buf, len);
212         if (len <= 0)
213                 return 0;
214         while ((*buf)[len-1] != '\n') {
215         /* now the less common case.  There was no newline,
216          * so we have to keep reading after re-alloc
217          */
218                 char *new;
219                 int nl;
220                 *lenp *= 2;
221                 new = realloc(*buf, *lenp);
222                 if (new == NULL)
223                         return 0;
224                 *buf = new;
225                 nl = read(fd, *buf + len, *lenp - len);
226                 if (nl <= 0)
227                         return 0;
228                 len += nl;
229         }
230         (*buf)[len-1] = '\0';
231         return 1;
232 }
233
234
235 /* Check if we should use the new caching interface
236  * This succeeds iff the "nfsd" filesystem is mounted on
237  * /proc/fs/nfs
238  */
239 int
240 check_new_cache(void)
241 {
242         struct stat stb;
243         return  (stat("/proc/fs/nfs/filehandle", &stb) == 0) ||
244                 (stat("/proc/fs/nfsd/filehandle", &stb) == 0);
245 }       
246
247
248 /* flush the kNFSd caches.
249  * Set the flush time to the mtime of _PATH_ETAB or
250  * if force, to now.
251  * the caches to flush are:
252  *  auth.unix.ip nfsd.export nfsd.fh
253  */
254
255 void
256 cache_flush(int force)
257 {
258         struct stat stb;
259         int c;
260         char stime[20];
261         char path[200];
262         time_t now;
263         /* Note: the order of these caches is important.
264          * They need to be flushed in dependancy order. So
265          * a cache that references items in another cache,
266          * as nfsd.fh entries reference items in nfsd.export,
267          * must be flushed before the cache that it references.
268          */
269         static char *cachelist[] = {
270                 "auth.unix.ip",
271                 "auth.unix.gid",
272                 "nfsd.fh",
273                 "nfsd.export",
274                 NULL
275         };
276         now = time(0);
277         if (force ||
278             stat(_PATH_ETAB, &stb) != 0 ||
279             stb.st_mtime > now)
280                 stb.st_mtime = time(0);
281         
282         sprintf(stime, "%ld\n", stb.st_mtime);
283         for (c=0; cachelist[c]; c++) {
284                 int fd;
285                 sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]);
286                 fd = open(path, O_RDWR);
287                 if (fd >= 0) {
288                         write(fd, stime, strlen(stime));
289                         close(fd);
290                 }
291         }
292 }