Query the kernel to ask which flavors vary by pseudoflavor, and use that
instead of a fixed constant. To allow the possibility of more flags
varying by pseudoflavor, use the set/clear_flags functions for all
options instead of setting some by hand.
Signed-off-by: J. Bruce Fields <bfields@citi.umich.edu>
struct nfskey * key_lookup(char *hname);
struct nfskey * key_lookup(char *hname);
+struct export_features {
+ unsigned int flags;
+ unsigned int secinfo_flags;
+};
+
+struct export_features *get_export_features(void);
+
/* Record export error. */
extern int export_errno;
/* Record export error. */
extern int export_errno;
#define NFSEXP_FSID 0x2000
#define NFSEXP_CROSSMOUNT 0x4000
#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
#define NFSEXP_FSID 0x2000
#define NFSEXP_CROSSMOUNT 0x4000
#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */
-#define NFSEXP_ALLFLAGS 0xFFFF
+/*
+ * All flags supported by the kernel before addition of the
+ * export_features interface:
+ */
+#define NFSEXP_OLDFLAGS 0x7E3F
+/*
+ * Flags that can vary per flavor, for kernels before addition of the
+ * export_features interface:
+ */
+#define NFSEXP_OLD_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
+ | NFSEXP_ALLSQUASH)
#endif /* _NSF_EXPORT_H */
#endif /* _NSF_EXPORT_H */
-/* options that can vary per flavor: */
-#define NFSEXP_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \
- | NFSEXP_ALLSQUASH)
/*
* For those flags which are not allowed to vary by pseudoflavor,
* ensure that the export flags agree with the flags on each
/*
* For those flags which are not allowed to vary by pseudoflavor,
* ensure that the export flags agree with the flags on each
*/
static void fix_pseudoflavor_flags(struct exportent *ep)
{
*/
static void fix_pseudoflavor_flags(struct exportent *ep)
{
+ struct export_features *ef;
+ ef = get_export_features();
for (p = ep->e_secinfo; p->flav; p++)
for (p = ep->e_secinfo; p->flav; p++)
- p->flags |= ep->e_flags & ~NFSEXP_SECINFO_FLAGS;
+ p->flags |= ep->e_flags & ~ef->secinfo_flags;
else if (strcmp(opt, "rw") == 0)
clearflags(NFSEXP_READONLY, active, ep);
else if (!strcmp(opt, "secure"))
else if (strcmp(opt, "rw") == 0)
clearflags(NFSEXP_READONLY, active, ep);
else if (!strcmp(opt, "secure"))
- ep->e_flags &= ~NFSEXP_INSECURE_PORT;
+ clearflags(NFSEXP_INSECURE_PORT, active, ep);
else if (!strcmp(opt, "insecure"))
else if (!strcmp(opt, "insecure"))
- ep->e_flags |= NFSEXP_INSECURE_PORT;
+ setflags(NFSEXP_INSECURE_PORT, active, ep);
else if (!strcmp(opt, "sync"))
else if (!strcmp(opt, "sync"))
- ep->e_flags &= ~NFSEXP_ASYNC;
+ clearflags(NFSEXP_ASYNC, active, ep);
else if (!strcmp(opt, "async"))
else if (!strcmp(opt, "async"))
- ep->e_flags |= NFSEXP_ASYNC;
+ setflags(NFSEXP_ASYNC, active, ep);
else if (!strcmp(opt, "nohide"))
else if (!strcmp(opt, "nohide"))
- ep->e_flags |= NFSEXP_NOHIDE;
+ setflags(NFSEXP_NOHIDE, active, ep);
else if (!strcmp(opt, "hide"))
else if (!strcmp(opt, "hide"))
- ep->e_flags &= ~NFSEXP_NOHIDE;
+ clearflags(NFSEXP_NOHIDE, active, ep);
else if (!strcmp(opt, "crossmnt"))
else if (!strcmp(opt, "crossmnt"))
- ep->e_flags |= NFSEXP_CROSSMOUNT;
+ setflags(NFSEXP_CROSSMOUNT, active, ep);
else if (!strcmp(opt, "nocrossmnt"))
else if (!strcmp(opt, "nocrossmnt"))
- ep->e_flags &= ~NFSEXP_CROSSMOUNT;
+ clearflags(NFSEXP_CROSSMOUNT, active, ep);
else if (!strcmp(opt, "wdelay"))
else if (!strcmp(opt, "wdelay"))
- ep->e_flags |= NFSEXP_GATHERED_WRITES;
+ setflags(NFSEXP_GATHERED_WRITES, active, ep);
else if (!strcmp(opt, "no_wdelay"))
else if (!strcmp(opt, "no_wdelay"))
- ep->e_flags &= ~NFSEXP_GATHERED_WRITES;
+ clearflags(NFSEXP_GATHERED_WRITES, active, ep);
else if (strcmp(opt, "root_squash") == 0)
setflags(NFSEXP_ROOTSQUASH, active, ep);
else if (!strcmp(opt, "no_root_squash"))
else if (strcmp(opt, "root_squash") == 0)
setflags(NFSEXP_ROOTSQUASH, active, ep);
else if (!strcmp(opt, "no_root_squash"))
clearflags(NFSEXP_ALLSQUASH, active, ep);
else if (strcmp(opt, "subtree_check") == 0) {
had_subtree_opt = 1;
clearflags(NFSEXP_ALLSQUASH, active, ep);
else if (strcmp(opt, "subtree_check") == 0) {
had_subtree_opt = 1;
- ep->e_flags &= ~NFSEXP_NOSUBTREECHECK;
+ clearflags(NFSEXP_NOSUBTREECHECK, active, ep);
} else if (strcmp(opt, "no_subtree_check") == 0) {
had_subtree_opt = 1;
} else if (strcmp(opt, "no_subtree_check") == 0) {
had_subtree_opt = 1;
- ep->e_flags |= NFSEXP_NOSUBTREECHECK;
+ setflags(NFSEXP_NOSUBTREECHECK, active, ep);
} else if (strcmp(opt, "auth_nlm") == 0)
} else if (strcmp(opt, "auth_nlm") == 0)
- ep->e_flags &= ~NFSEXP_NOAUTHNLM;
+ clearflags(NFSEXP_NOAUTHNLM, active, ep);
else if (strcmp(opt, "no_auth_nlm") == 0)
else if (strcmp(opt, "no_auth_nlm") == 0)
- ep->e_flags |= NFSEXP_NOAUTHNLM;
+ setflags(NFSEXP_NOAUTHNLM, active, ep);
else if (strcmp(opt, "secure_locks") == 0)
else if (strcmp(opt, "secure_locks") == 0)
- ep->e_flags &= ~NFSEXP_NOAUTHNLM;
+ clearflags(NFSEXP_NOAUTHNLM, active, ep);
else if (strcmp(opt, "insecure_locks") == 0)
else if (strcmp(opt, "insecure_locks") == 0)
- ep->e_flags |= NFSEXP_NOAUTHNLM;
+ setflags(NFSEXP_NOAUTHNLM, active, ep);
else if (strcmp(opt, "acl") == 0)
else if (strcmp(opt, "acl") == 0)
- ep->e_flags &= ~NFSEXP_NOACL;
+ clearflags(NFSEXP_NOACL, active, ep);
else if (strcmp(opt, "no_acl") == 0)
else if (strcmp(opt, "no_acl") == 0)
- ep->e_flags |= NFSEXP_NOACL;
+ setflags(NFSEXP_NOACL, active, ep);
else if (strncmp(opt, "anonuid=", 8) == 0) {
char *oe;
ep->e_anonuid = strtol(opt+8, &oe, 10);
else if (strncmp(opt, "anonuid=", 8) == 0) {
char *oe;
ep->e_anonuid = strtol(opt+8, &oe, 10);
char *oe;
if (strcmp(opt+5, "root") == 0) {
ep->e_fsid = 0;
char *oe;
if (strcmp(opt+5, "root") == 0) {
ep->e_fsid = 0;
- ep->e_flags |= NFSEXP_FSID;
+ setflags(NFSEXP_FSID, active, ep);
} else {
ep->e_fsid = strtoul(opt+5, &oe, 0);
if (opt[5]!='\0' && *oe == '\0')
} else {
ep->e_fsid = strtoul(opt+5, &oe, 0);
if (opt[5]!='\0' && *oe == '\0')
- ep->e_flags |= NFSEXP_FSID;
+ setflags(NFSEXP_FSID, active, ep);
else if (valid_uuid(opt+5))
ep->e_uuid = strdup(opt+5);
else {
else if (valid_uuid(opt+5))
ep->e_uuid = strdup(opt+5);
else {
} else {
xlog(L_ERROR, "%s:%d: unknown keyword \"%s\"\n",
flname, flline, opt);
} else {
xlog(L_ERROR, "%s:%d: unknown keyword \"%s\"\n",
flname, flline, opt);
- ep->e_flags |= NFSEXP_ALLSQUASH | NFSEXP_READONLY;
+ setflags(NFSEXP_ALLSQUASH | NFSEXP_READONLY, active, ep);
goto bad_option;
}
free(opt);
while (isblank(*cp))
cp++;
}
goto bad_option;
}
free(opt);
while (isblank(*cp))
cp++;
}
/*
* Turn on nohide which will allow this export to cross over
* the 'mount --bind' mount point.
*/
if (ep->e_fslocdata)
/*
* Turn on nohide which will allow this export to cross over
* the 'mount --bind' mount point.
*/
if (ep->e_fslocdata)
- ep->e_flags |= NFSEXP_NOHIDE;
+ setflags(NFSEXP_NOHIDE, active, ep);
fix_pseudoflavor_flags(ep);
ep->e_squids = squids;
ep->e_sqgids = sqgids;
fix_pseudoflavor_flags(ep);
ep->e_squids = squids;
ep->e_sqgids = sqgids;
xlog(L_ERROR, "%s:%d: syntax error: %s",
efname, efp?efp->x_line:0, msg);
}
xlog(L_ERROR, "%s:%d: syntax error: %s",
efname, efp?efp->x_line:0, msg);
}
+struct export_features *get_export_features(void)
+{
+ static char *path = "/proc/fs/nfsd/export_features";
+ static struct export_features ef;
+ static int cached = 0;
+ char buf[50];
+ int c;
+ int fd;
+
+ if (cached)
+ return &ef;
+
+ ef.flags = NFSEXP_OLDFLAGS;
+ ef.secinfo_flags = NFSEXP_OLD_SECINFO_FLAGS;
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ goto good;
+ fd = read(fd, buf, 50);
+ if (fd == -1)
+ goto err;
+ c = sscanf(buf, "%x %x", &ef.flags, &ef.secinfo_flags);
+ if (c != 2)
+ goto err;
+good:
+ cached = 1;
+ return &ef;
+err:
+ xlog(L_WARNING, "unexpected error reading %s", path);
+ return &ef;
+}