d7ad4293762f4b6dd583fec668cb0ea9df47b733
[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 <ctype.h>
21 #include <unistd.h>
22 #include <sys/types.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <time.h>
26
27 void qword_add(char **bpp, int *lp, char *str)
28 {
29         char *bp = *bpp;
30         int len = *lp;
31         char c;
32
33         if (len < 0) return;
34
35         while ((c=*str++) && len)
36                 switch(c) {
37                 case ' ':
38                 case '\t':
39                 case '\n':
40                 case '\\':
41                         if (len >= 4) {
42                                 *bp++ = '\\';
43                                 *bp++ = '0' + ((c & 0300)>>6);
44                                 *bp++ = '0' + ((c & 0070)>>3);
45                                 *bp++ = '0' + ((c & 0007)>>0);
46                         }
47                         len -= 4;
48                         break;
49                 default:
50                         *bp++ = c;
51                         len--;
52                 }
53         if (c || len <1) len = -1;
54         else {
55                 *bp++ = ' ';
56                 len--;
57         }
58         *bpp = bp;
59         *lp = len;
60 }
61
62 void qword_addhex(char **bpp, int *lp, char *buf, int blen)
63 {
64         char *bp = *bpp;
65         int len = *lp;
66
67         if (len < 0) return;
68
69         if (len > 2) {
70                 *bp++ = '\\';
71                 *bp++ = 'x';
72                 len -= 2;
73                 while (blen && len >= 2) {
74                         unsigned char c = *buf++;
75                         *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
76                         *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
77                         len -= 2;
78                         blen--;
79                 }
80         }
81         if (blen || len<1) len = -1;
82         else {
83                 *bp++ = ' ';
84                 len--;
85         }
86         *bpp = bp;
87         *lp = len;
88 }
89
90 static char qword_buf[8192];
91 void qword_print(FILE *f, char *str)
92 {
93         char *bp = qword_buf;
94         int len = sizeof(qword_buf);
95         qword_add(&bp, &len, str);
96         fwrite(qword_buf, bp-qword_buf, 1, f);
97 }
98
99 void qword_printhex(FILE *f, char *str, int slen)
100 {
101         char *bp = qword_buf;
102         int len = sizeof(qword_buf);
103         qword_addhex(&bp, &len, str, slen);
104         fwrite(qword_buf, bp-qword_buf, 1, f);
105 }
106
107 void qword_printint(FILE *f, int num)
108 {
109         fprintf(f, "%d ", num);
110 }
111
112 void qword_eol(FILE *f)
113 {
114         fprintf(f,"\n");
115         fflush(f);
116 }
117
118
119
120 #define isodigit(c) (isdigit(c) && c <= '7')
121 int qword_get(char **bpp, char *dest, int bufsize)
122 {
123         /* return bytes copied, or -1 on error */
124         char *bp = *bpp;
125         int len = 0;
126
127         while (*bp == ' ') bp++;
128
129         if (bp[0] == '\\' && bp[1] == 'x') {
130                 /* HEX STRING */
131                 bp += 2;
132                 while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
133                         int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
134                         bp++;
135                         byte <<= 4;
136                         byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
137                         *dest++ = byte;
138                         bp++;
139                         len++;
140                 }
141         } else {
142                 /* text with \nnn octal quoting */
143                 while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) {
144                         if (*bp == '\\' &&
145                             isodigit(bp[1]) && (bp[1] <= '3') &&
146                             isodigit(bp[2]) &&
147                             isodigit(bp[3])) {
148                                 int byte = (*++bp -'0');
149                                 bp++;
150                                 byte = (byte << 3) | (*bp++ - '0');
151                                 byte = (byte << 3) | (*bp++ - '0');
152                                 *dest++ = byte;
153                                 len++;
154                         } else {
155                                 *dest++ = *bp++;
156                                 len++;
157                         }
158                 }
159         }
160
161         if (*bp != ' ' && *bp != '\n' && *bp != '\0')
162                 return -1;
163         while (*bp == ' ') bp++;
164         *bpp = bp;
165         *dest = '\0';
166         return len;
167 }
168
169 int qword_get_int(char **bpp, int *anint)
170 {
171         char buf[50];
172         char *ep;
173         int rv;
174         int len = qword_get(bpp, buf, 50);
175         if (len < 0) return -1;
176         if (len ==0) return -1;
177         rv = strtol(buf, &ep, 0);
178         if (*ep) return -1;
179         *anint = rv;
180         return 0;
181 }
182
183 int readline(int fd, char **buf, int *lenp)
184 {
185         /* read a line into *buf, which is malloced *len long
186          * realloc if needed until we find a \n
187          * nul out the \n and return
188          * 0 of eof, 1 of success 
189          */
190         int len = *lenp;
191
192         if (len == 0) {
193                 char *b = malloc(128);
194                 if (b == NULL)
195                         return 0;
196                 *buf = b;
197                 *lenp = 128;
198         }
199         len = read(fd, *buf, len);
200         if (len <= 0)
201                 return 0;
202         while ((*buf)[len-1] != '\n') {
203         /* now the less common case.  There was no newline,
204          * so we have to keep reading after re-alloc
205          */
206                 char *new;
207                 int nl;
208                 *lenp *= 2;
209                 new = realloc(*buf, *lenp);
210                 if (new == NULL)
211                         return 0;
212                 *buf = new;
213                 nl = read(fd, *buf + len, *lenp - len);
214                 if (nl <= 0)
215                         return 0;
216                 len += nl;
217         }
218         (*buf)[len-1] = '\0';
219         return 1;
220 }
221
222
223 /* Check if we should use the new caching interface
224  * This succeeds iff the "nfsd" filesystem is mounted on
225  * /proc/fs/nfs
226  */
227 int
228 check_new_cache(void)
229 {
230         struct stat stb;
231         return  (stat("/proc/fs/nfs/filehandle", &stb) == 0) ||
232                 (stat("/proc/fs/nfsd/filehandle", &stb) == 0);
233 }       
234
235
236 /* flush the kNFSd caches.
237  * Set the flush time to the mtime of _PATH_ETAB or
238  * if force, to now.
239  * the caches to flush are:
240  *  auth.unix.ip nfsd.export nfsd.fh
241  */
242
243 void
244 cache_flush(int force)
245 {
246         struct stat stb;
247         int c;
248         char stime[20];
249         char path[200];
250         /* Note: the order of these caches is important.
251          * The need to be flushed in dependancy order. So
252          * a cache that references items in another cache,
253          * as nfsd.fh entries reference items in nfsd.export,
254          * must be flushed before the cache that it references.
255          */
256         static char *cachelist[] = {
257                 "auth.unix.ip",
258                 "nfsd.fh",
259                 "nfsd.export",
260                 NULL
261         };
262         stb.st_mtime = time(0);
263         if (!force)
264                 stat(_PATH_ETAB, &stb);
265         
266         sprintf(stime, "%ld\n", stb.st_mtime);
267         for (c=0; cachelist[c]; c++) {
268                 int fd;
269                 sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]);
270                 fd = open(path, O_RDWR);
271                 if (fd >= 0) {
272                         write(fd, stime, strlen(stime));
273                         close(fd);
274                 }
275         }
276 }