Esempio n. 1
0
/*
 * These routines add a new style of selector; function-style boolean
 * operators.  To add new ones, just define functions as in true, false,
 * exists (below) and add them to the functable, above.
 *
 * Usage example: Some people have X11R5 local, some go to a server. I do
 * this:
 *
 *    *       exists(/usr/pkg/${key});type:=link;fs:=/usr/pkg/${key} || \
 *            -type:=nfs;rfs=/usr/pkg/${key} \
 *            rhost:=server1 \
 *            rhost:=server2
 *
 * -Rens Troost <*****@*****.**>
 */
static IntFuncPtr
functable_lookup(char *key)
{
  struct functable *fp;

  for (fp = functable; fp->name; fp++)
    if (FSTREQ(fp->name, key))
        return (fp->func);
  return (IntFuncPtr) NULL;
}
Esempio n. 2
0
/*
 * Fill in the global structure fs_static by
 * cracking the string opts.  opts may be
 * scribbled on at will.  Does NOT evaluate options.
 * Returns 0 on error, 1 if no syntax errors were discovered.
 */
static int
split_opts(char *opts, char *mapkey)
{
  char *o = opts;
  char *f;

  /*
   * For each user-specified option
   */
  for (f = opt(&o); *f; f = opt(&o)) {
    struct opt *op;
    char *eq = strchr(f, '=');
    char *opt = NULL;

    if (!eq)
      continue;

    if (eq[-1] == '!' ||
	eq[1] == '=' ||
	eq[1] == '!') {	/* != or == or =! */
      continue;			/* we don't care about selectors */
    }

    if (eq[-1] == ':') {	/* := */
      eq[-1] = '\0';
    } else {
      /* old style assignment */
      eq[0] = '\0';
    }
    opt = eq + 1;

    /*
     * For each recognized option
     */
    for (op = opt_fields; op->name; op++) {
      /*
       * Check whether they match
       */
      if (FSTREQ(op->name, f)) {
	if (op->sel_p) {
	  plog(XLOG_USER, "key %s: Can't assign to a selector (%s)",
	       mapkey, op->name);
	  return 0;
	}
	*op->optp = opt;	/* actual assignment into fs_static */
	break;			/* break out of for loop */
      }	/* end of "if (FSTREQ(op->name, f))" statement  */
    } /* end of "for (op = opt_fields..." statement  */

    if (!op->name)
      plog(XLOG_USER, "key %s: Unrecognized key/option \"%s\"", mapkey, f);
  }

  return 1;
}
Esempio n. 3
0
/*
 * Process global section of configuration file options.
 * Return 0 upon success, 1 otherwise.
 */
static int
process_global_option(const char *key, const char *val)
{
  struct _func_map *gfp;

  /* ensure that val is valid */
  if (!val || val[0] == '\0')
    return 1;

  /*
   * search for global function.
   */
  for (gfp = glob_functable; gfp->name; gfp++)
    if (FSTREQ(gfp->name, key))
      return (gfp->func)(val);

  fprintf(stderr, "conf: unknown global key: \"%s\"\n", key);
  return 1;			/* failed to match any command */
}
Esempio n. 4
0
static void
mapc_repl_kv(mnt_map *m, char *key, char *val)
{
  kv *k;

  /*
   * Compute the hash table offset
   */
  k = m->kvhash[kvhash_of(key)];

  /*
   * Scan the linked list for the key
   */
  while (k && !FSTREQ(k->key, key))
    k = k->next;

  if (k) {
    XFREE(k->val);
    k->val = val;
  } else {
    mapc_add_kv(m, key, val);
  }
}
Esempio n. 5
0
/****************************************************************************
 *** FUNCTIONS                                                             ***
 ****************************************************************************/
