* NEWS: mention new feature of executable maps.
authorErez Zadok <ezk@cs.sunysb.edu>
Tue, 8 Mar 2005 06:05:32 +0000 (06:05 +0000)
committerErez Zadok <ezk@cs.sunysb.edu>
Tue, 8 Mar 2005 06:05:32 +0000 (06:05 +0000)
* AUTHORS: Acknowledge Erik Kline.

* scripts/amd.conf.5: document executable maps and
exec_map_timeout parameter.

* scripts/amd.conf-sample: examples of an executable map and
exec_map_timeout.

* m4/macros/header_templates.m4: template for HAVE_MAP_EXEC.

* doc/am-utils.texi: document Executable maps and exec_map_timeout
parameter.

* amd/conf.c (gopt_exec_map_timeout): function to parse
exec_map_timeout [global] parameter.

* amd/amd.h (AMFS_EXEC_MAP_TIMEOUT): define default executable map
timeout to 10 seconds, and a global placeholder for the
configurable value.

* amd/amd.c (init_global_options): initialize default executable
map timeout.

* amd/Makefile.am (EXTRA_amd_SOURCES): include info_exec.c in
tarball.

* configure.in: enable executable maps.

* amd/mapc.c: define executable map functions and behavior.

* amd/info_exec.c: executable map implementation from Erik Kline
<ekline at ekline dot com>, modified, cleaned-up, and fixed.

This is not the correct behavior.

14 files changed:
AUTHORS
ChangeLog
NEWS
amd/Makefile.am
amd/amd.c
amd/amd.h
amd/conf.c
amd/info_exec.c [new file with mode: 0644]
amd/mapc.c
configure.in
doc/am-utils.texi
m4/macros/header_templates.m4
scripts/amd.conf-sample
scripts/amd.conf.5

diff --git a/AUTHORS b/AUTHORS
index 63b1969c114db4573aa15aaa8ae507474b1509ed..8ff68cb9659f29d1b514c54e130aaa3afd9175eb 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -406,3 +406,6 @@ March 2, 2005: new global amd.conf option debug_mtab_file, to set the debug
 mtab file when using debug_options=mtab.  Default has changed from "./mtab"
 to "/tmp/mtab" to avoid security problem.  Bug fixed to ensure that Amd
 terminates properly even mtab file doesn't exist.
+
+* Erik Kline <ekline at ekline dot com>
+January 3, 2005: implementation of executable maps for Amd.
index 81835c98cfb878cffdadb01efe9e368759a9fc34..671d5f88c2d3ad7945a508ef5e638b42134fa0a5 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2005-03-08  Erez Zadok  <ezk@cs.sunysb.edu>
+
+       * NEWS: mention new feature of executable maps.
+
+       * AUTHORS: Acknowledge Erik Kline.
+
+       * scripts/amd.conf.5: document executable maps and
+       exec_map_timeout parameter.
+
+       * scripts/amd.conf-sample: examples of an executable map and
+       exec_map_timeout.
+
+       * m4/macros/header_templates.m4: template for HAVE_MAP_EXEC.
+
+       * doc/am-utils.texi: document Executable maps and exec_map_timeout
+       parameter.
+
+       * amd/conf.c (gopt_exec_map_timeout): function to parse
+       exec_map_timeout [global] parameter.
+
+       * amd/amd.h (AMFS_EXEC_MAP_TIMEOUT): define default executable map
+       timeout to 10 seconds, and a global placeholder for the
+       configurable value.
+
+       * amd/amd.c (init_global_options): initialize default executable
+       map timeout.
+
+       * amd/Makefile.am (EXTRA_amd_SOURCES): include info_exec.c in
+       tarball.
+
+       * configure.in: enable executable maps.
+
+       * amd/mapc.c: define executable map functions and behavior.
+
+       * amd/info_exec.c: executable map implementation from Erik Kline
+       <ekline at ekline dot com>, modified, cleaned-up, and fixed.
+
 2005-03-07  Erez Zadok  <ezk@cs.sunysb.edu>
 
        * amd/info_file.c (file_init_or_mtime): consolidate identical
        amu_ldap_init, aldh->ldap is not set.  So when amu_ldap_rebind is
        called, this function is absolutely sure to return 0.  Then
        amu_ldap_init return 0 without having opened any LDAP connection.
