From e39e879ede3eb48cca848118af6f9fb6435c7241 Mon Sep 17 00:00:00 2001 From: alfred Date: Tue, 31 Aug 2004 16:26:01 +0000 Subject: Enter the autofs. --- share/examples/autofs/driver/Makefile | 18 ++ share/examples/autofs/driver/autodriver.c | 510 ++++++++++++++++++++++++++++++ share/examples/autofs/driver/autotab | 7 + 3 files changed, 535 insertions(+) create mode 100644 share/examples/autofs/driver/Makefile create mode 100644 share/examples/autofs/driver/autodriver.c create mode 100644 share/examples/autofs/driver/autotab (limited to 'share/examples/autofs') diff --git a/share/examples/autofs/driver/Makefile b/share/examples/autofs/driver/Makefile new file mode 100644 index 0000000..51791bb --- /dev/null +++ b/share/examples/autofs/driver/Makefile @@ -0,0 +1,18 @@ +# $Id: Makefile,v 1.2 2004/07/17 11:26:51 bright Exp $ +# $FreeBSD$ + +PROG=autodriver + +SRCS= autodriver.c +NOMAN= YES +WERROR= YES +WARNS= 4 +CFLAGS+= -g + +DPADD+= ${.OBJDIR}/../libautofs/libautofs.a +#LDADD+= -lautofs +LDADD+= ${.OBJDIR}/../libautofs/libautofs.a +LDFLAGS+= -L${.OBJDIR}/../libautofs +CFLAGS+= -I${.CURDIR}/../libautofs + +.include diff --git a/share/examples/autofs/driver/autodriver.c b/share/examples/autofs/driver/autodriver.c new file mode 100644 index 0000000..e2c9b05 --- /dev/null +++ b/share/examples/autofs/driver/autodriver.c @@ -0,0 +1,510 @@ +/* + * Copyright (c) 2004 Alfred Perlstein + * 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. + * + * $Id: autodriver.c,v 1.8 2004/08/31 08:49:56 bright Exp $ + * $FreeBSD$ + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +struct autoentry { + char *ae_mnt; /* autofs mountpoint. */ + char *ae_path; /* path under mount. */ + char *ae_type; /* fs to be mounted type. */ + char *ae_opts; /* options passed to mount. */ + char *ae_rpath; /* remote path */ + char *ae_free; /* freeme! */ + char *ae_fullpath; /* full path to mount */ + int ae_line; /* line it came from in the conf. */ + int ae_indirect; /* is this an indirect mount? */ + int ae_direct; /* is this a direct mount? */ + int ae_browse; /* browseable? */ + struct autoentry *ae_next; /* next. */ +}; + +struct autoentry *entries; +const char *mount_prog = "mount"; +const char *fstype = "autofs"; + +void *xmalloc(size_t); +void *xcalloc(size_t number, size_t size); +void parsetab(void); +void populate_tab(void); +void doreq(autoh_t, autoreq_t); +void dotheneedful(autoh_t); +void eventloop(void); +int poll_handles(autoh_t *array, int cnt); +int mount_indirect(struct autofs_userreq *req, struct autoentry *ent); +int mount_direct(struct autofs_userreq *req, struct autoentry *ent); +int mount_browse(struct autofs_userreq *req, struct autoentry *ent); + +#define DSTR(s) sizeof(s) - 1, s + +struct dirent dumbents[] = { + {50, sizeof(struct dirent), DT_DIR, DSTR("one") }, + {51, sizeof(struct dirent), DT_DIR, DSTR(".") }, + {52, sizeof(struct dirent), DT_DIR, DSTR("..") }, + {50, sizeof(struct dirent), DT_DIR, DSTR("two") }, +}; + +void * +xmalloc(size_t size) +{ + void *ret; + + ret = malloc(size); + if (ret == NULL) + err(1, "malloc %d", (int) size); + return (ret); +} + +void * +xcalloc(size_t number, size_t size) +{ + void *ret; + + ret = calloc(number, size); + if (ret == NULL) + err(1, "calloc %d %d", (int)number, (int)size); + return (ret); +} + +void +parsetab(void) +{ + FILE *fp; + const char *tab; + char *cp, *p, *line, *opt; + size_t len; + struct autoentry *ent; + int lineno, x, gotopt; + const char *expecting = "expecting 'direct', 'indirect' or 'browse'"; + + tab = "autotab"; + lineno = 0; + + fp = fopen(tab, "r"); + if (fp == NULL) + err(1, "fopen %s", tab); + + while ((cp = fgetln(fp, &len)) != NULL) { + lineno++; + while (len > 0 && isspace(cp[len - 1])) + len--; + line = xmalloc(len + 1); + bcopy(cp, line, len); + line[len] = '\0'; + cp = line; + if ((cp = strchr(line, '#')) != NULL) + *cp = '\0'; + cp = line; + while (isspace(*cp)) + cp++; + if (*cp == '\0') { + free(line); + continue; + } + ent = xcalloc(1, sizeof(*ent)); + if ((p = strsep(&cp, " \t")) == NULL) + goto bad; + ent->ae_mnt = p; + if ((p = strsep(&cp, " \t")) == NULL) + goto bad; + ent->ae_path = p; + if ((p = strsep(&cp, " \t")) == NULL) + goto bad; + ent->ae_type = p; + if ((p = strsep(&cp, " \t")) == NULL) + goto bad; + ent->ae_opts = p; + if ((p = strsep(&cp, " \t")) == NULL) + goto bad; + ent->ae_rpath = p; + if ((p = strsep(&cp, " \t")) == NULL) + goto bad; + gotopt = 0; + opt = p; + while ((p = strsep(&opt, ",")) != NULL) { + if (strcmp(p, "indirect") == 0) { + ent->ae_indirect = 1; + gotopt = 1; + } else if (strcmp(p, "direct") == 0) { + ent->ae_direct = 1; + gotopt = 1; + } else if (strcmp(p, "browse") == 0) { + ent->ae_browse = 1; + gotopt = 1; + } else { + warnx("unreconized option '%s', %s", + p, expecting); + goto bad2; + } + } + if (!gotopt) { + warnx("no options specified %s", expecting); + goto bad2; + } + if (ent->ae_direct && ent->ae_indirect) { + warnx("direct and indirect are mutually exclusive"); + goto bad2; + + } + x = asprintf(&ent->ae_fullpath, "%s/%s", + ent->ae_mnt, ent->ae_path); + if (x == -1) + err(1, "asprintf"); + + if (strlen(ent->ae_fullpath) + 1 > PATH_MAX) { + warnx("Error in file %s, line %d, " + "mountpath (%s) exceeds PATH_MAX (%d)", + tab, lineno, ent->ae_fullpath, PATH_MAX); + goto bad2; + } + ent->ae_line = lineno; + ent->ae_free = line; + ent->ae_next = entries; + entries = ent; + continue; +bad: + warnx("Parse error in file %s, line %d", tab, lineno); +bad2: + free(ent->ae_fullpath); + free(line); + free(ent); + } + if (ferror(fp)) + err(1, "error with file %s", tab); +} + +void +populate_tab(void) +{ + struct autoentry *ent; + char *path, *cmd; + int error; + autoh_t ah; + + path = cmd = NULL; + + for (ent = entries; ent != NULL; ent = ent->ae_next) { + free(path); + free(cmd); + error = asprintf(&path, "%s/%s", ent->ae_mnt, ent->ae_path); + if (error == -1) + err(1, "asprintf"); + error = asprintf(&cmd, "mkdir -p %s", path); + if (error == -1) + err(1, "asprintf"); + error = system(cmd); + if (error) { + warn("system: %s", cmd); + continue; + } + if (autoh_get(ent->ae_mnt, &ah)) { + warn("autoh_get %s", path); + continue; + } + error = autoh_togglepath(ah, AUTO_MOUNTER, getpid(), path); + if (error) { + err(1, "AUTO_MOUNTER %s", path); + continue; + } + if (ent->ae_browse) { + error = autoh_togglepath(ah, AUTO_BROWSE, getpid(), + path); + if (error) + err(1, "AUTO_BROWSE %s", path); + } + if (ent->ae_direct) { + error = autoh_togglepath(ah, AUTO_DIRECT, getpid(), + path); + if (error) + err(1, "AUTO_DIRECT %s", path); + } + if (ent->ae_indirect) { + error = autoh_togglepath(ah, AUTO_INDIRECT, getpid(), + path); + if (error) + err(1, "AUTO_INDIRECT %s", path); + } + autoh_free(ah); + } + free(path); + free(cmd); +} + +/* + * Process an autofs request, scan the list of entries in the config + * looking for our node, if found mount it. + */ +void +doreq(autoh_t ah, autoreq_t req) +{ + struct autoentry *ent; + int error; + int mcmp; + const char *mnt; + + mnt = autoh_mp(ah); + + autoreq_seterrno(req, 0); + for (ent = entries; ent != NULL; ent = ent->ae_next) { + fprintf(stderr, "comparing {%s,%s} to {%s,%s}\n", + mnt, ent->ae_mnt, autoreq_getpath(req), ent->ae_path); + fprintf(stderr, "comparing {%d,%d} to {%d,%d}\n", + (int)strlen(mnt), + (int)strlen(ent->ae_mnt), + (int)strlen(autoreq_getpath(req)), + (int)strlen(ent->ae_path)); + if ((mcmp = strcmp(mnt, ent->ae_mnt)) != 0) { + fprintf(stderr, "mcmp = %d\n", mcmp); + continue; + } + if (mount_direct(req, ent)) + goto serve; + if (mount_indirect(req, ent)) + goto serve; + if (mount_browse(req, ent)) + goto serve; + } + fprintf(stderr, "no entry found...\n"); + autoreq_seterrno(req, ENOENT); +serve: + error = autoreq_serv(ah, req); + if (error == -1) { + warn("AUTOFS_CTL_SERVREQ"); + } +} + +int +mount_indirect(req, ent) + struct autofs_userreq *req; + struct autoentry *ent; +{ + struct stat sb; + char *path, *cmd; + int error, x; + + if (ent->ae_indirect != 1) + return (0); + /* + * handle lookups, fake all stat(2) requests... this is bad, + * but we're a driver so we don't care... + * If we don't care about the type of request, then just return. + */ + switch (autoreq_getop(req)) { + case AUTOREQ_OP_LOOKUP: + break; + case AUTOREQ_OP_STAT: + return (1); + default: + return (0); + } + if (stat(ent->ae_fullpath, &sb)) + return (0); + if (sb.st_ino != autoreq_getdirino(req)) + return (0); + x = asprintf(&path, "%s/%s", ent->ae_fullpath, autoreq_getpath(req)); + if (x > PATH_MAX) { + autoreq_seterrno(req, ENAMETOOLONG); + return (1); + } + if (mkdir(path, 0555) == -1) + warn("mkdir %s", path); + error = asprintf(&cmd, "%s -t %s -o %s %s/%s %s", mount_prog, + ent->ae_type, ent->ae_opts, ent->ae_rpath, autoreq_getpath(req), path); + fprintf(stderr, "running:\n\t%s\n", cmd); + error = system(cmd); + fprintf(stderr, "error = %d\n", error); + free(cmd); + if (error) { + if (rmdir(path) == -1) + warn("rmdir %s", path); + autoreq_seterrno(req, ENOENT); + } else { + if (stat(path, &sb) != -1) + autoreq_setino(req, sb.st_ino); + /* XXX !!! */ + /* req->au_flags = 1; */ + } + free(path); + return (1); +} + +int +mount_direct(req, ent) + struct autofs_userreq *req; + struct autoentry *ent; +{ + struct stat sb; + char *cmd; + int error; + + if (ent->ae_direct != 1) + return (0); + /* + * handle lookups, fake all stat(2) requests... this is bad, + * but we're a driver so we don't care... + * If we don't care about the type of request, then just return. + */ + switch (autoreq_getop(req)) { + case AUTOREQ_OP_LOOKUP: + break; + case AUTOREQ_OP_STAT: + return (1); + default: + return (0); + } + if (stat(ent->ae_fullpath, &sb)) + return (0); + if (sb.st_ino != autoreq_getino(req)) + return (0); + error = asprintf(&cmd, "%s -t %s -o %s %s %s", mount_prog, + ent->ae_type, ent->ae_opts, ent->ae_rpath, ent->ae_fullpath); + if (error == -1) + err(1, "asprintf"); + fprintf(stderr, "running:\n\t%s\n", cmd); + error = system(cmd); + fprintf(stderr, "error = %d\n", error); + free(cmd); + if (error) { + autoreq_seterrno(req, ENOENT); + return (1); + } + /* XXX: fix ONLIST in kernel */ + /* req->au_flags = 1; */ + return (1); +} + +int +mount_browse(req, ent) + struct autofs_userreq *req; + struct autoentry *ent; +{ + off_t off; + + if (ent->ae_browse != 1) + return (0); + if (autoreq_getop(req) != AUTOREQ_OP_READDIR) + return (0); + autoreq_getoffset(req, &off); + if (off < sizeof(dumbents)) + autoreq_setaux(req, dumbents, sizeof(dumbents)); + fprintf(stderr, "mount_browse: offset %d, size %d\n", + (int)off, (int)sizeof(dumbents)); + autoreq_seteof(req, 1); + return (1); +} + +/* + * Ask the filesystem passed in if it has a pending request. + * if so process them. + */ +void +dotheneedful(autoh_t ah) +{ + int cnt, i; + autoreq_t *reqs; + + if (autoreq_get(ah, &reqs, &cnt)) + err(1, "autoreq_get"); + + for (i = 0; i < cnt; i++) { + fprintf(stderr, "processing request for '%s' '%s'\n", + autoh_mp(ah), autoreq_getpath(reqs[i])); + doreq(ah, reqs[i]); + } + free(reqs); +} + +int +poll_handles(autoh_t *array, int cnt) +{ + int i, saved_errno, x; + static struct pollfd *pfd = NULL; + + pfd = reallocf(pfd, cnt * sizeof(*pfd)); + if (pfd == NULL) + return (-1); + for (i = 0; i < cnt; i++) { + pfd[i].fd = autoh_fd(array[i]); + pfd[i].events = POLLPRI; + pfd[i].revents = 0; + } + fprintf(stderr, "start polling...\n"); + x = poll(pfd, cnt, 10000); + saved_errno = errno; + fprintf(stderr, "done polling...\n"); + errno = saved_errno; + if (x == -1) + return (-1); + /* at least one fs is ready... */ + if (x > 0) + return (0); + return (0); +} + +void +eventloop(void) +{ + autoh_t *array; + int cnt, i; + + fprintf(stderr, "starting event loop...\n"); + for ( ;; ) { + if (autoh_getall(&array, &cnt)) + err(1, "autoh_getall"); + if (poll_handles(array, cnt)) + err(1, "poll_handles"); + for (i = 0; i < cnt; i++) { + dotheneedful(array[i]); + } + } +} + +int +main(int argc __unused, char **argv __unused) +{ + + parsetab(); + populate_tab(); + eventloop(); + return (0); +} diff --git a/share/examples/autofs/driver/autotab b/share/examples/autofs/driver/autotab new file mode 100644 index 0000000..e2f8569 --- /dev/null +++ b/share/examples/autofs/driver/autotab @@ -0,0 +1,7 @@ +# $Id: autotab,v 1.7 2004/08/31 15:59:44 bright Exp $ +# $FreeBSD$ +# autofs, directory, fstype, opts, path +/auto share nfs ro,-R=1 big:/vol/share direct +#/auto src nfs ro,-R=1 big:/vol/share/src indirect +/auto src nfs ro,-R=1 big:/vol/share/src direct +/auto browse nfs ro,-R=1 big:/vol/share/src browse,indirect -- cgit v1.1