static am_node *
amfs_lookup_node(am_node *mp, char *fname, int *error_return)
{
  am_node *new_mp;
  int error = 0;		/* Error so far */
  int in_progress = 0;		/* # of (un)mount in progress */
  mntfs *mf;
  char *expanded_fname = NULL;

  dlog("in amfs_lookup_node");

  /*
   * If the server is shutting down
   * then don't return information
   * about the mount point.
   */
  if (amd_state == Finishing) {
    if (mp->am_al == NULL || mp->am_al->al_mnt == NULL || mp->am_al->al_mnt->mf_fsflags & FS_DIRECT) {
      dlog("%s mount ignored - going down", fname);
    } else {
      dlog("%s/%s mount ignored - going down", mp->am_path, fname);
    }
    ereturn(ENOENT);
  }

  /*
   * Handle special case of "." and ".."
   */
  if (fname[0] == '.') {
    if (fname[1] == '\0')
      return mp;		/* "." is the current node */
    if (fname[1] == '.' && fname[2] == '\0') {
      if (mp->am_parent) {
	dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path);
	return mp->am_parent;	/* ".." is the parent node */
      }
      ereturn(ESTALE);
    }
  }

  /*
   * Check for valid key name.
   * If it is invalid then pretend it doesn't exist.
   */
  if (!valid_key(fname)) {
    plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname);
    ereturn(ENOENT);
  }

  /*
   * Expand key name.
   * expanded_fname is now a private copy.
   */
  expanded_fname = expand_selectors(fname);

  /*
   * Search children of this node
   */
  for (new_mp = mp->am_child; new_mp; new_mp = new_mp->am_osib) {
    if (FSTREQ(new_mp->am_name, expanded_fname)) {
      if (new_mp->am_error) {
	error = new_mp->am_error;
	continue;
      }

      /*
       * If the error code is undefined then it must be
       * in progress.
       */
      mf = new_mp->am_al->al_mnt;
      if (mf->mf_error < 0)
	goto in_progrss;

      /*
       * If there was a previous error with this node
       * then return that error code.
       */
      if (mf->mf_flags & MFF_ERROR) {
	error = mf->mf_error;
	continue;
      }
      if (!(mf->mf_flags & MFF_MOUNTED) || (mf->mf_flags & MFF_UNMOUNTING)) {
      in_progrss:
	/*
	 * If the fs is not mounted or it is unmounting then there
	 * is a background (un)mount in progress.  In this case
	 * we just drop the RPC request (return nil) and
	 * wait for a retry, by which time the (un)mount may
	 * have completed.
	 */
	dlog("ignoring mount of %s in %s -- %smounting in progress, flags %x",
	     expanded_fname, mf->mf_mount,
	     (mf->mf_flags & MFF_UNMOUNTING) ? "un" : "", mf->mf_flags);
	in_progress++;
	if (mf->mf_flags & MFF_UNMOUNTING) {
	  dlog("will remount later");
	  new_mp->am_flags |= AMF_REMOUNT;
	}
	continue;
      }

      /*
       * Otherwise we have a hit: return the current mount point.
       */
      dlog("matched %s in %s", expanded_fname, new_mp->am_path);
      XFREE(expanded_fname);
      return new_mp;
    }
  }

  if (in_progress) {
    dlog("Waiting while %d mount(s) in progress", in_progress);
    XFREE(expanded_fname);
    ereturn(-1);
  }

  /*
   * If an error occurred then return it.
   */
  if (error) {
    dlog("Returning error: %s", strerror(error));
    XFREE(expanded_fname);
    ereturn(error);
  }

  /*
   * If the server is going down then just return,
   * don't try to mount any more file systems
   */
  if ((int) amd_state >= (int) Finishing) {
    dlog("not found - server going down anyway");
    ereturn(ENOENT);
  }

  /*
   * Allocate a new map
   */
  new_mp = get_ap_child(mp, expanded_fname);
  XFREE(expanded_fname);
  if (new_mp == NULL)
    ereturn(ENOSPC);

  *error_return = -1;
  return new_mp;
}
Esempio n. 6
0
/*
 * Just evaluate selectors, which were split by split_opts.
 * Returns 0 on error or no match, 1 if matched.
 */
static int
eval_selectors(char *opts, char *mapkey)
{
  char *o, *old_o;
  char *f;
  int ret = 0;

  o = old_o = strdup(opts);

  /*
   * For each user-specified option
   */
  for (f = opt(&o); *f; f = opt(&o)) {
    struct opt *op;
    enum vs_opt vs_opt;
    char *eq = strchr(f, '=');
    char *fx;
    IntFuncPtr func;
    char *opt = NULL;
    char *arg;

    if (!eq) {
      /*
       * No value, is it a function call?
       */
      arg = strchr(f, '(');

      if (!arg || arg[1] == '\0' || arg == f) {
	/*
	 * No, just continue
	 */
	plog(XLOG_USER, "key %s: No value component in \"%s\"", mapkey, f);
	continue;
      }

      /* null-terminate the argument  */
      *arg++ = '\0';
      fx = strchr(arg, ')');
      if (!arg || fx == arg) {
	plog(XLOG_USER, "key %s: Malformed function in \"%s\"", mapkey, f);
	continue;
      }
      *fx = '\0';

      if (f[0] == '!') {
	vs_opt = SelNE;
	f++;
      } else {
	vs_opt = SelEQ;
      }
      /*
       * look up f in functable and pass it arg.
       * func must return 0 on failure, and 1 on success.
       */
      if ((func = functable_lookup(f))) {
	int funok;

	/* this allocates memory, don't forget to free */
	arg = expand_options(arg);
	funok = func(arg);
	XFREE(arg);

	if (vs_opt == SelNE)
	  funok = !funok;
	if (!funok)
	  goto out;

	continue;
      } else {
	plog(XLOG_USER, "key %s: unknown function \"%s\"", mapkey, f);
	goto out;
      }
    } else {
      if (eq[1] == '\0' || eq == f) {
	/* misformed selector */
	plog(XLOG_USER, "key %s: Bad selector \"%s\"", mapkey, f);
	continue;
      }
    }

    /*
     * Check what type of operation is happening
     * !=, =!  is SelNE
     * == is SelEQ
     * =, := is VarAss
     */
    if (eq[-1] == '!') {	/* != */
      vs_opt = SelNE;
      eq[-1] = '\0';
      opt = eq + 1;
    } else if (eq[-1] == ':') {	/* := */
      continue;
    } else if (eq[1] == '=') {	/* == */
      vs_opt = SelEQ;
      eq[0] = '\0';
      opt = eq + 2;
    } else if (eq[1] == '!') {	/* =! */
      vs_opt = SelNE;
      eq[0] = '\0';
      opt = eq + 2;
    } else {
      /* old style assignment */
      continue;
    }

    /*
     * For each recognized option
     */
    for (op = opt_fields; op->name; op++) {
      /*
       * Check whether they match
       */
      if (FSTREQ(op->name, f)) {
	opt = expand_options(opt);

	if (op->sel_p != NULL) {
	  int selok;
	  if (op->case_insensitive) {
	    selok = STRCEQ(*op->sel_p, opt);
	  } else {
	    selok = STREQ(*op->sel_p, opt);
	  }
	  if (vs_opt == SelNE)
	    selok = !selok;
	  if (!selok) {
	    plog(XLOG_MAP, "key %s: map selector %s (=%s) did not %smatch %s",
		 mapkey,
		 op->name,
		 *op->sel_p,
		 vs_opt == SelNE ? "mis" : "",
		 opt);
	    XFREE(opt);
	    goto out;
	  }
	  XFREE(opt);
	}
	/* check if to apply a function */
	if (op->fxn_p) {
	  int funok;

	  funok = op->fxn_p(opt);
	  if (vs_opt == SelNE)
	    funok = !funok;
	  if (!funok) {
	    plog(XLOG_MAP, "key %s: map function %s did not %smatch %s",
		 mapkey,
		 op->name,
		 vs_opt == SelNE ? "mis" : "",
		 opt);
	    XFREE(opt);
	    goto out;
	  }
	  XFREE(opt);
	}
	break;			/* break out of for loop */
      }
    }

    if (!op->name)
      plog(XLOG_USER, "key %s: Unrecognized key/option \"%s\"", mapkey, f);
  }

  /* all is ok */
  ret = 1;

 out:
  free(old_o);
  return ret;
}
Esempio n. 7
0
/*
 * Search the map for the key.
 * Put a safe copy in *pval or return
 * an error code
 */