-       This is not the correct behaviour.
+       This is not the correct behavior.
        (get_ldap_timestamp, amu_ldap_search): error to free an object
        ("entry") that is automatically freed by the library.  Patch from
        Sebastien Bahloul <sebastien.bahloul@mangoosta.fr>.
diff --git a/NEWS b/NEWS
index 7f375bb2fcbd5806f29620be6bb74294ba92159a..d6b1d0a7b37b7643fc4cdfd525de327a651b18b5 100644 (file)
--- a/NEWS
+++ b/NEWS
        sparc64-unknown-linux-deb3.0
        x86_64-unknown-linux-rh2.9.5AS
 
+- support for executable maps ala Sun automounter.  Set map_type=exec in
+  amd.conf, and map_name to a program/script that takes a key as argv[1],
+  and returns key-value pair on stdout.  See also exec_map_timeout [global]
+  parameter which defines how many seconds (default 10 sec) Amd will wait
+  for an executable map program to return output before timing out.  See
+  am-utils manual for full details.
+
 - new amd.conf parameter "nfs_allow_insecure_port".  Used to work around
   bugs in certain kernels, which cause them to try and talk to amd from
   unprivileged ports.
index c9fcd5f08b0ee6d843242ed5f49c582705d45fb8..4d4fcbb6e7ace0718f8f9892feff1f70a7dc2100 100644 (file)
@@ -63,6 +63,7 @@ amd_SOURCES =                 \
 # the complete list of all optional sources
 EXTRA_amd_SOURCES =    \
        info_file.c     \
+       info_exec.c     \
        info_hesiod.c   \
        info_ldap.c     \
        info_ndbm.c     \
index 45b84619f8a5b870a33cbfa9b90c869e689b45f7..f091c3783e448a75ed05f9420c45fb3c70ae1a73 100644 (file)
--- a/amd/amd.c
+++ b/amd/amd.c
@@ -37,7 +37,7 @@
  * SUCH DAMAGE.
  *
  *
- * $Id: amd.c,v 1.34 2005/02/27 23:33:34 ezk Exp $
+ * $Id: amd.c,v 1.35 2005/03/08 06:05:33 ezk Exp $
  *
  */
 
@@ -254,6 +254,9 @@ init_global_options(void)
   /* cluster name */
   gopt.cluster = NULL;
 
+  /* executable map timeout */
+  gopt.exec_map_timeout = AMFS_EXEC_MAP_TIMEOUT;
+
   /*
    * kernel architecture: this you must get from uname() if possible.
    */
index 8982bd076fafe170510f6e16dc24505922a65a2a..2a71a0ad21830fd2d78dfbd0df058ce602fba4e2 100644 (file)
--- a/amd/amd.h
+++ b/amd/amd.h
@@ -37,7 +37,7 @@
  * SUCH DAMAGE.
  *
  *
- * $Id: amd.h,v 1.62 2005/03/06 01:26:30 ib42 Exp $
+ * $Id: amd.h,v 1.63 2005/03/08 06:05:33 ezk Exp $
  *
  */
 
@@ -55,7 +55,7 @@
  */
 #ifdef MOUNT_TABLE_ON_FILE
 # define DEBUG_MNTTAB_FILE               "/tmp/mnttab"
-#endif
+#endif /* MOUNT_TABLE_ON_FILE */
 
 /* options for amd.conf */
 #define CFM_BROWSABLE_DIRS             0x0001
 #define        AM_TTL_W                (120) /* Default unmount interval (2 min) */
 #define        AM_PINGER               30 /* NFS ping interval for live systems */
 #define        AMFS_AUTO_TIMEO         8 /* Default amfs_auto timeout - .8s */
+#define AMFS_EXEC_MAP_TIMEOUT  10 /* default 10sec exec map timeout */
 
 /* interval between forced retries of a mount */
 #define RETRY_INTERVAL 2
@@ -296,6 +297,7 @@ struct amu_global_options {
 #endif /* HAVE_MAP_NIS */
   char *nfs_proto;             /* NFS protocol (NULL, udp, tcp) */
   int nfs_vers;                        /* NFS version (0, 2, 3, 4) */
+  u_int exec_map_timeout;      /* timeout (seconds) for executable maps */
 };
 
 /* if you add anything here, update conf.c:reset_cf_map() */
index d5cd76dafefb98ff0675553f6765c9aac7f8fa0b..6c152dd92b9718a945ed1f1ae80875de3a4c9fed 100644 (file)
@@ -37,7 +37,7 @@
  * SUCH DAMAGE.
  *
  *
