aboutsummaryrefslogtreecommitdiffstats
path: root/modules
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>1997-10-06 21:05:49 +0000
committerH. Peter Anvin <hpa@zytor.com>1997-10-06 21:05:49 +0000
commitbddd43e289c8b8b62d7cb3f1f7eb27ca67cae28e (patch)
treeaac5e4a4b924cb13a54cc0760e99f349ea36bd12 /modules
downloadautofs3-bddd43e289c8b8b62d7cb3f1f7eb27ca67cae28e.tar.gz
autofs3-bddd43e289c8b8b62d7cb3f1f7eb27ca67cae28e.tar.xz
autofs3-bddd43e289c8b8b62d7cb3f1f7eb27ca67cae28e.zip
Initial revision
Diffstat (limited to 'modules')
-rw-r--r--modules/Makefile30
-rw-r--r--modules/lookup_file.c214
-rw-r--r--modules/lookup_program.c197
-rw-r--r--modules/lookup_yp.c106
-rw-r--r--modules/mount_generic.c78
-rw-r--r--modules/mount_nfs.c164
-rw-r--r--modules/mount_smbfs.c180
-rw-r--r--modules/parse_sun.c502
8 files changed, 1471 insertions, 0 deletions
diff --git a/modules/Makefile b/modules/Makefile
new file mode 100644
index 0000000..ee08b43
--- /dev/null
+++ b/modules/Makefile
@@ -0,0 +1,30 @@
+#
+# Makefile for autofs
+#
+
+SRCS = lookup_yp.c lookup_file.c lookup_program.c \
+ parse_sun.c \
+ mount_generic.c mount_nfs.c mount_smbfs.c
+MODS = lookup_yp.so lookup_file.so lookup_program.so \
+ parse_sun.so \
+ mount_generic.so mount_nfs.so mount_smbfs.so
+
+include ../Makefile.rules
+
+CFLAGS += -I../include -fpic -DAUTOFS_LIB_DIR=\"$(autofslibdir)\"
+
+all: $(MODS)
+
+clean:
+ rm -f *.o *.s *.so
+
+install: all
+ install -d -m 755 $(autofslibdir)
+ install -c $(MODS) -m 644 -o root $(autofslibdir)
+
+#
+# Ad hoc compilation rules for modules which need auxilliary libraries
+#
+lookup_yp.so: lookup_yp.c
+ $(CC) $(SOLDFLAGS) $(CFLAGS) -o lookup_yp.so lookup_yp.c $(YPLIBS)
+ $(STRIP) lookup_yp.so
diff --git a/modules/lookup_file.c b/modules/lookup_file.c
new file mode 100644
index 0000000..17200a0
--- /dev/null
+++ b/modules/lookup_file.c
@@ -0,0 +1,214 @@
+/*
+ * lookup_file.c
+ *
+ * Module for Linux automountd to access a plain file automount map
+ */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <errno.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define MODULE_LOOKUP
+#include "automount.h"
+
+#define MAPFMT_DEFAULT "sun"
+
+#define MODPREFIX "lookup(file): "
+
+#define MAPENT_MAX_LEN 4095
+
+struct lookup_context {
+ const char *mapname;
+ struct parse_mod *parse;
+};
+
+int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+
+int lookup_init(const char *mapfmt, int argc, const char * const *argv,
+ void **context)
+{
+ struct lookup_context *ctxt;
+
+ if ( !(*context = ctxt = malloc(sizeof(struct lookup_context))) ) {
+ syslog(LOG_CRIT, MODPREFIX "malloc: %m");
+ return 1;
+ }
+ if ( argc < 1 ) {
+ syslog(LOG_CRIT, MODPREFIX "No map name");
+ return 1;
+ }
+ ctxt->mapname = argv[0];
+
+ if (ctxt->mapname[0] != '/') {
+ syslog(LOG_CRIT, MODPREFIX "file map %s is not an absolute pathname",
+ ctxt->mapname);
+ return 1;
+ }
+
+ if ( access(ctxt->mapname, R_OK) ) {
+ syslog(LOG_WARNING, MODPREFIX "file map %s missing or not readable",
+ ctxt->mapname);
+ }
+
+ if ( !mapfmt )
+ mapfmt = MAPFMT_DEFAULT;
+
+ return !(ctxt->parse = open_parse(mapfmt,MODPREFIX,argc-1,argv+1));
+}
+
+int lookup_mount(const char *root, const char *name, int name_len,
+ void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ int ch, nch;
+ char mapent[MAPENT_MAX_LEN+1], *p;
+ const char *nptr;
+ int mapent_len;
+ FILE *f;
+ enum {
+ st_begin, st_compare, st_star, st_badent, st_entspc, st_getent
+ } state;
+ enum { got_nothing, got_star, got_real } getting, gotten;
+ enum { esc_none, esc_char, esc_val } escape;
+
+ syslog(LOG_DEBUG, MODPREFIX "looking up %s", name);
+
+ chdir("/"); /* If this is not here the filesystem stays
+ busy, for some reason... */
+ f = fopen(ctxt->mapname, "r");
+ if ( !f ) {
+ syslog(LOG_ERR, MODPREFIX "could not open map file %s", ctxt->mapname);
+ return 1;
+ }
+
+ state = st_begin;
+ gotten = got_nothing;
+
+ /* Shut up gcc */
+ nptr = p = NULL;
+ mapent_len = 0;
+ getting = got_nothing;
+ escape = esc_none;
+
+ /* This is ugly. We can't just remove \ escape sequences in the value
+ portion of an entry, because the parsing routine may need it. */
+
+ while ( (ch = getc(f)) != EOF ) {
+ switch ( escape ) {
+ case esc_none:
+ if ( ch == '\\' ) {
+ /* Handle continuation lines */
+ if ( (nch = getc(f)) == '\n' )
+ goto next_char;
+ ungetc(nch,f);
+ escape = esc_char;
+ }
+ break;
+
+ case esc_char:
+ escape = esc_val;
+ break;
+
+ case esc_val:
+ escape = esc_none;
+ break;
+ }
+
+ switch(state) {
+ case st_begin:
+ if ( isspace(ch) && !escape )
+ ;
+ else if ( escape == esc_char )
+ ;
+ else if ( ch == '#' && !escape )
+ state = st_badent;
+ else if ( (char)ch == name[0] ) {
+ state = st_compare;
+ nptr = name+1;
+ } else if ( ch == '*' && !escape )
+ state = st_star;
+ else
+ state = st_badent;
+ break;
+
+ case st_compare:
+ if ( ch == '\n' )
+ state = st_begin;
+ else if ( isspace(ch) && !*nptr && !escape ) {
+ getting = got_real;
+ state = st_entspc;
+ } else if ( escape == esc_char )
+ ;
+ else if ( (char)ch != *(nptr++) )
+ state = st_badent;
+ break;
+
+ case st_star:
+ if ( ch == '\n' )
+ state = st_begin;
+ else if ( isspace(ch) && gotten < got_star && !escape ) {
+ getting = got_star;
+ state = st_entspc;
+ } else if ( escape != esc_char )
+ state = st_badent;
+ break;
+
+ case st_badent:
+ if ( ch == '\n' )
+ state = st_begin;
+ break;
+
+ case st_entspc:
+ if ( ch == '\n' )
+ state = st_begin;
+ else if ( !isspace(ch) || escape ) {
+ state = st_getent;
+ p = mapent;
+ gotten = getting;
+ *(p++) = ch;
+ mapent_len = 1;
+ }
+ break;
+
+ case st_getent:
+ if ( ch == '\n' ) {
+ state = st_begin;
+ if ( gotten == got_real )
+ goto got_it; /* No point in parsing the rest of the file */
+ } else if ( mapent_len < MAPENT_MAX_LEN ) {
+ mapent_len++;
+ *(p++) = ch;
+ }
+ break;
+ }
+ next_char: /* End of loop, since we can't continue;
+ inside a switch */
+ }
+
+got_it:
+ fclose(f);
+
+ if ( gotten == got_nothing ) {
+ syslog(LOG_NOTICE, MODPREFIX "lookup for %s failed", name);
+ return 1; /* Didn't found anything */
+ }
+ *p = '\0'; /* Null-terminate */
+
+ syslog(LOG_DEBUG, MODPREFIX "%s -> %s", name, mapent);
+
+ return ctxt->parse->parse_mount(root,name,name_len,mapent,ctxt->parse->context);
+}
+
+int lookup_done(void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ int rv = close_parse(ctxt->parse);
+ free(ctxt);
+ return rv;
+}
diff --git a/modules/lookup_program.c b/modules/lookup_program.c
new file mode 100644
index 0000000..ccd8c83
--- /dev/null
+++ b/modules/lookup_program.c
@@ -0,0 +1,197 @@
+/*
+ * lookup_program.c
+ *
+ * Module for Linux automountd to access a automount map via a query program
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/times.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#define MODULE_LOOKUP
+#include "automount.h"
+
+#define MAPFMT_DEFAULT "sun"
+
+#define MODPREFIX "lookup(program): "
+
+#define MAPENT_MAX_LEN 4095
+
+struct lookup_context {
+ const char *mapname;
+ struct parse_mod *parse;
+};
+
+int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+
+int lookup_init(const char *mapfmt, int argc, const char * const *argv,
+ void **context)
+{
+ struct lookup_context *ctxt;
+
+ if ( !(*context = ctxt = malloc(sizeof(struct lookup_context))) ) {
+ syslog(LOG_CRIT, MODPREFIX "malloc: %m");
+ return 1;
+ }
+ if ( argc < 1 ) {
+ syslog(LOG_CRIT, MODPREFIX "No map name");
+ return 1;
+ }
+ ctxt->mapname = argv[0];
+
+ if (ctxt->mapname[0] != '/') {
+ syslog(LOG_CRIT, MODPREFIX "program map %s is not an absolute pathname",
+ ctxt->mapname);
+ return 1;
+ }
+
+ if ( access(ctxt->mapname, X_OK) ) {
+ syslog(LOG_WARNING, MODPREFIX "program map %s missing or not executable",
+ ctxt->mapname);
+ }
+
+ if ( !mapfmt )
+ mapfmt = MAPFMT_DEFAULT;
+
+ return !(ctxt->parse = open_parse(mapfmt,MODPREFIX,argc-1,argv+1));
+}
+
+int lookup_mount(const char *root, const char *name, int name_len,
+ void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ char mapent[MAPENT_MAX_LEN+1], *mapp;
+ char errbuf[1024], *errp;
+ char *p, ch;
+ int pipefd[2], epipefd[2];
+ pid_t f;
+ int files_left;
+ int status;
+ fd_set readfds, ourfds;
+
+ syslog(LOG_DEBUG, MODPREFIX "looking up %s", name);
+
+ /* We don't use popen because we don't want to run /bin/sh plus we
+ want to send stderr to the syslog, and we don't use spawnl()
+ because we need the pipe hooks */
+
+ if ( pipe(pipefd) ) {
+ syslog(LOG_ERR, MODPREFIX "pipe: %m");
+ return 1;
+ }
+ if ( pipe(epipefd) ) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ return 1;
+ }
+ f = fork();
+ if ( f < 0 ) {
+ close(pipefd[0]);
+ close(pipefd[1]);
+ close(epipefd[0]);
+ close(epipefd[1]);
+ syslog(LOG_ERR, MODPREFIX "fork: %m");
+ return 1;
+ } else if ( f == 0 ) {
+ close(pipefd[0]);
+ close(epipefd[0]);
+ dup2(pipefd[1],STDOUT_FILENO);
+ dup2(epipefd[1],STDERR_FILENO);
+ close(pipefd[1]);
+ close(epipefd[1]);
+ execl(ctxt->mapname, ctxt->mapname, name, NULL);
+ _exit(255); /* execl() failed */
+ }
+ close(pipefd[1]);
+ close(epipefd[1]);
+
+ mapp = mapent;
+ errp = errbuf;
+
+ FD_ZERO(&ourfds);
+ FD_SET(pipefd[0],&ourfds);
+ FD_SET(epipefd[0],&ourfds);
+
+ files_left = 2;
+
+ while (files_left) {
+ readfds = ourfds;
+ if ( select(OPEN_MAX, &readfds, NULL, NULL, NULL) < 0 &&
+ errno != EINTR )
+ break;
+
+ if ( FD_ISSET(pipefd[0],&readfds) ) {
+ if ( read(pipefd[0], &ch, 1) < 1 ) {
+ FD_CLR(pipefd[0], &ourfds);
+ files_left--;
+ } else if ( mapp ) {
+ if ( ch == '\n' ) {
+ *mapp = '\0';
+ mapp = NULL; /* End of line reached */
+ } else if ( mapp-mapent < MAPENT_MAX_LEN )
+ *(mapp++) = ch;
+ }
+ }
+ if ( FD_ISSET(epipefd[0],&readfds) ) {
+ if ( read(epipefd[0], &ch, 1) < 1 ) {
+ FD_CLR(epipefd[0], &ourfds);
+ files_left--;
+ } else if ( ch == '\n' ) {
+ *errp = '\0';
+ if ( errbuf[0] )
+ syslog(LOG_NOTICE, ">> %s", errbuf);
+ errp = errbuf;
+ } else {
+ if ( errp >= &errbuf[1023] ) {
+ *errp = '\0';
+ syslog(LOG_NOTICE, ">> %s", errbuf);
+ errp = errbuf;
+ }
+ *(errp++) = ch;
+ }
+ }
+ }
+
+ if ( mapp )
+ *mapp = '\0';
+ if ( errp > errbuf ) {
+ *errp = '\0';
+ syslog(LOG_NOTICE, ">> %s", errbuf);
+ }
+
+ close(pipefd[0]);
+ close(epipefd[0]);
+
+ if ( waitpid(f,&status,0) != f ) {
+ syslog(LOG_ERR, MODPREFIX "waitpid: %m");
+ return 1;
+ }
+ if ( mapp == mapent || !WIFEXITED(status) || WEXITSTATUS(status) != 0 ) {
+ syslog(LOG_NOTICE, MODPREFIX "lookup for %s failed", name);
+ return 1;
+ }
+ if ( (p = strchr(mapent,'\n')) ) *p = '\0';
+
+ syslog(LOG_DEBUG, MODPREFIX "%s -> %s", name, mapent);
+
+ return ctxt->parse->parse_mount(root,name,name_len,mapent,
+ ctxt->parse->context);
+}
+
+int lookup_done(void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ int rv = close_parse(ctxt->parse);
+ free(ctxt);
+ return rv;
+}
diff --git a/modules/lookup_yp.c b/modules/lookup_yp.c
new file mode 100644
index 0000000..93d7c1b
--- /dev/null
+++ b/modules/lookup_yp.c
@@ -0,0 +1,106 @@
+/*
+ * lookup_yp.c
+ *
+ * Module for Linux automountd to access a YP (NIS) automount map
+ */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <errno.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <rpc/rpc.h>
+#include <rpc/xdr.h>
+#include <rpcsvc/yp_prot.h>
+#include <rpcsvc/ypclnt.h>
+
+#define MODULE_LOOKUP
+#include "automount.h"
+
+#define MAPFMT_DEFAULT "sun"
+
+#define MODPREFIX "lookup(yp): "
+
+struct lookup_context {
+ const char *domainname;
+ const char *mapname;
+ struct parse_mod *parse;
+};
+
+int lookup_version = AUTOFS_LOOKUP_VERSION; /* Required by protocol */
+
+int lookup_init(const char *mapfmt, int argc, const char * const *argv,
+ void **context)
+{
+ struct lookup_context *ctxt;
+ int err;
+
+ if ( !(*context = ctxt = malloc(sizeof(struct lookup_context))) ) {
+ syslog(LOG_CRIT, MODPREFIX "%m");
+ return 1;
+ }
+
+ if ( argc < 1 ) {
+ syslog(LOG_CRIT, MODPREFIX "No map name");
+ return 1;
+ }
+ ctxt->mapname = argv[0];
+
+ /* This should, but doesn't, take a const char ** */
+ err = yp_get_default_domain((char **) &ctxt->domainname);
+ if ( err ) {
+ syslog(LOG_CRIT, MODPREFIX "map %s: %s\n", ctxt->mapname, yperr_string(err));
+ return 1;
+ }
+
+ if ( !mapfmt )
+ mapfmt = MAPFMT_DEFAULT;
+
+ return !(ctxt->parse = open_parse(mapfmt,MODPREFIX,argc-1,argv+1));
+}
+
+int lookup_mount(const char *root, const char *name,
+ int name_len, void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ char *mapent;
+ int mapent_len;
+ int err, rv;
+
+ syslog(LOG_DEBUG, MODPREFIX "looking up %s", name);
+
+ /* For reasons unknown, the standard YP definitions doesn't define input
+ strings as const char *. However, my understanding is that they will
+ not be modified by the library. */
+ err = yp_match((char *) ctxt->domainname, (char *) ctxt->mapname,
+ (char *) name, name_len, &mapent, &mapent_len);
+ if ( err == YPERR_KEY ) {
+ /* Try to get the "*" entry if there is one - note that we *don't*
+ modify "name" so & -> the name we used, not "*" */
+ err = yp_match((char *) ctxt->domainname, (char *) ctxt->mapname,
+ "*", 1, &mapent, &mapent_len);
+ }
+ if ( err ) {
+ syslog(LOG_NOTICE, MODPREFIX "lookup for %s failed: %s", name, yperr_string(err));
+ return 1;
+ }
+
+ mapent[mapent_len] = '\0';
+
+ syslog(LOG_DEBUG, MODPREFIX "%s -> %s", name, mapent);
+
+ rv = ctxt->parse->parse_mount(root,name,name_len,mapent,ctxt->parse->context);
+ free(mapent);
+ return rv;
+}
+
+int lookup_done(void *context)
+{
+ struct lookup_context *ctxt = (struct lookup_context *) context;
+ int rv = close_parse(ctxt->parse);
+ free(ctxt);
+ return rv;
+}
diff --git a/modules/mount_generic.c b/modules/mount_generic.c
new file mode 100644
index 0000000..9e23c97
--- /dev/null
+++ b/modules/mount_generic.c
@@ -0,0 +1,78 @@
+/*
+ * mount_generic.c
+ *
+ * Module for Linux automountd to mount filesystems for which no special
+ * magic is required
+ *
+ */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define MODULE_MOUNT
+#include "automount.h"
+
+#define MODPREFIX "mount(generic): "
+int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */
+
+
+int mount_init(void **context)
+{
+ return 0;
+}
+
+int mount_mount(const char *root, const char *name, int name_len,
+ const char *what, const char *fstype, const char *options,
+ void *context)
+{
+ char *fullpath;
+ int err;
+
+ fullpath = alloca(strlen(root)+name_len+2);
+ if ( !fullpath ) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %m");
+ return 1;
+ }
+ sprintf(fullpath, "%s/%s", root, name);
+
+ syslog(LOG_DEBUG, MODPREFIX "calling mkdir %s", fullpath);
+ if ( mkdir(fullpath, 0555) && errno != EEXIST ) {
+ syslog(LOG_NOTICE, MODPREFIX "mkdir %s failed: %m", name);
+ return 1;
+ }
+
+ if ( options ) {
+ syslog(LOG_DEBUG, MODPREFIX "calling mount -t %s -o %s %s %s",
+ fstype, options, what, fullpath);
+ err = spawnl(LOG_NOTICE, _PATH_MOUNT, _PATH_MOUNT, "-t", fstype,
+ "-o", options, what, fullpath, NULL);
+ } else {
+ syslog(LOG_DEBUG, MODPREFIX "calling mount -t %s %s %s",
+ fstype, what, fullpath);
+ err = spawnl(LOG_NOTICE, _PATH_MOUNT, _PATH_MOUNT, "-t", fstype,
+ what, fullpath, NULL);
+ }
+ if ( err ) {
+ rmdir(fullpath);
+ syslog(LOG_NOTICE, MODPREFIX "failed to mount %s (type %s) on %s",
+ what, fstype, fullpath);
+ return 1;
+ } else {
+ syslog(LOG_DEBUG, MODPREFIX "mounted %s type %s on %s",
+ what, fstype, fullpath);
+ return 0;
+ }
+}
+
+int mount_done(void *context)
+{
+ return 0;
+}
diff --git a/modules/mount_nfs.c b/modules/mount_nfs.c
new file mode 100644
index 0000000..747326f
--- /dev/null
+++ b/modules/mount_nfs.c
@@ -0,0 +1,164 @@
+/*
+ * mount_nfs.c
+ *
+ * Module for Linux automountd to mount an NFS filesystem, with fallback to
+ * symlinking if the path is local
+ *
+ */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <errno.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <netinet/in.h>
+
+#define MODULE_MOUNT
+#include "automount.h"
+
+#define MODPREFIX "mount(nfs): "
+int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */
+
+static int udpproto;
+static short port_discard;
+
+int mount_init(void **context)
+{
+ struct protoent *udp;
+ struct servent *port_dis;
+
+ /* These are context independent */
+ udp = getprotobyname("udp");
+ udpproto = udp ? udp->p_proto : 0;
+ port_dis = getservbyname("discard","udp");
+ if ( port_dis )
+ port_discard = port_dis->s_port;
+ else
+ port_discard = htons(9); /* 9 is the standard discard port */
+
+ return 0;
+}
+
+int mount_mount(const char *root, const char *name, int name_len,
+ const char *what, const char *fstype,
+ const char *options, void *context)
+{
+ char *colon, **haddr, *fullpath;
+ struct hostent *he;
+ struct sockaddr_in saddr, laddr;
+ int sock, local, err;
+ size_t len;
+
+ colon = strchr(what, ':');
+ if ( !colon ) {
+ /* No colon, take this as a symlink (local) entry */
+ syslog(LOG_DEBUG, MODPREFIX "entry %s -> %s: no colon, assume local",
+ name, what);
+ chdir(root);
+ err = symlink(what, name);
+ if ( err && errno == EEXIST )
+ err = 0;
+ if ( err )
+ syslog(LOG_NOTICE, MODPREFIX "symlink %s: %m", name);
+ chdir("/");
+ return err ? 1 : 0;
+ }
+
+ *colon = '\0';
+ if ( !(he = gethostbyname(what)) ) {
+ syslog(LOG_NOTICE, MODPREFIX "entry %s: host %s: lookup failure",
+ name, what);
+ return 1; /* No such host */
+ }
+
+ /* Probe to see if we are the local host. Open a UDP socket and see
+ if the local address is the same as the remote one */
+
+ local = 0;
+ for ( haddr = he->h_addr_list ; *haddr ; haddr++ ) {
+ sock = socket(AF_INET, SOCK_DGRAM, udpproto);
+ if ( sock < 0 ) {
+ syslog(LOG_ERR, MODPREFIX "socket: %m");
+ return 1;
+ }
+ saddr.sin_family = AF_INET;
+ bcopy(*haddr, &saddr.sin_addr, he->h_length);
+ saddr.sin_port = port_discard;
+
+ len = sizeof(laddr);
+ if ( connect(sock, (struct sockaddr *) &saddr, sizeof(saddr)) < 0
+ || getsockname(sock, (struct sockaddr *) &laddr, &len) < 0 ) {
+ syslog(LOG_ERR, MODPREFIX "connect+getsockname failed for %s", name);
+ close(sock);
+ return 1;
+ }
+ close(sock);
+
+ if ( !memcmp(&saddr.sin_addr,&laddr.sin_addr,he->h_length) ) {
+ local = 1;
+ break;
+ }
+ }
+
+ if ( local ) {
+ /* Local host -- do a symlink */
+
+ syslog(LOG_DEBUG, MODPREFIX "%s is local, symlinking", name);
+ chdir(root);
+ err = symlink(colon+1, name);
+ if ( err && errno == EEXIST )
+ err = 0;
+ if ( err )
+ syslog(LOG_NOTICE, MODPREFIX "symlink %s: %m", name);
+ chdir("/");
+ return err ? 1 : 0;
+ } else {
+ /* Not a local host - do a mount */
+
+ fullpath = alloca(strlen(root)+name_len+2);
+ if ( !fullpath ) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %m");
+ return 1;
+ }
+ sprintf(fullpath, "%s/%s", root, name);
+
+ *colon = ':';
+ syslog(LOG_DEBUG, MODPREFIX "calling mkdir %s", fullpath);
+ if ( mkdir(fullpath, 0555) && errno != EEXIST ) {
+ syslog(LOG_NOTICE, MODPREFIX "mkdir %s failed: %m", name);
+ return 1;
+ }
+
+ if ( options ) {
+ syslog(LOG_DEBUG, MODPREFIX "calling mount -t nfs -o %s %s %s",
+ options, what, fullpath);
+ err = spawnl(LOG_NOTICE, _PATH_MOUNT, _PATH_MOUNT, "-t", "nfs", "-o",
+ options, what, fullpath, NULL);
+ } else {
+ syslog(LOG_DEBUG, MODPREFIX "calling mount -t nfs %s %s", what, fullpath);
+ err = spawnl(LOG_NOTICE, _PATH_MOUNT, _PATH_MOUNT, "-t", "nfs",
+ what, fullpath, NULL);
+ }
+ if ( err ) {
+ rmdir(fullpath);
+ syslog(LOG_NOTICE, MODPREFIX "nfs: mount failure %s on %s",
+ what, fullpath);
+ return 1;
+ } else {
+ syslog(LOG_DEBUG, MODPREFIX "mounted %s on %s", what, fullpath);
+ return 0;
+ }
+ }
+}
+
+int mount_done(void *context)
+{
+ return 0;
+}
diff --git a/modules/mount_smbfs.c b/modules/mount_smbfs.c
new file mode 100644
index 0000000..200d1f2
--- /dev/null
+++ b/modules/mount_smbfs.c
@@ -0,0 +1,180 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * mount_smbfs.c
+ *
+ * Module for Linux automountd to mount an SMB/CIFS filesystem
+ *
+ * Mount point input format expected is: //server/service[/root_path...]
+ *
+ * Copyright 1997 Transmeta Corporation - All Rights Reserved
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139,
+ * USA; either version 2 of the License, or (at your option) any later
+ * version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define MODULE_MOUNT
+#include "automount.h"
+
+#define MODPREFIX "mount(smbfs): "
+int mount_version = AUTOFS_MOUNT_VERSION; /* Required by protocol */
+
+struct smb_mount_opt {
+ char *optname; /* mount-style option name */
+ char *optflag; /* command-line flag for smbmount */
+ int hasarg; /* takes argument? */
+ int satisfies_pwd; /* true if this means we don't need a -n */
+};
+
+static struct smb_mount_opt mount_opt_list[] = {
+ { "nocaps", "-C", 0, 0 },
+ { "guest", "-n", 0, 1 },
+ { "passwd", "-P", 1, 1 },
+ { "srvname", "-s", 1, 0 },
+ { "mysmbname", "-c", 1, 0 },
+ { "login", "-U", 1, 0 },
+ { "uid", "-u", 1, 0 },
+ { "gid", "-g", 1, 0 },
+ { "filemod", "-f", 1, 0 },
+ { "dirmod", "-d", 1, 0 },
+ { "port", "-p", 1, 0 },
+ { "maxxmit", "-m", 1, 0 },
+ { NULL, NULL, 0, 0 }
+};
+
+int mount_init(void **context)
+{
+ return 0;
+}
+
+static int smb_parse_options(char *optstr, const char **argv,
+ char *qbuf, int *qbuflen)
+{
+ char *opt;
+ int ln;
+ int argc;
+ int has_pwd;
+ int qbufchr, qln;
+ struct smb_mount_opt *mount_opt;
+
+ has_pwd = 0;
+ qbufchr = 0;
+ argc = 0;
+
+ if ( optstr ) {
+ for ( opt = strtok(optstr, ",") ; opt ; opt = strtok(NULL, ",") ) {
+ for ( mount_opt = mount_opt_list ; mount_opt->optname ; mount_opt++ ) {
+ if ( mount_opt->hasarg ) {
+ ln = strlen(mount_opt->optname);
+ if ( !strncmp(opt, mount_opt->optname, ln) && opt[ln] == '=' ) {
+ qln = strlen(opt)-ln;
+ if ( argv ) {
+ *(argv++) = mount_opt->optflag;
+ memcpy(qbuf, opt+ln+1, qln);
+ *(argv++) = qbuf;
+ qbuf += qln;
+ }
+ qbufchr += qln;
+ has_pwd = has_pwd || mount_opt->satisfies_pwd;
+ argc += 2;
+ break;
+ }
+ } else {
+ if ( !strcmp(opt, mount_opt->optname) ) {
+ if ( argv )
+ *(argv++) = mount_opt->optflag;
+ has_pwd = has_pwd || mount_opt->satisfies_pwd;
+ argc++;
+ break;
+ }
+ }
+ }
+ /* Ignore unknown options */
+ }
+ }
+
+ if ( !has_pwd ) {
+ syslog(LOG_DEBUG, MODPREFIX "no password option, adding -n");
+ if ( argv )
+ *(argv++) = "-n";
+ argc++;
+ }
+
+ if ( argv )
+ *argv = NULL;
+
+ if ( qbuflen )
+ *qbuflen = qbufchr;
+
+ return argc;
+}
+
+int mount_mount(const char *root, const char *name, int name_len,
+ const char *what, const char *fstype, const char *options,
+ void *context)
+{
+ char *fullpath, *optcopy;
+ int err;
+ char *qbuf;
+ int argc, optsize, qbuflen;
+ const char **argv;
+
+ fullpath = alloca(strlen(root)+name_len+2);
+ optcopy = alloca(optsize = strlen(options)+1);
+ if ( !fullpath || !optcopy ) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %m");
+ return 1;
+ }
+ sprintf(fullpath, "%s/%s", root, name);
+
+ memcpy(optcopy, options, optsize);
+ argc = smb_parse_options(optcopy, NULL, NULL, &qbuflen) + 4;
+ argv = alloca(sizeof(char *) * argc);
+ qbuf = alloca(qbuflen);
+ if ( !argv || (qbuflen && !qbuf) ) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %m");
+ return 1;
+ }
+ argv[0] = _PATH_SMBMOUNT;
+ argv[1] = what;
+ argv[2] = fullpath;
+ memcpy(optcopy, options, optsize);
+ smb_parse_options(optcopy, argv+3, qbuf, NULL);
+
+ syslog(LOG_DEBUG, MODPREFIX "calling mkdir %s", fullpath);
+ if ( mkdir(fullpath, 0555) && errno != EEXIST ) {
+ syslog(LOG_NOTICE, MODPREFIX "mkdir %s failed: %m", name);
+ return 1;
+ }
+
+ err = spawnv(LOG_NOTICE, _PATH_SMBMOUNT, argv);
+
+ if ( err ) {
+ rmdir(fullpath);
+ syslog(LOG_NOTICE, MODPREFIX "failed to mount %s on %s", what, fullpath);
+ return 1;
+ } else {
+ syslog(LOG_DEBUG, MODPREFIX "mounted %s on %s", what, fullpath);
+ return 0;
+ }
+}
+
+int mount_done(void *context)
+{
+ return 0;
+}
diff --git a/modules/parse_sun.c b/modules/parse_sun.c
new file mode 100644
index 0000000..3c87f05
--- /dev/null
+++ b/modules/parse_sun.c
@@ -0,0 +1,502 @@
+/*
+ * parse_sun.c
+ *
+ * Module for Linux automountd to parse a Sun-format automounter map
+ */
+
+#include <stdio.h>
+#include <malloc.h>
+#include <errno.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <syslog.h>
+#include <string.h>
+#include <syslog.h>
+#include <ctype.h>
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <netinet/in.h>
+
+#define MODULE_PARSE
+#include "automount.h"
+
+#define MODPREFIX "parse(sun): "
+int parse_version = AUTOFS_PARSE_VERSION; /* Required by protocol */
+
+static struct mount_mod *mount_nfs = NULL;
+static int init_ctr = 0;
+
+struct substvar {
+ char *def; /* Define variable */
+ char *val; /* Value to replace with */
+ struct substvar *next;
+};
+
+struct parse_context {
+ char *optstr; /* Mount options */
+ struct substvar *subst; /* $-substitutions */
+ int slashify_colons; /* Change colons to slashes? */
+};
+
+struct utsname un;
+char processor[65]; /* Not defined on Linux, so we make our own */
+
+static struct substvar /* Predefined variables: tail of link chain */
+ sv_arch = { "ARCH", un.machine, NULL },
+ sv_cpu = { "CPU", processor, &sv_arch },
+ sv_host = { "HOST", un.nodename, &sv_cpu },
+ sv_osname = { "OSNAME", un.sysname, &sv_host },
+ sv_osrel = { "OSREL", un.release, &sv_osname },
+ sv_osvers = { "OSVERS", un.version, &sv_osrel };
+
+/* Default context pattern */
+
+static struct parse_context default_context = {
+ NULL, /* No mount options */
+ &sv_osvers, /* The substvar predefined variables */
+ 1 /* Do slashify_colons */
+};
+
+/* Free all storage associated with this context */
+static void kill_context(struct parse_context *ctxt)
+{
+ struct substvar *sv, *nsv;
+
+ sv = ctxt->subst;
+ while ( sv != &sv_osvers ) {
+ nsv = sv->next;
+ free(sv);
+ sv = nsv;
+ }
+
+ if ( ctxt->optstr )
+ free(ctxt->optstr);
+
+ free(ctxt);
+}
+
+/* Find the $-variable matching a certain string fragment */
+static const struct substvar *findvar(const struct substvar *sv,
+ const char *str, int len)
+{
+ while ( sv ) {
+ if ( !strncmp(str,sv->def,len) && sv->def[len] == '\0' )
+ return sv;
+ sv = sv->next;
+ }
+ return NULL;
+}
+
+/* $- and &-expand a Sun-style map entry and return the length of the entry.
+ If "dst" is NULL, just count the length. */
+static int expandsunent(const char *src, char *dst, const char *key,
+ const struct substvar *svc, int slashify_colons)
+{
+ const struct substvar *sv;
+ int len, l, seen_colons;
+ const char *p;
+ char ch;
+
+ len = 0;
+ seen_colons = 0;
+
+ while ( (ch = *src++) ) {
+ switch ( ch ) {
+ case '&':
+ l = strlen(key);
+ if ( dst ) {
+ strcpy(dst,key);
+ dst += l;
+ }
+ len += l;
+ break;
+
+ case '$':
+ if ( *src == '{' ) {
+ p = strchr(++src,'}');
+ if ( !p ) {
+ /* Ignore rest of string */
+ if ( dst ) *dst = '\0';
+ return len;
+ }
+ sv = findvar(svc, src, p-src);
+ if ( sv ) {
+ l = strlen(sv->val);
+ if ( dst ) {
+ strcpy(dst,sv->val);
+ dst += l;
+ }
+ len += l;
+ }
+ src = p+1;
+ } else {
+ p = src;
+ while ( isalnum(*p) || *p == '_' ) p++;
+ sv = findvar(svc, src, p-src);
+ if ( sv ) {
+ l = strlen(sv->val);
+ if ( dst ) {
+ strcpy(dst,sv->val);
+ dst += l;
+ }
+ len += l;
+ }
+ src = p;
+ }
+ break;
+
+ case '\\':
+ ch = *src;
+ if ( ch ) {
+ src++;
+ if ( dst ) *(dst++) = ch;
+ len++;
+ } else {
+ ; /* Terminal backslash, just eat it */
+ }
+ break;
+
+ case ':':
+ if ( dst ) *(dst++) = (seen_colons && slashify_colons) ? '/' : ':';
+ len++;
+ seen_colons = 1;
+ break;
+
+ default:
+ if ( dst ) *(dst++) = ch;
+ len++;
+ break;
+ }
+ }
+ if ( dst ) *dst = '\0';
+ return len;
+}
+
+/* Skip whitespace in a string; if we hit a #, consider the rest of the
+ entry a comment */
+char *skipspace(char *whence)
+{
+ while(1) {
+ switch(*whence) {
+ case ' ':
+ case '\b':
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ whence++;
+ break;
+ case '\0':
+ case '#':
+ return NULL; /* End of string */
+ default:
+ return whence;
+ }
+ }
+}
+
+/* Get the length of a chunk delimitered by whitespace */
+int chunklen(char *whence)
+{
+ int n = 0;
+ while(1) {
+ switch(*whence) {
+ case ' ':
+ case '\b':
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case '#':
+ case '\0':
+ return n;
+ default:
+ break;
+ }
+ n++;
+ whence++;
+ }
+}
+
+/* Compare str with pat. Return 0 if compare equal or str is an abbreviation of
+ pat of no less than mchr characters. */
+int strmcmp(const char *str, const char *pat, int mchr)
+{
+ int nchr = 0;
+
+ while ( *str == *pat ) {
+ if ( ! *str ) return 0;
+ str++; pat++; nchr++;
+ }
+
+ if ( ! *str && nchr > mchr )
+ return 0;
+
+ return *pat - *str;
+}
+
+int parse_init(int argc, const char * const *argv, void **context)
+{
+ struct parse_context *ctxt;
+ struct substvar *sv;
+ char *noptstr;
+ const char *xopt;
+ int optlen, len;
+ int i, bval;
+
+ /* Get processor information for predefined escapes */
+
+ if ( !init_ctr ) {
+ uname(&un);
+ /* uname -p is not defined on Linux. Make it the same as uname -m,
+ except make it return i386 on all x86 (x >= 3) */
+ strcpy(processor, un.machine);
+ if ( processor[0] == 'i' && processor[1] >= '3' &&
+ !strcmp(processor+2, "86") )
+ processor[1] = '3';
+ }
+
+ /* Set up context and escape chain */
+
+ if ( !(ctxt = (struct parse_context *) malloc(sizeof(struct parse_context))) ) {
+ syslog(LOG_CRIT, MODPREFIX "malloc: %m");
+ return 1;
+ }
+ *context = (void *) ctxt;
+
+ *ctxt = default_context;
+ optlen = 0;
+
+ /* Look for options and capture, and create new defines if we need to */
+
+ for ( i = 0 ; i < argc ; i++ ) {
+ if ( argv[i][0] == '-' ) {
+ switch(argv[i][1]) {
+ case 'D':
+ sv = malloc(sizeof(struct substvar));
+ if ( !sv ) {
+ syslog(LOG_ERR, MODPREFIX "malloc: %m");
+ break;
+ }
+ if ( argv[i][2] )
+ sv->def = strdup(argv[i]+2);
+ else if ( ++i < argc )
+ sv->def = strdup(argv[i]);
+ else {
+ free(sv);
+ break;
+ }
+
+ if ( !sv->def ) {
+ syslog(LOG_ERR, MODPREFIX "strdup: %m");
+ free(sv);
+ } else {
+ sv->val = strchr(sv->def, '=');
+ if ( sv->val )
+ *(sv->val++) = '\0';
+ else
+ sv->val = "";
+
+ sv->next = ctxt->subst;
+ ctxt->subst = sv;
+ }
+ break;
+
+ case '-':
+ if ( !strncmp(argv[i]+2, "no-", 3) ) {
+ xopt = argv[i]+5;
+ bval = 0;
+ } else {
+ xopt = argv[i]+2;
+ bval = 1;
+ }
+
+ if ( strmcmp(xopt, "slashify-colons", 1) )
+ ctxt->slashify_colons = bval;
+ else
+ syslog(LOG_ERR, MODPREFIX "unknown option: %s", argv[i]);
+
+ break;
+
+ default:
+ syslog(LOG_ERR, MODPREFIX "unknown option: %s", argv[i]);
+ break;
+ }
+ } else {
+ len = strlen(argv[i]);
+ if ( ctxt->optstr ) {
+ noptstr = (char *) realloc(ctxt->optstr, optlen+len+2);
+ if ( !noptstr )
+ break;
+ noptstr[optlen] = ',';
+ strcpy(noptstr+optlen+1, argv[i]);
+ optlen += len+1;
+ } else {
+ noptstr = (char *) malloc(len+1);
+ strcpy(noptstr, argv[i]);
+ optlen = len;
+ }
+ if ( !noptstr ) {
+ kill_context(ctxt);
+ syslog(LOG_CRIT, MODPREFIX "%m");
+ return 1;
+ }
+ ctxt->optstr = noptstr;
+ syslog(LOG_DEBUG, MODPREFIX "init gathered options: %s", ctxt->optstr);
+ }
+ }
+
+ /* We only need this once. NFS mounts are so common that we cache
+ this module. */
+ if ( !mount_nfs )
+ if ( (mount_nfs = open_mount("nfs", MODPREFIX)) ) {
+ init_ctr++;
+ return 0;
+ } else {
+ kill_context(ctxt);
+ return 1;
+ }
+ else {
+ init_ctr++;
+ return 0;
+ }
+}
+
+int parse_mount(const char *root, const char *name,
+ int name_len, const char *mapent, void *context)
+{
+ struct parse_context *ctxt = (struct parse_context *) context;
+ char *pmapent, *options, *noptions, *ent, *p, *q, *fstype;
+ int mapent_len, rv;
+ int l, optlen;
+
+ mapent_len = expandsunent(mapent,NULL,name,ctxt->subst,ctxt->slashify_colons);
+ pmapent = alloca(mapent_len + 1);
+ if (!pmapent) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %m");
+ return 1;
+ }
+ expandsunent(mapent,pmapent,name,ctxt->subst,ctxt->slashify_colons);
+
+ syslog(LOG_DEBUG, "expanded entry: %s", pmapent);
+
+ options = strdup(ctxt->optstr ? ctxt->optstr : "");
+ if ( !options ) {
+ syslog(LOG_ERR, MODPREFIX "strdup: %m");
+ return 1;
+ }
+ optlen = strlen(options);
+
+ p = pmapent;
+ ent = NULL;
+
+ while ( (p = skipspace(p)) ) {
+ if ( *p == '-' ) {
+ l = chunklen(++p);
+ if ( !l )
+ continue;
+ noptions = realloc(options, optlen+l+(optlen ? 2 : 1));
+ if ( !noptions ) {
+ free(options);
+ syslog(LOG_ERR, MODPREFIX "realloc: %m");
+ return 1;
+ }
+ if ( optlen ) noptions[optlen++] = ',';
+ memcpy(noptions+optlen, p, l);
+ noptions[optlen += l] = '\0';
+ options = noptions;
+ p += l;
+ syslog(LOG_DEBUG, MODPREFIX "gathered options: %s", options);
+ } else if ( *p == '/' ) {
+ /* Uh-oh, a multientry; don't support now, but ****FIXME**** */
+ /* We do tolerate "multientries" that only contain / though... */
+ if ( chunklen(p) == 1 ) {
+ p++;
+ } else {
+ free(options);
+ syslog(LOG_NOTICE, MODPREFIX "entry %s is a multipath entry", name);
+ return 1;
+ }
+ } else {
+ p[chunklen(p)] = '\0'; /* We don't use anything after the entry */
+ if ( *p == ':' ) p++; /* Sun escape for entries starting with / */
+ if ( ! *p ) {
+ syslog(LOG_ERR, MODPREFIX "entry %s is empty!", name);
+ free(options);
+ return 1;
+ }
+ ent = p;
+ syslog(LOG_DEBUG, MODPREFIX "core of entry: %s", ent);
+ break; /* We have the core entry, run w/it */
+ }
+ }
+
+ fstype = "nfs"; /* Default filesystem type */
+
+ /* Scan for -fstype= option, which isn't a real mount option */
+
+ noptions = strdup(options);
+ if ( !noptions ) {
+ syslog(LOG_ERR, MODPREFIX "strdup: %m");
+ free(options);
+ return 1;
+ }
+
+ p = options;
+
+ for ( q = strtok(noptions, ",") ; q ; q = strtok(NULL, ",") ) {
+ if ( !strncmp(q, "fstype=", 7) ) {
+ fstype = alloca(strlen(q+7)+1);
+ if ( !fstype ) {
+ syslog(LOG_ERR, MODPREFIX "alloca: %s");
+ return 1;
+ }
+ strcpy(fstype, q+7);
+ } else {
+ l = strlen(q);
+ memcpy(p, q, l);
+ p += l;
+ *p = ',';
+ p++;
+ }
+ }
+
+ if ( p > options ) {
+ --p; /* Delete last comma */
+ *p = '\0';
+ } else {
+ free(options); /* No options - mount modules want NULL here */
+ options = NULL;
+ }
+ free(noptions);
+
+ if ( !strcmp(fstype, "nfs") ) {
+ rv = mount_nfs->mount_mount(root, name, name_len, ent, fstype, options,
+ mount_nfs->context);
+ } else {
+ /* Generic mount routine */
+ rv = do_mount(root, name, name_len, ent, fstype, options);
+ }
+
+ if (options) free(options);
+ return rv;
+}
+
+int parse_done(void *context)
+{
+ int rv = 0;
+ struct parse_context *ctxt = (struct parse_context *)context;
+
+ if ( --init_ctr == 0 ) {
+ rv = close_mount(mount_nfs);
+ mount_nfs = NULL;
+ }
+ kill_context(ctxt);
+ return rv;
+}