int
mapc_meta_search(mnt_map *m, char *key, char **pval, int recurse)
{
	int error = 0;
	kv *k = 0;

	/*
	 * Firewall
	 */
	if (!m) {
		plog(XLOG_ERROR, "Null map request for %s", key);
		return ENOENT;
	}

	if (m->flags & MAPC_SYNC) {
		/*
		 * Get modify time...
		 */
		time_t t;
		error = (*m->mtime)(m->map_name, &t);
		if (error || t > m->modify) {
			m->modify = t;
			plog(XLOG_INFO, "Map %s is out of date", m->map_name);
			mapc_sync(m);
		}
	}

	if (!MAPC_ISRE(m)) {
		/*
		 * Compute the hash table offset
		 */
		k = m->kvhash[kvhash_of(key)];

		/*
		 * Scan the linked list for the key
		 */
		while (k && !FSTREQ(k->key, key)) k = k->next;

	}
#ifdef HAS_REGEXP
	else if (recurse == MREC_FULL) {
		/*
		 * Try for an RE match against the entire map.
		 * Note that this will be done in a "random"
		 * order.
		 */

		int i;

		for (i = 0; i < NKVHASH; i++) {
			k = m->kvhash[i];
			while (k) {
				if (regexec((regex_t *)k->key, key,
				    0, NULL, 0) == 0)
					break;
				k = k->next;
			}
			if (k)
				break;
		}
	}
#endif

	/*
	 * If found then take a copy
	 */
	if (k) {
		if (k->val)
			*pval = strdup(k->val);
		else
			error = ENOENT;
	} else if (m->alloc >= MAPC_ALL) {
		/*
		 * If the entire map is cached then this
		 * key does not exist.
		 */
		error = ENOENT;
	} else {
		/*
		 * Otherwise search the map.  If we are
		 * in incremental mode then add the key
		 * to the cache.
		 */
		error = search_map(m, key, pval);
		if (!error && m->alloc == MAPC_INC)
			mapc_add_kv(m, strdup(key), strdup(*pval));
	}

	/*
	 * If an error, and a wildcard exists,
	 * and the key is not internal then
	 * return a copy of the wildcard.
	 */
	if (error > 0) {
		if (recurse == MREC_FULL && !MAPC_ISRE(m)) {
			char wildname[MAXPATHLEN];
			char *subp;
			if (*key == '/')
				return error;
			/*
			 * Keep chopping sub-directories from the RHS
			 * and replacing with "/ *" and repeat the lookup.
			 * For example:
			 * "src/gnu/gcc" -> "src / gnu / *" -> "src / *"
			 */
			strlcpy(wildname, key, sizeof wildname);
			while (error && (subp = strrchr(wildname, '/'))) {
				strlcpy(subp, "/*", 3);
#ifdef DEBUG
				dlog("mapc recurses on %s", wildname);
#endif
				error = mapc_meta_search(m, wildname, pval, MREC_PART);
				if (error)
					*subp = 0;
			}
			if (error > 0 && m->wildcard) {
				*pval = strdup(m->wildcard);
				error = 0;
			}
		}
	}

	return error;
}