- * $Id: conf.c,v 1.30 2005/03/04 18:42:43 ezk Exp $
+ * $Id: conf.c,v 1.31 2005/03/08 06:05:33 ezk Exp $
  *
  */
 
@@ -85,6 +85,7 @@ static int gopt_debug_mtab_file(const char *val);
 static int gopt_debug_options(const char *val);
 static int gopt_dismount_interval(const char *val);
 static int gopt_domain_strip(const char *val);
+static int gopt_exec_map_timeout(const char *val);
 static int gopt_full_os(const char *val);
 static int gopt_fully_qualified_hosts(const char *val);
 static int gopt_hesiod_base(const char *val);
@@ -160,6 +161,7 @@ static struct _func_map glob_functable[] = {
   {"debug_options",            gopt_debug_options},
   {"dismount_interval",                gopt_dismount_interval},
   {"domain_strip",             gopt_domain_strip},
+  {"exec_map_timeout",         gopt_exec_map_timeout},
   {"fully_qualified_hosts",    gopt_fully_qualified_hosts},
   {"full_os",                  gopt_full_os},
   {"hesiod_base",              gopt_hesiod_base},
@@ -478,6 +480,16 @@ gopt_domain_strip(const char *val)
 }
 
 
+static int
+gopt_exec_map_timeout(const char *val)
+{
+  gopt.exec_map_timeout = atoi(val);
+  if (gopt.exec_map_timeout <= 0)
+    gopt.exec_map_timeout = AMFS_EXEC_MAP_TIMEOUT; /* default exec map timeout */
+  return 0;
+}
+
+
 static int
 gopt_full_os(const char *val)
 {
diff --git a/amd/info_exec.c b/amd/info_exec.c
new file mode 100644 (file)
index 0000000..e138882
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 1997-2005 Erez Zadok
+ * Copyright (c) 1990 Jan-Simon Pendry
+ * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Jan-Simon Pendry at Imperial College, London.
+ *
+ * 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.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgment:
+ *      This product includes software developed by the University of
+ *      California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
+ *
+ *      %W% (Berkeley) %G%
+ *
+ * $Id: info_exec.c,v 1.1 2005/03/08 06:05:33 ezk Exp $
+ *
+ */
+
+/*
+ * Get info from executable map
+ *
+ * Original from Erik Kline, 2004.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif /* HAVE_CONFIG_H */
+#include <am_defs.h>
+#include <amd.h>
+
+#define        MAX_LINE_LEN            1500
+
+/* forward declarations */
+int exec_init(mnt_map *m, char *map, time_t *tp);
+int exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp);
+
+
+/*
+ * a timed fgets()
+ */
+static char *
+fgets_timed(char *s, int size, int rdfd, int secs)
+{
+  fd_set fds;
+  struct timeval timeo;
+  time_t start, now;
+  int rval=0, i=0;
+
+  if (!s || size < 0 || rdfd < 0)
+    return 0;
+
+  s[0] = 0;
+  if (size == 0)
+    return s;
+
+  start = clocktime();
+  while (s[i] != '\n'  &&  i < size-1) {
+    s[i+1] = 0; /* places the requisite trailing '\0' */
+
+    /* ready for reading */
+    rval = read(rdfd, (void *)(s+i), 1);
+    if (rval == 1) {
+      if (s[i] == 0) {
+        rval = 0;
+        break;
+      }
+      i++;
+      continue;
+    } else if (rval == 0) {
+      break;
+    } else if (rval < 0  &&  errno != EAGAIN  &&  errno != EINTR) {
+      plog(XLOG_WARNING, "fgets_timed read error: %m");
+      break;
+    }
+
+    timeo.tv_usec = 0;
+    now = clocktime() - start;
+    if (secs <= 0)
+      timeo.tv_sec = 0;
+    else if (now < secs)
+      timeo.tv_sec = secs - now;
+    else {
+      /* timed out (now>=secs) */
+      plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs);
+      rval = -1;
+      break;
+    }
+
+    FD_ZERO(&fds);
+    FD_SET(rdfd, &fds);
+
+    rval = select(rdfd+1, &fds, 0, 0, &timeo);
+    if (rval < 0) {
+      /* error selecting */
+      plog(XLOG_WARNING, "fgets_timed select error: %m");
+      if (errno == EINTR)
+        continue;
+      rval = -1;
+      break;
+    } else if (rval == 0) {
+      /* timed out */
+      plog(XLOG_WARNING, "executable map read timed out (> %d secs)", secs);
+      rval = -1;
+      break;
+    }
+  }
+
+  if (rval > 0)
+    return s;
+
+  close(rdfd);
+  return (rval == 0 ? s : 0);
+}
+
+
+static int
+read_line(char *buf, int size, int fd)
+{
+  int done = 0;
+
+  while (fgets_timed(buf, size, fd, gopt.exec_map_timeout)) {
+    int len = strlen(buf);
+    done += len;
+    if (len > 1  &&  buf[len - 2] == '\\' &&
+        buf[len - 1] == '\n') {
+      buf += len - 2;
+      size -= len - 2;
+      *buf = '\n';
+      buf[1] = '\0';
+    } else {
+      return done;
+    }
+  }
+
+  return done;
+}
+
+
+/*
+ * Try to locate a value in a query answer
+ */
+static int
+exec_parse_qanswer(int fd, char *map, char *key, char **pval, time_t *tp)
+{
+  char qanswer[MAX_LINE_LEN], *dc = 0;
+  int chuck = 0;
+  int line_no = 0;
+
+  while (read_line(qanswer, sizeof(qanswer), fd)) {
+    char *cp;
+    char *hash;
+    int len = strlen(qanswer);
+    line_no++;
+
+    /*
+     * Make sure we got the whole line
+     */
+    if (qanswer[len - 1] != '\n') {
+      plog(XLOG_WARNING, "line %d in \"%s\" is too long", line_no, map);
+      chuck = 1;
+    } else {
+      qanswer[len - 1] = '\0';
+    }
+
+    /*
+     * Strip comments
+     */
+    hash = strchr(qanswer, '#');
+    if (hash)
+      *hash = '\0';
+
+    /*
+     * Find beginning of value (query answer)
+     */
+    for (cp = qanswer; *cp && !isascii((int)*cp) && !isspace((int)*cp); cp++)
+      ;;
+
+    /* Ignore blank lines */
+    if (!*cp)
+      goto again;
+
+    /*
+     * Return a copy of the data
+     */
+    dc = strdup(cp);
+    *pval = dc;
+    dlog("%s returns %s", key, dc);
+
+    close(fd);
+    return 0;
+
+  again:
+    /*
+     * If the last read didn't get a whole line then
+     * throw away the remainder before continuing...
+     */
+    if (chuck) {
+      while (fgets_timed(qanswer, sizeof(qanswer), fd, gopt.exec_map_timeout) &&
+            !strchr(qanswer, '\n')) ;
+      chuck = 0;
+    }
+  }
+
+  return ENOENT;
+}
+
+
+static int
+set_nonblock(int fd)
+{
+  int val;
+
+  if (fd < 0)
+     return 0;
+
+  if ((val = fcntl(fd, F_GETFL, 0)) < 0) {
+    plog(XLOG_WARNING, "set_nonblock fcntl F_GETFL error: %m");
+    return 0;
+  }
+
+  val |= O_NONBLOCK;
+  if (fcntl(fd, F_SETFL, val) < 0) {
+    plog(XLOG_WARNING, "set_nonblock fcntl F_SETFL error: %m");
+    return 0;
+  }
+
+  return 1;
+}
+
+
+static int
+exec_map_open(char *emap, char *key)
+{
+  pid_t p1, p2;
+  int pdes[2], nullfd, i;
+  char *argv[3];
+
+  if (!emap)
+    return 0;
+
+  argv[0] = emap;
+  argv[1] = key;
+  argv[2] = NULL;
+
+  if ((nullfd = open("/dev/null", O_WRONLY|O_NOCTTY)) < 0)
+    return -1;
+
+  if (pipe(pdes) < 0) {
+    close(nullfd);
+    return -1;
+  }
+
+  switch((p1 = vfork())) {
+    case -1:
+      /* parent: fork error */
+      close(nullfd);
+      close(pdes[0]);
+      close(pdes[1]);
+      return -1;
+    case 0:
+      /* child #1 */
+      switch((p2 = vfork())) {
+        case -1:
+          /* child #1: fork error */
+          exit(errno);
+        case 0:
+          /* child #2: init will reap our status */
+          if (pdes[1] != STDOUT_FILENO) {
+            dup2(pdes[1], STDOUT_FILENO);
+            close(pdes[1]);
+          }
+
+          if (nullfd != STDERR_FILENO) {
+            dup2(nullfd, STDERR_FILENO);
+            close(nullfd);
+          }
+
+          for (i=0; i<FD_SETSIZE; i++)
+            if (i != STDOUT_FILENO  &&  i != STDERR_FILENO)
+              close(i);
+
+          /* make the write descriptor non-blocking */
+          if (!set_nonblock(STDOUT_FILENO)) {
+            close(STDOUT_FILENO);
+            exit(-1);
+          }
+
+          execve(emap, argv, NULL);
+          exit(errno);         /* in case execve failed */
+      }
+
+      /* child #1 */
+      exit(0);
+  }
+
+  /* parent */
+  close(nullfd);
+  close(pdes[1]);
+
+  /* anti-zombie insurance */
+  while(waitpid(p1,0,0) < 0)
+    if (errno != EINTR)
+      exit(errno);
+
+  /* make the read descriptor non-blocking */
+  if (!set_nonblock(pdes[0])) {
+    close(pdes[0]);
+    return -1;
+  }
+
+  return pdes[0];
+}
+
+
+/*
+ * Check for various permissions on executable map without trying to
+ * fork a new executable-map process.
+ *
+ * return: >0 (errno) if failed
+ *          0 if ok
+ */
+static int
+exec_check_perm(char *map)
+{
+  struct stat sb;
+
+  /* sanity and permission checks */
+  if (!map) {
+    dlog("exec_check_permission got a NULL map");
+    return EINVAL;
+  }
+  if (stat(map, &sb)) {
+    plog(XLOG_ERROR, "map \"%s\" stat failure: %m", map);
+    return errno;
+  }
+  if (!S_ISREG(sb.st_mode)) {
+    plog(XLOG_ERROR, "map \"%s\" should be regular file", map);
+    return EINVAL;
+  }
+  if (sb.st_uid != 0) {
+    plog(XLOG_ERROR, "map \"%s\" owned by uid %d (must be 0)", map, sb.st_uid);
+    return EACCES;
+  }
+  if (!(sb.st_mode & S_IXUSR)) {
+    plog(XLOG_ERROR, "map \"%s\" should be executable", map);
+    return EACCES;
+  }
+  if (sb.st_mode & (S_ISUID|S_ISGID)) {
+    plog(XLOG_ERROR, "map \"%s\" should not be setuid/setgid", map);
+    return EACCES;
+  }
+  if (sb.st_mode & S_IWOTH) {
+    plog(XLOG_ERROR, "map \"%s\" should not be world writeable", map);
+    return EACCES;
+  }
+
+  return 0;                    /* all is well */
+}
+
+
+int
+exec_init(mnt_map *m, char *map, time_t *tp)
+{
+  /*
+   * Basically just test that the executable map can be found
+   * and has proper permissions.
+   */
+  return exec_check_perm(map);
+}
+
+
+int
+exec_search(mnt_map *m, char *map, char *key, char **pval, time_t *tp)
+{
+  int mapfd, ret;
+
+  if ((ret = exec_check_perm(map)) != 0) {
+    return ret;
+  }
+
+  if (!key)
+    return 0;
+
+  if (logfp)
+    fflush(logfp);
+  dlog("exec_search \"%s\", key: \"%s\"", map, key);
+  mapfd = exec_map_open(map, key);
+
+  if (mapfd >= 0) {
+    if (tp)
+      *tp = clocktime();
+
+    return exec_parse_qanswer(mapfd, map, key, pval, tp);
+  }
+
+  return errno;
+}
index 6953cb41aeaf6823fda5df9d865ee5e2f44bc034..ac6df926cd3501fe298e9b5c2d53a5eaac3674d9 100644 (file)
@@ -37,7 +37,7 @@
  * SUCH DAMAGE.
  *
  *
