Changeset View
Standalone View
usr.sbin/mountd/mountd.c
Show First 20 Lines • Show All 114 Lines • ▼ Show 20 Lines | |||||
struct exportlist { | struct exportlist { | ||||
struct dirlist *ex_dirl; | struct dirlist *ex_dirl; | ||||
struct dirlist *ex_defdir; | struct dirlist *ex_defdir; | ||||
struct grouplist *ex_grphead; | struct grouplist *ex_grphead; | ||||
int ex_flag; | int ex_flag; | ||||
fsid_t ex_fs; | fsid_t ex_fs; | ||||
char *ex_fsdir; | char *ex_fsdir; | ||||
char *ex_indexfile; | char *ex_indexfile; | ||||
struct xucred ex_defanon; | |||||
int ex_defexflags; | |||||
int ex_numsecflavors; | int ex_numsecflavors; | ||||
int ex_secflavors[MAXSECFLAVORS]; | int ex_secflavors[MAXSECFLAVORS]; | ||||
int ex_defnumsecflavors; | int ex_defnumsecflavors; | ||||
int ex_defsecflavors[MAXSECFLAVORS]; | int ex_defsecflavors[MAXSECFLAVORS]; | ||||
SLIST_ENTRY(exportlist) entries; | SLIST_ENTRY(exportlist) entries; | ||||
}; | }; | ||||
/* ex_flag bits */ | /* ex_flag bits */ | ||||
#define EX_LINKED 0x1 | #define EX_LINKED 0x1 | ||||
#define EX_DONE 0x2 | |||||
#define EX_DEFSET 0x4 | |||||
#define EX_PUBLICFH 0x8 | |||||
SLIST_HEAD(exportlisthead, exportlist); | SLIST_HEAD(exportlisthead, exportlist); | ||||
struct netmsk { | struct netmsk { | ||||
struct sockaddr_storage nt_net; | struct sockaddr_storage nt_net; | ||||
struct sockaddr_storage nt_mask; | struct sockaddr_storage nt_mask; | ||||
char *nt_name; | char *nt_name; | ||||
}; | }; | ||||
union grouptypes { | union grouptypes { | ||||
struct addrinfo *gt_addrinfo; | struct addrinfo *gt_addrinfo; | ||||
struct netmsk gt_net; | struct netmsk gt_net; | ||||
}; | }; | ||||
struct grouplist { | struct grouplist { | ||||
int gr_type; | int gr_type; | ||||
union grouptypes gr_ptr; | union grouptypes gr_ptr; | ||||
struct grouplist *gr_next; | struct grouplist *gr_next; | ||||
struct xucred gr_anon; | |||||
int gr_exflags; | |||||
int gr_flag; | |||||
int gr_numsecflavors; | int gr_numsecflavors; | ||||
int gr_secflavors[MAXSECFLAVORS]; | int gr_secflavors[MAXSECFLAVORS]; | ||||
}; | }; | ||||
/* Group types */ | /* Group types */ | ||||
#define GT_NULL 0x0 | #define GT_NULL 0x0 | ||||
#define GT_HOST 0x1 | #define GT_HOST 0x1 | ||||
#define GT_NET 0x2 | #define GT_NET 0x2 | ||||
#define GT_DEFAULT 0x3 | #define GT_DEFAULT 0x3 | ||||
#define GT_IGNORE 0x5 | #define GT_IGNORE 0x5 | ||||
/* Group flags */ | |||||
#define GR_FND 0x1 | |||||
struct hostlist { | struct hostlist { | ||||
int ht_flag; /* Uses DP_xx bits */ | int ht_flag; /* Uses DP_xx bits */ | ||||
struct grouplist *ht_grp; | struct grouplist *ht_grp; | ||||
struct hostlist *ht_next; | struct hostlist *ht_next; | ||||
}; | }; | ||||
struct fhreturn { | struct fhreturn { | ||||
int fhr_flag; | int fhr_flag; | ||||
int fhr_vers; | int fhr_vers; | ||||
nfsfh_t fhr_fh; | nfsfh_t fhr_fh; | ||||
int fhr_numsecflavors; | int fhr_numsecflavors; | ||||
int *fhr_secflavors; | int *fhr_secflavors; | ||||
}; | }; | ||||
#define GETPORT_MAXTRY 20 /* Max tries to get a port # */ | #define GETPORT_MAXTRY 20 /* Max tries to get a port # */ | ||||
/* Global defs */ | /* Global defs */ | ||||
static char *add_expdir(struct dirlist **, char *, int); | static char *add_expdir(struct dirlist **, char *, int); | ||||
static void add_dlist(struct dirlist **, struct dirlist *, | static void add_dlist(struct dirlist **, struct dirlist *, | ||||
struct grouplist *, int, struct exportlist *); | struct grouplist *, int, struct exportlist *, | ||||
struct xucred *, int); | |||||
static void add_mlist(char *, char *); | static void add_mlist(char *, char *); | ||||
static int check_dirpath(char *); | static int check_dirpath(char *); | ||||
static int check_options(struct dirlist *); | static int check_options(struct dirlist *); | ||||
static int checkmask(struct sockaddr *sa); | static int checkmask(struct sockaddr *sa); | ||||
static int chk_host(struct dirlist *, struct sockaddr *, int *, int *, | static int chk_host(struct dirlist *, struct sockaddr *, int *, int *, | ||||
int *, int **); | int *, int **); | ||||
static char *strsep_quote(char **stringp, const char *delim); | static char *strsep_quote(char **stringp, const char *delim); | ||||
static int create_service(struct netconfig *nconf); | static int create_service(struct netconfig *nconf); | ||||
static void complete_service(struct netconfig *nconf, char *port_str); | static void complete_service(struct netconfig *nconf, char *port_str); | ||||
static void clearout_service(void); | static void clearout_service(void); | ||||
static void del_mlist(char *hostp, char *dirp); | static void del_mlist(char *hostp, char *dirp); | ||||
static struct dirlist *dirp_search(struct dirlist *, char *); | static struct dirlist *dirp_search(struct dirlist *, char *); | ||||
static int do_export_mount(struct exportlist *, struct statfs *); | |||||
static int do_mount(struct exportlist *, struct grouplist *, int, | static int do_mount(struct exportlist *, struct grouplist *, int, | ||||
struct xucred *, char *, int, struct statfs *); | struct xucred *, char *, int, struct statfs *, int, int *); | ||||
static int do_opt(char **, char **, struct exportlist *, | static int do_opt(char **, char **, struct exportlist *, | ||||
struct grouplist *, int *, int *, struct xucred *); | struct grouplist *, int *, int *, struct xucred *); | ||||
static struct exportlist *ex_search(fsid_t *, struct exportlisthead *); | static struct exportlist *ex_search(fsid_t *, struct exportlisthead *); | ||||
static struct exportlist *get_exp(void); | static struct exportlist *get_exp(void); | ||||
static void free_dir(struct dirlist *); | static void free_dir(struct dirlist *); | ||||
static void free_exp(struct exportlist *); | static void free_exp(struct exportlist *); | ||||
static void free_grp(struct grouplist *); | static void free_grp(struct grouplist *); | ||||
static void free_host(struct hostlist *); | static void free_host(struct hostlist *); | ||||
static void get_exportlist(void); | static void free_v4rootexp(void); | ||||
static void get_exportlist_one(int); | |||||
static void get_exportlist(int); | |||||
static void insert_exports(struct exportlist *, struct exportlisthead *); | static void insert_exports(struct exportlist *, struct exportlisthead *); | ||||
static void free_exports(struct exportlisthead *); | static void free_exports(struct exportlisthead *); | ||||
static void read_exportfile(void); | static void read_exportfile(int); | ||||
static int compare_nmount_exportlist(struct iovec *, int, char *); | |||||
static int compare_export(struct exportlist *, struct exportlist *); | |||||
static int compare_cred(struct xucred *, struct xucred *); | |||||
static int compare_secflavor(int *, int *, int); | |||||
static void delete_export(struct iovec *, int, struct statfs *, char *); | static void delete_export(struct iovec *, int, struct statfs *, char *); | ||||
static int get_host(char *, struct grouplist *, struct grouplist *); | static int get_host(char *, struct grouplist *, struct grouplist *); | ||||
static struct hostlist *get_ht(void); | static struct hostlist *get_ht(void); | ||||
static int get_line(void); | static int get_line(void); | ||||
static void get_mountlist(void); | static void get_mountlist(void); | ||||
static int get_net(char *, struct netmsk *, int); | static int get_net(char *, struct netmsk *, int); | ||||
static void getexp_err(struct exportlist *, struct grouplist *, const char *); | static void getexp_err(struct exportlist *, struct grouplist *, const char *); | ||||
static struct grouplist *get_grp(void); | static struct grouplist *get_grp(void); | ||||
static void hang_dirp(struct dirlist *, struct grouplist *, | static void hang_dirp(struct dirlist *, struct grouplist *, | ||||
struct exportlist *, int); | struct exportlist *, int, struct xucred *, int); | ||||
static void huphandler(int sig); | static void huphandler(int sig); | ||||
static int makemask(struct sockaddr_storage *ssp, int bitlen); | static int makemask(struct sockaddr_storage *ssp, int bitlen); | ||||
static void mntsrv(struct svc_req *, SVCXPRT *); | static void mntsrv(struct svc_req *, SVCXPRT *); | ||||
static void nextfield(char **, char **); | static void nextfield(char **, char **); | ||||
static void out_of_mem(void); | static void out_of_mem(void); | ||||
static void parsecred(char *, struct xucred *); | static void parsecred(char *, struct xucred *); | ||||
static int parsesec(char *, struct exportlist *); | static int parsesec(char *, struct exportlist *); | ||||
static int put_exlist(struct dirlist *, XDR *, struct dirlist *, | static int put_exlist(struct dirlist *, XDR *, struct dirlist *, | ||||
int *, int); | int *, int); | ||||
static void *sa_rawaddr(struct sockaddr *sa, int *nbytes); | static void *sa_rawaddr(struct sockaddr *sa, int *nbytes); | ||||
static int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, | static int sacmp(struct sockaddr *sa1, struct sockaddr *sa2, | ||||
struct sockaddr *samask); | struct sockaddr *samask); | ||||
static int scan_tree(struct dirlist *, struct sockaddr *); | static int scan_tree(struct dirlist *, struct sockaddr *); | ||||
static void usage(void); | static void usage(void); | ||||
static int xdr_dir(XDR *, char *); | static int xdr_dir(XDR *, char *); | ||||
static int xdr_explist(XDR *, caddr_t); | static int xdr_explist(XDR *, caddr_t); | ||||
static int xdr_explist_brief(XDR *, caddr_t); | static int xdr_explist_brief(XDR *, caddr_t); | ||||
static int xdr_explist_common(XDR *, caddr_t, int); | static int xdr_explist_common(XDR *, caddr_t, int); | ||||
static int xdr_fhs(XDR *, caddr_t); | static int xdr_fhs(XDR *, caddr_t); | ||||
static int xdr_mlist(XDR *, caddr_t); | static int xdr_mlist(XDR *, caddr_t); | ||||
static void terminate(int); | static void terminate(int); | ||||
#define EXPHASH(f) (fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize) | #define EXPHASH(f) (fnv_32_buf((f), sizeof(fsid_t), 0) % exphashsize) | ||||
static struct exportlisthead *exphead = NULL; | static struct exportlisthead *exphead = NULL; | ||||
static struct exportlisthead *oldexphead = NULL; | |||||
static int exphashsize = 0; | static int exphashsize = 0; | ||||
static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead); | static SLIST_HEAD(, mountlist) mlhead = SLIST_HEAD_INITIALIZER(&mlhead); | ||||
static char *exnames_default[2] = { _PATH_EXPORTS, NULL }; | static char *exnames_default[2] = { _PATH_EXPORTS, NULL }; | ||||
static char **exnames; | static char **exnames; | ||||
static char **hosts = NULL; | static char **hosts = NULL; | ||||
static struct xucred def_anon = { | static struct xucred def_anon = { | ||||
XUCRED_VERSION, | XUCRED_VERSION, | ||||
(uid_t)65534, | (uid_t)65534, | ||||
Show All 16 Lines | |||||
static int sock_fdpos; | static int sock_fdpos; | ||||
static int suspend_nfsd = 0; | static int suspend_nfsd = 0; | ||||
static int opt_flags; | static int opt_flags; | ||||
static int have_v6 = 1; | static int have_v6 = 1; | ||||
static int v4root_phase = 0; | static int v4root_phase = 0; | ||||
static char v4root_dirpath[PATH_MAX + 1]; | static char v4root_dirpath[PATH_MAX + 1]; | ||||
static struct exportlist *v4root_ep = NULL; | |||||
static int has_publicfh = 0; | static int has_publicfh = 0; | ||||
static int has_set_publicfh = 0; | |||||
static struct pidfh *pfh = NULL; | static struct pidfh *pfh = NULL; | ||||
/* Bits for opt_flags above */ | /* Bits for opt_flags above */ | ||||
#define OP_MAPROOT 0x01 | #define OP_MAPROOT 0x01 | ||||
#define OP_MAPALL 0x02 | #define OP_MAPALL 0x02 | ||||
/* 0x4 free */ | /* 0x4 free */ | ||||
#define OP_MASK 0x08 | #define OP_MASK 0x08 | ||||
#define OP_NET 0x10 | #define OP_NET 0x10 | ||||
#define OP_ALLDIRS 0x40 | #define OP_ALLDIRS 0x40 | ||||
#define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ | #define OP_HAVEMASK 0x80 /* A mask was specified or inferred. */ | ||||
#define OP_QUIET 0x100 | #define OP_QUIET 0x100 | ||||
#define OP_MASKLEN 0x200 | #define OP_MASKLEN 0x200 | ||||
#define OP_SEC 0x400 | #define OP_SEC 0x400 | ||||
#ifdef DEBUG | #ifdef DEBUG | ||||
static int debug = 1; | static int debug = 1; | ||||
static void SYSLOG(int, const char *, ...) __printflike(2, 3); | static void SYSLOG(int, const char *, ...) __printflike(2, 3); | ||||
#define syslog SYSLOG | #define syslog SYSLOG | ||||
#else | #else | ||||
static int debug = 0; | static int debug = 0; | ||||
#endif | #endif | ||||
/* | /* | ||||
* The LOGDEBUG() syslog() calls are always compiled into the daemon. | |||||
* To enable them, create a file at _PATH_MOUNTDDEBUG. This file can be empty. | |||||
* To disable the logging, just delete the file at _PATH_MOUNTDDEBUG. | |||||
*/ | |||||
static int logdebug = 0; | |||||
#define LOGDEBUG(format, ...) \ | |||||
(logdebug ? syslog(LOG_DEBUG, format, ## __VA_ARGS__) : 0) | |||||
/* | |||||
* Similar to strsep(), but it allows for quoted strings | * Similar to strsep(), but it allows for quoted strings | ||||
* and escaped characters. | * and escaped characters. | ||||
* | * | ||||
* It returns the string (or NULL, if *stringp is NULL), | * It returns the string (or NULL, if *stringp is NULL), | ||||
* which is a de-quoted version of the string if necessary. | * which is a de-quoted version of the string if necessary. | ||||
* | * | ||||
* It modifies *stringp in place. | * It modifies *stringp in place. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 68 Lines • ▼ Show 20 Lines | main(int argc, char **argv) | ||||
fd_set readfds; | fd_set readfds; | ||||
struct netconfig *nconf; | struct netconfig *nconf; | ||||
char *endptr, **hosts_bak; | char *endptr, **hosts_bak; | ||||
void *nc_handle; | void *nc_handle; | ||||
pid_t otherpid; | pid_t otherpid; | ||||
in_port_t svcport; | in_port_t svcport; | ||||
int c, k, s; | int c, k, s; | ||||
int maxrec = RPC_MAXDATASIZE; | int maxrec = RPC_MAXDATASIZE; | ||||
int attempt_cnt, port_len, port_pos, ret; | int attempt_cnt, passno, port_len, port_pos, ret; | ||||
char **port_list; | char **port_list; | ||||
passno = 0; | |||||
/* Check that another mountd isn't already running. */ | /* Check that another mountd isn't already running. */ | ||||
pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); | pfh = pidfile_open(_PATH_MOUNTDPID, 0600, &otherpid); | ||||
if (pfh == NULL) { | if (pfh == NULL) { | ||||
if (errno == EEXIST) | if (errno == EEXIST) | ||||
errx(1, "mountd already running, pid: %d.", otherpid); | errx(1, "mountd already running, pid: %d.", otherpid); | ||||
warn("cannot open or create pidfile"); | warn("cannot open or create pidfile"); | ||||
} | } | ||||
s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); | s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); | ||||
if (s < 0) | if (s < 0) | ||||
have_v6 = 0; | have_v6 = 0; | ||||
else | else | ||||
close(s); | close(s); | ||||
while ((c = getopt(argc, argv, "2deh:lnp:rS")) != -1) | while ((c = getopt(argc, argv, "2deh:Ilnp:rS")) != -1) | ||||
switch (c) { | switch (c) { | ||||
case '2': | case '2': | ||||
force_v2 = 1; | force_v2 = 1; | ||||
break; | break; | ||||
case 'e': | case 'e': | ||||
/* now a no-op, since this is the default */ | /* now a no-op, since this is the default */ | ||||
break; | break; | ||||
case 'n': | case 'n': | ||||
Show All 35 Lines | case 'h': | ||||
free(hosts[k]); | free(hosts[k]); | ||||
free(hosts); | free(hosts); | ||||
out_of_mem(); | out_of_mem(); | ||||
} | } | ||||
break; | break; | ||||
case 'S': | case 'S': | ||||
suspend_nfsd = 1; | suspend_nfsd = 1; | ||||
break; | break; | ||||
case 'I': | |||||
passno = 1; | |||||
break; | |||||
default: | default: | ||||
usage(); | usage(); | ||||
} | } | ||||
if (modfind("nfsd") < 0) { | if (modfind("nfsd") < 0) { | ||||
/* Not present in kernel, try loading it */ | /* Not present in kernel, try loading it */ | ||||
if (kldload("nfsd") < 0 || modfind("nfsd") < 0) | if (kldload("nfsd") < 0 || modfind("nfsd") < 0) | ||||
errx(1, "NFS server is not available"); | errx(1, "NFS server is not available"); | ||||
} | } | ||||
argc -= optind; | argc -= optind; | ||||
argv += optind; | argv += optind; | ||||
if (argc > 0) | if (argc > 0) | ||||
exnames = argv; | exnames = argv; | ||||
else | else | ||||
exnames = exnames_default; | exnames = exnames_default; | ||||
openlog("mountd", LOG_PID, LOG_DAEMON); | openlog("mountd", LOG_PID, LOG_DAEMON); | ||||
if (debug) | if (debug) | ||||
warnx("getting export list"); | warnx("getting export list"); | ||||
get_exportlist(); | get_exportlist(0); | ||||
if (debug) | if (debug) | ||||
warnx("getting mount list"); | warnx("getting mount list"); | ||||
get_mountlist(); | get_mountlist(); | ||||
if (debug) | if (debug) | ||||
warnx("here we go"); | warnx("here we go"); | ||||
if (debug == 0) { | if (debug == 0) { | ||||
daemon(0, 0); | daemon(0, 0); | ||||
signal(SIGINT, SIG_IGN); | signal(SIGINT, SIG_IGN); | ||||
▲ Show 20 Lines • Show All 154 Lines • ▼ Show 20 Lines | main(int argc, char **argv) | ||||
if (xcreated == 0) { | if (xcreated == 0) { | ||||
syslog(LOG_ERR, "could not create any services"); | syslog(LOG_ERR, "could not create any services"); | ||||
exit(1); | exit(1); | ||||
} | } | ||||
/* Expand svc_run() here so that we can call get_exportlist(). */ | /* Expand svc_run() here so that we can call get_exportlist(). */ | ||||
for (;;) { | for (;;) { | ||||
if (got_sighup) { | if (got_sighup) { | ||||
get_exportlist(); | get_exportlist(passno); | ||||
got_sighup = 0; | got_sighup = 0; | ||||
} | } | ||||
readfds = svc_fdset; | readfds = svc_fdset; | ||||
switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { | switch (select(svc_maxfd + 1, &readfds, NULL, NULL, NULL)) { | ||||
case -1: | case -1: | ||||
if (errno == EINTR) | if (errno == EINTR) | ||||
continue; | continue; | ||||
syslog(LOG_ERR, "mountd died: select: %m"); | syslog(LOG_ERR, "mountd died: select: %m"); | ||||
▲ Show 20 Lines • Show All 773 Lines • ▼ Show 20 Lines | |||||
static char *line; | static char *line; | ||||
static size_t linesize; | static size_t linesize; | ||||
static FILE *exp_file; | static FILE *exp_file; | ||||
/* | /* | ||||
* Get the export list from one, currently open file | * Get the export list from one, currently open file | ||||
*/ | */ | ||||
static void | static void | ||||
get_exportlist_one(void) | get_exportlist_one(int passno) | ||||
{ | { | ||||
struct exportlist *ep; | struct exportlist *ep; | ||||
struct grouplist *grp, *tgrp; | struct grouplist *grp, *tgrp, *savgrp; | ||||
struct dirlist *dirhead; | struct dirlist *dirhead; | ||||
struct statfs fsb; | struct statfs fsb; | ||||
struct xucred anon; | struct xucred anon; | ||||
char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; | char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; | ||||
int len, has_host, exflags, got_nondir, dirplen, netgrp; | int len, has_host, exflags, got_nondir, dirplen, netgrp; | ||||
v4root_phase = 0; | v4root_phase = 0; | ||||
dirhead = (struct dirlist *)NULL; | dirhead = (struct dirlist *)NULL; | ||||
▲ Show 20 Lines • Show All 217 Lines • ▼ Show 20 Lines | if (v4root_phase == 1) { | ||||
getexp_err(ep, tgrp, "V4:root, no dirp, ignored"); | getexp_err(ep, tgrp, "V4:root, no dirp, ignored"); | ||||
goto nextline; | goto nextline; | ||||
} | } | ||||
/* | /* | ||||
* Loop through hosts, pushing the exports into the kernel. | * Loop through hosts, pushing the exports into the kernel. | ||||
* After loop, tgrp points to the start of the list and | * After loop, tgrp points to the start of the list and | ||||
* grp points to the last entry in the list. | * grp points to the last entry in the list. | ||||
* Do not do the do_mount() for passno == 1, since the | |||||
* second pass will do it, as required. | |||||
*/ | */ | ||||
grp = tgrp; | grp = tgrp; | ||||
do { | do { | ||||
if (do_mount(ep, grp, exflags, &anon, dirp, dirplen, | grp->gr_exflags = exflags; | ||||
&fsb)) { | grp->gr_anon = anon; | ||||
if (v4root_phase == 2 && passno == 0) | |||||
LOGDEBUG("do_mount v4root"); | |||||
if (passno == 0 && do_mount(ep, grp, exflags, &anon, | |||||
dirp, dirplen, &fsb, ep->ex_numsecflavors, | |||||
ep->ex_secflavors)) { | |||||
getexp_err(ep, tgrp, NULL); | getexp_err(ep, tgrp, NULL); | ||||
goto nextline; | goto nextline; | ||||
} | } | ||||
} while (grp->gr_next && (grp = grp->gr_next)); | } while (grp->gr_next && (grp = grp->gr_next)); | ||||
/* | /* | ||||
* For V4: don't enter in mount lists. | * For V4: don't enter in mount lists. | ||||
*/ | */ | ||||
if (v4root_phase > 0 && v4root_phase <= 2) { | if (v4root_phase > 0 && v4root_phase <= 2) { | ||||
/* | /* | ||||
* Since these structures aren't used by mountd, | * These structures are used for the "-I" reload, | ||||
* so save them for that case. Otherwise, just | |||||
* free them up now. | * free them up now. | ||||
*/ | */ | ||||
if (passno == 1 && ep != NULL) { | |||||
savgrp = tgrp; | |||||
while (tgrp != NULL) { | |||||
/* | |||||
* Save the security flavors and exflags | |||||
* for this host set in the groups. | |||||
*/ | |||||
tgrp->gr_numsecflavors = | |||||
ep->ex_numsecflavors; | |||||
if (ep->ex_numsecflavors > 0) | |||||
memcpy(tgrp->gr_secflavors, | |||||
ep->ex_secflavors, | |||||
sizeof(ep->ex_secflavors)); | |||||
tgrp = tgrp->gr_next; | |||||
} | |||||
if (v4root_ep == NULL) { | |||||
v4root_ep = ep; | |||||
ep = NULL; /* Don't free below. */ | |||||
} | |||||
grp->gr_next = v4root_ep->ex_grphead; | |||||
v4root_ep->ex_grphead = savgrp; | |||||
} | |||||
if (ep != NULL) | if (ep != NULL) | ||||
free_exp(ep); | free_exp(ep); | ||||
while (tgrp != NULL) { | while (tgrp != NULL) { | ||||
grp = tgrp; | grp = tgrp; | ||||
tgrp = tgrp->gr_next; | tgrp = tgrp->gr_next; | ||||
free_grp(grp); | free_grp(grp); | ||||
} | } | ||||
goto nextline; | goto nextline; | ||||
} | } | ||||
/* | /* | ||||
* Success. Update the data structures. | * Success. Update the data structures. | ||||
*/ | */ | ||||
if (has_host) { | if (has_host) { | ||||
hang_dirp(dirhead, tgrp, ep, opt_flags); | hang_dirp(dirhead, tgrp, ep, opt_flags, &anon, exflags); | ||||
grp->gr_next = ep->ex_grphead; | grp->gr_next = ep->ex_grphead; | ||||
ep->ex_grphead = tgrp; | ep->ex_grphead = tgrp; | ||||
} else { | } else { | ||||
hang_dirp(dirhead, (struct grouplist *)NULL, ep, | hang_dirp(dirhead, (struct grouplist *)NULL, ep, | ||||
opt_flags); | opt_flags, &anon, exflags); | ||||
free_grp(grp); | free_grp(grp); | ||||
} | } | ||||
dirhead = (struct dirlist *)NULL; | dirhead = (struct dirlist *)NULL; | ||||
if ((ep->ex_flag & EX_LINKED) == 0) { | if ((ep->ex_flag & EX_LINKED) == 0) { | ||||
insert_exports(ep, exphead); | insert_exports(ep, exphead); | ||||
ep->ex_flag |= EX_LINKED; | ep->ex_flag |= EX_LINKED; | ||||
} | } | ||||
nextline: | nextline: | ||||
v4root_phase = 0; | v4root_phase = 0; | ||||
if (dirhead) { | if (dirhead) { | ||||
free_dir(dirhead); | free_dir(dirhead); | ||||
dirhead = (struct dirlist *)NULL; | dirhead = (struct dirlist *)NULL; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Get the export list from all specified files | * Get the export list from all specified files | ||||
*/ | */ | ||||
static void | static void | ||||
get_exportlist(void) | get_exportlist(int passno) | ||||
{ | { | ||||
struct export_args export; | struct export_args export; | ||||
struct iovec *iov; | struct iovec *iov; | ||||
struct statfs *mntbufp; | struct statfs *mntbufp; | ||||
char errmsg[255]; | char errmsg[255]; | ||||
int num, i; | int num, i; | ||||
int iovlen; | int iovlen; | ||||
struct nfsex_args eargs; | struct nfsex_args eargs; | ||||
FILE *debug_file; | |||||
if (suspend_nfsd != 0) | if ((debug_file = fopen(_PATH_MOUNTDDEBUG, "r")) != NULL) { | ||||
(void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); | fclose(debug_file); | ||||
logdebug = 1; | |||||
} else | |||||
logdebug = 0; | |||||
LOGDEBUG("passno=%d", passno); | |||||
v4root_dirpath[0] = '\0'; | v4root_dirpath[0] = '\0'; | ||||
free_v4rootexp(); | |||||
if (passno == 1) { | |||||
/* | |||||
* Save the current lists as old ones, so that the new lists | |||||
* can be compared with the old ones in the 2nd pass. | |||||
*/ | |||||
for (i = 0; i < exphashsize; i++) { | |||||
SLIST_FIRST(&oldexphead[i]) = SLIST_FIRST(&exphead[i]); | |||||
SLIST_INIT(&exphead[i]); | |||||
} | |||||
/* Note that the public fh has not yet been set. */ | |||||
has_set_publicfh = 0; | |||||
/* Read the export file(s) and process them */ | |||||
read_exportfile(passno); | |||||
} else { | |||||
/* | |||||
* Just make the old lists empty. | |||||
* exphashsize == 0 for the first call, before oldexphead | |||||
* has been initialized-->loop won't be executed. | |||||
*/ | |||||
for (i = 0; i < exphashsize; i++) | |||||
SLIST_INIT(&oldexphead[i]); | |||||
} | |||||
bzero(&export, sizeof(export)); | bzero(&export, sizeof(export)); | ||||
export.ex_flags = MNT_DELEXPORT; | export.ex_flags = MNT_DELEXPORT; | ||||
iov = NULL; | iov = NULL; | ||||
iovlen = 0; | iovlen = 0; | ||||
bzero(errmsg, sizeof(errmsg)); | bzero(errmsg, sizeof(errmsg)); | ||||
if (suspend_nfsd != 0) | |||||
(void)nfssvc(NFSSVC_SUSPENDNFSD, NULL); | |||||
/* | /* | ||||
* First, get rid of the old list | * Delete the old V4 root dir. | ||||
*/ | */ | ||||
if (exphead != NULL) | |||||
free_exports(exphead); | |||||
/* | |||||
* and the old V4 root dir. | |||||
*/ | |||||
bzero(&eargs, sizeof (eargs)); | bzero(&eargs, sizeof (eargs)); | ||||
eargs.export.ex_flags = MNT_DELEXPORT; | eargs.export.ex_flags = MNT_DELEXPORT; | ||||
if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && | if (nfssvc(NFSSVC_V4ROOTEXPORT, (caddr_t)&eargs) < 0 && | ||||
errno != ENOENT) | errno != ENOENT) | ||||
syslog(LOG_ERR, "Can't delete exports for V4:"); | syslog(LOG_ERR, "Can't delete exports for V4:"); | ||||
build_iovec(&iov, &iovlen, "fstype", NULL, 0); | |||||
build_iovec(&iov, &iovlen, "fspath", NULL, 0); | |||||
build_iovec(&iov, &iovlen, "from", NULL, 0); | |||||
build_iovec(&iov, &iovlen, "update", NULL, 0); | |||||
build_iovec(&iov, &iovlen, "export", &export, | |||||
sizeof(export)); | |||||
build_iovec(&iov, &iovlen, "errmsg", errmsg, | |||||
sizeof(errmsg)); | |||||
/* | /* | ||||
* and clear flag that notes if a public fh has been exported. | * For passno == 1, compare the old and new lists updating the kernel | ||||
* exports for any cases that have changed. | |||||
* This call is doing the second pass through the lists. | |||||
* If it fails, fall back on the bulk reload. | |||||
*/ | */ | ||||
if (passno == 1 && compare_nmount_exportlist(iov, iovlen, errmsg) == | |||||
0) { | |||||
LOGDEBUG("compareok"); | |||||
/* Free up the old lists. */ | |||||
free_exports(oldexphead); | |||||
} else { | |||||
LOGDEBUG("doing passno=0"); | |||||
/* | |||||
* Clear flag that notes if a public fh has been exported. | |||||
* It is set by do_mount() if MNT_EXPUBLIC is set for the entry. | |||||
*/ | |||||
has_publicfh = 0; | has_publicfh = 0; | ||||
/* exphead == NULL if not yet allocated (first call). */ | |||||
if (exphead != NULL) { | |||||
/* | /* | ||||
* First, get rid of the old lists. | |||||
*/ | |||||
free_exports(exphead); | |||||
free_exports(oldexphead); | |||||
} | |||||
/* | |||||
* And delete exports that are in the kernel for all local | * And delete exports that are in the kernel for all local | ||||
* filesystems. | * filesystems. | ||||
* XXX: Should know how to handle all local exportable filesystems. | * XXX: Should know how to handle all local exportable | ||||
* filesystems. | |||||
*/ | */ | ||||
num = getmntinfo(&mntbufp, MNT_NOWAIT); | num = getmntinfo(&mntbufp, MNT_NOWAIT); | ||||
/* Allocate hash tables, for first call. */ | /* Allocate hash tables, for first call. */ | ||||
if (exphead == NULL) { | if (exphead == NULL) { | ||||
/* Target an average linked list length of 10. */ | /* Target an average linked list length of 10. */ | ||||
exphashsize = num / 10; | exphashsize = num / 10; | ||||
if (exphashsize < 1) | if (exphashsize < 1) | ||||
exphashsize = 1; | exphashsize = 1; | ||||
else if (exphashsize > 100000) | else if (exphashsize > 100000) | ||||
exphashsize = 100000; | exphashsize = 100000; | ||||
exphead = malloc(exphashsize * sizeof(*exphead)); | exphead = malloc(exphashsize * sizeof(*exphead)); | ||||
if (exphead == NULL) | oldexphead = malloc(exphashsize * sizeof(*oldexphead)); | ||||
errx(1, "Can't malloc hash table"); | if (exphead == NULL || oldexphead == NULL) | ||||
errx(1, "Can't malloc hash tables"); | |||||
for (i = 0; i < exphashsize; i++) | for (i = 0; i < exphashsize; i++) { | ||||
SLIST_INIT(&exphead[i]); | SLIST_INIT(&exphead[i]); | ||||
SLIST_INIT(&oldexphead[i]); | |||||
} | } | ||||
if (num > 0) { | |||||
build_iovec(&iov, &iovlen, "fstype", NULL, 0); | |||||
build_iovec(&iov, &iovlen, "fspath", NULL, 0); | |||||
build_iovec(&iov, &iovlen, "from", NULL, 0); | |||||
build_iovec(&iov, &iovlen, "update", NULL, 0); | |||||
build_iovec(&iov, &iovlen, "export", &export, sizeof(export)); | |||||
build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); | |||||
} | } | ||||
for (i = 0; i < num; i++) | for (i = 0; i < num; i++) | ||||
delete_export(iov, iovlen, &mntbufp[i], errmsg); | delete_export(iov, iovlen, &mntbufp[i], errmsg); | ||||
/* Read the export file(s) and process them */ | |||||
read_exportfile(0); | |||||
} | |||||
if (iov != NULL) { | if (iov != NULL) { | ||||
/* Free strings allocated by strdup() in getmntopts.c */ | /* Free strings allocated by strdup() in getmntopts.c */ | ||||
free(iov[0].iov_base); /* fstype */ | free(iov[0].iov_base); /* fstype */ | ||||
free(iov[2].iov_base); /* fspath */ | free(iov[2].iov_base); /* fspath */ | ||||
free(iov[4].iov_base); /* from */ | free(iov[4].iov_base); /* from */ | ||||
free(iov[6].iov_base); /* update */ | free(iov[6].iov_base); /* update */ | ||||
free(iov[8].iov_base); /* export */ | free(iov[8].iov_base); /* export */ | ||||
free(iov[10].iov_base); /* errmsg */ | free(iov[10].iov_base); /* errmsg */ | ||||
/* free iov, allocated by realloc() */ | /* free iov, allocated by realloc() */ | ||||
free(iov); | free(iov); | ||||
iovlen = 0; | iovlen = 0; | ||||
} | } | ||||
read_exportfile(); | |||||
/* | /* | ||||
* If there was no public fh, clear any previous one set. | * If there was no public fh, clear any previous one set. | ||||
*/ | */ | ||||
if (has_publicfh == 0) | if (has_publicfh == 0) { | ||||
LOGDEBUG("clear public fh"); | |||||
(void) nfssvc(NFSSVC_NOPUBLICFH, NULL); | (void) nfssvc(NFSSVC_NOPUBLICFH, NULL); | ||||
} | |||||
/* Resume the nfsd. If they weren't suspended, this is harmless. */ | /* Resume the nfsd. If they weren't suspended, this is harmless. */ | ||||
(void)nfssvc(NFSSVC_RESUMENFSD, NULL); | (void)nfssvc(NFSSVC_RESUMENFSD, NULL); | ||||
LOGDEBUG("eo get_exportlist"); | |||||
} | } | ||||
/* | /* | ||||
* Insert an export entry in the appropriate list. | * Insert an export entry in the appropriate list. | ||||
*/ | */ | ||||
static void | static void | ||||
insert_exports(struct exportlist *ep, struct exportlisthead *exhp) | insert_exports(struct exportlist *ep, struct exportlisthead *exhp) | ||||
{ | { | ||||
uint32_t i; | uint32_t i; | ||||
i = EXPHASH(&ep->ex_fs); | i = EXPHASH(&ep->ex_fs); | ||||
LOGDEBUG("fs=%s hash=%i", ep->ex_fsdir, i); | |||||
SLIST_INSERT_HEAD(&exhp[i], ep, entries); | SLIST_INSERT_HEAD(&exhp[i], ep, entries); | ||||
} | } | ||||
/* | /* | ||||
* Free up the exports lists passed in as arguments. | * Free up the exports lists passed in as arguments. | ||||
*/ | */ | ||||
static void | static void | ||||
free_exports(struct exportlisthead *exhp) | free_exports(struct exportlisthead *exhp) | ||||
Show All 9 Lines | for (i = 0; i < exphashsize; i++) { | ||||
SLIST_INIT(&exhp[i]); | SLIST_INIT(&exhp[i]); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Read the exports file(s) and call get_exportlist_one() for each line. | * Read the exports file(s) and call get_exportlist_one() for each line. | ||||
*/ | */ | ||||
static void | static void | ||||
read_exportfile(void) | read_exportfile(int passno) | ||||
{ | { | ||||
int done, i; | int done, i; | ||||
/* | /* | ||||
* Read in the exports file and build the list, calling | * Read in the exports file and build the list, calling | ||||
* nmount() as we go along to push the export rules into the kernel. | * nmount() as we go along to push the export rules into the kernel. | ||||
*/ | */ | ||||
done = 0; | done = 0; | ||||
for (i = 0; exnames[i] != NULL; i++) { | for (i = 0; exnames[i] != NULL; i++) { | ||||
if (debug) | if (debug) | ||||
warnx("reading exports from %s", exnames[i]); | warnx("reading exports from %s", exnames[i]); | ||||
if ((exp_file = fopen(exnames[i], "r")) == NULL) { | if ((exp_file = fopen(exnames[i], "r")) == NULL) { | ||||
syslog(LOG_WARNING, "can't open %s", exnames[i]); | syslog(LOG_WARNING, "can't open %s", exnames[i]); | ||||
continue; | continue; | ||||
} | } | ||||
get_exportlist_one(); | get_exportlist_one(passno); | ||||
fclose(exp_file); | fclose(exp_file); | ||||
done++; | done++; | ||||
} | } | ||||
if (done == 0) { | if (done == 0) { | ||||
syslog(LOG_ERR, "can't open any exports file"); | syslog(LOG_ERR, "can't open any exports file"); | ||||
exit(2); | exit(2); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Compare the export lists against the old ones and do nmount() operations | |||||
* for any cases that have changed. This avoids doing nmount() for entries | |||||
* that have not changed. | |||||
* Return 0 upon success, 1 otherwise. | |||||
*/ | |||||
static int | |||||
compare_nmount_exportlist(struct iovec *iov, int iovlen, char *errmsg) | |||||
{ | |||||
struct exportlist *ep, *oep; | |||||
struct grouplist *grp; | |||||
struct statfs fs, ofs; | |||||
int i, ret; | |||||
/* | |||||
* Loop through the current list and look for an entry in the old | |||||
* list. | |||||
* If found, check to see if it the same. | |||||
* If it is not the same, delete and re-export. | |||||
* Then mark it done on the old list. | |||||
* else (not found) | |||||
* export it. | |||||
* Any entries left in the old list after processing must have their | |||||
* exports deleted. | |||||
*/ | |||||
for (i = 0; i < exphashsize; i++) | |||||
SLIST_FOREACH(ep, &exphead[i], entries) { | |||||
LOGDEBUG("foreach ep=%s", ep->ex_fsdir); | |||||
oep = ex_search(&ep->ex_fs, oldexphead); | |||||
if (oep != NULL) { | |||||
/* | |||||
* Check the mount paths are the same. | |||||
* If not, return 1 so that the reload of the | |||||
* exports will be done in bulk, the | |||||
* passno == 0 way. | |||||
*/ | |||||
LOGDEBUG("found old exp"); | |||||
if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0) | |||||
return (1); | |||||
LOGDEBUG("same fsdir"); | |||||
/* | |||||
* Test to see if the entry is the same. | |||||
* If not the same delete exports and | |||||
* re-export. | |||||
*/ | |||||
if (compare_export(ep, oep) != 0) { | |||||
/* | |||||
* Clear has_publicfh if if was set | |||||
* in the old exports, but only if it | |||||
* has not been set during processing of | |||||
* the exports for this pass, as | |||||
* indicated by has_set_publicfh. | |||||
*/ | |||||
if (has_set_publicfh == 0 && | |||||
(oep->ex_flag & EX_PUBLICFH) != 0) | |||||
has_publicfh = 0; | |||||
/* Delete and re-export. */ | |||||
if (statfs(ep->ex_fsdir, &fs) < 0) | |||||
return (1); | |||||
delete_export(iov, iovlen, &fs, errmsg); | |||||
ret = do_export_mount(ep, &fs); | |||||
if (ret != 0) | |||||
return (ret); | |||||
} | |||||
oep->ex_flag |= EX_DONE; | |||||
LOGDEBUG("exdone"); | |||||
} else { | |||||
LOGDEBUG("not found so export"); | |||||
/* Not found, so do export. */ | |||||
if (statfs(ep->ex_fsdir, &fs) < 0) | |||||
return (1); | |||||
ret = do_export_mount(ep, &fs); | |||||
if (ret != 0) | |||||
return (ret); | |||||
} | |||||
} | |||||
/* Delete exports not done. */ | |||||
for (i = 0; i < exphashsize; i++) | |||||
SLIST_FOREACH(oep, &oldexphead[i], entries) { | |||||
if ((oep->ex_flag & EX_DONE) == 0) { | |||||
LOGDEBUG("not done delete=%s", oep->ex_fsdir); | |||||
if (statfs(oep->ex_fsdir, &ofs) >= 0 && | |||||
oep->ex_fs.val[0] == ofs.f_fsid.val[0] && | |||||
oep->ex_fs.val[1] == ofs.f_fsid.val[1]) { | |||||
LOGDEBUG("do delete"); | |||||
/* | |||||
* Clear has_publicfh if if was set | |||||
* in the old exports, but only if it | |||||
* has not been set during processing of | |||||
* the exports for this pass, as | |||||
* indicated by has_set_publicfh. | |||||
*/ | |||||
if (has_set_publicfh == 0 && | |||||
(oep->ex_flag & EX_PUBLICFH) != 0) | |||||
has_publicfh = 0; | |||||
delete_export(iov, iovlen, &ofs, | |||||
errmsg); | |||||
} | |||||
} | |||||
} | |||||
/* Do the V4 root exports, as required. */ | |||||
grp = NULL; | |||||
if (v4root_ep != NULL) | |||||
grp = v4root_ep->ex_grphead; | |||||
v4root_phase = 2; | |||||
while (v4root_ep != NULL && grp != NULL) { | |||||
LOGDEBUG("v4root expath=%s", v4root_dirpath); | |||||
ret = do_mount(v4root_ep, grp, grp->gr_exflags, &grp->gr_anon, | |||||
v4root_dirpath, strlen(v4root_dirpath), &fs, | |||||
grp->gr_numsecflavors, grp->gr_secflavors); | |||||
if (ret != 0) { | |||||
v4root_phase = 0; | |||||
return (ret); | |||||
} | |||||
grp = grp->gr_next; | |||||
} | |||||
v4root_phase = 0; | |||||
free_v4rootexp(); | |||||
return (0); | |||||
} | |||||
/* | |||||
* Compare old and current exportlist entries for the fsid and return 0 | |||||
* if they are the same, 1 otherwise. | |||||
*/ | |||||
static int | |||||
compare_export(struct exportlist *ep, struct exportlist *oep) | |||||
{ | |||||
struct grouplist *grp, *ogrp; | |||||
if (strcmp(ep->ex_fsdir, oep->ex_fsdir) != 0) | |||||
return (1); | |||||
if ((ep->ex_flag & EX_DEFSET) != (oep->ex_flag & EX_DEFSET)) | |||||
return (1); | |||||
if ((ep->ex_defdir != NULL && oep->ex_defdir == NULL) || | |||||
(ep->ex_defdir == NULL && oep->ex_defdir != NULL)) | |||||
return (1); | |||||
if (ep->ex_defdir != NULL && (ep->ex_defdir->dp_flag & DP_DEFSET) != | |||||
(oep->ex_defdir->dp_flag & DP_DEFSET)) | |||||
return (1); | |||||
if ((ep->ex_flag & EX_DEFSET) != 0 && (ep->ex_defnumsecflavors != | |||||
oep->ex_defnumsecflavors || ep->ex_defexflags != | |||||
oep->ex_defexflags || compare_cred(&ep->ex_defanon, | |||||
&oep->ex_defanon) != 0 || compare_secflavor(ep->ex_defsecflavors, | |||||
oep->ex_defsecflavors, ep->ex_defnumsecflavors) != 0)) | |||||
return (1); | |||||
/* Now, check all the groups. */ | |||||
for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) | |||||
ogrp->gr_flag = 0; | |||||
for (grp = ep->ex_grphead; grp != NULL; grp = grp->gr_next) { | |||||
for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = | |||||
ogrp->gr_next) | |||||
if ((ogrp->gr_flag & GR_FND) == 0 && | |||||
grp->gr_numsecflavors == ogrp->gr_numsecflavors && | |||||
grp->gr_exflags == ogrp->gr_exflags && | |||||
compare_cred(&grp->gr_anon, &ogrp->gr_anon) == 0 && | |||||
compare_secflavor(grp->gr_secflavors, | |||||
ogrp->gr_secflavors, grp->gr_numsecflavors) == 0) | |||||
break; | |||||
if (ogrp != NULL) | |||||
ogrp->gr_flag |= GR_FND; | |||||
else | |||||
return (1); | |||||
} | |||||
for (ogrp = oep->ex_grphead; ogrp != NULL; ogrp = ogrp->gr_next) | |||||
if ((ogrp->gr_flag & GR_FND) == 0) | |||||
return (1); | |||||
return (0); | |||||
} | |||||
/* | |||||
* This algorithm compares two arrays of "n" items. It returns 0 if they are | |||||
* the "same" and 1 otherwise. Although suboptimal, it is always safe to | |||||
* return 1, which makes compare_nmount_export() reload the exports entry. | |||||
* "same" refers to having the same set of values in the two arrays. | |||||
* The arrays are in no particular order and duplicates (multiple entries | |||||
* in an array with the same value) is allowed. | |||||
* The algorithm is inefficient, but the common cases are handled first | |||||
* and "n" is normally fairly small. | |||||
* Since the two functions need the same algorithm but for arrays of | |||||
* different types (gid_t vs int), this is done as a macro. | |||||
*/ | |||||
#define COMPARE_ARRAYS(typ, a1, a2, n, maxn) \ | |||||
kib: Why do you need maxn ? If only to declare fndarray[] below, you can use fndarray[n], we are… | |||||
rmacklemAuthorUnsubmitted Done Inline ActionsSure. I wasn't sure if variable sized arrays were allowed in FreeBSD source, but since you rmacklem: Sure. I wasn't sure if variable sized arrays were allowed in FreeBSD source, but since you… | |||||
do { \ | |||||
int fnd, fndarray[(maxn)], i, j; \ | |||||
/* Handle common cases. */ \ | |||||
if ((n) == 0) \ | |||||
return (0); \ | |||||
if ((n) == 1) { \ | |||||
Done Inline ActionsI think that these micro-optimizations are not an optimizations at all. Memcmp has early-stop behavior, and you do not need to squeeze the last cycle from the reload code anyway. I would seriously consider just doing per-element comparision only. It is both more correct and produce less code, which might be faster due to the less code, after all. kib: I think that these micro-optimizations are not an optimizations at all. Memcmp has early-stop… | |||||
Done Inline ActionsThese have been removed and replaced with a simple for loop to check for rmacklem: These have been removed and replaced with a simple for loop to check for
identical arrays.
| |||||
if ((a1)[0] == (a2)[0]) \ | |||||
return (0); \ | |||||
return (1); \ | |||||
} \ | |||||
if (memcmp((a1), (a2), sizeof(typ) * (n)) == 0) \ | |||||
kibUnsubmitted Done Inline ActionsGenerally, use of memcmp() is not correct if members of array can contain padding. kib: Generally, use of memcmp() is not correct if members of array can contain padding. | |||||
rmacklemAuthorUnsubmitted Done Inline ActionsThe only types it is used for are "gid_t" and "int", so I don't think padding will be an issue. If you think it should be changed to a for(;;) loop on the n elements, I can easily change rmacklem: The only types it is used for are "gid_t" and "int", so I don't think padding will be an issue. | |||||
rmacklemAuthorUnsubmitted Done Inline Actionsmemcmp() has now been removed from the patch. rmacklem: memcmp() has now been removed from the patch.
| |||||
return (0); \ | |||||
for (i = 0; i < (n); i++) \ | |||||
fndarray[i] = 0; \ | |||||
for (i = 0; i < (n); i++) { \ | |||||
fnd = 0; \ | |||||
for (j = 0; j < (n); j++) { \ | |||||
if ((a1)[i] == (a2)[j]) { \ | |||||
fndarray[j] = 1; \ | |||||
fnd = 1; \ | |||||
} \ | |||||
} \ | |||||
if (fnd == 0) \ | |||||
return (1); \ | |||||
} \ | |||||
for (i = 0; i < (n); i++) \ | |||||
if (fndarray[i] == 0) \ | |||||
return (1); \ | |||||
return (0); \ | |||||
} while (0) | |||||
/* | |||||
* Compare to struct xucred's. Return 0 if the same and 1 otherwise. | |||||
*/ | |||||
static int | |||||
compare_cred(struct xucred *cr0, struct xucred *cr1) | |||||
{ | |||||
if (cr0->cr_uid != cr1->cr_uid || cr0->cr_ngroups != cr1->cr_ngroups) | |||||
return (1); | |||||
COMPARE_ARRAYS(gid_t, cr0->cr_groups, cr1->cr_groups, cr0->cr_ngroups, | |||||
XU_NGROUPS); | |||||
} | |||||
/* | |||||
* Compare two lists of security flavors. Return 0 if the same and 1 otherwise. | |||||
*/ | |||||
static int | |||||
compare_secflavor(int *sec1, int *sec2, int nsec) | |||||
{ | |||||
COMPARE_ARRAYS(int, sec1, sec2, nsec, MAXSECFLAVORS); | |||||
} | |||||
/* | |||||
* Delete an exports entry. | * Delete an exports entry. | ||||
*/ | */ | ||||
static void | static void | ||||
delete_export(struct iovec *iov, int iovlen, struct statfs *fsp, char *errmsg) | delete_export(struct iovec *iov, int iovlen, struct statfs *fsp, char *errmsg) | ||||
{ | { | ||||
struct xvfsconf vfc; | struct xvfsconf vfc; | ||||
if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { | if (getvfsbyname(fsp->f_fstypename, &vfc) != 0) { | ||||
▲ Show 20 Lines • Show All 130 Lines • ▼ Show 20 Lines | |||||
} | } | ||||
/* | /* | ||||
* Hang the dir list element off the dirpath binary tree as required | * Hang the dir list element off the dirpath binary tree as required | ||||
* and update the entry for host. | * and update the entry for host. | ||||
*/ | */ | ||||
static void | static void | ||||
hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, | hang_dirp(struct dirlist *dp, struct grouplist *grp, struct exportlist *ep, | ||||
int flags) | int flags, struct xucred *anoncrp, int exflags) | ||||
{ | { | ||||
struct hostlist *hp; | struct hostlist *hp; | ||||
struct dirlist *dp2; | struct dirlist *dp2; | ||||
if (flags & OP_ALLDIRS) { | if (flags & OP_ALLDIRS) { | ||||
if (ep->ex_defdir) | if (ep->ex_defdir) | ||||
free((caddr_t)dp); | free((caddr_t)dp); | ||||
else | else | ||||
ep->ex_defdir = dp; | ep->ex_defdir = dp; | ||||
if (grp == (struct grouplist *)NULL) { | if (grp == (struct grouplist *)NULL) { | ||||
ep->ex_flag |= EX_DEFSET; | |||||
ep->ex_defdir->dp_flag |= DP_DEFSET; | ep->ex_defdir->dp_flag |= DP_DEFSET; | ||||
/* Save the default security flavors list. */ | /* Save the default security flavors list. */ | ||||
ep->ex_defnumsecflavors = ep->ex_numsecflavors; | ep->ex_defnumsecflavors = ep->ex_numsecflavors; | ||||
if (ep->ex_numsecflavors > 0) | if (ep->ex_numsecflavors > 0) | ||||
memcpy(ep->ex_defsecflavors, ep->ex_secflavors, | memcpy(ep->ex_defsecflavors, ep->ex_secflavors, | ||||
sizeof(ep->ex_secflavors)); | sizeof(ep->ex_secflavors)); | ||||
ep->ex_defanon = *anoncrp; | |||||
ep->ex_defexflags = exflags; | |||||
} else while (grp) { | } else while (grp) { | ||||
hp = get_ht(); | hp = get_ht(); | ||||
hp->ht_grp = grp; | hp->ht_grp = grp; | ||||
hp->ht_next = ep->ex_defdir->dp_hosts; | hp->ht_next = ep->ex_defdir->dp_hosts; | ||||
ep->ex_defdir->dp_hosts = hp; | ep->ex_defdir->dp_hosts = hp; | ||||
/* Save the security flavors list for this host set. */ | /* Save the security flavors list for this host set. */ | ||||
grp->gr_numsecflavors = ep->ex_numsecflavors; | grp->gr_numsecflavors = ep->ex_numsecflavors; | ||||
if (ep->ex_numsecflavors > 0) | if (ep->ex_numsecflavors > 0) | ||||
memcpy(grp->gr_secflavors, ep->ex_secflavors, | memcpy(grp->gr_secflavors, ep->ex_secflavors, | ||||
sizeof(ep->ex_secflavors)); | sizeof(ep->ex_secflavors)); | ||||
grp = grp->gr_next; | grp = grp->gr_next; | ||||
} | } | ||||
} else { | } else { | ||||
/* | /* | ||||
* Loop through the directories adding them to the tree. | * Loop through the directories adding them to the tree. | ||||
*/ | */ | ||||
while (dp) { | while (dp) { | ||||
dp2 = dp->dp_left; | dp2 = dp->dp_left; | ||||
add_dlist(&ep->ex_dirl, dp, grp, flags, ep); | add_dlist(&ep->ex_dirl, dp, grp, flags, ep, anoncrp, | ||||
exflags); | |||||
dp = dp2; | dp = dp2; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Traverse the binary tree either updating a node that is already there | * Traverse the binary tree either updating a node that is already there | ||||
* for the new directory or adding the new node. | * for the new directory or adding the new node. | ||||
*/ | */ | ||||
static void | static void | ||||
add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, | add_dlist(struct dirlist **dpp, struct dirlist *newdp, struct grouplist *grp, | ||||
int flags, struct exportlist *ep) | int flags, struct exportlist *ep, struct xucred *anoncrp, int exflags) | ||||
{ | { | ||||
struct dirlist *dp; | struct dirlist *dp; | ||||
struct hostlist *hp; | struct hostlist *hp; | ||||
int cmp; | int cmp; | ||||
dp = *dpp; | dp = *dpp; | ||||
if (dp) { | if (dp) { | ||||
cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); | cmp = strcmp(dp->dp_dirp, newdp->dp_dirp); | ||||
if (cmp > 0) { | if (cmp > 0) { | ||||
add_dlist(&dp->dp_left, newdp, grp, flags, ep); | add_dlist(&dp->dp_left, newdp, grp, flags, ep, anoncrp, | ||||
exflags); | |||||
return; | return; | ||||
} else if (cmp < 0) { | } else if (cmp < 0) { | ||||
add_dlist(&dp->dp_right, newdp, grp, flags, ep); | add_dlist(&dp->dp_right, newdp, grp, flags, ep, anoncrp, | ||||
exflags); | |||||
return; | return; | ||||
} else | } else | ||||
free((caddr_t)newdp); | free((caddr_t)newdp); | ||||
} else { | } else { | ||||
dp = newdp; | dp = newdp; | ||||
dp->dp_left = (struct dirlist *)NULL; | dp->dp_left = (struct dirlist *)NULL; | ||||
*dpp = dp; | *dpp = dp; | ||||
} | } | ||||
Show All 10 Lines | do { | ||||
/* Save the security flavors list for this host set. */ | /* Save the security flavors list for this host set. */ | ||||
grp->gr_numsecflavors = ep->ex_numsecflavors; | grp->gr_numsecflavors = ep->ex_numsecflavors; | ||||
if (ep->ex_numsecflavors > 0) | if (ep->ex_numsecflavors > 0) | ||||
memcpy(grp->gr_secflavors, ep->ex_secflavors, | memcpy(grp->gr_secflavors, ep->ex_secflavors, | ||||
sizeof(ep->ex_secflavors)); | sizeof(ep->ex_secflavors)); | ||||
grp = grp->gr_next; | grp = grp->gr_next; | ||||
} while (grp); | } while (grp); | ||||
} else { | } else { | ||||
ep->ex_flag |= EX_DEFSET; | |||||
dp->dp_flag |= DP_DEFSET; | dp->dp_flag |= DP_DEFSET; | ||||
/* Save the default security flavors list. */ | /* Save the default security flavors list. */ | ||||
ep->ex_defnumsecflavors = ep->ex_numsecflavors; | ep->ex_defnumsecflavors = ep->ex_numsecflavors; | ||||
if (ep->ex_numsecflavors > 0) | if (ep->ex_numsecflavors > 0) | ||||
memcpy(ep->ex_defsecflavors, ep->ex_secflavors, | memcpy(ep->ex_defsecflavors, ep->ex_secflavors, | ||||
sizeof(ep->ex_secflavors)); | sizeof(ep->ex_secflavors)); | ||||
ep->ex_defanon = *anoncrp; | |||||
ep->ex_defexflags = exflags; | |||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Search for a dirpath on the export point. | * Search for a dirpath on the export point. | ||||
*/ | */ | ||||
static struct dirlist * | static struct dirlist * | ||||
dirp_search(struct dirlist *dp, char *dirp) | dirp_search(struct dirlist *dp, char *dirp) | ||||
▲ Show 20 Lines • Show All 349 Lines • ▼ Show 20 Lines | while (grp) { | ||||
tgrp = grp; | tgrp = grp; | ||||
grp = grp->gr_next; | grp = grp->gr_next; | ||||
free_grp(tgrp); | free_grp(tgrp); | ||||
} | } | ||||
free((caddr_t)ep); | free((caddr_t)ep); | ||||
} | } | ||||
/* | /* | ||||
* Free up the v4root exports. | |||||
*/ | |||||
static void | |||||
free_v4rootexp(void) | |||||
{ | |||||
if (v4root_ep != NULL) { | |||||
free_exp(v4root_ep); | |||||
v4root_ep = NULL; | |||||
} | |||||
} | |||||
/* | |||||
* Free hosts. | * Free hosts. | ||||
*/ | */ | ||||
static void | static void | ||||
free_host(struct hostlist *hp) | free_host(struct hostlist *hp) | ||||
{ | { | ||||
struct hostlist *hp2; | struct hostlist *hp2; | ||||
while (hp) { | while (hp) { | ||||
Show All 23 Lines | |||||
out_of_mem(void) | out_of_mem(void) | ||||
{ | { | ||||
syslog(LOG_ERR, "out of memory"); | syslog(LOG_ERR, "out of memory"); | ||||
exit(2); | exit(2); | ||||
} | } | ||||
/* | /* | ||||
* Call do_mount() from the struct exportlist, for each case needed. | |||||
*/ | |||||
static int | |||||
do_export_mount(struct exportlist *ep, struct statfs *fsp) | |||||
{ | |||||
struct grouplist *grp, defgrp; | |||||
int ret; | |||||
size_t dirlen; | |||||
LOGDEBUG("do_export_mount=%s", ep->ex_fsdir); | |||||
dirlen = strlen(ep->ex_fsdir); | |||||
if ((ep->ex_flag & EX_DEFSET) != 0) { | |||||
defgrp.gr_type = GT_DEFAULT; | |||||
defgrp.gr_next = NULL; | |||||
/* We have an entry for all other hosts/nets. */ | |||||
LOGDEBUG("ex_defexflags=0x%x", ep->ex_defexflags); | |||||
ret = do_mount(ep, &defgrp, ep->ex_defexflags, &ep->ex_defanon, | |||||
ep->ex_fsdir, dirlen, fsp, ep->ex_defnumsecflavors, | |||||
ep->ex_defsecflavors); | |||||
if (ret != 0) | |||||
return (ret); | |||||
} | |||||
/* Do a mount for each group. */ | |||||
grp = ep->ex_grphead; | |||||
while (grp != NULL) { | |||||
LOGDEBUG("do mount gr_type=0x%x gr_exflags=0x%x", | |||||
grp->gr_type, grp->gr_exflags); | |||||
ret = do_mount(ep, grp, grp->gr_exflags, &grp->gr_anon, | |||||
ep->ex_fsdir, dirlen, fsp, grp->gr_numsecflavors, | |||||
grp->gr_secflavors); | |||||
if (ret != 0) | |||||
return (ret); | |||||
grp = grp->gr_next; | |||||
} | |||||
return (0); | |||||
} | |||||
/* | |||||
* Do the nmount() syscall with the update flag to push the export info into | * Do the nmount() syscall with the update flag to push the export info into | ||||
* the kernel. | * the kernel. | ||||
*/ | */ | ||||
static int | static int | ||||
do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, | do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, | ||||
struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb) | struct xucred *anoncrp, char *dirp, int dirplen, struct statfs *fsb, | ||||
int numsecflavors, int *secflavors) | |||||
{ | { | ||||
struct statfs fsb1; | struct statfs fsb1; | ||||
struct addrinfo *ai; | struct addrinfo *ai; | ||||
struct export_args *eap; | struct export_args *eap; | ||||
char errmsg[255]; | char errmsg[255]; | ||||
char *cp; | char *cp; | ||||
int done; | int done; | ||||
char savedc; | char savedc; | ||||
Show All 9 Lines | do_mount(struct exportlist *ep, struct grouplist *grp, int exflags, | ||||
iov = NULL; | iov = NULL; | ||||
iovlen = 0; | iovlen = 0; | ||||
ret = 0; | ret = 0; | ||||
bzero(eap, sizeof (struct export_args)); | bzero(eap, sizeof (struct export_args)); | ||||
bzero(errmsg, sizeof(errmsg)); | bzero(errmsg, sizeof(errmsg)); | ||||
eap->ex_flags = exflags; | eap->ex_flags = exflags; | ||||
eap->ex_anon = *anoncrp; | eap->ex_anon = *anoncrp; | ||||
LOGDEBUG("do_mount exflags=0x%x", exflags); | |||||
eap->ex_indexfile = ep->ex_indexfile; | eap->ex_indexfile = ep->ex_indexfile; | ||||
if (grp->gr_type == GT_HOST) | if (grp->gr_type == GT_HOST) | ||||
ai = grp->gr_ptr.gt_addrinfo; | ai = grp->gr_ptr.gt_addrinfo; | ||||
else | else | ||||
ai = NULL; | ai = NULL; | ||||
eap->ex_numsecflavors = ep->ex_numsecflavors; | eap->ex_numsecflavors = numsecflavors; | ||||
LOGDEBUG("do_mount numsec=%d", numsecflavors); | |||||
for (i = 0; i < eap->ex_numsecflavors; i++) | for (i = 0; i < eap->ex_numsecflavors; i++) | ||||
eap->ex_secflavors[i] = ep->ex_secflavors[i]; | eap->ex_secflavors[i] = secflavors[i]; | ||||
if (eap->ex_numsecflavors == 0) { | if (eap->ex_numsecflavors == 0) { | ||||
eap->ex_numsecflavors = 1; | eap->ex_numsecflavors = 1; | ||||
eap->ex_secflavors[0] = AUTH_SYS; | eap->ex_secflavors[0] = AUTH_SYS; | ||||
} | } | ||||
done = FALSE; | done = FALSE; | ||||
if (v4root_phase == 0) { | if (v4root_phase == 0) { | ||||
build_iovec(&iov, &iovlen, "fstype", NULL, 0); | build_iovec(&iov, &iovlen, "fstype", NULL, 0); | ||||
▲ Show 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | if ((exflags & MNT_EXPUBLIC) != 0) { | ||||
else | else | ||||
public_name = dirp; | public_name = dirp; | ||||
if (getfh(public_name, &fh) < 0) | if (getfh(public_name, &fh) < 0) | ||||
syslog(LOG_ERR, | syslog(LOG_ERR, | ||||
"Can't get public fh for %s", public_name); | "Can't get public fh for %s", public_name); | ||||
else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) | else if (nfssvc(NFSSVC_PUBLICFH, (caddr_t)&fh) < 0) | ||||
syslog(LOG_ERR, | syslog(LOG_ERR, | ||||
"Can't set public fh for %s", public_name); | "Can't set public fh for %s", public_name); | ||||
else | else { | ||||
has_publicfh = 1; | has_publicfh = 1; | ||||
has_set_publicfh = 1; | |||||
ep->ex_flag |= EX_PUBLICFH; | |||||
} | |||||
} | } | ||||
skip: | skip: | ||||
if (ai != NULL) | if (ai != NULL) | ||||
ai = ai->ai_next; | ai = ai->ai_next; | ||||
if (ai == NULL) | if (ai == NULL) | ||||
done = TRUE; | done = TRUE; | ||||
} | } | ||||
if (cp) | if (cp) | ||||
▲ Show 20 Lines • Show All 625 Lines • Show Last 20 Lines |
Why do you need maxn ? If only to declare fndarray[] below, you can use fndarray[n], we are way past c99.