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.
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.
20 #include <stdio_ext.h>
23 #include <sys/types.h>
29 void qword_add(char **bpp, int *lp, char *str)
37 while ((c=*str++) && len)
45 *bp++ = '0' + ((c & 0300)>>6);
46 *bp++ = '0' + ((c & 0070)>>3);
47 *bp++ = '0' + ((c & 0007)>>0);
55 if (c || len <1) len = -1;
64 void qword_addhex(char **bpp, int *lp, char *buf, int blen)
75 while (blen && len >= 2) {
76 unsigned char c = *buf++;
77 *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
78 *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
83 if (blen || len<1) len = -1;
92 void qword_addint(char **bpp, int *lp, int n)
96 len = snprintf(*bpp, *lp, "%d ", n);
103 void qword_adduint(char **bpp, int *lp, unsigned int n)
107 len = snprintf(*bpp, *lp, "%u ", n);
114 void qword_addeol(char **bpp, int *lp)
123 static char qword_buf[8192];
124 void qword_print(FILE *f, char *str)
126 char *bp = qword_buf;
127 int len = sizeof(qword_buf);
128 qword_add(&bp, &len, str);
129 if (fwrite(qword_buf, bp-qword_buf, 1, f) != 1) {
130 xlog_warn("qword_print: fwrite failed: errno %d (%s)",
131 errno, strerror(errno));
135 void qword_printhex(FILE *f, char *str, int slen)
137 char *bp = qword_buf;
138 int len = sizeof(qword_buf);
139 qword_addhex(&bp, &len, str, slen);
140 if (fwrite(qword_buf, bp-qword_buf, 1, f) != 1) {
141 xlog_warn("qword_printhex: fwrite failed: errno %d (%s)",
142 errno, strerror(errno));
146 void qword_printint(FILE *f, int num)
148 fprintf(f, "%d ", num);
151 void qword_printuint(FILE *f, unsigned int num)
153 fprintf(f, "%u ", num);
156 void qword_printtimefrom(FILE *f, unsigned int num)
158 fprintf(f, "%lu ", time(0) + num);
161 int qword_eol(FILE *f)
165 err = fprintf(f,"\n");
167 xlog_warn("qword_eol: fprintf failed: errno %d (%s)",
168 errno, strerror(errno));
172 xlog_warn("qword_eol: fflush failed: errno %d (%s)",
173 errno, strerror(errno));
177 * We must send one line (and one line only) in a single write
178 * call. In case of a write error, libc may accumulate the
179 * unwritten data and try to write it again later, resulting in a
180 * multi-line write. So we must explicitly ask it to throw away
181 * any such cached data. But we return any original error
182 * indication to the caller.
191 #define isodigit(c) (isdigit(c) && c <= '7')
192 int qword_get(char **bpp, char *dest, int bufsize)
194 /* return bytes copied, or -1 on error */
198 while (*bp == ' ') bp++;
200 if (bp[0] == '\\' && bp[1] == 'x') {
203 while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
204 int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
207 byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
213 /* text with \nnn octal quoting */
214 while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) {
216 isodigit(bp[1]) && (bp[1] <= '3') &&
219 int byte = (*++bp -'0');
221 byte = (byte << 3) | (*bp++ - '0');
222 byte = (byte << 3) | (*bp++ - '0');
232 if (*bp != ' ' && *bp != '\n' && *bp != '\0')
234 while (*bp == ' ') bp++;
240 int qword_get_int(char **bpp, int *anint)
245 int len = qword_get(bpp, buf, 50);
246 if (len < 0) return -1;
247 if (len ==0) return -1;
248 rv = strtol(buf, &ep, 0);
254 int qword_get_uint(char **bpp, unsigned int *anint)
259 int len = qword_get(bpp, buf, 50);
260 if (len < 0) return -1;
261 if (len ==0) return -1;
262 rv = strtoul(buf, &ep, 0);
268 #define READLINE_BUFFER_INCREMENT 2048
270 int readline(int fd, char **buf, int *lenp)
272 /* read a line into *buf, which is malloced *len long
273 * realloc if needed until we find a \n
274 * nul out the \n and return
275 * 0 on eof, 1 on success
280 char *b = malloc(READLINE_BUFFER_INCREMENT);
284 *lenp = READLINE_BUFFER_INCREMENT;
286 len = read(fd, *buf, *lenp);
289 while ((*buf)[len-1] != '\n') {
290 /* now the less common case. There was no newline,
291 * so we have to keep reading after re-alloc
295 *lenp += READLINE_BUFFER_INCREMENT;
296 new = realloc(*buf, *lenp);
300 nl = read(fd, *buf + len, *lenp - len);
305 (*buf)[len-1] = '\0';
310 /* Check if we should use the new caching interface
311 * This succeeds iff the "nfsd" filesystem is mounted on
315 check_new_cache(void)
317 return (access("/proc/fs/nfs/filehandle", F_OK) == 0) ||
318 (access("/proc/fs/nfsd/filehandle", F_OK) == 0);
322 /* flush the kNFSd caches.
323 * Set the flush time to the mtime of _PATH_ETAB or
325 * the caches to flush are:
326 * auth.unix.ip nfsd.export nfsd.fh
330 cache_flush(int force)
337 /* Note: the order of these caches is important.
338 * They need to be flushed in dependancy order. So
339 * a cache that references items in another cache,
340 * as nfsd.fh entries reference items in nfsd.export,
341 * must be flushed before the cache that it references.
343 static char *cachelist[] = {
352 stat(_PATH_ETAB, &stb) != 0 ||
354 stb.st_mtime = time(0);
356 sprintf(stime, "%ld\n", stb.st_mtime);
357 for (c=0; cachelist[c]; c++) {
359 sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]);
360 fd = open(path, O_RDWR);
362 if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) {
363 xlog_warn("Writing to '%s' failed: errno %d (%s)",
364 path, errno, strerror(errno));