- * $Id: mapc.c,v 1.23 2005/03/08 02:51:30 ezk Exp $
+ * $Id: mapc.c,v 1.24 2005/03/08 06:05:33 ezk Exp $
  *
  */
 
@@ -198,6 +198,12 @@ extern int ndbm_search(mnt_map *, char *, char *, char **, time_t *);
 extern int ndbm_mtime(mnt_map *, char *, time_t *);
 #endif /* HAVE_MAP_NDBM */
 
+/* EXECUTABLE MAPS */
+#ifdef HAVE_MAP_EXEC
+extern int exec_init(mnt_map *, char *, time_t *);
+extern int exec_search(mnt_map *, char *, char *, char **, time_t *);
+#endif /* HAVE_MAP_EXEC */
+
 /* FILE MAPS */
 #ifdef HAVE_MAP_FILE
 extern int file_init_or_mtime(mnt_map *, char *, time_t *);
@@ -295,6 +301,17 @@ static map_type maptypes[] =
     MAPC_INC
   },
 #endif /* HAVE_MAP_NDBM */
+#ifdef HAVE_MAP_EXEC
+  {
+    "exec",
+    exec_init,
+    error_reload,
+    NULL,                      /* isup function */
+    exec_search,
+    error_mtime,
+    MAPC_INC
+  },
+#endif /* HAVE_MAP_EXEC */
 #ifdef HAVE_MAP_FILE
   {
     "file",
index 1166267664ea2cef503f010d76f9b72b04624848..ba6a96610ffe211a8be2820c02ce42d20f6ab325 100644 (file)
@@ -53,7 +53,7 @@ AH_BOTTOM([
 dnl
 dnl AC_CONFIG_AUX_DIR(m4)
 AC_PREREQ(2.52)
-AC_REVISION($Revision: 1.79 $)
+AC_REVISION($Revision: 1.80 $)
 AC_COPYRIGHT([Copyright (c) 1997-2005 Erez Zadok])
 dnl find out system type
 AC_MSG_NOTICE(*** SYSTEM TYPES ***)
@@ -799,6 +799,7 @@ AC_MSG_NOTICE(*** MAP TYPES ***)
 dnl DBM is obsolete, use NDBM
 dnl AMU_CHECK_MAP_FUNCS(dbminit dbmopen, dbm)
 AMU_CHECK_MAP_FUNCS(fgets, file)
+AMU_CHECK_MAP_FUNCS(waitpid, exec)
 dnl Define HESIOD map if user wanted it, and both headers and libraries exist
 if test "$with_hesiod" = "yes" && test "$ac_cv_header_hesiod_h" = "yes"
 then
index db5775b11f4d941d875881de669695a6b6c5127d..c53b6c6f2171f69cb4c1470e7f50ed50fab67013 100644 (file)
@@ -38,7 +38,7 @@
 @c
 @c      %W% (Berkeley) %G%
 @c
-@c $Id: am-utils.texi,v 1.99 2005/03/06 03:19:01 ezk Exp $
+@c $Id: am-utils.texi,v 1.100 2005/03/08 06:05:33 ezk Exp $
 @c
 @setfilename am-utils.info
 
@@ -841,8 +841,10 @@ list of map types configured on your machine.
 * Password maps::
 * Union maps::
 * LDAP maps::
+* Executable maps::
 @end menu
 
+@c ----------------------------------------------------------------
 @node File maps, ndbm maps, Map Types, Map Types
 @comment  node-name,  next,  previous,  up
 @subsection File maps
@@ -897,6 +899,7 @@ file maps, or ndbm maps built with the @code{mk-amd-map} program.
 When caching is enabled, file maps have a default cache mode of
 @code{all} (@pxref{Automount Filesystem}).
 
+@c ----------------------------------------------------------------
 @node ndbm maps, NIS maps, File maps, Map Types
 @comment  node-name,  next,  previous,  up
 @subsection ndbm maps
@@ -910,8 +913,10 @@ be sharable across machine architectures.  The notion of speed generally
 only applies to large maps; a small map, less than a single disk block,
 is almost certainly better implemented as a file map.
 
-ndbm maps have a default cache mode of @samp{all} (@pxref{Automount Filesystem}).
+ndbm maps have a default cache mode of @samp{all}
+(@pxref{Automount Filesystem}).
 
+@c ----------------------------------------------------------------
 @node NIS maps, NIS+ maps, ndbm maps, Map Types
 @comment  node-name,  next,  previous,  up
 @subsection NIS maps
@@ -952,9 +957,10 @@ $(YPTSDIR)/amd.home.time: $(ETCDIR)/amd.home
     fi
 @end example
 
-Here @code{$(YPTSDIR)} contains the time stamp files, and @code{$(YPDBDIR)} contains
-the dbm format NIS files.
+Here @code{$(YPTSDIR)} contains the time stamp files, and
+@code{$(YPDBDIR)} contains the dbm format NIS files.
 
+@c ----------------------------------------------------------------
 @node NIS+ maps, Hesiod maps, NIS maps, Map Types
 @comment  node-name,  next,  previous,  up
 @subsection NIS+ maps
@@ -965,6 +971,7 @@ enabled, have a default cache mode of @samp{inc}.
 
 XXX: FILL IN WITH AN EXAMPLE.
 
+@c ----------------------------------------------------------------
 @node Hesiod maps, Password maps, NIS+ maps, Map Types
 @comment  node-name,  next,  previous,  up
 @subsection Hesiod maps
@@ -990,6 +997,7 @@ jsp.homes.automount HS TXT "rfs:=/home/charm;rhost:=charm;sublink:=jsp"
 njw.homes.automount HS TXT "rfs:=/home/dylan/dk2;rhost:=dylan;sublink:=njw"
 @end example
 
+@c ----------------------------------------------------------------
 @node Password maps, Union maps, Hesiod maps, Map Types
 @comment  node-name,  next,  previous,  up
 @subsection Password maps
@@ -1036,7 +1044,8 @@ the map entry used by @i{Amd} would be
 rfs:=/home/sugar;rhost:=sugar.cc;sublink:=jsp
 @end example
 
-@node Union maps, LDAP maps , Password maps, Map Types
+@c ----------------------------------------------------------------
+@node Union maps, LDAP maps, Password maps, Map Types
 @comment  node-name,  next,  previous,  up
 @subsection Union maps
 @cindex Union file maps
@@ -1051,7 +1060,8 @@ directories take precedence over earlier ones.  The union filesystem
 type then uses the map cache to determine the union of the names in all
 the directories.
 
-@node LDAP maps, , Union maps, Map Types
+@c ----------------------------------------------------------------
+@node LDAP maps, Executable maps, Union maps, Map Types
 @comment  node-name,  next,  previous,  up
 @subsection LDAP maps
 @cindex LDAP maps
@@ -1102,8 +1112,42 @@ amdmapKey   : zing
 amdmapValue : -rhost:=shekel host==shekel host!=shekel;type:=nfs
 @end example
 
-@c subsection Gdbm
+@c ----------------------------------------------------------------
+@node Executable maps, , LDAP maps, Map Types
+@comment  node-name,  next,  previous,  up
+@subsection Executable maps
+@cindex Executable maps
 
+An executable map is a dynamic map in which the keys and values for
+the maps are generated on the fly by a program or script.  The program
+is expected to take a single parameter argument which is the key to
+lookup.  If the key is found, the program should print on stdout the
+key-value pair that were found; if the key was not found, nothing
+should be printed out.  Below is an sample of such a map script:
+
+@example
+#!/bin/sh
+# execuatable map example
+case "$1" in
+    "/defaults" )
+       echo "/defaults   type:=nfs;rfs:=filer"
+       ;;
+    "a" )
+       echo "a   type:=nfs;fs:=/tmp"
+       ;;
+    "b" )
+       echo "b   type:=link;fs:=/usr/local"
+       ;;
+    * )  # no match, echo nothing
+       ;;
+esac
+@end example
+
+@xref{exec_map_timeout Parameter}.
+
+@c ----------------------------------------------------------------
+@c subsection Gdbm
+@c ----------------------------------------------------------------
 @node Key Lookup, Location Format, Map Types, Mount Maps
 @comment  node-name,  next,  previous,  up
 @section How keys are looked up
