+2003-03-26 NeilBrown <neilb@cse.unsw.edu.au>
+
+ * support/nfs/cacheio.c: New File - support for read/writing
+ to export cache in /proc/rpc/*/channel
+ * support/nfs/Makefile: compile cacheio.c
+ * support/include/nfslib.h: declare cacheio.c functions
+ * support/nfs/nfsexport.c: export and unexport through
+ /proc/rpc/*/channel if possible, as old syscall interface
+ may not survive into 2.6 on all architectures.
+
2003-02-19 NeilBrown <neilb@cse.unsw.edu.au>
Ben Leslie <benno@sesgroup.net>
struct nfs_fh_len * getfh(struct sockaddr *addr, const char *);
struct nfs_fh_len * getfh_size(struct sockaddr *addr, const char *, int size);
+void qword_print(FILE *f, char *str);
+void qword_printhex(FILE *f, char *str, int slen);
+void qword_printint(FILE *f, int num);
+void qword_eol(FILE *f);
+
/* lockd. */
int lockdsvc();
OBJS = exports.o rmtab.o xio.o \
rpcmisc.o rpcdispatch.o xlog.o xmalloc.o wildmat.o \
nfssvc.o nfsclient.o nfsexport.o getfh.o nfsctl.o \
- lockdsvc.o svc_socket.o
+ lockdsvc.o svc_socket.o cacheio.o
include $(TOP)rules.mk
--- /dev/null
+/*
+ * support/nfs/cacheio.c
+ * support IO on the cache channel files in 2.5 and beyond.
+ * These use 'qwords' which are like words, but with a little quoting.
+ *
+ */
+
+
+/*
+ * Support routines for text-based upcalls.
+ * Fields are separated by spaces.
+ * Fields are either mangled to quote space tab newline slosh with slosh
+ * or a hexified with a leading \x
+ * Record is terminated with newline.
+ *
+ */
+
+#include <nfslib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+
+void qword_add(char **bpp, int *lp, char *str)
+{
+ char *bp = *bpp;
+ int len = *lp;
+ char c;
+
+ if (len < 0) return;
+
+ while ((c=*str++) && len)
+ switch(c) {
+ case ' ':
+ case '\t':
+ case '\n':
+ case '\\':
+ if (len >= 4) {
+ *bp++ = '\\';
+ *bp++ = '0' + ((c & 0300)>>6);
+ *bp++ = '0' + ((c & 0070)>>3);
+ *bp++ = '0' + ((c & 0007)>>0);
+ }
+ len -= 4;
+ break;
+ default:
+ *bp++ = c;
+ len--;
+ }
+ if (c || len <1) len = -1;
+ else {
+ *bp++ = ' ';
+ len--;
+ }
+ *bpp = bp;
+ *lp = len;
+}
+
+void qword_addhex(char **bpp, int *lp, char *buf, int blen)
+{
+ char *bp = *bpp;
+ int len = *lp;
+
+ if (len < 0) return;
+
+ if (len > 2) {
+ *bp++ = '\\';
+ *bp++ = 'x';
+ len -= 2;
+ while (blen && len >= 2) {
+ unsigned char c = *buf++;
+ *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
+ *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
+ len -= 2;
+ blen--;
+ }
+ }
+ if (blen || len<1) len = -1;
+ else {
+ *bp++ = ' ';
+ len--;
+ }
+ *bpp = bp;
+ *lp = len;
+}
+
+static char qword_buf[8192];
+void qword_print(FILE *f, char *str)
+{
+ char *bp = qword_buf;
+ int len = sizeof(qword_buf);
+ qword_add(&bp, &len, str);
+ fwrite(qword_buf, bp-qword_buf, 1, f);
+}
+
+void qword_printhex(FILE *f, char *str, int slen)
+{
+ char *bp = qword_buf;
+ int len = sizeof(qword_buf);
+ qword_addhex(&bp, &len, str, slen);
+ fwrite(qword_buf, bp-qword_buf, 1, f);
+}
+
+void qword_printint(FILE *f, int num)
+{
+ fprintf(f, "%d ", num);
+}
+
+void qword_eol(FILE *f)
+{
+ fprintf(f,"\n");
+ fflush(f);
+}
+
+
+
+#define isodigit(c) (isdigit(c) && c <= '7')
+int qword_get(char **bpp, char *dest, int bufsize)
+{
+ /* return bytes copied, or -1 on error */
+ char *bp = *bpp;
+ int len = 0;
+
+ while (*bp == ' ') bp++;
+
+ if (bp[0] == '\\' && bp[1] == 'x') {
+ /* HEX STRING */
+ bp += 2;
+ while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) {
+ int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
+ bp++;
+ byte <<= 4;
+ byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10;
+ *dest++ = byte;
+ bp++;
+ len++;
+ }
+ } else {
+ /* text with \nnn octal quoting */
+ while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) {
+ if (*bp == '\\' &&
+ isodigit(bp[1]) && (bp[1] <= '3') &&
+ isodigit(bp[2]) &&
+ isodigit(bp[3])) {
+ int byte = (*++bp -'0');
+ bp++;
+ byte = (byte << 3) | (*bp++ - '0');
+ byte = (byte << 3) | (*bp++ - '0');
+ *dest++ = byte;
+ len++;
+ } else {
+ *dest++ = *bp++;
+ len++;
+ }
+ }
+ }
+
+ if (*bp != ' ' && *bp != '\n' && *bp != '\0')
+ return -1;
+ while (*bp == ' ') bp++;
+ *bpp = bp;
+ *dest = '\0';
+ return len;
+}
+
+int qword_get_int(char **bpp, int *anint)
+{
+ char buf[50];
+ char *ep;
+ int rv;
+ int len = qword_get(bpp, buf, 50);
+ if (len < 0) return -1;
+ if (len ==0) return -1;
+ rv = strtol(buf, &ep, 0);
+ if (*ep) return -1;
+ *anint = rv;
+ return 0;
+}
+
+int readline(int fd, char **buf, int *lenp)
+{
+ /* read a line into *buf, which is malloced *len long
+ * realloc if needed until we find a \n
+ * nul out the \n and return
+ * 0 of eof, 1 of success
+ */
+ int len = *lenp;
+
+ if (len == 0) {
+ char *b = malloc(128);
+ if (b == NULL)
+ return 0;
+ *buf = b;
+ *lenp = 128;
+ }
+ len = read(fd, *buf, len);
+ if (len <= 0)
+ return 0;
+ while ((*buf)[len-1] != '\n') {
+ /* now the less common case. There was no newline,
+ * so we have to keep reading after re-alloc
+ */
+ char *new;
+ int nl;
+ *lenp += 128;
+ new = realloc(*buf, *lenp);
+ if (new == NULL)
+ return 0;
+ nl = read(fd, *buf +len, *lenp - len);
+ if (nl <= 0 )
+ return 0;
+ new += nl;
+ }
+ (*buf)[len-1] = 0;
+ return 1;
+}
+
#include "config.h"
#include <string.h>
+#include <sys/types.h>
+#include <asm/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fcntl.h>
+
#include "nfslib.h"
+ /* if /proc/net/rpc/... exists, then
+ * write to it, as that interface is more stable.
+ * Write:
+ * client fsidtype fsid path
+ * to /proc/net/rpc/nfsd.fh/channel
+ * and
+ * client path expiry flags anonuid anongid fsid
+ * to /proc/net/rpc/nfsd.export/channel
+ */
+
+static int
+exp_unexp(struct nfsctl_export *exp, int export)
+{
+ FILE *f;
+ struct stat stb;
+ __u32 fsid;
+ char fsidstr[8];
+ __u16 dev;
+ __u32 inode;
+
+
+ f = fopen("/proc/net/rpc/nfsd.export/channel", "w");
+ if (f == NULL) return -1;
+ qword_print(f, exp->ex_client);
+ qword_print(f, exp->ex_path);
+ qword_printint(f, 0x7fffffff);
+ if (export) {
+ qword_printint(f, exp->ex_flags);
+ qword_printint(f, exp->ex_anon_uid);
+ qword_printint(f, exp->ex_anon_gid);
+ qword_printint(f, exp->ex_dev);
+ }
+ qword_eol(f);
+ fclose(f);
+
+ if (stat(exp->ex_path, &stb) != 0)
+ return -1;
+ f = fopen("/proc/net/rpc/nfsd.fh/channel", "w");
+ if (f==NULL) return -1;
+ if (exp->ex_flags & NFSEXP_FSID) {
+ qword_print(f,exp->ex_client);
+ qword_printint(f,1);
+ fsid = exp->ex_dev;
+ qword_printhex(f, (char*)&fsid, 4);
+ qword_printint(f, 0x7fffffff);
+ if (export)
+ qword_print(f, exp->ex_path);
+ qword_eol(f);
+ }
+ qword_print(f,exp->ex_client);
+ qword_printint(f,0);
+ dev = htons(major(stb.st_dev)); memcpy(fsidstr, &dev, 2);
+ dev = htons(minor(stb.st_dev)); memcpy(fsidstr+2, &dev, 2);
+ inode = stb.st_ino; memcpy(fsidstr+4, &inode, 4);
+
+ qword_printhex(f, fsidstr, 8);
+ qword_printint(f, 0x7fffffff);
+ if (export)
+ qword_print(f, exp->ex_path);
+ qword_eol(f);
+ fclose(f);
+ return 0;
+}
+
int
nfsexport(struct nfsctl_export *exp)
{
struct nfsctl_arg arg;
-
+ int fd;
+ if ((fd=open("/proc/net/rpc/nfsd.fh/channel", O_RDWR))>= 0) {
+ close(fd);
+ return exp_unexp(exp, 1);
+ }
arg.ca_version = NFSCTL_VERSION;
memcpy(&arg.ca_export, exp, sizeof(arg.ca_export));
return nfsctl(NFSCTL_EXPORT, &arg, NULL);
{
struct nfsctl_arg arg;
+ int fd;
+ if ((fd=open("/proc/net/rpc/nfsd.fh/channel", O_RDWR))>= 0) {
+ close(fd);
+ return exp_unexp(exp, 0);
+ }
+
arg.ca_version = NFSCTL_VERSION;
memcpy(&arg.ca_export, exp, sizeof(arg.ca_export));
return nfsctl(NFSCTL_UNEXPORT, &arg, NULL);