summaryrefslogtreecommitdiffstats
path: root/lib/libautofs/libautofs.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libautofs/libautofs.c')
-rw-r--r--lib/libautofs/libautofs.c479
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)));
+}
+
OpenPOWER on IntegriCloud