Initial support for RQUOTA protocol
authorRonnie Sahlberg <ronniesahlberg@gmail.com>
Wed, 1 Jun 2011 10:55:27 +0000 (20:55 +1000)
committerRonnie Sahlberg <ronniesahlberg@gmail.com>
Wed, 1 Jun 2011 10:55:27 +0000 (20:55 +1000)
Makefile.in
examples/nfsclient-raw.c
include/libnfs-raw.h
rquota/rquota.c [new file with mode: 0644]
rquota/rquota.x [new file with mode: 0644]

index 278873b62d6ac5850730486d9aa3f91593612727..06303e69adc3ba20ad15db7e87b5faf871b258e6 100644 (file)
@@ -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
 
index 40d570a4ed8fac4d77fe6a12f7afc5966fa6a5fa..ad8576af6b219d04937c31d370958b2ab183bcf7 100644 (file)
 #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);
        }
index b141e6156c9250a1b1b1e3310acb96e056b8f58e..8ba8e9803a6a3a1a41320c6817829d630ce501e9 100644 (file)
@@ -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 (file)
index 0000000..e6a49de
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+   Copyright (C) 2010 by Ronnie Sahlberg <ronniesahlberg@gmail.com>
+
+   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 <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <rpc/xdr.h>
+#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 (file)
index 0000000..0efc16d
--- /dev/null
@@ -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<RQUOTAPATHLEN>;
+
+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;
+