diff --git a/.gitignore b/.gitignore index 126d12c..941aca0 100644 --- a/.gitignore +++ b/.gitignore @@ -70,6 +70,7 @@ tests/nsm_client/nlm_sm_inter_svc.c tests/nsm_client/nlm_sm_inter_xdr.c utils/nfsidmap/nfsidmap systemd/nfs-server-generator +systemd/rpc-pipefs-generator systemd/nfs-config.service systemd/rpc-gssd.service # cscope database files diff --git a/nfs.conf b/nfs.conf index 81ece06..0d0ec9b 100644 --- a/nfs.conf +++ b/nfs.conf @@ -1,7 +1,10 @@ # -# This is a general conifguration for the +# This is a general configuration for the # NFS daemons and tools # +#[general] +# pipefs-directory=/var/lib/nfs/rpc_pipefs +# #[exportfs] # debug=0 # @@ -12,7 +15,6 @@ # limit-to-legacy-enctypes=0 # context-timeout=0 # rpc-timeout=5 -# pipefs-directory=/var/lib/nfs/rpc_pipefs # keytab-file=/etc/krb5.keytab # cred-cache-directory= # preferred-realm= @@ -42,7 +44,7 @@ # port=0 # grace-time=90 # lease-time=90 -# udp=y +# udp=n # tcp=y # vers2=n # vers3=y @@ -65,6 +67,7 @@ # retry-time=900 # outgoing-port= # outgoing-addr= +# lift-grace=y # #[svcgssd] # principal= diff --git a/support/export/xtab.c b/support/export/xtab.c index 22cf539..d42eeef 100644 --- a/support/export/xtab.c +++ b/support/export/xtab.c @@ -14,12 +14,20 @@ #include #include #include +#include +#include +#include +#include #include "nfslib.h" #include "exportfs.h" #include "xio.h" #include "xlog.h" #include "v4root.h" +#include "misc.h" + +static char state_base_dirname[PATH_MAX] = NFS_STATEDIR; +extern struct state_paths etab; int v4root_needed; static void cond_rename(char *newfile, char *oldfile); @@ -65,7 +73,7 @@ xtab_read(char *xtab, char *lockfn, int is_export) int xtab_export_read(void) { - return xtab_read(_PATH_ETAB, _PATH_ETABLCK, 1); + return xtab_read(etab.statefn, etab.lockfn, 1); } /* @@ -112,7 +120,7 @@ xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export) int xtab_export_write() { - return xtab_write(_PATH_ETAB, _PATH_ETABTMP, _PATH_ETABLCK, 1); + return xtab_write(etab.statefn, etab.tmpfn, etab.lockfn, 1); } /* @@ -158,3 +166,74 @@ static void cond_rename(char *newfile, char *oldfile) rename(newfile, oldfile); return; } + +/* + * Returns a dynamically allocated, '\0'-terminated buffer + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +static char * +state_make_pathname(const char *tabname) +{ + return generic_make_pathname(state_base_dirname, tabname); +} + +/** + * state_setup_basedir - set up basedir + * @progname: C string containing name of program, for error messages + * @parentdir: C string containing pathname to on-disk state, or NULL + * + * This runs before logging is set up, so error messages are directed + * to stderr. + * + * Returns true and sets up our basedir, if @parentdir was valid + * and usable; otherwise false is returned. + */ +_Bool +state_setup_basedir(const char *progname, const char *parentdir) +{ + return generic_setup_basedir(progname, parentdir, state_base_dirname, + PATH_MAX); +} + +int +setup_state_path_names(const char *progname, const char *statefn, + const char *tmpfn, const char *lockfn, + struct state_paths *paths) +{ + paths->statefn = state_make_pathname(statefn); + if (!paths->statefn) { + fprintf(stderr, "%s: state_make_pathname(%s) failed\n", + progname, statefn); + goto out_err; + } + paths->tmpfn = state_make_pathname(tmpfn); + if (!paths->tmpfn) { + fprintf(stderr, "%s: state_make_pathname(%s) failed\n", + progname, tmpfn); + goto out_free_statefn; + } + paths->lockfn = state_make_pathname(lockfn); + if (!paths->lockfn) { + fprintf(stderr, "%s: state_make_pathname(%s) failed\n", + progname, lockfn); + goto out_free_tmpfn; + } + return 1; + +out_free_tmpfn: + free(paths->tmpfn); +out_free_statefn: + free(paths->statefn); +out_err: + return 0; + +} + +void +free_state_path_names(struct state_paths *paths) +{ + free(paths->statefn); + free(paths->tmpfn); + free(paths->lockfn); +} diff --git a/support/include/conffile.h b/support/include/conffile.h index 3fe3a78..2d11a52 100644 --- a/support/include/conffile.h +++ b/support/include/conffile.h @@ -48,8 +48,6 @@ struct conf_list { TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields; }; -extern char *conf_path; - extern int conf_begin(void); extern int conf_decode_base64(uint8_t *, uint32_t *, unsigned char *); extern int conf_end(int, int); @@ -61,9 +59,9 @@ extern int conf_get_num(char *, char *, int); extern _Bool conf_get_bool(char *, char *, _Bool); extern char *conf_get_str(char *, char *); extern char *conf_get_section(char *, char *, char *); -extern void conf_init(void); +extern void conf_init(const char *); +extern void conf_cleanup(void); extern int conf_match_num(char *, char *, int); -extern void conf_reinit(void); extern int conf_remove(int, char *, char *); extern int conf_remove_section(int, char *); extern void conf_report(void); diff --git a/support/include/misc.h b/support/include/misc.h index eedc1fe..06e2a0c 100644 --- a/support/include/misc.h +++ b/support/include/misc.h @@ -15,6 +15,9 @@ int randomkey(unsigned char *keyout, int len); int weakrandomkey(unsigned char *keyout, int len); +char *generic_make_pathname(const char *, const char *); +_Bool generic_setup_basedir(const char *, const char *, char *, const size_t); + extern int is_mountpoint(char *path); /* size of the file pointer buffers for rpc procfs files */ diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h index 15ecc6b..7933ff5 100644 --- a/support/include/nfs/nfs.h +++ b/support/include/nfs/nfs.h @@ -16,8 +16,8 @@ #define NFSD_MINVERS 2 #define NFSD_MAXVERS 4 -#define NFS4_MINMINOR 1 -#define NFS4_MAXMINOR WORD_BIT +#define NFS4_MINMINOR 0 +#define NFS4_MAXMINOR (WORD_BIT-1) struct nfs_fh_len { int fh_size; @@ -27,21 +27,24 @@ struct nfs_fh_len { #define NFSCTL_UDPBIT (1 << (17 - 1)) #define NFSCTL_TCPBIT (1 << (18 - 1)) +#define NFSCTL_PROTODEFAULT (NFSCTL_TCPBIT) #define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1))) +#define NFSCTL_MINORUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v))) #define NFSCTL_UDPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_UDPBIT) #define NFSCTL_TCPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_TCPBIT) #define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1))) +#define NFSCTL_MINORISSET(_cltbits, _v) ((_cltbits) & (1 << (_v))) #define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & NFSCTL_UDPBIT) #define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT) #define NFSCTL_VERDEFAULT (0xc) /* versions 3 and 4 */ #define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1))) +#define NFSCTL_MINORSET(_cltbits, _v) ((_cltbits) |= (1 << (_v))) #define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT) #define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= NFSCTL_TCPBIT) #define NFSCTL_ANYPROTO(_cltbits) ((_cltbits) & (NFSCTL_UDPBIT | NFSCTL_TCPBIT)) -#define NFSCTL_ALLBITS (~0) #endif /* _NFS_NFS_H */ diff --git a/support/include/nfslib.h b/support/include/nfslib.h index 1498977..ab8b2bf 100644 --- a/support/include/nfslib.h +++ b/support/include/nfslib.h @@ -35,29 +35,24 @@ #ifndef _PATH_IDMAPDCONF #define _PATH_IDMAPDCONF "/etc/idmapd.conf" #endif -#ifndef _PATH_ETAB -#define _PATH_ETAB NFS_STATEDIR "/etab" -#endif -#ifndef _PATH_ETABTMP -#define _PATH_ETABTMP NFS_STATEDIR "/etab.tmp" -#endif -#ifndef _PATH_ETABLCK -#define _PATH_ETABLCK NFS_STATEDIR "/.etab.lock" -#endif -#ifndef _PATH_RMTAB -#define _PATH_RMTAB NFS_STATEDIR "/rmtab" -#endif -#ifndef _PATH_RMTABTMP -#define _PATH_RMTABTMP _PATH_RMTAB ".tmp" -#endif -#ifndef _PATH_RMTABLCK -#define _PATH_RMTABLCK NFS_STATEDIR "/.rmtab.lock" -#endif #ifndef _PATH_PROC_EXPORTS #define _PATH_PROC_EXPORTS "/proc/fs/nfs/exports" #define _PATH_PROC_EXPORTS_ALT "/proc/fs/nfsd/exports" #endif +#define ETAB "etab" +#define ETABTMP "etab.tmp" +#define ETABLCK ".etab.lock" +#define RMTAB "rmtab" +#define RMTABTMP "rmtab.tmp" +#define RMTABLCK ".rmtab.lock" + +struct state_paths { + char *statefn; + char *tmpfn; + char *lockfn; +}; + /* Maximum number of security flavors on an export: */ #define SECFLAVOR_COUNT 8 @@ -120,6 +115,10 @@ void fputrmtabent(FILE *fp, struct rmtabent *xep, long *pos); void fendrmtabent(FILE *fp); void frewindrmtabent(FILE *fp); +_Bool state_setup_basedir(const char *, const char *); +int setup_state_path_names(const char *, const char *, const char *, const char *, struct state_paths *); +void free_state_path_names(struct state_paths *); + /* mydaemon */ void daemon_init(bool fg); void daemon_ready(void); diff --git a/support/misc/Makefile.am b/support/misc/Makefile.am index 1048580..8936b0d 100644 --- a/support/misc/Makefile.am +++ b/support/misc/Makefile.am @@ -1,6 +1,6 @@ ## Process this file with automake to produce Makefile.in noinst_LIBRARIES = libmisc.a -libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c +libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c file.c MAINTAINERCLEANFILES = Makefile.in diff --git a/support/misc/file.c b/support/misc/file.c new file mode 100644 index 0000000..63597df --- /dev/null +++ b/support/misc/file.c @@ -0,0 +1,110 @@ +/* + * Copyright 2009 Oracle. All rights reserved. + * Copyright 2017 Red Hat, Inc. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils 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; either version 2 of the License, or + * (at your option) any later version. + * + * nfs-utils is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nfs-utils. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "xlog.h" +#include "misc.h" + +/* + * Returns a dynamically allocated, '\0'-terminated buffer + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +__attribute__((__malloc__)) +char * +generic_make_pathname(const char *base, const char *leaf) +{ + size_t size; + char *path; + int len; + + size = strlen(base) + strlen(leaf) + 2; + if (size > PATH_MAX) + return NULL; + + path = malloc(size); + if (path == NULL) + return NULL; + + len = snprintf(path, size, "%s/%s", base, leaf); + if ((len < 0) || ((size_t)len >= size)) { + free(path); + return NULL; + } + + return path; +} + + +/** + * generic_setup_basedir - set up basedir + * @progname: C string containing name of program, for error messages + * @parentdir: C string containing pathname to on-disk state, or NULL + * @base: character buffer to contain the basedir that is set up + * @baselen: size of @base in bytes + * + * This runs before logging is set up, so error messages are directed + * to stderr. + * + * Returns true and sets up our basedir, if @parentdir was valid + * and usable; otherwise false is returned. + */ +_Bool +generic_setup_basedir(const char *progname, const char *parentdir, char *base, + const size_t baselen) +{ + static char buf[PATH_MAX]; + struct stat st; + char *path; + + /* First: test length of name and whether it exists */ + if ((strlen(parentdir) >= baselen) || (strlen(parentdir) >= PATH_MAX)) { + (void)fprintf(stderr, "%s: Directory name too long: %s", + progname, parentdir); + return false; + } + if (lstat(parentdir, &st) == -1) { + (void)fprintf(stderr, "%s: Failed to stat %s: %s", + progname, parentdir, strerror(errno)); + return false; + } + + /* Ensure we have a clean directory pathname */ + strncpy(buf, parentdir, sizeof(buf)); + path = dirname(buf); + if (*path == '.') { + (void)fprintf(stderr, "%s: Unusable directory %s", + progname, parentdir); + return false; + } + + xlog(D_CALL, "Using %s as the state directory", parentdir); + strcpy(base, parentdir); + return true; +} diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c index e5e2579..9912afa 100644 --- a/support/nfs/cacheio.c +++ b/support/nfs/cacheio.c @@ -27,6 +27,8 @@ #include #include +extern struct state_paths etab; + void qword_add(char **bpp, int *lp, char *str) { char *bp = *bpp; @@ -199,7 +201,7 @@ int qword_get_uint(char **bpp, unsigned int *anint) } /* flush the kNFSd caches. - * Set the flush time to the mtime of _PATH_ETAB or + * Set the flush time to the mtime of the etab state file or * if force, to now. * the caches to flush are: * auth.unix.ip nfsd.export nfsd.fh @@ -228,7 +230,7 @@ cache_flush(int force) }; now = time(0); if (force || - stat(_PATH_ETAB, &stb) != 0 || + stat(etab.statefn, &stb) != 0 || stb.st_mtime > now) stb.st_mtime = time(0); diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c index e717c1e..8690218 100644 --- a/support/nfs/conffile.c +++ b/support/nfs/conffile.c @@ -30,6 +30,10 @@ * This code was written under funding by Ericsson Radio Systems. */ +#ifdef HAVE_CONFIG_H +#include +#endif + #include #include #include @@ -52,9 +56,11 @@ #pragma GCC visibility push(hidden) static void conf_load_defaults(void); -static int conf_load(int trans, char *path); +static char * conf_load(const char *path); static int conf_set(int , char *, char *, char *, char *, int , int ); +static void conf_parse(int trans, char *buf, + char **section, char **subsection); struct conf_trans { TAILQ_ENTRY (conf_trans) link; @@ -73,8 +79,10 @@ TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; /* * Radix-64 Encoding. */ +#if 0 static const uint8_t bin2asc[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; +#endif static const uint8_t asc2bin[] = { @@ -105,7 +113,6 @@ struct conf_binding { int is_default; }; -char *conf_path; LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; static __inline__ uint8_t @@ -199,7 +206,6 @@ conf_set_now(char *section, char *arg, char *tag, node->tag = strdup(tag); node->value = strdup(value); node->is_default = is_default; - LIST_INSERT_HEAD(&conf_bindings[conf_hash (section)], node, link); return 0; } @@ -209,17 +215,10 @@ conf_set_now(char *section, char *arg, char *tag, * headers and feed tag-value pairs into our configuration database. */ static void -conf_parse_line(int trans, char *line, size_t sz) +conf_parse_line(int trans, char *line, int lineno, char **section, char **subsection) { char *val, *ptr; - size_t i; - size_t j; - static char *section = 0; - static char *arg = 0; - static int ln = 0; - /* Lines starting with '#' or ';' are comments. */ - ln++; /* Ignore blank lines */ if (*line == '\0') return; @@ -228,123 +227,188 @@ conf_parse_line(int trans, char *line, size_t sz) while (isblank(*line)) line++; + /* Lines starting with '#' or ';' are comments. */ if (*line == '#' || *line == ';') return; /* '[section]' parsing... */ if (*line == '[') { line++; + + if (*section) { + free(*section); + *section = NULL; + } + if (*subsection) { + free(*subsection); + *subsection = NULL; + } + /* Strip off any blanks after '[' */ while (isblank(*line)) line++; - for (i = 0; i < sz; i++) { - if (line[i] == ']') { - break; - } - } - if (section) - free(section); - if (i == sz) { + + /* find the closing ] */ + ptr = strchr(line, ']'); + if (ptr == NULL) { xlog_warn("config file error: line %d: " - "non-matched ']', ignoring until next section", ln); - section = 0; + "non-matched ']', ignoring until next section", lineno); return; } + + /* just ignore everything after the closing ] */ + *(ptr--) = '\0'; + /* Strip off any blanks before ']' */ - val = line; - j=0; - while (*val && !isblank(*val)) - val++, j++; - if (*val) - i = j; - section = malloc(i+1); - if (!section) { - xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln, - (unsigned long)i); + while (ptr >= line && isblank(*ptr)) + *(ptr--)='\0'; + + /* look for an arg to split from the section name */ + val = strchr(line, '"'); + if (val != NULL) { + ptr = val - 1; + *(val++) = '\0'; + + /* trim away any whitespace before the " */ + while (ptr > line && isblank(*ptr)) + *(ptr--)='\0'; + } + + /* copy the section name */ + *section = strdup(line); + if (!*section) { + xlog_warn("conf_parse_line: %d: malloc failed", lineno); return; } - strncpy(section, line, i); - section[i] = '\0'; - if (arg) - free(arg); - arg = 0; + /* there is no arg, we are done */ + if (val == NULL) return; + /* check for the closing " */ ptr = strchr(val, '"'); - if (ptr == NULL) - return; - line = ++ptr; - while (*ptr && *ptr != '"' && *ptr != ']') - ptr++; - if (*ptr == '\0' || *ptr == ']') { + if (ptr == NULL) { xlog_warn("config file error: line %d: " - "non-matched '\"', ignoring until next section", ln); - } else { - *ptr = '\0'; - arg = strdup(line); - if (!arg) - xlog_warn("conf_parse_line: %d: malloc arg failed", ln); + "non-matched '\"', ignoring until next section", lineno); + return; } + *ptr = '\0'; + *subsection = strdup(val); + if (!*subsection) + xlog_warn("conf_parse_line: %d: malloc arg failed", lineno); return; } /* Deal with assignments. */ - for (i = 0; i < sz; i++) { - if (line[i] == '=') { - /* If no section, we are ignoring the lines. */ - if (!section) { + ptr = strchr(line, '='); + + /* not an assignment line */ + if (ptr == NULL) { + /* Other non-empty lines are weird. */ + if (line[strspn(line, " \t")]) xlog_warn("config file error: line %d: " - "ignoring line due to no section", ln); - return; - } - line[strcspn (line, " \t=")] = '\0'; - val = line + i + 1 + strspn (line + i + 1, " \t"); - - if (val[0] == '"') { - val ++; - j = strcspn(val, "\""); - val[j] = 0; - } else if (val[0] == '\'') { - val ++; - j = strcspn(val, "'"); - val[j] = 0; - } else { - /* Skip trailing spaces and comments */ - for (j = 0; val[j]; j++) { - if ((val[j] == '#' || val[j] == ';') - && (j == 0 || isspace(val[j-1]))) { - val[j] = '\0'; - break; - } - } - while (j && isspace(val[j-1])) - val[--j] = '\0'; - } - if (strcasecmp(line, "include") == 0) - conf_load(trans, val); - else - /* XXX Perhaps should we not ignore errors? */ - conf_set(trans, section, arg, line, val, 0, 0); + "line not empty and not an assignment", lineno); + return; + } + + /* If no section, we are ignoring the line. */ + if (!*section) { + xlog_warn("config file error: line %d: " + "ignoring line due to no section", lineno); + return; + } + + val = ptr + 1; + *(ptr--) = '\0'; + + /* strip spaces before and after the = */ + while (ptr >= line && isblank(*ptr)) + *(ptr--)='\0'; + while (*val != '\0' && isblank(*val)) + val++; + + if (*val == '"') { + val++; + ptr = strchr(val, '"'); + if (ptr == NULL) { + xlog_warn("config file error: line %d: " + "unmatched quotes", lineno); + return; + } + *ptr = '\0'; + } else + if (*val == '\'') { + val++; + ptr = strchr(val, '\''); + if (ptr == NULL) { + xlog_warn("config file error: line %d: " + "unmatched quotes", lineno); return; } + *ptr = '\0'; + } else { + /* Trim any trailing spaces and comments */ + if ((ptr=strchr(val, '#'))!=NULL) + *ptr = '\0'; + if ((ptr=strchr(val, ';'))!=NULL) + *ptr = '\0'; + + ptr = val + strlen(val) - 1; + while (ptr > val && isspace(*ptr)) + *(ptr--) = '\0'; } - /* Other non-empty lines are weird. */ - i = strspn(line, " \t"); - if (line[i]) - xlog_warn("config file error: line %d:", ln); - return; + if (*line == '\0') { + xlog_warn("config file error: line %d: " + "missing tag in assignment", lineno); + return; + } + if (*val == '\0') { + xlog_warn("config file error: line %d: " + "missing value in assignment", lineno); + return; + } + + if (strcasecmp(line, "include")==0) { + /* load and parse subordinate config files */ + char * subconf = conf_load(val); + if (subconf == NULL) { + xlog_warn("config file error: line %d: " + "error loading included config", lineno); + return; + } + + /* copy the section data so the included file can inherit it + * without accidentally changing it for us */ + char * inc_section = NULL; + char * inc_subsection = NULL; + if (*section != NULL) { + inc_section = strdup(*section); + if (*subsection != NULL) + inc_subsection = strdup(*subsection); + } + + conf_parse(trans, subconf, &inc_section, &inc_subsection); + + if (inc_section) free(inc_section); + if (inc_subsection) free(inc_subsection); + free(subconf); + } else { + /* XXX Perhaps should we not ignore errors? */ + conf_set(trans, *section, *subsection, line, val, 0, 0); + } } /* Parse the mapped configuration file. */ static void -conf_parse(int trans, char *buf, size_t sz) +conf_parse(int trans, char *buf, char **section, char **subsection) { char *cp = buf; - char *bufend = buf + sz; + char *bufend = NULL; char *line; + int lineno = 0; line = cp; + bufend = buf + strlen(buf); while (cp < bufend) { if (*cp == '\n') { /* Check for escaped newlines. */ @@ -352,7 +416,8 @@ conf_parse(int trans, char *buf, size_t sz) *(cp - 1) = *cp = ' '; else { *cp = '\0'; - conf_parse_line(trans, line, cp - line); + lineno++; + conf_parse_line(trans, line, lineno, section, subsection); line = cp + 1; } } @@ -369,33 +434,21 @@ conf_load_defaults(void) return; } -void -conf_init (void) -{ - unsigned int i; - - for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) - LIST_INIT (&conf_bindings[i]); - - TAILQ_INIT (&conf_trans_queue); - conf_reinit(); -} - -static int -conf_load(int trans, char *path) +static char * +conf_load(const char *path) { struct stat sb; if ((stat (path, &sb) == 0) || (errno != ENOENT)) { - char *new_conf_addr; + char *new_conf_addr = NULL; size_t sz = sb.st_size; int fd = open (path, O_RDONLY, 0); if (fd == -1) { xlog_warn("conf_reinit: open (\"%s\", O_RDONLY) failed", path); - return -1; + return NULL; } - new_conf_addr = malloc(sz); + new_conf_addr = malloc(sz+1); if (!new_conf_addr) { xlog_warn("conf_reinit: malloc (%lu) failed", (unsigned long)sz); goto fail; @@ -410,42 +463,103 @@ conf_load(int trans, char *path) close(fd); /* XXX Should we not care about errors and rollback? */ - conf_parse(trans, new_conf_addr, sz); - free(new_conf_addr); - return 0; + new_conf_addr[sz] = '\0'; + return new_conf_addr; fail: close(fd); - free(new_conf_addr); + if (new_conf_addr) free(new_conf_addr); + } + return NULL; +} + +/* remove and free up any existing config state */ +static void conf_free_bindings(void) +{ + unsigned int i; + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) { + struct conf_binding *cb, *next; + + cb = LIST_FIRST(&conf_bindings[i]); + for (; cb; cb = next) { + next = LIST_NEXT(cb, link); + LIST_REMOVE(cb, link); + free(cb->section); + free(cb->arg); + free(cb->tag); + free(cb->value); + free(cb); + } + LIST_INIT(&conf_bindings[i]); } - return -1; } /* Open the config file and map it into our address space, then parse it. */ -void -conf_reinit(void) +static void +conf_reinit(const char *conf_file) { - struct conf_binding *cb = 0; int trans; - unsigned int i; + char * conf_data; trans = conf_begin(); - if (conf_load(trans, conf_path) < 0) + conf_data = conf_load(conf_file); + + if (conf_data == NULL) return; /* Load default configuration values. */ conf_load_defaults(); + /* Parse config contents into the transaction queue */ + char *section = NULL; + char *subsection = NULL; + conf_parse(trans, conf_data, §ion, &subsection); + if (section) free(section); + if (subsection) free(subsection); + free(conf_data); + /* Free potential existing configuration. */ - for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) { - cb = LIST_FIRST (&conf_bindings[i]); - for (; cb; cb = LIST_FIRST (&conf_bindings[i])) - conf_remove_now(cb->section, cb->tag); - } + conf_free_bindings(); + /* Apply the new configuration values */ conf_end(trans, 1); return; } +void +conf_init (const char *conf_file) +{ + unsigned int i; + + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) + LIST_INIT (&conf_bindings[i]); + + TAILQ_INIT (&conf_trans_queue); + + if (conf_file == NULL) conf_file=NFS_CONFFILE; + conf_reinit(conf_file); +} + +/* + * Empty the config and free up any used memory + */ +void +conf_cleanup(void) +{ + conf_free_bindings(); + + struct conf_trans *node, *next; + for (node = TAILQ_FIRST(&conf_trans_queue); node; node = next) { + next = TAILQ_NEXT(node, link); + TAILQ_REMOVE (&conf_trans_queue, node, link); + if (node->section) free(node->section); + if (node->arg) free(node->arg); + if (node->tag) free(node->tag); + if (node->value) free(node->value); + free (node); + } + TAILQ_INIT(&conf_trans_queue); +} + /* * Return the numeric value denoted by TAG in section SECTION or DEF * if that tag does not exist. @@ -533,7 +647,7 @@ retry: * or from environment */ char *env = getenv(cb->value+1); - if (env) + if (env && *env) return env; section = "environment"; tag = cb->value + 1; diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c index 59dfbdf..2ecb2cc 100644 --- a/support/nfs/rmtab.c +++ b/support/nfs/rmtab.c @@ -33,12 +33,14 @@ static FILE *rmfp = NULL; +extern struct state_paths rmtab; + int setrmtabent(char *type) { if (rmfp) fclose(rmfp); - rmfp = fsetrmtabent(_PATH_RMTAB, type); + rmfp = fsetrmtabent(rmtab.statefn, type); return (rmfp != NULL); } diff --git a/support/nsm/file.c b/support/nsm/file.c index aafa755..52f5401 100644 --- a/support/nsm/file.c +++ b/support/nsm/file.c @@ -88,6 +88,7 @@ #include "xlog.h" #include "nsm.h" +#include "misc.h" #define RPCARGSLEN (4 * (8 + 1)) #define LINELEN (RPCARGSLEN + SM_PRIV_SIZE * 2 + 1) @@ -170,25 +171,7 @@ __attribute__((__malloc__)) static char * nsm_make_pathname(const char *directory) { - size_t size; - char *path; - int len; - - size = strlen(nsm_base_dirname) + strlen(directory) + 2; - if (size > PATH_MAX) - return NULL; - - path = malloc(size); - if (path == NULL) - return NULL; - - len = snprintf(path, size, "%s/%s", nsm_base_dirname, directory); - if (error_check(len, size)) { - free(path); - return NULL; - } - - return path; + return generic_make_pathname(nsm_base_dirname, directory); } /* @@ -293,29 +276,8 @@ out: _Bool nsm_setup_pathnames(const char *progname, const char *parentdir) { - static char buf[PATH_MAX]; - struct stat st; - char *path; - - /* First: test length of name and whether it exists */ - if (lstat(parentdir, &st) == -1) { - (void)fprintf(stderr, "%s: Failed to stat %s: %s", - progname, parentdir, strerror(errno)); - return false; - } - - /* Ensure we have a clean directory pathname */ - strncpy(buf, parentdir, sizeof(buf)); - path = dirname(buf); - if (*path == '.') { - (void)fprintf(stderr, "%s: Unusable directory %s", - progname, parentdir); - return false; - } - - xlog(D_CALL, "Using %s as the state directory", parentdir); - strncpy(nsm_base_dirname, parentdir, sizeof(nsm_base_dirname)); - return true; + return generic_setup_basedir(progname, parentdir, nsm_base_dirname, + PATH_MAX); } /** diff --git a/systemd/Makefile.am b/systemd/Makefile.am index 0d15b9f..eef53c4 100644 --- a/systemd/Makefile.am +++ b/systemd/Makefile.am @@ -4,6 +4,7 @@ MAINTAINERCLEANFILES = Makefile.in unit_files = \ nfs-client.target \ + rpc_pipefs.target \ \ nfs-mountd.service \ nfs-server.service \ @@ -42,14 +43,23 @@ EXTRA_DIST = $(unit_files) $(man5_MANS) $(man7_MANS) unit_dir = /usr/lib/systemd/system generator_dir = /usr/lib/systemd/system-generators -EXTRA_PROGRAMS = nfs-server-generator +EXTRA_PROGRAMS = nfs-server-generator rpc-pipefs-generator genexecdir = $(generator_dir) + +COMMON_SRCS = systemd.c systemd.h + +nfs_server_generator_SOURCES = $(COMMON_SRCS) nfs-server-generator.c + +rpc_pipefs_generator_SOURCES = $(COMMON_SRCS) rpc-pipefs-generator.c + nfs_server_generator_LDADD = ../support/export/libexport.a \ ../support/nfs/libnfs.a \ ../support/misc/libmisc.a +rpc_pipefs_generator_LDADD = ../support/nfs/libnfs.a + if INSTALL_SYSTEMD -genexec_PROGRAMS = nfs-server-generator +genexec_PROGRAMS = nfs-server-generator rpc-pipefs-generator install-data-hook: $(unit_files) mkdir -p $(DESTDIR)/$(unitdir) cp $(unit_files) $(DESTDIR)/$(unitdir) diff --git a/systemd/nfs-blkmap.service b/systemd/nfs-blkmap.service index ddc324e..2bbcee6 100644 --- a/systemd/nfs-blkmap.service +++ b/systemd/nfs-blkmap.service @@ -2,8 +2,8 @@ Description=pNFS block layout mapping daemon DefaultDependencies=no Conflicts=umount.target -After=var-lib-nfs-rpc_pipefs.mount -Requires=var-lib-nfs-rpc_pipefs.mount +After=rpc_pipefs.target +Requires=rpc_pipefs.target PartOf=nfs-utils.service diff --git a/systemd/nfs-idmapd.service b/systemd/nfs-idmapd.service index acca86b..f38fe52 100644 --- a/systemd/nfs-idmapd.service +++ b/systemd/nfs-idmapd.service @@ -1,8 +1,8 @@ [Unit] Description=NFSv4 ID-name mapping service DefaultDependencies=no -Requires=var-lib-nfs-rpc_pipefs.mount -After=var-lib-nfs-rpc_pipefs.mount local-fs.target +Requires=rpc_pipefs.target +After=rpc_pipefs.target local-fs.target BindsTo=nfs-server.service diff --git a/systemd/nfs-mountd.service b/systemd/nfs-mountd.service index 15e828b..e8ece53 100644 --- a/systemd/nfs-mountd.service +++ b/systemd/nfs-mountd.service @@ -2,8 +2,10 @@ Description=NFS Mount Daemon DefaultDependencies=no Requires=proc-fs-nfsd.mount +Wants=network-online.target After=proc-fs-nfsd.mount -After=network.target local-fs.target +After=network-online.target local-fs.target +After=rpcbind.socket BindsTo=nfs-server.service [Service] diff --git a/systemd/nfs-server-generator.c b/systemd/nfs-server-generator.c index cc99969..737f109 100644 --- a/systemd/nfs-server-generator.c +++ b/systemd/nfs-server-generator.c @@ -29,6 +29,7 @@ #include "misc.h" #include "nfslib.h" #include "exportfs.h" +#include "systemd.h" /* A simple "set of strings" to remove duplicates * found in /etc/exports @@ -55,38 +56,31 @@ static int is_unique(struct list **lp, char *path) return 1; } -/* We need to convert a path name to a systemd unit - * name. This requires some translation ('/' -> '-') - * and some escaping. - */ -static void systemd_escape(FILE *f, char *path) +static int has_noauto_flag(char *path) { - while (*path == '/') - path++; - if (!*path) { - /* "/" becomes "-", otherwise leading "/" is ignored */ - fputs("-", f); - return; - } - while (*path) { - char c = *path++; - - if (c == '/') { - /* multiple non-trailing slashes become '-' */ - while (*path == '/') - path++; - if (*path) - fputs("-", f); - } else if (isalnum(c) || c == ':' || c == '.') - fputc(c, f); - else - fprintf(f, "\\x%02x", c & 0xff); + FILE *fstab; + struct mntent *mnt; + + fstab = setmntent("/etc/fstab", "r"); + if (!fstab) + return 0; + + while ((mnt = getmntent(fstab)) != NULL) { + int l = strlen(mnt->mnt_dir); + if (strncmp(mnt->mnt_dir, path, l) != 0) + continue; + if (path[l] && path[l] != '/') + continue; + if (hasmntopt(mnt, "noauto")) + break; } + fclose(fstab); + return mnt != NULL; } int main(int argc, char *argv[]) { - char *path; + char *path, *spath; char dirbase[] = "/nfs-server.service.d"; char filebase[] = "/order-with-mounts.conf"; nfs_export *exp; @@ -124,6 +118,10 @@ int main(int argc, char *argv[]) for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { if (!is_unique(&list, exp->m_export.e_path)) continue; + if (exp->m_export.e_mountpoint) + continue; + if (has_noauto_flag(exp->m_export.e_path)) + continue; if (strchr(exp->m_export.e_path, ' ')) fprintf(f, "RequiresMountsFor=\"%s\"\n", exp->m_export.e_path); @@ -141,9 +139,15 @@ int main(int argc, char *argv[]) if (strcmp(mnt->mnt_type, "nfs") != 0 && strcmp(mnt->mnt_type, "nfs4") != 0) continue; - fprintf(f, "Before= "); - systemd_escape(f, mnt->mnt_dir); - fprintf(f, ".mount\n"); + + spath = systemd_escape(mnt->mnt_dir, ".mount"); + if (!spath) { + fprintf(stderr, + "nfs-server-generator: convert path failed: %s\n", + mnt->mnt_dir); + continue; + } + fprintf(f, "Before=%s\n", spath); } fclose(fstab); diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service index 5be5de6..136552b 100644 --- a/systemd/nfs-server.service +++ b/systemd/nfs-server.service @@ -3,12 +3,12 @@ Description=NFS server and services DefaultDependencies=no Requires= network.target proc-fs-nfsd.mount Requires= nfs-mountd.service -Wants=rpcbind.socket +Wants=rpcbind.socket network-online.target Wants=rpc-statd.service nfs-idmapd.service Wants=rpc-statd-notify.service -After= local-fs.target -After= network.target proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service +After= network-online.target local-fs.target +After= proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service After= nfs-idmapd.service rpc-statd.service Before= rpc-statd-notify.service diff --git a/systemd/nfs.conf.man b/systemd/nfs.conf.man index 91c49a0..189b052 100644 --- a/systemd/nfs.conf.man +++ b/systemd/nfs.conf.man @@ -96,6 +96,18 @@ value, which can be one or more from the list .BR all . When a list is given, the members should be comma-separated. .TP +.B general +Recognized values: +.BR pipefs-directory . + +See +.BR blkmapd (8), +.BR rpc.idmapd (8), +and +.BR rpc.gssd (8) +for details. + +.TP .B nfsdcltrack Recognized values: .BR storagedir . @@ -154,6 +166,13 @@ section, are used to configure mountd. See .BR rpc.mountd (8) for details. +The +.B state-directory-path +value in the +.B [mountd] +section is also used by +.BR exportfs (8). + .TP .B statd Recognized values: @@ -198,7 +217,6 @@ Recognized values: .BR limit-to-legacy-enctypes , .BR context-timeout , .BR rpc-timeout , -.BR pipefs-directory , .BR keytab-file , .BR cred-cache-directory , .BR preferred-realm . diff --git a/systemd/rpc-gssd.service.in b/systemd/rpc-gssd.service.in index b353027..6807db3 100644 --- a/systemd/rpc-gssd.service.in +++ b/systemd/rpc-gssd.service.in @@ -2,8 +2,8 @@ Description=RPC security service for NFS client and server DefaultDependencies=no Conflicts=umount.target -Requires=var-lib-nfs-rpc_pipefs.mount -After=var-lib-nfs-rpc_pipefs.mount +Requires=rpc_pipefs.target +After=rpc_pipefs.target ConditionPathExists=@_sysconfdir@/krb5.keytab diff --git a/systemd/rpc-pipefs-generator.c b/systemd/rpc-pipefs-generator.c new file mode 100644 index 0000000..59eee87 --- /dev/null +++ b/systemd/rpc-pipefs-generator.c @@ -0,0 +1,137 @@ +/* + * rpc-pipefs-generator: + * systemd generator to create ordering dependencies between + * nfs services and the rpc_pipefs mountpoint + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfslib.h" +#include "conffile.h" +#include "systemd.h" + +#define RPC_PIPEFS_DEFAULT "/var/lib/nfs/rpc_pipefs" + +static int generate_mount_unit(const char *pipefs_path, const char *pipefs_unit, + const char *dirname) +{ + char *path; + FILE *f; + + path = malloc(strlen(dirname) + 1 + strlen(pipefs_unit)); + if (!path) + return 1; + sprintf(path, "%s/%s", dirname, pipefs_unit); + f = fopen(path, "w"); + if (!f) + return 1; + + fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n"); + fprintf(f, "Description=RPC Pipe File System\n"); + fprintf(f, "DefaultDependencies=no\n"); + fprintf(f, "After=systemd-tmpfiles-setup.service\n"); + fprintf(f, "Conflicts=umount.target\n"); + fprintf(f, "\n[Mount]\n"); + fprintf(f, "What=sunrpc\n"); + fprintf(f, "Where=%s\n", pipefs_path); + fprintf(f, "Type=rpc_pipefs\n"); + + fclose(f); + return 0; +} + +static +int generate_target(char *pipefs_path, const char *dirname) +{ + char *path; + char filebase[] = "/rpc_pipefs.target"; + char *pipefs_unit; + FILE *f; + int ret = 0; + + pipefs_unit = systemd_escape(pipefs_path, ".mount"); + if (!pipefs_unit) + return 1; + + ret = generate_mount_unit(pipefs_path, pipefs_unit, dirname); + if (ret) + return ret; + + path = malloc(strlen(dirname) + 1 + sizeof(filebase)); + if (!path) + return 2; + sprintf(path, "%s", dirname); + mkdir(path, 0755); + strcat(path, filebase); + f = fopen(path, "w"); + if (!f) + return 1; + + fprintf(f, "# Automatically generated by rpc-pipefs-generator\n\n[Unit]\n"); + fprintf(f, "Requires=%s\n", pipefs_unit); + fprintf(f, "After=%s\n", pipefs_unit); + fclose(f); + + return 0; +} + +static int is_non_pipefs_mountpoint(char *path) +{ + FILE *mtab; + struct mntent *mnt; + + mtab = setmntent("/etc/mtab", "r"); + if (!mtab) + return 0; + + while ((mnt = getmntent(mtab)) != NULL) { + if (strlen(mnt->mnt_dir) != strlen(path)) + continue; + if (strncmp(mnt->mnt_dir, path, strlen(mnt->mnt_dir))) + continue; + if (strncmp(mnt->mnt_type, "rpc_pipefs", strlen(mnt->mnt_type))) + break; + } + fclose(mtab); + return mnt != NULL; +} + +int main(int argc, char *argv[]) +{ + int ret; + char *s; + + /* Avoid using any external services */ + xlog_syslog(0); + + if (argc != 4 || argv[1][0] != '/') { + fprintf(stderr, "rpc-pipefs-generator: create systemd dependencies for nfs services\n"); + fprintf(stderr, "Usage: normal-dir early-dir late-dir\n"); + exit(1); + } + + conf_init(NFS_CONFFILE); + s = conf_get_str("general", "pipefs-directory"); + if (!s) + exit(0); + if (strlen(s) == strlen(RPC_PIPEFS_DEFAULT) && + strcmp(s, RPC_PIPEFS_DEFAULT) == 0) + exit(0); + + if (is_non_pipefs_mountpoint(s)) + exit(1); + + ret = generate_target(s, argv[1]); + exit(ret); +} diff --git a/systemd/rpc-statd-notify.service b/systemd/rpc-statd-notify.service index 7bfc9b1..687fe31 100644 --- a/systemd/rpc-statd-notify.service +++ b/systemd/rpc-statd-notify.service @@ -1,8 +1,8 @@ [Unit] Description=Notify NFS peers of a restart DefaultDependencies=no -Requires=network.target -After=local-fs.target network.target nss-lookup.target +Wants=network-online.target +After=local-fs.target network-online.target nss-lookup.target # if we run an nfs server, it needs to be running before we # tell clients that it has restarted. diff --git a/systemd/rpc-statd.service b/systemd/rpc-statd.service index 60d600f..f41ae20 100644 --- a/systemd/rpc-statd.service +++ b/systemd/rpc-statd.service @@ -3,7 +3,8 @@ Description=NFS status monitor for NFSv2/3 locking. DefaultDependencies=no Conflicts=umount.target Requires=nss-lookup.target rpcbind.socket -After=network.target nss-lookup.target rpcbind.socket +Wants=network-online.target +After=network-online.target nss-lookup.target rpcbind.socket PartOf=nfs-utils.service diff --git a/systemd/rpc-svcgssd.service b/systemd/rpc-svcgssd.service index 7187e3c..cb2bcd4 100644 --- a/systemd/rpc-svcgssd.service +++ b/systemd/rpc-svcgssd.service @@ -1,8 +1,7 @@ [Unit] Description=RPC security service for NFS server DefaultDependencies=no -Requires=var-lib-nfs-rpc_pipefs.mount -After=var-lib-nfs-rpc_pipefs.mount local-fs.target +After=local-fs.target PartOf=nfs-server.service PartOf=nfs-utils.service diff --git a/systemd/rpc_pipefs.target b/systemd/rpc_pipefs.target new file mode 100644 index 0000000..01d4d27 --- /dev/null +++ b/systemd/rpc_pipefs.target @@ -0,0 +1,3 @@ +[Unit] +Requires=var-lib-nfs-rpc_pipefs.mount +After=var-lib-nfs-rpc_pipefs.mount diff --git a/systemd/systemd.c b/systemd/systemd.c new file mode 100644 index 0000000..17820d4 --- /dev/null +++ b/systemd/systemd.c @@ -0,0 +1,133 @@ +/* + * Helper functions for systemd generators in nfs-utils. + * + * Currently just systemd_escape(). + */ + +#include +#include +#include +#include + +static const char hex[16] = +{ + '0', '1', '2', '3', '4', '5', '6', '7', + '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', +}; + +/* + * determine length of the string that systemd_escape() needs to allocate + */ +static int systemd_len(char *path) +{ + char *p; + int len = 0; + + p = path; + while (*p == '/') + /* multiple leading "/" are ignored */ + p++; + + if (!*p) + /* root directory "/" becomes is encoded as a single "-" */ + return 1; + + if (*p == '.') + /* + * replace "." with "\x2d" escape sequence if + * it's the first character in escaped path + * */ + len += 4; + + while (*p) { + unsigned char c = *p++; + + if (c == '/') { + /* multiple non-trailing slashes become '-' */ + while (*p == '/') + p++; + if (*p) + len++; + } else if (isalnum(c) || c == ':' || c == '.' || c == '_') + /* these characters are not replaced */ + len++; + else + /* replace with "\x2d" escape sequence */ + len += 4; + } + + return len; +} + +/* + * convert c to "\x2d" escape sequence and append to string + * at position p, advancing p + */ +static char *hexify(unsigned char c, char *p) +{ + *p++ = '\\'; + *p++ = 'x'; + *p++ = hex[c >> 4]; + *p++ = hex[c & 0xf]; + return p; +} + +/* + * convert a path to a unit name according to the logic in systemd.unit(5): + * + * Basically, given a path, "/" is replaced by "-", and all other + * characters which are not ASCII alphanumerics are replaced by C-style + * "\x2d" escapes (except that "_" is never replaced and "." is only + * replaced when it would be the first character in the escaped path). + * The root directory "/" is encoded as single dash, while otherwise the + * initial and ending "/" are removed from all paths during + * transformation. + * + * NB: Although the systemd.unit(5) doesn't mention it, the ':' character + * is not escaped. + */ +char *systemd_escape(char *path, char *suffix) +{ + char *result; + char *p; + int len; + + len = systemd_len(path); + result = malloc(len + strlen(suffix) + 1); + p = result; + while (*path == '/') + /* multiple leading "/" are ignored */ + path++; + if (!*path) { + /* root directory "/" becomes is encoded as a single "-" */ + *p++ = '-'; + goto out; + } + if (*path == '.') + /* + * replace "." with "\x2d" escape sequence if + * it's the first character in escaped path + * */ + p = hexify(*path++, p); + + while (*path) { + unsigned char c = *path++; + + if (c == '/') { + /* multiple non-trailing slashes become '-' */ + while (*path == '/') + path++; + if (*path) + *p++ = '-'; + } else if (isalnum(c) || c == ':' || c == '.' || c == '_') + /* these characters are not replaced */ + *p++ = c; + else + /* replace with "\x2d" escape sequence */ + p = hexify(c, p); + } + +out: + sprintf(p, "%s", suffix); + return result; +} diff --git a/systemd/systemd.h b/systemd/systemd.h new file mode 100644 index 0000000..25235ec --- /dev/null +++ b/systemd/systemd.h @@ -0,0 +1,6 @@ +#ifndef SYSTEMD_H +#define SYSTEMD_H + +char *systemd_escape(char *path, char *suffix); + +#endif /* SYSTEMD_H */ diff --git a/utils/blkmapd/blkmapd.man b/utils/blkmapd/blkmapd.man index 914b80f..4b3d3f0 100644 --- a/utils/blkmapd/blkmapd.man +++ b/utils/blkmapd/blkmapd.man @@ -43,9 +43,24 @@ Performs device discovery only then exits. Runs .B blkmapd in the foreground and sends output to stderr (as opposed to syslogd) +.SH CONFIGURATION FILE +The +.B blkmapd +daemon recognizes the following value from the +.B [general] +section of the +.I /etc/nfs.conf +configuration file: +.TP +.B pipefs-directory +Tells +.B blkmapd +where to look for the rpc_pipefs filesystem. The default value is +.IR /var/lib/nfs/rpc_pipefs . .SH SEE ALSO .BR nfs (5), -.BR dmsetup (8) +.BR dmsetup (8), +.BR nfs.conf (5) .sp RFC 5661 for the NFS version 4.1 specification. .br diff --git a/utils/blkmapd/device-discovery.c b/utils/blkmapd/device-discovery.c index 8eb3fd0..c66669d 100644 --- a/utils/blkmapd/device-discovery.c +++ b/utils/blkmapd/device-discovery.c @@ -50,21 +50,36 @@ #include #include +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + #include "device-discovery.h" #include "xcommon.h" +#include "nfslib.h" +#include "conffile.h" #define EVENT_SIZE (sizeof(struct inotify_event)) #define EVENT_BUFSIZE (1024 * EVENT_SIZE) -#define BL_PIPE_FILE "/var/lib/nfs/rpc_pipefs/nfs/blocklayout" -#define NFSPIPE_DIR "/var/lib/nfs/rpc_pipefs/nfs" #define RPCPIPE_DIR "/var/lib/nfs/rpc_pipefs" #define PID_FILE "/var/run/blkmapd.pid" +#define CONF_SAVE(w, f) do { \ + char *p = f; \ + if (p != NULL) \ + (w) = p; \ +} while (0) + +static char bl_pipe_file[PATH_MAX]; +static char nfspipe_dir[PATH_MAX]; +static char rpcpipe_dir[PATH_MAX]; + struct bl_disk *visible_disk_list; int bl_watch_fd, bl_pipe_fd, nfs_pipedir_wfd, rpc_pipedir_wfd; int pidfd = -1; + struct bl_disk_path *bl_get_path(const char *filepath, struct bl_disk_path *paths) { @@ -358,8 +373,8 @@ static void bl_rpcpipe_cb(void) continue; if (event->mask & IN_CREATE) { BL_LOG_WARNING("nfs pipe dir created\n"); - bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd); - bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR); + bl_watch_dir(nfspipe_dir, &nfs_pipedir_wfd); + bl_pipe_fd = open(bl_pipe_file, O_RDWR); } else if (event->mask & IN_DELETE) { BL_LOG_WARNING("nfs pipe dir deleted\n"); inotify_rm_watch(bl_watch_fd, nfs_pipedir_wfd); @@ -372,7 +387,7 @@ static void bl_rpcpipe_cb(void) continue; if (event->mask & IN_CREATE) { BL_LOG_WARNING("blocklayout pipe file created\n"); - bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR); + bl_pipe_fd = open(bl_pipe_file, O_RDWR); if (bl_pipe_fd < 0) BL_LOG_ERR("open %s failed: %s\n", event->name, strerror(errno)); @@ -437,6 +452,18 @@ int main(int argc, char **argv) { int opt, dflag = 0, fg = 0, ret = 1; char pidbuf[64]; + char *xrpcpipe_dir = NULL; + + strncpy(rpcpipe_dir, RPCPIPE_DIR, sizeof(rpcpipe_dir)); + conf_init(NFS_CONFFILE); + CONF_SAVE(xrpcpipe_dir, conf_get_str("general", "pipefs-directory")); + if (xrpcpipe_dir != NULL) + strlcpy(rpcpipe_dir, xrpcpipe_dir, sizeof(rpcpipe_dir)); + + strncpy(nfspipe_dir, rpcpipe_dir, sizeof(nfspipe_dir)); + strlcat(nfspipe_dir, "/nfs", sizeof(nfspipe_dir)); + strncpy(bl_pipe_file, rpcpipe_dir, sizeof(bl_pipe_file)); + strlcat(bl_pipe_file, "/nfs/blocklayout", sizeof(bl_pipe_file)); while ((opt = getopt(argc, argv, "hdf")) != -1) { switch (opt) { @@ -496,12 +523,12 @@ int main(int argc, char **argv) } /* open pipe file */ - bl_watch_dir(RPCPIPE_DIR, &rpc_pipedir_wfd); - bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd); + bl_watch_dir(rpcpipe_dir, &rpc_pipedir_wfd); + bl_watch_dir(nfspipe_dir, &nfs_pipedir_wfd); - bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR); + bl_pipe_fd = open(bl_pipe_file, O_RDWR); if (bl_pipe_fd < 0) - BL_LOG_ERR("open pipe file %s failed: %s\n", BL_PIPE_FILE, strerror(errno)); + BL_LOG_ERR("open pipe file %s failed: %s\n", bl_pipe_file, strerror(errno)); while (1) { /* discover device when needed */ diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c index 61dddfb..beed1b3 100644 --- a/utils/exportfs/exportfs.c +++ b/utils/exportfs/exportfs.c @@ -50,7 +50,8 @@ static void release_lockfile(void); static const char *lockfile = EXP_LOCKFILE; static int _lockfd = -1; -char *conf_path = NFS_CONFFILE; + +struct state_paths etab; /* * If we aren't careful, changes made by exportfs can be lost @@ -95,6 +96,7 @@ main(int argc, char **argv) int f_ignore = 0; int i, c; int force_flush = 0; + char *s; if ((progname = strrchr(argv[0], '/')) != NULL) progname++; @@ -105,9 +107,14 @@ main(int argc, char **argv) xlog_stderr(1); xlog_syslog(0); - conf_init(); + conf_init(NFS_CONFFILE); xlog_from_conffile("exportfs"); + /* NOTE: following uses "mountd" section of nfs.conf !!!! */ + s = conf_get_str("mountd", "state-directory-path"); + if (s && !state_setup_basedir(argv[0], s)) + exit(1); + while ((c = getopt(argc, argv, "ad:fhio:ruvs")) != EOF) { switch(c) { case 'a': @@ -159,13 +166,17 @@ main(int argc, char **argv) xlog(L_ERROR, "-r and -u are incompatible"); return 1; } + if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab)) + return 1; if (optind == argc && ! f_all) { if (force_flush) { cache_flush(1); + free_state_path_names(&etab); return 0; } else { xtab_export_read(); dump(f_verbose, f_export_format); + free_state_path_names(&etab); return 0; } } @@ -206,6 +217,7 @@ main(int argc, char **argv) } xtab_export_write(); cache_flush(force_flush); + free_state_path_names(&etab); return export_errno; } diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man index 45b6d83..91d3589 100644 --- a/utils/exportfs/exportfs.man +++ b/utils/exportfs/exportfs.man @@ -148,6 +148,29 @@ options. .TP .B -s Display the current export list suitable for /etc/exports. + +.SH CONFIGURATION FILE +The +.B [exportfs] +section of the +.I /etc/nfs.conf +configuration file can contain a +.B debug +value, which can be one or more from the list +.BR general , +.BR call , +.BR auth , +.BR parse , +.BR all . +When a list is given, the members should be comma-separated. + +.B exportfs +will also recognize the +.B state-directory-path +value from the +.B [mountd] +section. + .SH DISCUSSION .SS Exporting Directories The first synopsis shows how to invoke diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man index 0c516fa..9efa29f 100644 --- a/utils/exportfs/nfsd.man +++ b/utils/exportfs/nfsd.man @@ -105,11 +105,6 @@ clients have for different filesystems. The caches are: .TP -.B auth.domain -This cache maps the name of a client (or domain) to an internal data -structure. The only access that is possible is to flush the cache. - -.TP .B auth.unix.ip This cache contains a mapping from IP address to the name of the authentication domain that the ipaddress should be treated as part of. @@ -133,7 +128,8 @@ are: .B flush When a number of seconds since epoch (1 Jan 1970) is written to this file, all entries in the cache that were last updated before that file -become invalidated and will be flushed out. Writing 1 will flush +become invalidated and will be flushed out. Writing a time in the +future (in seconds since epoch) will flush everything. This is the only file that will always be present. .TP diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c index 4d18d35..053a223 100644 --- a/utils/gssd/gssd.c +++ b/utils/gssd/gssd.c @@ -79,7 +79,6 @@ static int pipefs_fd; static int inotify_fd; struct event inotify_ev; -char *conf_path = NFS_CONFFILE; char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE; char **ccachesearch; int use_memcache = 0; @@ -87,6 +86,7 @@ int root_uses_machine_creds = 1; unsigned int context_timeout = 0; unsigned int rpc_timeout = 5; char *preferred_realm = NULL; +char *ccachedir = NULL; /* Avoid DNS reverse lookups on server names */ static bool avoid_dns = true; int thread_started = false; @@ -837,21 +837,12 @@ usage(char *progname) exit(1); } -int -main(int argc, char *argv[]) +inline static void +read_gss_conf(void) { - int fg = 0; - int verbosity = 0; - int rpc_verbosity = 0; - int opt; - int i; - extern char *optarg; - char *progname; - char *ccachedir = NULL; - struct event sighup_ev; char *s; - conf_init(); + conf_init(NFS_CONFFILE); use_memcache = conf_get_bool("gssd", "use-memcache", use_memcache); root_uses_machine_creds = conf_get_bool("gssd", "use-machine-creds", root_uses_machine_creds); @@ -865,6 +856,10 @@ main(int argc, char *argv[]) s = conf_get_str("gssd", "pipefs-directory"); if (!s) s = conf_get_str("general", "pipefs-directory"); + else + printerr(0, "WARNING: Specifying pipefs-directory in the [gssd] " + "section of %s is deprecated. Use the [general] " + "section instead.", NFS_CONFFILE); if (s) pipefs_path = s; s = conf_get_str("gssd", "keytab-file"); @@ -877,6 +872,22 @@ main(int argc, char *argv[]) if (s) preferred_realm = s; +} + +int +main(int argc, char *argv[]) +{ + int fg = 0; + int verbosity = 0; + int rpc_verbosity = 0; + int opt; + int i; + extern char *optarg; + char *progname; + struct event sighup_ev; + + read_gss_conf(); + while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:T:R:")) != -1) { switch (opt) { case 'f': diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man index 87eef02..e620f0d 100644 --- a/utils/gssd/gssd.man +++ b/utils/gssd/gssd.man @@ -335,10 +335,6 @@ Equivalent to Equivalent to .BR -t . .TP -.B pipefs-directory -Equivalent to -.BR -p . -.TP .B keytab-file Equivalent to .BR -k . @@ -350,6 +346,14 @@ Equivalent to .B preferred-realm Equivalent to .BR -R . +.P +In addtion, the following value is recognized from the +.B [general] +section: +.TP +.B pipefs-directory +Equivalent to +.BR -p . .SH SEE ALSO .BR rpc.svcgssd (8), diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c index d74d372..4fc81c3 100644 --- a/utils/gssd/gssd_proc.c +++ b/utils/gssd/gssd_proc.c @@ -729,10 +729,18 @@ handle_gssd_upcall(struct clnt_upcall_info *info) char *target = NULL; char *service = NULL; char *enctypes = NULL; + char *upcall_str; + char *pbuf = info->lbuf; printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath); - for (p = strtok(info->lbuf, " "); p; p = strtok(NULL, " ")) { + upcall_str = strdup(info->lbuf); + if (upcall_str == NULL) { + printerr(0, "ERROR: malloc failure\n"); + goto out_nomem; + } + + while ((p = strsep(&pbuf, " "))) { if (!strncmp(p, "mech=", strlen("mech="))) mech = p + strlen("mech="); else if (!strncmp(p, "uid=", strlen("uid="))) @@ -748,7 +756,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) if (!mech || strlen(mech) < 1) { printerr(0, "WARNING: handle_gssd_upcall: " "failed to find gss mechanism name " - "in upcall string '%s'\n", info->lbuf); + "in upcall string '%s'\n", upcall_str); goto out; } @@ -761,7 +769,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) if (!uidstr) { printerr(0, "WARNING: handle_gssd_upcall: " "failed to find uid " - "in upcall string '%s'\n", info->lbuf); + "in upcall string '%s'\n", upcall_str); goto out; } @@ -774,7 +782,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) if (target && strlen(target) < 1) { printerr(0, "WARNING: handle_gssd_upcall: " "failed to parse target name " - "in upcall string '%s'\n", info->lbuf); + "in upcall string '%s'\n", upcall_str); goto out; } @@ -789,7 +797,7 @@ handle_gssd_upcall(struct clnt_upcall_info *info) if (service && strlen(service) < 1) { printerr(0, "WARNING: handle_gssd_upcall: " "failed to parse service type " - "in upcall string '%s'\n", info->lbuf); + "in upcall string '%s'\n", upcall_str); goto out; } @@ -802,6 +810,8 @@ handle_gssd_upcall(struct clnt_upcall_info *info) do_error_downcall(clp->gssd_fd, uid, -EACCES); } out: + free(upcall_str); +out_nomem: free(info); return; } diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c index 1fb579a..3514ae1 100644 --- a/utils/gssd/svcgssd.c +++ b/utils/gssd/svcgssd.c @@ -63,8 +63,6 @@ #include "err_util.h" #include "conffile.h" -char *conf_path = NFS_CONFFILE; - void sig_die(int signal) { @@ -103,7 +101,7 @@ main(int argc, char *argv[]) char *principal = NULL; char *s; - conf_init(); + conf_init(NFS_CONFFILE); s = conf_get_str("svcgssd", "principal"); if (!s) diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c index f4e083a..c12e878 100644 --- a/utils/idmapd/idmapd.c +++ b/utils/idmapd/idmapd.c @@ -165,9 +165,6 @@ static char *nobodyuser, *nobodygroup; static uid_t nobodyuid; static gid_t nobodygid; -/* Used by conffile.c in libnfs.a */ -char *conf_path; - static int flush_nfsd_cache(char *path, time_t now) { @@ -219,8 +216,8 @@ main(int argc, char **argv) int serverstart = 1, clientstart = 1; int ret; char *progname; + char *conf_path = NULL; - conf_path = _PATH_IDMAPDCONF; nobodyuser = NFS4NOBODY_USER; nobodygroup = NFS4NOBODY_GROUP; strlcpy(pipefsdir, PIPEFS_DIR, sizeof(pipefsdir)); @@ -234,8 +231,11 @@ main(int argc, char **argv) #define GETOPTSTR "hvfd:p:U:G:c:CS" opterr=0; /* Turn off error messages */ while ((opt = getopt(argc, argv, GETOPTSTR)) != -1) { - if (opt == 'c') + if (opt == 'c') { + warnx("-c is deprecated and may be removed in the " + "future. See idmapd(8)."); conf_path = optarg; + } if (opt == '?') { if (strchr(GETOPTSTR, optopt)) warnx("'-%c' option requires an argument.", optopt); @@ -247,17 +247,33 @@ main(int argc, char **argv) } optind = 1; - if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) { - warn("Skipping configuration file \"%s\"", conf_path); - conf_path = NULL; + if (conf_path) { /* deprecated -c option was specified */ + if (stat(conf_path, &sb) == -1 && (errno == ENOENT || errno == EACCES)) { + warn("Skipping configuration file \"%s\"", conf_path); + conf_path = NULL; + } else { + conf_init(conf_path); + verbose = conf_get_num("General", "Verbosity", 0); + cache_entry_expiration = conf_get_num("General", + "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY); + CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); + if (xpipefsdir != NULL) + strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); + CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User")); + CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group")); + } } else { - conf_init(); - verbose = conf_get_num("General", "Verbosity", 0); - cache_entry_expiration = conf_get_num("General", - "Cache-Expiration", DEFAULT_IDMAP_CACHE_EXPIRY); + conf_path = NFS_CONFFILE; + conf_init(conf_path); CONF_SAVE(xpipefsdir, conf_get_str("General", "Pipefs-Directory")); if (xpipefsdir != NULL) strlcpy(pipefsdir, xpipefsdir, sizeof(pipefsdir)); + + conf_path = _PATH_IDMAPDCONF; + conf_init(conf_path); + verbose = conf_get_num("General", "Verbosity", 0); + cache_entry_expiration = conf_get_num("General", + "cache-expiration", DEFAULT_IDMAP_CACHE_EXPIRY); CONF_SAVE(nobodyuser, conf_get_str("Mapping", "Nobody-User")); CONF_SAVE(nobodygroup, conf_get_str("Mapping", "Nobody-Group")); } diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man index d4ab894..5f34d2b 100644 --- a/utils/idmapd/idmapd.man +++ b/utils/idmapd/idmapd.man @@ -73,11 +73,28 @@ The default value is \&"/var/lib/nfs/rpc_pipefs\&". .It Fl c Ar path Use configuration file .Ar path . +This option is deprecated. .It Fl C Client-only: perform no idmapping for any NFS server, even if one is detected. .It Fl S Server-only: perform no idmapping for any NFS client, even if one is detected. .El +.Sh CONFIGURATION FILES +.Nm +recognizes the following value from the +.Sy [general] +section of the +.Pa /etc/nfs.conf +configuration file: +.Bl -tag -width Ds_imagedir +.It Sy pipefs-directory +Equivalent to +.Sy -p . +.El +.Pp +All other settings related to id mapping are found in the +.Pa /etc/idmapd.conf +configuration file. .Sh EXAMPLES .Cm rpc.idmapd -f -vvv .Pp @@ -94,9 +111,11 @@ messages to console, and with a verbosity level of 3. .\" This next request is for sections 1, 6, 7 & 8 only. .\" .Sh ENVIRONMENT .Sh FILES -.Pa /etc/idmapd.conf +.Pa /etc/idmapd.conf , +.Pa /etc/nfs.conf .Sh SEE ALSO .Xr idmapd.conf 5 , +.Xr nfs.conf 5 , .Xr nfsidmap 8 .\".Sh SEE ALSO .\".Xr nylon.conf 4 diff --git a/utils/mount/configfile.c b/utils/mount/configfile.c index 0a4cc04..dc964c7 100644 --- a/utils/mount/configfile.c +++ b/utils/mount/configfile.c @@ -51,10 +51,6 @@ #define NFSMOUNT_SERVER "Server" #endif -#ifndef MOUNTOPTS_CONFFILE -#define MOUNTOPTS_CONFFILE "/etc/nfsmount.conf" -#endif -char *conf_path = MOUNTOPTS_CONFFILE; enum { MNT_NOARG=0, MNT_INTARG, diff --git a/utils/mount/mount_config.h b/utils/mount/mount_config.h index 69ffd1e..e4f8511 100644 --- a/utils/mount/mount_config.h +++ b/utils/mount/mount_config.h @@ -20,6 +20,10 @@ #include "conffile.h" #include "xlog.h" +#ifndef MOUNTOPTS_CONFFILE +#define MOUNTOPTS_CONFFILE "/etc/nfsmount.conf" +#endif + extern char *conf_get_mntopts(char *, char *, char *); static inline void mount_config_init(char *program) @@ -28,7 +32,7 @@ static inline void mount_config_init(char *program) /* * Read the the default mount options */ - conf_init(); + conf_init(MOUNTOPTS_CONFFILE); } static inline char *mount_config_opts(char *spec, diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c index 1f01f7f..2d40657 100644 --- a/utils/mount/mount_libmount.c +++ b/utils/mount/mount_libmount.c @@ -188,6 +188,7 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv) }; mnt_context_init_helper(cxt, MNT_ACT_UMOUNT, 0); + mnt_context_disable_canonicalize(cxt, 1); while ((c = getopt_long (argc, argv, "fvnrlh", longopts, NULL)) != -1) { diff --git a/utils/mount/network.c b/utils/mount/network.c index 7dceb2d..281e935 100644 --- a/utils/mount/network.c +++ b/utils/mount/network.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -804,6 +805,7 @@ int start_statd(void) pid_t pid = fork(); switch (pid) { case 0: /* child */ + setgroups(0, NULL); setgid(0); setuid(0); execle(START_STATD, START_STATD, NULL, envp); @@ -1638,6 +1640,7 @@ int nfs_options2pmap(struct mount_options *options, struct pmap *nfs_pmap, struct pmap *mnt_pmap) { struct nfs_version version; + memset(&version, 0, sizeof(version)); if (!nfs_nfs_program(options, &nfs_pmap->pm_prog)) return 0; diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c index 387d734..c2a739b 100644 --- a/utils/mount/stropts.c +++ b/utils/mount/stropts.c @@ -73,6 +73,13 @@ #define NFS_DEF_BG_TIMEOUT_MINUTES (10000u) #endif +#ifndef NFS_DEFAULT_MAJOR +#define NFS_DEFAULT_MAJOR 4 +#endif +#ifndef NFS_DEFAULT_MINOR +#define NFS_DEFAULT_MINOR 2 +#endif + extern int nfs_mount_data_version; extern char *progname; extern int verbose; @@ -112,20 +119,28 @@ static void nfs_default_version(struct nfsmount_info *mi) if (mi->version.v_mode == V_DEFAULT && config_default_vers.v_mode != V_DEFAULT) { mi->version.major = config_default_vers.major; - mi->version.minor = config_default_vers.minor; + if (config_default_vers.v_mode == V_SPECIFIC) + mi->version.minor = config_default_vers.minor; + else + mi->version.minor = NFS_DEFAULT_MINOR; return; } if (mi->version.v_mode == V_GENERAL) { if (config_default_vers.v_mode != V_DEFAULT && - mi->version.major == config_default_vers.major) - mi->version.minor = config_default_vers.minor; + mi->version.major == config_default_vers.major) { + if (config_default_vers.v_mode == V_SPECIFIC) + mi->version.minor = config_default_vers.minor; + else + mi->version.minor = NFS_DEFAULT_MINOR; + } else + mi->version.minor = NFS_DEFAULT_MINOR; return; } #endif /* MOUNT_CONFIG */ - mi->version.major = 4; - mi->version.minor = 2; + mi->version.major = NFS_DEFAULT_MAJOR; + mi->version.minor = NFS_DEFAULT_MINOR; } /* @@ -315,9 +330,12 @@ static int nfs_set_version(struct nfsmount_info *mi) if (!nfs_nfs_version(mi->options, &mi->version)) return 0; - if (strncmp(mi->type, "nfs4", 4) == 0) - mi->version.major = 4; - + if (strncmp(mi->type, "nfs4", 4) == 0) { + /* Set to default values */ + mi->version.major = NFS_DEFAULT_MAJOR; + mi->version.minor = NFS_DEFAULT_MINOR; + mi->version.v_mode = V_GENERAL; + } /* * Before 2.6.32, the kernel NFS client didn't * support "-t nfs vers=4" mounts, so NFS version @@ -517,6 +535,10 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options, int checkv4) unsigned long protocol; struct pmap mnt_pmap; + /* initialize structs */ + memset(&nfs_pmap, 0, sizeof(struct pmap)); + memset(&mnt_pmap, 0, sizeof(struct pmap)); + /* * Version and transport negotiation is not required * and does not work for RDMA mounts. @@ -727,13 +749,9 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi, } if (mi->version.v_mode != V_SPECIFIC) { - if (mi->version.v_mode == V_GENERAL) - snprintf(version_opt, sizeof(version_opt) - 1, - "vers=%lu", mi->version.major); - else - snprintf(version_opt, sizeof(version_opt) - 1, - "vers=%lu.%lu", mi->version.major, - mi->version.minor); + snprintf(version_opt, sizeof(version_opt) - 1, + "vers=%lu.%lu", mi->version.major, + mi->version.minor); if (po_append(options, version_opt) == PO_FAILED) { errno = EINVAL; @@ -834,9 +852,6 @@ check_result: case EINVAL: /* A less clear indication that our client * does not support NFSv4 minor version. */ - if (mi->version.v_mode == V_GENERAL && - mi->version.minor == 0) - return result; if (mi->version.v_mode != V_SPECIFIC) { if (mi->version.minor > 0) { mi->version.minor--; @@ -858,19 +873,28 @@ check_result: /* UDP-Only servers won't support v4, but maybe it * just isn't ready yet. So try v3, but double-check * with rpcbind for v4. */ + if (mi->version.v_mode == V_GENERAL) + /* Mustn't try v2,v3 */ + return result; result = nfs_try_mount_v3v2(mi, TRUE); if (result == 0 && errno == EAGAIN) { /* v4 server seems to be registered now. */ result = nfs_try_mount_v4(mi); if (result == 0 && errno != ECONNREFUSED) goto check_result; - } + } else if (result == 0) + /* Restore original errno with v3 failures */ + errno = ECONNREFUSED; + return result; default: return result; } fall_back: + if (mi->version.v_mode == V_GENERAL) + /* v2,3 fallback not allowed */ + return result; return nfs_try_mount_v3v2(mi, FALSE); } diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c index d065830..8299256 100644 --- a/utils/mountd/auth.c +++ b/utils/mountd/auth.c @@ -41,6 +41,8 @@ static nfs_client my_client; extern int use_ipaddr; +extern struct state_paths etab; + void auth_init(void) { @@ -84,10 +86,10 @@ auth_reload() static unsigned int counter; int fd; - if ((fd = open(_PATH_ETAB, O_RDONLY)) < 0) { - xlog(L_FATAL, "couldn't open %s", _PATH_ETAB); + if ((fd = open(etab.statefn, O_RDONLY)) < 0) { + xlog(L_FATAL, "couldn't open %s", etab.statefn); } else if (fstat(fd, &stb) < 0) { - xlog(L_FATAL, "couldn't stat %s", _PATH_ETAB); + xlog(L_FATAL, "couldn't stat %s", etab.statefn); close(fd); } else if (last_fd != -1 && stb.st_ino == last_inode) { /* We opened the etab file before, and its inode diff --git a/utils/mountd/mountd.c b/utils/mountd/mountd.c index 61699e6..829f803 100644 --- a/utils/mountd/mountd.c +++ b/utils/mountd/mountd.c @@ -29,6 +29,7 @@ #include "mountd.h" #include "rpcmisc.h" #include "pseudoflavors.h" +#include "nfslib.h" extern void my_svc_run(void); @@ -40,7 +41,8 @@ int reverse_resolve = 0; int manage_gids; int use_ipaddr = -1; -char *conf_path = NFS_CONFFILE; +struct state_paths etab; +struct state_paths rmtab; /* PRC: a high-availability callout program can be specified with -H * When this is done, the program will receive callouts whenever clients @@ -110,8 +112,8 @@ unregister_services (void) static void cleanup_lockfiles (void) { - unlink(_PATH_ETABLCK); - unlink(_PATH_RMTABLCK); + unlink(etab.lockfn); + unlink(rmtab.lockfn); } /* Wait for all worker child processes to exit and reap them */ @@ -181,6 +183,8 @@ fork_workers(void) wait_for_workers(); unregister_services(); cleanup_lockfiles(); + free_state_path_names(&etab); + free_state_path_names(&rmtab); xlog(L_NOTICE, "mountd: no more workers, exiting\n"); exit(0); } @@ -198,6 +202,8 @@ killer (int sig) wait_for_workers(); } cleanup_lockfiles(); + free_state_path_names(&etab); + free_state_path_names(&rmtab); xlog (L_NOTICE, "Caught signal %d, un-registering and exiting.", sig); exit(0); } @@ -656,7 +662,6 @@ get_exportlist(void) int main(int argc, char **argv) { - char *state_dir = NFS_STATEDIR; char *progname; char *s; unsigned int listeners = 0; @@ -674,7 +679,7 @@ main(int argc, char **argv) else progname = argv[0]; - conf_init(); + conf_init(NFS_CONFFILE); xlog_from_conffile("mountd"); manage_gids = conf_get_bool("mountd", "manage-gids", manage_gids); descriptors = conf_get_num("mountd", "descriptors", descriptors); @@ -684,8 +689,8 @@ main(int argc, char **argv) ha_callout_prog = conf_get_str("mountd", "ha-callout"); s = conf_get_str("mountd", "state-directory-path"); - if (s) - state_dir = s; + if (s && !state_setup_basedir(argv[0], s)) + exit(1); /* NOTE: following uses "nfsd" section of nfs.conf !!!! */ if (conf_get_bool("nfsd", "udp", NFSCTL_UDPISSET(_rpcprotobits))) @@ -758,7 +763,8 @@ main(int argc, char **argv) reverse_resolve = 1; break; case 's': - state_dir = xstrdup(optarg); + if (!state_setup_basedir(argv[0], optarg)) + exit(1); break; case 't': num_threads = atoi (optarg); @@ -790,11 +796,10 @@ main(int argc, char **argv) fprintf(stderr, "%s: No protocol versions specified!\n", progname); usage(progname, 1); } - if (chdir(state_dir)) { - fprintf(stderr, "%s: chdir(%s) failed: %s\n", - progname, state_dir, strerror(errno)); - exit(1); - } + if (!setup_state_path_names(progname, ETAB, ETABTMP, ETABLCK, &etab)) + return 1; + if (!setup_state_path_names(progname, RMTAB, RMTABTMP, RMTABLCK, &rmtab)) + return 1; if (getrlimit (RLIMIT_NOFILE, &rlim) != 0) fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n", @@ -888,6 +893,8 @@ main(int argc, char **argv) xlog(L_ERROR, "RPC service loop terminated unexpectedly. Exiting...\n"); unregister_services(); + free_state_path_names(&etab); + free_state_path_names(&rmtab); exit(1); } diff --git a/utils/mountd/mountd.man b/utils/mountd/mountd.man index 9f0a51f..9978afc 100644 --- a/utils/mountd/mountd.man +++ b/utils/mountd/mountd.man @@ -144,7 +144,7 @@ Instead, mount the nfsd filesystem on .IR /proc/fs/nfsd . .TP .BI "\-s," "" " \-\-state\-directory\-path " directory -Specify a directory in which to place statd state information. +Specify a directory in which to place state information (etab and rmtab). If this option is not specified the default of .I /var/lib/nfs is used. diff --git a/utils/mountd/rmtab.c b/utils/mountd/rmtab.c index 527377f..3ae0dbb 100644 --- a/utils/mountd/rmtab.c +++ b/utils/mountd/rmtab.c @@ -28,6 +28,8 @@ extern int reverse_resolve; +extern struct state_paths rmtab; + /* If new path is a link do not destroy it but place the * file where the link points. */ @@ -59,7 +61,7 @@ mountlist_add(char *host, const char *path) int lockid; long pos; - if ((lockid = xflock(_PATH_RMTABLCK, "a")) < 0) + if ((lockid = xflock(rmtab.lockfn, "a")) < 0) return; setrmtabent("r+"); while ((rep = getrmtabent(1, &pos)) != NULL) { @@ -99,13 +101,13 @@ mountlist_del(char *hname, const char *path) int lockid; int match; - if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0) + if ((lockid = xflock(rmtab.lockfn, "w")) < 0) return; if (!setrmtabent("r")) { xfunlock(lockid); return; } - if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) { + if (!(fp = fsetrmtabent(rmtab.tmpfn, "w"))) { endrmtabent(); xfunlock(lockid); return; @@ -121,9 +123,9 @@ mountlist_del(char *hname, const char *path) if (!match || rep->r_count) fputrmtabent(fp, rep, NULL); } - if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) { + if (slink_safe_rename(rmtab.tmpfn, rmtab.statefn) < 0) { xlog(L_ERROR, "couldn't rename %s to %s", - _PATH_RMTABTMP, _PATH_RMTAB); + rmtab.tmpfn, rmtab.statefn); } endrmtabent(); /* close & unlink */ fendrmtabent(fp); @@ -138,7 +140,7 @@ mountlist_del_all(const struct sockaddr *sap) FILE *fp; int lockid; - if ((lockid = xflock(_PATH_RMTABLCK, "w")) < 0) + if ((lockid = xflock(rmtab.lockfn, "w")) < 0) return; hostname = host_canonname(sap); if (hostname == NULL) { @@ -151,7 +153,7 @@ mountlist_del_all(const struct sockaddr *sap) if (!setrmtabent("r")) goto out_free; - if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) + if (!(fp = fsetrmtabent(rmtab.tmpfn, "w"))) goto out_close; while ((rep = getrmtabent(1, NULL)) != NULL) { @@ -160,9 +162,9 @@ mountlist_del_all(const struct sockaddr *sap) continue; fputrmtabent(fp, rep, NULL); } - if (slink_safe_rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) { + if (slink_safe_rename(rmtab.tmpfn, rmtab.statefn) < 0) { xlog(L_ERROR, "couldn't rename %s to %s", - _PATH_RMTABTMP, _PATH_RMTAB); + rmtab.tmpfn, rmtab.statefn); } fendrmtabent(fp); out_close: @@ -195,11 +197,11 @@ mountlist_list(void) struct stat stb; int lockid; - if ((lockid = xflock(_PATH_RMTABLCK, "r")) < 0) + if ((lockid = xflock(rmtab.lockfn, "r")) < 0) return NULL; - if (stat(_PATH_RMTAB, &stb) < 0) { + if (stat(rmtab.statefn, &stb) < 0) { xlog(L_ERROR, "can't stat %s: %s", - _PATH_RMTAB, strerror(errno)); + rmtab.statefn, strerror(errno)); xfunlock(lockid); return NULL; } diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c index 20f4b79..2b38249 100644 --- a/utils/nfsd/nfsd.c +++ b/utils/nfsd/nfsd.c @@ -34,8 +34,6 @@ #define NFSD_NPROC 8 #endif -char *conf_path = NFS_CONFFILE; - static void usage(const char *); static struct option longopts[] = @@ -44,7 +42,9 @@ static struct option longopts[] = { "help", 0, 0, 'h' }, { "no-nfs-version", 1, 0, 'N' }, { "nfs-version", 1, 0, 'V' }, + { "tcp", 0, 0, 't' }, { "no-tcp", 0, 0, 'T' }, + { "udp", 0, 0, 'u' }, { "no-udp", 0, 0, 'U' }, { "port", 1, 0, 'P' }, { "port", 1, 0, 'p' }, @@ -67,8 +67,9 @@ main(int argc, char **argv) int socket_up = 0; unsigned int minorvers = 0; unsigned int minorversset = 0; + unsigned int minormask = 0; unsigned int versbits = NFSCTL_VERDEFAULT; - unsigned int protobits = NFSCTL_ALLBITS; + unsigned int protobits = NFSCTL_PROTODEFAULT; int grace = -1; int lease = -1; @@ -79,7 +80,7 @@ main(int argc, char **argv) xlog_syslog(0); xlog_stderr(1); - conf_init(); + conf_init(NFS_CONFFILE); xlog_from_conffile("nfsd"); count = conf_get_num("nfsd", "threads", count); grace = conf_get_num("nfsd", "grace-time", grace); @@ -104,10 +105,16 @@ main(int argc, char **argv) else NFSCTL_VERUNSET(versbits, i); } + + nfssvc_get_minormask(&minormask); /* We assume the kernel will default all minor versions to 'on', * and allow the config file to disable some. */ - for (i = NFS4_MINMINOR; i <= NFS4_MAXMINOR; i++) { + if (NFSCTL_VERISSET(versbits, 4)) { + NFSCTL_MINORSET(minorversset, 0); + NFSCTL_MINORSET(minorvers, 0); + } + for (i = 1; i <= NFS4_MAXMINOR; i++) { char tag[20]; sprintf(tag, "vers4.%d", i); /* The default for minor version support is to let the @@ -119,12 +126,12 @@ main(int argc, char **argv) * (i.e. don't set the bit in minorversset). */ if (!conf_get_bool("nfsd", tag, 1)) { - NFSCTL_VERSET(minorversset, i); - NFSCTL_VERUNSET(minorvers, i); + NFSCTL_MINORSET(minorversset, i); + NFSCTL_MINORUNSET(minorvers, i); } if (conf_get_bool("nfsd", tag, 0)) { - NFSCTL_VERSET(minorversset, i); - NFSCTL_VERSET(minorvers, i); + NFSCTL_MINORSET(minorversset, i); + NFSCTL_MINORSET(minorvers, i); } } @@ -138,7 +145,7 @@ main(int argc, char **argv) } } - while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:sTUrG:L:", longopts, NULL)) != EOF) { + while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:stTituUrG:L:", longopts, NULL)) != EOF) { switch(c) { case 'd': xlog_config(D_ALL, 1); @@ -179,13 +186,17 @@ main(int argc, char **argv) case 4: if (*p == '.') { int i = atoi(p+1); - if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) { + if (i < 0 || i > NFS4_MAXMINOR) { fprintf(stderr, "%s: unsupported minor version\n", optarg); exit(1); } - NFSCTL_VERSET(minorversset, i); - NFSCTL_VERUNSET(minorvers, i); - break; + NFSCTL_MINORSET(minorversset, i); + NFSCTL_MINORUNSET(minorvers, i); + if (minorvers != 0) + break; + } else { + minorvers = 0; + minorversset = minormask; } case 3: case 2: @@ -201,14 +212,14 @@ main(int argc, char **argv) case 4: if (*p == '.') { int i = atoi(p+1); - if (i < NFS4_MINMINOR || i > NFS4_MAXMINOR) { + if (i < 0 || i > NFS4_MAXMINOR) { fprintf(stderr, "%s: unsupported minor version\n", optarg); exit(1); } - NFSCTL_VERSET(minorversset, i); - NFSCTL_VERSET(minorvers, i); - break; - } + NFSCTL_MINORSET(minorversset, i); + NFSCTL_MINORSET(minorvers, i); + } else + minorvers = minorversset = minormask; case 3: case 2: NFSCTL_VERSET(versbits, c); @@ -222,9 +233,15 @@ main(int argc, char **argv) xlog_syslog(1); xlog_stderr(0); break; + case 't': + NFSCTL_TCPSET(protobits); + break; case 'T': NFSCTL_TCPUNSET(protobits); break; + case 'u': + NFSCTL_UDPSET(protobits); + break; case 'U': NFSCTL_UDPUNSET(protobits); break; @@ -372,9 +389,9 @@ usage(const char *prog) { fprintf(stderr, "Usage:\n" "%s [-d|--debug] [-H hostname] [-p|-P|--port port]\n" - " [-N|--no-nfs-version version] [-V|--nfs-version version]\n" - " [-s|--syslog] [-T|--no-tcp] [-U|--no-udp] [-r|--rdma=]\n" - " [-G|--grace-time secs] [-L|--leasetime secs] nrservs\n", + " [-N|--no-nfs-version version] [-V|--nfs-version version]\n" + " [-s|--syslog] [-t|--tcp] [-T|--no-tcp] [-u|--udp] [-U|--no-udp]\n" + " [-r|--rdma=] [-G|--grace-time secs] [-L|--leasetime secs] nrservs\n", prog); exit(2); } diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man index 8901fb6..d83ef86 100644 --- a/utils/nfsd/nfsd.man +++ b/utils/nfsd/nfsd.man @@ -57,7 +57,7 @@ This option can be used to request that .B rpc.nfsd does not offer certain versions of NFS. The current version of .B rpc.nfsd -can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2. +can support major NFS versions 2,3,4 and the minor versions 4.0, 4.1 and 4.2. .TP .B \-s " or " \-\-syslog By default, @@ -67,22 +67,24 @@ logs error messages (and debug messages, if enabled) to stderr. This option make log these messages to syslog instead. Note that errors encountered during option processing will still be logged to stderr regardless of this option. .TP +.B \-t " or " \-\-tcp +Instruct the kernel nfs server to open and listen on a TCP socket. This is the default. +.TP .B \-T " or " \-\-no-tcp -Disable -.B rpc.nfsd -from accepting TCP connections from clients. +Instruct the kernel nfs server not to open and listen on a TCP socket. +.TP +.B \-u " or " \-\-udp +Instruct the kernel nfs server to open and listen on a UDP socket. .TP .B \-U " or " \-\-no-udp -Disable -.B rpc.nfsd -from accepting UDP connections from clients. +Instruct the kernel nfs server not to open and listen on a UDP socket. This is the default. .TP .B \-V " or " \-\-nfs-version vers This option can be used to request that .B rpc.nfsd offer certain versions of NFS. The current version of .B rpc.nfsd -can support major NFS versions 2,3,4 and the minor versions 4.1 and 4.2. +can support major NFS versions 2,3,4 and the minor versions 4.0, 4.1 and 4.2. .TP .B \-L " or " \-\-lease-time seconds Set the lease-time used for NFSv4. This corresponds to how often diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c index 07f6ff1..e8609c1 100644 --- a/utils/nfsd/nfssvc.c +++ b/utils/nfsd/nfssvc.c @@ -330,36 +330,78 @@ nfssvc_set_time(const char *type, const int seconds) } void +nfssvc_get_minormask(unsigned int *mask) +{ + int fd; + char *ptr = buf; + ssize_t size; + + fd = open(NFSD_VERS_FILE, O_RDONLY); + if (fd < 0) + return; + + size = read(fd, buf, sizeof(buf)); + if (size < 0) { + xlog(L_ERROR, "Getting versions failed: errno %d (%m)", errno); + goto out; + } + ptr[size] = '\0'; + for (;;) { + unsigned vers, minor = 0; + char *token = strtok(ptr, " "); + + if (!token) + break; + ptr = NULL; + if (*token != '+' && *token != '-') + continue; + if (sscanf(++token, "%u.%u", &vers, &minor) > 0 && + vers == 4 && minor <= NFS4_MAXMINOR) + NFSCTL_MINORSET(*mask, minor); + } +out: + close(fd); + return; +} + +static int +nfssvc_print_vers(char *ptr, unsigned size, unsigned vers, unsigned minorvers, + int isset) +{ + char sign = isset ? '+' : '-'; + if (minorvers == 0) + return snprintf(ptr, size, "%c%u ", sign, vers); + return snprintf(ptr, size, "%c%u.%u ", sign, vers, minorvers); +} + +void nfssvc_setvers(unsigned int ctlbits, unsigned int minorvers, unsigned int minorversset) { int fd, n, off; - char *ptr; - ptr = buf; off = 0; fd = open(NFSD_VERS_FILE, O_WRONLY); if (fd < 0) return; - for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) { - if (NFSCTL_VERISSET(minorversset, n)) { - if (NFSCTL_VERISSET(minorvers, n)) - off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n); - else - off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n); - } - } - for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { - if (NFSCTL_VERISSET(ctlbits, n)) - off += snprintf(ptr+off, sizeof(buf) - off, "+%d ", n); - else - off += snprintf(ptr+off, sizeof(buf) - off, "-%d ", n); + for (n = NFSD_MINVERS; n <= ((NFSD_MAXVERS < 3) ? NFSD_MAXVERS : 3); n++) + off += nfssvc_print_vers(&buf[off], sizeof(buf) - off, + n, 0, NFSCTL_VERISSET(ctlbits, n)); + + for (n = 0; n <= NFS4_MAXMINOR; n++) { + if (!NFSCTL_MINORISSET(minorversset, n)) + continue; + off += nfssvc_print_vers(&buf[off], sizeof(buf) - off, + 4, n, NFSCTL_MINORISSET(minorvers, n)); } + if (!off--) + goto out; + buf[off] = '\0'; xlog(D_GENERAL, "Writing version string to kernel: %s", buf); - snprintf(ptr+off, sizeof(buf) - off, "\n"); + snprintf(&buf[off], sizeof(buf) - off, "\n"); if (write(fd, buf, strlen(buf)) != (ssize_t)strlen(buf)) xlog(L_ERROR, "Setting version failed: errno %d (%m)", errno); - +out: close(fd); return; diff --git a/utils/nfsd/nfssvc.h b/utils/nfsd/nfssvc.h index cd5a7e8..39ebf37 100644 --- a/utils/nfsd/nfssvc.h +++ b/utils/nfsd/nfssvc.h @@ -28,3 +28,4 @@ void nfssvc_set_time(const char *type, const int seconds); int nfssvc_set_rdmaport(const char *port); void nfssvc_setvers(unsigned int ctlbits, unsigned int minorvers4, unsigned int minorvers4set); int nfssvc_threads(int nrservs); +void nfssvc_get_minormask(unsigned int *mask); diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c index 7af9efb..124c923 100644 --- a/utils/nfsdcltrack/nfsdcltrack.c +++ b/utils/nfsdcltrack/nfsdcltrack.c @@ -56,8 +56,6 @@ /* defined by RFC 3530 */ #define NFS4_OPAQUE_LIMIT 1024 -char *conf_path = NFS_CONFFILE; - /* private data structures */ struct cltrack_cmd { char *name; @@ -566,7 +564,7 @@ main(int argc, char **argv) xlog_syslog(1); xlog_stderr(0); - conf_init(); + conf_init(NFS_CONFFILE); xlog_from_conffile("nfsdcltrack"); val = conf_get_str("nfsdcltrack", "storagedir"); if (val) diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c index 54cd748..1552eba 100644 --- a/utils/nfsdcltrack/sqlite.c +++ b/utils/nfsdcltrack/sqlite.c @@ -101,7 +101,7 @@ sqlite_query_schema_version(void) "SELECT value FROM parameters WHERE key == \"version\";", -1, &stmt, NULL); if (ret != SQLITE_OK) { - xlog(L_ERROR, "Unable to prepare select statement: %s", + xlog(D_GENERAL, "Unable to prepare select statement: %s", sqlite3_errmsg(dbh)); ret = 0; goto out; @@ -110,7 +110,7 @@ sqlite_query_schema_version(void) /* query schema version */ ret = sqlite3_step(stmt); if (ret != SQLITE_ROW) { - xlog(L_ERROR, "Select statement execution failed: %s", + xlog(D_GENERAL, "Select statement execution failed: %s", sqlite3_errmsg(dbh)); ret = 0; goto out; diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am index 152b680..ea32075 100644 --- a/utils/statd/Makefile.am +++ b/utils/statd/Makefile.am @@ -18,6 +18,7 @@ statd_LDADD = ../../support/nsm/libnsm.a \ $(LIBWRAP) $(LIBNSL) $(LIBCAP) $(LIBTIRPC) sm_notify_LDADD = ../../support/nsm/libnsm.a \ ../../support/nfs/libnfs.a \ + ../../support/misc/libmisc.a \ $(LIBNSL) $(LIBCAP) $(LIBTIRPC) EXTRA_DIST = sim_sm_inter.x $(man8_MANS) simulate.c diff --git a/utils/statd/sm-notify.c b/utils/statd/sm-notify.c index 623213e..d216ddb 100644 --- a/utils/statd/sm-notify.c +++ b/utils/statd/sm-notify.c @@ -45,6 +45,8 @@ #define NLM_END_GRACE_FILE "/proc/fs/lockd/nlm_end_grace" +int lift_grace = 1; + struct nsm_host { struct nsm_host * next; char * name; @@ -67,7 +69,6 @@ static _Bool opt_update_state = true; static unsigned int opt_max_retry = 15 * 60; static char * opt_srcaddr = NULL; static char * opt_srcport = NULL; -char * conf_path = NFS_CONFFILE; static void notify(const int sock); static int notify_host(int, struct nsm_host *); @@ -489,11 +490,12 @@ main(int argc, char **argv) else progname = argv[0]; - conf_init(); + conf_init(NFS_CONFFILE); xlog_from_conffile("sm-notify"); opt_max_retry = conf_get_num("sm-notify", "retry-time", opt_max_retry / 60) * 60; opt_srcport = conf_get_str("sm-notify", "outgoing-port"); opt_srcaddr = conf_get_str("sm-notify", "outgoing-addr"); + lift_grace = conf_get_bool("sm-notify", "lift-grace", lift_grace); s = conf_get_str("statd", "state-directory-path"); if (s && !nsm_setup_pathnames(argv[0], s)) exit(1); @@ -570,7 +572,8 @@ usage: fprintf(stderr, (void)nsm_retire_monitored_hosts(); if (nsm_load_notify_list(smn_get_host) == 0) { xlog(D_GENERAL, "No hosts to notify; exiting"); - nsm_lift_grace_period(); + if (lift_grace) + nsm_lift_grace_period(); return 0; } diff --git a/utils/statd/sm-notify.man b/utils/statd/sm-notify.man index bb7f6e0..cfe1e4b 100644 --- a/utils/statd/sm-notify.man +++ b/utils/statd/sm-notify.man @@ -241,6 +241,24 @@ These have the same effect as the command line options .B v respectively. +An additional value recognized in the +.B [sm-notify] +section is +.BR lift-grace . +By default, +.B sm-notify +will lift lockd's grace period early if it has no hosts to notify. +Some high availability configurations will run one +.B sm-notify +per floating IP address. In these configurations, lifting the +grace period early may prevent clients from reclaiming locks. +.RB "Setting " lift-grace " to " n +will prevent +.B sm-notify +from ending the grace period early. +.B lift-grace +has no corresponding command line option. + The value recognized in the .B [statd] section is diff --git a/utils/statd/statd.c b/utils/statd/statd.c index d333b29..1443715 100644 --- a/utils/statd/statd.c +++ b/utils/statd/statd.c @@ -37,7 +37,6 @@ #include int run_mode = 0; /* foreground logging mode */ -char *conf_path = NFS_CONFFILE; /* LH - I had these local to main, but it seemed silly to have * two copies of each - one in main(), one static in log.c... @@ -274,7 +273,7 @@ int main (int argc, char **argv) /* Set hostname */ MY_NAME = NULL; - conf_init(); + conf_init(NFS_CONFFILE); xlog_from_conffile("statd"); out_port = conf_get_num("statd", "outgoing-port", out_port); port = conf_get_num("statd", "port", port);