diff options
Diffstat (limited to 'lib/libautofs/libautofs.c')
-rw-r--r-- | lib/libautofs/libautofs.c | 479 |
1 files changed, 479 insertions, 0 deletions
diff --git a/lib/libautofs/libautofs.c b/lib/libautofs/libautofs.c new file mode 100644 index 0000000..459b32d --- /dev/null +++ b/lib/libautofs/libautofs.c @@ -0,0 +1,479 @@ +/* + * Copyright (c) 2004 Alfred Perlstein <alfred@FreeBSD.org> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * $Id: libautofs.c,v 1.5 2004/09/08 08:44:12 bright Exp $ + */ +#include <err.h> +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/poll.h> +#include <sys/stat.h> +#include <sys/sysctl.h> + +#ifdef AUTOFSSTANDALONE +#include "../autofs/autofs.h" +#else +#include <fs/autofs/autofs.h> +#endif + +#include "libautofs.h" + +struct auto_handle { + char ah_mp[MNAMELEN]; + fsid_t ah_fsid; + int ah_fd; +}; + +static int autofs_sysctl(int, fsid_t *, void *, size_t *, void *, size_t); +static void safe_free(void *ptr); +static int getmntlst(struct statfs **sfsp, int *cntp); + +static void +safe_free(void *ptr) +{ + int saved_errno; + + saved_errno = errno; + free(ptr); + errno = saved_errno; +} + +int +getmntlst(struct statfs **sfsp, int *cntp) +{ + int cnt; + long bufsize; + + *sfsp = NULL; + cnt = getfsstat(NULL, 0, MNT_NOWAIT); + bufsize = cnt * sizeof(**sfsp); + /*fprintf(stderr, "getmntlst bufsize %ld, cnt %d\n", bufsize, cnt);*/ + *sfsp = malloc(bufsize); + if (sfsp == NULL) + goto err; + cnt = getfsstat(*sfsp, bufsize, MNT_NOWAIT); + if (cnt == -1) + goto err; + *cntp = cnt; + /*fprintf(stderr, "getmntlst ok, cnt %d\n", cnt);*/ + return (0); +err: + safe_free(sfsp); + *sfsp = NULL; + /*fprintf(stderr, "getmntlst bad\n");*/ + return (-1); +} + +/* get a handle based on a path. */ +int +autoh_get(const char *path, autoh_t *ahp) +{ + struct statfs *sfsp, *sp; + int cnt, fd, i; + autoh_t ret; + + ret = NULL; + /* + * We use getfsstat to prevent avoid the lookups on the mountpoints + * that statfs(2) would do. + */ + if (getmntlst(&sfsp, &cnt)) + goto err; + for (i = 0; i < cnt; i++) { + if (strcmp(sfsp[i].f_mntonname, path) == 0) + break; + } + if (i == cnt) { + /*fprintf(stderr, "autoh_get bad %d %d\n", i, cnt);*/ + errno = ENOENT; + goto err; + } + sp = &sfsp[i]; + if (strcmp(sp->f_fstypename, "autofs")) { + errno = ENOTTY; + goto err; + } + fd = open(sp->f_mntonname, O_RDONLY); + if (fd == -1) + goto err; + ret = malloc(sizeof(*ret)); + if (ret == NULL) + goto err; + + ret->ah_fsid = sp->f_fsid; + ret->ah_fd = fd; + strlcpy(ret->ah_mp, sp->f_mntonname, sizeof(ret->ah_mp)); + safe_free(sfsp); + *ahp = ret; + return (0); +err: + safe_free(ret); + safe_free(sfsp); + return (-1); +} + +/* release. */ +void +autoh_free(autoh_t ah) +{ + int saved_errno; + + saved_errno = errno; + close(ah->ah_fd); + free(ah); + errno = saved_errno; +} + +/* + * Get an array of pointers to all the currently mounted autofs + * instances. + */ +int +autoh_getall(autoh_t **arrayp, int *cntp) +{ + struct statfs *sfsp; + int cnt, i, pos; + autoh_t *array; + + array = NULL; + /* + * We use getfsstat to prevent avoid the lookups on the mountpoints + * that statfs(2) would do. + */ + if (getmntlst(&sfsp, &cnt)) + goto err; + array = *arrayp = calloc(cnt + 1, sizeof(**arrayp)); + if (array == NULL) + goto err; + for (i = 0, pos = 0; i < cnt; i++) { + if (autoh_get(sfsp[i].f_mntonname, &array[pos]) == -1) { + /* not an autofs entry, that's ok, otherwise bail */ + if (errno == ENOTTY) + continue; + goto err; + } + pos++; + } + if (pos == 0) { + errno = ENOENT; + goto err; + } + *arrayp = array; + *cntp = pos; + safe_free(sfsp); + return (0); +err: + safe_free(sfsp); + if (array) + autoh_freeall(array); + return (-1); +} + +/* release. */ +void +autoh_freeall(autoh_t *ah) +{ + autoh_t *ahp; + + ahp = ah; + + while (*ahp != NULL) { + autoh_free(*ahp); + ahp++; + } + safe_free(ah); +} + +/* return fd to select on. */ +int +autoh_fd(autoh_t ah) +{ + + return (ah->ah_fd); +} + +const char * +autoh_mp(autoh_t ah) +{ + + return (ah->ah_mp); +} + +static int do_autoreq_get(autoh_t ah, autoreq_t *reqp, int *cntp); + +/* get an array of pending requests */ +int +autoreq_get(autoh_t ah, autoreq_t **reqpp, int *cntp) +{ + int cnt, i; + autoreq_t req, *reqp; + + if (do_autoreq_get(ah, &req, &cnt)) + return (-1); + + reqp = calloc(cnt + 1, sizeof(*reqp)); + if (reqp == NULL) { + safe_free(req); + return (-1); + } + for (i = 0; i < cnt; i++) + reqp[i] = &req[i]; + *reqpp = reqp; + *cntp = cnt; + return (0); +} + +int +do_autoreq_get(autoh_t ah, autoreq_t *reqp, int *cntp) +{ + size_t olen; + struct autofs_userreq *reqs; + int cnt, error; + int vers; + + vers = AUTOFS_PROTOVERS; + + error = 0; + reqs = NULL; + olen = 0; + cnt = 0; + error = autofs_sysctl(AUTOFS_CTL_GETREQS, &ah->ah_fsid, NULL, &olen, + &vers, sizeof(vers)); + if (error == -1) + goto out; + if (olen == 0) + goto out; + + reqs = malloc(olen); + if (reqs == NULL) + goto out; + error = autofs_sysctl(AUTOFS_CTL_GETREQS, &ah->ah_fsid, reqs, &olen, + &vers, sizeof(vers)); + if (error == -1) + goto out; +out: + if (error) { + safe_free(reqs); + return (-1); + } + cnt = olen / sizeof(*reqs); + *cntp = cnt; + *reqp = reqs; + return (0); +} + +/* free an array of requests */ +void +autoreq_free(autoh_t ah __unused, autoreq_t *req) +{ + + free(*req); + free(req); +} + +/* serve a request */ +int +autoreq_serv(autoh_t ah, autoreq_t req) +{ + int error; + + error = autofs_sysctl(AUTOFS_CTL_SERVREQ, &ah->ah_fsid, NULL, NULL, + req, sizeof(*req)); + return (error); +} + +enum autoreq_op +autoreq_getop(autoreq_t req) +{ + + switch (req->au_op) { + case AREQ_LOOKUP: + return (AUTOREQ_OP_LOOKUP); + case AREQ_STAT: + return (AUTOREQ_OP_STAT); + case AREQ_READDIR: + return (AUTOREQ_OP_READDIR); + default: + return (AUTOREQ_OP_UNKNOWN); + } +} + +/* get a request's file name. */ +const char * +autoreq_getpath(autoreq_t req) +{ + + return (req->au_name); +} + +/* get a request's inode. a indirect mount may return AUTO_INODE_NONE. */ +autoino_t +autoreq_getino(autoreq_t req) +{ + + return (req->au_ino); +} + +void +autoreq_setino(autoreq_t req, autoino_t ino) +{ + + req->au_ino = ino; +} + +/* get a request's directory inode. */ +autoino_t +autoreq_getdirino(autoreq_t req) +{ + + return (req->au_dino); +} + +void +autoreq_seterrno(autoreq_t req, int error) +{ + + req->au_errno = error; +} + +void +autoreq_setaux(autoreq_t req, void *auxdata, size_t auxlen) +{ + + req->au_auxdata = auxdata; + req->au_auxlen = auxlen; +} + +void +autoreq_getaux(autoreq_t req, void **auxdatap, size_t *auxlenp) +{ + + *auxdatap = req->au_auxdata; + *auxlenp = req->au_auxlen; +} + +void +autoreq_seteof(autoreq_t req, int eof) +{ + + req->au_eofflag = eof; +} + +void +autoreq_getoffset(autoreq_t req, off_t *offp) +{ + + *offp = req->au_offset - AUTOFS_USEROFF; +} + +void +autoreq_getxid(autoreq_t req, int *xid) +{ + + *xid = req->au_xid; +} + +/* toggle by path. args = handle, AUTO_?, pid (-1 to disable), path. */ +int +autoh_togglepath(autoh_t ah, int op, pid_t pid, const char *path) +{ + int fd, ret; + + fd = open(path, O_RDONLY); + if (fd == -1) + return (-1); + ret = autoh_togglefd(ah, op, pid, fd); + close(fd); + return (ret); +} + +/* toggle by fd. args = handle, AUTO_?, pid (-1 to disable), fd. */ +int +autoh_togglefd(autoh_t ah, int op, pid_t pid, int fd) +{ + struct stat sb; + struct autofs_mounterreq mr; + int error, realop; + + switch (op) { + case AUTO_DIRECT: + realop = AUTOFS_CTL_TRIGGER; + break; + case AUTO_INDIRECT: + realop = AUTOFS_CTL_SUBTRIGGER; + break; + case AUTO_MOUNTER: + realop = AUTOFS_CTL_MOUNTER; + break; + case AUTO_BROWSE: + realop = AUTOFS_CTL_BROWSE; + break; + default: + errno = ENOTTY; + return (-1); + } + + if (fstat(fd, &sb)) + return (-1); + bzero(&mr, sizeof(mr)); + mr.amu_ino = sb.st_ino; + mr.amu_pid = pid; + error = autofs_sysctl(realop, &ah->ah_fsid, NULL, NULL, + &mr, sizeof(mr)); + return (error); +} + +int +autofs_sysctl(op, fsid, oldp, oldlenp, newp, newlen) + int op; + fsid_t *fsid; + void *oldp; + size_t *oldlenp; + void *newp; + size_t newlen; +{ + struct vfsidctl vc; + + bzero(&vc, sizeof(vc)); + vc.vc_op = op; + strcpy(vc.vc_fstypename, "*"); + vc.vc_vers = VFS_CTL_VERS1; + vc.vc_fsid = *fsid; + vc.vc_ptr = newp; + vc.vc_len = newlen; + return (sysctlbyname("vfs.autofs.ctl", oldp, oldlenp, &vc, sizeof(vc))); +} + |