@@ -4232,6 +4276,7 @@ The following parameters are applicable to the @samp{[global]} section only.
 * debug_options Parameter::
 * dismount_interval Parameter::
 * domain_strip Parameter::
+* exec_map_timeout Parameter::
 * full_os Parameter::
 * fully_qualified_hosts Parameter::
 * hesiod_base Parameter::
@@ -4364,7 +4409,7 @@ values those listed for the -D option.  @xref{-D Option}.
 systems that have exceeded their cached times.
 
 @c ----------------------------------------------------------------
-@node domain_strip Parameter, full_os Parameter, dismount_interval Parameter, Global Parameters
+@node domain_strip Parameter, exec_map_timeout Parameter, dismount_interval Parameter, Global Parameters
 @comment  node-name,  next,  previous,  up
 @subsection @t{domain_strip} Parameter
 @cindex domain_strip Parameter
@@ -4376,9 +4421,22 @@ part is left changed.  This is useful when using multiple domains with
 the same maps (as you may have hosts whose domain-stripped name is
 identical).
 
+@c ----------------------------------------------------------------
+@node exec_map_timeout Parameter, full_os Parameter, domain_strip Parameter, Global Parameters
+@comment  node-name,  next,  previous,  up
+@subsection @t{exec_map_timeout} Parameter
+@cindex exec_map_timeout Parameter
+
+(type=numeric, default=10).  The timeout in seconds that @i{Amd} will
+wait for an executable map program before an answer is returned from
+that program (or script).  This value should be set to as small as
+possible while still allowing normal replies to be returned before the
+timer expires, because during the time that the executable map program
+is queried, @i{Amd} is essentially waiting and is thus not responding
+to any other queries.  @xref{Executable maps}.
 
 @c ----------------------------------------------------------------
