[OpenAFS] check in c (linux) whether a directory entry is a mount point for an AFS volume

Michael Meffie mmeffie@sinenomine.net
Fri, 3 Aug 2018 23:04:44 -0400


On Fri, 3 Aug 2018 13:22:05 +0200
Stephan Wiesand <stephan.wiesand@desy.de> wrote:

>
> > On 3. Aug 2018, at 13:08, Christian <chanlists@googlemail.com> wrote:
>
> > is there an easy  way to check in C (under linux) whether a directory
> > entry is a mount point for an afs volume and maybe also obtain the name
> > of the volume mounted?
>
> popen("fs lsm /the/path", "r") ?

Hi Christian,

Since you asked for a way to check in C, looking at the fs lsmount
implementation, you can see the OpenAFS fs program issues an ioctl (under linux) to
do a "mount point stat". The ioctl returns EINVAL if the path is not an openafs
"mount point".

Here's a working example (for linux only):

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    #include <fcntl.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <sys/ioctl.h>

    #define AFSCALL_PIOCTL 20
    #define AFS_PIOCTL_MAXSIZE 2048

    #define _VICEIOCTL(id) ((unsigned int) _IOW('V', id, struct ViceIoctl))
    #define VIOC_AFS_STAT_MT_PT  _VICEIOCTL(29)
    #define VIOC_SYSCALL_TYPE 'C'
    #define VIOC_SYSCALL _IOW(VIOC_SYSCALL_TYPE,1,void *)

    #define PROC_SYSCALL_FNAME "/proc/fs/openafs/afs_ioctl"

    struct ViceIoctl {
        caddr_t in;
        caddr_t out;
        short in_size;
        short out_size;
    };

    struct afsprocdata {
        long param4;
        long param3;
        long param2;
        long param1;
        long syscall;
    };

    char buffer[AFS_PIOCTL_MAXSIZE];

    int pioctl(char *path, int command, struct ViceIoctl *arg, int follow)
    {
        int code;
        int fd;
        struct afsprocdata syscall_data;

        fd = open(PROC_SYSCALL_FNAME, O_RDONLY);
        if (fd < 0) {
            fprintf(stderr, "failed to open %s; errno=%d\n", PROC_SYSCALL_FNAME, errno);
            return -1;
        }

        syscall_data.syscall = (long)AFSCALL_PIOCTL;
        syscall_data.param1 = (long)path;
        syscall_data.param2 = (long)command;
        syscall_data.param3 = (long)arg;
        syscall_data.param4 = (long)follow;

        code = ioctl(fd, VIOC_SYSCALL, &syscall_data);
        close(fd);
        return code;
    }

    int main(int argc, char *argv)
    {
        int code;
        struct ViceIoctl blob;
        char *parent = "/afs/example.com/test";
        char *last = "xyzzy";

        memset(buffer, 0, AFS_PIOCTL_MAXSIZE);
        blob.in = last;
        blob.in_size = strlen(last) + 1;
        blob.out_size = AFS_PIOCTL_MAXSIZE;
        blob.out = buffer;

        code = pioctl(parent, VIOC_AFS_STAT_MT_PT, &blob, 1);
        if (code == 0) {
            printf("%s/%s is a mount point for volume %s\n", parent, last, buffer);
        } else if (errno == EINVAL) {
            printf("%s/%s is not a mount point\n", parent, last);
        } else {
            fprintf(stderr, "pioctl failed: code=%d; errno=%d\n", code, errno);
        }

        return 0;
    }

    /*
     * Example usage:
     *
     *    $ make lsm
     *    cc     lsm.c   -o lsm
     *    $ ./lsm
     *    /afs/example.com/test/xyzzy is a mount point for volume #xyzzy
     *
     */

Hope this helps,
Mike


-- 
Michael Meffie <mmeffie@sinenomine.net>