/* * Macro-expand an option. Note that this does not * handle recursive expansions. They will go badly wrong. * If sel is true then old expand selectors, otherwise * don't expand selectors. */ static char * expand_op(char *opt, int sel_p) { static const char expand_error[] = "No space to expand \"%s\""; char expbuf[MAXPATHLEN + 1]; char nbuf[NLEN + 1]; char *ep = expbuf; char *cp = opt; char *dp; struct opt *op; char *cp_orig = opt; while ((dp = strchr(cp, '$'))) { char ch; /* * First copy up to the $ */ { int len = dp - cp; if (BUFSPACE(ep, len)) { strncpy(ep, cp, len); ep += len; } else { plog(XLOG_ERROR, expand_error, opt); goto out; } } cp = dp + 1; ch = *cp++; if (ch == '$') { if (BUFSPACE(ep, 1)) { *ep++ = '$'; } else { plog(XLOG_ERROR, expand_error, opt); goto out; } } else if (ch == '{') { /* Expansion... */ enum { E_All, E_Dir, E_File, E_Domain, E_Host } todo; /* * Find closing brace */ char *br_p = strchr(cp, '}'); int len; /* * Check we found it */ if (!br_p) { /* * Just give up */ plog(XLOG_USER, "No closing '}' in \"%s\"", opt); goto out; } len = br_p - cp; /* * Figure out which part of the variable to grab. */ if (*cp == '/') { /* * Just take the last component */ todo = E_File; cp++; --len; } else if (br_p[-1] == '/') { /* * Take all but the last component */ todo = E_Dir; --len; } else if (*cp == '.') { /* * Take domain name */ todo = E_Domain; cp++; --len; } else if (br_p[-1] == '.') { /* * Take host name */ todo = E_Host; --len; } else { /* * Take the whole lot */ todo = E_All; } /* * Truncate if too long. Since it won't * match anyway it doesn't matter that * it has been cut short. */ if (len > NLEN) len = NLEN; /* * Put the string into another buffer so * we can do comparisons. */ strncpy(nbuf, cp, len); nbuf[len] = '\0'; /* * Advance cp */ cp = br_p + 1; /* * Search the option array */ for (op = opt_fields; op->name; op++) { /* * Check for match */ if (len == op->nlen && STREQ(op->name, nbuf)) { char xbuf[NLEN + 3]; char *val; /* * Found expansion. Copy * the correct value field. */ if (!(!op->sel_p == !sel_p)) { /* * Copy the string across unexpanded */ sprintf(xbuf, "${%s%s%s}", todo == E_File ? "/" : todo == E_Domain ? "." : "", nbuf, todo == E_Dir ? "/" : todo == E_Host ? "." : ""); val = xbuf; /* * Make sure expansion doesn't * munge the value! */ todo = E_All; } else if (op->sel_p) { val = *op->sel_p; } else { val = *op->optp; } if (val) { /* * Do expansion: * ${/var} means take just the last part * ${var/} means take all but the last part * ${.var} means take all but first part * ${var.} means take just the first part * ${var} means take the whole lot */ int vlen = strlen(val); char *vptr = val; switch (todo) { case E_Dir: vptr = strrchr(val, '/'); if (vptr) vlen = vptr - val; vptr = val; break; case E_File: vptr = strrchr(val, '/'); if (vptr) { vptr++; vlen = strlen(vptr); } else vptr = val; break; case E_Domain: vptr = strchr(val, '.'); if (vptr) { vptr++; vlen = strlen(vptr); } else { vptr = ""; vlen = 0; } break; case E_Host: vptr = strchr(val, '.'); if (vptr) vlen = vptr - val; vptr = val; break; case E_All: break; } if (BUFSPACE(ep, vlen)) { strcpy(ep, vptr); ep += vlen; } else { plog(XLOG_ERROR, expand_error, opt); goto out; } } /* * Done with this variable */ break; } } /* * Check that the search was successful */ if (!op->name) { /* * If it wasn't then scan the * environment for that name * and use any value found */ char *env = getenv(nbuf); if (env) { int vlen = strlen(env); if (BUFSPACE(ep, vlen)) { strcpy(ep, env); ep += vlen; } else { plog(XLOG_ERROR, expand_error, opt); goto out; } amuDebug(D_STR) plog(XLOG_DEBUG, "Environment gave \"%s\" -> \"%s\"", nbuf, env); } else { plog(XLOG_USER, "Unknown sequence \"${%s}\"", nbuf); } } } else { /* * Error, error */ plog(XLOG_USER, "Unknown $ sequence in \"%s\"", opt); } } out: /* * Handle common case - no expansion */ if (cp == opt) { opt = strdup(cp); } else { /* * Finish off the expansion */ if (BUFSPACE(ep, strlen(cp))) { strcpy(ep, cp); /* ep += strlen(ep); */ } else { plog(XLOG_ERROR, expand_error, opt); } /* * Save the expansion */ opt = strdup(expbuf); } normalize_slash(opt); amuDebug(D_STR) { plog(XLOG_DEBUG, "Expansion of \"%s\"...", cp_orig); plog(XLOG_DEBUG, "......... is \"%s\"", opt); } return opt; }
am_ops * ops_match(am_opts *fo, char *key, char *g_key, char *path, char *keym, char *map) { am_ops *rop = NULL; char *link_dir; /* * First crack the global opts and the local opts */ if (!eval_fs_opts(fo, key, g_key, path, keym, map)) { rop = &amfs_error_ops; } else if (fo->opt_type == 0) { plog(XLOG_USER, "No fs type specified (key = \"%s\", map = \"%s\")", keym, map); rop = &amfs_error_ops; } else { /* * Next find the correct filesystem type */ rop = ops_search(fo->opt_type); if (!rop) { plog(XLOG_USER, "fs type \"%s\" not recognized", fo->opt_type); rop = &amfs_error_ops; } } /* * Make sure we have a default mount option. * Otherwise skip past any leading '-'. */ if (fo->opt_opts == 0) fo->opt_opts = strdup("rw,defaults"); else if (*fo->opt_opts == '-') { /* * We cannot simply do fo->opt_opts++ here since the opts * module will try to free the pointer fo->opt_opts later. * So just reallocate the thing -- stolcke 11/11/94 */ char *old = fo->opt_opts; fo->opt_opts = strdup(old + 1); XFREE(old); } /* * If addopts option was used, then append it to the * current options and remote mount options. */ if (fo->opt_addopts) { if (STREQ(fo->opt_opts, fo->opt_remopts)) { /* optimize things for the common case where opts==remopts */ char *mergedstr; mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts); plog(XLOG_INFO, "merge rem/opts \"%s\" add \"%s\" => \"%s\"", fo->opt_opts, fo->opt_addopts, mergedstr); XFREE(fo->opt_opts); XFREE(fo->opt_remopts); fo->opt_opts = mergedstr; fo->opt_remopts = strdup(mergedstr); } else { char *mergedstr, *remmergedstr; mergedstr = merge_opts(fo->opt_opts, fo->opt_addopts); plog(XLOG_INFO, "merge opts \"%s\" add \"%s\" => \"%s\"", fo->opt_opts, fo->opt_addopts, mergedstr); XFREE(fo->opt_opts); fo->opt_opts = mergedstr; remmergedstr = merge_opts(fo->opt_remopts, fo->opt_addopts); plog(XLOG_INFO, "merge remopts \"%s\" add \"%s\" => \"%s\"", fo->opt_remopts, fo->opt_addopts, remmergedstr); XFREE(fo->opt_remopts); fo->opt_remopts = remmergedstr; } } /* * Initialize opt_mount_type to "nfs", if it's not initialized already */ if (!fo->opt_mount_type) fo->opt_mount_type = "nfs"; /* Normalize the sublink and make it absolute */ link_dir = fo->opt_sublink; if (link_dir && link_dir[0] && link_dir[0] != '/') { link_dir = str3cat((char *) NULL, fo->opt_fs, "/", link_dir); normalize_slash(link_dir); XFREE(fo->opt_sublink); fo->opt_sublink = link_dir; } /* * Check the filesystem is happy */ if (fo->fs_mtab) XFREE(fo->fs_mtab); fo->fs_mtab = rop->fs_match(fo); if (fo->fs_mtab) return rop; /* * Return error file system */ fo->fs_mtab = amfs_error_ops.fs_match(fo); return &amfs_error_ops; }
static int amfs_nfsx_init(mntfs *mf) { /* * mf_info has the form: * host:/prefix/path,sub,sub,sub */ int i; int glob_error; struct amfs_nfsx *nx; int asked_for_wakeup = 0; nx = (struct amfs_nfsx *) mf->mf_private; if (nx == 0) { char **ivec; char *info = 0; char *host; char *pref; int error = 0; info = strdup(mf->mf_info); host = strchr(info, ':'); if (!host) { error = EINVAL; goto errexit; } pref = host + 1; host = info; /* * Split the prefix off from the suffices */ ivec = strsplit(pref, ',', '\''); /* * Count array size */ for (i = 0; ivec[i]; i++) /* nothing */; nx = ALLOC(struct amfs_nfsx); mf->mf_private = (opaque_t) nx; mf->mf_prfree = amfs_nfsx_prfree; nx->nx_c = i - 1; /* i-1 because we don't want the prefix */ nx->nx_v = (amfs_nfsx_mnt *) xmalloc(nx->nx_c * sizeof(amfs_nfsx_mnt)); nx->nx_mp = 0; { char *mp = 0; char *xinfo = 0; char *fs = mf->mf_fo->opt_fs; char *rfs = 0; for (i = 0; i < nx->nx_c; i++) { char *path = ivec[i + 1]; rfs = str3cat(rfs, pref, "/", path); /* * Determine the mount point. * If this is the root, then don't remove * the trailing slash to avoid mntfs name clashes. */ mp = str3cat(mp, fs, "/", rfs); normalize_slash(mp); deslashify(mp); /* * Determine the mount info */ xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path); normalize_slash(xinfo); if (pref[1] != '\0') deslashify(xinfo); dlog("amfs_nfsx: init mount for %s on %s", xinfo, mp); nx->nx_v[i].n_error = -1; nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts); /* propagate the on_autofs flag */ nx->nx_v[i].n_mnt->mf_flags |= mf->mf_flags & MFF_ON_AUTOFS; } if (rfs) XFREE(rfs); if (mp) XFREE(mp); if (xinfo) XFREE(xinfo); } XFREE(ivec); errexit: if (info) XFREE(info); if (error) return error; }
static int nfsx_init(mntfs *mf) { /* * mf_info has the form: * host:/prefix/path,sub,sub,sub */ int i; int glob_error; struct nfsx *nx; int asked_for_wakeup = 0; nx = (struct nfsx *) mf->mf_private; if (nx == 0) { char **ivec; char *info = 0; char *host; char *pref; int error = 0; info = strdup(mf->mf_info); host = strchr(info, ':'); if (!host) { error = EINVAL; goto errexit; } pref = host+1; host = info; /* * Split the prefix off from the suffices */ ivec = strsplit(pref, ',', '\''); /* * Count array size */ for (i = 0; ivec[i]; i++) ; nx = ALLOC(nfsx); mf->mf_private = nx; mf->mf_prfree = nfsx_prfree; nx->nx_c = i - 1; /* i-1 because we don't want the prefix */ nx->nx_v = xreallocarray(NULL, nx->nx_c, sizeof *nx->nx_v); { char *mp = 0; char *xinfo = 0; char *fs = mf->mf_fo->opt_fs; char *rfs = 0; for (i = 0; i < nx->nx_c; i++) { char *path = ivec[i+1]; rfs = str3cat(rfs, pref, "/", path); /* * Determine the mount point. * If this is the root, then don't remove * the trailing slash to avoid mntfs name clashes. */ mp = str3cat(mp, fs, "/", rfs); normalize_slash(mp); deslashify(mp); /* * Determine the mount info */ xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path); normalize_slash(xinfo); if (pref[1] != '\0') deslashify(xinfo); #ifdef DEBUG dlog("nfsx: init mount for %s on %s", xinfo, mp); #endif nx->nx_v[i].n_error = -1; nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts); } free(rfs); free(mp); free(xinfo); } free(ivec); errexit: free(info); if (error) return error; } /* * Iterate through the mntfs's and call * the underlying init routine on each */ glob_error = 0; for (i = 0; i < nx->nx_c; i++) { nfsx_mnt *n = &nx->nx_v[i]; mntfs *m = n->n_mnt; int error = (*m->mf_ops->fs_init)(m); /* * If HARD_NFSX_ERRORS is defined, make any * initialisation failure a hard error and * fail the entire group. Otherwise only fail * if none of the group is mountable (see nfsx_fmount). */ #ifdef HARD_NFSX_ERRORS if (error > 0) return error; #else if (error > 0) n->n_error = error; #endif else if (error < 0) { glob_error = -1; if (!asked_for_wakeup) { asked_for_wakeup = 1; sched_task(wakeup_task, mf, m); } } } return glob_error; }