From 05a777d98ae6cd5dd121f5d7fe5193febb01a394 Mon Sep 17 00:00:00 2001 From: Ronnie Sahlberg Date: Wed, 1 Jun 2011 20:55:27 +1000 Subject: [PATCH] Initial support for RQUOTA protocol --- Makefile.in | 18 +++++++- examples/nfsclient-raw.c | 86 ++++++++++++++++++++++++++++++++--- include/libnfs-raw.h | 38 ++++++++++++++++ rquota/rquota.c | 96 ++++++++++++++++++++++++++++++++++++++++ rquota/rquota.x | 47 ++++++++++++++++++++ 5 files changed, 277 insertions(+), 8 deletions(-) create mode 100644 rquota/rquota.c create mode 100644 rquota/rquota.x diff --git a/Makefile.in b/Makefile.in index 278873b..06303e6 100644 --- a/Makefile.in +++ b/Makefile.in @@ -7,7 +7,7 @@ LIBS=@LIBS@ INSTALLCMD = @install@ -c CC=gcc -CFLAGS=-g -O0 -fPIC -Wall -W -I. -Iinclude -Imount -Infs -Iportmap "-D_U_=__attribute__((unused))" -D_FILE_OFFSET_BITS=64 +CFLAGS=-g -O0 -fPIC -Wall -W -I. -Iinclude -Imount -Infs -Iportmap -Irquota "-D_U_=__attribute__((unused))" -D_FILE_OFFSET_BITS=64 LIBNFS_A=lib/libnfs.a LIBNFS_SO_NAME=libnfs.so.1 @@ -20,7 +20,8 @@ lib/libnfs.o lib/libnfs-sync.o LIBNFS_OBJS = \ mount/libnfs-raw-mount.o mount/mount.o \ portmap/libnfs-raw-portmap.o portmap/portmap.o \ -nfs/libnfs-raw-nfs.o nfs/nfs.o +nfs/libnfs-raw-nfs.o nfs/nfs.o \ +rquota/libnfs-raw-rquota.o rquota/rquota.o EXAMPLES=bin/nfsclient-raw bin/nfsclient-async bin/nfsclient-sync @@ -83,6 +84,18 @@ nfs/libnfs-raw-nfs.o: nfs/libnfs-raw-nfs.c nfs/libnfs-raw-nfs.h @echo Compiling $@ $(CC) $(CFLAGS) -c nfs/libnfs-raw-nfs.c -o $@ +rquota/libnfs-raw-rquota.h: rquota/rquota.x + @echo Generating $@ + rpcgen -h rquota/rquota.x > rquota/libnfs-raw-rquota.h + +rquota/libnfs-raw-rquota.c: rquota/rquota.x + @echo Generating $@ + rpcgen -c rquota/rquota.x | sed -e "s/#include \"rquota\/rquota.h\"/#include \"libnfs-raw-rquota.h\"/" > rquota/libnfs-raw-rquota.c + +rquota/libnfs-raw-rquota.o: rquota/libnfs-raw-rquota.c rquota/libnfs-raw-rquota.h + @echo Compiling $@ + $(CC) $(CFLAGS) -c rquota/libnfs-raw-rquota.c -o $@ + install: $(LIBNFS_A) $(LIBNFS_SO) ifeq ("$(LIBDIR)x","x") $(INSTALLCMD) -m 755 $(LIBNFS_SO) $(libdir) @@ -107,5 +120,6 @@ clean: rm -f mount/*.o mount/libnfs-raw-mount.h mount/libnfs-raw-mount.c rm -f nfs/*.o nfs/libnfs-raw-nfs.h nfs/libnfs-raw-nfs.c rm -f portmap/*.o portmap/libnfs-raw-portmap.h portmap/libnfs-raw-portmap.c + rm -f rquota/*.o rquota/libnfs-raw-rquota.h rquota/libnfs-raw-rquota.c rm -f nfsclient-raw nfsclient-async nfsclient-sync diff --git a/examples/nfsclient-raw.c b/examples/nfsclient-raw.c index 40d570a..ad8576a 100644 --- a/examples/nfsclient-raw.c +++ b/examples/nfsclient-raw.c @@ -29,15 +29,52 @@ #include "libnfs-raw.h" #include "libnfs-raw-mount.h" #include "libnfs-raw-nfs.h" +#include "libnfs-raw-rquota.h" struct client { char *server; char *export; uint32_t mount_port; + uint32_t rquota_port; int is_finished; struct nfs_fh3 rootfh; }; +void rquota_getquota_cb(struct rpc_context *rpc _U_, int status, void *data, void *private_data) +{ + struct client *client = private_data; + GETQUOTA1res *res = data; + + if (status == RPC_STATUS_ERROR) { + printf("rquota/getquota call failed with \"%s\"\n", (char *)data); + exit(10); + } + if (status != RPC_STATUS_SUCCESS) { + printf("rquota/getquota call to server %s failed, status:%d\n", client->server, status); + exit(10); + } + + printf("rquota responded ok\n"); + client->is_finished = 1; +} + +void rquota_connect_cb(struct rpc_context *rpc, int status, void *data _U_, void *private_data) +{ + struct client *client = private_data; + + if (status != RPC_STATUS_SUCCESS) { + printf("connection to RPC.RQUOTAD on server %s failed\n", client->server); + exit(10); + } + + printf("Connected to RPC.RQUOTAD on %s:%d\n", client->server, client->rquota_port); + printf("Send GETQUOTA request for uid 100\n"); + if (rpc_rquota1_getquota_async(rpc, rquota_getquota_cb, EXPORT, 100, client) != 0) { + printf("Failed to send fsinfo request\n"); + exit(10); + } +} + void nfs_fsinfo_cb(struct rpc_context *rpc _U_, int status, void *data, void *private_data) { struct client *client = private_data; @@ -55,7 +92,18 @@ void nfs_fsinfo_cb(struct rpc_context *rpc _U_, int status, void *data, void *pr printf("Got reply from server for NFS/FSINFO procedure.\n"); printf("Read Max:%d\n", (int)res->FSINFO3res_u.resok.rtmax); printf("Write Max:%d\n", (int)res->FSINFO3res_u.resok.wtmax); - client->is_finished = 1; + + printf("Disconnect socket from nfs server\n"); + if (rpc_disconnect(rpc, "normal disconnect") != 0) { + printf("Failed to disconnect socket to nfs\n"); + exit(10); + } + + printf("Connect to RPC.RQUOTAD on %s:%d\n", client->server, client->rquota_port); + if (rpc_connect_async(rpc, client->server, client->rquota_port, rquota_connect_cb, client) != 0) { + printf("Failed to start connection\n"); + exit(10); + } } @@ -68,7 +116,7 @@ void nfs_connect_cb(struct rpc_context *rpc, int status, void *data _U_, void *p exit(10); } - printf("Connected to RPC.NFSDD on %s:%d\n", client->server, client->mount_port); + printf("Connected to RPC.NFSD on %s:%d\n", client->server, client->mount_port); printf("Send FSINFO request\n"); if (rpc_nfs_fsinfo_async(rpc, nfs_fsinfo_cb, &client->rootfh, client) != 0) { printf("Failed to send fsinfo request\n"); @@ -101,7 +149,7 @@ void mount_mnt_cb(struct rpc_context *rpc, int status, void *data, void *private exit(10); } - printf("Connect to RPC.NFSDD on %s:%d\n", client->server, 2049); + printf("Connect to RPC.NFSD on %s:%d\n", client->server, 2049); if (rpc_connect_async(rpc, client->server, 2049, nfs_connect_cb, client) != 0) { printf("Failed to start connection\n"); exit(10); @@ -148,7 +196,7 @@ void mount_connect_cb(struct rpc_context *rpc, int status, void *data _U_, void } -void pmap_getport_cb(struct rpc_context *rpc, int status, void *data, void *private_data) +void pmap_getport2_cb(struct rpc_context *rpc, int status, void *data, void *private_data) { struct client *client = private_data; @@ -162,7 +210,7 @@ void pmap_getport_cb(struct rpc_context *rpc, int status, void *data, void *priv } client->mount_port = *(uint32_t *)data; - printf("GETPORT returned Port:%d\n", client->mount_port); + printf("GETPORT returned RPC.MOUNTD is on port:%d\n", client->mount_port); if (client->mount_port == 0) { printf("RPC.MOUNTD is not available on server : %s:%d\n", client->server, client->mount_port); exit(10); @@ -181,6 +229,32 @@ void pmap_getport_cb(struct rpc_context *rpc, int status, void *data, void *priv } } +void pmap_getport1_cb(struct rpc_context *rpc, int status, void *data, void *private_data) +{ + struct client *client = private_data; + + if (status == RPC_STATUS_ERROR) { + printf("portmapper getport call failed with \"%s\"\n", (char *)data); + exit(10); + } + if (status != RPC_STATUS_SUCCESS) { + printf("portmapper getport call to server %s failed, status:%d\n", client->server, status); + exit(10); + } + + client->rquota_port = *(uint32_t *)data; + printf("GETPORT returned RPC.RQUOTAD on port:%d\n", client->rquota_port); + if (client->rquota_port == 0) { + printf("RPC.RQUOTAD is not available on server : %s:%d\n", client->server, client->rquota_port); + exit(10); + } + + printf("Send getport request asking for MOUNT port\n"); + if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, pmap_getport2_cb, client) != 0) { + printf("Failed to send getport request\n"); + exit(10); + } +} void pmap_null_cb(struct rpc_context *rpc, int status, void *data, void *private_data) { @@ -197,7 +271,7 @@ void pmap_null_cb(struct rpc_context *rpc, int status, void *data, void *private printf("Got reply from server for PORTMAP/NULL procedure.\n"); printf("Send getport request asking for MOUNT port\n"); - if (rpc_pmap_getport_async(rpc, MOUNT_PROGRAM, MOUNT_V3, pmap_getport_cb, client) != 0) { + if (rpc_pmap_getport_async(rpc, RQUOTA_PROGRAM, RQUOTA_V1, pmap_getport1_cb, client) != 0) { printf("Failed to send getport request\n"); exit(10); } diff --git a/include/libnfs-raw.h b/include/libnfs-raw.h index b141e61..8ba8e98 100644 --- a/include/libnfs-raw.h +++ b/include/libnfs-raw.h @@ -551,3 +551,41 @@ int rpc_nfs_link_async(struct rpc_context *rpc, rpc_cb cb, struct nfs_fh3 *file, + +/* + * RQUOTA FUNCTIONS + */ +char *rquotastat_to_str(int error); +int rquotastat_to_errno(int error); + +/* + * Call RQUOTA1/NULL + * Function returns + * 0 : The call was initiated. The callback will be invoked when the call completes. + * <0 : An error occured when trying to set up the call. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * RPC_STATUS_SUCCESS : We got a successful response from the rquota daemon. + * data is NULL. + * RPC_STATUS_ERROR : An error occured when trying to contact the rquota daemon. + * data is the error string. + * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete. + * data is NULL. + */ +int rpc_rquota1_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data); + +/* + * Call RQUOTA1/GETQUOTA + * Function returns + * 0 : The call was initiated. The callback will be invoked when the call completes. + * <0 : An error occured when trying to set up the call. The callback will not be invoked. + * + * When the callback is invoked, status indicates the result: + * RPC_STATUS_SUCCESS : We got a successful response from the rquota daemon. + * data is a RQUOTA1res structure. + * RPC_STATUS_ERROR : An error occured when trying to contact the rquota daemon. + * data is the error string. + * RPC_STATUS_CANCEL : The connection attempt was aborted before it could complete. + * data is NULL. + */ +int rpc_rquota1_getquota_async(struct rpc_context *rpc, rpc_cb cb, char *export, int uid, void *private_data); diff --git a/rquota/rquota.c b/rquota/rquota.c new file mode 100644 index 0000000..e6a49de --- /dev/null +++ b/rquota/rquota.c @@ -0,0 +1,96 @@ +/* + Copyright (C) 2010 by Ronnie Sahlberg + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 2.1 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License + along with this program; if not, see . +*/ + +#include +#include +#include +#include +#include "libnfs.h" +#include "libnfs-raw.h" +#include "libnfs-private.h" +#include "libnfs-raw-rquota.h" + + + +char *rquotastat_to_str(int error) +{ + switch (error) { + case RQUOTA_OK: return "RQUOTA_OK"; break; + case RQUOTA_NOQUOTA: return "RQUOTA_NOQUOTA"; break; + case RQUOTA_EPERM: return "RQUOTA_EPERM"; break; + }; + return "unknown rquota error"; +} + +int rquotastat_to_errno(int error) +{ + switch (error) { + case RQUOTA_OK: return 0; break; + case RQUOTA_NOQUOTA: return -ENOENT; break; + case RQUOTA_EPERM: return -EPERM; break; + }; + return -ENOENT; +} + + +int rpc_rquota1_null_async(struct rpc_context *rpc, rpc_cb cb, void *private_data) +{ + struct rpc_pdu *pdu; + + pdu = rpc_allocate_pdu(rpc, RQUOTA_PROGRAM, RQUOTA_V1, RQUOTA1_NULL, cb, private_data, (xdrproc_t)xdr_void, 0); + if (pdu == NULL) { + rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for rquota/null call"); + return -1; + } + + if (rpc_queue_pdu(rpc, pdu) != 0) { + rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota/null call"); + rpc_free_pdu(rpc, pdu); + return -2; + } + + return 0; +} + +int rpc_rquota1_getquota_async(struct rpc_context *rpc, rpc_cb cb, char *export, int uid, void *private_data) +{ + struct rpc_pdu *pdu; + GETQUOTA1args args; + + pdu = rpc_allocate_pdu(rpc, RQUOTA_PROGRAM, RQUOTA_V1, RQUOTA1_GETQUOTA, cb, private_data, (xdrproc_t)xdr_GETQUOTA1res, sizeof(GETQUOTA1res)); + if (pdu == NULL) { + rpc_set_error(rpc, "Out of memory. Failed to allocate pdu for rquota/getquota call"); + return -1; + } + + args.export = export; + args.uid = uid; + + if (xdr_GETQUOTA1args(&pdu->xdr, &args) == 0) { + rpc_set_error(rpc, "XDR error: Failed to encode GETQUOTA1args"); + rpc_free_pdu(rpc, pdu); + return -2; + } + + if (rpc_queue_pdu(rpc, pdu) != 0) { + rpc_set_error(rpc, "Out of memory. Failed to queue pdu for rquota/getquota call"); + rpc_free_pdu(rpc, pdu); + return -3; + } + + return 0; +} diff --git a/rquota/rquota.x b/rquota/rquota.x new file mode 100644 index 0000000..0efc16d --- /dev/null +++ b/rquota/rquota.x @@ -0,0 +1,47 @@ +/* implementation based on wireshark c-code */ + +const RQUOTAPATHLEN = 1024; /* Guess this is max. It is max for mount so probably rquota too */ + +enum rquotastat { + RQUOTA_OK = 1, + RQUOTA_NOQUOTA = 2, + RQUOTA_EPERM = 3 +}; + +typedef string exportpath; + +struct GETQUOTA1args { + exportpath export; + int uid; +}; + +struct GETQUOTA1res_ok { + int bsize; + int active; + int bhardlimit; + int bsoftlimit; + int curblocks; + int fhardlimit; + int fsoftlimit; + int curfiles; + int btimeleft; + int ftimeleft; +}; + +union GETQUOTA1res switch (rquotastat status) { + case RQUOTA_OK: + GETQUOTA1res_ok quota; + default: + void; +}; + +program RQUOTA_PROGRAM { + version RQUOTA_V1 { + void + RQUOTA1_NULL(void) = 0; + + GETQUOTA1res + RQUOTA1_GETQUOTA(GETQUOTA1args) = 1; + } = 1; +} = 100011; + -- 2.34.1