-@node full_os Parameter, fully_qualified_hosts Parameter, domain_strip Parameter, Global Parameters
+@node full_os Parameter, fully_qualified_hosts Parameter, exec_map_timeout Parameter, Global Parameters
 @comment  node-name,  next,  previous,  up
 @subsection @t{full_os} Parameter
 @cindex full_os Parameter
index 9d59a9bb499e94334a7df667c21be2b0fca51705..9af0ae299d952dc02aa08c86c155bdf2a3409cb6 100644 (file)
@@ -61,6 +61,9 @@ AH_TEMPLATE([HAVE_MAP_PASSWD],
 AH_TEMPLATE([HAVE_MAP_UNION],
 [Define if have UNION maps])
 
+AH_TEMPLATE([HAVE_MAP_EXEC],
+[Define if have executable maps])
+
 AH_TEMPLATE([HAVE_FS_UFS],
 [Define if have UFS filesystem])
 
index 5a75532d81535d1fa0d151ed24ba78c8a12a0366..cf5a1568f7b3a02b6bb50b6251e343de845547a3 100644 (file)
@@ -102,6 +102,8 @@ use_tcpwrappers =           yes | no
 nfs_allow_insecure_port =      yes | no
 # address used for local NFS mount and RPC server (default to localhost)
 localhost_address =            foo.example.com | 192.168.1.2
+# number of seconds to timeout before map returns output
+exec_map_timeout =             10
 
 ##############################################################################
 # DEFINE AN AMD MOUNT POINT
@@ -130,3 +132,10 @@ mount_type =                       nfs
 map_defaults =                 type:=nfs
 
 ##############################################################################
+# DEFINE ANOTHER AMD MOUNT POINT
+[ /test ]
+map_name =                     /etc/lookup-entry.sh
+# an executable map type
+mount_type =                   exec
+
+##############################################################################
index 0bf20ab5530e7ecc0b0b90600b07208e90ce2205..18972a0d71ea7aa49023cb463d9b7aecf7e8d4fa 100644 (file)
@@ -38,7 +38,7 @@
 .\"
 .\"    %W% (Berkeley) %G%
 .\"
-.\" $Id: amd.conf.5,v 1.35 2005/03/05 04:49:16 ezk Exp $
+.\" $Id: amd.conf.5,v 1.36 2005/03/08 06:05:33 ezk Exp $
 .\"
 .TH AMD.CONF 5 "7 August 1997"
 .SH NAME
@@ -145,6 +145,7 @@ and can have undesired side-effects such as initializing NIS even if not
 used.  Possible values are
 
 .nf
+\fBexec\fR      executable maps
 \fBfile\fR      plain files
 \fBhesiod\fR    Hesiod name service from MIT
 \fBldap\fR      Lightweight Directory Access Protocol
@@ -268,6 +269,17 @@ part is left changed.  This is useful when using multiple domains with
 the same maps (as you may have hosts whose domain-stripped name is
 identical).
 
+.TP
+.BR exec_map_timeout " (numeric, default=10)"
+The timeout in seconds that
+.I Amd
+will wait for an executable map program before an answer is returned from
+that program (or script).  This value should be set to as small as possible
+while still allowing normal replies to be returned before the timer expires,
+because during the time that the executable map program is queried,
+.I Amd
+is essentially waiting and is thus not responding to any other queries.
+
 .TP
 .BR full_os " (string, default to compiled in value)"
 The full name of the operating system, along with its version.  Allows you