From: Hallyson Melo Date: Wed, 18 Nov 2009 20:36:24 +0000 (-0300) Subject: Added initial unfs3 sources for version 0.9.22+dfsg-1maemo2 X-Git-Url: https://vcs.maemo.org/git/?a=commitdiff_plain;ds=sidebyside;h=1ddb92b899989e26e26a4491251d4bc61be22918;p=unfs3 Added initial unfs3 sources for version 0.9.22+dfsg-1maemo2 --- diff --git a/unfs3/BRANCHES b/unfs3/BRANCHES new file mode 100644 index 0000000..f16282a --- /dev/null +++ b/unfs3/BRANCHES @@ -0,0 +1,21 @@ +uidmapping +---------- +Unused. + + +removable-fsidhash +------------------ +This branch has been used for work on removable support. All changes +has been merged with the HEAD branch now. + + +removable-support +----------------- +Experimental ASCII-filehandles work. These changes will probably not +be merged with HEAD; they are pretty much obsoleted by the work on the +"removable-fsidhash" branch. + + +pharao90 +-------- +Main vendor branch. diff --git a/unfs3/CREDITS b/unfs3/CREDITS new file mode 100644 index 0000000..9f44fd1 --- /dev/null +++ b/unfs3/CREDITS @@ -0,0 +1,37 @@ +CREDITS +======= + +The design of unfs3's filehandle code owes much to the original NFSv2 +universal user-space NFS server. Thanks to Mark Shand and Don Becker +for coming up with those concepts. + +We also give credit to Gregory R. Warnes for the idea of file +tagging as used by ClusterNFS and the unfs3 cluster extension. + +People who contributed ideas, suggestions, or code to UNFS3: + +- Bernd Schubert +- Avery Pennarun +- Juergen Brendel +- Peter Astrand +- Igor Durdanovic +- Jan P. Springer +- Thomas Schwinge +- Simon Matter +- Brian +- Jean Aumont +- Constantin Scheder +- Sam Sharma +- Holger Wolf +- Frank v Waveren +- Matthew Bloch +- Nick S. Grechukh +- Michael Shigorin +- Tim Weippert +- Hanpen-san +- Sergey Bolshakov +- Phill Bertolus +- Brent A Nelson +- Garrett Cooper +- Wesley Shields +- Bernhard Duebi diff --git a/unfs3/Config/Makefile.in b/unfs3/Config/Makefile.in new file mode 100644 index 0000000..45c56e7 --- /dev/null +++ b/unfs3/Config/Makefile.in @@ -0,0 +1,33 @@ +CC = @CC@ +CFLAGS = @CFLAGS@ +AR = ar +RM = rm -f +LEX = @LEX@ +YACC = @YACC@ + +OBJS = @LEX_OUTPUT_ROOT@.o y.tab.o + +all: lib.a + +lib.a: $(OBJS) + $(AR) crs lib.a $(OBJS) + +y.tab.h y.tab.c: exports.y + $(YACC) -d exports.y + +y.tab.o: y.tab.c exports.h ../nfs.h ../mount.h ../daemon.h + +@LEX_OUTPUT_ROOT@.c: exports.l + $(LEX) exports.l + +@LEX_OUTPUT_ROOT@.o: @LEX_OUTPUT_ROOT@.c y.tab.h ../nfs.h + +dep: + : + +clean: + $(RM) $(OBJS) lib.a + $(RM) @LEX_OUTPUT_ROOT@.c y.tab.h y.tab.c + +distclean: + $(RM) Makefile diff --git a/unfs3/Config/exports.h b/unfs3/Config/exports.h new file mode 100644 index 0000000..2c5edec --- /dev/null +++ b/unfs3/Config/exports.h @@ -0,0 +1,45 @@ +/* + * UNFS3 export controls + * (C) 2003, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_EXPORTS_H +#define UNFS3_EXPORTS_H + +#include "../mount.h" /* exports type */ + +#define OPT_NO_ROOT_SQUASH 1 +#define OPT_ALL_SQUASH 2 +#define OPT_RW 4 +#define OPT_REMOVABLE 8 +#define OPT_INSECURE 16 + +#define PASSWORD_MAXLEN 64 + +#define ANON_NOTSPECIAL 0xffffffff + +extern exports exports_nfslist; +/* Options cache */ +extern int exports_opts; +const char *export_path; +extern uint32 export_fsid; +extern uint32 export_password_hash; + +extern unsigned char password[PASSWORD_MAXLEN+1]; + +int exports_parse(void); +int exports_options(const char *path, struct svc_req *rqstp, char **password, uint32 *fsid); +int export_point(const char *path); +char *export_point_from_fsid(uint32 fsid, time_t **last_mtime, uint32 **dir_hash); +nfsstat3 exports_compat(const char *path, struct svc_req *rqstp); +nfsstat3 exports_rw(void); +uint32 exports_anonuid(void); +uint32 exports_anongid(void); +uint32 fnv1a_32(const char *str, uint32 hval); +#ifdef WIN32 +uint32 wfnv1a_32(const wchar_t *str, uint32 hval); +#endif /* WIN32 */ +char *normpath(const char *path, char *normpath); + +#endif diff --git a/unfs3/Config/exports.l b/unfs3/Config/exports.l new file mode 100644 index 0000000..8a2d6d1 --- /dev/null +++ b/unfs3/Config/exports.l @@ -0,0 +1,70 @@ +%{ +/* + * UNFS3 exports lexer + * (C) 2003, Pascal Schmidt + * see file LICENSE for license details + */ +#include "../config.h" + +#include +#include + +#include "../nfs.h" +#include "y.tab.h" + +#define YY_NO_UNPUT + +YYSTYPE yylval; +extern int e_error; + +/* + * copy matching text to yylval.text + */ +static void copy_text(const char *from, int leng) +{ + int len; + + /* check length to prevent buffer overflow */ + if (leng + 1 > NFS_MAXPATHLEN) { + len = NFS_MAXPATHLEN - 1; + e_error = 1; + } else + len = leng; + + memcpy(yylval.text, from, len); + yylval.text[len] = 0; +} +%} + +WHITE [ \t] +NOWHITE [^ \n\t] +PATH "/"{NOWHITE}* +ID [a-z][\.\-_a-z0-9]* +OPTVALUE [^ \n\t,)]* + +IPCOMP [0-9]{1,3} +IP {IPCOMP}"."{IPCOMP}"."{IPCOMP}"."{IPCOMP} +NETCOMP [0-9]{1,2} +NET {IP}"/"{NETCOMP} +OLDNET {IP}"/"{IP} + +%% + +^{WHITE}*\n { /* eat empty line */ } +^{WHITE}* { /* eat whitespace at beginning of line */ } +"\\"\n { /* eat escaped newline */ } +^{WHITE}*"#".*\n { /* eat one-line comment */ } +{WHITE}*"#".* { /* eat trailing comment */ } + +{IP} { copy_text(yytext, yyleng); return IP; } +{NET} { copy_text(yytext, yyleng); return NET; } +{OLDNET} { copy_text(yytext, yyleng); return OLDNET; } +"\"".*"\"" { copy_text(yytext+1, yyleng-2); return PATH; } +"="{OPTVALUE} { copy_text(yytext+1, yyleng-1); return OPTVALUE; } +{PATH} { copy_text(yytext, yyleng); return PATH; } +{WHITE}+ { copy_text(yytext, yyleng); return WHITE; } +{ID} { copy_text(yytext, yyleng); return ID; } + +. { return *yytext; } +\n { return '\n'; } + \ No newline at end of file diff --git a/unfs3/Config/exports.y b/unfs3/Config/exports.y new file mode 100644 index 0000000..f30e8af --- /dev/null +++ b/unfs3/Config/exports.y @@ -0,0 +1,848 @@ +%{ +/* + * UNFS3 exports parser and export controls + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ +#include "../config.h" + +#include +#include + +#ifdef WIN32 +#include "../winsupport.h" +#else +#include +#include +#include +#include +#include +#endif /* WIN32 */ +#include +#include +#include + +#include "../nfs.h" +#include "../mount.h" +#include "../daemon.h" +#include "../backend.h" +#include "exports.h" + +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + +/* for lack of a better place */ +#ifdef __GNUC__ +#define U(x) x __attribute__ ((unused)) +#else +#define U(x) x +#endif + +/* lexer stuff, to avoid compiler warnings */ +int yylex(void); +extern FILE *yyin; + +/* + * C code used by yacc parser + */ + +typedef struct { + char orig[NFS_MAXPATHLEN]; + int options; + char password[PASSWORD_MAXLEN+1]; + uint32 password_hash; + struct in_addr addr; + struct in_addr mask; + uint32 anonuid; + uint32 anongid; + struct e_host *next; +} e_host; + +typedef struct { + char path[NFS_MAXPATHLEN]; + char orig[NFS_MAXPATHLEN]; + e_host *hosts; + uint32 fsid; /* export point fsid (for removables) */ + time_t last_mtime; /* Last returned mtime (for removables) */ + uint32 dir_hash; /* Hash of dir contents (for removables) */ + struct e_item *next; +} e_item; + +/* export list, item, and host filled during parse */ +static e_item *e_list = NULL; +static e_item cur_item; +static e_host cur_host; + +/* last looked-up anonuid and anongid */ +static uint32 last_anonuid = ANON_NOTSPECIAL; +static uint32 last_anongid = ANON_NOTSPECIAL; + +/* mount protocol compatible variants */ +static exports ne_list = NULL; +static struct exportnode ne_item; +static struct groupnode ne_host; + +/* error status of last parse */ +int e_error = FALSE; + +/* + * The FNV1a-32 hash algorithm + * (http://www.isthe.com/chongo/tech/comp/fnv/) + */ +uint32 fnv1a_32(const char *str, uint32 hval) +{ + static const uint32 fnv_32_prime = 0x01000193; + + while (*str) { + hval ^= *str++; + hval *= fnv_32_prime; + } + return hval; +} + +#ifdef WIN32 +uint32 wfnv1a_32(const wchar_t *str, uint32 hval) +{ + static const uint32 fnv_32_prime = 0x01000193; + + while (*str) { + hval ^= *str++; + hval *= fnv_32_prime; + } + return hval; +} +#endif + +/* + * get static fsid, for use with removable media export points + */ +static uint32 get_free_fsid(const char *path) +{ + uint32 hval; + + /* The 32:th bit is set to one on all special filehandles. The + last 31 bits are hashed from the export point path. */ + hval = fnv1a_32(path, 0); + hval |= 0x80000000; + return hval; +} + + +/* + * clear current host + */ +static void clear_host(void) +{ + memset(&cur_host, 0, sizeof(e_host)); + strcpy(cur_host.orig, ""); + memset(&ne_host, 0, sizeof(struct groupnode)); + + cur_host.anonuid = + cur_host.anongid = ANON_NOTSPECIAL; +} + +/* + * clear current item + */ +static void clear_item(void) +{ + memset(&cur_item, 0, sizeof(e_item)); + memset(&ne_item, 0, sizeof(struct exportnode)); +} + +/* + * add current host to current export item + */ +static void add_host(void) +{ + e_host *new; + e_host *iter; + + groups ne_new; + groups ne_iter; + + new = malloc(sizeof(e_host)); + ne_new = malloc(sizeof(struct groupnode)); + if (!new || !ne_new) { + logmsg(LOG_EMERG, "out of memory, aborting"); + daemon_exit(CRISIS); + } + + *new = cur_host; + *ne_new = ne_host; + ne_new->gr_name = new->orig; + + /* internal list */ + if (cur_item.hosts) { + iter = cur_item.hosts; + while (iter->next) + iter = (e_host *) iter->next; + iter->next = (struct e_host *) new; + } else + cur_item.hosts = new; + + /* matching mount protocol list */ + if (ne_item.ex_groups) { + ne_iter = ne_item.ex_groups; + while (ne_iter->gr_next) + ne_iter = (groups) ne_iter->gr_next; + ne_iter->gr_next = ne_new; + } else + ne_item.ex_groups = ne_new; + + clear_host(); +} + +/* + Normalize path, eliminating double slashes, etc. To be used instead + of realpath, when realpath is not possible. Normalizing export + points is important. Otherwise, mount requests might fail, since + /x/y is not a prefix of ///x///y/ etc. +*/ +char *normpath(const char *path, char *normpath) +{ + char *n; + const char *p; + + /* Copy path to normpath, and replace blocks of slashes with + single slash */ + p = path; + n = normpath; + while (*p) { + /* Skip over multiple slashes */ + if (*p == '/' && *(p+1) == '/') { + p++; + continue; + } + *n++ = *p++; + } + *n = '\0'; + + /* Remove trailing slash, if any. */ + if ((n - normpath) > 1 && *(n-1) == '/') + *(n-1) = '\0'; + + return normpath; +} + +/* + * add current item to current export list + */ +static void add_item(const char *path) +{ + char buf[PATH_MAX]; + e_item *new; + e_item *iter; + e_host *host; + /* Is this item marked as removable for all hosts? */ + int removable_for_all = 1; + + exports ne_new; + exports ne_iter; + + new = malloc(sizeof(e_item)); + ne_new = malloc(sizeof(struct exportnode)); + if (!new || !ne_new) { + logmsg(LOG_EMERG, "out of memory, aborting"); + daemon_exit(CRISIS); + } + + /* Loop over all hosts and check if marked as removable. */ + host = cur_item.hosts; + while (host) { + if (!(host->options & OPT_REMOVABLE)) + removable_for_all = 0; + host = (e_host *) host->next; + } + + if (removable_for_all) { + /* If marked as removable for all hosts, don't try + realpath. */ + normpath(path, buf); + } else if (!backend_realpath(path, buf)) { + logmsg(LOG_CRIT, "realpath for %s failed", path); + e_error = TRUE; + free(new); + free(ne_new); + clear_item(); + return; + } + + if (strlen(buf) + 1 > NFS_MAXPATHLEN) { + logmsg(LOG_CRIT, "attempted to export too long path"); + e_error = TRUE; + free(new); + free(ne_new); + clear_item(); + return; + } + + /* if no hosts listed, list default host */ + if (!cur_item.hosts) + add_host(); + + *new = cur_item; + strcpy(new->path, buf); + strcpy(new->orig, path); + new->fsid = get_free_fsid(path); + new->last_mtime = 0; + new->dir_hash = 0; + + *ne_new = ne_item; + ne_new->ex_dir = new->orig; + + /* internal list */ + if (e_list) { + iter = e_list; + while (iter->next) + iter = (e_item *) iter->next; + iter->next = (struct e_item *) new; + } else + e_list = new; + + /* matching mount protocol list */ + if (ne_list) { + ne_iter = ne_list; + while (ne_iter->ex_next) + ne_iter = (exports) ne_iter->ex_next; + ne_iter->ex_next = ne_new; + } else + ne_list = ne_new; + + clear_item(); +} + +/* + * fill current host's address given a hostname + */ +static void set_hostname(const char *name) +{ + struct hostent *ent; + + if (strlen(name) + 1 > NFS_MAXPATHLEN) { + e_error = TRUE; + return; + } + strcpy(cur_host.orig, name); + + ent = gethostbyname(name); + + if (ent) { + memcpy(&cur_host.addr, ent->h_addr_list[0], + sizeof(struct in_addr)); + cur_host.mask.s_addr = ~0UL; + } else { + logmsg(LOG_CRIT, "could not resolve hostname '%s'", name); + e_error = TRUE; + } +} + +/* + * fill current host's address given an IP address + */ +static void set_ipaddr(const char *addr) +{ + strcpy(cur_host.orig, addr); + + if (!inet_aton(addr, &cur_host.addr)) + e_error = TRUE; + cur_host.mask.s_addr = ~0UL; +} + +/* + * compute network bitmask + */ +static unsigned long make_netmask(int bits) { + unsigned long buf = 0; + int i; + + for (i=0; i PASSWORD_MAXLEN) { + logmsg(LOG_WARNING, "Warning: password for export %s truncated to 64 chars", + cur_item.orig); + } + strncpy(cur_host.password, val, sizeof(password)); + cur_host.password[PASSWORD_MAXLEN] = '\0'; + /* Calculate hash */ + cur_host.password_hash = fnv1a_32(cur_host.password, 0); + } else if (strcmp(opt,"anonuid") == 0) { + cur_host.anonuid = atoi(val); + } else if (strcmp(opt,"anongid") == 0) { + cur_host.anongid = atoi(val); + } else { + logmsg(LOG_WARNING, "Warning: unknown exports option `%s' ignored", + opt); + } +} + +/* + * dummy error function + */ +void yyerror(U(char *s)) +{ + e_error = TRUE; + return; +} + +%} + +%union { + char text[NFS_MAXPATHLEN]; +}; + +%token PATH +%token ID +%token OPTVALUE +%token WHITE +%token IP +%token NET +%token OLDNET + +%% + +exports: + export + | export '\n' exports + | + ; + +export: + PATH { add_item($1); } + | PATH WHITE hosts { add_item($1); } + | PATH WHITE { add_item($1); } + ; + +hosts: + host + | host WHITE hosts + | host WHITE + ; + +host: + name { add_host(); } + | name '(' opts ')' { add_host(); } + | '(' opts ')' { add_host(); } + ; + +name: + ID { set_hostname($1); } + | IP { set_ipaddr($1); } + | NET { set_ipnet($1, TRUE); } + | OLDNET { set_ipnet($1, FALSE); } + ; + +opts: + opt + | opt ',' opts + | + ; + +opt: + ID { add_option($1); } + | ID OPTVALUE { add_option_with_value($1,$2); } + ; +%% + +/* + * C code using yacc parser + access code for exports list + */ + +/* effective export list and access flag */ +static e_item *export_list = NULL; +static volatile int exports_access = FALSE; + +/* mount protocol compatible exports list */ +exports exports_nfslist = NULL; + +/* + * free NFS groups list + */ +void free_nfsgroups(groups group) +{ + groups list, next; + + list = group; + while (list) { + next = (groups) list->gr_next; + free(list); + list = next; + } +} + +/* + * free NFS exports list + */ +void free_nfslist(exports elist) +{ + exports list, next; + + list = elist; + while(list) { + next = (exports) list->ex_next; + free_nfsgroups(list->ex_groups); + free(list); + list = next; + } +} + +/* + * free list of host structures + */ +static void free_hosts(e_item *item) +{ + e_host *host, *cur; + + host = item->hosts; + while (host) { + cur = host; + host = (e_host *) host->next; + free(cur); + } +} + +/* + * free list of export items + */ +static void free_list(e_item *item) +{ + e_item *cur; + + while (item) { + free_hosts(item); + cur = item; + item = (e_item *) item->next; + free(cur); + } +} + +/* + * print out the current exports list (for debugging) + */ +void print_list(void) +{ + char addrbuf[16], maskbuf[16]; + + e_item *item; + e_host *host; + + item = e_list; + + while (item) { + host = item->hosts; + while (host) { + /* inet_ntoa returns static buffer */ + strcpy(addrbuf, inet_ntoa(host->addr)); + strcpy(maskbuf, inet_ntoa(host->mask)); + printf("%s: ip %s mask %s options %i\n", + item->path, addrbuf, maskbuf, + host->options); + host = (e_host *) host->next; + } + item = (e_item *) item->next; + } +} + +/* + * clear current parse state + */ +static void clear_cur(void) +{ + e_list = NULL; + ne_list = NULL; + e_error = FALSE; + clear_host(); + clear_item(); +} + +/* + * parse an exports file + */ +int exports_parse(void) +{ + FILE *efile; + + /* + * if we are in the SIGHUP handler, a may_mount or get_options + * may currently be accessing the list + */ + if (exports_access) { + logmsg(LOG_CRIT, "export list is being traversed, no reload\n"); + return FALSE; + } + + efile = fopen(opt_exports, "r"); + if (!efile) { + logmsg(LOG_CRIT, "could not open '%s', exporting nothing", + opt_exports); + free_list(export_list); + free_nfslist(exports_nfslist); + export_list = NULL; + exports_nfslist = NULL; + return FALSE; + } + + yyin = efile; + clear_cur(); + yyparse(); + fclose(efile); + + if (e_error) { + logmsg(LOG_CRIT, "syntax error in '%s', exporting nothing", + opt_exports); + free_list(export_list); + free_nfslist(exports_nfslist); + export_list = NULL; + exports_nfslist = NULL; + return FALSE; + } + + /* print out new list for debugging */ + if (!opt_detach) + print_list(); + + free_list(export_list); + free_nfslist(exports_nfslist); + export_list = e_list; + exports_nfslist = ne_list; + return TRUE; +} + +/* + * find a given host inside a host list, return options + */ +static e_host* find_host(struct in_addr remote, e_item *item, + char **password, uint32 *password_hash) +{ + e_host *host; + + host = item->hosts; + while (host) { + if ((remote.s_addr & host->mask.s_addr) == host->addr.s_addr) { + if (password != NULL) + *password = host->password; + if (password_hash != NULL) + *password_hash = host->password_hash; + return host; + } + host = (e_host *) host->next; + } + return NULL; +} + +/* options cache */ +int exports_opts = -1; +const char *export_path = NULL; +uint32 export_fsid = 0; +uint32 export_password_hash = 0; + +/* + * given a path, return client's effective options + */ +int exports_options(const char *path, struct svc_req *rqstp, + char **password, uint32 *fsid) +{ + e_item *list; + struct in_addr remote; + unsigned int last_len = 0; + + exports_opts = -1; + export_path = NULL; + export_fsid = 0; + last_anonuid = ANON_NOTSPECIAL; + last_anongid = ANON_NOTSPECIAL; + + /* check for client attempting to use invalid pathname */ + if (!path || strstr(path, "/../")) + return exports_opts; + + remote = get_remote(rqstp); + + /* protect against SIGHUP reloading the list */ + exports_access = TRUE; + + list = export_list; + while (list) { + /* longest matching prefix wins */ + if (strlen(list->path) > last_len && +#ifndef WIN32 + strstr(path, list->path) == path) { +#else + !win_utf8ncasecmp(path, list->path, strlen(list->path))) { +#endif + e_host* cur_host = find_host(remote, list, password, &export_password_hash); + + if (fsid != NULL) + *fsid = list->fsid; + if (cur_host) { + exports_opts = cur_host->options; + export_path = list->path; + export_fsid = list->fsid; + last_len = strlen(list->path); + last_anonuid = cur_host->anonuid; + last_anongid = cur_host->anongid; + } + } + list = (e_item *) list->next; + } + exports_access = FALSE; + return exports_opts; +} + +/* + * check whether path is an export point + */ +int export_point(const char *path) +{ + e_item *list; + + exports_access = TRUE; + list = export_list; + + while (list) { + if (strcmp(path, list->path) == 0) { + exports_access = FALSE; + return TRUE; + } + list = (e_item *) list->next; + } + exports_access = FALSE; + return FALSE; +} + +/* + * return exported path from static fsid + */ +char *export_point_from_fsid(uint32 fsid, time_t **last_mtime, uint32 **dir_hash) +{ + e_item *list; + + exports_access = TRUE; + list = export_list; + + while (list) { + if (list->fsid == fsid) { + if (last_mtime != NULL) + *last_mtime = &list->last_mtime; + if (dir_hash != NULL) + *dir_hash = &list->dir_hash; + exports_access = FALSE; + return list->path; + } + list = (e_item *) list->next; + } + exports_access = FALSE; + return NULL; +} + + +/* + * check whether export options of a path match with last set of options + */ +nfsstat3 exports_compat(const char *path, struct svc_req *rqstp) +{ + int prev; + uint32 prev_anonuid, prev_anongid; + + prev = exports_opts; + prev_anonuid = last_anonuid; + prev_anongid = last_anongid; + + if (exports_options(path, rqstp, NULL, NULL) == prev && + last_anonuid == prev_anonuid && + last_anongid == prev_anongid) + return NFS3_OK; + else if (exports_opts == -1) + return NFS3ERR_ACCES; + else + return NFS3ERR_XDEV; +} + +/* + * check whether options indicate rw mount + */ +nfsstat3 exports_rw(void) +{ + if (exports_opts != -1 && (exports_opts & OPT_RW)) + return NFS3_OK; + else + return NFS3ERR_ROFS; +} + +/* + * returns the last looked-up anonuid for a mount (ANON_NOTSPECIAL means none in effect) + */ +uint32 exports_anonuid(void) +{ + return last_anonuid; +} + +/* + * returns the last looked-up anongid for a mount (ANON_NOTSPECIAL means none in effect) + */ +uint32 exports_anongid(void) +{ + return last_anongid; +} diff --git a/unfs3/Extras/Makefile.in b/unfs3/Extras/Makefile.in new file mode 100644 index 0000000..038f10c --- /dev/null +++ b/unfs3/Extras/Makefile.in @@ -0,0 +1,23 @@ +CC = @CC@ +CFLAGS = @CFLAGS@ +AR = ar +RM = rm -f + +SOURCES = cluster.c +OBJS = cluster.o + +all: lib.a + +lib.a: $(OBJS) + $(AR) crs lib.a $(OBJS) + +dep: $(SOURCES) + $(CC) $(CFLAGS) -MM $(SOURCES) >> Makefile + +clean: + $(RM) $(OBJS) lib.a + +distclean: + $(RM) Makefile + +# automatically generated dependencies follow diff --git a/unfs3/Extras/cluster.c b/unfs3/Extras/cluster.c new file mode 100644 index 0000000..3dd5628 --- /dev/null +++ b/unfs3/Extras/cluster.c @@ -0,0 +1,512 @@ + +/* + * UNFS3 cluster support + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "../config.h" + +#ifdef WANT_CLUSTER + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../nfs.h" +#include "../daemon.h" +#include "../backend.h" +#include "cluster.h" + +/* array of dirents prefixed with master file name */ +static char **cluster_dirents = NULL; + +/* number of dirents in above array */ +static int cluster_count = -1; + +/* + * check whether given pathname is in clustering path + */ +int want_cluster(const char *path) +{ + char buf[NFS_MAXPATHLEN]; + char *last, *next; + + /* if path is too long, play it safe */ + if (strlen(opt_cluster_path) + 1 > NFS_MAXPATHLEN) + return TRUE; + + strcpy(buf, opt_cluster_path); + last = buf; + + /* iterate over colon-seperated list */ + do { + next = strchr(last, ':'); + if (next) + *next = 0; + + if (strstr(path, last) == path) + return TRUE; + + if (next) { + last = next + 1; + if (strlen(last) == 0) + last = NULL; + } else { + last = NULL; + } + } while (last); + + return FALSE; +} + +/* + * get name of remote machine + */ +static char *get_host(struct in_addr remote) +{ + static char buf[NFS_MAXPATHLEN]; + struct hostent *entry; + char *dot; + + entry = gethostbyaddr((char *) &remote, sizeof(struct in_addr), AF_INET); + + if (entry) { + strcpy(buf, entry->h_name); + + /* have the name string end at the first dot */ + dot = strchr(buf, '.'); + if (dot) + *dot = 0; + + return buf; + } + + return NULL; +} + +/* + * check whether name is already host tagged name + */ +int is_host(const char *name) +{ + return (int) (strstr(name, "$$HOST=") && name[strlen(name) - 1] == '$' && + name[strlen(name) - 2] == '$'); +} + +/* + * check whether a hostname matches a dirent + */ +char *match_host(const char *hname, const char *entry) +{ + char buf[NFS_MAXPATHLEN]; + static char *part; + + /* check for presence of hostname tag */ + if (!is_host(entry)) + return NULL; + + part = strstr(entry, "$$HOST="); + + /* copy hostname part of host tag */ + memcpy(buf, part + 7, strlen(part) - 8); + buf[strlen(part) - 9] = 0; + + /* exact match? */ + if (strcmp(buf, hname) == 0) + return part; + + /* wildcard pattern? */ + if (buf[strlen(buf) - 1] != '*') + return NULL; + + /* if wildcard, check for matching prefix */ + buf[strlen(buf) - 1] = 0; + if (strstr(hname, buf) == hname) + return part; + + return NULL; +} + +/* + * better dirname providing internal buffer + */ +char *cluster_dirname(const char *path) +{ + static char buf[NFS_MAXPATHLEN]; + + strcpy(buf, path); + return dirname(buf); +} + +/* + * better basename providing internal buffer + */ +char *cluster_basename(const char *path) +{ + static char buf[NFS_MAXPATHLEN]; + + strcpy(buf, path); + return basename(buf); +} + +/* + * free dirent array + */ +void cluster_freedir(void) +{ + /* only if it was really allocated before */ + if (cluster_dirents) { + while (cluster_count--) + free(cluster_dirents[cluster_count]); + free(cluster_dirents); + cluster_dirents = NULL; + } +} + +/* + * compare function for qsort'ing the scandir list + */ +int compar(const void *x, const void *y) +{ + return strcmp(*(const char **) x, *(const char **) y); +} + +/* + * reset euid/egid to specific values + */ +static void reset_ids(uid_t euid, gid_t egid) +{ + if (backend_setegid(egid) || backend_seteuid(euid)) { + logmsg(LOG_EMERG, "euid/egid switching failed, aborting"); + daemon_exit(CRISIS); + } +} + +/* + * scan directory for filenames beginning with master name as prefix + */ +void cluster_scandir(const char *path) +{ + char prefix[NFS_MAXPATHLEN]; + DIR *scan; + struct dirent *entry; + char **new, *name; + uid_t euid; + gid_t egid; + + strcpy(prefix, cluster_basename(path)); + + /* + * need to read directory as root, temporarily switch back + */ + euid = backend_geteuid(); + egid = backend_getegid(); + backend_setegid(0); + backend_seteuid(0); + + scan = backend_opendir(cluster_dirname(path)); + if (!scan) { + cluster_count = -1; + reset_ids(euid, egid); + return; + } + + cluster_count = 0; + while ((entry = backend_readdir(scan))) { + if (strstr(entry->d_name, prefix) != entry->d_name && + strcmp(entry->d_name, "$$CREATE=IP$$") != 0 && + strcmp(entry->d_name, "$$CREATE=CLIENT$$") != 0 && + strcmp(entry->d_name, "$$ALWAYS=IP$$") != 0 && + strcmp(entry->d_name, "$$ALWAYS=CLIENT$$") != 0) + continue; + + name = malloc(strlen(entry->d_name) + 1); + new = realloc(cluster_dirents, (cluster_count + 1) * sizeof(char *)); + if (!new || !name) { + cluster_freedir(); + cluster_count = -1; + free(new); + free(name); + backend_closedir(scan); + reset_ids(euid, egid); + return; + } + + strcpy(name, entry->d_name); + cluster_dirents = new; + cluster_dirents[cluster_count] = name; + cluster_count++; + } + + backend_closedir(scan); + reset_ids(euid, egid); + + /* list needs to be sorted for cluster_lookup_lowlevel to work */ + qsort(cluster_dirents, cluster_count, sizeof(char *), compar); +} + +/* + * check whether master name + suffix matches with a string + */ +int match_suffix(const char *master, const char *suffix, const char *entry) +{ + char obj[NFS_MAXPATHLEN]; + + sprintf(obj, "%s%s", master, suffix); + + if (strcmp(entry, obj) == 0) + return CLU_SLAVE; + else + return FALSE; +} + +/* + * create string version of a netmask + * buf: where to put string + * remote: full IP address of remote machine + * n: number of dots to keep + */ +void cluster_netmask(char *buf, const char *remote, int n) +{ + int i; + + sprintf(buf, "$$IP=%s", remote); + + /* skip to desired dot position */ + for (i = 0; i < n; i++) + buf = strchr(buf, '.') + 1; + + *buf-- = 0; + + /* append trailer of netmask string */ + switch (n) { + case 3: + strcat(buf, "0_24$$"); + break; + case 2: + strcat(buf, "0.0_16$$"); + break; + case 1: + strcat(buf, "0.0.0_8$$"); + break; + } +} + +/* + * look up cluster name, defaulting to master name if no slave name found + */ +int cluster_lookup_lowlevel(char *path, struct svc_req *rqstp) +{ + struct in_addr raddr; + char *remote, *hname, *master, *entry, *match; + char buf[NFS_MAXPATHLEN]; + int i, res = CLU_MASTER; + + cluster_freedir(); + cluster_scandir(path); + + if (cluster_count == -1) + return CLU_IO; + else if (cluster_count == 0) + return CLU_MASTER; + + raddr = get_remote(rqstp); /* remote IP address */ + master = cluster_basename(path); /* master file name */ + remote = inet_ntoa(raddr); /* remote IP address string */ + hname = get_host(raddr); /* remote hostname */ + + /* + * traversal in reverse alphanumerical order, so that + * IP is encountered before HOST, HOST before CLIENT, + * CLIENT before ALWAYS, and also subnets are encountered + * in the right order + */ + i = cluster_count; + while (i--) { + entry = cluster_dirents[i]; + + /* match specific IP address */ + sprintf(buf, "$$IP=%s$$", remote); + if ((res = match_suffix(master, buf, entry))) + break; + + /* always match IP file */ + if ((res = match_suffix(master, "$$ALWAYS=IP$$", entry))) + break; + if (strcmp("$$ALWAYS=IP$$", entry) == 0) { + res = CLU_SLAVE; + break; + } + + /* match all clients */ + strcpy(buf, "$$CLIENT$$"); + if ((res = match_suffix(master, buf, entry))) + break; + + /* always match CLIENT file */ + if ((res = match_suffix(master, "$$ALWAYS=CLIENT$$", entry))) + break; + if (strcmp("$$ALWAYS=CLIENT$$", entry) == 0) { + res = CLU_SLAVE; + break; + } + + /* match 24 bit network address */ + cluster_netmask(buf, remote, 3); + if ((res = match_suffix(master, buf, entry))) + break; + + /* match 16 bit network address */ + cluster_netmask(buf, remote, 2); + if ((res = match_suffix(master, buf, entry))) + break; + + /* match 8 bit network address */ + cluster_netmask(buf, remote, 1); + if ((res = match_suffix(master, buf, entry))) + break; + + /* match hostname pattern */ + if (!is_host(master)) { + match = match_host(hname, entry); + if (match) { + res = CLU_SLAVE; + strcpy(buf, match); + break; + } + } + } + + /* append suffix if possible */ + if (res == CLU_SLAVE) { + if (strlen(path) + strlen(buf) + 1 < NFS_MAXPATHLEN) + strcat(path, buf); + else + res = CLU_TOOLONG; + } else { + /* res will be 0 after above loop */ + res = CLU_MASTER; + } + + /* + * dirent array not freed here since cluster_create may need + * to look at it afterwards + */ + + return res; +} + +/* + * substitute slave filename if possible + */ +void cluster_lookup(char *path, struct svc_req *rqstp, nfsstat3 * nstat) +{ + int res; + + if (!opt_cluster) + return; + + if (!path) + return; + + if (*nstat != NFS3_OK) + return; + + if (!want_cluster(path)) + return; + + res = strlen(path); + if (strstr(path, "$$$$") == path + res - 4) { + *(path + res - 4) = 0; + return; + } + + res = cluster_lookup_lowlevel(path, rqstp); + if (res == CLU_TOOLONG) + *nstat = NFS3ERR_NAMETOOLONG; + else if (res == CLU_IO) + *nstat = NFS3ERR_IO; +} + +/* + * substitute slave filename if possible, for create operations + */ +void cluster_create(char *path, struct svc_req *rqstp, nfsstat3 * nstat) +{ + int i, res; + char buf[NFS_MAXPATHLEN]; + char *master, *entry; + + if (!opt_cluster) + return; + + if (*nstat != NFS3_OK) + return; + + if (!want_cluster(path)) + return; + + res = cluster_lookup_lowlevel(path, rqstp); + + if (res == CLU_TOOLONG) { + *nstat = NFS3ERR_NAMETOOLONG; + return; + } else if (res == CLU_IO) { + *nstat = NFS3ERR_IO; + return; + } else if (res == CLU_SLAVE) + return; + + master = cluster_basename(path); + + /* look for create tag */ + i = cluster_count; + while (i--) { + entry = cluster_dirents[i]; + + /* always create IP file */ + sprintf(buf, "$$IP=%s$$", inet_ntoa(get_remote(rqstp))); + if ((res = match_suffix(master, "$$CREATE=IP$$", entry)) || + (res = match_suffix(master, "$$ALWAYS=IP$$", entry))) + break; + if ((strcmp("$$CREATE=IP$$", entry) == 0) || + (strcmp("$$ALWAYS=IP$$", entry) == 0)) { + res = CLU_SLAVE; + break; + } + + /* always create CLIENT file */ + sprintf(buf, "$$CLIENT$$"); + if ((res = match_suffix(master, "$$CREATE=CLIENT$$", entry)) || + (res = match_suffix(master, "$$ALWAYS=CLIENT$$", entry))) + break; + if ((strcmp("$$CREATE=CLIENT$$", entry) == 0) || + (strcmp("$$ALWAYS=CLIENT$$", entry) == 0)) { + res = CLU_SLAVE; + break; + } + } + + if (res != CLU_SLAVE) + return; + + /* append suffix if possible */ + if (strlen(path) + strlen(buf) + 1 < NFS_MAXPATHLEN) + strcat(path, buf); + else + *nstat = NFS3ERR_NAMETOOLONG; +} + +#endif diff --git a/unfs3/Extras/cluster.h b/unfs3/Extras/cluster.h new file mode 100644 index 0000000..d892e2e --- /dev/null +++ b/unfs3/Extras/cluster.h @@ -0,0 +1,27 @@ +/* + * UNFS3 cluster extensions + * (C) 2003, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_CLUSTER_H +#define UNFS3_CLUSTER_H + +#ifdef WANT_CLUSTER + +#define CLU_TOOLONG 0 /* name got too long */ +#define CLU_SLAVE 1 /* slave file matched */ +#define CLU_MASTER 2 /* master file matched */ +#define CLU_IO 3 /* I/O error */ + +void cluster_lookup(char *path, struct svc_req *rqstp, nfsstat3 *nstat); +void cluster_create(char *path, struct svc_req *rqstp, nfsstat3 *nstat); + +#else + +#define cluster_lookup(x,y,z) +#define cluster_create(x,y,z) + +#endif + +#endif diff --git a/unfs3/Extras/tags.7 b/unfs3/Extras/tags.7 new file mode 100644 index 0000000..b95c2f3 --- /dev/null +++ b/unfs3/Extras/tags.7 @@ -0,0 +1,123 @@ +.\" +.\" (C) 2004, Pascal Schmidt +.\" +.TH tags 7 "04 Jan 2004" +.SH NAME +tags \- tagged files used for clustering extensions +.SH DESCRIPTION +Tagged files are used by +.B ClusterNFS +and +.B unfs3 +to support NFS exporting directories like +.I /etc +and +.I /var +to a cluster of client machines. The problem at hand is that different +files need to be served to different clients. Tagged files provide a +way to specify which file should be served to which client(s). +.P +Tags are appended to the end of a filename and are seperated from the +rest of the name by beginning and ending with $$. For each file, there +can be multiple tagged variants. The normal file, without a tag, is +only served to clients by default when no tagged file matching the client is +found. The following tags exist: +.TP +.B file$$$$ +If a client attempts to access this file, it will be redirected to the +normal file instead, no matter what other tagged files exist. This +is mainly useful for use inside symlinks that need to point to a normal +file although other access to the normal file should be redirected. In +this special case, the tagged file +.B file$$$$ +does not even need to exist (the symlink will then seem to be dangling +on the server). +.TP +.B file$$IP=a.b.c.d$$ +If a client with an IP address of +.I a.b.c.d +attempts to access the normal file, +it will be redirected to this file instead. +.TP +.B file$$IP=a.b.c.d_n$$ +If a client with an IP adress in the network +.I a.b.c.d/n +attempts to +access the normal file, it will be redirected to this file instead. Note that +.B unfs3 +only supports 8, 16, and 24 as values for +.BR n . +.TP +.B file$$HOST=name$$ +If a client with the hostname +.I name +attempts to access the normal file, it will be redirected to this file instead. +.TP +.B file$$HOST=name*$$ +If a client whose hostname begins with the string +.I name +attempts to access the normal file, it will be redirected to this file instead. +.TP +.B file$$CLIENT$$ +If any client attempts to access the normal file, it will be redirected to this +file instead. +.TP +.B file$$ALWAYS=IP$$ +If any client attempts to access or create the normal file, it will be redirected to +.B file$$IP=a.b.c.d$$ +instead, where +.I a.b.c.d +is the IP address of the client. It does not matter whether the target +tagged file exists or not. +.TP +.B file$$ALWAYS=CLIENT$$ +If any client attempts to access or create the normal file, it will be redirected to +.B file$$CLIENT$$ +instead. It does not matter whether that file exists or not. +.TP +.B $$ALWAYS=CLIENT$$ +Like above, but effective for all files in the directory where it is found. +.TP +.B $$ALWAYS=IP$$ +Like above, but effective for all files in the directory where it is found. +.PP +Note that the ALWAYS tag can lead to file not found errors on clients +if the tagged files it redirects to does not exist on the server. For +example, +.BR ls (1) +can suffer from this problem. Furthermore, this tag is a +.B unfs3 +extension and does not exist in +.BR ClusterNFS . +When this tags exists, it prevents all access to the normal file by any +client. +.TP +.B file$$CREATE=IP$$ +If any client attempts to create the normal file, +.B file$$IP=a.b.c.d$$ +will be created instead, where +.I a.b.c.d +is the IP address of the client. +.TP +.B file$$CREATE=CLIENT$$ +If any client attempts to create the normal file, +.B file$$CLIENT$$ +will be created instead. +.TP +.B $$CREATE=IP$$ +Like above, but effective for all files in the directory where it is found. +.TP +.B $$CREATE=CLIENT$$ +Like above, but effective for all files in the directory where it is found. +.PP +Tags work for all kinds of named filesystem objects. +If multiple tagged files +are found for a normal file, they are considered in the order they are +given above, starting at the top. Processing stops once a match is found. +In +.BR ClusterNFS ", but not in " unfs3 , +only files accessible and readable by a client are considered matches. +.SH AUTHOR +Pascal Schmidt +.SH "SEE ALSO" +.BR unfsd (8) diff --git a/unfs3/LICENSE b/unfs3/LICENSE new file mode 100644 index 0000000..7f2b53f --- /dev/null +++ b/unfs3/LICENSE @@ -0,0 +1,24 @@ +UNFS3 user-space NFSv3 server +(C) 2003, Pascal Schmidt + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; +OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR +OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/unfs3/Makefile.in b/unfs3/Makefile.in new file mode 100644 index 0000000..551aa22 --- /dev/null +++ b/unfs3/Makefile.in @@ -0,0 +1,158 @@ +CC = @CC@ +CFLAGS = @CFLAGS@ -D_GNU_SOURCE +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +VERSION = @PACKAGE_VERSION@ +RM = rm -f +MAKE = make + +SOURCES = attr.c daemon.c error.c fd_cache.c fh.c fh_cache.c locate.c \ + md5.c mount.c nfs.c password.c readdir.c user.c xdr.c winsupport.c +OBJS = attr.o daemon.o error.o fd_cache.o fh.o fh_cache.o locate.o \ + md5.o mount.o nfs.o password.o readdir.o user.o xdr.o winsupport.o +CONFOBJ = Config/lib.a +EXTRAOBJ = @EXTRAOBJ@ +LDFLAGS = @LDFLAGS@ @LIBS@ @LEXLIB@ +EXEEXT = @EXEEXT@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +sbindir = @sbindir@ +mandir = @mandir@ +datarootdir = @datarootdir@ + +SUBDIRS = Config @SUBDIRS@ + +DESTDIR = + +all: subdirs unfsd$(EXEEXT) + +unfsd$(EXEEXT): $(OBJS) $(CONFOBJ) $(EXTRAOBJ) + $(CC) -o $@ $(OBJS) $(CONFOBJ) $(EXTRAOBJ) $(LDFLAGS) + +subdirs: + for i in $(SUBDIRS); do cd $$i; $(MAKE) all; cd ..; done + +install: unfsd$(EXEEXT) + $(INSTALL) -d $(DESTDIR)$(sbindir) + $(INSTALL) -d $(DESTDIR)$(mandir)/man7 + $(INSTALL) -d $(DESTDIR)$(mandir)/man8 + $(INSTALL) unfsd$(EXEEXT) $(DESTDIR)$(sbindir)/unfsd$(EXEEXT) + $(INSTALL_DATA) Extras/tags.7 $(DESTDIR)$(mandir)/man7/tags.7 + $(INSTALL_DATA) unfsd.8 $(DESTDIR)$(mandir)/man8/unfsd.8 + +# Not installed by default, since it installs files outside prefix +install-init: unfsd.init + $(INSTALL) -d $(DESTDIR)/etc/init.d + $(INSTALL) unfsd.init $(DESTDIR)/etc/init.d/unfsd + +install-strip: install + strip $(DESTDIR)$(sbindir)/unfsd$(EXEEXT) + +uninstall: + $(RM) $(DESTDIR)$(sbindir)/unfsd$(EXEEXT) + $(RM) $(DESTDIR)$(mandir)/man7/tags.7 + $(RM) $(DESTDIR)$(mandir)/man8/unfsd.8 + +clean: + for i in $(SUBDIRS); do cd $$i; $(MAKE) clean; cd ..; done + $(RM) $(OBJS) + $(RM) unfsd$(EXEEXT) + $(RM) unfs3-$(VERSION).tar.gz + +distclean: clean + for i in $(SUBDIRS); do cd $$i; $(MAKE) distclean; cd ..; done + $(RM) Makefile config.h + $(RM) config.log config.status + +maintainer-clean: distclean + $(RM) config.h.in configure + $(RM) -rf autom4te.cache + +dep: $(SOURCES) + for i in $(SUBDIRS); do cd $$i; $(MAKE) dep; cd ..; done + $(CC) $(CFLAGS) -MM $(SOURCES) >> Makefile + +.PHONY: dist unfs3-$(VERSION).tar.gz + +dist: unfs3-$(VERSION).tar.gz + +unfs3-$(VERSION).tar.gz: + rm -rf /tmp/unfs3-make-dist-dir + mkdir /tmp/unfs3-make-dist-dir + ln -sf `pwd` /tmp/unfs3-make-dist-dir/unfs3-$(VERSION) + (cd /tmp/unfs3-make-dist-dir; \ + tar zcf unfs3-$(VERSION)/unfs3-$(VERSION).tar.gz \ + unfs3-$(VERSION)/fd_cache.c \ + unfs3-$(VERSION)/md5.h \ + unfs3-$(VERSION)/xdr.h \ + unfs3-$(VERSION)/attr.c \ + unfs3-$(VERSION)/README \ + unfs3-$(VERSION)/backend.h \ + unfs3-$(VERSION)/password.c \ + unfs3-$(VERSION)/README.nfsroot \ + unfs3-$(VERSION)/error.c \ + unfs3-$(VERSION)/winsupport.c \ + unfs3-$(VERSION)/fh_cache.h \ + unfs3-$(VERSION)/user.c \ + unfs3-$(VERSION)/unfs3.spec \ + unfs3-$(VERSION)/winsupport.h \ + unfs3-$(VERSION)/readdir.h \ + unfs3-$(VERSION)/nfs.c \ + unfs3-$(VERSION)/configure \ + unfs3-$(VERSION)/xdr.c \ + unfs3-$(VERSION)/install-sh \ + unfs3-$(VERSION)/mount.c \ + unfs3-$(VERSION)/password.h \ + unfs3-$(VERSION)/Extras/Makefile.in \ + unfs3-$(VERSION)/Extras/cluster.c \ + unfs3-$(VERSION)/Extras/tags.7 \ + unfs3-$(VERSION)/Extras/cluster.h \ + unfs3-$(VERSION)/NEWS \ + unfs3-$(VERSION)/CREDITS \ + unfs3-$(VERSION)/aclocal.m4 \ + unfs3-$(VERSION)/daemon.h \ + unfs3-$(VERSION)/doc/TODO \ + unfs3-$(VERSION)/doc/README.win \ + unfs3-$(VERSION)/doc/kirch1.txt \ + unfs3-$(VERSION)/doc/passwords.txt \ + unfs3-$(VERSION)/unfsd.8 \ + unfs3-$(VERSION)/Makefile.in \ + unfs3-$(VERSION)/unfsd.init \ + unfs3-$(VERSION)/backend_win32.h \ + unfs3-$(VERSION)/indent-all \ + unfs3-$(VERSION)/backend_unix.h \ + unfs3-$(VERSION)/nfs.h \ + unfs3-$(VERSION)/locate.c \ + unfs3-$(VERSION)/BRANCHES \ + unfs3-$(VERSION)/fd_cache.h \ + unfs3-$(VERSION)/daemon.c \ + unfs3-$(VERSION)/error.h \ + unfs3-$(VERSION)/contrib/nfsotpclient/README \ + unfs3-$(VERSION)/contrib/nfsotpclient/mountclient \ + unfs3-$(VERSION)/contrib/nfsotpclient/mountclient/__init__.py \ + unfs3-$(VERSION)/contrib/nfsotpclient/mountclient/mountpacker.py \ + unfs3-$(VERSION)/contrib/nfsotpclient/mountclient/mountconstants.py \ + unfs3-$(VERSION)/contrib/nfsotpclient/mountclient/mounttypes.py \ + unfs3-$(VERSION)/contrib/nfsotpclient/nfsotpclient.py \ + unfs3-$(VERSION)/contrib/nfsotpclient/rpc.py \ + unfs3-$(VERSION)/contrib/rpcproxy/rpcproxy \ + unfs3-$(VERSION)/LICENSE \ + unfs3-$(VERSION)/fh.h \ + unfs3-$(VERSION)/fh.c \ + unfs3-$(VERSION)/Config/exports.y \ + unfs3-$(VERSION)/Config/exports.l \ + unfs3-$(VERSION)/Config/exports.h \ + unfs3-$(VERSION)/Config/Makefile.in \ + unfs3-$(VERSION)/locate.h \ + unfs3-$(VERSION)/md5.c \ + unfs3-$(VERSION)/fh_cache.c \ + unfs3-$(VERSION)/config.h.in \ + unfs3-$(VERSION)/attr.h \ + unfs3-$(VERSION)/configure.ac \ + unfs3-$(VERSION)/mount.h \ + unfs3-$(VERSION)/readdir.c \ + unfs3-$(VERSION)/user.h) + rm -rf /tmp/unfs3-make-dist-dir + +# automatically generated dependencies follow diff --git a/unfs3/NEWS b/unfs3/NEWS new file mode 100644 index 0000000..231eaad --- /dev/null +++ b/unfs3/NEWS @@ -0,0 +1,242 @@ +What's new or changed in 0.9.22 +=============================== + +Garrett Cooper reported that Andy Levine found a bug +where the "no_all_squash" option is unusable due to a +spelling mistake in the options parser. This is fixed now. + +Wesley Shields reported build problems on more recent +FreeBSD systems which are fixed now. + +Bernhard Duebi reported problems with filesystem size +reporting when using a Solaris Zone. This is fixed now. + +The BUGS section of the manpage has been updated to +explicitly list the permissions that UNFS3 will need +for exported directories and the parents of exported +directories. + + +ChangeLog +========= + +Version 0.9.22 + + - fix spelling mistake in "no_all_squash" export option parsing + - fix build on more recent FreeBSD systems + - fix filesystem size reporting for Solaris Zones and others + - document permission needs for exported directories + +Version 0.9.21 + + - avoid returning large fileids on Windows, for better compatibility + with clients such as Linux 2.6.24 + - try to prevent races between READDIR and removal of files + +Version 0.9.20 + + - fix LOOKUP permission reporting on execute-bit-only directories + - fix writing of files opened for writing with intervening chmod -w + - fix reading of files opened for reading with intervening chmod -r + +Version 0.9.19 + + - fix chown operation on symbolic links + - fix auxiliary group support + +Version 0.9.18 + + - add support for writing a pid file with the -i option + - fix atomic_attr() to respect uid/gid squashing + - add -T option for doing test parse of the exports file + +Version 0.9.17 + + - add support for 64 bit inode numbers + - the returned "fileid" is now equal to the file's real inode number + - fix ACCESS and read_executable to stop adding permissions when user or + group matches + - report unreadable executables as unreadable unless -r is used + - support for using larger read and write sizes: up to 32K for UDP and + 512K for TCP + - add support for "anonuid" and "anongid" export options + - add Windows support + - improve error reporting for WRITE and COMMIT requests + - improve file descriptor cache to not keep files open forever + +Version 0.9.16 + + - add support for "insecure" and "secure" export options + - do not abort daemon on RPC or XDR failures + +Version 0.9.15 + + - only allow mount requests from source ports below 1024 + +Version 0.9.14 + + - accept SET_TO_SERVER_TIME in object creation calls + - update maintainer email address + +Version 0.9.13 + + - add support for CREATE EXCLUSIVE procedure call + - fix some minor compiler warnings + +Version 0.9.12 + + - add option for binding to a specified interface + - lots of compile fixes for Solaris/AIX/Irix/Mac OS X + - make redirection of operating system calls possible + - fix READDIR error reporting + - fix handling of . and .. lookups for Irix clients + +Version 0.9.11 + + - handle case where a tagged file exists but the master file doesn't + - make clustering work in non-readable directories + - make filehandle resolution work on non-readable directories + - fix file creation by Solaris NFS clients + +Version 0.9.10 + + - fix building with gcc 2.95.x or 2.96 + - make ALWAYS cluster tag take effect for file creations + - fix possible use-after-free bug in fh.c:fh_rec + +Version 0.9.9 + + - add support for mount passwords, for use with secure links + - make exports parser accept dashes in hostnames and leading whitespace + - fix debug mode to use line buffering, useful for redirections + - make exporting of (automounted) removable media possible + +Version 0.9.8 + + - fix cache LRU algorithm, could lead to unreliable operations once + the filehandle cache filled up + +Version 0.9.7 + + - make renames across directories not cause stale filehandles + - allow clients to read files they only have execute permission for + - lift restrictions on attribute setting + - fix bug in special-casing of root directory filehandles + - add file$$$$ tag to clustering extensions + +Version 0.9.6 + + - run the source through indent to improve style consistency + - fix bug in READDIR that resulted in truncated replies + - add options to specify which ports and protocols to use + +Version 0.9.5 + + - code cleanups, remove now impossible cases (stale filehandles) + - fix bug in READDIR that could return EOF one entry too early + +Version 0.9.4 + + - support the DUMP and EXPORT mount protocol procedures + - use a simple counter instead of the system time for cache LRU + - document tagged files in a seperate manpage, tags(7) + - introduce a new ALWAYS tag for forced redirection + +Version 0.9.3 + + - fix mount handler not properly initializing return status + - send messages to syslog for some mount problems + - make it possible to export and mount symlinks to directories + - fix cluster extensions breakage from 0.9.1 code merge + - prevent filehandle cache from storing redundant information + +Version 0.9.2 + + - clean up lots of duplicate code in nfs.c + - move configuration parser and cluster extensions into subdirectories + - use real write verifier in WRITE and COMMIT + +Version 0.9.1 + + - add -d option to prevent forking into background (for debugging) + - merge in lots of cleaner code from the experimental branch + - merge nfsd and mountd into one program + - better /etc/exports parser using lex and yacc + +Version 0.9.0 + + - check for clients attempting to use invalid pathnames + - include cluster extensions (optional at compile and run time) + +Version 0.8.8 + + - fix ACCESS compatibility problem affecting HP-UX clients + +Version 0.8.7 + + - fixed chmod handling to make us pass the Connectathon 2003 NFS + testsuite's "basic" and "general" tests + - improve filehandle integrity checking + +Version 0.8.6 + + - use inode generation numbers only in SETATTR and fd cache because + it is a huge performance hit everywhere else + - use 32 bit device and inode numbers to save space in filehandles + - have nfsd bind to port number 2049 (nfs) by default + +Version 0.8.5 + + - undo refusal to use "." and ".." since it confuses NetBSD clients + - include inode generation number in filehandles whenever possible + +Version 0.8.4 + + - handle export of the root directory correctly + - return XDEV error in RENAME and LINK if export options for given + objects do not match (needed for squash options differences) + - prevent the use of "." and ".." as names + - use largefile API to enable access to files greater than 2 GB + - check filehandles for integrity before using them + - we no longer need GNU make + +Version 0.8.3 + + - use shorter filehandles whenever possible + - use stat cache in unfs3_readdir() + - switch filehandle cache to use static allocation of entries + - make unfs3_readdir() account for XDR overhead correctly + +Version 0.8.2 + + - simplify and speed up low-level filehandle routines + - fix a serious bug in READDIR, cookie == 0 was handled incorrectly + - make it build and run on NetBSD 1.6.1/i386 + +Version 0.8.1 + + - use svc_getcaller instead of our own hack (well, duh) + - don't attempt to service v1 mount calls, only v1 umount + - check incoming object names for validity + +Version 0.8 + + - support for export controls via /etc/exports + - introduce caching of stat() results to improve performance + - explicitly check for gcc in the configure script + - make user/group id squashing be based on export options + - remove the now obsolete -r and -a nfsd options + +Version 0.7 + + - attempt at race protection/detection code for many NFS procedures + - add comments to all error code paths + +Version 0.6.1 + + - document possible races with local fs activity on server + - minor fix in LOOKUP error handling + +Version 0.6 + + - initial public release diff --git a/unfs3/README b/unfs3/README new file mode 100644 index 0000000..d8a7059 --- /dev/null +++ b/unfs3/README @@ -0,0 +1,89 @@ +UNFS3 (User-Space NFSv3 Server) +(C) 2003-2006, Pascal Schmidt + + +INTRODUCTION +============ + +UNFS3 is a user-space implementation of the NFSv3 server +specification. + +UNFS3 supports all NFSv3 procedures with the exception of the +READDIRPLUS procedure. It tries to provide as much information +to NFS clients as possible, within the limits possible from +user-space. + +See the unfsd(8) manpage for restrictions imposed on NFS +operations (section RESTRICTIONS) and for possible races +with local file system activity (section BUGS). + +It is not possible to export to netgroups or wildcard hostnames +via /etc/exports, all other addressing methods should work. The +following options are recognized in the exports file: ro, rw, +root_squash, all_squash, no_root_squash, no_all_squash. If +other options are present, they are ignored. + +Cluster extensions compatible to the older ClusterNFS project +are supported when the source is configured with --enable-cluster. + + +SUPPORTED SYSTEMS +================= + +Linux: compiles and runs, passes Connectathon 2003 NFS + testsuite's "basic" and "general" tests, survives + fsx stress testing + +Solaris: compiles and runs, survives light testing + +NetBSD: compiles and runs, but there are compatibility + problems with the in-kernel NFS client + +AIX: compiles + +Irix: compiles (with gcc and native compiler) + +OS X: compiles + +Note that only Linux support is checked for all releases. If unfs3 +breaks on other platforms, a bug report is appreciated. + + +INSTALLATION +============ + +You will need gcc, lex (flex), and yacc (bison) to compile UNFS3. + + ./configure + make + make install + +Please read the manpage for information about command-line +options. + + man 8 unfsd + +If you decide to modify the code yourself, you can run + + make dep + +to append dependency information to the Makefile, so that make +knows which files depend on each other and recompiles all the +necessary files on changes. + + +CVS REPOSITORY +============== + +The unfs3 CVS repository is accessible via anonymous CVS. The source +can be checked out with: + + cvs -d:pserver:anonymous@cvs.lysator.liu.se:/cvsroot/unfs3 login + cvs -d:pserver:anonymous@cvs.lysator.liu.se:/cvsroot/unfs3 co unfs3 + +You can also use the web-based CVS repository viewer at: + + http://cvs.lysator.liu.se/viewcvs/viewcvs.cgi/?cvsroot=unfs3 + +In the HEAD branch, you will find a file called "BRANCHES", which +describes the different branches in this repository. diff --git a/unfs3/README.nfsroot b/unfs3/README.nfsroot new file mode 100644 index 0000000..6b2fb1b --- /dev/null +++ b/unfs3/README.nfsroot @@ -0,0 +1,44 @@ +Using UNFS3 for Linux nfsroot +============================= + +General information about Linux nfsroot can be found in the +Linux kernel source, in the file Documentation/nfsroot.txt. + +If you want the use the Linux kernel's "nfsroot=" boot option +to use a root directory on an NFS server and use UNFS3 in the +role of the NFS server for that, you need to remember that UNFS3 +only supports NFSv3, not NFSv2. The kernel, on the other hand, +always defaults to using NFSv2. Thus, you need to modify the +nfsroot boot option to force the kernel to use NFSv3. If you do +not do this, an error message like this will appear on the +client machine: + + Looking up port of RPC 1000003/2 on 172.16.100.100 + Root-NFS: Portmapper on server returned 2049 as nfsd port + Looking up port of RPC 1000005/1 on 172.16.100.100 + Root-NFS: mounted port is 2049 + NFS: nfs_mount (ac106464:/nfsroot) + RPC: call_verify: programm 100003 version 2 unsupported by server + nfs_get_root: getattr error = 5 + nfs_read_super: get root inode failed + VFS: Unable to mount root fs via NFS trying floppy + +To fix this problem, append the "v3" NFS option to the nfsroot +boot option. Assuming your NFS server's IP address is 192.168.2.72 +and the path you need to mount is /tftpboot/nfsroot, the boot +option should look like this: + + nfsroot=192.168.2.72:/tftpboot/nfsroot,v3 + +You can add more options to the end, seperated by commas. If you +use DHCP to pass the NFS server configuration to the client, you +need to use a line like this in the /etc/dhcpd.conf settings +for the client machine: + + option root-path "/tftpboot/nfsroot,v3"; + +As above, more options can be added to the end, sepereated by +commas. + +Thanks go to Jean Aumont for suggesting +this bit of information to be documented. diff --git a/unfs3/aclocal.m4 b/unfs3/aclocal.m4 new file mode 100644 index 0000000..1a2845e --- /dev/null +++ b/unfs3/aclocal.m4 @@ -0,0 +1,25 @@ +dnl Special rpc library for Solaris +dnl +AC_DEFUN([UNFS3_SOLARIS_RPC],[ + AC_CHECK_FUNC(svc_tli_create, [ + # On Solaris, you must link with librpcsoc, or the binaries won't work. + LDFLAGS="-L/usr/ucblib -R/usr/ucblib $LDFLAGS" + AC_CHECK_LIB(rpcsoc, svctcp_create, + [ LIBS="-lrpcsoc $LIBS" ], + [ AC_MSG_WARN([*** Cannot find librpcsoc. On Solaris, install package SUNWscpu. ***]) ] + ) + ]) +]) +dnl PORTMAP define needed for Solaris +dnl +AC_DEFUN([UNFS3_PORTMAP_DEFINE],[ + AC_DEFINE([PORTMAP], [], [Define to an empty value if you use Solaris.]) +]) +dnl Set compiler warnings for gcc +dnl +AC_DEFUN([UNFS3_COMPILE_WARNINGS],[ + if test "$GCC" = "yes" + then + CFLAGS="$CFLAGS -Wall -W" + fi +]) diff --git a/unfs3/attr.c b/unfs3/attr.c new file mode 100644 index 0000000..2653ed0 --- /dev/null +++ b/unfs3/attr.c @@ -0,0 +1,496 @@ + +/* + * UNFS3 attribute handling + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#endif +#include +#include + +#include "backend.h" +#include "nfs.h" +#include "attr.h" +#include "error.h" +#include "fh.h" +#include "fh_cache.h" +#include "daemon.h" +#include "user.h" +#include "Config/exports.h" + +/* + * check whether stat_cache is for a regular file + * + * fh_decomp must be called before to fill the stat cache + */ +nfsstat3 is_reg(void) +{ + if (!st_cache_valid) + return NFS3ERR_STALE; + else if (S_ISREG(st_cache.st_mode)) + return NFS3_OK; + else + return NFS3ERR_INVAL; +} + +/* + * find stat bit corresponding to given NFS file type + */ +mode_t type_to_mode(ftype3 ftype) +{ + switch (ftype) { + case NF3REG: + return S_IFREG; + case NF3DIR: + return S_IFDIR; + case NF3LNK: + return S_IFLNK; + case NF3CHR: + return S_IFCHR; + case NF3BLK: + return S_IFBLK; + case NF3FIFO: + return S_IFIFO; + case NF3SOCK: + return S_IFSOCK; + } + + /* fix gcc warning */ + return 0; +} + +/* + * post_op_attr for error returns + */ +#ifdef __GNUC__ +static post_op_attr error_attr = {.attributes_follow = FALSE }; +#else +static post_op_attr error_attr = { FALSE }; +#endif + +/* + * return pre-operation attributes + * + * fh_decomp must be called before to fill the stat cache + */ +pre_op_attr get_pre_cached(void) +{ + pre_op_attr result; + + if (!st_cache_valid) { + result.attributes_follow = FALSE; + return result; + } + + result.attributes_follow = TRUE; + + result.pre_op_attr_u.attributes.size = st_cache.st_size; + result.pre_op_attr_u.attributes.mtime.seconds = st_cache.st_mtime; + result.pre_op_attr_u.attributes.mtime.nseconds = 0; + result.pre_op_attr_u.attributes.ctime.seconds = st_cache.st_ctime; + result.pre_op_attr_u.attributes.ctime.nseconds = 0; + + return result; +} + +/* + * compute post-operation attributes given a stat buffer + */ +post_op_attr get_post_buf(backend_statstruct buf, struct svc_req * req) +{ + post_op_attr result; + + result.attributes_follow = TRUE; + + if (S_ISDIR(buf.st_mode)) + result.post_op_attr_u.attributes.type = NF3DIR; + else if (S_ISBLK(buf.st_mode)) + result.post_op_attr_u.attributes.type = NF3BLK; + else if (S_ISCHR(buf.st_mode)) + result.post_op_attr_u.attributes.type = NF3CHR; +#ifdef S_ISLNK + else if (S_ISLNK(buf.st_mode)) + result.post_op_attr_u.attributes.type = NF3LNK; +#endif /* S_ISLNK */ +#ifdef S_ISSOCK + else if (S_ISSOCK(buf.st_mode)) + result.post_op_attr_u.attributes.type = NF3SOCK; +#endif /* S_ISSOCK */ + else if (S_ISFIFO(buf.st_mode)) + result.post_op_attr_u.attributes.type = NF3FIFO; + else + result.post_op_attr_u.attributes.type = NF3REG; + + /* adapt permissions for executable files */ + if (opt_readable_executables && S_ISREG(buf.st_mode)) { + if (buf.st_mode & S_IXUSR) + buf.st_mode |= S_IRUSR; + if (buf.st_mode & S_IXGRP) + buf.st_mode |= S_IRGRP; + if (buf.st_mode & S_IXOTH) + buf.st_mode |= S_IROTH; + } + + result.post_op_attr_u.attributes.mode = buf.st_mode & 0xFFFF; + result.post_op_attr_u.attributes.nlink = buf.st_nlink; + + /* If -s, translate uids */ + if (opt_singleuser) { + unsigned int req_uid = 0; + unsigned int req_gid = 0; + struct authunix_parms *auth = (void *) req->rq_clntcred; + uid_t ruid = backend_getuid(); + + if (req->rq_cred.oa_flavor == AUTH_UNIX) { + req_uid = auth->aup_uid; + req_gid = auth->aup_gid; + } + + if ((buf.st_uid == ruid) || (ruid == 0)) + result.post_op_attr_u.attributes.uid = req_uid; + else + result.post_op_attr_u.attributes.uid = 0; + + if ((buf.st_gid == backend_getgid()) || (ruid == 0)) + result.post_op_attr_u.attributes.gid = req_gid; + else + result.post_op_attr_u.attributes.gid = 0; + } else { + /* Normal case */ + result.post_op_attr_u.attributes.uid = buf.st_uid; + result.post_op_attr_u.attributes.gid = buf.st_gid; + } + + result.post_op_attr_u.attributes.size = buf.st_size; + result.post_op_attr_u.attributes.used = buf.st_blocks * 512; + result.post_op_attr_u.attributes.rdev.specdata1 = + (buf.st_rdev >> 8) & 0xFF; + result.post_op_attr_u.attributes.rdev.specdata2 = buf.st_rdev & 0xFF; + result.post_op_attr_u.attributes.fsid = buf.st_dev; + + /* If this is a removable export point, we should return the preset fsid + for all objects which resides in the same file system as the exported + directory */ + if (exports_opts & OPT_REMOVABLE) { + backend_statstruct epbuf; + + if (backend_lstat(export_path, &epbuf) != -1 && + buf.st_dev == epbuf.st_dev) { + result.post_op_attr_u.attributes.fsid = export_fsid; + } + } +#ifdef WIN32 + /* Recent Linux kernels (2.6.24 and newer) exposes large fileids even to + non-LFS 32-bit applications, unless kernel parameter + nfs.enable_ino64=0. This means that applications will fail with + EOVERFLOW. On Windows, we always have large st_ino:s. To avoid + trouble, we truncate to 32 bits */ + result.post_op_attr_u.attributes.fileid = + (buf.st_ino >> 32) ^ (buf.st_ino & 0xffffffff); +#else + result.post_op_attr_u.attributes.fileid = buf.st_ino; +#endif + result.post_op_attr_u.attributes.atime.seconds = buf.st_atime; + result.post_op_attr_u.attributes.atime.nseconds = 0; + result.post_op_attr_u.attributes.mtime.seconds = buf.st_mtime; + result.post_op_attr_u.attributes.mtime.nseconds = 0; + result.post_op_attr_u.attributes.ctime.seconds = buf.st_ctime; + result.post_op_attr_u.attributes.ctime.nseconds = 0; + + return result; +} + +/* + * lowlevel routine for getting post-operation attributes + */ +static post_op_attr get_post_ll(const char *path, uint32 dev, uint64 ino, + struct svc_req *req) +{ + backend_statstruct buf; + int res; + + if (!path) + return error_attr; + + res = backend_lstat(path, &buf); + if (res == -1) + return error_attr; + + /* protect against local fs race */ + if (dev != buf.st_dev || ino != buf.st_ino) + return error_attr; + + return get_post_buf(buf, req); +} + +/* + * return post-operation attributes, using fh for old dev/ino + */ +post_op_attr get_post_attr(const char *path, nfs_fh3 nfh, + struct svc_req * req) +{ + unfs3_fh_t *fh = (void *) nfh.data.data_val; + + return get_post_ll(path, fh->dev, fh->ino, req); +} + +/* + * return post-operation attributes, using stat cache for old dev/ino + */ +post_op_attr get_post_stat(const char *path, struct svc_req * req) +{ + return get_post_ll(path, st_cache.st_dev, st_cache.st_ino, req); +} + +/* + * return post-operation attributes using stat cache + * + * fd_decomp must be called before to fill the stat cache + */ +post_op_attr get_post_cached(struct svc_req * req) +{ + if (!st_cache_valid) + return error_attr; + + return get_post_buf(st_cache, req); +} + +/* + * setting of time, races with local filesystem + * + * there is no futimes() function in POSIX or Linux + */ +static nfsstat3 set_time(const char *path, backend_statstruct buf, sattr3 new) +{ + time_t new_atime, new_mtime; + struct utimbuf utim; + int res; + + /* set atime and mtime */ + if (new.atime.set_it != DONT_CHANGE || new.mtime.set_it != DONT_CHANGE) { + + /* compute atime to set */ + if (new.atime.set_it == SET_TO_SERVER_TIME) + new_atime = time(NULL); + else if (new.atime.set_it == SET_TO_CLIENT_TIME) + new_atime = new.atime.set_atime_u.atime.seconds; + else /* DONT_CHANGE */ + new_atime = buf.st_atime; + + /* compute mtime to set */ + if (new.mtime.set_it == SET_TO_SERVER_TIME) + new_mtime = time(NULL); + else if (new.mtime.set_it == SET_TO_CLIENT_TIME) + new_mtime = new.mtime.set_mtime_u.mtime.seconds; + else /* DONT_CHANGE */ + new_mtime = buf.st_mtime; + + utim.actime = new_atime; + utim.modtime = new_mtime; + + res = backend_utime(path, &utim); + if (res == -1) + return setattr_err(); + } + + return NFS3_OK; +} + +/* + * race unsafe setting of attributes + */ +static nfsstat3 set_attr_unsafe(const char *path, nfs_fh3 nfh, sattr3 new) +{ + unfs3_fh_t *fh = (void *) nfh.data.data_val; + uid_t new_uid; + gid_t new_gid; + backend_statstruct buf; + int res; + + res = backend_lstat(path, &buf); + if (res != 0) + return NFS3ERR_STALE; + + /* check local fs race */ + if (buf.st_dev != fh->dev || buf.st_ino != fh->ino) + return NFS3ERR_STALE; + + /* set file size */ + if (new.size.set_it == TRUE) { + res = backend_truncate(path, new.size.set_size3_u.size); + if (res == -1) + return setattr_err(); + } + + /* set uid and gid */ + if (new.uid.set_it == TRUE || new.gid.set_it == TRUE) { + if (new.uid.set_it == TRUE) + new_uid = new.uid.set_uid3_u.uid; + else + new_uid = -1; + if (new_uid == buf.st_uid) + new_uid = -1; + + if (new.gid.set_it == TRUE) + new_gid = new.gid.set_gid3_u.gid; + else + new_gid = -1; + + res = backend_lchown(path, new_uid, new_gid); + if (res == -1) + return setattr_err(); + } + + /* set mode */ + if (new.mode.set_it == TRUE) { + res = backend_chmod(path, new.mode.set_mode3_u.mode); + if (res == -1) + return setattr_err(); + } + + return set_time(path, buf, new); +} + +/* + * set attributes of an object + */ +nfsstat3 set_attr(const char *path, nfs_fh3 nfh, sattr3 new) +{ + unfs3_fh_t *fh = (void *) nfh.data.data_val; + int res, fd; + uid_t new_uid; + gid_t new_gid; + backend_statstruct buf; + + res = backend_lstat(path, &buf); + if (res != 0) + return NFS3ERR_STALE; + + /* + * don't open(2) device nodes, it could trigger + * module loading on the server + */ + if (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode)) + return set_attr_unsafe(path, nfh, new); + +#ifdef S_ISLNK + /* + * opening a symlink would open the underlying file, + * don't try to do that + */ + if (S_ISLNK(buf.st_mode)) + return set_attr_unsafe(path, nfh, new); +#endif + + /* + * open object for atomic setting of attributes + */ + fd = backend_open(path, O_WRONLY | O_NONBLOCK); + if (fd == -1) + fd = backend_open(path, O_RDONLY | O_NONBLOCK); + + if (fd == -1) + return set_attr_unsafe(path, nfh, new); + + res = backend_fstat(fd, &buf); + if (res == -1) { + backend_close(fd); + return NFS3ERR_STALE; + } + + /* check local fs race */ + if (fh->dev != buf.st_dev || fh->ino != buf.st_ino || + fh->gen != backend_get_gen(buf, fd, path)) { + backend_close(fd); + return NFS3ERR_STALE; + } + + /* set file size */ + if (new.size.set_it == TRUE) { + res = backend_ftruncate(fd, new.size.set_size3_u.size); + if (res == -1) { + backend_close(fd); + return setattr_err(); + } + } + + /* set uid and gid */ + if (new.uid.set_it == TRUE || new.gid.set_it == TRUE) { + if (new.uid.set_it == TRUE) + new_uid = new.uid.set_uid3_u.uid; + else + new_uid = -1; + if (new_uid == buf.st_uid) + new_uid = -1; + + if (new.gid.set_it == TRUE) + new_gid = new.gid.set_gid3_u.gid; + else + new_gid = -1; + + res = backend_fchown(fd, new_uid, new_gid); + if (res == -1) { + backend_close(fd); + return setattr_err(); + } + } + + /* set mode */ + if (new.mode.set_it == TRUE) { + res = backend_fchmod(fd, new.mode.set_mode3_u.mode); + if (res == -1) { + backend_close(fd); + return setattr_err(); + } + } + + res = backend_close(fd); + if (res == -1) { + /* error on close probably means attributes didn't make it */ + return NFS3ERR_IO; + } + + /* finally, set times */ + return set_time(path, buf, new); +} + +/* + * deduce mode from given settable attributes + * default to rwxrwxr-x if no mode given + */ +mode_t create_mode(sattr3 new) +{ + if (new.mode.set_it == TRUE) + return new.mode.set_mode3_u.mode; + else + return S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | + S_IROTH | S_IXOTH; +} + +/* + * check whether an sattr3 is settable atomically on a create op + */ +nfsstat3 atomic_attr(sattr3 attr) +{ + uid_t used_uid = mangle_uid(attr.uid.set_uid3_u.uid); + gid_t used_gid = mangle_gid(attr.gid.set_gid3_u.gid); + + if ((attr.uid.set_it == TRUE && used_uid != backend_geteuid()) || + (attr.gid.set_it == TRUE && used_gid != backend_getegid()) || + (attr.size.set_it == TRUE && attr.size.set_size3_u.size != 0) || + attr.atime.set_it == SET_TO_CLIENT_TIME || + attr.mtime.set_it == SET_TO_CLIENT_TIME) + return NFS3ERR_INVAL; + else + return NFS3_OK; +} diff --git a/unfs3/attr.h b/unfs3/attr.h new file mode 100644 index 0000000..4b2b0bc --- /dev/null +++ b/unfs3/attr.h @@ -0,0 +1,26 @@ +/* + * UNFS3 attribute handling + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef NFS_ATTR_H +#define NFS_ATTR_H + +nfsstat3 is_reg(void); + +mode_t type_to_mode(ftype3 ftype); + +post_op_attr get_post_attr(const char *path, nfs_fh3 fh, struct svc_req *req); +post_op_attr get_post_stat(const char *path, struct svc_req *req); +post_op_attr get_post_cached(struct svc_req *req); +post_op_attr get_post_buf(backend_statstruct buf, struct svc_req *req); +pre_op_attr get_pre_cached(void); + +nfsstat3 set_attr(const char *path, nfs_fh3 fh, sattr3 sattr); + +mode_t create_mode(sattr3 sattr); + +nfsstat3 atomic_attr(sattr3 sattr); + +#endif diff --git a/unfs3/backend.h b/unfs3/backend.h new file mode 100644 index 0000000..d3c595d --- /dev/null +++ b/unfs3/backend.h @@ -0,0 +1,16 @@ +/* + * UNFS3 low-level filesystem calls + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_BACKEND_H +#define UNFS3_BACKEND_H + +#ifdef WIN32 +#include "backend_win32.h" +#else +#include "backend_unix.h" +#endif /* WIN32 */ + +#endif diff --git a/unfs3/backend_unix.h b/unfs3/backend_unix.h new file mode 100644 index 0000000..713288d --- /dev/null +++ b/unfs3/backend_unix.h @@ -0,0 +1,84 @@ +/* + * UNFS3 low-level filesystem calls for Unix + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_BACKEND_UNIX_H +#define UNFS3_BACKEND_UNIX_H + +/* + * backend init and shutdown + */ +#define backend_init() 1 +#define backend_shutdown() do { } while (0) + +/* + * unfs3 functions + */ +#define backend_get_gen get_gen +#define backend_mksocket mksocket +#define backend_locate_file locate_file + +/* + * system calls + */ +#define backend_chmod chmod +#define backend_chown chown +#define backend_close close +#define backend_closedir closedir +#define backend_fchmod fchmod +#define backend_fchown fchown +#define backend_fstat fstat +#define backend_fsync fsync +#define backend_ftruncate ftruncate +#define backend_getegid getegid +#define backend_geteuid geteuid +#define backend_getgid getgid +#define backend_getuid getuid +#define backend_link link +#define backend_lseek lseek +#define backend_lstat lstat +#define backend_mkdir mkdir +#define backend_mkfifo mkfifo +#define backend_mknod mknod +#define backend_open open +#define backend_open_create open +#define backend_opendir opendir +#define backend_pread pread +#define backend_pwrite pwrite +#define backend_readdir readdir +#define backend_readlink readlink +#define backend_realpath realpath +#define backend_remove remove +#define backend_rename rename +#define backend_rmdir rmdir +#define backend_setegid setegid +#define backend_seteuid seteuid +#define backend_setgroups setgroups +#define backend_stat stat +#define backend_statvfs statvfs +#define backend_symlink symlink +#define backend_truncate truncate +#define backend_utime utime +#define backend_statstruct struct stat +#define backend_dirstream DIR +#define backend_statvfsstruct struct statvfs +#define backend_fsinfo_properties FSF3_LINK | FSF3_SYMLINK | FSF3_HOMOGENEOUS | FSF3_CANSETTIME; +#define backend_time_delta_seconds 1 +#define backend_pathconf_case_insensitive FALSE +#define backend_passwdstruct struct passwd +#define backend_getpwnam getpwnam +#define backend_gen_nonce gen_nonce +#define backend_flock flock +#define backend_getpid getpid +#define backend_store_create_verifier store_create_verifier +#define backend_check_create_verifier check_create_verifier + +#if HAVE_LCHOWN == 1 +#define backend_lchown lchown +#else +#define backend_lchown chown +#endif + +#endif diff --git a/unfs3/backend_win32.h b/unfs3/backend_win32.h new file mode 100644 index 0000000..03878a3 --- /dev/null +++ b/unfs3/backend_win32.h @@ -0,0 +1,83 @@ +/* + * UNFS3 low-level filesystem calls for Win32 + * (C) 2006, Peter Åstrand + * see file LICENSE for license details + */ + +#ifndef UNFS3_BACKEND_WIN32_H +#define UNFS3_BACKEND_WIN32_H + +#include "winsupport.h" + +/* + * backend init and shutdown + */ +#define backend_shutdown() do { } while (0) + +/* + * unfs3 functions + */ +#define backend_get_gen get_gen +#define backend_mksocket win_mkfifo +#define backend_locate_file locate_file + +/* + * system calls + */ +#define backend_chmod win_chmod +#define backend_chown win_chown +#define backend_close win_close +#define backend_closedir win_closedir +#define backend_fchmod win_fchmod +#define backend_fchown win_fchown +#define backend_fstat win_fstat +#define backend_fsync _commit +#define backend_ftruncate chsize +#define backend_getegid() 0 +#define backend_geteuid() 0 +#define backend_getgid() 0 +#define backend_getuid() 0 +#define backend_lchown win_chown +#define backend_link win_link +#define backend_lseek lseek +#define backend_lstat win_stat +#define backend_mkdir win_mkdir +#define backend_mkfifo win_mkfifo +#define backend_mknod win_mknod +#define backend_open win_open +#define backend_open_create win_open +#define backend_opendir win_opendir +#define backend_pread pread +#define backend_pwrite pwrite +#define backend_readdir win_readdir +#define backend_readlink win_readlink +#define backend_realpath win_realpath +#define backend_remove win_remove +#define backend_rename win_rename +#define backend_rmdir win_rmdir +#define backend_setegid win_setegid +#define backend_seteuid win_seteuid +#define backend_setgroups(size, groups) 0 +#define backend_stat win_stat +#define backend_statvfs win_statvfs +#define backend_symlink win_symlink +#define backend_truncate win_truncate +#define backend_utime win_utime +#define backend_init win_init +#define backend_dirstream UNFS3_WIN_DIR +#define backend_fsinfo_properties FSF3_HOMOGENEOUS | FSF3_CANSETTIME; +/* + Note: FAT has different granularities for different times: 1 day for + atime, 2 seconds for mtime and 10ms för CreationTime. time_delta + only applies to atime/mtime. We are choosing 2 seconds. +*/ +#define backend_time_delta_seconds 2 +#define backend_pathconf_case_insensitive TRUE +#define backend_getpwnam(name) NULL +#define backend_gen_nonce win_gen_nonce +#define backend_flock flock(fd, op) (-1) +#define backend_getpid getpid +#define backend_store_create_verifier win_store_create_verifier +#define backend_check_create_verifier win_check_create_verifier + +#endif diff --git a/unfs3/bootstrap b/unfs3/bootstrap new file mode 100755 index 0000000..68f4a17 --- /dev/null +++ b/unfs3/bootstrap @@ -0,0 +1,2 @@ +#!/bin/sh +autoreconf -i diff --git a/unfs3/config.h.in b/unfs3/config.h.in new file mode 100644 index 0000000..f50dddd --- /dev/null +++ b/unfs3/config.h.in @@ -0,0 +1,119 @@ +/* config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if the system has the type `int32'. */ +#undef HAVE_INT32 + +/* Define to 1 if the system has the type `int64'. */ +#undef HAVE_INT64 + +/* Define to 1 if you have the `lchown' function. */ +#undef HAVE_LCHOWN + +/* Define to 1 if you have the header file. */ +#undef HAVE_LINUX_EXT2_FS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MNTENT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_RPC_SVC_SOC_H + +/* Define to 1 if you have the `setegid' function. */ +#undef HAVE_SETEGID + +/* Define to 1 if you have the `seteuid' function. */ +#undef HAVE_SETEUID + +/* Define to 1 if you have the `setgroups' function. */ +#undef HAVE_SETGROUPS + +/* Define to 1 if you have the `setresgid' function. */ +#undef HAVE_SETRESGID + +/* Define to 1 if you have the `setresuid' function. */ +#undef HAVE_SETRESUID + +/* Define to 1 if you have the `statvfs' function. */ +#undef HAVE_STATVFS + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if `st_gen' is member of `struct stat'. */ +#undef HAVE_STRUCT_STAT_ST_GEN + +/* Define to 1 if `xp_fd' is member of `struct __rpc_svcxprt'. */ +#undef HAVE_STRUCT___RPC_SVCXPRT_XP_FD + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MNTTAB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MOUNT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_VMOUNT_H + +/* Define to 1 if the system has the type `uint32'. */ +#undef HAVE_UINT32 + +/* Define to 1 if the system has the type `uint64'. */ +#undef HAVE_UINT64 + +/* Define to 1 if you have the `vsyslog' function. */ +#undef HAVE_VSYSLOG + +/* Define to 1 if you have the `xdr_int32' function. */ +#undef HAVE_XDR_INT32 + +/* Define to 1 if you have the `xdr_long' function. */ +#undef HAVE_XDR_LONG + +/* Define to 1 if you have the `xdr_uint32' function. */ +#undef HAVE_XDR_UINT32 + +/* Define to 1 if you have the `xdr_uint64' function. */ +#undef HAVE_XDR_UINT64 + +/* Define to 1 if you have the `xdr_uint64_t' function. */ +#undef HAVE_XDR_UINT64_T + +/* Define to 1 if you have the `xdr_u_int64_t' function. */ +#undef HAVE_XDR_U_INT64_T + +/* Define to 1 if you have the `xdr_u_long' function. */ +#undef HAVE_XDR_U_LONG + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to an empty value if you use Solaris. */ +#undef PORTMAP + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Cluster extensions */ +#undef WANT_CLUSTER + +/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a + `char[]'. */ +#undef YYTEXT_POINTER + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES diff --git a/unfs3/configure b/unfs3/configure new file mode 100755 index 0000000..07ec5cd --- /dev/null +++ b/unfs3/configure @@ -0,0 +1,6835 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61 for unfs3 0.9.22. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME='unfs3' +PACKAGE_TARNAME='unfs3' +PACKAGE_VERSION='0.9.22' +PACKAGE_STRING='unfs3 0.9.22' +PACKAGE_BUGREPORT='' + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +LEX +LEX_OUTPUT_ROOT +LEXLIB +YACC +YFLAGS +CPP +GREP +EGREP +SUBDIRS +EXTRAOBJ +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +YACC +YFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures unfs3 0.9.22 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/unfs3] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of unfs3 0.9.22:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-largefile omit support for large files + --enable-cluster include clustering extensions + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + YACC The `Yet Another C Compiler' implementation to use. Defaults to + the first program found out of: `bison -y', `byacc', `yacc'. + YFLAGS The list of arguments that will be passed by default to $YACC. + This script will default YFLAGS to the empty string to avoid a + default value of `-d' given by some make applications. + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +unfs3 configure 0.9.22 +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by unfs3 $as_me 0.9.22, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +ac_config_headers="$ac_config_headers config.h" + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in gcc egcs kgcc cc + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in gcc egcs kgcc cc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +for ac_prog in flex lex +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_LEX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$LEX"; then + ac_cv_prog_LEX="$LEX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_LEX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +LEX=$ac_cv_prog_LEX +if test -n "$LEX"; then + { echo "$as_me:$LINENO: result: $LEX" >&5 +echo "${ECHO_T}$LEX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$LEX" && break +done +test -n "$LEX" || LEX=":" + +if test "x$LEX" != "x:"; then + cat >conftest.l <<_ACEOF +%% +a { ECHO; } +b { REJECT; } +c { yymore (); } +d { yyless (1); } +e { yyless (input () != 0); } +f { unput (yytext[0]); } +. { BEGIN INITIAL; } +%% +#ifdef YYTEXT_POINTER +extern char *yytext; +#endif +int +main (void) +{ + return ! yylex () + ! yywrap (); +} +_ACEOF +{ (ac_try="$LEX conftest.l" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$LEX conftest.l") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ echo "$as_me:$LINENO: checking lex output file root" >&5 +echo $ECHO_N "checking lex output file root... $ECHO_C" >&6; } +if test "${ac_cv_prog_lex_root+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + +if test -f lex.yy.c; then + ac_cv_prog_lex_root=lex.yy +elif test -f lexyy.c; then + ac_cv_prog_lex_root=lexyy +else + { { echo "$as_me:$LINENO: error: cannot find output from $LEX; giving up" >&5 +echo "$as_me: error: cannot find output from $LEX; giving up" >&2;} + { (exit 1); exit 1; }; } +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_root" >&5 +echo "${ECHO_T}$ac_cv_prog_lex_root" >&6; } +LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root + +if test -z "${LEXLIB+set}"; then + { echo "$as_me:$LINENO: checking lex library" >&5 +echo $ECHO_N "checking lex library... $ECHO_C" >&6; } +if test "${ac_cv_lib_lex+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + + ac_save_LIBS=$LIBS + ac_cv_lib_lex='none needed' + for ac_lib in '' -lfl -ll; do + LIBS="$ac_lib $ac_save_LIBS" + cat >conftest.$ac_ext <<_ACEOF +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_lex=$ac_lib +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext + test "$ac_cv_lib_lex" != 'none needed' && break + done + LIBS=$ac_save_LIBS + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_lex" >&5 +echo "${ECHO_T}$ac_cv_lib_lex" >&6; } + test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex +fi + + +{ echo "$as_me:$LINENO: checking whether yytext is a pointer" >&5 +echo $ECHO_N "checking whether yytext is a pointer... $ECHO_C" >&6; } +if test "${ac_cv_prog_lex_yytext_pointer+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # POSIX says lex can declare yytext either as a pointer or an array; the +# default is implementation-dependent. Figure out which it is, since +# not all implementations provide the %pointer and %array declarations. +ac_cv_prog_lex_yytext_pointer=no +ac_save_LIBS=$LIBS +LIBS="$LEXLIB $ac_save_LIBS" +cat >conftest.$ac_ext <<_ACEOF +#define YYTEXT_POINTER 1 +`cat $LEX_OUTPUT_ROOT.c` +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_prog_lex_yytext_pointer=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_save_LIBS + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_lex_yytext_pointer" >&5 +echo "${ECHO_T}$ac_cv_prog_lex_yytext_pointer" >&6; } +if test $ac_cv_prog_lex_yytext_pointer = yes; then + +cat >>confdefs.h <<\_ACEOF +#define YYTEXT_POINTER 1 +_ACEOF + +fi +rm -f conftest.l $LEX_OUTPUT_ROOT.c + +fi +for ac_prog in 'bison -y' byacc +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_YACC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$YACC"; then + ac_cv_prog_YACC="$YACC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_YACC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +YACC=$ac_cv_prog_YACC +if test -n "$YACC"; then + { echo "$as_me:$LINENO: result: $YACC" >&5 +echo "${ECHO_T}$YACC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$YACC" && break +done +test -n "$YACC" || YACC="yacc" + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# Check whether --enable-largefile was given. +if test "${enable_largefile+set}" = set; then + enableval=$enable_largefile; +fi + +if test "$enable_largefile" != no; then + + { echo "$as_me:$LINENO: checking for special C compiler options needed for large files" >&5 +echo $ECHO_N "checking for special C compiler options needed for large files... $ECHO_C" >&6; } +if test "${ac_cv_sys_largefile_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_sys_largefile_CC=no + if test "$GCC" != yes; then + ac_save_CC=$CC + while :; do + # IRIX 6.2 and later do not support large files by default, + # so use the C compiler's -n32 option if that helps. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + CC="$CC -n32" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_largefile_CC=' -n32'; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + break + done + CC=$ac_save_CC + rm -f conftest.$ac_ext + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_largefile_CC" >&5 +echo "${ECHO_T}$ac_cv_sys_largefile_CC" >&6; } + if test "$ac_cv_sys_largefile_CC" != no; then + CC=$CC$ac_cv_sys_largefile_CC + fi + + { echo "$as_me:$LINENO: checking for _FILE_OFFSET_BITS value needed for large files" >&5 +echo $ECHO_N "checking for _FILE_OFFSET_BITS value needed for large files... $ECHO_C" >&6; } +if test "${ac_cv_sys_file_offset_bits+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_file_offset_bits=no; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#define _FILE_OFFSET_BITS 64 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_file_offset_bits=64; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_file_offset_bits=unknown + break +done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_file_offset_bits" >&5 +echo "${ECHO_T}$ac_cv_sys_file_offset_bits" >&6; } +case $ac_cv_sys_file_offset_bits in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _FILE_OFFSET_BITS $ac_cv_sys_file_offset_bits +_ACEOF +;; +esac +rm -f conftest* + if test $ac_cv_sys_file_offset_bits = unknown; then + { echo "$as_me:$LINENO: checking for _LARGE_FILES value needed for large files" >&5 +echo $ECHO_N "checking for _LARGE_FILES value needed for large files... $ECHO_C" >&6; } +if test "${ac_cv_sys_large_files+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_large_files=no; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#define _LARGE_FILES 1 +#include + /* Check that off_t can represent 2**63 - 1 correctly. + We can't simply define LARGE_OFF_T to be 9223372036854775807, + since some C++ compilers masquerading as C compilers + incorrectly reject 9223372036854775807. */ +#define LARGE_OFF_T (((off_t) 1 << 62) - 1 + ((off_t) 1 << 62)) + int off_t_is_large[(LARGE_OFF_T % 2147483629 == 721 + && LARGE_OFF_T % 2147483647 == 1) + ? 1 : -1]; +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_sys_large_files=1; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cv_sys_large_files=unknown + break +done +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sys_large_files" >&5 +echo "${ECHO_T}$ac_cv_sys_large_files" >&6; } +case $ac_cv_sys_large_files in #( + no | unknown) ;; + *) +cat >>confdefs.h <<_ACEOF +#define _LARGE_FILES $ac_cv_sys_large_files +_ACEOF +;; +esac +rm -f conftest* + fi +fi + +{ echo "$as_me:$LINENO: checking for library containing xdr_int" >&5 +echo $ECHO_N "checking for library containing xdr_int... $ECHO_C" >&6; } +if test "${ac_cv_search_xdr_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char xdr_int (); +int +main () +{ +return xdr_int (); + ; + return 0; +} +_ACEOF +for ac_lib in '' nsl; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_search_xdr_int=$ac_res +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext + if test "${ac_cv_search_xdr_int+set}" = set; then + break +fi +done +if test "${ac_cv_search_xdr_int+set}" = set; then + : +else + ac_cv_search_xdr_int=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_search_xdr_int" >&5 +echo "${ECHO_T}$ac_cv_search_xdr_int" >&6; } +ac_res=$ac_cv_search_xdr_int +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ echo "$as_me:$LINENO: checking for library containing socket" >&5 +echo $ECHO_N "checking for library containing socket... $ECHO_C" >&6; } +if test "${ac_cv_search_socket+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char socket (); +int +main () +{ +return socket (); + ; + return 0; +} +_ACEOF +for ac_lib in '' socket; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_search_socket=$ac_res +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext + if test "${ac_cv_search_socket+set}" = set; then + break +fi +done +if test "${ac_cv_search_socket+set}" = set; then + : +else + ac_cv_search_socket=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_search_socket" >&5 +echo "${ECHO_T}$ac_cv_search_socket" >&6; } +ac_res=$ac_cv_search_socket +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + +{ echo "$as_me:$LINENO: checking for library containing inet_aton" >&5 +echo $ECHO_N "checking for library containing inet_aton... $ECHO_C" >&6; } +if test "${ac_cv_search_inet_aton+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_func_search_save_LIBS=$LIBS +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char inet_aton (); +int +main () +{ +return inet_aton (); + ; + return 0; +} +_ACEOF +for ac_lib in '' resolv; do + if test -z "$ac_lib"; then + ac_res="none required" + else + ac_res=-l$ac_lib + LIBS="-l$ac_lib $ac_func_search_save_LIBS" + fi + rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_search_inet_aton=$ac_res +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext + if test "${ac_cv_search_inet_aton+set}" = set; then + break +fi +done +if test "${ac_cv_search_inet_aton+set}" = set; then + : +else + ac_cv_search_inet_aton=no +fi +rm conftest.$ac_ext +LIBS=$ac_func_search_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_search_inet_aton" >&5 +echo "${ECHO_T}$ac_cv_search_inet_aton" >&6; } +ac_res=$ac_cv_search_inet_aton +if test "$ac_res" != no; then + test "$ac_res" = "none required" || LIBS="$ac_res $LIBS" + +fi + + +for ac_header in mntent.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in stdint.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/mnttab.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/mount.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in sys/vmount.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in rpc/svc_soc.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +for ac_header in linux/ext2_fs.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + +{ echo "$as_me:$LINENO: checking for int32" >&5 +echo $ECHO_N "checking for int32... $ECHO_C" >&6; } +if test "${ac_cv_type_int32+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +typedef int32 ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_int32=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_int32=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_int32" >&5 +echo "${ECHO_T}$ac_cv_type_int32" >&6; } +if test $ac_cv_type_int32 = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_INT32 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for uint32" >&5 +echo $ECHO_N "checking for uint32... $ECHO_C" >&6; } +if test "${ac_cv_type_uint32+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +typedef uint32 ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_uint32=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_uint32=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_uint32" >&5 +echo "${ECHO_T}$ac_cv_type_uint32" >&6; } +if test $ac_cv_type_uint32 = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_UINT32 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for int64" >&5 +echo $ECHO_N "checking for int64... $ECHO_C" >&6; } +if test "${ac_cv_type_int64+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +typedef int64 ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_int64=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_int64=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_int64" >&5 +echo "${ECHO_T}$ac_cv_type_int64" >&6; } +if test $ac_cv_type_int64 = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_INT64 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for uint64" >&5 +echo $ECHO_N "checking for uint64... $ECHO_C" >&6; } +if test "${ac_cv_type_uint64+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +typedef uint64 ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_uint64=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_uint64=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_uint64" >&5 +echo "${ECHO_T}$ac_cv_type_uint64" >&6; } +if test $ac_cv_type_uint64 = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_UINT64 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for struct stat.st_gen" >&5 +echo $ECHO_N "checking for struct stat.st_gen... $ECHO_C" >&6; } +if test "${ac_cv_member_struct_stat_st_gen+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +static struct stat ac_aggr; +if (ac_aggr.st_gen) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_gen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +static struct stat ac_aggr; +if (sizeof ac_aggr.st_gen) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct_stat_st_gen=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct_stat_st_gen=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct_stat_st_gen" >&5 +echo "${ECHO_T}$ac_cv_member_struct_stat_st_gen" >&6; } +if test $ac_cv_member_struct_stat_st_gen = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT_STAT_ST_GEN 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for struct __rpc_svcxprt.xp_fd" >&5 +echo $ECHO_N "checking for struct __rpc_svcxprt.xp_fd... $ECHO_C" >&6; } +if test "${ac_cv_member_struct___rpc_svcxprt_xp_fd+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +static struct __rpc_svcxprt ac_aggr; +if (ac_aggr.xp_fd) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct___rpc_svcxprt_xp_fd=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +int +main () +{ +static struct __rpc_svcxprt ac_aggr; +if (sizeof ac_aggr.xp_fd) +return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_member_struct___rpc_svcxprt_xp_fd=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_member_struct___rpc_svcxprt_xp_fd=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_member_struct___rpc_svcxprt_xp_fd" >&5 +echo "${ECHO_T}$ac_cv_member_struct___rpc_svcxprt_xp_fd" >&6; } +if test $ac_cv_member_struct___rpc_svcxprt_xp_fd = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_STRUCT___RPC_SVCXPRT_XP_FD 1 +_ACEOF + + +fi + + + + + +for ac_func in xdr_long xdr_int32 xdr_u_long xdr_uint32 +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + + +for ac_func in xdr_uint64 xdr_uint64_t xdr_u_int64_t +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_func in statvfs +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +for ac_func in seteuid setegid +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + +for ac_func in setresuid setresgid +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_func in vsyslog +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_func in lchown +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_func in setgroups +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + + { echo "$as_me:$LINENO: checking for svc_tli_create" >&5 +echo $ECHO_N "checking for svc_tli_create... $ECHO_C" >&6; } +if test "${ac_cv_func_svc_tli_create+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define svc_tli_create to an innocuous variant, in case declares svc_tli_create. + For example, HP-UX 11i declares gettimeofday. */ +#define svc_tli_create innocuous_svc_tli_create + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char svc_tli_create (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef svc_tli_create + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char svc_tli_create (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_svc_tli_create || defined __stub___svc_tli_create +choke me +#endif + +int +main () +{ +return svc_tli_create (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_func_svc_tli_create=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_func_svc_tli_create=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_func_svc_tli_create" >&5 +echo "${ECHO_T}$ac_cv_func_svc_tli_create" >&6; } +if test $ac_cv_func_svc_tli_create = yes; then + + # On Solaris, you must link with librpcsoc, or the binaries won't work. + LDFLAGS="-L/usr/ucblib -R/usr/ucblib $LDFLAGS" + { echo "$as_me:$LINENO: checking for svctcp_create in -lrpcsoc" >&5 +echo $ECHO_N "checking for svctcp_create in -lrpcsoc... $ECHO_C" >&6; } +if test "${ac_cv_lib_rpcsoc_svctcp_create+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lrpcsoc $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char svctcp_create (); +int +main () +{ +return svctcp_create (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_rpcsoc_svctcp_create=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_rpcsoc_svctcp_create=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_rpcsoc_svctcp_create" >&5 +echo "${ECHO_T}$ac_cv_lib_rpcsoc_svctcp_create" >&6; } +if test $ac_cv_lib_rpcsoc_svctcp_create = yes; then + LIBS="-lrpcsoc $LIBS" +else + { echo "$as_me:$LINENO: WARNING: *** Cannot find librpcsoc. On Solaris, install package SUNWscpu. ***" >&5 +echo "$as_me: WARNING: *** Cannot find librpcsoc. On Solaris, install package SUNWscpu. ***" >&2;} + +fi + + +fi + + + + +cat >>confdefs.h <<\_ACEOF +#define PORTMAP +_ACEOF + + + + if test "$GCC" = "yes" + then + CFLAGS="$CFLAGS -Wall -W" + fi + +# Check whether --enable-cluster was given. +if test "${enable_cluster+set}" = set; then + enableval=$enable_cluster; +cat >>confdefs.h <<\_ACEOF +#define WANT_CLUSTER +_ACEOF + SUBDIRS=Extras + EXTRAOBJ=Extras/lib.a + +fi + +ac_config_files="$ac_config_files Makefile Config/Makefile Extras/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by unfs3 $as_me 0.9.22, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +unfs3 config.status 0.9.22 +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "Config/Makefile") CONFIG_FILES="$CONFIG_FILES Config/Makefile" ;; + "Extras/Makefile") CONFIG_FILES="$CONFIG_FILES Extras/Makefile" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +LEX!$LEX$ac_delim +LEX_OUTPUT_ROOT!$LEX_OUTPUT_ROOT$ac_delim +LEXLIB!$LEXLIB$ac_delim +YACC!$YACC$ac_delim +YFLAGS!$YFLAGS$ac_delim +CPP!$CPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +SUBDIRS!$SUBDIRS$ac_delim +EXTRAOBJ!$EXTRAOBJ$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 59; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then replace #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" + ;; + + + esac + +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/unfs3/configure.ac b/unfs3/configure.ac new file mode 100644 index 0000000..023b296 --- /dev/null +++ b/unfs3/configure.ac @@ -0,0 +1,37 @@ +AC_INIT(unfs3, 0.9.22) +AC_CONFIG_HEADER(config.h) +AC_PROG_INSTALL +AC_PROG_CC([gcc egcs kgcc cc]) +AC_PROG_LEX +AC_PROG_YACC +AC_HEADER_STDC +AC_SYS_LARGEFILE +AC_SEARCH_LIBS(xdr_int, nsl) +AC_SEARCH_LIBS(socket, socket) +AC_SEARCH_LIBS(inet_aton, resolv) +AC_CHECK_HEADERS(mntent.h,,,[#include ]) +AC_CHECK_HEADERS(stdint.h,,,[#include ]) +AC_CHECK_HEADERS(sys/mnttab.h,,,[#include ]) +AC_CHECK_HEADERS(sys/mount.h,,,[#include ]) +AC_CHECK_HEADERS(sys/vmount.h,,,[#include ]) +AC_CHECK_HEADERS(rpc/svc_soc.h,,,[#include ]) +AC_CHECK_HEADERS(linux/ext2_fs.h,,,[#include ]) +AC_CHECK_TYPES(int32,,,[#include ]) +AC_CHECK_TYPES(uint32,,,[#include ]) +AC_CHECK_TYPES(int64,,,[#include ]) +AC_CHECK_TYPES(uint64,,,[#include ]) +AC_CHECK_MEMBERS([struct stat.st_gen],,,[#include ]) +AC_CHECK_MEMBERS([struct __rpc_svcxprt.xp_fd],,,[#include ]) +AC_CHECK_FUNCS(xdr_long xdr_int32 xdr_u_long xdr_uint32) +AC_CHECK_FUNCS(xdr_uint64 xdr_uint64_t xdr_u_int64_t) +AC_CHECK_FUNCS(statvfs) +AC_CHECK_FUNCS(seteuid setegid) +AC_CHECK_FUNCS(setresuid setresgid) +AC_CHECK_FUNCS(vsyslog) +AC_CHECK_FUNCS(lchown) +AC_CHECK_FUNCS(setgroups) +UNFS3_SOLARIS_RPC +UNFS3_PORTMAP_DEFINE +UNFS3_COMPILE_WARNINGS +AC_ARG_ENABLE(cluster,[ --enable-cluster include clustering extensions],[AC_DEFINE([WANT_CLUSTER], [], [Cluster extensions]) AC_SUBST([SUBDIRS],[Extras]) AC_SUBST([EXTRAOBJ],[Extras/lib.a])]) +AC_OUTPUT(Makefile Config/Makefile Extras/Makefile) diff --git a/unfs3/contrib/nfsotpclient/README b/unfs3/contrib/nfsotpclient/README new file mode 100644 index 0000000..5ad1f0e --- /dev/null +++ b/unfs3/contrib/nfsotpclient/README @@ -0,0 +1,3 @@ + +This is a NFS one time password client. Read doc/passwords.txt for +more information. diff --git a/unfs3/contrib/nfsotpclient/mountclient/__init__.py b/unfs3/contrib/nfsotpclient/mountclient/__init__.py new file mode 100644 index 0000000..88c0f92 --- /dev/null +++ b/unfs3/contrib/nfsotpclient/mountclient/__init__.py @@ -0,0 +1,6 @@ + +import mountconstants +import mounttypes +import mountpacker + +__all__ = ['mountconstants', 'mounttypes', 'mountpacker'] diff --git a/unfs3/contrib/nfsotpclient/mountclient/mountconstants.py b/unfs3/contrib/nfsotpclient/mountclient/mountconstants.py new file mode 100644 index 0000000..e5b0628 --- /dev/null +++ b/unfs3/contrib/nfsotpclient/mountclient/mountconstants.py @@ -0,0 +1,48 @@ +# Generated by rpcgen.py at Mon Mar 8 11:09:57 2004 + +__all__ = ['MNTPATHLEN', 'MNTNAMLEN', 'FHSIZE2', 'FHSIZE3', 'MNT3_OK', 'MNT3ERR_PERM', 'MNT3ERR_NOENT', 'MNT3ERR_IO', 'MNT3ERR_ACCES', 'MNT3ERR_NOTDIR', 'MNT3ERR_INVAL', 'MNT3ERR_NAMETOOLONG', 'MNT3ERR_NOTSUPP', 'MNT3ERR_SERVERFAULT', 'mountstat3_id', 'MOUNTPROC_NULL', 'MOUNTPROC_MNT', 'MOUNTPROC_DUMP', 'MOUNTPROC_UMNT', 'MOUNTPROC_UMNTALL', 'MOUNTPROC_EXPORT', 'MOUNTPROC_EXPORTALL', 'MOUNT_V1', 'MOUNTPROC3_NULL', 'MOUNTPROC3_MNT', 'MOUNTPROC3_DUMP', 'MOUNTPROC3_UMNT', 'MOUNTPROC3_UMNTALL', 'MOUNTPROC3_EXPORT', 'MOUNT_V3', 'MOUNT_PROGRAM'] + +FALSE = 0 +TRUE = 1 +MNTPATHLEN = 1024 +MNTNAMLEN = 255 +FHSIZE2 = 32 +FHSIZE3 = 64 +MNT3_OK = 0 +MNT3ERR_PERM = 1 +MNT3ERR_NOENT = 2 +MNT3ERR_IO = 5 +MNT3ERR_ACCES = 13 +MNT3ERR_NOTDIR = 20 +MNT3ERR_INVAL = 22 +MNT3ERR_NAMETOOLONG = 63 +MNT3ERR_NOTSUPP = 10004 +MNT3ERR_SERVERFAULT = 10006 +mountstat3_id = { + MNT3_OK: "MNT3_OK", + MNT3ERR_PERM: "MNT3ERR_PERM", + MNT3ERR_NOENT: "MNT3ERR_NOENT", + MNT3ERR_IO: "MNT3ERR_IO", + MNT3ERR_ACCES: "MNT3ERR_ACCES", + MNT3ERR_NOTDIR: "MNT3ERR_NOTDIR", + MNT3ERR_INVAL: "MNT3ERR_INVAL", + MNT3ERR_NAMETOOLONG: "MNT3ERR_NAMETOOLONG", + MNT3ERR_NOTSUPP: "MNT3ERR_NOTSUPP", + MNT3ERR_SERVERFAULT: "MNT3ERR_SERVERFAULT" + } +MOUNTPROC_NULL = 0 +MOUNTPROC_MNT = 1 +MOUNTPROC_DUMP = 2 +MOUNTPROC_UMNT = 3 +MOUNTPROC_UMNTALL = 4 +MOUNTPROC_EXPORT = 5 +MOUNTPROC_EXPORTALL = 6 +MOUNT_V1 = 1 +MOUNTPROC3_NULL = 0 +MOUNTPROC3_MNT = 1 +MOUNTPROC3_DUMP = 2 +MOUNTPROC3_UMNT = 3 +MOUNTPROC3_UMNTALL = 4 +MOUNTPROC3_EXPORT = 5 +MOUNT_V3 = 3 +MOUNT_PROGRAM = 100005 diff --git a/unfs3/contrib/nfsotpclient/mountclient/mountpacker.py b/unfs3/contrib/nfsotpclient/mountclient/mountpacker.py new file mode 100644 index 0000000..b6e1e1f --- /dev/null +++ b/unfs3/contrib/nfsotpclient/mountclient/mountpacker.py @@ -0,0 +1,113 @@ +# Generated by rpcgen.py at Mon Mar 8 11:09:57 2004 + +import rpc +import mounttypes +import mountconstants +import xdrlib + +__all__ = ['MOUNTPacker', 'MOUNTUnpacker'] + +class MOUNTPacker(rpc.Packer): + def __init__(self, ncl): + xdrlib.Packer.__init__(self) + self.ncl = ncl + + pack_hyper = rpc.Packer.pack_hyper + + pack_string = rpc.Packer.pack_string + + pack_enum = rpc.Packer.pack_enum + + pack_opaque = rpc.Packer.pack_opaque + + pack_int = rpc.Packer.pack_int + + pack_double = rpc.Packer.pack_double + + pack_float = rpc.Packer.pack_float + + pack_unsigned = rpc.Packer.pack_uint + + pack_quadruple = rpc.Packer.pack_double + + pack_bool = rpc.Packer.pack_bool + + pack_unsigned_int = rpc.Packer.pack_uint + + pack_unsigned_hyper = rpc.Packer.pack_uhyper + + def pack_fhandle2(self, data): + self.pack_fopaque(mountconstants.FHSIZE2, data) + + def pack_fhandle3(self, data): + self.pack_opaque(data) + + def pack_dirpath(self, data): + self.pack_string(data) + + def pack_name(self, data): + self.pack_string(data) + + pack_mountstat3 = pack_enum + + def pack_mountlist(self, data): + mounttypes.pack_objarray(self, data) + + def pack_groups(self, data): + mounttypes.pack_objarray(self, data) + + def pack_exports(self, data): + mounttypes.pack_objarray(self, data) + +class MOUNTUnpacker(rpc.Unpacker): + def __init__(self, ncl, data=''): + xdrlib.Unpacker.__init__(self, data) + self.ncl = ncl + + unpack_hyper = rpc.Unpacker.unpack_hyper + + unpack_string = rpc.Unpacker.unpack_string + + unpack_enum = rpc.Unpacker.unpack_enum + + unpack_opaque = rpc.Unpacker.unpack_opaque + + unpack_int = rpc.Unpacker.unpack_int + + unpack_double = rpc.Unpacker.unpack_double + + unpack_float = rpc.Unpacker.unpack_float + + unpack_unsigned = rpc.Unpacker.unpack_uint + + unpack_quadruple = rpc.Unpacker.unpack_double + + unpack_bool = rpc.Unpacker.unpack_bool + + unpack_unsigned_int = rpc.Unpacker.unpack_uint + + unpack_unsigned_hyper = rpc.Unpacker.unpack_uhyper + + def unpack_fhandle2(self): + return self.unpack_fopaque(mountconstants.FHSIZE2) + + def unpack_fhandle3(self): + return self.unpack_opaque() + + def unpack_dirpath(self): + return self.unpack_string() + + def unpack_name(self): + return self.unpack_string() + + unpack_mountstat3 = unpack_enum + + def unpack_mountlist(self): + return mounttypes.unpack_objarray(self.ncl, mounttypes.mountbody) + + def unpack_groups(self): + return mounttypes.unpack_objarray(self.ncl, mounttypes.groupnode) + + def unpack_exports(self): + return mounttypes.unpack_objarray(self.ncl, mounttypes.exportnode) + diff --git a/unfs3/contrib/nfsotpclient/mountclient/mounttypes.py b/unfs3/contrib/nfsotpclient/mountclient/mounttypes.py new file mode 100644 index 0000000..303462c --- /dev/null +++ b/unfs3/contrib/nfsotpclient/mountclient/mounttypes.py @@ -0,0 +1,232 @@ +# Generated by rpcgen.py at Mon Mar 8 11:09:57 2004 + +from mountconstants import * +from mountpacker import * +import rpc + +__all__ = ['BadDiscriminant', 'fhstatus', 'mountres3_ok', 'mountres3', 'mountbody', 'groupnode', 'exportnode'] + +def init_type_class(klass, ncl): + # Initilize type class + klass.ncl = ncl + klass.packer = ncl.packer + klass.unpacker = ncl.unpacker + +def assert_not_none(klass, *args): + for arg in args: + if arg == None: + raise TypeError(repr(klass) + " has uninitialized data") + +def pack_objarray(ncl, list): + # FIXME: Support for length assertion. + ncl.packer.pack_uint(len(list)) + for item in list: + item.pack() + +def unpack_objarray(ncl, klass): + n = ncl.unpacker.unpack_uint() + list = [] + for i in range(n): + obj = klass(ncl) + obj.unpack() + list.append(obj) + return list + + +class BadDiscriminant(rpc.RPCException): + def __init__(self, value, klass): + self.value = value + self.klass = klass + + def __str__(self): + return "Bad Discriminant %s in %s" % (self.value, self.klass) + +class fhstatus: + # XDR definition: + # union fhstatus switch (unsigned fhs_status) { + # case 0: + # fhandle2 fhs_fhandle; + # default: + # void; + # }; + def __init__(self, ncl, fhs_status=None, fhs_fhandle=None): + init_type_class(self, ncl) + self.fhs_status = fhs_status + self.fhs_fhandle = fhs_fhandle + # Shortcut to current arm + self.arm = None + + def __repr__(self): + s = " fhs_status=%s fhs_fhandle=%s" % (str(self.fhs_status), str(self.fhs_fhandle)) + if len(s) > 70: s = s[:70] + "..." + return "" % s + + def pack(self, dummy=None): + assert_not_none(self, self.fhs_status) + self.packer.pack_unsigned(self.fhs_status) + if self.fhs_status == 0: + assert_not_none(self, self.fhs_fhandle) + self.packer.pack_fhandle2(self.fhs_fhandle) + self.arm = self.fhs_fhandle + else: + pass + + + def unpack(self): + self.fhs_status = self.unpacker.unpack_unsigned() + if self.fhs_status == 0: + self.fhs_fhandle = self.unpacker.unpack_fhandle2() + self.arm = self.fhs_fhandle + else: + pass + + +class mountres3_ok: + # XDR definition: + # struct mountres3_ok { + # fhandle3 fhandle; + # int auth_flavors<>; + # }; + def __init__(self, ncl, fhandle=None, auth_flavors=None): + init_type_class(self, ncl) + self.fhandle = fhandle + self.auth_flavors = auth_flavors + + def __repr__(self): + s = " fhandle=%s auth_flavors=%s" % (str(self.fhandle), str(self.auth_flavors)) + if len(s) > 70: s = s[:70] + "..." + return "" % s + + def pack(self, dummy=None): + assert_not_none(self, self.fhandle, self.auth_flavors) + self.packer.pack_fhandle3(self.fhandle) + self.packer.pack_int(self.auth_flavors) + + def unpack(self): + self.fhandle = self.unpacker.unpack_fhandle3() + self.auth_flavors = self.unpacker.unpack_array(self.unpacker.unpack_int) + +class mountres3: + # XDR definition: + # union mountres3 switch (mountstat3 fhs_status) { + # case MNT3_OK: + # mountres3_ok mountinfo; + # default: + # void; + # }; + def __init__(self, ncl, fhs_status=None, mountinfo=None): + init_type_class(self, ncl) + self.fhs_status = fhs_status + self.mountinfo = mountinfo + # Shortcut to current arm + self.arm = None + + def __repr__(self): + s = " fhs_status=%s mountinfo=%s" % (str(self.fhs_status), str(self.mountinfo)) + if len(s) > 70: s = s[:70] + "..." + return "" % s + + def pack(self, dummy=None): + assert_not_none(self, self.fhs_status) + self.packer.pack_mountstat3(self.fhs_status) + if self.fhs_status == MNT3_OK: + assert_not_none(self, self.mountinfo) + self.mountinfo.pack() + self.arm = self.mountinfo + else: + pass + + + def unpack(self): + self.fhs_status = self.unpacker.unpack_mountstat3() + if self.fhs_status == MNT3_OK: + self.mountinfo = mountres3_ok(self) + self.mountinfo.unpack() + self.arm = self.mountinfo + else: + pass + + +class mountbody: + # XDR definition: + # struct mountbody { + # name ml_hostname; + # dirpath ml_directory; + # mountlist ml_next; + # }; + def __init__(self, ncl, ml_hostname=None, ml_directory=None, ml_next=None): + init_type_class(self, ncl) + self.ml_hostname = ml_hostname + self.ml_directory = ml_directory + self.ml_next = ml_next + + def __repr__(self): + s = " ml_hostname=%s ml_directory=%s ml_next=%s" % (str(self.ml_hostname), str(self.ml_directory), str(self.ml_next)) + if len(s) > 70: s = s[:70] + "..." + return "" % s + + def pack(self, dummy=None): + assert_not_none(self, self.ml_hostname, self.ml_directory, self.ml_next) + self.packer.pack_name(self.ml_hostname) + self.packer.pack_dirpath(self.ml_directory) + self.packer.pack_mountlist(self.ml_next) + + def unpack(self): + self.ml_hostname = self.unpacker.unpack_name() + self.ml_directory = self.unpacker.unpack_dirpath() + self.ml_next = self.unpacker.unpack_mountlist() + +class groupnode: + # XDR definition: + # struct groupnode { + # name gr_name; + # groups gr_next; + # }; + def __init__(self, ncl, gr_name=None, gr_next=None): + init_type_class(self, ncl) + self.gr_name = gr_name + self.gr_next = gr_next + + def __repr__(self): + s = " gr_name=%s gr_next=%s" % (str(self.gr_name), str(self.gr_next)) + if len(s) > 70: s = s[:70] + "..." + return "" % s + + def pack(self, dummy=None): + assert_not_none(self, self.gr_name, self.gr_next) + self.packer.pack_name(self.gr_name) + self.packer.pack_groups(self.gr_next) + + def unpack(self): + self.gr_name = self.unpacker.unpack_name() + self.gr_next = self.unpacker.unpack_groups() + +class exportnode: + # XDR definition: + # struct exportnode { + # dirpath ex_dir; + # groups ex_groups; + # exports ex_next; + # }; + def __init__(self, ncl, ex_dir=None, ex_groups=None, ex_next=None): + init_type_class(self, ncl) + self.ex_dir = ex_dir + self.ex_groups = ex_groups + self.ex_next = ex_next + + def __repr__(self): + s = " ex_dir=%s ex_groups=%s ex_next=%s" % (str(self.ex_dir), str(self.ex_groups), str(self.ex_next)) + if len(s) > 70: s = s[:70] + "..." + return "" % s + + def pack(self, dummy=None): + assert_not_none(self, self.ex_dir, self.ex_groups, self.ex_next) + self.packer.pack_dirpath(self.ex_dir) + self.packer.pack_groups(self.ex_groups) + self.packer.pack_exports(self.ex_next) + + def unpack(self): + self.ex_dir = self.unpacker.unpack_dirpath() + self.ex_groups = self.unpacker.unpack_groups() + self.ex_next = self.unpacker.unpack_exports() + diff --git a/unfs3/contrib/nfsotpclient/nfsotpclient.py b/unfs3/contrib/nfsotpclient/nfsotpclient.py new file mode 100755 index 0000000..2470906 --- /dev/null +++ b/unfs3/contrib/nfsotpclient/nfsotpclient.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python +# -*-mode: python; coding: iso-8859-1 -*- +# +# Copyright (c) 2002-2005 Cendio AB. All rights reserved. + +import sys +import rpc +import mountclient +import socket +import os +import md5 + + +class PartialMOUNTClient: + def __init__(self): + pass + + def addpackers(self): + self.packer = mountclient.mountpacker.MOUNTPacker(self) + self.unpacker = mountclient.mountpacker.MOUNTUnpacker(self, '') + + def mnt(self, dirpath): + res = mountclient.mounttypes.mountres3(self) + self.make_call(mountclient.mountconstants.MOUNTPROC_MNT, + dirpath, self.packer.pack_string, res.unpack) + return res + + +class TCPMOUNTClient(PartialMOUNTClient, rpc.RawTCPClient): + def __init__(self, host, port): + rpc.RawTCPClient.__init__(self, host, + mountclient.mountconstants.MOUNT_PROGRAM, + mountclient.mountconstants.MOUNT_V3, + port) + PartialMOUNTClient.__init__(self) + + +class NFSOTPClient: + def __init__(self, host, port): + self.mountcl = TCPMOUNTClient(host, port) + + def getotp(self, password): + res = self.mountcl.mnt("@getnonce") + + if res.fhs_status != mountclient.mountconstants.MNT3_OK: + print >>sys.stderr, "Failed to get nonce:", mountclient.mountconstants.mountstat3_id[res.fhs_status] + sys.exit(1) + + fhandle = res.mountinfo.fhandle + digest = md5.new(fhandle + password).hexdigest() + return digest + + +def usage(): + print >>sys.stderr, "Usage: nfsotpclient.py host[:port]" + sys.exit(1) + + +if __name__ == "__main__": + if len(sys.argv) != 2: + usage() + + fields = sys.argv[1].split(":") + host = fields[0] + del fields[0] + if fields: + port = int(fields[0]) + else: + # No port specified, fetch from portmapper + # FIXME + print >>sys.stderr, "Portmapper support not yet implemented" + sys.exit(1) + + cl = NFSOTPClient(host, port) + import getpass + password = getpass.getpass() + + print cl.getotp(password) diff --git a/unfs3/contrib/nfsotpclient/rpc.py b/unfs3/contrib/nfsotpclient/rpc.py new file mode 100644 index 0000000..8be1926 --- /dev/null +++ b/unfs3/contrib/nfsotpclient/rpc.py @@ -0,0 +1,1050 @@ + +# rpc.py - RFC1057/RFC1831 +# +# Copyright (C) 2001 Cendio Systems AB (http://www.cendio.se) +# All rights reserved. +# +# Copyright (c) 2001 Python Software Foundation. +# All rights reserved. +# +# Copyright (c) 2000 BeOpen.com. +# All rights reserved. +# +# Copyright (c) 1995-2001 Corporation for National Research Initiatives. +# All rights reserved. +# +# Copyright (c) 1991-1995 Stichting Mathematisch Centrum. +# All rights reserved. +# +# +# This program 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; version 2 of the License. +# +# This program 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 this program; if not, write to the Free Software +# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +# XXX The UDP version of the protocol resends requests when it does +# XXX not receive a timely reply -- use only for idempotent calls! + +# XXX There is no provision for call timeout on TCP connections + +__pychecker__ = 'no-callinit' + +import xdrlib +import socket +import os +import time + +RPCVERSION = 2 + +CALL = 0 +REPLY = 1 + +AUTH_NULL = 0 +AUTH_UNIX = 1 +AUTH_SHORT = 2 +AUTH_DES = 3 + +MSG_ACCEPTED = 0 +MSG_DENIED = 1 + +SUCCESS = 0 # RPC executed successfully +PROG_UNAVAIL = 1 # remote hasn't exported program +PROG_MISMATCH = 2 # remote can't support version # +PROC_UNAVAIL = 3 # program can't support procedure +GARBAGE_ARGS = 4 # procedure can't decode params + +RPC_MISMATCH = 0 # RPC version number != 2 +AUTH_ERROR = 1 # remote can't authenticate caller + +AUTH_BADCRED = 1 # bad credentials (seal broken) +AUTH_REJECTEDCRED = 2 # client must begin new session +AUTH_BADVERF = 3 # bad verifier (seal broken) +AUTH_REJECTEDVERF = 4 # verifier expired or replayed +AUTH_TOOWEAK = 5 # rejected for security reasons + +# All RPC errors are subclasses of RPCException +class RPCException(Exception): + def __str__(self): + return "RPCException" + +class BadRPCMsgType(RPCException): + def __init__(self, msg_type): + self.msg_type = msg_type + + def __str__(self): + return "BadRPCMsgType %d" % self.msg_type + +class BadRPCVersion(RPCException): + def __init__(self, version): + self.version = version + + def __str__(self): + return "BadRPCVersion %d" % self.version + +class RPCMsgDenied(RPCException): + # MSG_DENIED + def __init__(self, stat): + self.stat = stat + + def __str__(self): + return "RPCMsgDenied %d" % self.stat + +class RPCMisMatch(RPCException): + # MSG_DENIED: RPC_MISMATCH + def __init__(self, low, high): + self.low = low + self.high = high + + def __str__(self): + return "RPCMisMatch %d,%d" % (self.low, self.high) + +class RPCAuthError(RPCException): + # MSG_DENIED: AUTH_ERROR + def __init__(self, stat): + self.stat = stat + + def __str__(self): + return "RPCAuthError %d" % self.stat + +class BadRPCReplyType(RPCException): + # Neither MSG_DENIED nor MSG_ACCEPTED + def __init__(self, msg_type): + self.msg_type = msg_type + + def __str__(self): + return "BadRPCReplyType %d" % self.msg_type + +class RPCProgUnavail(RPCException): + # PROG_UNAVAIL + def __str__(self): + return "RPCProgUnavail" + +class RPCProgMismatch(RPCException): + # PROG_MISMATCH + def __init__(self, low, high): + self.low = low + self.high = high + + def __str__(self): + return "RPCProgMismatch %d,%d" % (self.low, self.high) + +class RPCProcUnavail(RPCException): + # PROC_UNAVAIL + def __str__(self): + return "RPCProcUnavail" + +class RPCGarbageArgs(RPCException): + # GARBAGE_ARGS + def __str__(self): + return "RPCGarbageArgs" + +class RPCUnextractedData(RPCException): + # xdrlib raised exception because unextracted data remained + def __str__(self): + return "RPCUnextractedData" + +class RPCBadAcceptStats(RPCException): + # Unknown accept_stat + def __init__(self, stat): + self.stat = stat + + def __str__(self): + return "RPCBadAcceptStats %d" % self.stat + +class XidMismatch(RPCException): + # Got wrong XID in reply, got "xid" instead of "expected" + def __init__(self, xid, expected): + self.xid = xid + self.expected = expected + + def __str__(self): + return "XidMismatch %d,%d" % (self.xid, self.expected) + +class TimeoutError(RPCException): + pass + +class PortMapError(RPCException): + pass + + +class Packer(xdrlib.Packer): + + def pack_auth(self, auth): + flavor, stuff = auth + self.pack_enum(flavor) + self.pack_opaque(stuff) + + def pack_auth_unix(self, stamp, machinename, uid, gid, gids): + self.pack_uint(stamp) + self.pack_string(machinename) + self.pack_uint(uid) + self.pack_uint(gid) + self.pack_uint(len(gids)) + for i in gids: + self.pack_uint(i) + + def pack_callheader(self, xid, prog, vers, proc, cred, verf): + self.pack_uint(xid) + self.pack_enum(CALL) + self.pack_uint(RPCVERSION) + self.pack_uint(prog) + self.pack_uint(vers) + self.pack_uint(proc) + self.pack_auth(cred) + self.pack_auth(verf) + # Caller must add procedure-specific part of call + + def pack_replyheader(self, xid, verf): + self.pack_uint(xid) + self.pack_enum(REPLY) + self.pack_uint(MSG_ACCEPTED) + self.pack_auth(verf) + self.pack_enum(SUCCESS) + # Caller must add procedure-specific part of reply + + +class Unpacker(xdrlib.Unpacker): + + def unpack_auth(self): + flavor = self.unpack_enum() + stuff = self.unpack_opaque() + if flavor == AUTH_UNIX: + p = Unpacker(stuff) + stuff = p.unpack_auth_unix() + return (flavor, stuff) + + def unpack_auth_unix(self): + stamp=self.unpack_uint() + machinename=self.unpack_string() + print "machinename: %s" % machinename + uid=self.unpack_uint() + gid=self.unpack_uint() + n_gids=self.unpack_uint() + gids = [] + print "n_gids: %d" % n_gids + for i in range(n_gids): + gids.append(self.unpack_uint()) + return stamp, machinename, uid, gid, gids + + + def unpack_callheader(self): + xid = self.unpack_uint() + msg_type = self.unpack_enum() + if msg_type <> CALL: + raise BadRPCMsgType(msg_type) + rpcvers = self.unpack_uint() + if rpcvers <> RPCVERSION: + raise BadRPCVersion(rpcvers) + prog = self.unpack_uint() + vers = self.unpack_uint() + proc = self.unpack_uint() + cred = self.unpack_auth() + verf = self.unpack_auth() + return xid, prog, vers, proc, cred, verf + # Caller must add procedure-specific part of call + + def unpack_replyheader(self): + xid = self.unpack_uint() + msg_type = self.unpack_enum() + if msg_type <> REPLY: + raise BadRPCMsgType(msg_type) + stat = self.unpack_enum() + if stat == MSG_DENIED: + stat = self.unpack_enum() + if stat == RPC_MISMATCH: + low = self.unpack_uint() + high = self.unpack_uint() + raise RPCMisMatch(low, high) + if stat == AUTH_ERROR: + stat = self.unpack_uint() + raise RPCAuthError(stat) + raise RPCMsgDenied(stat) + if stat <> MSG_ACCEPTED: + raise BadRPCReplyType(stat) + verf = self.unpack_auth() + stat = self.unpack_enum() + if stat == PROG_UNAVAIL: + raise RPCProgUnavail() + if stat == PROG_MISMATCH: + low = self.unpack_uint() + high = self.unpack_uint() + raise RPCProgMismatch(low, high) + if stat == PROC_UNAVAIL: + raise RPCProcUnavail() + if stat == GARBAGE_ARGS: + raise RPCGarbageArgs() + if stat <> SUCCESS: + raise RPCBadAcceptStats(stat) + return xid, verf + # Caller must get procedure-specific part of reply + + +# Subroutines to create opaque authentication objects + +def make_auth_null(): + return '' + +def make_auth_unix(seed, host, uid, gid, groups): + p = Packer() + p.pack_auth_unix(seed, host, uid, gid, groups) + return p.get_buffer() + +def make_auth_unix_default(): + try: + uid = os.getuid() + gid = os.getgid() + except AttributeError: + uid = gid = 0 + return make_auth_unix(int(time.time()-unix_epoch()), \ + socket.gethostname(), uid, gid, []) + +_unix_epoch = -1 +def unix_epoch(): + """Very painful calculation of when the Unix Epoch is. + + This is defined as the return value of time.time() on Jan 1st, + 1970, 00:00:00 GMT. + + On a Unix system, this should always return 0.0. On a Mac, the + calculations are needed -- and hard because of integer overflow + and other limitations. + + """ + global _unix_epoch + if _unix_epoch >= 0: return _unix_epoch + now = time.time() + localt = time.localtime(now) # (y, m, d, hh, mm, ss, ..., ..., ...) + gmt = time.gmtime(now) + offset = time.mktime(localt) - time.mktime(gmt) + y, m, d, hh, mm, ss = 1970, 1, 1, 0, 0, 0 + offset, ss = divmod(ss + offset, 60) + offset, mm = divmod(mm + offset, 60) + offset, hh = divmod(hh + offset, 24) + d = d + offset + _unix_epoch = time.mktime((y, m, d, hh, mm, ss, 0, 0, 0)) + print "Unix epoch:", time.ctime(_unix_epoch) + return _unix_epoch + + +# Common base class for clients + +class Client: + + def __init__(self, host, prog, vers, port): + self.host = host + self.prog = prog + self.vers = vers + self.port = port + self.sock = None + self.makesocket() # Assigns to self.sock + self.bindsocket() + self.connsocket() + # Servers may do XID caching, so try to come up with something + # unique to start with. XIDs are 32 bits. Python integers are always + # at least 32 bits. + self.lastxid = int(long(time.time() * 1E6) & 0xfffffff) + self.addpackers() + self.cred = None + self.verf = None + + def close(self): + self.sock.close() + + def makesocket(self): + # This MUST be overridden + raise RuntimeError("makesocket not defined") + + def connsocket(self): + # Override this if you don't want/need a connection + self.sock.connect((self.host, self.port)) + + def bindsocket(self): + # Override this to bind to a different port (e.g. reserved) + self.sock.bind(('', 0)) + + def addpackers(self): + # Override this to use derived classes from Packer/Unpacker + self.packer = Packer() + self.unpacker = Unpacker('') + + def make_call(self, proc, args, pack_func, unpack_func): + # Don't normally override this (but see Broadcast) + if pack_func is None and args is not None: + raise TypeError("non-null args with null pack_func") + self.start_call(proc) + if pack_func: + pack_func(args) + self.do_call() + if unpack_func: + result = unpack_func() + else: + result = None + try: + self.unpacker.done() + except xdrlib.Error: + raise RPCUnextractedData() + + return result + + def start_call(self, proc): + # Don't override this + self.lastxid = xid = self.lastxid + 1 + cred = self.mkcred() + verf = self.mkverf() + p = self.packer + p.reset() + p.pack_callheader(xid, self.prog, self.vers, proc, cred, verf) + + def do_call(self): + # This MUST be overridden + raise RuntimeError("do_call not defined") + + def mkcred(self): + # Override this to use more powerful credentials + if self.cred == None: + self.cred = (AUTH_NULL, make_auth_null()) + return self.cred + + def mkverf(self): + # Override this to use a more powerful verifier + if self.verf == None: + self.verf = (AUTH_NULL, make_auth_null()) + return self.verf + + def call_0(self): # Procedure 0 is always like this + return self.make_call(0, None, None, None) + + +# Record-Marking standard support + +def sendfrag(sock, last, frag): + x = len(frag) + if last: x = x | 0x80000000L + header = (chr(int(x>>24 & 0xff)) + chr(int(x>>16 & 0xff)) + \ + chr(int(x>>8 & 0xff)) + chr(int(x & 0xff))) + sock.send(header + frag) + +def sendrecord(sock, record): + sendfrag(sock, 1, record) + +def recvfrag(sock): + header = sock.recv(4) + if len(header) < 4: + raise EOFError + x = long(ord(header[0]))<<24 | ord(header[1])<<16 | \ + ord(header[2])<<8 | ord(header[3]) + last = ((x & 0x80000000) != 0) + n = int(x & 0x7fffffff) + frag = '' + while n > 0: + buf = sock.recv(n) + if not buf: raise EOFError + n = n - len(buf) + frag = frag + buf + return last, frag + +def recvrecord(sock): + record = '' + last = 0 + while not last: + last, frag = recvfrag(sock) + record = record + frag + return record + + +# Try to bind to a reserved port (must be root) + +last_resv_port_tried = None +def bindresvport(sock, host): + global last_resv_port_tried + FIRST, LAST = 600, 1024 # Range of ports to try + if last_resv_port_tried == None: + last_resv_port_tried = FIRST + os.getpid() % (LAST-FIRST) + for i in range(last_resv_port_tried, LAST) + \ + range(FIRST, last_resv_port_tried): + last_resv_port_tried = i + try: + sock.bind((host, i)) + return last_resv_port_tried + except socket.error, (errno, msg): + if errno <> 114: + raise socket.error(errno, msg) + raise RuntimeError("can't assign reserved port") + + +# Client using TCP to a specific port + +class RawTCPClient(Client): + + def makesocket(self): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + + def do_call(self): + call = self.packer.get_buffer() + sendrecord(self.sock, call) + reply = recvrecord(self.sock) + u = self.unpacker + u.reset(reply) + xid, verf = u.unpack_replyheader() + if xid <> self.lastxid: + # Can't really happen since this is TCP... + raise XidMismatch(xid, self.lastxid) + +# Client using UDP to a specific port + +class RawUDPClient(Client): + + def makesocket(self): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + + def do_call(self): + call = self.packer.get_buffer() + self.sock.send(call) + try: + from select import select + except ImportError: + print 'WARNING: select not found, RPC may hang' + select = None + BUFSIZE = 8192 # Max UDP buffer size + timeout = 1 + count = 5 + while 1: + r, w, x = [self.sock], [], [] + if select: + r, w, x = select(r, w, x, timeout) + if self.sock not in r: + count = count - 1 + if count < 0: raise TimeoutError() + if timeout < 25: timeout = timeout *2 +## print 'RESEND', timeout, count + self.sock.send(call) + continue + reply = self.sock.recv(BUFSIZE) + u = self.unpacker + u.reset(reply) + xid, verf = u.unpack_replyheader() + if xid <> self.lastxid: +## print 'BAD xid' + continue + break + + +# Client using UDP broadcast to a specific port + +class RawBroadcastUDPClient(RawUDPClient): + + def __init__(self, bcastaddr, prog, vers, port): + RawUDPClient.__init__(self, bcastaddr, prog, vers, port) + self.reply_handler = None + self.timeout = 30 + + def connsocket(self): + # Don't connect -- use sendto + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) + + def set_reply_handler(self, reply_handler): + self.reply_handler = reply_handler + + def set_timeout(self, timeout): + self.timeout = timeout # Use None for infinite timeout + + def make_call(self, proc, args, pack_func, unpack_func): + if pack_func is None and args is not None: + raise TypeError("non-null args with null pack_func") + self.start_call(proc) + if pack_func: + pack_func(args) + call = self.packer.get_buffer() + self.sock.sendto(call, (self.host, self.port)) + try: + from select import select + except ImportError: + print 'WARNING: select not found, broadcast will hang' + select = None + BUFSIZE = 8192 # Max UDP buffer size (for reply) + replies = [] + if unpack_func is None: + def dummy(): pass + unpack_func = dummy + while 1: + r, w, x = [self.sock], [], [] + if select: + if self.timeout is None: + r, w, x = select(r, w, x) + else: + r, w, x = select(r, w, x, self.timeout) + if self.sock not in r: + break + reply, fromaddr = self.sock.recvfrom(BUFSIZE) + u = self.unpacker + u.reset(reply) + xid, verf = u.unpack_replyheader() + if xid <> self.lastxid: +## print 'BAD xid' + continue + reply = unpack_func() + try: + self.unpacker.done() + except xdrlib.Error: + raise RPCUnextractedData() + replies.append((reply, fromaddr)) + if self.reply_handler: + self.reply_handler(reply, fromaddr) + return replies + + +# Port mapper interface + +# Program number, version and (fixed!) port number +PMAP_PROG = 100000 +PMAP_VERS = 2 +PMAP_PORT = 111 + +# Procedure numbers +PMAPPROC_NULL = 0 # (void) -> void +PMAPPROC_SET = 1 # (mapping) -> bool +PMAPPROC_UNSET = 2 # (mapping) -> bool +PMAPPROC_GETPORT = 3 # (mapping) -> unsigned int +PMAPPROC_DUMP = 4 # (void) -> pmaplist +PMAPPROC_CALLIT = 5 # (call_args) -> call_result + +# A mapping is (prog, vers, prot, port) and prot is one of: + +IPPROTO_TCP = 6 +IPPROTO_UDP = 17 + +# A pmaplist is a variable-length list of mappings, as follows: +# either (1, mapping, pmaplist) or (0). + +# A call_args is (prog, vers, proc, args) where args is opaque; +# a call_result is (port, res) where res is opaque. + + +class PortMapperPacker(Packer): + + def pack_mapping(self, mapping): + prog, vers, prot, port = mapping + self.pack_uint(prog) + self.pack_uint(vers) + self.pack_uint(prot) + self.pack_uint(port) + + def pack_pmaplist(self, list): + self.pack_list(list, self.pack_mapping) + + def pack_call_args(self, ca): + prog, vers, proc, args = ca + self.pack_uint(prog) + self.pack_uint(vers) + self.pack_uint(proc) + self.pack_opaque(args) + + +class PortMapperUnpacker(Unpacker): + + def unpack_mapping(self): + prog = self.unpack_uint() + vers = self.unpack_uint() + prot = self.unpack_uint() + port = self.unpack_uint() + return prog, vers, prot, port + + def unpack_pmaplist(self): + return self.unpack_list(self.unpack_mapping) + + def unpack_call_result(self): + port = self.unpack_uint() + res = self.unpack_opaque() + return port, res + + +class PartialPortMapperClient: + __pychecker__ = 'no-classattr' + def addpackers(self): + self.packer = PortMapperPacker() + self.unpacker = PortMapperUnpacker('') + + def Set(self, mapping): + return self.make_call(PMAPPROC_SET, mapping, \ + self.packer.pack_mapping, \ + self.unpacker.unpack_uint) + + def Unset(self, mapping): + return self.make_call(PMAPPROC_UNSET, mapping, \ + self.packer.pack_mapping, \ + self.unpacker.unpack_uint) + + def Getport(self, mapping): + return self.make_call(PMAPPROC_GETPORT, mapping, \ + self.packer.pack_mapping, \ + self.unpacker.unpack_uint) + + def Dump(self): + return self.make_call(PMAPPROC_DUMP, None, \ + None, \ + self.unpacker.unpack_pmaplist) + + def Callit(self, ca): + return self.make_call(PMAPPROC_CALLIT, ca, \ + self.packer.pack_call_args, \ + self.unpacker.unpack_call_result) + + +class TCPPortMapperClient(PartialPortMapperClient, RawTCPClient): + + def __init__(self, host): + RawTCPClient.__init__(self, \ + host, PMAP_PROG, PMAP_VERS, PMAP_PORT) + + +class UDPPortMapperClient(PartialPortMapperClient, RawUDPClient): + + def __init__(self, host): + RawUDPClient.__init__(self, \ + host, PMAP_PROG, PMAP_VERS, PMAP_PORT) + + +class BroadcastUDPPortMapperClient(PartialPortMapperClient, \ + RawBroadcastUDPClient): + + def __init__(self, bcastaddr): + RawBroadcastUDPClient.__init__(self, \ + bcastaddr, PMAP_PROG, PMAP_VERS, PMAP_PORT) + + +# Generic clients that find their server through the Port mapper + +class TCPClient(RawTCPClient): + + def __init__(self, host, prog, vers): + pmap = TCPPortMapperClient(host) + port = pmap.Getport((prog, vers, IPPROTO_TCP, 0)) + pmap.close() + if port == 0: + raise PortMapError("program not registered") + RawTCPClient.__init__(self, host, prog, vers, port) + + +class UDPClient(RawUDPClient): + + def __init__(self, host, prog, vers): + pmap = UDPPortMapperClient(host) + port = pmap.Getport((prog, vers, IPPROTO_UDP, 0)) + pmap.close() + if port == 0: + raise PortMapError("program not registered") + RawUDPClient.__init__(self, host, prog, vers, port) + + +class BroadcastUDPClient(Client): + + def __init__(self, bcastaddr, prog, vers): + self.pmap = BroadcastUDPPortMapperClient(bcastaddr) + self.pmap.set_reply_handler(self.my_reply_handler) + self.prog = prog + self.vers = vers + self.user_reply_handler = None + self.addpackers() + + def close(self): + self.pmap.close() + + def set_reply_handler(self, reply_handler): + self.user_reply_handler = reply_handler + + def set_timeout(self, timeout): + self.pmap.set_timeout(timeout) + + def my_reply_handler(self, reply, fromaddr): + port, res = reply + self.unpacker.reset(res) + result = self.unpack_func() + try: + self.unpacker.done() + except xdrlib.Error: + raise RPCUnextractedData() + self.replies.append((result, fromaddr)) + if self.user_reply_handler is not None: + self.user_reply_handler(result, fromaddr) + + def make_call(self, proc, args, pack_func, unpack_func): + self.packer.reset() + if pack_func: + pack_func(args) + if unpack_func is None: + def dummy(): pass + self.unpack_func = dummy + else: + self.unpack_func = unpack_func + self.replies = [] + packed_args = self.packer.get_buffer() + dummy_replies = self.pmap.Callit( \ + (self.prog, self.vers, proc, packed_args)) + return self.replies + + +# Server classes + +# These are not symmetric to the Client classes +# XXX No attempt is made to provide authorization hooks yet + +class Server: + + def __init__(self, host, prog, vers, port): + self.host = host # Should normally be '' for default interface + self.prog = prog + self.vers = vers + self.port = port # Should normally be 0 for random port + self.sock = None + self.prot = None + self.makesocket() # Assigns to self.sock and self.prot + self.bindsocket() + self.host, self.port = self.sock.getsockname() + self.addpackers() + + def register(self): + mapping = self.prog, self.vers, self.prot, self.port + p = TCPPortMapperClient(self.host) + if not p.Set(mapping): + raise PortMapError("register failed") + + def unregister(self): + mapping = self.prog, self.vers, self.prot, self.port + p = TCPPortMapperClient(self.host) + if not p.Unset(mapping): + raise PortMapError("unregister failed") + + def handle(self, call): + # Don't use unpack_header but parse the header piecewise + # XXX I have no idea if I am using the right error responses! + self.unpacker.reset(call) + self.packer.reset() + xid = self.unpacker.unpack_uint() + self.packer.pack_uint(xid) + temp = self.unpacker.unpack_enum() + if temp <> CALL: + return None # Not worthy of a reply + self.packer.pack_uint(REPLY) + temp = self.unpacker.unpack_uint() + if temp <> RPCVERSION: + self.packer.pack_uint(MSG_DENIED) + self.packer.pack_uint(RPC_MISMATCH) + self.packer.pack_uint(RPCVERSION) + self.packer.pack_uint(RPCVERSION) + return self.packer.get_buffer() + self.packer.pack_uint(MSG_ACCEPTED) + self.packer.pack_auth((AUTH_NULL, make_auth_null())) + prog = self.unpacker.unpack_uint() + if prog <> self.prog: + self.packer.pack_uint(PROG_UNAVAIL) + return self.packer.get_buffer() + vers = self.unpacker.unpack_uint() + if vers <> self.vers: + self.packer.pack_uint(PROG_MISMATCH) + self.packer.pack_uint(self.vers) + self.packer.pack_uint(self.vers) + return self.packer.get_buffer() + proc = self.unpacker.unpack_uint() + methname = 'handle_' + `proc` + try: + meth = getattr(self, methname) + except AttributeError: + self.packer.pack_uint(PROC_UNAVAIL) + return self.packer.get_buffer() + self.recv_cred = self.unpacker.unpack_auth() + self.recv_verf = self.unpacker.unpack_auth() + try: + meth() # Unpack args, call turn_around(), pack reply + except (EOFError, RPCGarbageArgs): + # Too few or too many arguments + self.packer.reset() + self.packer.pack_uint(xid) + self.packer.pack_uint(REPLY) + self.packer.pack_uint(MSG_ACCEPTED) + self.packer.pack_auth((AUTH_NULL, make_auth_null())) + self.packer.pack_uint(GARBAGE_ARGS) + return self.packer.get_buffer() + + def turn_around(self): + try: + self.unpacker.done() + except xdrlib.Error: + raise RPCUnextractedData() + + self.packer.pack_uint(SUCCESS) + + def handle_0(self): # Handle NULL message + self.turn_around() + + def makesocket(self): + # This MUST be overridden + raise RuntimeError("makesocket not defined") + + def bindsocket(self): + # Override this to bind to a different port (e.g. reserved) + self.sock.bind((self.host, self.port)) + + def addpackers(self): + # Override this to use derived classes from Packer/Unpacker + self.packer = Packer() + self.unpacker = Unpacker('') + + +class TCPServer(Server): + + def makesocket(self): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.prot = IPPROTO_TCP + + def loop(self): + self.sock.listen(0) + while 1: + self.session(self.sock.accept()) + + def session(self, connection): + sock, (host, port) = connection + while 1: + try: + call = recvrecord(sock) + except EOFError: + break + except socket.error, msg: + print 'socket error:', msg + break + reply = self.handle(call) + if reply is not None: + sendrecord(sock, reply) + + def forkingloop(self): + # Like loop but uses forksession() + self.sock.listen(0) + while 1: + self.forksession(self.sock.accept()) + + def forksession(self, connection): + # Like session but forks off a subprocess + # Wait for deceased children + try: + while 1: + pid, sts = os.waitpid(0, 1) + except os.error: + pass + pid = None + try: + pid = os.fork() + if pid: # Parent + connection[0].close() + return + # Child + self.session(connection) + finally: + # Make sure we don't fall through in the parent + if pid == 0: + os._exit(0) + + +class UDPServer(Server): + + def makesocket(self): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + self.prot = IPPROTO_UDP + + def loop(self): + while 1: + self.session() + + def session(self): + call, host_port = self.sock.recvfrom(8192) + self.sender_port = host_port + reply = self.handle(call) + if reply <> None: + self.sock.sendto(reply, host_port) + + +# Simple test program -- dump local portmapper status + +def test(): + pmap = UDPPortMapperClient('') + list = pmap.Dump() + list.sort() + for prog, vers, prot, port in list: + print prog, vers, + if prot == IPPROTO_TCP: print 'tcp', + elif prot == IPPROTO_UDP: print 'udp', + else: print prot, + print port + + +# Test program for broadcast operation -- dump everybody's portmapper status + +def testbcast(): + import sys + if sys.argv[1:]: + bcastaddr = sys.argv[1] + else: + bcastaddr = '' + def rh(reply, fromaddr): + host, port = fromaddr + print host + '\t' + `reply` + pmap = BroadcastUDPPortMapperClient(bcastaddr) + pmap.set_reply_handler(rh) + pmap.set_timeout(5) + unused_replies = pmap.Getport((100002, 1, IPPROTO_UDP, 0)) + + +# Test program for server, with corresponding client +# On machine A: python -c 'import rpc; rpc.testsvr()' +# On machine B: python -c 'import rpc; rpc.testclt()' A +# (A may be == B) + +def testsvr(): + # Simple test class -- proc 1 doubles its string argument as reply + class S(UDPServer): + def handle_1(self): + arg = self.unpacker.unpack_string() + self.turn_around() + print 'RPC function 1 called, arg', `arg` + self.packer.pack_string(arg + arg) + # + s = S('', 0x20000000, 1, 0) + try: + s.unregister() + except PortMapError, e: + print 'RuntimeError:', e.args, '(ignored)' + s.register() + print 'Service started...' + try: + s.loop() + finally: + s.unregister() + print 'Service interrupted.' + + +def testclt(): + import sys + if sys.argv[1:]: host = sys.argv[1] + else: host = '' + # Client for above server + class C(UDPClient): + def call_1(self, arg): + return self.make_call(1, arg, \ + self.packer.pack_string, \ + self.unpacker.unpack_string) + c = C(host, 0x20000000, 1) + print 'making call...' + reply = c.call_1('hello, world, ') + print 'call returned', `reply` + + +# Local variables: +# py-indent-offset: 4 +# tab-width: 8 +# End: diff --git a/unfs3/contrib/rpcproxy/rpcproxy b/unfs3/contrib/rpcproxy/rpcproxy new file mode 100755 index 0000000..e800b1e --- /dev/null +++ b/unfs3/contrib/rpcproxy/rpcproxy @@ -0,0 +1,378 @@ +#!/usr/bin/env python +# -*-mode: python; coding: utf-8 -*- + +# TODO: +# Support for limiting data sizes, max number of connections from the same IP etc + +import sys +import time +import socket +import select +import struct + +# Connection states, both for client and server connection. +# Client cycle: STATE_READING, WAITING, WRITING +# Server cycle: WAITING, WRITING, STATE_READING +STATE_READING = 0 # Reading record +STATE_WAITING = 2 # Waiting for server response callback, or client mission. +STATE_WRITING = 3 # Writing response to client or request to server +STATE_EOF = 4 # EOF while reading + +# Constants +FRAG_HEADER_LEN = 4 +FRAG_MAX_SIZE = 2**31 - 1 +FRAG_SIZE = FRAG_MAX_SIZE # Size of newly created fragments + + +class ProxyEngine: + def __init__(self): + self.connections = [] # Client or server connections + self.proxies = [] # Proxy objects + + + def add_proxy(self, bind_address, port, host, hostport): + """Add a new proxy""" + proxy = Proxy(self, bind_address, port, host, hostport) + self.proxies.append(proxy) + self.connections.append(proxy.srv) + + def add_connection(self, conn): + """Add a new connection""" + self.connections.append(conn) + + +class Proxy: + def __init__(self, pe, bind_address, port, host, hostport): + self.pe = pe + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + self.sock.bind((bind_address, port)) + self.sock.listen(1) + self.srv = ServerConnection(host, hostport) + + + def fileno(self): + """Return the sockets fileno""" + return self.sock.fileno() + + + def handle_read(self): + """Accept a new connection. Return a new ClientConnection""" + sock, addr = self.sock.accept() + self.pe.add_connection(ClientConnection(sock, addr, self.srv)) + + +class ServerCall: + def __init__(self, data, callback): + self.data = data + self.callback = callback + + +class RPCConnection: + def __init__(self): + self.record = "" # Current record, as stream with RMs + self.sndbuf = None + self.sock = None + + + def set_sock(self, sock): + """Set socket to use""" + self.sock = sock + self.sndbuf = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF) + + + def eof_event(self): + """recv/send discovered that the connection was closed""" + self.state = STATE_EOF + self.sock.close() + + + def assert_sock(self): + """Make sure a socket is available. May be overridden.""" + assert self.sock is not None + + + def readable(self): + """Returns true if connection wants to read""" + return self.state is STATE_READING + + + def writable(self): + """Returns true if connection wants to write""" + return self.state is STATE_WRITING + + + def eof(self): + """Returns true if EOF has been detected""" + return self.state is STATE_EOF + + + def fileno(self): + """Return the sockets fileno""" + self.assert_sock() + return self.sock.fileno() + + + def write_record(self): + """Write RPC record. Returns true when everything is written""" + self.assert_sock() + # We can write up to SO_SNDBUF without risk blocking + wrote = self.sock.send(buffer(self.record, 0, self.sndbuf)) + self.record = self.record[wrote:] + return len(self.record) == 0 + + + def frag_length(self, head): + """Return the length of a fragment, including header""" + assert len(head) == FRAG_HEADER_LEN + x = struct.unpack('>L', head)[0] + return int(x & 0x7fffffff) + FRAG_HEADER_LEN + + + def frag_last(self, head): + """Return true if last flag is set""" + assert len(head) == FRAG_HEADER_LEN + x = struct.unpack('>L', head)[0] + return ((x & 0x80000000L) != 0) + + + def rm_stream(self, stream): + """Record-mark a data stream""" + fragpos = 0 + data = [] + + while 1: + last = (fragpos+FRAG_SIZE >= len(stream)) + frag_data = buffer(stream, fragpos, FRAG_SIZE) + x = len(frag_data) + if last: + x = x | 0x80000000L + frag_head = struct.pack('>L', x) + data.append(frag_head + str(frag_data)) + if last: + break + fragpos += len(frag_data) + + return "".join(data) + + + def parsed_record(self): + """Return tupel (data, missing_bytes) of record""" + fragpos = 0 + data = [] + while 1: + frag = buffer(self.record, fragpos) + fraghead = buffer(self.record, fragpos, FRAG_HEADER_LEN) + data.append(frag[4:]) + + if len(frag) < FRAG_HEADER_LEN: + return ("".join(data), FRAG_HEADER_LEN - len(frag)) + + len_from_head = self.frag_length(fraghead) + if len(frag) < len_from_head: + # Incomplete fragment + return ("".join(data), len_from_head - len(frag)) + elif len(frag) == len_from_head: + # Complete fragment + if self.frag_last(fraghead): + # No need to read anything more + return ("".join(data), 0) + else: + # Read another fragment + return ("".join(data), FRAG_HEADER_LEN) + elif len(frag) > len_from_head: + # There are more fragments, check them + fragpos += len(frag) + else: + assert 0 + + + def read_record(self): + """Read RPC record. Returns true if record complete""" + self.assert_sock() + assert self.state == STATE_READING + bytes_to_read = self.parsed_record()[1] + if bytes_to_read == 0: + return 1 + + data = self.sock.recv(bytes_to_read) + + if data == "": + self.eof_event() + return 0 + + self.record += data + return self.parsed_record()[1] == 0 + + +class ServerConnection(RPCConnection): + def __init__(self, host, port): + RPCConnection.__init__(self) + self.host = host + self.port = port + self.calls = [] # A list of ServerCalls + self.state = STATE_WAITING + self.current_cb = None + + + def eof_event(self): + """Overridden eof_event, which re-connects""" + print >>sys.stderr, "Lost connection to server, trying to reconnect." + # Discard the current call + self.current_cb("") + self.current_cb = None + if self.calls: + self.state = STATE_WRITING + else: + self.state = STATE_WAITING + + # Re-create socket + self.sock.close() + self.sock = None + self.assert_sock() + + + def assert_sock(self): + """Overridden assert_sock, which connects dynamically""" + if self.sock is None: + srv_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + while 1: + try: + srv_sock.connect((self.host, self.port)) + print >>sys.stderr, "Connected to %s:%d" % (self.host, self.port) + break + except socket.error, e: + print >>sys.stderr, "Connection to %s:%d failed: %s" % (self.host, self.port, e[1]) + time.sleep(5) + self.set_sock(srv_sock) + + + def call(self, servercall): + """Put another call on the call queue. The call argument is a + stream, without RMs. The callback will be called with result""" + self.calls.append(servercall) + if self.state == STATE_WAITING: + self.state = STATE_WRITING + + + def handle_read(self): + """Called when socket is ready for read""" + if self.read_record(): + self.current_cb(self.parsed_record()[0]) + self.current_cb = None + if self.calls: + self.state = STATE_WRITING + else: + self.state = STATE_WAITING + + + def handle_write(self): + """Called when socket is ready for write""" + assert self.state == STATE_WRITING + if self.current_cb is None: + # Start working on another request + servercall = self.calls.pop(0) + self.record = self.rm_stream(servercall.data) + self.current_cb = servercall.callback + + assert self.current_cb + if self.write_record(): + self.state = STATE_READING + self.record = "" + + +class ClientConnection(RPCConnection): + def __init__(self, sock, addr, srv): + RPCConnection.__init__(self) + self.set_sock(sock) + self.addr = addr + self.srv = srv + self.state = STATE_READING + + + def handle_read(self): + """Called when socket is ready for read""" + if self.read_record(): + self.state = STATE_WAITING + self.srv.call(ServerCall(self.parsed_record()[0], self.got_response)) + + + def handle_write(self): + """Called when socket is ready for write""" + assert self.state == STATE_WRITING + if self.write_record(): + self.state = STATE_READING + self.record = "" + + + def got_response(self, data): + """Callback: We got a response from the server""" + # send to client + self.state = STATE_WRITING + self.record = self.rm_stream(data) + + +def usage(): + sys.exit("Usage: %s [bind_address:]port:host:hostport ..." % sys.argv[0]) + + +def parse_arg(arg): + """Parse a command argument, specifying hosts and ports. + Returns tuple (bind_address, port, host, hostport)""" + fields = arg.split(":") + if len(fields) == 3: + fields.insert(0, "127.0.0.1") + + if len(fields) != 4: + usage() + + bind_address, port, host, hostport = fields + port = int(port) + hostport = int(hostport) + return bind_address, port, host, hostport + + +def main(): + if len(sys.argv) < 2: + usage() + + pe = ProxyEngine() + + # + # Determine hosts and ports + # + for arg in sys.argv[1:]: + pe.add_proxy(*parse_arg(arg)) + + # + # Select loop + # + while 1: + # Set up sets + read_set = [] + read_set.extend(pe.proxies) + write_set = [] + for conn in pe.connections: + if conn.readable(): + read_set.append(conn) + if conn.writable(): + write_set.append(conn) + + rlist, wlist, xlist = select.select(read_set, write_set, []) + + for obj in rlist: + obj.handle_read() + + for obj in wlist: + obj.handle_write() + + for conn in pe.connections: + if conn.eof(): + pe.connections.remove(conn) + + +if __name__ == "__main__": + try: + main() + except KeyboardInterrupt: + sys.exit(0) diff --git a/unfs3/daemon.c b/unfs3/daemon.c new file mode 100644 index 0000000..d14af45 --- /dev/null +++ b/unfs3/daemon.c @@ -0,0 +1,974 @@ + +/* + * UNFS3 server framework + * Originally generated using rpcgen + * Portions (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#include +#include +#include + +#ifndef WIN32 +#include +#include +#include +#include +#else /* WIN32 */ +#include +#endif /* WIN32 */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_RPC_SVC_SOC_H == 1 +# include +#endif + +#include "nfs.h" +#include "mount.h" +#include "xdr.h" +#include "fh.h" +#include "fh_cache.h" +#include "fd_cache.h" +#include "user.h" +#include "daemon.h" +#include "backend.h" +#include "Config/exports.h" + +#ifndef SIG_PF +#define SIG_PF void(*)(int) +#endif + +#define UNFS_NAME "UNFS3 unfsd " PACKAGE_VERSION " (C) 2006, Pascal Schmidt \n" + +/* write verifier */ +writeverf3 wverf; + +/* readdir cookie */ +cookie3 rcookie = 0; + +/* options and default values */ +int opt_detach = TRUE; +char *opt_exports = "/etc/exports"; +int opt_cluster = FALSE; +char *opt_cluster_path = "/"; +int opt_tcponly = FALSE; +unsigned int opt_nfs_port = NFS_PORT; /* 0 means RPC_ANYSOCK */ +unsigned int opt_mount_port = NFS_PORT; +int opt_singleuser = FALSE; +int opt_brute_force = FALSE; +int opt_testconfig = FALSE; +struct in_addr opt_bind_addr; +int opt_readable_executables = FALSE; +char *opt_pid_file = NULL; + +/* Register with portmapper? */ +int opt_portmapper = TRUE; + +/* + * output message to syslog or stdout + */ +void logmsg(int prio, const char *fmt, ...) +{ + va_list ap; + +#if HAVE_VSYSLOG == 0 + char mesg[1024]; +#endif + + va_start(ap, fmt); + if (opt_detach) { +#if HAVE_VSYSLOG == 1 + vsyslog(prio, fmt, ap); +#else + vsnprintf(mesg, 1024, fmt, ap); + syslog(prio, mesg, 1024); +#endif + } else { + vprintf(fmt, ap); + putchar('\n'); + } + va_end(ap); +} + +/* + * return remote address from svc_req structure + */ +struct in_addr get_remote(struct svc_req *rqstp) +{ + return (svc_getcaller(rqstp->rq_xprt))->sin_addr; +} + +/* + * return remote port from svc_req structure + */ +short get_port(struct svc_req *rqstp) +{ + return (svc_getcaller(rqstp->rq_xprt))->sin_port; +} + +/* + * return the socket type of the request (SOCK_STREAM or SOCK_DGRAM) + */ +int get_socket_type(struct svc_req *rqstp) +{ + int v, res; + socklen_t l; + + l = sizeof(v); + +#if HAVE_STRUCT___RPC_SVCXPRT_XP_FD == 1 + res = getsockopt(rqstp->rq_xprt->xp_fd, SOL_SOCKET, SO_TYPE, &v, &l); +#else + res = getsockopt(rqstp->rq_xprt->xp_sock, SOL_SOCKET, SO_TYPE, &v, &l); +#endif + + if (res < 0) { + logmsg(LOG_CRIT, "unable to determine socket type"); + return -1; + } + + return v; +} + +/* + * write current pid to a file + */ +static void create_pid_file(void) +{ + char buf[16]; + int fd, res, len; + + if (!opt_pid_file) + return; + + fd = backend_open_create(opt_pid_file, O_RDWR | O_CREAT | O_TRUNC, 0644); + if (fd == -1) { + logmsg(LOG_WARNING, "failed to create pid file `%s'", opt_pid_file); + return; + } +#if defined(LOCK_EX) && defined(LOCK_NB) + res = backend_flock(fd, LOCK_EX | LOCK_NB); + if (res == -1) { + logmsg(LOG_WARNING, "failed to lock pid file `%s'", opt_pid_file); + backend_close(fd); + return; + } +#endif + + sprintf(buf, "%i\n", backend_getpid()); + len = strlen(buf); + + res = backend_pwrite(fd, buf, len, 0); + backend_close(fd); + if (res != len) { + logmsg(LOG_WARNING, "failed to write pid file `%s'", opt_pid_file); + } +} + +/* + * remove pid file + */ +static void remove_pid_file(void) +{ + int res; + + if (!opt_pid_file) + return; + + res = backend_remove(opt_pid_file); + if (res == -1 && errno != ENOENT) { + logmsg(LOG_WARNING, "failed to remove pid file `%s'", opt_pid_file); + } +} + +/* + * parse command line options + */ +static void parse_options(int argc, char **argv) +{ + int opt = 0; + char *optstring = "bcC:de:hl:m:n:prstTuwi:"; + + while (opt != -1) { + opt = getopt(argc, argv, optstring); + switch (opt) { + case 'b': + opt_brute_force = TRUE; + break; +#ifdef WANT_CLUSTER + case 'c': + opt_cluster = TRUE; + break; + case 'C': + opt_cluster_path = optarg; + break; +#endif + case 'd': + printf(UNFS_NAME); + opt_detach = FALSE; + break; + case 'e': +#ifndef WIN32 + if (optarg[0] != '/') { + /* A relative path won't work for re-reading the exports + file on SIGHUP, since we are changing directory */ + fprintf(stderr, "Error: relative path to exports file\n"); + exit(1); + } +#endif + opt_exports = optarg; + break; + case 'h': + printf(UNFS_NAME); + printf("Usage: %s [options]\n", argv[0]); + printf("\t-h display this short option summary\n"); + printf("\t-u use unprivileged port for services\n"); + printf("\t-d do not detach from terminal\n"); + printf("\t-e file to use instead of /etc/exports\n"); + printf("\t-i write daemon pid to given file\n"); +#ifdef WANT_CLUSTER + printf("\t-c enable cluster extensions\n"); + printf("\t-C set path for cluster extensions\n"); +#endif + printf("\t-n port to use for NFS service\n"); + printf("\t-m port to use for MOUNT service\n"); + printf + ("\t-t TCP only, do not listen on UDP ports\n"); + printf("\t-p do not register with the portmapper\n"); + printf("\t-s single user mode\n"); + printf("\t-b enable brute force file searching\n"); + printf + ("\t-l bind to interface with specified address\n"); + printf + ("\t-r report unreadable executables as readable\n"); + printf("\t-T test exports file and exit\n"); + exit(0); + break; + case 'l': + opt_bind_addr.s_addr = inet_addr(optarg); + if (opt_bind_addr.s_addr == (unsigned) -1) { + fprintf(stderr, "Invalid bind address\n"); + exit(1); + } + break; + case 'm': + opt_mount_port = strtol(optarg, NULL, 10); + if (opt_mount_port == 0) { + fprintf(stderr, "Invalid port\n"); + exit(1); + } + break; + case 'n': + opt_nfs_port = strtol(optarg, NULL, 10); + if (opt_nfs_port == 0) { + fprintf(stderr, "Invalid port\n"); + exit(1); + } + break; + case 'p': + opt_portmapper = FALSE; + break; + case 'r': + opt_readable_executables = TRUE; + break; + case 's': + opt_singleuser = TRUE; +#ifndef WIN32 + if (backend_getuid() == 0) { + logmsg(LOG_WARNING, + "Warning: running as root with -s is dangerous"); + logmsg(LOG_WARNING, + "All clients will have root access to all exported files!"); + } +#endif + break; + case 't': + opt_tcponly = TRUE; + break; + case 'T': + opt_testconfig = TRUE; + break; + case 'u': + opt_nfs_port = 0; + opt_mount_port = 0; + break; + case 'i': + opt_pid_file = optarg; + break; + case '?': + exit(1); + break; + } + } +} + +/* + * signal handler and error exit function + */ +void daemon_exit(int error) +{ +#ifndef WIN32 + if (error == SIGHUP) { + get_squash_ids(); + exports_parse(); + return; + } + + if (error == SIGUSR1) { + if (fh_cache_use > 0) + logmsg(LOG_INFO, "fh entries %i access %i hit %i miss %i", + fh_cache_max, fh_cache_use, fh_cache_hit, + fh_cache_use - fh_cache_hit); + else + logmsg(LOG_INFO, "fh cache unused"); + logmsg(LOG_INFO, "open file descriptors: read %i, write %i", + fd_cache_readers, fd_cache_writers); + return; + } +#endif /* WIN32 */ + + if (opt_portmapper) { + svc_unregister(MOUNTPROG, MOUNTVERS1); + svc_unregister(MOUNTPROG, MOUNTVERS3); + } + + if (opt_portmapper) { + svc_unregister(NFS3_PROGRAM, NFS_V3); + } + + if (error == SIGSEGV) + logmsg(LOG_EMERG, "segmentation fault"); + + fd_cache_purge(); + + if (opt_detach) + closelog(); + + remove_pid_file(); + backend_shutdown(); + + exit(1); +} + +/* + * NFS service dispatch function + * generated by rpcgen + */ +static void nfs3_program_3(struct svc_req *rqstp, register SVCXPRT * transp) +{ + union { + GETATTR3args nfsproc3_getattr_3_arg; + SETATTR3args nfsproc3_setattr_3_arg; + LOOKUP3args nfsproc3_lookup_3_arg; + ACCESS3args nfsproc3_access_3_arg; + READLINK3args nfsproc3_readlink_3_arg; + READ3args nfsproc3_read_3_arg; + WRITE3args nfsproc3_write_3_arg; + CREATE3args nfsproc3_create_3_arg; + MKDIR3args nfsproc3_mkdir_3_arg; + SYMLINK3args nfsproc3_symlink_3_arg; + MKNOD3args nfsproc3_mknod_3_arg; + REMOVE3args nfsproc3_remove_3_arg; + RMDIR3args nfsproc3_rmdir_3_arg; + RENAME3args nfsproc3_rename_3_arg; + LINK3args nfsproc3_link_3_arg; + READDIR3args nfsproc3_readdir_3_arg; + READDIRPLUS3args nfsproc3_readdirplus_3_arg; + FSSTAT3args nfsproc3_fsstat_3_arg; + FSINFO3args nfsproc3_fsinfo_3_arg; + PATHCONF3args nfsproc3_pathconf_3_arg; + COMMIT3args nfsproc3_commit_3_arg; + } argument; + char *result; + xdrproc_t _xdr_argument, _xdr_result; + char *(*local) (char *, struct svc_req *); + + switch (rqstp->rq_proc) { + case NFSPROC3_NULL: + _xdr_argument = (xdrproc_t) xdr_void; + _xdr_result = (xdrproc_t) xdr_void; + local = (char *(*)(char *, struct svc_req *)) nfsproc3_null_3_svc; + break; + + case NFSPROC3_GETATTR: + _xdr_argument = (xdrproc_t) xdr_GETATTR3args; + _xdr_result = (xdrproc_t) xdr_GETATTR3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_getattr_3_svc; + break; + + case NFSPROC3_SETATTR: + _xdr_argument = (xdrproc_t) xdr_SETATTR3args; + _xdr_result = (xdrproc_t) xdr_SETATTR3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_setattr_3_svc; + break; + + case NFSPROC3_LOOKUP: + _xdr_argument = (xdrproc_t) xdr_LOOKUP3args; + _xdr_result = (xdrproc_t) xdr_LOOKUP3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_lookup_3_svc; + break; + + case NFSPROC3_ACCESS: + _xdr_argument = (xdrproc_t) xdr_ACCESS3args; + _xdr_result = (xdrproc_t) xdr_ACCESS3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_access_3_svc; + break; + + case NFSPROC3_READLINK: + _xdr_argument = (xdrproc_t) xdr_READLINK3args; + _xdr_result = (xdrproc_t) xdr_READLINK3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_readlink_3_svc; + break; + + case NFSPROC3_READ: + _xdr_argument = (xdrproc_t) xdr_READ3args; + _xdr_result = (xdrproc_t) xdr_READ3res; + local = (char *(*)(char *, struct svc_req *)) nfsproc3_read_3_svc; + break; + + case NFSPROC3_WRITE: + _xdr_argument = (xdrproc_t) xdr_WRITE3args; + _xdr_result = (xdrproc_t) xdr_WRITE3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_write_3_svc; + break; + + case NFSPROC3_CREATE: + _xdr_argument = (xdrproc_t) xdr_CREATE3args; + _xdr_result = (xdrproc_t) xdr_CREATE3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_create_3_svc; + break; + + case NFSPROC3_MKDIR: + _xdr_argument = (xdrproc_t) xdr_MKDIR3args; + _xdr_result = (xdrproc_t) xdr_MKDIR3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_mkdir_3_svc; + break; + + case NFSPROC3_SYMLINK: + _xdr_argument = (xdrproc_t) xdr_SYMLINK3args; + _xdr_result = (xdrproc_t) xdr_SYMLINK3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_symlink_3_svc; + break; + + case NFSPROC3_MKNOD: + _xdr_argument = (xdrproc_t) xdr_MKNOD3args; + _xdr_result = (xdrproc_t) xdr_MKNOD3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_mknod_3_svc; + break; + + case NFSPROC3_REMOVE: + _xdr_argument = (xdrproc_t) xdr_REMOVE3args; + _xdr_result = (xdrproc_t) xdr_REMOVE3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_remove_3_svc; + break; + + case NFSPROC3_RMDIR: + _xdr_argument = (xdrproc_t) xdr_RMDIR3args; + _xdr_result = (xdrproc_t) xdr_RMDIR3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_rmdir_3_svc; + break; + + case NFSPROC3_RENAME: + _xdr_argument = (xdrproc_t) xdr_RENAME3args; + _xdr_result = (xdrproc_t) xdr_RENAME3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_rename_3_svc; + break; + + case NFSPROC3_LINK: + _xdr_argument = (xdrproc_t) xdr_LINK3args; + _xdr_result = (xdrproc_t) xdr_LINK3res; + local = (char *(*)(char *, struct svc_req *)) nfsproc3_link_3_svc; + break; + + case NFSPROC3_READDIR: + _xdr_argument = (xdrproc_t) xdr_READDIR3args; + _xdr_result = (xdrproc_t) xdr_READDIR3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_readdir_3_svc; + break; + + case NFSPROC3_READDIRPLUS: + _xdr_argument = (xdrproc_t) xdr_READDIRPLUS3args; + _xdr_result = (xdrproc_t) xdr_READDIRPLUS3res; + local = (char *(*)(char *, struct svc_req *)) + nfsproc3_readdirplus_3_svc; + break; + + case NFSPROC3_FSSTAT: + _xdr_argument = (xdrproc_t) xdr_FSSTAT3args; + _xdr_result = (xdrproc_t) xdr_FSSTAT3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_fsstat_3_svc; + break; + + case NFSPROC3_FSINFO: + _xdr_argument = (xdrproc_t) xdr_FSINFO3args; + _xdr_result = (xdrproc_t) xdr_FSINFO3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_fsinfo_3_svc; + break; + + case NFSPROC3_PATHCONF: + _xdr_argument = (xdrproc_t) xdr_PATHCONF3args; + _xdr_result = (xdrproc_t) xdr_PATHCONF3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_pathconf_3_svc; + break; + + case NFSPROC3_COMMIT: + _xdr_argument = (xdrproc_t) xdr_COMMIT3args; + _xdr_result = (xdrproc_t) xdr_COMMIT3res; + local = + (char *(*)(char *, struct svc_req *)) nfsproc3_commit_3_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + memset((char *) &argument, 0, sizeof(argument)); + if (!svc_getargs(transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) { + svcerr_decode(transp); + return; + } + result = (*local) ((char *) &argument, rqstp); + if (result != NULL && + !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) { + svcerr_systemerr(transp); + logmsg(LOG_CRIT, "unable to send RPC reply"); + } + if (!svc_freeargs + (transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) { + logmsg(LOG_CRIT, "unable to free XDR arguments"); + } + return; +} + +/* + * mount protocol dispatcher + * generated by rpcgen + */ +static void mountprog_3(struct svc_req *rqstp, register SVCXPRT * transp) +{ + union { + dirpath mountproc_mnt_3_arg; + dirpath mountproc_umnt_3_arg; + } argument; + char *result; + xdrproc_t _xdr_argument, _xdr_result; + char *(*local) (char *, struct svc_req *); + + switch (rqstp->rq_proc) { + case MOUNTPROC_NULL: + _xdr_argument = (xdrproc_t) xdr_void; + _xdr_result = (xdrproc_t) xdr_void; + local = + (char *(*)(char *, struct svc_req *)) mountproc_null_3_svc; + break; + + case MOUNTPROC_MNT: + _xdr_argument = (xdrproc_t) xdr_dirpath; + _xdr_result = (xdrproc_t) xdr_mountres3; + local = (char *(*)(char *, struct svc_req *)) mountproc_mnt_3_svc; + break; + + case MOUNTPROC_DUMP: + _xdr_argument = (xdrproc_t) xdr_void; + _xdr_result = (xdrproc_t) xdr_mountlist; + local = + (char *(*)(char *, struct svc_req *)) mountproc_dump_3_svc; + break; + + case MOUNTPROC_UMNT: + _xdr_argument = (xdrproc_t) xdr_dirpath; + _xdr_result = (xdrproc_t) xdr_void; + local = + (char *(*)(char *, struct svc_req *)) mountproc_umnt_3_svc; + break; + + case MOUNTPROC_UMNTALL: + _xdr_argument = (xdrproc_t) xdr_void; + _xdr_result = (xdrproc_t) xdr_void; + local = + (char *(*)(char *, struct svc_req *)) mountproc_umntall_3_svc; + break; + + case MOUNTPROC_EXPORT: + _xdr_argument = (xdrproc_t) xdr_void; + _xdr_result = (xdrproc_t) xdr_exports; + local = + (char *(*)(char *, struct svc_req *)) mountproc_export_3_svc; + break; + + default: + svcerr_noproc(transp); + return; + } + memset((char *) &argument, 0, sizeof(argument)); + if (!svc_getargs(transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) { + svcerr_decode(transp); + return; + } + result = (*local) ((char *) &argument, rqstp); + if (result != NULL && + !svc_sendreply(transp, (xdrproc_t) _xdr_result, result)) { + svcerr_systemerr(transp); + logmsg(LOG_CRIT, "unable to send RPC reply"); + } + if (!svc_freeargs + (transp, (xdrproc_t) _xdr_argument, (caddr_t) & argument)) { + logmsg(LOG_CRIT, "unable to free XDR arguments"); + } + return; +} + +static void register_nfs_service(SVCXPRT * udptransp, SVCXPRT * tcptransp) +{ + if (opt_portmapper) { + pmap_unset(NFS3_PROGRAM, NFS_V3); + } + + if (udptransp != NULL) { + /* Register NFS service for UDP */ + if (!svc_register + (udptransp, NFS3_PROGRAM, NFS_V3, nfs3_program_3, + opt_portmapper ? IPPROTO_UDP : 0)) { + fprintf(stderr, "%s\n", + "unable to register (NFS3_PROGRAM, NFS_V3, udp)."); + daemon_exit(0); + } + } + + if (tcptransp != NULL) { + /* Register NFS service for TCP */ + if (!svc_register + (tcptransp, NFS3_PROGRAM, NFS_V3, nfs3_program_3, + opt_portmapper ? IPPROTO_TCP : 0)) { + fprintf(stderr, "%s\n", + "unable to register (NFS3_PROGRAM, NFS_V3, tcp)."); + daemon_exit(0); + } + } +} + +static void register_mount_service(SVCXPRT * udptransp, SVCXPRT * tcptransp) +{ + if (opt_portmapper) { + pmap_unset(MOUNTPROG, MOUNTVERS1); + pmap_unset(MOUNTPROG, MOUNTVERS3); + } + + if (udptransp != NULL) { + /* Register MOUNT service (v1) for UDP */ + if (!svc_register + (udptransp, MOUNTPROG, MOUNTVERS1, mountprog_3, + opt_portmapper ? IPPROTO_UDP : 0)) { + fprintf(stderr, "%s\n", + "unable to register (MOUNTPROG, MOUNTVERS1, udp)."); + daemon_exit(0); + } + + /* Register MOUNT service (v3) for UDP */ + if (!svc_register + (udptransp, MOUNTPROG, MOUNTVERS3, mountprog_3, + opt_portmapper ? IPPROTO_UDP : 0)) { + fprintf(stderr, "%s\n", + "unable to register (MOUNTPROG, MOUNTVERS3, udp)."); + daemon_exit(0); + } + } + + if (tcptransp != NULL) { + /* Register MOUNT service (v1) for TCP */ + if (!svc_register + (tcptransp, MOUNTPROG, MOUNTVERS1, mountprog_3, + opt_portmapper ? IPPROTO_TCP : 0)) { + fprintf(stderr, "%s\n", + "unable to register (MOUNTPROG, MOUNTVERS1, tcp)."); + daemon_exit(0); + } + + /* Register MOUNT service (v3) for TCP */ + if (!svc_register + (tcptransp, MOUNTPROG, MOUNTVERS3, mountprog_3, + opt_portmapper ? IPPROTO_TCP : 0)) { + fprintf(stderr, "%s\n", + "unable to register (MOUNTPROG, MOUNTVERS3, tcp)."); + daemon_exit(0); + } + } +} + +static SVCXPRT *create_udp_transport(unsigned int port) +{ + SVCXPRT *transp = NULL; + struct sockaddr_in sin; + int sock; + const int on = 1; + + if (port == 0) + sock = RPC_ANYSOCK; + else { + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = opt_bind_addr.s_addr; + sock = socket(PF_INET, SOCK_DGRAM, 0); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); + if (bind(sock, (struct sockaddr *) &sin, sizeof(struct sockaddr))) { + perror("bind"); + fprintf(stderr, "Couldn't bind to udp port %d\n", port); + exit(1); + } + } + + transp = svcudp_bufcreate(sock, NFS_MAX_UDP_PACKET, NFS_MAX_UDP_PACKET); + + if (transp == NULL) { + fprintf(stderr, "%s\n", "cannot create udp service."); + daemon_exit(0); + } + + return transp; +} + +static SVCXPRT *create_tcp_transport(unsigned int port) +{ + SVCXPRT *transp = NULL; + struct sockaddr_in sin; + int sock; + const int on = 1; + + if (port == 0) + sock = RPC_ANYSOCK; + else { + sin.sin_family = AF_INET; + sin.sin_port = htons(port); + sin.sin_addr.s_addr = opt_bind_addr.s_addr; + sock = socket(PF_INET, SOCK_STREAM, 0); + setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); + if (bind(sock, (struct sockaddr *) &sin, sizeof(struct sockaddr))) { + perror("bind"); + fprintf(stderr, "Couldn't bind to tcp port %d\n", port); + exit(1); + } + } + + transp = svctcp_create(sock, 0, 0); + + if (transp == NULL) { + fprintf(stderr, "%s\n", "cannot create tcp service."); + daemon_exit(0); + } + + return transp; +} + +/* Run RPC service. This is our own implementation of svc_run(), which + allows us to handle other events as well. */ +static void unfs3_svc_run() +{ + fd_set readfds; + struct timeval tv; + + for (;;) { + fd_cache_close_inactive(); + readfds = svc_fdset; + tv.tv_sec = 1; + tv.tv_usec = 0; + /* Note: On Windows, it's not possible to call select with all sets + empty; to use it as a sleep function. In our case, however, + readfds should never be empty, since we always have our listen + socket. Well, at least hope that our Windows RPC library works + like that. oncrpc-ms does. */ + switch (select(FD_SETSIZE, &readfds, NULL, NULL, &tv)) { + case -1: + if (errno == EINTR) { + continue; + } + perror("unfs3_svc_run: select failed"); + return; + case 0: + /* timeout */ + continue; + default: + svc_getreqset(&readfds); + } + } +} + +/* + * Generate write verifier based on PID and current time + */ +void regenerate_write_verifier(void) +{ + *(wverf + 0) = (uint32) getpid(); + *(wverf + 0) ^= rand(); + *(wverf + 4) = (uint32) time(NULL); +} + +/* + * Change readdir cookie value + */ +void change_readdir_cookie(void) +{ + rcookie = rcookie >> 32; + ++rcookie; + rcookie = rcookie << 32; +} + +/* + * NFSD main function + * originally generated by rpcgen + * forking, logging, options, and signal handler stuff added + */ +int main(int argc, char **argv) +{ + register SVCXPRT *tcptransp = NULL, *udptransp = NULL; + pid_t pid = 0; + +#ifndef WIN32 + struct sigaction act; + sigset_t actset; +#endif /* WIN32 */ + int res; + + opt_bind_addr.s_addr = INADDR_ANY; + + parse_options(argc, argv); + if (optind < argc) { + fprintf(stderr, "Error: extra arguments on command line\n"); + exit(1); + } + + /* init write verifier */ + regenerate_write_verifier(); + + res = backend_init(); + if (res == -1) { + fprintf(stderr, "backend initialization failed\n"); + daemon_exit(0); + } + + /* config test mode */ + if (opt_testconfig) { + res = exports_parse(); + if (res) { + exit(0); + } else { + fprintf(stderr, "Parse error in `%s'\n", opt_exports); + exit(1); + } + } + + if (opt_detach) { + /* prepare syslog access */ + openlog("unfsd", LOG_CONS | LOG_PID, LOG_DAEMON); + } else { + /* flush stdout after each newline */ + setvbuf(stdout, NULL, _IOLBF, 0); + } + + /* NFS transports */ + if (!opt_tcponly) + udptransp = create_udp_transport(opt_nfs_port); + tcptransp = create_tcp_transport(opt_nfs_port); + + register_nfs_service(udptransp, tcptransp); + + /* MOUNT transports. If ports are equal, then the MOUNT service can reuse + the NFS transports. */ + if (opt_mount_port != opt_nfs_port) { + if (!opt_tcponly) + udptransp = create_udp_transport(opt_mount_port); + tcptransp = create_tcp_transport(opt_mount_port); + } + + register_mount_service(udptransp, tcptransp); + +#ifndef WIN32 + if (opt_detach) { + pid = fork(); + if (pid == -1) { + fprintf(stderr, "could not fork into background\n"); + daemon_exit(0); + } + } +#endif /* WIN32 */ + + if (!opt_detach || pid == 0) { +#ifndef WIN32 + sigemptyset(&actset); + act.sa_handler = daemon_exit; + act.sa_mask = actset; + act.sa_flags = 0; + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGINT, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGUSR1, &act, NULL); + + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, NULL); + sigaction(SIGUSR2, &act, NULL); + sigaction(SIGALRM, &act, NULL); + + /* don't make directory we started in busy */ + chdir("/"); + + /* detach from terminal */ + if (opt_detach) { + setsid(); + fclose(stdin); + fclose(stdout); + fclose(stderr); + } +#endif /* WIN32 */ + + /* no umask to not screw up create modes */ + umask(0); + + /* create pid file if wanted */ + create_pid_file(); + + /* initialize internal stuff */ + fh_cache_init(); + fd_cache_init(); + get_squash_ids(); + exports_parse(); + + unfs3_svc_run(); + exit(1); + /* NOTREACHED */ + } + + return 0; +} diff --git a/unfs3/daemon.h b/unfs3/daemon.h new file mode 100644 index 0000000..13b20af --- /dev/null +++ b/unfs3/daemon.h @@ -0,0 +1,49 @@ +/* + * UNFS3 server framework + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_DAEMON_H +#define UNFS3_DAEMON_H + +#include "nfs.h" + +/* exit status for internal errors */ +#define CRISIS 99 + +/* HP-UX does not have seteuid() and setegid() */ +#if HAVE_SETEUID == 0 && HAVE_SETRESUID == 1 +#define seteuid(u) setresuid(-1, u, -1) +#endif +#if HAVE_SETEGID == 0 && HAVE_SETRESGID == 1 +#define setegid(g) setresgid(-1, g, -1) +#endif + +/* error handling */ +void daemon_exit(int); +void logmsg(int, const char *, ...); + +/* remote address */ +struct in_addr get_remote(struct svc_req *); +short get_port(struct svc_req *); +int get_socket_type(struct svc_req *rqstp); + +/* write verifier */ +extern writeverf3 wverf; +void regenerate_write_verifier(void); + +/* readdir cookie */ +extern cookie3 rcookie; +void change_readdir_cookie(void); + +/* options */ +extern int opt_detach; +extern char *opt_exports; +extern int opt_cluster; +extern char *opt_cluster_path; +extern int opt_singleuser; +extern int opt_brute_force; +extern int opt_readable_executables; + +#endif diff --git a/unfs3/debian/changelog b/unfs3/debian/changelog new file mode 100644 index 0000000..53e9705 --- /dev/null +++ b/unfs3/debian/changelog @@ -0,0 +1,88 @@ +unfs3 (0.9.22+dfsg-1maemo2) unstable; urgency=low + + * init.d script changed to start portmap + + -- Walter Thu, 4 Jun 2009 10:53:07 -0400 + +unfs3 (0.9.22+dfsg-1maemo1) unstable; urgency=low + + * Downgrading pacakge to debhelper 5. + + -- Hallyson Melo Mon, 26 Jan 2009 15:20:20 -0300 + +unfs3 (0.9.22+dfsg-1) unstable; urgency=low + + * Updating vcs fields in control file. + * Replacing obsolete dh_clean -k with dh_prep. + * Merging upstream version 0.9.22+dfsg. + * Prefixing debhelper files with package name. + * Upgrading package to debhelper 7. + * Updating year in copyright. + * Updating rules to current state of the art. + + -- Daniel Baumann Sun, 25 Jan 2009 02:50:00 +0100 + +unfs3 (0.9.21+dfsg-1) unstable; urgency=low + + * Merging upstream version 0.9.21+dfsg. + + -- Daniel Baumann Wed, 16 Jul 2008 01:09:00 +0200 + +unfs3 (0.9.20+dfsg-2) unstable; urgency=low + + * Don't hide make errors in clean target of rules. + + -- Daniel Baumann Sun, 23 Dec 2007 21:14:00 +0100 + +unfs3 (0.9.20+dfsg-1) unstable; urgency=low + + * New upstream release. + + -- Daniel Baumann Sat, 22 Dec 2007 12:18:00 +0100 + +unfs3 (0.9.19+dfsg-1) unstable; urgency=low + + * New upstream release: + - fix auxiliary group support (Closes: #432896). + + -- Daniel Baumann Mon, 26 Nov 2007 21:52:00 +0100 + +unfs3 (0.9.18+dfsg-1) unstable; urgency=low + + * New upstream release. + + -- Daniel Baumann Tue, 4 Sep 2007 23:19:00 +0200 + +unfs3 (0.9.17+dfsg-1) unstable; urgency=low + + * New upstream release. + * Added lsb header to the init script. + + -- Daniel Baumann Mon, 12 Mar 2007 10:07:00 +0100 + +unfs3 (0.9.16+dfsg-1) unstable; urgency=low + + * New upstream release. + + -- Daniel Baumann Thu, 18 Jan 2007 11:27:00 +0100 + +unfs3 (0.9.15+dfsg-1) unstable; urgency=low + + * New upstream release. + + -- Daniel Baumann Sat, 7 Oct 2006 00:31:00 +0200 + +unfs3 (0.9.13+dfsg-2) unstable; urgency=low + + * New email address. + * Bumped policy version. + * Added note about locking to the long-description (Closes: #358925). + + -- Daniel Baumann Sat, 8 Jul 2006 14:55:00 +0200 + +unfs3 (0.9.13+dfsg-1) unstable; urgency=low + + * Initial release (Closes: #214872). + * Rebuild upstream-tarball without contrib directory due to missing license. + + -- Daniel Baumann Sat, 28 Jan 2006 14:37:00 +0100 diff --git a/unfs3/debian/compat b/unfs3/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/unfs3/debian/compat @@ -0,0 +1 @@ +5 diff --git a/unfs3/debian/control b/unfs3/debian/control new file mode 100644 index 0000000..7f5efec --- /dev/null +++ b/unfs3/debian/control @@ -0,0 +1,23 @@ +Source: unfs3 +Section: net +Priority: optional +Maintainer: Daniel Baumann +Build-Depends: debhelper (>= 5), autotools-dev, bison, flex +Standards-Version: 3.8.0 +Homepage: http://unfs3.sourceforge.net/ +Vcs-Browser: http://git.debian.net/?p=debian/unfs3.git +Vcs-Git: git://git.debian.net/git/debian/unfs3.git + +Package: unfs3 +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, portmap +Conflicts: nfs-server +Replaces: nfs-server +Provides: nfs-server +Description: User-space NFSv3 Server + UNFS3 is a user-space implementation of the NFSv3 server specification. It + provides a daemon for the MOUNT and NFS protocols, which are used by NFS + clients for accessing files on the server. + . + Unlike nfs-user-server, unfs3 is capable of handling files larger than 2GB, but + there is currently no support for file locking. diff --git a/unfs3/debian/copyright b/unfs3/debian/copyright new file mode 100644 index 0000000..5433015 --- /dev/null +++ b/unfs3/debian/copyright @@ -0,0 +1,81 @@ +Author: Pascal Schmidt +Download: http://unfs3.sourceforge.net/ + +Files: * +Copyright: (C) 2003-2009 Pascal Schmidt +License: BSD + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +Files: md5.* +Copyright (C) 1999-2002 Aladdin Enterprises +License: BSD + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + . + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + . + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + . + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + . + 3. This notice may not be removed or altered from any source distribution. + +Files: debian/* +Copyright: (C) 2006-2009 Daniel Baumann +License: BSD + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + . + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + . + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + . + 3. The name of the author may not be used to endorse or promote products + derived from this software without specific prior written permission. + . + THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. diff --git a/unfs3/debian/rules b/unfs3/debian/rules new file mode 100755 index 0000000..fb2332c --- /dev/null +++ b/unfs3/debian/rules @@ -0,0 +1,73 @@ +#!/usr/bin/make -f + +DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +ifneq ($(DEB_HOST_GNU_TYPE),$(DEB_BUILD_GNU_TYPE)) + CROSS=CC=$(DEB_HOST_GNU_TYPE)-gcc +else + CROSS= +endif + +upstream: + rm -rf contrib # No license attached. + +clean: + dh_testdir + dh_testroot + rm -f build-stamp + rm -f config.guess config.sub + + [ ! -f Makefile ] || $(MAKE) distclean + + dh_clean + +config.status: configure + dh_testdir + +ifneq "$(wildcard /usr/share/misc/config.sub)" "" + cp -f /usr/share/misc/config.sub config.sub +endif +ifneq "$(wildcard /usr/share/misc/config.guess)" "" + cp -f /usr/share/misc/config.guess config.guess +endif + + ./configure $(CROSS) --prefix=/usr --mandir=\$${prefix}/share/man --enable-cluster CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,defs" + +build: build-stamp +build-stamp: config.status + dh_testdir + + $(MAKE) + + touch build-stamp + +install: build + dh_testdir + dh_testroot + dh_clean -k + dh_installdirs + + $(MAKE) install prefix=$(CURDIR)/debian/unfs3/usr + +binary: binary-arch + +binary-arch: install + dh_testdir + dh_testroot + dh_installchangelogs + dh_installdocs + dh_installinit --update-rcd-params='defaults 25' + dh_installman + dh_strip + dh_compress + dh_fixperms + dh_installdeb + dh_shlibdeps + dh_gencontrol + dh_md5sums + dh_builddeb + +binary-indep: + +.PHONY: clean build install binary binary-arch binary-indep diff --git a/unfs3/debian/unfs3.default b/unfs3/debian/unfs3.default new file mode 100644 index 0000000..f93fdbe --- /dev/null +++ b/unfs3/debian/unfs3.default @@ -0,0 +1,88 @@ +# Defaults for unfs3 (user-space NFSv3 server) + +# Unprivileged port +# Use an unprivileged port for NFS and MOUNT service. Normally, unfsd will use +# port number 2049, which is the standard port for NFS. When this option is in +# effect, arbitrary ports chosen by the RPC library will be used. You may need +# to use this option when running unfsd from a normal user account. +PORT_UNPRIVILEGED="-u" + +# Specified port +# Use the specified port for the NFS service. +PORT_NFS="2049" + +# Specified port (MOUNT service) +# Use the specified port for the MOUNT service. The default is to use port +# number 2049, the same as for the NFS service. You can use the same port for +# both services if you want. +PORT_MOUNT="2049" + +# TCP only operation +# By default, unfsd provides its services to clients using either UDP or TCP as +# communications protocol. When this option is present, only TCP connections are +# serviced. +#TCP_ONLY="-t" + +# Register with the portmapper +# Do not register with the portmapper. This will prevent other hosts from +# finding out the port numbers used for the MOUNT and NFS services by querying +# the portmap daemon. Clients will need to manually specify the port numbers to +# use (on Linux clients, use the mountport and port mount options). +#NO_PORTMAPPER="-p" + +# Expiring write cache +# Allow the built-in file descriptor cache to expire writers. For performance +# reasons, unfsd keeps file descriptors open across multiple READ or WRITE +# requests. Normally, only READ file descriptors will be expired from the cache +# when it fills up. Setting this option allows file descriptors from WRITE +# operations to be expired, too. When this happens, pending data will be +# written to the server filesystem. However, if an error occurs while doing +# this, there is no way to notify the NFS client of the error. A message +# indicating the problem will be sent to the system log on the server. +#NO_WRITE_CACHE="-w" + +# Cluster extensions +# Enable cluster extensions. When this option is enabled, so-called tagged +# files are handled differently from normal files, making it possible to +# serve different file contents to different clients for the same filename. +# See tags(7) for a description of tagged files. This option causes a +# performance hit. +#CLUSTER_EXTENSION="-c" + +# Cluster path +# Limit the use of cluster extensions to a list of colon-seperated directories. +# When this option is present, the performance hit caused by clustering +# extensions only applies to the listed directories and their subdirectories. +#CLUSTER_PATH="-C /" + +# Single user mode +# Activate basic uid translation. This option is useful when the server and +# client are using different user and group ids. All requests from the client +# will be served from the user id that started unfsd, no user id switching will +# take place (even if unfsd was started by root). Ownership is reported as +# follows: files belonging to the user id running unfsd will look as if they +# are owned by the client's user. Other files will look as if they are owned by +# root. The same principle applies to group ownership. +#SINGLE_USER="-s" + +# Brute force file searching +# Normally, when you rename a file across several directories on an NFS volume, +# the filehandle for that file becomes stale. When this option is enabled, unfsd +# will attempt a recursive search on the relevant server filesystem to find the +# file referenced by the filehandle. This can have a huge performance impact as +# this will also happen for files that were really deleted (by another NFS +# client) instead of moved, and cannot be found. +#BRUTE_FORCE="-b" + +# Bind to interface with specified address +# The default is to bind to all local interfaces. +#INTERFACE="-l 127.0.0.1" + +# Debug mode +# When this option is present, unfsd will not fork into the background at +# startup, and all messages that would normally go to the system log go to +# stdout instead. +#DEBUG="-d" + +# Additional options that are passed to the Daemon. +DAEMON_OPTS="$PORT_UNPRIVILEGED -n $PORT_NFS -m $PORT_MOUNT $TCP_ONLY $NO_PORTMAPPER $NO_WRITE_CACHE $CLUSTER_EXTENSION $CLUSTER_PATH $SINGLE_USER $BRUTE_FORCE $INTERFACE $DEBUG" diff --git a/unfs3/debian/unfs3.docs b/unfs3/debian/unfs3.docs new file mode 100644 index 0000000..b577397 --- /dev/null +++ b/unfs3/debian/unfs3.docs @@ -0,0 +1,4 @@ +CREDITS +NEWS +README +README.nfsroot diff --git a/unfs3/debian/unfs3.init b/unfs3/debian/unfs3.init new file mode 100644 index 0000000..6dc1952 --- /dev/null +++ b/unfs3/debian/unfs3.init @@ -0,0 +1,62 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: unfs3 +# Required-Start: $network +# Required-Stop: $network +# Should-Start: +# Should-Stop: +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: starts user-space NFSv3 server +# Description: UNFS3 is a user-space implementation of the NFSv3 server +# specification. +### END INIT INFO + +PATH=/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/unfsd +NAME=unfs3 +DESC=unfs3 + +test -x $DAEMON -a -f /etc/exports || exit 0 + +# Include #PACKAGE# defaults if available +if [ -f /etc/default/unfs3 ] +then + . /etc/default/unfs3 +fi + +set -e + +case "$1" in + start) + echo -n "Starting $DESC: " + /etc/init.d/portmap start + start-stop-daemon --start --quiet --oknodo --exec $DAEMON \ + -- $DAEMON_OPTS + echo "$NAME." + ;; + + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --stop --oknodo --quiet --exec $DAEMON + echo "$NAME." + ;; + + restart|force-reload) + echo -n "Restarting $DESC: " + start-stop-daemon --stop --oknodo --quiet --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --oknodo --exec $DAEMON \ + -- $DAEMON_OPTS + echo "$NAME." + ;; + + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 diff --git a/unfs3/debian/unfs3.postinst b/unfs3/debian/unfs3.postinst new file mode 100644 index 0000000..868d0ea --- /dev/null +++ b/unfs3/debian/unfs3.postinst @@ -0,0 +1,30 @@ +#!/bin/sh + +set -e + +case "${1}" in + configure) + if [ ! -f /etc/exports ] + then + +cat > /etc/exports << EOF +# /etc/exports: the access control list for filesystems which may be exported +# to NFS clients. See unfsd(8). +EOF + + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + + ;; + + *) + echo "postinst called with unknown argument \`${1}'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/unfs3/debian/unfs3.postrm b/unfs3/debian/unfs3.postrm new file mode 100644 index 0000000..8a1bac4 --- /dev/null +++ b/unfs3/debian/unfs3.postrm @@ -0,0 +1,25 @@ +#!/bin/sh + +set -e + +case "${1}" in + purge) + if [ -e /etc/exports ] + then + rm -f /etc/exports + fi + ;; + + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + + ;; + + *) + echo "postrm called with unknown argument \`${1}'" >&2 + exit 1 + ;; +esac + +#DEBHELPER# + +exit 0 diff --git a/unfs3/doc/README.win b/unfs3/doc/README.win new file mode 100644 index 0000000..55fa4d7 --- /dev/null +++ b/unfs3/doc/README.win @@ -0,0 +1,51 @@ + +Building unfs3 for Windows +========================== + +Building unfs3 using MinGW +-------------------------- +1. Build and install the oncrpc-ms library (http://oncrpc-ms.sourceforge.net/) + +2. Configure unfs3 with: + +LIBS="/myprefix/oncrpc-ms/lib/liboncrpc.a -lwsock32" CFLAGS="-I/myprefix/oncrpc-ms/include -DONCRPCDLL" ./configure --host=`gcc -dumpmachine` + + +Using unfs3 on Windows +====================== + +Limitations +----------- +* Single-user mode is required. Internally, unfs3 assumes that it is + running with uid 0. + +* Foreground mode is required. + +* Inode numbers are emulated by hashing file paths. This means that + there's a small risk that two files ends up with the same inode + number. + + +Path syntax +----------- +unfs3 implements a virtual file system. The root "/" directory +contains the drive letters of the drives present on the system. Below +each drive letter, the actual drive contents is found. unfs3 uses +forward slashes instead of backslashes. This applies both to mount +requests and the exports-file. + + +Example exports file +-------------------- +/a (ro) +/c/windows/temp (rw) + + +Example invocation +------------------ +unfsd.exe -s -d -p -n 4711 -m 4711 -e exports + + +Example mount command from a Linux host +--------------------------------------- +mount -o port=4711,mountport=4711,mountvers=3,nfsvers=3,nolock,tcp mywindowshost:/c/windows/temp /mnt diff --git a/unfs3/doc/TODO b/unfs3/doc/TODO new file mode 100644 index 0000000..291bd76 --- /dev/null +++ b/unfs3/doc/TODO @@ -0,0 +1,12 @@ + +* In some cases, unfs3 issues system calls like stat() with a path + beginning with double slashes. This happens to work on most UNIX + systems, but this is not guaranteed by POSIX. See + http://www.opengroup.org/onlinepubs/009695399/xrat/xbd_chap04.html + or section 2.2.2.102 in POSIX-1003.2-Draft-12. + +Windows platform: + +* Cluster extensions have not been tried on this platform. + +* Investigate possibilities for changing times on directory diff --git a/unfs3/doc/kirch1.txt b/unfs3/doc/kirch1.txt new file mode 100644 index 0000000..eb0ea25 --- /dev/null +++ b/unfs3/doc/kirch1.txt @@ -0,0 +1,271 @@ + + Re: A multi-threaded NFS server for Linux + + Olaf Kirch (okir@monad.swb.de) + Tue, 26 Nov 1996 23:09:08 +0100 + + * Messages sorted by: [1][ date ][2][ thread ][3][ subject ][4][ + author ] + * Next message: [5]Olaf Kirch: "Re: rpc.lockd/rpc.statd" + * Previous message: [6]Paul Christenson: "smail SPAM filter?" + * Next in thread: [7]Linus Torvalds: "Re: A multi-threaded NFS + server for Linux" + * Reply: [8]Linus Torvalds: "Re: A multi-threaded NFS server for + Linux" + _________________________________________________________________ + + Hi all, + + here are some ramblings about implementing nfsd, the differences + between kernel- and user-space, and life in general. It's become quite + long, so if you're not interested in either of these topics, + just skip it... + + On Sun, 24 Nov 1996 12:01:01 PST, "H.J. Lu" wrote: + > With the upcoming the Linux C library 6.0, it is possible to + > implement a multi-threaded NFS server in the user space using + > the kernel-based pthread and MT-safe API included in libc 6.0. + + In my opinion, servicing NFS from user space is an idea that should + die. + The current unfsd (and I'm pretty sure this will hold for any other + implementation) has a host of problems: + + 1. Speed. + + This is only partly related to nfsd being single-threaded. I have + run some benchmarks a while ago comparing my kernel-based nfsd to + the user-space nfsd. + + In the unfsd case, I was running 4 daemons in parallel (which is + possible + even now as long as you restrict yourself to read-only access), and + found the upper limit for peak throughput was around 800 KBps; the + rate + for sustained reads was even lower. In comparison, the kernel-based + nfsd achieved around than 1.1 MBps peak throughput which is almost + the theoretical cheapernet limit; its sustained rate was around 1 + MBps. + Testers of my recent knfsd implementation reported a sustained rate + of 3.8 MBps over 100 Mbps Ethernet. + + Even though some tweaking of the unfsd source (especially by getting + rid + of the Sun RPC code) may improve performance some more, I don't + believe + the user-space can be pushed much further. [Speaking of the RPC + library, + a rewrite would be required anyway to safely support NFS over TCP. You + can easily hang a vanilla RPC server by sending an incomplete request + over TCP and keeping the connection open] + + Now add to that the synchronization overhead required to keep the file + handle cache in sync between the various threads... + + This leads me straight to the next topic: + + 2. File Handle Layout + + Traditional nfsds usually stuff a file's device and inode number into + the + file handle, along with some information on the exported inode. Since + a user space program has no way of opening a file just given its inode + number, unfsd takes a different approach. It basically creates a + hashed + version of the file's path. Each path component is stat'ed, and an + 8bit + hash of the component's device and inode number is used. + + The first problem is that this kind of file handle is not invariant + against renames from one directory to another. Agreed, this doesn't + happen too often, but it does break Unix semantics. Try this on an + nfs-mounted file system (with appropriate foo and bar): + + (mv bar foo/bar; cat) < bar + + The second problem is a lot worse. When unfsd is presented with a file + handle it does not have in its cache, it must map it to a valid path + name. This is basically done in the following way: + + path = "/"; + depth = 0; + while (depth < length(fhandle)) { + deeper: + dirp = opendir(path); + while ((entry = readdir(dirp)) != NULL) { + if (hash(dev,ino) matches fhandle component) { + remember dirp + append entry to path + depth++; + goto deeper; + } + } + closedir(dirp); + backtrack; + } + + Needless to say, this is not very fast. The file handle cache helps + a lot here, but this kind of mapping operation occurs far more often + than one might expect (consider a development tree where files get + created and deleted continuously). In addition, the current + implementation + discards conflicting handles when there's a hash collision. + + This file handle layout also leaves little room for any additional + baggage. Unfsd currently uses 4 bytes for an inode hash of the file + itself and 28 bytes for the hashed path, but as soon as you add other + information like the inode generation number, you will sooner or + later run out of room. + + Last not least, the file handle cache must be strictly synchronized + between different nfsd processes/threads. Suppose you rename foo to + bar, which is performed by thread1, then try to read the file, which + is + performed by thread2. If the latter doesn't know the cached path is + stale, + it will fail. You could of course retry every operation that fails + with + ENOENT, but this will add even more clutter and overhead to the code. + + 3. Adherence to the NFSv2 specification + + The Linux nfsd currently does not fulfill the NFSv2 spec in its + entirety. + Especially when it comes to safe writes, it is really a fake. It + neither + makes an attempt to sync file data before replying to the client + (which + could be implemented, along with the `async' export option for turning + off this kind of behavior), nor does it sync meta-data after inode + operations (which is impossible from user space). To most people this + is no big loss, but this behavior is definitely not acceptable if you + want industry-strengh NFS. + + But even if you did implement at least synchronous file writes in + unfsd, + be it as an option or as the default, there seems to be no way to + implement some of the more advanced techniques like gathered writes. + When implementing gathered writes, the server tries to detect whether + other nfsd threads are writing to the file at the same time (which + frequently happens when the client's biods flush out the data on file + close), and if they do, it delays syncing file data for a few + milliseconds + so the others can finish first, and then flushes all data in one go. + You + can do this in kernel-land by watching inode->i_writecount, but you're + totally at a loss in user-space. + + 4. Supporting NFSv3 + + A user-space NFS server is not particularly well suited for + implementing + NFSv3. For instance, NFSv3 tries to help cache consistency on the + client + by providing pre-operation attributes for some operations, for + instance + the WRITE call. When a client finds that the pre-operation attributes + returned by the server agree with those it has cached, it can safely + assume that any data it has cached was still valid when the server + replied to its call, so there's no need to discard the cached file + data + and meta-data. + + However, pre-op attributes can only be provided safely when the server + retains exclusive access to the inode throughout the operation. This + is + impossible from user space. + + A similar example is the exclusive create operation where a verifier + is stored in the inode's atime/mtime fields by the server to guarantee + exactly-once behavior even in the face of request retransmissions. + These + values cannot be checked atomically by a user-space server. + + What this boils down to is that a user-space server cannot, without + violating the protocol spec, implement many of the advanced features + of NFSv3. + + 5. File locking over NFS + + Supporting lockd in user-space is close to impossible. I've tried it, + and have run into a large number of problems. Some of the highlights: + + * lockd can provide only a limited number of locks at the same + time because it has only a limited number of file descriptors. + + * When lockd blocks a client's lock request because of a lock held + by a local process on the server, it must continuously poll + /proc/locks to see whether the request could be granted. What's + more, if there's heavy contention for the file, it may take + a long time before it succeeds because it cannot add itself + to the inode's lock wait list in the kernel. That is, unless + you want it to create a new thread just for blocking on this + lock. + + * Lockd must synchronize its file handle cache with that of + the NFS servers. Unfortunately, lockd is also needed when + running as an NFS client only, so you run into problems with + who owns the file handle cache, and how to share it between + these to services. + + 6. Conclusion + + Alright, this has become rather long. Some of the problems I've + described + above may be solvable with more or less effort, but I believe that, + taken + as a whole, they make a pretty strong argument against sticking with + a user-space nfsd. + + In kernel-space, most of these issues are addressed most easily, and + more + efficiently. My current kernel nfsd is fairly small. Together with the + RPC core, which is used by both client and server, it takes up + something + like 20 pages--don't quote me on the exact number. As mentioned above, + it is also pretty fast, and I hope I'll be able to also provide fully + functional file locking soon. + + If you want to take a look at the current snapshot, it's available at + ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/linux-nfs-X.Y.ta + r.gz. + This version still has a bug in the nfsd readdir implementation, but + I'll release an updated (and fixed) version as soon as I have the + necessary + lockd rewrite sorted out. + + I would particularly welcome comments from Keepers of the Source + whether + my NFS rewrite has any chance of being incorporated into the kernel at + some time... that would definitely motivate me to sick more time into + it than I currently do. + + Happy hacking + Olaf +-- +Olaf Kirch | --- o --- Nous sommes du soleil we love when we play +okir@monad.swb.de | / | \ sol.dhoop.naytheet.ah kin.ir.samse.qurax + For my PGP public key, finger okir@brewhq.swb.de. + _________________________________________________________________ + + * Next message: [9]Olaf Kirch: "Re: rpc.lockd/rpc.statd" + * Previous message: [10]Paul Christenson: "smail SPAM filter?" + * Next in thread: [11]Linus Torvalds: "Re: A multi-threaded NFS + server for Linux" + * Reply: [12]Linus Torvalds: "Re: A multi-threaded NFS server for + Linux" + +Referenser + + 1. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/date.html#18 + 2. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/index.html#18 + 3. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/subject.html#18 + 4. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/author.html#18 + 5. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0019.html + 6. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0017.html + 7. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0020.html + 8. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0020.html + 9. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0019.html + 10. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0017.html + 11. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0020.html + 12. http://www.ussg.iu.edu/hypermail/linux/net/9611.3/0020.html diff --git a/unfs3/doc/passwords.txt b/unfs3/doc/passwords.txt new file mode 100644 index 0000000..f7c73d1 --- /dev/null +++ b/unfs3/doc/passwords.txt @@ -0,0 +1,46 @@ + +unfs3 mount-time password support +================================= + +Example exports file: + +/tmp (rw,password=gazonk) + +Syntax note: The password may contain any character, except +whitespace, comma and right parenthesis. + + +Mounting with clear-text passwords +---------------------------------- + +mount yourhost:@password:gazonk/tmp /mnt + +Note: When using @password, the password cannot contain slashes. + + +Mounting with one-time passwords +-------------------------------- + +1. Communicate with the mount server and issue a mount for + "@getnonce". The returned filehandle is your nonce. + +2. Concatenate the nonce with the password, and run it through + MD5. Convert the result to a hexascii representation. + +3. Example mount command: + +mount yourhost:@otp:851d689b11ed4779dd5fbb084b136c52/tmp /mnt + +Step 1 and 2 can be done by using the "nfsotpclient" found in the +contrib directory. + +Note: With otp:s, a race condition exists. Consider the following: + +1) client A requests nonce, gets NA +2) client B requests nonce, gets NB +3) client A sends otp mount using NA +4) client B sends otp mount using NB + +Step 3 will not succeed because the server only stores the last +nonce. Step 4 will succeed, though. Client A needs to fetch a new +nonce and retry the mount. diff --git a/unfs3/error.c b/unfs3/error.c new file mode 100644 index 0000000..920d974 --- /dev/null +++ b/unfs3/error.c @@ -0,0 +1,280 @@ + +/* + * UNFS3 error translation + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +/* + * translations from Unix errno to NFS error numbers + */ + +#include "config.h" + +#include +#include + +#include "nfs.h" +#include "error.h" +#include "backend.h" + +static int is_stale(void) +{ + if (errno == ENOTDIR || errno == ELOOP || errno == ENOENT || + errno == ENAMETOOLONG) + return -1; + else + return 0; +} + +nfsstat3 symlink_err(void) +{ + if (errno == EACCES || errno == EPERM) + return NFS3ERR_ACCES; + else if (is_stale()) + return NFS3ERR_STALE; + else if (errno == EROFS) + return NFS3ERR_ROFS; + else if (errno == EEXIST) + return NFS3ERR_EXIST; + else if (errno == ENOSPC) + return NFS3ERR_NOSPC; +#ifdef EDQUOT + else if (errno == EDQUOT) + return NFS3ERR_DQUOT; +#endif + else if (errno == ENOSYS) + return NFS3ERR_NOTSUPP; + else if (errno == EINVAL) + return NFS3ERR_INVAL; + else + return NFS3ERR_IO; +} + +nfsstat3 mkdir_err(void) +{ + return symlink_err(); +} + +nfsstat3 mknod_err(void) +{ + return symlink_err(); +} + +nfsstat3 link_err(void) +{ + if (errno == EXDEV) + return NFS3ERR_XDEV; + else if (errno == EMLINK) + return NFS3ERR_MLINK; +#ifdef EDQUOT + else if (errno == EDQUOT) + return NFS3ERR_DQUOT; +#endif + else + return symlink_err(); +} + +nfsstat3 lookup_err(void) +{ + if (errno == ENOENT) + return NFS3ERR_NOENT; +#ifdef ENOMEDIUM + else if (errno == ENOMEDIUM) + return NFS3ERR_NOENT; +#endif + else if (errno == EACCES) + return NFS3ERR_ACCES; + else if (errno == ENOTDIR || errno == ELOOP || errno == ENAMETOOLONG) + return NFS3ERR_STALE; + else if (errno == EINVAL) + return NFS3ERR_INVAL; + else + return NFS3ERR_IO; +} + +nfsstat3 readlink_err(void) +{ + if (errno == EINVAL) + return NFS3ERR_INVAL; + else if (errno == EACCES) + return NFS3ERR_ACCES; + else if (errno == ENOSYS) + return NFS3ERR_NOTSUPP; + else if (is_stale()) + return NFS3ERR_STALE; + else + return NFS3ERR_IO; +} + +nfsstat3 read_err(void) +{ + if (errno == EINVAL) + return NFS3ERR_INVAL; + else if (is_stale()) + return NFS3ERR_STALE; + else if (errno == EACCES) + return NFS3ERR_ACCES; + else if (errno == ENXIO || errno == ENODEV) + return NFS3ERR_NXIO; + else + return NFS3ERR_IO; +} + +nfsstat3 write_open_err(void) +{ + if (errno == EACCES) + return NFS3ERR_ACCES; + else if (is_stale()) + return NFS3ERR_STALE; + else if (errno == EINVAL) + return NFS3ERR_INVAL; + else if (errno == EROFS) + return NFS3ERR_ROFS; + else + return NFS3ERR_IO; +} + +nfsstat3 write_write_err(void) +{ + if (errno == EINVAL) + return NFS3ERR_INVAL; + else if (errno == EFBIG) + return NFS3ERR_FBIG; + else if (errno == ENOSPC) + return NFS3ERR_NOSPC; +#ifdef EDQUOT + else if (errno == EDQUOT) + return NFS3ERR_DQUOT; +#endif + else + return NFS3ERR_IO; +} + +nfsstat3 create_err(void) +{ + if (errno == EACCES) + return NFS3ERR_ACCES; + else if (is_stale()) + return NFS3ERR_STALE; + else if (errno == EROFS) + return NFS3ERR_ROFS; + else if (errno == ENOSPC) + return NFS3ERR_NOSPC; + else if (errno == EEXIST) + return NFS3ERR_EXIST; +#ifdef EDQUOT + else if (errno == EDQUOT) + return NFS3ERR_DQUOT; +#endif + else + return NFS3ERR_IO; +} + +nfsstat3 rename_err(void) +{ + if (errno == EISDIR) + return NFS3ERR_ISDIR; + else if (errno == EXDEV) + return NFS3ERR_XDEV; + else if (errno == EEXIST) + return NFS3ERR_EXIST; + else if (errno == ENOTEMPTY) + return NFS3ERR_NOTEMPTY; + else if (errno == EINVAL) + return NFS3ERR_INVAL; + else if (errno == ENOTDIR) + return NFS3ERR_NOTDIR; + else if (errno == EACCES || errno == EPERM) + return NFS3ERR_ACCES; + else if (errno == ENOENT) + return NFS3ERR_NOENT; + else if (errno == ELOOP || errno == ENAMETOOLONG) + return NFS3ERR_STALE; + else if (errno == EROFS) + return NFS3ERR_ROFS; + else if (errno == ENOSPC) + return NFS3ERR_NOSPC; +#ifdef EDQUOT + else if (errno == EDQUOT) + return NFS3ERR_DQUOT; +#endif + else + return NFS3ERR_IO; +} + +nfsstat3 remove_err(void) +{ + if (errno == EACCES || errno == EPERM) + return NFS3ERR_ACCES; + else if (errno == ENOENT) + return ENOENT; + else if (errno == ENOTDIR || errno == ELOOP || errno == ENAMETOOLONG) + return NFS3ERR_STALE; + else if (errno == EINVAL) + return NFS3ERR_INVAL; + else if (errno == EROFS) + return NFS3ERR_ROFS; + else + return NFS3ERR_IO; +} + +nfsstat3 rmdir_err(void) +{ + if (errno == ENOTEMPTY) + return NFS3ERR_NOTEMPTY; + else + return remove_err(); +} + +nfsstat3 setattr_err(void) +{ + if (errno == EPERM) + return NFS3ERR_PERM; + else if (errno == EROFS) + return NFS3ERR_ROFS; + else if (is_stale()) + return NFS3ERR_STALE; + else if (errno == EACCES) + return NFS3ERR_ACCES; +#ifdef EDQUOT + else if (errno == EDQUOT) + return NFS3ERR_DQUOT; +#endif + else if (errno == EINVAL) + return NFS3ERR_INVAL; + else + return NFS3ERR_IO; +} + +nfsstat3 readdir_err(void) +{ + if (errno == EPERM) + return NFS3ERR_PERM; + else if (errno == EACCES) + return NFS3ERR_ACCES; + else if (errno == ENOTDIR) + return NFS3ERR_NOTDIR; + else if (is_stale()) + return NFS3ERR_STALE; + else if (errno == EINVAL) + return NFS3ERR_INVAL; + else + return NFS3ERR_IO; +} + +/* + * combine two error values + */ +nfsstat3 join(nfsstat3 x, nfsstat3 y) +{ + return (x != NFS3_OK) ? x : y; +} + +/* + * combine three error values + */ +nfsstat3 join3(nfsstat3 x, nfsstat3 y, nfsstat3 z) +{ + return (x != NFS3_OK) ? x : join(y, z); +} diff --git a/unfs3/error.h b/unfs3/error.h new file mode 100644 index 0000000..1787a09 --- /dev/null +++ b/unfs3/error.h @@ -0,0 +1,29 @@ +/* + * UNFS3 error translation + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_ERROR_H +#define UNFS3_ERROR_H + +nfsstat3 symlink_err(void); +nfsstat3 remove_err(void); +nfsstat3 rmdir_err(void); +nfsstat3 setattr_err(void); +nfsstat3 readdir_err(void); +nfsstat3 mkdir_err(void); +nfsstat3 mknod_err(void); +nfsstat3 link_err(void); +nfsstat3 lookup_err(void); +nfsstat3 readlink_err(void); +nfsstat3 read_err(void); +nfsstat3 write_open_err(void); +nfsstat3 write_write_err(void); +nfsstat3 create_err(void); +nfsstat3 rename_err(void); + +nfsstat3 join(nfsstat3, nfsstat3); +nfsstat3 join3(nfsstat3, nfsstat3, nfsstat3); + +#endif diff --git a/unfs3/fd_cache.c b/unfs3/fd_cache.c new file mode 100644 index 0000000..e22b636 --- /dev/null +++ b/unfs3/fd_cache.c @@ -0,0 +1,398 @@ + +/* + * UNFS3 file descriptor cache + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#endif /* WIN32 */ + +#include "nfs.h" +#include "mount.h" +#include "fh.h" +#include "daemon.h" +#include "Config/exports.h" +#include "fd_cache.h" +#include "backend.h" + +/* + * intention of the file descriptor cache + * + * for READ operations, the intent is to open() the file on the first + * access and to close() it when we hit EOF or after two seconds of + * inactivity. + * + * for WRITE operations, the intent is to open() the file on the first + * UNSTABLE access and to close() it when COMMIT is called or after + * two seconds of inactivity. + * + * There are three states of an entry: + * 1) Unused. use == 0. + * 2) Open fd. use != 0, fd != -1. + * 3) Pending fsync/close error, to be reported in next COMMIT or WRITE. use != 0, fd == -1. + * + * Handling fsync/close errors 100% correctly is very difficult for a + * user space server. Although rare, fsync/close might fail, for + * example when out of quota or closing a file on a NFS file + * system. The most correct way of handling these errors would be to + * keep track of "dirty" and failed ranges. However, this would + * require runtime memory allocation, with no known upper bound, which + * in turn can lead to DOS attacks etc. Our solution returns a + * fsync/close error in the first WRITE or COMMIT + * response. Additionally, the write verifier is changed. Subsequent + * COMMITs may succeed even though data has been lost, but since the + * verifier is changed, clients will notice this and re-send their + * data. Eventually, with some luck, all clients will get an IO error. + */ + +/* number of entries in fd cache */ +#define FD_ENTRIES 256 + +/* The number of seconds to wait before closing inactive fd */ +#define INACTIVE_TIMEOUT 2 + +/* The number of seconds to keep pending errors */ +#define PENDING_ERROR_TIMEOUT 7200 /* 2 hours */ + +typedef struct { + int fd; /* open file descriptor */ + int kind; /* read or write */ + time_t use; /* last use */ + uint32 dev; /* device */ + uint64 ino; /* inode */ + uint32 gen; /* inode generation */ +} fd_cache_t; + +static fd_cache_t fd_cache[FD_ENTRIES]; + +/* statistics */ +int fd_cache_readers = 0; +int fd_cache_writers = 0; + +/* + * initialize the fd cache + */ +void fd_cache_init(void) +{ + int i; + + for (i = 0; i < FD_ENTRIES; i++) { + fd_cache[i].fd = -1; + fd_cache[i].kind = UNFS3_FD_READ; + fd_cache[i].use = 0; + fd_cache[i].dev = 0; + fd_cache[i].ino = 0; + fd_cache[i].gen = 0; + } +} + +/* + * find cache index to use for new entry + * returns an empty slot if found, else return error + */ +static int fd_cache_unused(void) +{ + int i; + static time_t last_warning = 0; + + for (i = 0; i < FD_ENTRIES; i++) { + if (fd_cache[i].use == 0) + return i; + } + + /* Do not print warning more than once per 10 second */ + if (time(NULL) > last_warning + 10) { + last_warning = time(NULL); + logmsg(LOG_INFO, + "fd cache full due to more than %d active files or pending IO errors", + FD_ENTRIES); + } + + return -1; +} + +/* + + * remove an entry from the cache. The keep_on_error variable + * indicates if the entry should be kept in the cache upon + * fsync/close failures. It should be set to TRUE when fd_cache_del is + * called from a code path which cannot report an IO error back to the + * client through WRITE or COMMIT. + */ +static int fd_cache_del(int idx, int keep_on_error) +{ + int res1, res2; + + res1 = -1; + + if (fd_cache[idx].fd != -1) { + if (fd_cache[idx].kind == UNFS3_FD_WRITE) { + /* sync file data if writing descriptor */ + fd_cache_writers--; + res1 = backend_fsync(fd_cache[idx].fd); + } else { + fd_cache_readers--; + res1 = 0; + } + res2 = backend_close(fd_cache[idx].fd); + fd_cache[idx].fd = -1; + + /* return -1 if something went wrong during sync or close */ + if (res1 == -1 || res2 == -1) { + res1 = -1; + } + } else + /* pending error */ + errno = EIO; + + if (res1 == -1 && !keep_on_error) { + /* The verifier should not be changed until we actually report & + remove the error */ + regenerate_write_verifier(); + } + + if (res1 != -1 || !keep_on_error) { + fd_cache[idx].fd = -1; + fd_cache[idx].use = 0; + fd_cache[idx].dev = 0; + fd_cache[idx].ino = 0; + fd_cache[idx].gen = 0; + } + + return res1; +} + +/* + * add an entry to the cache + */ +static void fd_cache_add(int fd, unfs3_fh_t * ufh, int kind) +{ + int idx; + + idx = fd_cache_unused(); + if (idx != -1) { + /* update statistics */ + if (kind == UNFS3_FD_READ) + fd_cache_readers++; + else + fd_cache_writers++; + + fd_cache[idx].fd = fd; + fd_cache[idx].kind = kind; + fd_cache[idx].use = time(NULL); + fd_cache[idx].dev = ufh->dev; + fd_cache[idx].ino = ufh->ino; + fd_cache[idx].gen = ufh->gen; + } +} + +/* + * find entry by operating system fd number + */ +static int idx_by_fd(int fd, int kind) +{ + int i; + int idx = -1; + + for (i = 0; i < FD_ENTRIES; i++) + if (fd_cache[i].fd == fd && fd_cache[i].kind == kind) { + idx = i; + break; + } + return idx; +} + +/* + * find entry by fh (device, inode, and generation number) + */ +static int idx_by_fh(unfs3_fh_t * ufh, int kind) +{ + int i; + int idx = -1; + + for (i = 0; i < FD_ENTRIES; i++) + if (fd_cache[i].kind == kind) { + if (fd_cache[i].dev == ufh->dev && fd_cache[i].ino == ufh->ino && + fd_cache[i].gen == ufh->gen) { + idx = i; + break; + } + } + return idx; +} + +/* + * open a file descriptor + * uses fd from cache if possible + */ +int fd_open(const char *path, nfs_fh3 nfh, int kind, int allow_caching) +{ + int idx, res, fd; + backend_statstruct buf; + unfs3_fh_t *fh = (void *) nfh.data.data_val; + + idx = idx_by_fh(fh, kind); + + if (idx != -1) { + if (fd_cache[idx].fd == -1) { + /* pending error, report to client and remove from cache */ + fd_cache_del(idx, FALSE); + return -1; + } + return fd_cache[idx].fd; + } else { + /* call open to obtain new fd */ + if (kind == UNFS3_FD_READ) + fd = backend_open(path, O_RDONLY); + else + fd = backend_open(path, O_WRONLY); + if (fd == -1) + return -1; + + /* check for local fs race */ + res = backend_fstat(fd, &buf); + if ((res == -1) || + (fh->dev != buf.st_dev || fh->ino != buf.st_ino || + fh->gen != backend_get_gen(buf, fd, path))) { + /* + * local fs changed meaning of path between + * calling NFS operation doing fh_decomp and + * arriving here + * + * set errno to ELOOP to make calling NFS + * operation return NFS3ERR_STALE + */ + backend_close(fd); + errno = ELOOP; + return -1; + } + + /* + * success, add to cache for later use + */ + if (allow_caching) + fd_cache_add(fd, fh, kind); + return fd; + } +} + +/* + * close a file descriptor + * returns error number from real close() if applicable + */ +int fd_close(int fd, int kind, int really_close) +{ + int idx, res1 = 0, res2 = 0; + + idx = idx_by_fd(fd, kind); + if (idx != -1) { + /* update usage time of cache entry */ + fd_cache[idx].use = time(NULL); + + if (really_close == FD_CLOSE_REAL) + /* delete entry on real close, will close() fd */ + return fd_cache_del(idx, FALSE); + else + return 0; + } else { + /* not in cache, sync and close directly */ + if (kind == UNFS3_FD_WRITE) + res1 = backend_fsync(fd); + + res2 = backend_close(fd); + + if (res1 != 0) + return res1; + else + return res2; + } +} + +/* + * sync file descriptor data to disk + */ +int fd_sync(nfs_fh3 nfh) +{ + int idx; + unfs3_fh_t *fh = (void *) nfh.data.data_val; + + idx = idx_by_fh(fh, UNFS3_FD_WRITE); + if (idx != -1) + /* delete entry, will fsync() and close() the fd */ + return fd_cache_del(idx, FALSE); + else + return 0; +} + +/* + * purge/shutdown the cache + */ +void fd_cache_purge(void) +{ + int i; + + /* close any open file descriptors we still have */ + for (i = 0; i < FD_ENTRIES; i++) { + if (fd_cache[i].use != 0) { + if (fd_cache_del(i, TRUE) == -1) + logmsg(LOG_CRIT, + "Error during shutdown fsync/close for dev %lu, inode %lu", + fd_cache[i].dev, fd_cache[i].ino); + + } + } +} + +/* + * close inactive fds + */ +void fd_cache_close_inactive(void) +{ + time_t now; + int i; + int found_error = 0; + int active_error = 0; + + now = time(NULL); + for (i = 0; i < FD_ENTRIES; i++) { + /* Check for inactive open fds */ + if (fd_cache[i].use && fd_cache[i].fd != -1 && + fd_cache[i].use + INACTIVE_TIMEOUT < now) { + fd_cache_del(i, TRUE); + } + + /* Check for inactive pending errors */ + if (fd_cache[i].use && fd_cache[i].fd == -1) { + found_error = 1; + if (fd_cache[i].use + PENDING_ERROR_TIMEOUT > now) + active_error = 1; + } + } + + if (found_error && !active_error) { + /* All pending errors are old. Delete them all from the table and + generate new verifier. This is done to prevent the table from + filling up with old pending errors, perhaps for files that never + will be written again. In this case, we throw away the errors, and + change the server verifier. If clients has pending COMMITs, they + will notify the changed verifier and re-send. */ + for (i = 0; i < FD_ENTRIES; i++) { + if (fd_cache[i].use && fd_cache[i].fd == -1) { + fd_cache_del(i, FALSE); + } + } + regenerate_write_verifier(); + } +} diff --git a/unfs3/fd_cache.h b/unfs3/fd_cache.h new file mode 100644 index 0000000..3812c5d --- /dev/null +++ b/unfs3/fd_cache.h @@ -0,0 +1,29 @@ +/* + * UNFS3 file descriptor cache + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_FD_CACHE_H +#define UNFS3_FD_CACHE_H + +/* FD_READ and FD_WRITE are already defined on Win32 */ +#define UNFS3_FD_READ 0 /* fd for READ */ +#define UNFS3_FD_WRITE 1 /* fd for WRITE */ + +#define FD_CLOSE_VIRT 0 /* virtually close the fd */ +#define FD_CLOSE_REAL 1 /* really close the fd */ + +/* statistics */ +extern int fd_cache_readers; +extern int fd_cache_writers; + +void fd_cache_init(void); + +int fd_open(const char *path, nfs_fh3 fh, int kind, int allow_caching); +int fd_close(int fd, int kind, int really_close); +int fd_sync(nfs_fh3 nfh); +void fd_cache_purge(void); +void fd_cache_close_inactive(void); + +#endif diff --git a/unfs3/fh.c b/unfs3/fh.c new file mode 100644 index 0000000..46c66cd --- /dev/null +++ b/unfs3/fh.c @@ -0,0 +1,473 @@ + +/* + * UNFS3 low-level filehandle routines + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#ifndef WIN32 +#include +#include +#endif /* WIN32 */ +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_LINUX_EXT2_FS_H == 1 + +/* + * presence of linux/ext2_fs.h is a hint that we are on Linux, really + * including that file doesn't work on Debian, so define the ioctl + * number here + */ +#define EXT2_IOC_GETVERSION 0x80047601 +#endif + +#include "nfs.h" +#include "mount.h" +#include "daemon.h" +#include "fh.h" +#include "backend.h" +#include "Config/exports.h" + +/* + * hash function for inode numbers + */ +#define FH_HASH(n) ((n ^ (n >> 8) ^ (n >> 16) ^ (n >> 24) ^ (n >> 32) ^ (n >> 40) ^ (n >> 48) ^ (n >> 56)) & 0xFF) + +/* + * stat cache + */ +int st_cache_valid = FALSE; +backend_statstruct st_cache; + +/* + * -------------------------------- + * INODE GENERATION NUMBER HANDLING + * -------------------------------- + */ + +/* + * obtain inode generation number if possible + * + * obuf: filled out stat buffer (must be given!) + * fd: open fd to file or FD_NONE (-1) if no fd open + * path: path to object in case we need to open it here + * + * returns 0 on failure + */ +uint32 get_gen(backend_statstruct obuf, U(int fd), U(const char *path)) +{ +#if HAVE_STRUCT_STAT_ST_GEN == 1 + return obuf.st_gen; +#endif + +#if HAVE_STRUCT_STAT_ST_GEN == 0 && HAVE_LINUX_EXT2_FS_H == 1 + int newfd, res; + uint32 gen; + uid_t euid; + gid_t egid; + + if (!S_ISREG(obuf.st_mode) && !S_ISDIR(obuf.st_mode)) + return 0; + + euid = backend_geteuid(); + egid = backend_getegid(); + backend_setegid(0); + backend_seteuid(0); + + if (fd != FD_NONE) { + res = ioctl(fd, EXT2_IOC_GETVERSION, &gen); + if (res == -1) + gen = 0; + } else { + newfd = backend_open(path, O_RDONLY); + if (newfd == -1) + gen = 0; + else { + res = ioctl(newfd, EXT2_IOC_GETVERSION, &gen); + close(newfd); + + if (res == -1) + gen = 0; + } + } + + backend_setegid(egid); + backend_seteuid(euid); + + if (backend_geteuid() != euid || backend_getegid() != egid) { + logmsg(LOG_EMERG, "euid/egid switching failed, aborting"); + daemon_exit(CRISIS); + } + + return gen; +#endif + +#if HAVE_STRUCT_STAT_ST_GEN == 0 && HAVE_LINUX_EXT2_FS_H == 0 + return obuf.st_ino; +#endif +} + +/* + * -------------------------------- + * FILEHANDLE COMPOSITION FUNCTIONS + * -------------------------------- + */ + +/* + * check whether an NFS filehandle is valid + */ +int nfh_valid(nfs_fh3 fh) +{ + unfs3_fh_t *obj = (void *) fh.data.data_val; + + /* too small? */ + if (fh.data.data_len < FH_MINLEN) + return FALSE; + + /* encoded length different from real length? */ + if (fh.data.data_len != fh_length(obj)) + return FALSE; + + return TRUE; +} + +/* + * check whether a filehandle is valid + */ +int fh_valid(unfs3_fh_t fh) +{ + /* invalid filehandles have zero device and inode */ + return (int) (fh.dev != 0 || fh.ino != 0); +} + +/* + * invalid fh for error returns + */ +#ifdef __GNUC__ +static const unfs3_fh_t invalid_fh = {.dev = 0,.ino = 0,.gen = 0,.len = + 0,.inos = {0} +}; +#else +static const unfs3_fh_t invalid_fh = { 0, 0, 0, 0, {0} }; +#endif + +/* + * compose a filehandle for a given path + * path: path to compose fh for + * rqstp: If not NULL, generate special FHs for removables + * need_dir: if not 0, path must point to a directory + */ +unfs3_fh_t fh_comp_raw(const char *path, struct svc_req *rqstp, int need_dir) +{ + char work[NFS_MAXPATHLEN]; + unfs3_fh_t fh; + backend_statstruct buf; + int res; + char *last; + int pos = 0; + + fh.len = 0; + + /* special case for removable device export point: return preset fsid and + inod 1. */ + if (rqstp && export_point(path)) { + uint32 fsid; + + if (exports_options(path, rqstp, NULL, &fsid) == -1) { + /* Shouldn't happen, unless the exports file changed after the + call to export_point() */ + return invalid_fh; + } + if (exports_opts & OPT_REMOVABLE) { + fh.dev = fsid; + /* There's a small risk that the file system contains other file + objects with st_ino = 1. This should be fairly uncommon, + though. The FreeBSD fs(5) man page says: + + "The root inode is the root of the file system. Inode 0 + cannot be used for normal purposes and historically bad blocks + were linked to inode 1, thus the root inode is 2 (inode 1 is + no longer used for this purpose, however numerous dump tapes + make this assumption, so we are stuck with it)." + + In Windows, there's also a small risk that the hash ends up + being exactly 1. */ + fh.ino = 0x1; + fh.gen = 0; + return fh; + } + } + + res = backend_lstat(path, &buf); + if (res == -1) + return invalid_fh; + + /* check for dir if need_dir is set */ + if (need_dir != 0 && !S_ISDIR(buf.st_mode)) + return invalid_fh; + + fh.dev = buf.st_dev; + fh.ino = buf.st_ino; + fh.gen = backend_get_gen(buf, FD_NONE, path); + + /* special case for root directory */ + if (strcmp(path, "/") == 0) + return fh; + + strcpy(work, path); + last = work; + + do { + *last = '/'; + last = strchr(last + 1, '/'); + if (last != NULL) + *last = 0; + + res = backend_lstat(work, &buf); + if (res == -1) { + return invalid_fh; + } + + /* store 8 bit hash of the component's inode */ + fh.inos[pos] = FH_HASH(buf.st_ino); + pos++; + + } while (last && pos < FH_MAXLEN); + + if (last) /* path too deep for filehandle */ + return invalid_fh; + + fh.len = pos; + + return fh; +} + +/* + * get real length of a filehandle + */ +u_int fh_length(const unfs3_fh_t * fh) +{ + return fh->len + sizeof(fh->len) + sizeof(fh->dev) + sizeof(fh->ino) + + sizeof(fh->gen) + sizeof(fh->pwhash); +} + +/* + * extend a filehandle with a given device, inode, and generation number + */ +unfs3_fh_t *fh_extend(nfs_fh3 nfh, uint32 dev, uint64 ino, uint32 gen) +{ + static unfs3_fh_t new; + unfs3_fh_t *fh = (void *) nfh.data.data_val; + + memcpy(&new, fh, fh_length(fh)); + + if (new.len == 0) { + char *path; + + path = export_point_from_fsid(new.dev, NULL, NULL); + if (path != NULL) { + /* Our FH to extend refers to a removable device export point, + which lacks .inos. We need to construct a real FH to extend, + which can be done by passing rqstp=NULL to fh_comp_raw. */ + new = fh_comp_raw(path, NULL, FH_ANY); + if (!fh_valid(new)) + return NULL; + } + } + + if (new.len == FH_MAXLEN) + return NULL; + + new.dev = dev; + new.ino = ino; + new.gen = gen; + new.pwhash = export_password_hash; + new.inos[new.len] = FH_HASH(ino); + new.len++; + + return &new; +} + +/* + * get post_op_fh3 extended by device, inode, and generation number + */ +post_op_fh3 fh_extend_post(nfs_fh3 fh, uint32 dev, uint64 ino, uint32 gen) +{ + post_op_fh3 post; + unfs3_fh_t *new; + + new = fh_extend(fh, dev, ino, gen); + + if (new) { + post.handle_follows = TRUE; + post.post_op_fh3_u.handle.data.data_len = fh_length(new); + post.post_op_fh3_u.handle.data.data_val = (char *) new; + } else + post.handle_follows = FALSE; + + return post; +} + +/* + * extend a filehandle given a path and needed type + */ +post_op_fh3 fh_extend_type(nfs_fh3 fh, const char *path, unsigned int type) +{ + post_op_fh3 result; + backend_statstruct buf; + int res; + + res = backend_lstat(path, &buf); + if (res == -1 || (buf.st_mode & type) != type) { + st_cache_valid = FALSE; + result.handle_follows = FALSE; + return result; + } + + st_cache_valid = TRUE; + st_cache = buf; + + return fh_extend_post(fh, buf.st_dev, buf.st_ino, + backend_get_gen(buf, FD_NONE, path)); +} + +/* + * ------------------------------- + * FILEHANDLE RESOLUTION FUNCTIONS + * ------------------------------- + */ + +/* + * filehandles have the following fields: + * dev: device of the file system object fh points to + * ino: inode of the file system object fh points to + * gen: inode generation number, if available + * len: number of entries in following inos array + * inos: array of max FH_MAXLEN directories needed to traverse to reach + * object, for each name, an 8 bit hash of the inode number is stored + * + * - search functions traverse directory structure from the root looking + * for directories matching the inode information stored + * - if such a directory is found, we descend into it trying to locate the + * object + */ + +/* + * recursive directory search + * fh: filehandle being resolved + * pos: position in filehandles path inode array + * lead: current directory for search + * result: where to store path if seach is complete + */ +static int fh_rec(const unfs3_fh_t * fh, int pos, const char *lead, + char *result) +{ + backend_dirstream *search; + struct dirent *entry; + backend_statstruct buf; + int res, rec; + char obj[NFS_MAXPATHLEN]; + + /* There's a slight risk of multiple files with the same st_ino on + Windows. Take extra care and make sure that there are no collisions */ + unsigned short matches = 0; + + /* went in too deep? */ + if (pos == fh->len) + return FALSE; + + search = backend_opendir(lead); + if (!search) + return FALSE; + + entry = backend_readdir(search); + + while (entry) { + if (strlen(lead) + strlen(entry->d_name) + 1 < NFS_MAXPATHLEN) { + + sprintf(obj, "%s/%s", lead, entry->d_name); + + res = backend_lstat(obj, &buf); + if (res == -1) { + buf.st_dev = 0; + buf.st_ino = 0; + } + + if (buf.st_dev == fh->dev && buf.st_ino == fh->ino) { + /* found the object */ + sprintf(result, "%s/%s", lead + 1, entry->d_name); + /* update stat cache */ + st_cache_valid = TRUE; + st_cache = buf; + matches++; +#ifndef WIN32 + break; +#endif + } + + if (strcmp(entry->d_name, "..") != 0 && + strcmp(entry->d_name, ".") != 0 && + FH_HASH(buf.st_ino) == fh->inos[pos]) { + /* + * might be directory we're looking for, + * try descending into it + */ + rec = fh_rec(fh, pos + 1, obj, result); + if (rec) { + /* object was found in dir */ + backend_closedir(search); + return TRUE; + } + } + } + entry = backend_readdir(search); + } + + backend_closedir(search); + switch (matches) { + case 0: + return FALSE; + case 1: + return TRUE; + default: +#ifdef WIN32 + logmsg(LOG_CRIT, "Hash collision detected for file %s!", result); +#endif + return FALSE; + } +} + +/* + * resolve a filehandle into a path + */ +char *fh_decomp_raw(const unfs3_fh_t * fh) +{ + int rec = 0; + static char result[NFS_MAXPATHLEN]; + + /* valid fh? */ + if (!fh) + return NULL; + + /* special case for root directory */ + if (fh->len == 0) + return "/"; + + rec = fh_rec(fh, 0, "/", result); + + if (rec) + return result; + + /* could not find object */ + return NULL; +} diff --git a/unfs3/fh.h b/unfs3/fh.h new file mode 100644 index 0000000..341982f --- /dev/null +++ b/unfs3/fh.h @@ -0,0 +1,62 @@ +/* + * UNFS3 low-level filehandle routines + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_FH_H +#define UNFS3_FH_H + +#include "backend.h" + +/* minimum length of complete filehandle */ +#define FH_MINLEN 21 + +/* maximum depth of pathname described by filehandle */ +#define FH_MAXLEN (64 - FH_MINLEN) + +#ifdef __GNUC__ +typedef struct { + uint32 dev; + uint64 ino; + uint32 gen; + uint32 pwhash; + unsigned char len; + unsigned char inos[FH_MAXLEN]; +} __attribute__((packed)) unfs3_fh_t; +#else +#pragma pack(1) +typedef struct { + uint32 dev; + uint64 ino; + uint32 gen; + uint32 pwhash; + unsigned char len; + unsigned char inos[FH_MAXLEN]; +} unfs3_fh_t; +#pragma pack(4) +#endif + +#define FH_ANY 0 +#define FH_DIR 1 + +#define FD_NONE (-1) /* used for get_gen */ + +extern int st_cache_valid; /* stat value is valid */ +extern backend_statstruct st_cache; /* cached stat value */ + +uint32 get_gen(backend_statstruct obuf, int fd, const char *path); + +int nfh_valid(nfs_fh3 fh); +int fh_valid(unfs3_fh_t fh); + +unfs3_fh_t fh_comp_raw(const char *path, struct svc_req *rqstp, int need_dir); +u_int fh_length(const unfs3_fh_t *fh); + +unfs3_fh_t *fh_extend(nfs_fh3 fh, uint32 dev, uint64 ino, uint32 gen); +post_op_fh3 fh_extend_post(nfs_fh3 fh, uint32 dev, uint64 ino, uint32 gen); +post_op_fh3 fh_extend_type(nfs_fh3 fh, const char *path, unsigned int type); + +char *fh_decomp_raw(const unfs3_fh_t *fh); + +#endif diff --git a/unfs3/fh_cache.c b/unfs3/fh_cache.c new file mode 100644 index 0000000..b411469 --- /dev/null +++ b/unfs3/fh_cache.c @@ -0,0 +1,347 @@ + +/* + * UNFS3 filehandle cache + * (C) 2004 + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfs.h" +#include "fh.h" +#include "locate.h" +#include "fh_cache.h" +#include "mount.h" +#include "daemon.h" +#include "Config/exports.h" +#include "readdir.h" +#include "backend.h" + +/* number of entries in fh cache */ +#define CACHE_ENTRIES 4096 + +typedef struct { + uint32 dev; /* device */ + uint64 ino; /* inode */ + char path[NFS_MAXPATHLEN]; /* pathname */ + unsigned int use; /* last use */ +} unfs3_cache_t; + +static unfs3_cache_t fh_cache[CACHE_ENTRIES]; + +/* statistics */ +int fh_cache_max = 0; +int fh_cache_use = 0; +int fh_cache_hit = 0; + +/* counter for LRU */ +static unsigned int fh_cache_time = 0; + +/* + * last returned entry + * + * this entry must not be overwritten before the next lookup, because + * operations such as CREATE may still be needing the path inside the + * entry for getting directory attributes + * + * this is needed since fh_cache_time can roll around to 0, thus + * making the entry evictable + */ +static int fh_last_entry = -1; + +/* + * return next pseudo-time value for LRU counter + */ +static unsigned int fh_cache_next(void) +{ + return ++fh_cache_time; +} + +/* + * initialize cache + */ +void fh_cache_init(void) +{ + memset(fh_cache, 0, sizeof(unfs3_cache_t) * CACHE_ENTRIES); +} + +/* + * find cache index to use for new entry + * returns either an empty slot or the least recently used slot if no + * empty slot is present + */ +static int fh_cache_lru(void) +{ + unsigned int best = UINT_MAX; + int best_idx = 0; + int i; + + /* if cache is not full, we simply hand out the next slot */ + if (fh_cache_max < CACHE_ENTRIES - 1) + return fh_cache_max++; + + for (i = 0; i < CACHE_ENTRIES; i++) { + if (i == fh_last_entry) + continue; + if (fh_cache[i].use == 0) + return i; + if (fh_cache[i].use < best) { + best = fh_cache[i].use; + best_idx = i; + } + } + + /* avoid stomping over last returned entry */ + if (best_idx == 0 && fh_last_entry == 0) + best_idx = 1; + + return best_idx; +} + +/* + * invalidate (clear) a cache entry + */ +static void fh_cache_inval(int idx) +{ + fh_cache[idx].dev = 0; + fh_cache[idx].ino = 0; + fh_cache[idx].use = 0; + fh_cache[idx].path[0] = 0; +} + +/* + * find index given device and inode number + */ +static int fh_cache_index(uint32 dev, uint64 ino) +{ + int i, res = -1; + + for (i = 0; i < fh_cache_max + 1; i++) + if (fh_cache[i].dev == dev && fh_cache[i].ino == ino) { + res = i; + break; + } + + return res; +} + +/* + * add an entry to the filehandle cache + */ +char *fh_cache_add(uint32 dev, uint64 ino, const char *path) +{ + int idx; + + /* if we already have a matching entry, overwrite that */ + idx = fh_cache_index(dev, ino); + + /* otherwise overwrite least recently used entry */ + if (idx == -1) + idx = fh_cache_lru(); + + fh_cache[idx].dev = dev; + fh_cache[idx].ino = ino; + fh_cache[idx].use = fh_cache_next(); + + strcpy(fh_cache[idx].path, path); + + return fh_cache[idx].path; +} + +/* + * lookup an entry in the cache given a device, inode, and generation number + */ +static char *fh_cache_lookup(uint32 dev, uint64 ino) +{ + int i, res; + backend_statstruct buf; + + i = fh_cache_index(dev, ino); + + if (i != -1) { + /* check whether path to relation still holds */ + res = backend_lstat(fh_cache[i].path, &buf); + if (res == -1) { + /* object does not exist any more */ + fh_cache_inval(i); + return NULL; + } + if (buf.st_dev == dev && buf.st_ino == ino) { + /* cache hit, update time on cache entry */ + fh_cache[i].use = fh_cache_next(); + + /* update stat cache */ + st_cache_valid = TRUE; + st_cache = buf; + + /* prevent next fh_cache_add from overwriting entry */ + fh_last_entry = i; + + return fh_cache[i].path; + } else { + /* path to relation has changed */ + fh_cache_inval(i); + return NULL; + } + } + + return NULL; +} + +/* + * resolve a filename into a path + * cache-using wrapper for fh_decomp_raw + */ +char *fh_decomp(nfs_fh3 fh) +{ + char *result; + unfs3_fh_t *obj = (void *) fh.data.data_val; + time_t *last_mtime; + uint32 *dir_hash, new_dir_hash; + + if (!nfh_valid(fh)) { + st_cache_valid = FALSE; + return NULL; + } + + /* Does the fsid match some static fsid? */ + if ((result = + export_point_from_fsid(obj->dev, &last_mtime, &dir_hash)) != NULL) { + if (obj->ino == 0x1) { + /* This FH refers to the export point itself */ + /* Need to fill stat cache */ + st_cache_valid = TRUE; + + if (backend_lstat(result, &st_cache) == -1) { + /* export point does not exist. This probably means that we + are using autofs and no media is inserted. Fill stat cache + with dummy information */ + st_cache.st_mode = S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO; + st_cache.st_nlink = 2; + st_cache.st_uid = 0; + st_cache.st_gid = 0; + st_cache.st_rdev = 0; + st_cache.st_size = 4096; + st_cache.st_blksize = 512; + st_cache.st_blocks = 8; + } else { + /* Stat was OK, but make sure the values are sane. Supermount + returns insane values when no media is inserted, for + example. */ + if (st_cache.st_nlink == 0) + st_cache.st_nlink = 1; + if (st_cache.st_size == 0) + st_cache.st_size = 4096; + if (st_cache.st_blksize == 0) + st_cache.st_blksize = 512; + if (st_cache.st_blocks == 0) + st_cache.st_blocks = 8; + } + + st_cache.st_dev = obj->dev; + st_cache.st_ino = 0x1; + + /* It's very important that we get mtime correct, since it's used + as verifier in READDIR. The generation of mtime is tricky, + because with some filesystems, such as the Linux 2.4 FAT fs, + the mtime value for the mount point is set to *zero* on each + mount. I consider this a bug, but we need to work around it + anyway. + + We store the last mtime returned. When stat returns a smaller + value than this, we double-check by doing a hash of the names + in the directory. If this hash is different from what we had + earlier, return current time. + + Note: Since dir_hash is stored in memory, we have introduced a + little statefulness here. This means that if unfsd is + restarted during two READDIR calls, NFS3ERR_BAD_COOKIE will be + returned, and the client has to retry the READDIR operation + with a zero cookie */ + + if (st_cache.st_mtime > *last_mtime) { + /* stat says our directory has changed */ + *last_mtime = st_cache.st_mtime; + } else if (*dir_hash != (new_dir_hash = directory_hash(result))) { + /* The names in the directory has changed. Return current + time. */ + st_cache.st_mtime = time(NULL); + *last_mtime = st_cache.st_mtime; + *dir_hash = new_dir_hash; + } else { + /* Hash unchanged. Returned stored mtime. */ + st_cache.st_mtime = *last_mtime; + } + + return result; + } + } + + /* try lookup in cache, increase cache usage counter */ + result = fh_cache_lookup(obj->dev, obj->ino); + fh_cache_use++; + + if (!result) { + /* not found, resolve the hard way */ + result = fh_decomp_raw(obj); + + /* if still not found, do full recursive search) */ + if (!result) + result = backend_locate_file(obj->dev, obj->ino); + + if (result) + /* add to cache for later use if resolution ok */ + result = fh_cache_add(obj->dev, obj->ino, result); + else + /* could not resolve in any way */ + st_cache_valid = FALSE; + } else + /* found, update cache hit statistic */ + fh_cache_hit++; + + return result; +} + +/* + * compose a filehandle for a path + * cache-using wrapper for fh_comp_raw + * exports_options must be called before + */ +unfs3_fh_t fh_comp(const char *path, struct svc_req * rqstp, int need_dir) +{ + unfs3_fh_t res; + + res = fh_comp_raw(path, rqstp, need_dir); + if (fh_valid(res)) + /* add to cache for later use */ + fh_cache_add(res.dev, res.ino, path); + + res.pwhash = export_password_hash; + return res; +} + +/* + * return pointer to composed filehandle + * wrapper for fh_comp + */ +unfs3_fh_t *fh_comp_ptr(const char *path, struct svc_req * rqstp, + int need_dir) +{ + static unfs3_fh_t res; + + res = fh_comp(path, rqstp, need_dir); + if (fh_valid(res)) + return &res; + else + return NULL; +} diff --git a/unfs3/fh_cache.h b/unfs3/fh_cache.h new file mode 100644 index 0000000..5801709 --- /dev/null +++ b/unfs3/fh_cache.h @@ -0,0 +1,23 @@ +/* + * UNFS3 filehandle cache + * (C) 2003, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_FH_CACHE_H +#define UNFS3_FH_CACHE_H + +/* statistics */ +extern int fh_cache_max; +extern int fh_cache_use; +extern int fh_cache_hit; + +void fh_cache_init(void); + +char *fh_decomp(nfs_fh3 fh); +unfs3_fh_t fh_comp(const char *path, struct svc_req *rqstp, int need_dir); +unfs3_fh_t *fh_comp_ptr(const char *path, struct svc_req *rqstp, int need_dir); + +char *fh_cache_add(uint32 dev, uint64 ino, const char *path); + +#endif diff --git a/unfs3/indent-all b/unfs3/indent-all new file mode 100755 index 0000000..5ba6bb7 --- /dev/null +++ b/unfs3/indent-all @@ -0,0 +1,5 @@ +#!/bin/sh +indent -bad -bap -bbb -bli4 -br -brs -c40 -cbi4 -c40 -cdw -ce -ci4 -cli4 \ + -cp40 -cs -d0 -di0 -fca -i4 -l78 -lc78 -lp -nbbo -nbc -nbfda -nhnl \ + -npcs -nprs -npsl -pi0 -saf -sai -saw -sob -ss -ts8 -ut \ + *.c Extras/*.c diff --git a/unfs3/install-sh b/unfs3/install-sh new file mode 100755 index 0000000..e9de238 --- /dev/null +++ b/unfs3/install-sh @@ -0,0 +1,251 @@ +#!/bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5 (mit/util/scripts/install.sh). +# +# Copyright 1991 by the Massachusetts Institute of Technology +# +# Permission to use, copy, modify, distribute, and sell this software and its +# documentation for any purpose is hereby granted without fee, provided that +# the above copyright notice appear in all copies and that both that +# copyright notice and this permission notice appear in supporting +# documentation, and that the name of M.I.T. not be used in advertising or +# publicity pertaining to distribution of the software without specific, +# written prior permission. M.I.T. makes no representations about the +# suitability of this software for any purpose. It is provided "as is" +# without express or implied warranty. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. It can only install one file at a time, a restriction +# shared with many OS's install programs. + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +transformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + chmodcmd="" + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/unfs3/locate.c b/unfs3/locate.c new file mode 100644 index 0000000..c5ed219 --- /dev/null +++ b/unfs3/locate.c @@ -0,0 +1,171 @@ + +/* + * UNFS3 brute force file search + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#if HAVE_MNTENT_H == 1 +#include +#endif + +#if HAVE_SYS_MNTTAB_H == 1 +#include +#endif + +#include "nfs.h" +#include "fh.h" +#include "daemon.h" + +/* + * these are the brute-force file searching routines that are used + * when both the filehandle cache and the hashed path inside the + * filehandle are unable to locate the file + * + * this can only happen if a file was rename(3)'d across directories + * + * these routines are slow, but better than returning ESTALE to + * clients + */ + +#if HAVE_MNTENT_H == 1 || HAVE_SYS_MNTTAB_H == 1 + +/* + * locate file given prefix, device, and inode number + */ +static int locate_pfx(const char *pfx, uint32 dev, uint64 ino, char *result) +{ + char path[NFS_MAXPATHLEN]; + backend_dirstream *search; + struct dirent *ent; + struct stat buf; + int res; + + search = opendir(pfx); + if (!search) + return FALSE; + + while ((ent = readdir(search))) { + if (strlen(pfx) + strlen(ent->d_name) + 2 >= NFS_MAXPATHLEN) + continue; + + sprintf(path, "%s/%s", pfx, ent->d_name); + + res = lstat(path, &buf); + if (res != 0) + continue; + + /* check for matching object */ + if (buf.st_dev == dev && buf.st_ino == ino) { + strcpy(result, path); + st_cache = buf; + st_cache_valid = TRUE; + closedir(search); + return TRUE; + } + + /* descend into directories with same dev */ + if (buf.st_dev == dev && S_ISDIR(buf.st_mode) && + strcmp(ent->d_name, ".") != 0 && strcmp(ent->d_name, "..") != 0) { + res = locate_pfx(path, dev, ino, result); + if (res == TRUE) { + closedir(search); + return TRUE; + } + } + } + + closedir(search); + return FALSE; +} +#endif + +/* + * locate file given device and inode number + * + * slow fallback in case other filehandle resolution functions fail + */ +char *locate_file(U(uint32 dev), U(uint64 ino)) +{ +#if HAVE_MNTENT_H == 1 || HAVE_SYS_MNTTAB_H == 1 + static char path[NFS_MAXPATHLEN]; + FILE *mtab; + struct stat buf; + int res; +#endif + +#if HAVE_MNTENT_H == 1 + struct mntent *ent; +#endif + +#if HAVE_SYS_MNTTAB_H == 1 + struct mnttab ent; + int found = FALSE; +#endif + + if (!opt_brute_force) + return NULL; + +#if HAVE_MNTENT_H == 1 + mtab = setmntent("/etc/mtab", "r"); + if (!mtab) + return NULL; + + /* + * look for mtab entry with matching device + */ + while ((ent = getmntent(mtab))) { + res = lstat(ent->mnt_dir, &buf); + + if (res == 0 && buf.st_dev == dev) + break; + } + endmntent(mtab); + + /* found matching entry? */ + if (ent) { + res = locate_pfx(ent->mnt_dir, dev, ino, path); + if (res == TRUE) + return path; + } +#endif + +#if HAVE_SYS_MNTTAB_H == 1 + mtab = fopen("/etc/mnttab", "r"); + if (!mtab) + return NULL; + + /* + * look for mnttab entry with matching device + */ + while (getmntent(mtab, &ent) == 0) { + res = lstat(ent.mnt_mountp, &buf); + + if (res == 0 && buf.st_dev == dev) { + found = TRUE; + break; + } + } + fclose(mtab); + + /* found matching entry? */ + if (found) { + res = locate_pfx(ent.mnt_mountp, dev, ino, path); + if (res == TRUE) + return path; + } +#endif + + return NULL; +} diff --git a/unfs3/locate.h b/unfs3/locate.h new file mode 100644 index 0000000..45ac305 --- /dev/null +++ b/unfs3/locate.h @@ -0,0 +1,13 @@ + +/* + * UNFS3 brute force file search + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_LOCATE_H +#define UNFS3_LOCATE_H + +char *locate_file(uint32 dev, uint64 ino); + +#endif diff --git a/unfs3/md5.c b/unfs3/md5.c new file mode 100644 index 0000000..7a7c7a5 --- /dev/null +++ b/unfs3/md5.c @@ -0,0 +1,379 @@ + +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ + +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5.h" +#include + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, + 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + +static void md5_process(md5_state_t * pms, const md5_byte_t * data /* [64] + */ ) +{ + md5_word_t a = pms->abcd[0], b = pms->abcd[1], c = pms->abcd[2], d = + pms->abcd[3]; + md5_word_t t; + +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *) &w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *) 0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *) data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = + xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation a = b + ((a + F(b,c,d) + X[k] + + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation a = b + ((a + G(b,c,d) + X[k] + + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation a = b + ((a + H(b,c,d) + X[k] + + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation a = b + ((a + I(b,c,d) + X[k] + + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each of the + four registers by the value it had before this block was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void md5_init(md5_state_t * pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /* 0xefcdab89 */ T_MASK ^ 0x10325476; + pms->abcd[2] = /* 0x98badcfe */ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void md5_append(md5_state_t * pms, const md5_byte_t * data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t) (nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void md5_finish(md5_state_t * pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t) (pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t) (pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/unfs3/md5.h b/unfs3/md5.h new file mode 100644 index 0000000..bc49597 --- /dev/null +++ b/unfs3/md5.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + L. Peter Deutsch + ghost@aladdin.com + + */ + +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/unfs3/mount.c b/unfs3/mount.c new file mode 100644 index 0000000..d14956e --- /dev/null +++ b/unfs3/mount.c @@ -0,0 +1,289 @@ + +/* + * UNFS3 mount protocol procedures + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#include +#include +#endif /* WIN32 */ +#include + +#include "nfs.h" +#include "mount.h" +#include "daemon.h" +#include "fh.h" +#include "fh_cache.h" +#include "fd_cache.h" +#include "Config/exports.h" +#include "password.h" +#include "backend.h" + +#ifndef PATH_MAX +# define PATH_MAX 4096 +#endif + +#define IS_SECURE(port) ((port) < 1024) + +/* + * number of active mounts + * + * only a guess since clients can crash and/or not sent UMNT calls + */ +static int mount_cnt = 0; + +/* list of currently mounted directories */ +static mountlist mount_list = NULL; + +static char nonce[32] = ""; + +/* + * add entry to mount list + */ +static void add_mount(const char *path, struct svc_req *rqstp) +{ + mountlist new; + mountlist iter; + char *host; + + new = malloc(sizeof(struct mountbody)); + if (!new) { + logmsg(LOG_CRIT, "add_mount: Unable to allocate memory"); + return; + } + + host = inet_ntoa(get_remote(rqstp)); + new->ml_hostname = malloc(strlen(host) + 1); + if (!new->ml_hostname) { + logmsg(LOG_CRIT, "add_mount: Unable to allocate memory"); + free(new); + return; + } + + new->ml_directory = malloc(strlen(path) + 1); + if (!new->ml_directory) { + logmsg(LOG_CRIT, "add_mount: Unable to allocate memory"); + free(new->ml_hostname); + free(new); + return; + } + + /* initialize the new entry */ + new->ml_next = NULL; + strcpy(new->ml_hostname, host); + strcpy(new->ml_directory, path); + + iter = mount_list; + if (iter) { + while (iter->ml_next) + iter = iter->ml_next; + iter->ml_next = new; + } else + mount_list = new; + + mount_cnt++; +} + +/* + * remove entries from mount list + */ +static void remove_mount(const char *path, struct svc_req *rqstp) +{ + mountlist iter, next, prev = NULL; + char *host; + + host = inet_ntoa(get_remote(rqstp)); + + iter = mount_list; + while (iter) { + if (strcmp(iter->ml_hostname, host) == 0 && + (!path || strcmp(iter->ml_directory, path) == 0)) { + if (prev) + prev->ml_next = iter->ml_next; + else + mount_list = iter->ml_next; + + next = iter->ml_next; + + free(iter->ml_hostname); + free(iter->ml_directory); + free(iter); + + iter = next; + + /* adjust mount count */ + if (mount_cnt > 0) + mount_cnt--; + } else { + prev = iter; + iter = iter->ml_next; + } + } +} + +void *mountproc_null_3_svc(U(void *argp), U(struct svc_req *rqstp)) +{ + static void *result = NULL; + + return &result; +} + +mountres3 *mountproc_mnt_3_svc(dirpath * argp, struct svc_req * rqstp) +{ + char buf[PATH_MAX]; + static unfs3_fh_t fh; + static mountres3 result; + static int auth = AUTH_UNIX; + int authenticated = 0; + char *password; + + /* We need to modify the *argp pointer. Make a copy. */ + char *dpath = *argp; + + /* error out if not version 3 */ + if (rqstp->rq_vers != 3) { + logmsg(LOG_INFO, + "%s attempted mount with unsupported protocol version", + inet_ntoa(get_remote(rqstp))); + result.fhs_status = MNT3ERR_INVAL; + return &result; + } + + /* Check for "mount commands" */ + if (strncmp(dpath, "@getnonce", sizeof("@getnonce") - 1) == 0) { + if (backend_gen_nonce(nonce) < 0) { + result.fhs_status = MNT3ERR_IO; + } else { + result.fhs_status = MNT3_OK; + result.mountres3_u.mountinfo.fhandle.fhandle3_len = 32; + result.mountres3_u.mountinfo.fhandle.fhandle3_val = nonce; + result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1; + result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = + &auth; + } + return &result; + } else if (strncmp(dpath, "@password:", sizeof("@password:") - 1) == 0) { + char pw[PASSWORD_MAXLEN + 1]; + + mnt_cmd_argument(&dpath, "@password:", pw, PASSWORD_MAXLEN); + if (exports_options(dpath, rqstp, &password, NULL) != -1) { + authenticated = !strcmp(password, pw); + } + /* else leave authenticated unchanged */ + } else if (strncmp(dpath, "@otp:", sizeof("@otp:") - 1) == 0) { + /* The otp from the client */ + char otp[PASSWORD_MAXLEN + 1]; + + /* Our calculated otp */ + char hexdigest[32]; + + mnt_cmd_argument(&dpath, "@otp:", otp, PASSWORD_MAXLEN); + if (exports_options(dpath, rqstp, &password, NULL) != -1) { + otp_digest(nonce, password, hexdigest); + + /* Compare our calculated digest with what the client submitted */ + authenticated = !strncmp(hexdigest, otp, 32); + + /* Change nonce */ + backend_gen_nonce(nonce); + } + /* else leave authenticated unchanged */ + } + + if ((exports_opts & OPT_REMOVABLE) && export_point(dpath)) { + /* Removable media export point. Do not call realpath; simply copy + path */ + strncpy(buf, dpath, PATH_MAX); + } else if (!backend_realpath(dpath, buf)) { + /* the given path does not exist */ + result.fhs_status = MNT3ERR_NOENT; + return &result; + } + + if (strlen(buf) + 1 > NFS_MAXPATHLEN) { + logmsg(LOG_INFO, "%s attempted to mount jumbo path", + inet_ntoa(get_remote(rqstp))); + result.fhs_status = MNT3ERR_NAMETOOLONG; + return &result; + } + + if ((exports_options(buf, rqstp, &password, NULL) == -1) + || (!authenticated && password[0]) + || (!(exports_opts & OPT_INSECURE) && + !IS_SECURE(ntohs(get_port(rqstp)))) + ) { + /* not exported to this host or at all, or a password defined and not + authenticated */ + result.fhs_status = MNT3ERR_ACCES; + return &result; + } + + fh = fh_comp(buf, rqstp, FH_DIR); + + if (!fh_valid(fh)) { + logmsg(LOG_INFO, "%s attempted to mount non-directory", + inet_ntoa(get_remote(rqstp))); + result.fhs_status = MNT3ERR_NOTDIR; + return &result; + } + + add_mount(dpath, rqstp); + + result.fhs_status = MNT3_OK; + result.mountres3_u.mountinfo.fhandle.fhandle3_len = fh_length(&fh); + result.mountres3_u.mountinfo.fhandle.fhandle3_val = (char *) &fh; + result.mountres3_u.mountinfo.auth_flavors.auth_flavors_len = 1; + result.mountres3_u.mountinfo.auth_flavors.auth_flavors_val = &auth; + + return &result; +} + +mountlist *mountproc_dump_3_svc(U(void *argp), U(struct svc_req *rqstp)) +{ + return &mount_list; +} + +void *mountproc_umnt_3_svc(dirpath * argp, struct svc_req *rqstp) +{ + /* RPC times out if we use a NULL pointer */ + static void *result = NULL; + + remove_mount(*argp, rqstp); + + /* if no more mounts are active, flush all open file descriptors */ + if (mount_cnt == 0) + fd_cache_purge(); + + return &result; +} + +void *mountproc_umntall_3_svc(U(void *argp), struct svc_req *rqstp) +{ + /* RPC times out if we use a NULL pointer */ + static void *result = NULL; + + remove_mount(NULL, rqstp); + + /* if no more mounts are active, flush all open file descriptors */ + if (mount_cnt == 0) + fd_cache_purge(); + + return &result; +} + +exports *mountproc_export_3_svc(U(void *argp), U(struct svc_req *rqstp)) +{ + return &exports_nfslist; +} diff --git a/unfs3/mount.h b/unfs3/mount.h new file mode 100644 index 0000000..94327f3 --- /dev/null +++ b/unfs3/mount.h @@ -0,0 +1,97 @@ +/* + * UNFS3 mount protocol definitions + * Generated by rpcgen + */ + +#ifndef _MOUNT_H_RPCGEN +#define _MOUNT_H_RPCGEN + +#define MNTPATHLEN 1024 +#define MNTNAMLEN 255 +#define FHSIZE3 64 + +typedef struct { + u_int fhandle3_len; + char *fhandle3_val; +} fhandle3; + +enum mountstat3 { + MNT3_OK = 0, + MNT3ERR_PERM = 1, + MNT3ERR_NOENT = 2, + MNT3ERR_IO = 5, + MNT3ERR_ACCES = 13, + MNT3ERR_NOTDIR = 20, + MNT3ERR_INVAL = 22, + MNT3ERR_NAMETOOLONG = 63, + MNT3ERR_NOTSUPP = 10004, + MNT3ERR_SERVERFAULT = 10006, +}; +typedef enum mountstat3 mountstat3; + +struct mountres3_ok { + fhandle3 fhandle; + struct { + u_int auth_flavors_len; + int *auth_flavors_val; + } auth_flavors; +}; +typedef struct mountres3_ok mountres3_ok; + +struct mountres3 { + mountstat3 fhs_status; + union { + mountres3_ok mountinfo; + } mountres3_u; +}; +typedef struct mountres3 mountres3; + +typedef char *dirpath; + +typedef char *name; + +typedef struct mountbody *mountlist; + +struct mountbody { + name ml_hostname; + dirpath ml_directory; + mountlist ml_next; +}; +typedef struct mountbody mountbody; + +typedef struct groupnode *groups; + +struct groupnode { + name gr_name; + groups gr_next; +}; +typedef struct groupnode groupnode; + +typedef struct exportnode *exports; + +struct exportnode { + dirpath ex_dir; + groups ex_groups; + exports ex_next; +}; +typedef struct exportnode exportnode; + +#define MOUNTPROG 100005 +#define MOUNTVERS1 1 +#define MOUNTVERS3 3 + +#define MOUNTPROC_NULL 0 +extern void * mountproc_null_3_svc(void *, struct svc_req *); +#define MOUNTPROC_MNT 1 +extern mountres3 * mountproc_mnt_3_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_DUMP 2 +extern mountlist * mountproc_dump_3_svc(void *, struct svc_req *); +#define MOUNTPROC_UMNT 3 +extern void * mountproc_umnt_3_svc(dirpath *, struct svc_req *); +#define MOUNTPROC_UMNTALL 4 +extern void * mountproc_umntall_3_svc(void *, struct svc_req *); +#define MOUNTPROC_EXPORT 5 +extern exports * mountproc_export_3_svc(void *, struct svc_req *); +extern int mountprog_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#endif /* !_MOUNT_H_RPCGEN */ diff --git a/unfs3/nfs.c b/unfs3/nfs.c new file mode 100644 index 0000000..5d99bf8 --- /dev/null +++ b/unfs3/nfs.c @@ -0,0 +1,1083 @@ + +/* + * UNFS3 NFS protocol procedures + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#include /* needed for statfs() on NetBSD */ +#if HAVE_SYS_MOUNT_H == 1 +#include /* dito */ +#endif +#if HAVE_SYS_VMOUNT_H == 1 +#include /* AIX */ +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#endif /* WIN32 */ + +#if HAVE_STATVFS == 1 +# include +#else +# define statvfs statfs +#endif + +#include "nfs.h" +#include "mount.h" +#include "fh.h" +#include "fh_cache.h" +#include "attr.h" +#include "readdir.h" +#include "user.h" +#include "error.h" +#include "fd_cache.h" +#include "daemon.h" +#include "backend.h" +#include "Config/exports.h" +#include "Extras/cluster.h" + +/* + * decompose filehandle and switch user if permitted access + * otherwise zero result structure and return with error status + */ +#define PREP(p,f) do { \ + unfs3_fh_t *fh = (void *)f.data.data_val; \ + switch_to_root(); \ + p = fh_decomp(f); \ + if (exports_options(p, rqstp, NULL, NULL) == -1) { \ + memset(&result, 0, sizeof(result)); \ + if (p) \ + result.status = NFS3ERR_ACCES; \ + else \ + result.status = NFS3ERR_STALE; \ + return &result; \ + } \ + if (fh->pwhash != export_password_hash) { \ + memset(&result, 0, sizeof(result)); \ + result.status = NFS3ERR_STALE; \ + return &result; \ + } \ + switch_user(rqstp); \ + } while (0) + +/* + * cat an object name onto a path, checking for illegal input + */ +nfsstat3 cat_name(const char *path, const char *name, char *result) +{ + char *last; + + if (!path) + return NFS3ERR_STALE; + + if (!name) + return NFS3ERR_ACCES; + + if (name[0] == 0 || strchr(name, '/') != NULL) + return NFS3ERR_ACCES; + + if (strlen(path) + strlen(name) + 2 > NFS_MAXPATHLEN) + return NFS3ERR_NAMETOOLONG; + + if (strcmp(name, ".") == 0) { + strcpy(result, path); + return NFS3_OK; + } + + /* + * Irix clients do lookups for .. and then use the + * resulting filehandle for more lookups, causing them + * to get filehandles that fh_decomp_raw will refuse to + * resolve. Export list handling will also get very + * confused if we allow such filehandles. + */ + if (strcmp(name, "..") == 0) { + last = strrchr(path, '/'); + if (!last || last == path) + strcpy(result, "/"); + else { + *last = 0; + strcpy(result, path); + *last = '/'; + } + return NFS3_OK; + } + + sprintf(result, "%s/%s", path, name); + return NFS3_OK; +} + +void *nfsproc3_null_3_svc(U(void *argp), U(struct svc_req *rqstp)) +{ + static void *result = NULL; + + return &result; +} + +GETATTR3res *nfsproc3_getattr_3_svc(GETATTR3args * argp, + struct svc_req * rqstp) +{ + static GETATTR3res result; + char *path; + post_op_attr post; + + PREP(path, argp->object); + post = get_post_cached(rqstp); + + result.status = NFS3_OK; + result.GETATTR3res_u.resok.obj_attributes = + post.post_op_attr_u.attributes; + + return &result; +} + +/* + * check ctime guard for SETATTR procedure + */ +static nfsstat3 in_sync(sattrguard3 guard, pre_op_attr pre) +{ + if (!pre.attributes_follow) + return NFS3ERR_STALE; + + if (!guard.check) + return NFS3_OK; + + if (guard.sattrguard3_u.obj_ctime.seconds != + pre.pre_op_attr_u.attributes.ctime.seconds) + return NFS3ERR_NOT_SYNC; + + return NFS3_OK; +} + +SETATTR3res *nfsproc3_setattr_3_svc(SETATTR3args * argp, + struct svc_req * rqstp) +{ + static SETATTR3res result; + pre_op_attr pre; + char *path; + + PREP(path, argp->object); + pre = get_pre_cached(); + result.status = join(in_sync(argp->guard, pre), exports_rw()); + + if (result.status == NFS3_OK) + result.status = set_attr(path, argp->object, argp->new_attributes); + + /* overlaps with resfail */ + result.SETATTR3res_u.resok.obj_wcc.before = pre; + result.SETATTR3res_u.resok.obj_wcc.after = get_post_stat(path, rqstp); + + return &result; +} + +LOOKUP3res *nfsproc3_lookup_3_svc(LOOKUP3args * argp, struct svc_req * rqstp) +{ + static LOOKUP3res result; + unfs3_fh_t *fh; + char *path; + char obj[NFS_MAXPATHLEN]; + backend_statstruct buf; + int res; + uint32 gen; + + PREP(path, argp->what.dir); + result.status = cat_name(path, argp->what.name, obj); + + cluster_lookup(obj, rqstp, &result.status); + + if (result.status == NFS3_OK) { + res = backend_lstat(obj, &buf); + if (res == -1) + result.status = lookup_err(); + else { + if (strcmp(argp->what.name, ".") == 0 || + strcmp(argp->what.name, "..") == 0) { + fh = fh_comp_ptr(obj, rqstp, 0); + } else { + gen = backend_get_gen(buf, FD_NONE, obj); + fh = fh_extend(argp->what.dir, buf.st_dev, buf.st_ino, gen); + fh_cache_add(buf.st_dev, buf.st_ino, obj); + } + + if (fh) { + result.LOOKUP3res_u.resok.object.data.data_len = + fh_length(fh); + result.LOOKUP3res_u.resok.object.data.data_val = (char *) fh; + result.LOOKUP3res_u.resok.obj_attributes = + get_post_buf(buf, rqstp); + } else { + /* path was too long */ + result.status = NFS3ERR_NAMETOOLONG; + } + } + } + + /* overlaps with resfail */ + result.LOOKUP3res_u.resok.dir_attributes = get_post_stat(path, rqstp); + + return &result; +} + +ACCESS3res *nfsproc3_access_3_svc(ACCESS3args * argp, struct svc_req * rqstp) +{ + static ACCESS3res result; + char *path; + post_op_attr post; + mode_t mode; + int access = 0; + + PREP(path, argp->object); + post = get_post_cached(rqstp); + mode = post.post_op_attr_u.attributes.mode; + + /* owner permissions */ + if (is_owner(st_cache.st_uid, rqstp)) { + if (mode & S_IRUSR) + access |= ACCESS3_READ; + if (mode & S_IWUSR) + access |= ACCESS3_MODIFY | ACCESS3_EXTEND; + if (mode & S_IXUSR) { + access |= ACCESS3_EXECUTE; + if (opt_readable_executables) + access |= ACCESS3_READ; + } + } else if (has_group(st_cache.st_gid, rqstp)) { + /* group permissions */ + if (mode & S_IRGRP) + access |= ACCESS3_READ; + if (mode & S_IWGRP) + access |= ACCESS3_MODIFY | ACCESS3_EXTEND; + if (mode & S_IXGRP) { + access |= ACCESS3_EXECUTE; + if (opt_readable_executables) + access |= ACCESS3_READ; + } + } else { + /* other permissions */ + if (mode & S_IROTH) + access |= ACCESS3_READ; + if (mode & S_IWOTH) + access |= ACCESS3_MODIFY | ACCESS3_EXTEND; + if (mode & S_IXOTH) { + access |= ACCESS3_EXECUTE; + if (opt_readable_executables) + access |= ACCESS3_READ; + } + } + + /* root is allowed everything */ + if (get_uid(rqstp) == 0) + access |= ACCESS3_READ | ACCESS3_MODIFY | ACCESS3_EXTEND; + + /* adjust if directory */ + if (post.post_op_attr_u.attributes.type == NF3DIR) { + if (access & (ACCESS3_READ | ACCESS3_EXECUTE)) + access |= ACCESS3_LOOKUP; + if (access & ACCESS3_MODIFY) + access |= ACCESS3_DELETE; + access &= ~ACCESS3_EXECUTE; + } + + result.status = NFS3_OK; + result.ACCESS3res_u.resok.access = access & argp->access; + result.ACCESS3res_u.resok.obj_attributes = post; + + return &result; +} + +READLINK3res *nfsproc3_readlink_3_svc(READLINK3args * argp, + struct svc_req * rqstp) +{ + static READLINK3res result; + char *path; + static char buf[NFS_MAXPATHLEN]; + int res; + + PREP(path, argp->symlink); + + res = backend_readlink(path, buf, NFS_MAXPATHLEN - 1); + if (res == -1) + result.status = readlink_err(); + else { + /* readlink does not NULL-terminate */ + buf[res] = 0; + + result.status = NFS3_OK; + result.READLINK3res_u.resok.data = buf; + } + + /* overlaps with resfail */ + result.READLINK3res_u.resok.symlink_attributes = + get_post_stat(path, rqstp); + + return &result; +} + +READ3res *nfsproc3_read_3_svc(READ3args * argp, struct svc_req * rqstp) +{ + static READ3res result; + char *path; + int fd, res; + static char buf[NFS_MAXDATA_TCP + 1]; + unsigned int maxdata; + + if (get_socket_type(rqstp) == SOCK_STREAM) + maxdata = NFS_MAXDATA_TCP; + else + maxdata = NFS_MAXDATA_UDP; + + PREP(path, argp->file); + result.status = is_reg(); + + /* handle reading of executables */ + read_executable(rqstp, st_cache); + + /* handle read of owned files */ + read_by_owner(rqstp, st_cache); + + /* if bigger than rtmax, truncate length */ + if (argp->count > maxdata) + argp->count = maxdata; + + if (result.status == NFS3_OK) { + fd = fd_open(path, argp->file, UNFS3_FD_READ, TRUE); + if (fd != -1) { + /* read one more to check for eof */ + res = backend_pread(fd, buf, argp->count + 1, argp->offset); + + /* eof if we could not read one more */ + result.READ3res_u.resok.eof = (res <= (int64) argp->count); + + /* close for real when hitting eof */ + if (result.READ3res_u.resok.eof) + fd_close(fd, UNFS3_FD_READ, FD_CLOSE_REAL); + else { + fd_close(fd, UNFS3_FD_READ, FD_CLOSE_VIRT); + res--; + } + + if (res >= 0) { + result.READ3res_u.resok.count = res; + result.READ3res_u.resok.data.data_len = res; + result.READ3res_u.resok.data.data_val = buf; + } else { + /* error during read() */ + + /* EINVAL means unreadable object */ + if (errno == EINVAL) + result.status = NFS3ERR_INVAL; + else + result.status = NFS3ERR_IO; + } + } else + /* opening for read failed */ + result.status = read_err(); + } + + /* overlaps with resfail */ + result.READ3res_u.resok.file_attributes = get_post_stat(path, rqstp); + + return &result; +} + +WRITE3res *nfsproc3_write_3_svc(WRITE3args * argp, struct svc_req * rqstp) +{ + static WRITE3res result; + char *path; + int fd, res, res_close; + + PREP(path, argp->file); + result.status = join(is_reg(), exports_rw()); + + /* handle write of owned files */ + write_by_owner(rqstp, st_cache); + + if (result.status == NFS3_OK) { + /* We allow caching of the fd only for unstable writes. This is to + prevent generating a new write verifier for failed stable writes, + when the fd was not in the cache. Besides, for stable writes, the + fd will be removed from the cache by fd_close() below, so adding + it to and removing it from the cache is just a waste of CPU cycles + */ + fd = fd_open(path, argp->file, UNFS3_FD_WRITE, + (argp->stable == UNSTABLE)); + if (fd != -1) { + res = + backend_pwrite(fd, argp->data.data_val, argp->data.data_len, + argp->offset); + + /* close for real if not UNSTABLE write */ + if (argp->stable == UNSTABLE) + res_close = fd_close(fd, UNFS3_FD_WRITE, FD_CLOSE_VIRT); + else + res_close = fd_close(fd, UNFS3_FD_WRITE, FD_CLOSE_REAL); + + /* we always do fsync(), never fdatasync() */ + if (argp->stable == DATA_SYNC) + argp->stable = FILE_SYNC; + + if (res != -1 && res_close != -1) { + result.WRITE3res_u.resok.count = res; + result.WRITE3res_u.resok.committed = argp->stable; + memcpy(result.WRITE3res_u.resok.verf, wverf, + NFS3_WRITEVERFSIZE); + } else { + /* error during write or close */ + result.status = write_write_err(); + } + } else + /* could not open for writing */ + result.status = write_open_err(); + } + + /* overlaps with resfail */ + result.WRITE3res_u.resok.file_wcc.before = get_pre_cached(); + result.WRITE3res_u.resok.file_wcc.after = get_post_stat(path, rqstp); + + return &result; +} + +#ifndef WIN32 + +/* + * store verifier in atime and mtime + */ +static int store_create_verifier(char *obj, createverf3 verf) +{ + struct utimbuf ubuf; + + ubuf.actime = verf[0] | verf[1] << 8 | verf[2] << 16 | verf[3] << 24; + ubuf.modtime = verf[4] | verf[5] << 8 | verf[6] << 16 | verf[7] << 24; + + return backend_utime(obj, &ubuf); +} + +/* + * check if a create verifier matches + */ +static int check_create_verifier(backend_statstruct * buf, createverf3 verf) +{ + return ((buf->st_atime == + (verf[0] | verf[1] << 8 | verf[2] << 16 | verf[3] << 24)) + && (buf->st_mtime == + (verf[4] | verf[5] << 8 | verf[6] << 16 | verf[7] << 24))); +} +#endif /* WIN32 */ + +CREATE3res *nfsproc3_create_3_svc(CREATE3args * argp, struct svc_req * rqstp) +{ + static CREATE3res result; + char *path; + char obj[NFS_MAXPATHLEN]; + sattr3 new_attr; + int fd = -1, res = -1; + backend_statstruct buf; + uint32 gen; + int flags = O_RDWR | O_CREAT | O_TRUNC | O_NONBLOCK; + + PREP(path, argp->where.dir); + result.status = join(cat_name(path, argp->where.name, obj), exports_rw()); + + cluster_create(obj, rqstp, &result.status); + + /* GUARDED and EXCLUSIVE maps to Unix exclusive create */ + if (argp->how.mode != UNCHECKED) + flags = flags | O_EXCL; + + if (argp->how.mode != EXCLUSIVE) { + new_attr = argp->how.createhow3_u.obj_attributes; + result.status = join(result.status, atomic_attr(new_attr)); + } + + /* Try to open the file */ + if (result.status == NFS3_OK) { + if (argp->how.mode != EXCLUSIVE) { + fd = backend_open_create(obj, flags, create_mode(new_attr)); + } else { + fd = backend_open_create(obj, flags, create_mode(new_attr)); + } + } + + if (fd != -1) { + /* Successful open */ + res = backend_fstat(fd, &buf); + if (res != -1) { + /* Successful stat */ + if (argp->how.mode == EXCLUSIVE) { + /* Save verifier in atime and mtime */ + res = + backend_store_create_verifier(obj, + argp->how.createhow3_u. + verf); + } + } + + if (res != -1) { + /* So far, so good */ + gen = backend_get_gen(buf, fd, obj); + fh_cache_add(buf.st_dev, buf.st_ino, obj); + backend_close(fd); + + result.CREATE3res_u.resok.obj = + fh_extend_post(argp->where.dir, buf.st_dev, buf.st_ino, gen); + result.CREATE3res_u.resok.obj_attributes = + get_post_buf(buf, rqstp); + } + + if (res == -1) { + /* backend_fstat() or backend_store_create_verifier() failed */ + backend_close(fd); + result.status = NFS3ERR_IO; + } + + } else if (result.status == NFS3_OK) { + /* open() failed */ + if (argp->how.mode == EXCLUSIVE && errno == EEXIST) { + /* Check if verifier matches */ + fd = backend_open(obj, O_NONBLOCK); + if (fd != -1) { + res = backend_fstat(fd, &buf); + } + + if (res != -1) { + if (backend_check_create_verifier + (&buf, argp->how.createhow3_u.verf)) { + /* The verifier matched. Return success */ + gen = backend_get_gen(buf, fd, obj); + fh_cache_add(buf.st_dev, buf.st_ino, obj); + backend_close(fd); + + result.CREATE3res_u.resok.obj = + fh_extend_post(argp->where.dir, buf.st_dev, + buf.st_ino, gen); + result.CREATE3res_u.resok.obj_attributes = + get_post_buf(buf, rqstp); + } else { + /* The verifier doesn't match */ + result.status = NFS3ERR_EXIST; + } + } + } + if (res == -1) { + result.status = create_err(); + } + } + + /* overlaps with resfail */ + result.CREATE3res_u.resok.dir_wcc.before = get_pre_cached(); + result.CREATE3res_u.resok.dir_wcc.after = get_post_stat(path, rqstp); + + return &result; +} + +MKDIR3res *nfsproc3_mkdir_3_svc(MKDIR3args * argp, struct svc_req * rqstp) +{ + static MKDIR3res result; + char *path; + pre_op_attr pre; + post_op_attr post; + char obj[NFS_MAXPATHLEN]; + int res; + + PREP(path, argp->where.dir); + pre = get_pre_cached(); + result.status = + join3(cat_name(path, argp->where.name, obj), + atomic_attr(argp->attributes), exports_rw()); + + cluster_create(obj, rqstp, &result.status); + + if (result.status == NFS3_OK) { + res = backend_mkdir(obj, create_mode(argp->attributes)); + if (res == -1) + result.status = mkdir_err(); + else { + result.MKDIR3res_u.resok.obj = + fh_extend_type(argp->where.dir, obj, S_IFDIR); + result.MKDIR3res_u.resok.obj_attributes = get_post_cached(rqstp); + } + } + + post = get_post_attr(path, argp->where.dir, rqstp); + + /* overlaps with resfail */ + result.MKDIR3res_u.resok.dir_wcc.before = pre; + result.MKDIR3res_u.resok.dir_wcc.after = post; + + return &result; +} + +SYMLINK3res *nfsproc3_symlink_3_svc(SYMLINK3args * argp, + struct svc_req * rqstp) +{ + static SYMLINK3res result; + char *path; + pre_op_attr pre; + post_op_attr post; + char obj[NFS_MAXPATHLEN]; + int res; + mode_t new_mode; + + PREP(path, argp->where.dir); + pre = get_pre_cached(); + result.status = + join3(cat_name(path, argp->where.name, obj), + atomic_attr(argp->symlink.symlink_attributes), exports_rw()); + + cluster_create(obj, rqstp, &result.status); + + if (argp->symlink.symlink_attributes.mode.set_it == TRUE) + new_mode = create_mode(argp->symlink.symlink_attributes); + else { + /* default rwxrwxrwx */ + new_mode = + S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IWGRP | S_IXGRP | + S_IROTH | S_IWOTH | S_IXOTH; + } + + if (result.status == NFS3_OK) { + umask(~new_mode); + res = backend_symlink(argp->symlink.symlink_data, obj); + umask(0); + if (res == -1) + result.status = symlink_err(); + else { + result.SYMLINK3res_u.resok.obj = + fh_extend_type(argp->where.dir, obj, S_IFLNK); + result.SYMLINK3res_u.resok.obj_attributes = + get_post_cached(rqstp); + } + } + + post = get_post_attr(path, argp->where.dir, rqstp); + + /* overlaps with resfail */ + result.SYMLINK3res_u.resok.dir_wcc.before = pre; + result.SYMLINK3res_u.resok.dir_wcc.after = post; + + return &result; +} + +#ifndef WIN32 + +/* + * create Unix socket + */ +static int mksocket(const char *path, mode_t mode) +{ + int res, sock; + struct sockaddr_un addr; + + sock = socket(PF_UNIX, SOCK_STREAM, 0); + addr.sun_family = AF_UNIX; + strcpy(addr.sun_path, path); + res = sock; + if (res != -1) { + umask(~mode); + res = + bind(sock, (struct sockaddr *) &addr, + sizeof(addr.sun_family) + strlen(addr.sun_path)); + umask(0); + close(sock); + } + return res; +} + +#endif /* WIN32 */ + +/* + * check and process arguments to MKNOD procedure + */ +static nfsstat3 mknod_args(mknoddata3 what, const char *obj, mode_t * mode, + dev_t * dev) +{ + sattr3 attr; + + /* determine attributes */ + switch (what.type) { + case NF3REG: + case NF3DIR: + case NF3LNK: + return NFS3ERR_INVAL; + case NF3SOCK: + if (strlen(obj) + 1 > UNIX_PATH_MAX) + return NFS3ERR_NAMETOOLONG; + /* fall thru */ + case NF3FIFO: + attr = what.mknoddata3_u.pipe_attributes; + break; + case NF3BLK: + case NF3CHR: + attr = what.mknoddata3_u.device.dev_attributes; + *dev = (what.mknoddata3_u.device.spec.specdata1 << 8) + + what.mknoddata3_u.device.spec.specdata2; + break; + } + + *mode = create_mode(attr); + + /* adjust mode for creation of device special files */ + switch (what.type) { + case NF3CHR: + *mode |= S_IFCHR; + break; + case NF3BLK: + *mode |= S_IFBLK; + break; + default: + break; + } + + return atomic_attr(attr); +} + +MKNOD3res *nfsproc3_mknod_3_svc(MKNOD3args * argp, struct svc_req * rqstp) +{ + static MKNOD3res result; + char *path; + pre_op_attr pre; + post_op_attr post; + char obj[NFS_MAXPATHLEN]; + int res; + mode_t new_mode = 0; + dev_t dev = 0; + + PREP(path, argp->where.dir); + pre = get_pre_cached(); + result.status = + join3(cat_name(path, argp->where.name, obj), + mknod_args(argp->what, obj, &new_mode, &dev), exports_rw()); + + cluster_create(obj, rqstp, &result.status); + + if (result.status == NFS3_OK) { + if (argp->what.type == NF3CHR || argp->what.type == NF3BLK) + res = backend_mknod(obj, new_mode, dev); /* device */ + else if (argp->what.type == NF3FIFO) + res = backend_mkfifo(obj, new_mode); /* FIFO */ + else + res = backend_mksocket(obj, new_mode); /* socket */ + + if (res == -1) { + result.status = mknod_err(); + } else { + result.MKNOD3res_u.resok.obj = + fh_extend_type(argp->where.dir, obj, + type_to_mode(argp->what.type)); + result.MKNOD3res_u.resok.obj_attributes = get_post_cached(rqstp); + } + } + + post = get_post_attr(path, argp->where.dir, rqstp); + + /* overlaps with resfail */ + result.MKNOD3res_u.resok.dir_wcc.before = pre; + result.MKNOD3res_u.resok.dir_wcc.after = post; + + return &result; +} + +REMOVE3res *nfsproc3_remove_3_svc(REMOVE3args * argp, struct svc_req * rqstp) +{ + static REMOVE3res result; + char *path; + char obj[NFS_MAXPATHLEN]; + int res; + + PREP(path, argp->object.dir); + result.status = + join(cat_name(path, argp->object.name, obj), exports_rw()); + + cluster_lookup(obj, rqstp, &result.status); + + if (result.status == NFS3_OK) { + change_readdir_cookie(); + res = backend_remove(obj); + if (res == -1) + result.status = remove_err(); + } + + /* overlaps with resfail */ + result.REMOVE3res_u.resok.dir_wcc.before = get_pre_cached(); + result.REMOVE3res_u.resok.dir_wcc.after = get_post_stat(path, rqstp); + + return &result; +} + +RMDIR3res *nfsproc3_rmdir_3_svc(RMDIR3args * argp, struct svc_req * rqstp) +{ + static RMDIR3res result; + char *path; + char obj[NFS_MAXPATHLEN]; + int res; + + PREP(path, argp->object.dir); + result.status = + join(cat_name(path, argp->object.name, obj), exports_rw()); + + cluster_lookup(obj, rqstp, &result.status); + + if (result.status == NFS3_OK) { + change_readdir_cookie(); + res = backend_rmdir(obj); + if (res == -1) + result.status = rmdir_err(); + } + + /* overlaps with resfail */ + result.RMDIR3res_u.resok.dir_wcc.before = get_pre_cached(); + result.RMDIR3res_u.resok.dir_wcc.after = get_post_stat(path, rqstp); + + return &result; +} + +RENAME3res *nfsproc3_rename_3_svc(RENAME3args * argp, struct svc_req * rqstp) +{ + static RENAME3res result; + char *from; + char *to; + char from_obj[NFS_MAXPATHLEN]; + char to_obj[NFS_MAXPATHLEN]; + pre_op_attr pre; + post_op_attr post; + int res; + + PREP(from, argp->from.dir); + pre = get_pre_cached(); + result.status = + join(cat_name(from, argp->from.name, from_obj), exports_rw()); + + cluster_lookup(from_obj, rqstp, &result.status); + + to = fh_decomp(argp->to.dir); + + if (result.status == NFS3_OK) { + result.status = + join(cat_name(to, argp->to.name, to_obj), + exports_compat(to, rqstp)); + + cluster_create(to_obj, rqstp, &result.status); + + if (result.status == NFS3_OK) { + change_readdir_cookie(); + res = backend_rename(from_obj, to_obj); + if (res == -1) + result.status = rename_err(); + } + } + + post = get_post_attr(from, argp->from.dir, rqstp); + + /* overlaps with resfail */ + result.RENAME3res_u.resok.fromdir_wcc.before = pre; + result.RENAME3res_u.resok.fromdir_wcc.after = post; + result.RENAME3res_u.resok.todir_wcc.before = get_pre_cached(); + result.RENAME3res_u.resok.todir_wcc.after = get_post_stat(to, rqstp); + + return &result; +} + +LINK3res *nfsproc3_link_3_svc(LINK3args * argp, struct svc_req * rqstp) +{ + static LINK3res result; + char *path, *old; + pre_op_attr pre; + post_op_attr post; + char obj[NFS_MAXPATHLEN]; + int res; + + PREP(path, argp->link.dir); + pre = get_pre_cached(); + result.status = join(cat_name(path, argp->link.name, obj), exports_rw()); + + cluster_create(obj, rqstp, &result.status); + + old = fh_decomp(argp->file); + + if (old && result.status == NFS3_OK) { + result.status = exports_compat(old, rqstp); + + if (result.status == NFS3_OK) { + res = backend_link(old, obj); + if (res == -1) + result.status = link_err(); + } + } else if (!old) + result.status = NFS3ERR_STALE; + + post = get_post_attr(path, argp->link.dir, rqstp); + + /* overlaps with resfail */ + result.LINK3res_u.resok.file_attributes = get_post_stat(old, rqstp); + result.LINK3res_u.resok.linkdir_wcc.before = pre; + result.LINK3res_u.resok.linkdir_wcc.after = post; + + return &result; +} + +READDIR3res *nfsproc3_readdir_3_svc(READDIR3args * argp, + struct svc_req * rqstp) +{ + static READDIR3res result; + char *path; + + PREP(path, argp->dir); + + result = read_dir(path, argp->cookie, argp->cookieverf, argp->count); + result.READDIR3res_u.resok.dir_attributes = get_post_stat(path, rqstp); + + return &result; +} + +READDIRPLUS3res *nfsproc3_readdirplus_3_svc(U(READDIRPLUS3args * argp), + U(struct svc_req * rqstp)) +{ + static READDIRPLUS3res result; + + /* + * we don't do READDIRPLUS since it involves filehandle and + * attribute getting which is impossible to do atomically + * from user-space + */ + result.status = NFS3ERR_NOTSUPP; + result.READDIRPLUS3res_u.resfail.dir_attributes.attributes_follow = FALSE; + + return &result; +} + +FSSTAT3res *nfsproc3_fsstat_3_svc(FSSTAT3args * argp, struct svc_req * rqstp) +{ + static FSSTAT3res result; + char *path; + backend_statvfsstruct buf; + int res; + + PREP(path, argp->fsroot); + + /* overlaps with resfail */ + result.FSSTAT3res_u.resok.obj_attributes = get_post_cached(rqstp); + + res = backend_statvfs(path, &buf); + if (res == -1) { + /* statvfs fell on its nose */ + if ((exports_opts & OPT_REMOVABLE) && export_point(path)) { + /* Removable media export point; probably no media inserted. + Return dummy values. */ + result.status = NFS3_OK; + result.FSSTAT3res_u.resok.tbytes = 0; + result.FSSTAT3res_u.resok.fbytes = 0; + result.FSSTAT3res_u.resok.abytes = 0; + result.FSSTAT3res_u.resok.tfiles = 0; + result.FSSTAT3res_u.resok.ffiles = 0; + result.FSSTAT3res_u.resok.afiles = 0; + result.FSSTAT3res_u.resok.invarsec = 0; + } else { + result.status = NFS3ERR_IO; + } + } else { + result.status = NFS3_OK; + result.FSSTAT3res_u.resok.tbytes = + (uint64) buf.f_blocks * buf.f_frsize; + result.FSSTAT3res_u.resok.fbytes = + (uint64) buf.f_bfree * buf.f_frsize; + result.FSSTAT3res_u.resok.abytes = + (uint64) buf.f_bavail * buf.f_frsize; + result.FSSTAT3res_u.resok.tfiles = buf.f_files; + result.FSSTAT3res_u.resok.ffiles = buf.f_ffree; + result.FSSTAT3res_u.resok.afiles = buf.f_ffree; + result.FSSTAT3res_u.resok.invarsec = 0; + } + + return &result; +} + +FSINFO3res *nfsproc3_fsinfo_3_svc(FSINFO3args * argp, struct svc_req * rqstp) +{ + static FSINFO3res result; + char *path; + unsigned int maxdata; + + if (get_socket_type(rqstp) == SOCK_STREAM) + maxdata = NFS_MAXDATA_TCP; + else + maxdata = NFS_MAXDATA_UDP; + + PREP(path, argp->fsroot); + + result.FSINFO3res_u.resok.obj_attributes = get_post_cached(rqstp); + + result.status = NFS3_OK; + result.FSINFO3res_u.resok.rtmax = maxdata; + result.FSINFO3res_u.resok.rtpref = maxdata; + result.FSINFO3res_u.resok.rtmult = 4096; + result.FSINFO3res_u.resok.wtmax = maxdata; + result.FSINFO3res_u.resok.wtpref = maxdata; + result.FSINFO3res_u.resok.wtmult = 4096; + result.FSINFO3res_u.resok.dtpref = 4096; + result.FSINFO3res_u.resok.maxfilesize = ~0ULL; + result.FSINFO3res_u.resok.time_delta.seconds = backend_time_delta_seconds; + result.FSINFO3res_u.resok.time_delta.nseconds = 0; + result.FSINFO3res_u.resok.properties = backend_fsinfo_properties; + + return &result; +} + +PATHCONF3res *nfsproc3_pathconf_3_svc(PATHCONF3args * argp, + struct svc_req * rqstp) +{ + static PATHCONF3res result; + char *path; + + PREP(path, argp->object); + + result.PATHCONF3res_u.resok.obj_attributes = get_post_cached(rqstp); + + result.status = NFS3_OK; + result.PATHCONF3res_u.resok.linkmax = 0xFFFFFFFF; + result.PATHCONF3res_u.resok.name_max = NFS_MAXPATHLEN; + result.PATHCONF3res_u.resok.no_trunc = TRUE; + result.PATHCONF3res_u.resok.chown_restricted = FALSE; + result.PATHCONF3res_u.resok.case_insensitive = + backend_pathconf_case_insensitive; + result.PATHCONF3res_u.resok.case_preserving = TRUE; + + return &result; +} + +COMMIT3res *nfsproc3_commit_3_svc(COMMIT3args * argp, struct svc_req * rqstp) +{ + static COMMIT3res result; + char *path; + int res; + + PREP(path, argp->file); + result.status = join(is_reg(), exports_rw()); + + if (result.status == NFS3_OK) { + res = fd_sync(argp->file); + if (res != -1) + memcpy(result.COMMIT3res_u.resok.verf, wverf, NFS3_WRITEVERFSIZE); + else + /* error during fsync() or close() */ + result.status = NFS3ERR_IO; + } + + /* overlaps with resfail */ + result.COMMIT3res_u.resfail.file_wcc.before = get_pre_cached(); + result.COMMIT3res_u.resfail.file_wcc.after = get_post_stat(path, rqstp); + + return &result; +} diff --git a/unfs3/nfs.h b/unfs3/nfs.h new file mode 100644 index 0000000..63041fa --- /dev/null +++ b/unfs3/nfs.h @@ -0,0 +1,1007 @@ +/* + * UNFS3 NFS protocol definitions + * Generated by rpcgen + */ + +#ifndef _NFS_PROT_H_RPCGEN +#define _NFS_PROT_H_RPCGEN + +/* for lack of a better place */ +#ifdef __GNUC__ +#define U(x) x __attribute__ ((unused)) +#else +#define U(x) x +#endif + +#if HAVE_STDINT_H == 1 +#include +#endif + +#include + +#define UNIX_PATH_MAX 108 + +#define NFS_PORT 2049 +#define NFS_MAXDATA_TCP 524288 +#define NFS_MAXDATA_UDP 32768 +#define NFS_MAX_UDP_PACKET (NFS_MAXDATA_UDP + 4096) /* The extra 4096 bytes are for the RPC header */ +#define NFS_MAXPATHLEN 1024 +#define NFS_MAXNAMLEN 255 +#define NFS_FIFO_DEV -1 +#define NFSMODE_FMT 0170000 +#define NFSMODE_DIR 0040000 +#define NFSMODE_CHR 0020000 +#define NFSMODE_BLK 0060000 +#define NFSMODE_REG 0100000 +#define NFSMODE_LNK 0120000 +#define NFSMODE_SOCK 0140000 +#define NFSMODE_FIFO 0010000 + +typedef char *filename; + +typedef char *nfspath; +#define NFS3_FHSIZE 64 +#define NFS3_COOKIEVERFSIZE 8 +#define NFS3_CREATEVERFSIZE 8 +#define NFS3_WRITEVERFSIZE 8 + +#if HAVE_UINT64 == 0 +typedef uint64_t uint64; +#endif + +#if HAVE_INT64 == 0 +typedef int64_t int64; +#endif + +#if HAVE_UINT32 == 0 +#if HAVE_XDR_U_LONG == 1 +typedef u_long uint32; +#else +typedef uint32_t uint32; +#endif +#endif + +#if HAVE_INT32 == 0 +#if HAVE_XDR_LONG == 1 +typedef long int32; +#else +typedef int32_t int32; +#endif +#endif + +typedef char *filename3; + +typedef char *nfspath3; + +typedef uint64 fileid3; + +typedef uint64 cookie3; + +typedef char cookieverf3[NFS3_COOKIEVERFSIZE]; + +typedef char createverf3[NFS3_CREATEVERFSIZE]; + +typedef char writeverf3[NFS3_WRITEVERFSIZE]; + +typedef uint32 uid3; + +typedef uint32 gid3; + +typedef uint64 size3; + +typedef uint64 offset3; + +typedef uint32 mode3; + +typedef uint32 count3; + +enum nfsstat3 { + NFS3_OK = 0, + NFS3ERR_PERM = 1, + NFS3ERR_NOENT = 2, + NFS3ERR_IO = 5, + NFS3ERR_NXIO = 6, + NFS3ERR_ACCES = 13, + NFS3ERR_EXIST = 17, + NFS3ERR_XDEV = 18, + NFS3ERR_NODEV = 19, + NFS3ERR_NOTDIR = 20, + NFS3ERR_ISDIR = 21, + NFS3ERR_INVAL = 22, + NFS3ERR_FBIG = 27, + NFS3ERR_NOSPC = 28, + NFS3ERR_ROFS = 30, + NFS3ERR_MLINK = 31, + NFS3ERR_NAMETOOLONG = 63, + NFS3ERR_NOTEMPTY = 66, + NFS3ERR_DQUOT = 69, + NFS3ERR_STALE = 70, + NFS3ERR_REMOTE = 71, + NFS3ERR_BADHANDLE = 10001, + NFS3ERR_NOT_SYNC = 10002, + NFS3ERR_BAD_COOKIE = 10003, + NFS3ERR_NOTSUPP = 10004, + NFS3ERR_TOOSMALL = 10005, + NFS3ERR_SERVERFAULT = 10006, + NFS3ERR_BADTYPE = 10007, + NFS3ERR_JUKEBOX = 10008, +}; +typedef enum nfsstat3 nfsstat3; + +enum ftype3 { + NF3REG = 1, + NF3DIR = 2, + NF3BLK = 3, + NF3CHR = 4, + NF3LNK = 5, + NF3SOCK = 6, + NF3FIFO = 7, +}; +typedef enum ftype3 ftype3; + +struct specdata3 { + uint32 specdata1; + uint32 specdata2; +}; +typedef struct specdata3 specdata3; + +struct nfs_fh3 { + struct { + u_int data_len; + char *data_val; + } data; +}; +typedef struct nfs_fh3 nfs_fh3; + +struct nfstime3 { + uint32 seconds; + uint32 nseconds; +}; +typedef struct nfstime3 nfstime3; + +struct fattr3 { + ftype3 type; + mode3 mode; + uint32 nlink; + uid3 uid; + gid3 gid; + size3 size; + size3 used; + specdata3 rdev; + uint64 fsid; + fileid3 fileid; + nfstime3 atime; + nfstime3 mtime; + nfstime3 ctime; +}; +typedef struct fattr3 fattr3; + +struct post_op_attr { + bool_t attributes_follow; + union { + fattr3 attributes; + } post_op_attr_u; +}; +typedef struct post_op_attr post_op_attr; + +struct wcc_attr { + size3 size; + nfstime3 mtime; + nfstime3 ctime; +}; +typedef struct wcc_attr wcc_attr; + +struct pre_op_attr { + bool_t attributes_follow; + union { + wcc_attr attributes; + } pre_op_attr_u; +}; +typedef struct pre_op_attr pre_op_attr; + +struct wcc_data { + pre_op_attr before; + post_op_attr after; +}; +typedef struct wcc_data wcc_data; + +struct post_op_fh3 { + bool_t handle_follows; + union { + nfs_fh3 handle; + } post_op_fh3_u; +}; +typedef struct post_op_fh3 post_op_fh3; + +enum time_how { + DONT_CHANGE = 0, + SET_TO_SERVER_TIME = 1, + SET_TO_CLIENT_TIME = 2, +}; +typedef enum time_how time_how; + +struct set_mode3 { + bool_t set_it; + union { + mode3 mode; + } set_mode3_u; +}; +typedef struct set_mode3 set_mode3; + +struct set_uid3 { + bool_t set_it; + union { + uid3 uid; + } set_uid3_u; +}; +typedef struct set_uid3 set_uid3; + +struct set_gid3 { + bool_t set_it; + union { + gid3 gid; + } set_gid3_u; +}; +typedef struct set_gid3 set_gid3; + +struct set_size3 { + bool_t set_it; + union { + size3 size; + } set_size3_u; +}; +typedef struct set_size3 set_size3; + +struct set_atime { + time_how set_it; + union { + nfstime3 atime; + } set_atime_u; +}; +typedef struct set_atime set_atime; + +struct set_mtime { + time_how set_it; + union { + nfstime3 mtime; + } set_mtime_u; +}; +typedef struct set_mtime set_mtime; + +struct sattr3 { + set_mode3 mode; + set_uid3 uid; + set_gid3 gid; + set_size3 size; + set_atime atime; + set_mtime mtime; +}; +typedef struct sattr3 sattr3; + +struct diropargs3 { + nfs_fh3 dir; + filename3 name; +}; +typedef struct diropargs3 diropargs3; + +struct GETATTR3args { + nfs_fh3 object; +}; +typedef struct GETATTR3args GETATTR3args; + +struct GETATTR3resok { + fattr3 obj_attributes; +}; +typedef struct GETATTR3resok GETATTR3resok; + +struct GETATTR3res { + nfsstat3 status; + union { + GETATTR3resok resok; + } GETATTR3res_u; +}; +typedef struct GETATTR3res GETATTR3res; + +struct sattrguard3 { + bool_t check; + union { + nfstime3 obj_ctime; + } sattrguard3_u; +}; +typedef struct sattrguard3 sattrguard3; + +struct SETATTR3args { + nfs_fh3 object; + sattr3 new_attributes; + sattrguard3 guard; +}; +typedef struct SETATTR3args SETATTR3args; + +struct SETATTR3resok { + wcc_data obj_wcc; +}; +typedef struct SETATTR3resok SETATTR3resok; + +struct SETATTR3resfail { + wcc_data obj_wcc; +}; +typedef struct SETATTR3resfail SETATTR3resfail; + +struct SETATTR3res { + nfsstat3 status; + union { + SETATTR3resok resok; + SETATTR3resfail resfail; + } SETATTR3res_u; +}; +typedef struct SETATTR3res SETATTR3res; + +struct LOOKUP3args { + diropargs3 what; +}; +typedef struct LOOKUP3args LOOKUP3args; + +struct LOOKUP3resok { + post_op_attr dir_attributes; + nfs_fh3 object; + post_op_attr obj_attributes; +}; +typedef struct LOOKUP3resok LOOKUP3resok; + +struct LOOKUP3resfail { + post_op_attr dir_attributes; +}; +typedef struct LOOKUP3resfail LOOKUP3resfail; + +struct LOOKUP3res { + nfsstat3 status; + union { + LOOKUP3resok resok; + LOOKUP3resfail resfail; + } LOOKUP3res_u; +}; +typedef struct LOOKUP3res LOOKUP3res; + +#define ACCESS3_READ 0x0001 +#define ACCESS3_LOOKUP 0x0002 +#define ACCESS3_MODIFY 0x0004 +#define ACCESS3_EXTEND 0x0008 +#define ACCESS3_DELETE 0x0010 +#define ACCESS3_EXECUTE 0x0020 + +struct ACCESS3args { + nfs_fh3 object; + uint32 access; +}; +typedef struct ACCESS3args ACCESS3args; + +struct ACCESS3resok { + post_op_attr obj_attributes; + uint32 access; +}; +typedef struct ACCESS3resok ACCESS3resok; + +struct ACCESS3resfail { + post_op_attr obj_attributes; +}; +typedef struct ACCESS3resfail ACCESS3resfail; + +struct ACCESS3res { + nfsstat3 status; + union { + ACCESS3resok resok; + ACCESS3resfail resfail; + } ACCESS3res_u; +}; +typedef struct ACCESS3res ACCESS3res; + +struct READLINK3args { + nfs_fh3 symlink; +}; +typedef struct READLINK3args READLINK3args; + +struct READLINK3resok { + post_op_attr symlink_attributes; + nfspath3 data; +}; +typedef struct READLINK3resok READLINK3resok; + +struct READLINK3resfail { + post_op_attr symlink_attributes; +}; +typedef struct READLINK3resfail READLINK3resfail; + +struct READLINK3res { + nfsstat3 status; + union { + READLINK3resok resok; + READLINK3resfail resfail; + } READLINK3res_u; +}; +typedef struct READLINK3res READLINK3res; + +struct READ3args { + nfs_fh3 file; + offset3 offset; + count3 count; +}; +typedef struct READ3args READ3args; + +struct READ3resok { + post_op_attr file_attributes; + count3 count; + bool_t eof; + struct { + u_int data_len; + char *data_val; + } data; +}; +typedef struct READ3resok READ3resok; + +struct READ3resfail { + post_op_attr file_attributes; +}; +typedef struct READ3resfail READ3resfail; + +struct READ3res { + nfsstat3 status; + union { + READ3resok resok; + READ3resfail resfail; + } READ3res_u; +}; +typedef struct READ3res READ3res; + +enum stable_how { + UNSTABLE = 0, + DATA_SYNC = 1, + FILE_SYNC = 2, +}; +typedef enum stable_how stable_how; + +struct WRITE3args { + nfs_fh3 file; + offset3 offset; + count3 count; + stable_how stable; + struct { + u_int data_len; + char *data_val; + } data; +}; +typedef struct WRITE3args WRITE3args; + +struct WRITE3resok { + wcc_data file_wcc; + count3 count; + stable_how committed; + writeverf3 verf; +}; +typedef struct WRITE3resok WRITE3resok; + +struct WRITE3resfail { + wcc_data file_wcc; +}; +typedef struct WRITE3resfail WRITE3resfail; + +struct WRITE3res { + nfsstat3 status; + union { + WRITE3resok resok; + WRITE3resfail resfail; + } WRITE3res_u; +}; +typedef struct WRITE3res WRITE3res; + +enum createmode3 { + UNCHECKED = 0, + GUARDED = 1, + EXCLUSIVE = 2, +}; +typedef enum createmode3 createmode3; + +struct createhow3 { + createmode3 mode; + union { + sattr3 obj_attributes; + createverf3 verf; + } createhow3_u; +}; +typedef struct createhow3 createhow3; + +struct CREATE3args { + diropargs3 where; + createhow3 how; +}; +typedef struct CREATE3args CREATE3args; + +struct CREATE3resok { + wcc_data dir_wcc; + post_op_fh3 obj; + post_op_attr obj_attributes; +}; +typedef struct CREATE3resok CREATE3resok; + +struct CREATE3resfail { + wcc_data dir_wcc; +}; +typedef struct CREATE3resfail CREATE3resfail; + +struct CREATE3res { + nfsstat3 status; + union { + CREATE3resok resok; + CREATE3resfail resfail; + } CREATE3res_u; +}; +typedef struct CREATE3res CREATE3res; + +struct MKDIR3args { + diropargs3 where; + sattr3 attributes; +}; +typedef struct MKDIR3args MKDIR3args; + +struct MKDIR3resok { + wcc_data dir_wcc; + post_op_fh3 obj; + post_op_attr obj_attributes; +}; +typedef struct MKDIR3resok MKDIR3resok; + +struct MKDIR3resfail { + wcc_data dir_wcc; +}; +typedef struct MKDIR3resfail MKDIR3resfail; + +struct MKDIR3res { + nfsstat3 status; + union { + MKDIR3resok resok; + MKDIR3resfail resfail; + } MKDIR3res_u; +}; +typedef struct MKDIR3res MKDIR3res; + +struct symlinkdata3 { + sattr3 symlink_attributes; + nfspath3 symlink_data; +}; +typedef struct symlinkdata3 symlinkdata3; + +struct SYMLINK3args { + diropargs3 where; + symlinkdata3 symlink; +}; +typedef struct SYMLINK3args SYMLINK3args; + +struct SYMLINK3resok { + wcc_data dir_wcc; + post_op_fh3 obj; + post_op_attr obj_attributes; +}; +typedef struct SYMLINK3resok SYMLINK3resok; + +struct SYMLINK3resfail { + wcc_data dir_wcc; +}; +typedef struct SYMLINK3resfail SYMLINK3resfail; + +struct SYMLINK3res { + nfsstat3 status; + union { + SYMLINK3resok resok; + SYMLINK3resfail resfail; + } SYMLINK3res_u; +}; +typedef struct SYMLINK3res SYMLINK3res; + +struct devicedata3 { + sattr3 dev_attributes; + specdata3 spec; +}; +typedef struct devicedata3 devicedata3; + +struct mknoddata3 { + ftype3 type; + union { + devicedata3 device; + sattr3 pipe_attributes; + } mknoddata3_u; +}; +typedef struct mknoddata3 mknoddata3; + +struct MKNOD3args { + diropargs3 where; + mknoddata3 what; +}; +typedef struct MKNOD3args MKNOD3args; + +struct MKNOD3resok { + wcc_data dir_wcc; + post_op_fh3 obj; + post_op_attr obj_attributes; +}; +typedef struct MKNOD3resok MKNOD3resok; + +struct MKNOD3resfail { + wcc_data dir_wcc; +}; +typedef struct MKNOD3resfail MKNOD3resfail; + +struct MKNOD3res { + nfsstat3 status; + union { + MKNOD3resok resok; + MKNOD3resfail resfail; + } MKNOD3res_u; +}; +typedef struct MKNOD3res MKNOD3res; + +struct REMOVE3args { + diropargs3 object; +}; +typedef struct REMOVE3args REMOVE3args; + +struct REMOVE3resok { + wcc_data dir_wcc; +}; +typedef struct REMOVE3resok REMOVE3resok; + +struct REMOVE3resfail { + wcc_data dir_wcc; +}; +typedef struct REMOVE3resfail REMOVE3resfail; + +struct REMOVE3res { + nfsstat3 status; + union { + REMOVE3resok resok; + REMOVE3resfail resfail; + } REMOVE3res_u; +}; +typedef struct REMOVE3res REMOVE3res; + +struct RMDIR3args { + diropargs3 object; +}; +typedef struct RMDIR3args RMDIR3args; + +struct RMDIR3resok { + wcc_data dir_wcc; +}; +typedef struct RMDIR3resok RMDIR3resok; + +struct RMDIR3resfail { + wcc_data dir_wcc; +}; +typedef struct RMDIR3resfail RMDIR3resfail; + +struct RMDIR3res { + nfsstat3 status; + union { + RMDIR3resok resok; + RMDIR3resfail resfail; + } RMDIR3res_u; +}; +typedef struct RMDIR3res RMDIR3res; + +struct RENAME3args { + diropargs3 from; + diropargs3 to; +}; +typedef struct RENAME3args RENAME3args; + +struct RENAME3resok { + wcc_data fromdir_wcc; + wcc_data todir_wcc; +}; +typedef struct RENAME3resok RENAME3resok; + +struct RENAME3resfail { + wcc_data fromdir_wcc; + wcc_data todir_wcc; +}; +typedef struct RENAME3resfail RENAME3resfail; + +struct RENAME3res { + nfsstat3 status; + union { + RENAME3resok resok; + RENAME3resfail resfail; + } RENAME3res_u; +}; +typedef struct RENAME3res RENAME3res; + +struct LINK3args { + nfs_fh3 file; + diropargs3 link; +}; +typedef struct LINK3args LINK3args; + +struct LINK3resok { + post_op_attr file_attributes; + wcc_data linkdir_wcc; +}; +typedef struct LINK3resok LINK3resok; + +struct LINK3resfail { + post_op_attr file_attributes; + wcc_data linkdir_wcc; +}; +typedef struct LINK3resfail LINK3resfail; + +struct LINK3res { + nfsstat3 status; + union { + LINK3resok resok; + LINK3resfail resfail; + } LINK3res_u; +}; +typedef struct LINK3res LINK3res; + +struct READDIR3args { + nfs_fh3 dir; + cookie3 cookie; + cookieverf3 cookieverf; + count3 count; +}; +typedef struct READDIR3args READDIR3args; + +struct entry3 { + fileid3 fileid; + filename3 name; + cookie3 cookie; + struct entry3 *nextentry; +}; +typedef struct entry3 entry3; + +struct dirlist3 { + entry3 *entries; + bool_t eof; +}; +typedef struct dirlist3 dirlist3; + +struct READDIR3resok { + post_op_attr dir_attributes; + cookieverf3 cookieverf; + dirlist3 reply; +}; +typedef struct READDIR3resok READDIR3resok; + +struct READDIR3resfail { + post_op_attr dir_attributes; +}; +typedef struct READDIR3resfail READDIR3resfail; + +struct READDIR3res { + nfsstat3 status; + union { + READDIR3resok resok; + READDIR3resfail resfail; + } READDIR3res_u; +}; +typedef struct READDIR3res READDIR3res; + +struct READDIRPLUS3args { + nfs_fh3 dir; + cookie3 cookie; + cookieverf3 cookieverf; + count3 dircount; + count3 maxcount; +}; +typedef struct READDIRPLUS3args READDIRPLUS3args; + +struct entryplus3 { + fileid3 fileid; + filename3 name; + cookie3 cookie; + post_op_attr name_attributes; + post_op_fh3 name_handle; + struct entryplus3 *nextentry; +}; +typedef struct entryplus3 entryplus3; + +struct dirlistplus3 { + entryplus3 *entries; + bool_t eof; +}; +typedef struct dirlistplus3 dirlistplus3; + +struct READDIRPLUS3resok { + post_op_attr dir_attributes; + cookieverf3 cookieverf; + dirlistplus3 reply; +}; +typedef struct READDIRPLUS3resok READDIRPLUS3resok; + +struct READDIRPLUS3resfail { + post_op_attr dir_attributes; +}; +typedef struct READDIRPLUS3resfail READDIRPLUS3resfail; + +struct READDIRPLUS3res { + nfsstat3 status; + union { + READDIRPLUS3resok resok; + READDIRPLUS3resfail resfail; + } READDIRPLUS3res_u; +}; +typedef struct READDIRPLUS3res READDIRPLUS3res; + +struct FSSTAT3args { + nfs_fh3 fsroot; +}; +typedef struct FSSTAT3args FSSTAT3args; + +struct FSSTAT3resok { + post_op_attr obj_attributes; + size3 tbytes; + size3 fbytes; + size3 abytes; + size3 tfiles; + size3 ffiles; + size3 afiles; + uint32 invarsec; +}; +typedef struct FSSTAT3resok FSSTAT3resok; + +struct FSSTAT3resfail { + post_op_attr obj_attributes; +}; +typedef struct FSSTAT3resfail FSSTAT3resfail; + +struct FSSTAT3res { + nfsstat3 status; + union { + FSSTAT3resok resok; + FSSTAT3resfail resfail; + } FSSTAT3res_u; +}; +typedef struct FSSTAT3res FSSTAT3res; +#define FSF3_LINK 0x0001 +#define FSF3_SYMLINK 0x0002 +#define FSF3_HOMOGENEOUS 0x0008 +#define FSF3_CANSETTIME 0x0010 + +struct FSINFO3args { + nfs_fh3 fsroot; +}; +typedef struct FSINFO3args FSINFO3args; + +struct FSINFO3resok { + post_op_attr obj_attributes; + uint32 rtmax; + uint32 rtpref; + uint32 rtmult; + uint32 wtmax; + uint32 wtpref; + uint32 wtmult; + uint32 dtpref; + size3 maxfilesize; + nfstime3 time_delta; + uint32 properties; +}; +typedef struct FSINFO3resok FSINFO3resok; + +struct FSINFO3resfail { + post_op_attr obj_attributes; +}; +typedef struct FSINFO3resfail FSINFO3resfail; + +struct FSINFO3res { + nfsstat3 status; + union { + FSINFO3resok resok; + FSINFO3resfail resfail; + } FSINFO3res_u; +}; +typedef struct FSINFO3res FSINFO3res; + +struct PATHCONF3args { + nfs_fh3 object; +}; +typedef struct PATHCONF3args PATHCONF3args; + +struct PATHCONF3resok { + post_op_attr obj_attributes; + uint32 linkmax; + uint32 name_max; + bool_t no_trunc; + bool_t chown_restricted; + bool_t case_insensitive; + bool_t case_preserving; +}; +typedef struct PATHCONF3resok PATHCONF3resok; + +struct PATHCONF3resfail { + post_op_attr obj_attributes; +}; +typedef struct PATHCONF3resfail PATHCONF3resfail; + +struct PATHCONF3res { + nfsstat3 status; + union { + PATHCONF3resok resok; + PATHCONF3resfail resfail; + } PATHCONF3res_u; +}; +typedef struct PATHCONF3res PATHCONF3res; + +struct COMMIT3args { + nfs_fh3 file; + offset3 offset; + count3 count; +}; +typedef struct COMMIT3args COMMIT3args; + +struct COMMIT3resok { + wcc_data file_wcc; + writeverf3 verf; +}; +typedef struct COMMIT3resok COMMIT3resok; + +struct COMMIT3resfail { + wcc_data file_wcc; +}; +typedef struct COMMIT3resfail COMMIT3resfail; + +struct COMMIT3res { + nfsstat3 status; + union { + COMMIT3resok resok; + COMMIT3resfail resfail; + } COMMIT3res_u; +}; +typedef struct COMMIT3res COMMIT3res; + +#define NFS3_PROGRAM 100003 +#define NFS_V3 3 + +#define NFSPROC3_NULL 0 +extern void * nfsproc3_null_3_svc(void *, struct svc_req *); +#define NFSPROC3_GETATTR 1 +extern GETATTR3res * nfsproc3_getattr_3_svc(GETATTR3args *, struct svc_req *); +#define NFSPROC3_SETATTR 2 +extern SETATTR3res * nfsproc3_setattr_3_svc(SETATTR3args *, struct svc_req *); +#define NFSPROC3_LOOKUP 3 +extern LOOKUP3res * nfsproc3_lookup_3_svc(LOOKUP3args *, struct svc_req *); +#define NFSPROC3_ACCESS 4 +extern ACCESS3res * nfsproc3_access_3_svc(ACCESS3args *, struct svc_req *); +#define NFSPROC3_READLINK 5 +extern READLINK3res * nfsproc3_readlink_3_svc(READLINK3args *, struct svc_req *); +#define NFSPROC3_READ 6 +extern READ3res * nfsproc3_read_3_svc(READ3args *, struct svc_req *); +#define NFSPROC3_WRITE 7 +extern WRITE3res * nfsproc3_write_3_svc(WRITE3args *, struct svc_req *); +#define NFSPROC3_CREATE 8 +extern CREATE3res * nfsproc3_create_3_svc(CREATE3args *, struct svc_req *); +#define NFSPROC3_MKDIR 9 +extern MKDIR3res * nfsproc3_mkdir_3_svc(MKDIR3args *, struct svc_req *); +#define NFSPROC3_SYMLINK 10 +extern SYMLINK3res * nfsproc3_symlink_3_svc(SYMLINK3args *, struct svc_req *); +#define NFSPROC3_MKNOD 11 +extern MKNOD3res * nfsproc3_mknod_3_svc(MKNOD3args *, struct svc_req *); +#define NFSPROC3_REMOVE 12 +extern REMOVE3res * nfsproc3_remove_3_svc(REMOVE3args *, struct svc_req *); +#define NFSPROC3_RMDIR 13 +extern RMDIR3res * nfsproc3_rmdir_3_svc(RMDIR3args *, struct svc_req *); +#define NFSPROC3_RENAME 14 +extern RENAME3res * nfsproc3_rename_3_svc(RENAME3args *, struct svc_req *); +#define NFSPROC3_LINK 15 +extern LINK3res * nfsproc3_link_3_svc(LINK3args *, struct svc_req *); +#define NFSPROC3_READDIR 16 +extern READDIR3res * nfsproc3_readdir_3_svc(READDIR3args *, struct svc_req *); +#define NFSPROC3_READDIRPLUS 17 +extern READDIRPLUS3res * nfsproc3_readdirplus_3_svc(READDIRPLUS3args *, struct svc_req *); +#define NFSPROC3_FSSTAT 18 +extern FSSTAT3res * nfsproc3_fsstat_3_svc(FSSTAT3args *, struct svc_req *); +#define NFSPROC3_FSINFO 19 +extern FSINFO3res * nfsproc3_fsinfo_3_svc(FSINFO3args *, struct svc_req *); +#define NFSPROC3_PATHCONF 20 +extern PATHCONF3res * nfsproc3_pathconf_3_svc(PATHCONF3args *, struct svc_req *); +#define NFSPROC3_COMMIT 21 +extern COMMIT3res * nfsproc3_commit_3_svc(COMMIT3args *, struct svc_req *); +extern int nfs3_program_3_freeresult (SVCXPRT *, xdrproc_t, caddr_t); + +#endif /* !_NFS_PROT_H_RPCGEN */ diff --git a/unfs3/password.c b/unfs3/password.c new file mode 100644 index 0000000..868bb4d --- /dev/null +++ b/unfs3/password.c @@ -0,0 +1,116 @@ + +/* + * UNFS3 mount password support routines + * (C) 2004, Peter Astrand + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#ifndef WIN32 +#include +#include +#include /* times */ +#endif /* WIN32 */ +#include +#include /* gettimeofday */ +#include "md5.h" +#include "backend.h" +#include "daemon.h" /* logmsg */ + +#ifndef WIN32 +int gen_nonce(char *nonce) +{ + struct stat st; + struct tms tmsbuf; + md5_state_t state; + unsigned int *arr; + int bytes_read, fd; + + if (((fd = open("/dev/urandom", O_RDONLY)) != -1) + || ((fd = open("/dev/random", O_RDONLY)) != -1)) { + bytes_read = read(fd, nonce, 32); + close(fd); + if (bytes_read == 32) + return 0; + } + + /* No /dev/random; do it by hand */ + arr = (unsigned int *) nonce; + stat("/tmp", &st); + arr[0] = st.st_mtime; + arr[1] = st.st_atime; + arr[2] = st.st_ctime; + arr[3] = times(&tmsbuf); + arr[4] = tmsbuf.tms_cutime; + arr[5] = tmsbuf.tms_cstime; + gettimeofday((struct timeval *) &arr[6], NULL); + + md5_init(&state); + md5_append(&state, (md5_byte_t *) nonce, 32); + md5_finish(&state, (md5_byte_t *) nonce); + return 0; +} +#endif /* WIN32 */ + +static char nibble_as_hexchar(unsigned char c) +{ + if (c <= 9) + return c + '0'; + + return c - 10 + 'a'; +} + +static void hexify(md5_byte_t digest[16], char hexdigest[32]) +{ + int i, j; + + for (i = j = 0; i < 16; i++) { + char c; + + /* The first four bits */ + c = (digest[i] >> 4) & 0xf; + hexdigest[j++] = nibble_as_hexchar(c); + /* The next four bits */ + c = (digest[i] & 0xf); + hexdigest[j++] = nibble_as_hexchar(c); + } +} + +/* Handle mount commands: + * Advance dpath to first slash + * Copy command arguments to arg. +*/ +void mnt_cmd_argument(char **dpath, const char *cmd, char *arg, size_t maxlen) +{ + char *slash; + + *dpath += strlen(cmd); + strncpy(arg, *dpath, maxlen); + arg[maxlen] = '\0'; + + slash = strchr(arg, '/'); + if (slash != NULL) + *slash = '\0'; + + *dpath += strlen(arg); +} + +void otp_digest(char nonce[32], char *password, char hexdigest[32]) +{ + md5_state_t state; + md5_byte_t digest[16]; + + /* Calculate the digest, in the same way as the client did */ + md5_init(&state); + md5_append(&state, (md5_byte_t *) nonce, 32); + md5_append(&state, (md5_byte_t *) password, strlen(password)); + md5_finish(&state, digest); + hexify(digest, hexdigest); +} diff --git a/unfs3/password.h b/unfs3/password.h new file mode 100644 index 0000000..946a6d8 --- /dev/null +++ b/unfs3/password.h @@ -0,0 +1,13 @@ +/* + * UNFS3 mount password support routines + * (C) 2004, Peter Astrand + * see file LICENSE for license details + */ + +int gen_nonce(char *nonce); + +void mnt_cmd_argument(char **dpath, const char *cmd, char *arg, size_t maxlen); + +void otp_digest(char nonce[32], + char *password, + char hexdigest[32]); diff --git a/unfs3/readdir.c b/unfs3/readdir.c new file mode 100644 index 0000000..0e7290c --- /dev/null +++ b/unfs3/readdir.c @@ -0,0 +1,215 @@ + +/* + * UNFS3 readdir routine + * (C) 2004, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nfs.h" +#include "mount.h" +#include "fh.h" +#include "readdir.h" +#include "backend.h" +#include "Config/exports.h" +#include "daemon.h" +#include "error.h" + +/* + * maximum number of entries in readdir results + * + * this is 4096 / 28 (the minimum size of an entry3) + */ +#define MAX_ENTRIES 143 + +/* + * static READDIR3resok size with XDR overhead + * + * 88 bytes attributes, 8 bytes verifier, 4 bytes value_follows for + * first entry, 4 bytes eof flag + */ +#define RESOK_SIZE 104 + +/* + * static entry3 size with XDR overhead + * + * 8 bytes fileid, 4 bytes name length, 8 bytes cookie, 4 byte value_follows + */ +#define ENTRY_SIZE 24 + +/* + * size of a name with XDR overhead + * + * XDR pads to multiple of 4 bytes + */ +#define NAME_SIZE(x) (((strlen((x))+3)/4)*4) + +uint32 directory_hash(const char *path) +{ + backend_dirstream *search; + struct dirent *this; + uint32 hval = 0; + + search = backend_opendir(path); + if (!search) { + return 0; + } + + while ((this = backend_readdir(search)) != NULL) { + hval = fnv1a_32(this->d_name, hval); + } + + backend_closedir(search); + return hval; +} + +/* + * perform a READDIR operation + * + * fh_decomp must be called directly before to fill the stat cache + */ +READDIR3res read_dir(const char *path, cookie3 cookie, cookieverf3 verf, + count3 count) +{ + READDIR3res result; + READDIR3resok resok; + cookie3 upper; + static entry3 entry[MAX_ENTRIES]; + backend_statstruct buf; + int res; + backend_dirstream *search; + struct dirent *this; + count3 i, real_count; + static char obj[NFS_MAXPATHLEN * MAX_ENTRIES]; + char scratch[NFS_MAXPATHLEN]; + + /* check upper part of cookie */ + upper = cookie & 0xFFFFFFFF00000000ULL; + if (cookie != 0 && upper != rcookie) { + /* ignore cookie if unexpected so we restart from the beginning */ + cookie = 0; + } + cookie &= 0xFFFFFFFFULL; + + /* we refuse to return more than 4k from READDIR */ + if (count > 4096) + count = 4096; + + /* account for size of information heading resok structure */ + real_count = RESOK_SIZE; + + /* We are always returning zero as a cookie verifier. One reason for this + is that stat() on Windows seems to return cached st_mtime values, + which gives spurious NFS3ERR_BAD_COOKIEs. Btw, here's what Peter + Staubach has to say about cookie verifiers: + + "From my viewpoint, the cookieverifier was a failed experiment in NFS + Version 3. The semantics were never well understood nor supported by + many local file systems. The Solaris NFS server always returns zeros + in the cookieverifier field." */ + memset(verf, 0, NFS3_COOKIEVERFSIZE); + + search = backend_opendir(path); + if (!search) { + if ((exports_opts & OPT_REMOVABLE) && (export_point(path))) { + /* Removable media export point; probably no media inserted. + Return empty directory. */ + memset(resok.cookieverf, 0, NFS3_COOKIEVERFSIZE); + resok.reply.entries = NULL; + resok.reply.eof = TRUE; + result.status = NFS3_OK; + result.READDIR3res_u.resok = resok; + return result; + } else { + result.status = readdir_err(); + return result; + } + } + + this = backend_readdir(search); + /* We cannot use telldir()/seekdir(), since the value from telldir() is + not valid after closedir(). */ + for (i = 0; i < cookie; i++) + if (this) + this = backend_readdir(search); + + i = 0; + entry[0].name = NULL; + while (this && real_count < count && i < MAX_ENTRIES) { + if (i > 0) + entry[i - 1].nextentry = &entry[i]; + + if (strlen(path) + strlen(this->d_name) + 1 < NFS_MAXPATHLEN) { + + if (strcmp(path, "/") == 0) + sprintf(scratch, "/%s", this->d_name); + else + sprintf(scratch, "%s/%s", path, this->d_name); + + res = backend_lstat(scratch, &buf); + if (res == -1) { + result.status = readdir_err(); + backend_closedir(search); + return result; + } + + strcpy(&obj[i * NFS_MAXPATHLEN], this->d_name); + +#ifdef WIN32 + /* See comment in attr.c:get_post_buf */ + entry[i].fileid = (buf.st_ino >> 32) ^ (buf.st_ino & 0xffffffff); +#else + entry[i].fileid = buf.st_ino; +#endif + entry[i].name = &obj[i * NFS_MAXPATHLEN]; + entry[i].cookie = (cookie + 1 + i) | rcookie; + entry[i].nextentry = NULL; + + /* account for entry size */ + real_count += ENTRY_SIZE + NAME_SIZE(this->d_name); + + /* whoops, overflowed the maximum size */ + if (real_count > count && i > 0) + entry[i - 1].nextentry = NULL; + else { + /* advance to next entry */ + this = backend_readdir(search); + } + + i++; + } else { + result.status = NFS3ERR_IO; + backend_closedir(search); + return result; + } + } + backend_closedir(search); + + if (entry[0].name) + resok.reply.entries = &entry[0]; + else + resok.reply.entries = NULL; + + if (this) + resok.reply.eof = FALSE; + else + resok.reply.eof = TRUE; + + memcpy(resok.cookieverf, verf, NFS3_COOKIEVERFSIZE); + + result.status = NFS3_OK; + result.READDIR3res_u.resok = resok; + + return result; +} diff --git a/unfs3/readdir.h b/unfs3/readdir.h new file mode 100644 index 0000000..3ec78bb --- /dev/null +++ b/unfs3/readdir.h @@ -0,0 +1,14 @@ +/* + * UNFS3 readdir routine + * (C) 2003, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_READDIR_H +#define UNFS3_READDIR_H + +READDIR3res +read_dir(const char *path, cookie3 cookie, cookieverf3 verf, count3 count); +uint32 directory_hash(const char *path); + +#endif diff --git a/unfs3/unfs3.spec b/unfs3/unfs3.spec new file mode 100644 index 0000000..88859f0 --- /dev/null +++ b/unfs3/unfs3.spec @@ -0,0 +1,38 @@ +%define version 0.9.22 +Summary: UNFS3 user-space NFSv3 server +Group: Applications/System +Name: unfs3 +Version: %{version} +Release: 1 +License: BSD +Packager: Pascal Schmidt +Vendor: none +Source: unfs3-%{version}.tar.gz +Buildroot: /tmp/unfs3 + +%prep +%setup + +%build +./configure --enable-cluster --prefix=/usr --mandir=/usr/share/man +make + +%install +[ -n "$RPM_BUILD_ROOT" ] && rm -rf "$RPM_BUILD_ROOT" +make DESTDIR="$RPM_BUILD_ROOT" install install-init + +%clean +[ -n "$RPM_BUILD_ROOT" ] && rm -rf "$RPM_BUILD_ROOT" + +%description +UNFS3 is a user-space implementation of the NFS (Network File System) +version 3 server specification. It provides a daemon that supports both +the MOUNT and NFS protocol. + +%files +%attr ( -, root, root) %doc CREDITS README README.nfsroot LICENSE NEWS contrib doc +%attr (755, root, root) /usr/sbin/unfsd +%attr (755, root, root) /etc/init.d/unfsd +%attr (644, root, root) %doc /usr/share/man/man7/tags.7.gz +%attr (644, root, root) %doc /usr/share/man/man8/unfsd.8.gz + diff --git a/unfs3/unfsd.8 b/unfs3/unfsd.8 new file mode 100644 index 0000000..eb7dd20 --- /dev/null +++ b/unfs3/unfsd.8 @@ -0,0 +1,394 @@ +.\" +.\" (C) 2008, Pascal Schmidt +.\" +.TH unfsd 8 "05 Jan 2008" +.SH NAME +unfsd \- NFS server process +.SH SYNOPSIS +.BI "/usr/sbin/unfsd [" options "]" +.SH DESCRIPTION +The +.B unfsd +program implements the MOUNT and NFS version 3 protocols. It listens for +client requests, performs them on the local filesystem of the server, and +then returns the results of the operations to the clients. +.P +At startup, +.B unfsd +reads the exports file, +.I /etc/exports +by default, to find out which directories are available to clients +and what options are in effect (see +.B EXPORTS FILE +section below for syntax and possible options). +.P +Normally, +.B unfsd +should be run as the +.B root +user. It will then switch its effective +user and group id to the numbers listed in incoming NFS requests. This +means filesystem operations will be performed as if done by a local +user with the same ids. If the incoming request is for user or group +id 0 (meaning +.BR root "), " unfsd +will switch to the user and group id of the +.B nobody +user before performing filesystem operations (this is known as +.BR "root squashing" ")." +If the user +.B nobody +does not exist on the system, a user and group id of 65534 will be used. +This behavior can be modified by use of the +.B no_root_squash +and +.B all_squash +options in the exports file as well as the +.B anonuid +and +.B anongid +options on a per-share basis. +.P +If +.B unfsd +is running as a normal unprivileged user, no switching of the effective +user and group id will take place. Instead, all filesystem operations +will be performed with the id of the user running +.BR unfsd . +.SH RESTRICTIONS +Some NFS clients may attempt to perform operations that +.B unfsd +cannot fully support. +.TP +.B "Object Creation" +When creating filesystem objects, it is only possible to specify the +initial mode for the object. The initial user and group ownership, +object size, and timestamps cannot be specified and will be set to +default values. +.TP +.B "File Locking" +The network lock manager (NLM) protocol is not supported. This means that +clients may have to mount with special mount options, disabling locking +on the mounted NFS volume (nolock for Linux clients). +.SH OPTIONS +.TP +.B \-h +Display a short option summary. +.TP +.BI "\-e " "\" +Use the given file as the exports file, instead of using +.IR /etc/exports . +Note that the file needs to be specified using an absolute path. +.TP +.BI "\-i " "\" +Use the given file as pid file. When the daemon starts up, it will +write its pid (process id) to the given file. Upon exit, the daemon +will remove the file. Failure to create or remove the pid file is +not considered fatal and only reported to syslog. +.TP +.B \-u +Use an unprivileged port for NFS and MOUNT service. Normally, +.B unfsd +will use port number 2049, which is the standard port for NFS. +When this option is in effect, arbitrary ports chosen by the RPC library +will be used. You may need to use this option when running +.B unfsd +from a normal user account. +.TP +.BI "\-n " "\" +Use the specified port for the NFS service. +.TP +.BI "\-m " "\" +Use the specified port for the MOUNT service. The default is to +use port number 2049, the same as for the NFS service. You can use +the same port for both services if you want. +.TP +.B \-t +TCP only operation. By default, +.B unfsd +provides its services to clients using either UDP or TCP as communications +protocol. When this option is present, only TCP connections are +serviced. +.TP +.B \-p +Do not register with the portmapper. This will prevent other hosts from +finding out the port numbers used for the MOUNT and NFS services by +querying the portmap daemon. Clients +will need to manually specify the port numbers to use (on Linux clients, +use the +.BR mountport " and " port +mount options). +.TP +.B \-c +Enable cluster extensions. This feature is only available when +.B unfsd +was compiled with cluster support. When this option is enabled, so-called +tagged files are handled differently from normal files, making it possible +to serve different file contents to different clients for the same filename. +See +.BR tags (7) +for a description of tagged files. This option causes a performance hit. +.TP +.BI "\-C" "\ " +Limit the use of cluster extensions to a list of colon-seperated +directories. When this option is present, the performance hit caused by +clustering extensions only applies to the listed directories and their +subdirectories. +.TP +.B \-s +Single user mode; activate basic uid translation. This option is +useful when the server and client are using different user and group +ids. All requests from the client will be served from the user id that started +.B unfsd, +no user id switching will take place (even if unfsd was started by +root). +Ownership is reported as follows: files belonging to the user id +running +.B unfsd +will look as if they are owned by the client's user. Other files will +look as if they are owned by root. The same principle applies to +group ownership. +.TP +.B \-b +Enable brute force file searching. Normally, when you rename a file +across several directories on an NFS volume, the filehandle for that +file becomes stale. When this option is enabled, +.B unfsd +will attempt a recursive search on the relevant server filesystem to +find the file referenced by the filehandle. This can have a huge +performance impact as this will also happen for files that were +really deleted (by another NFS client) instead of moved, and cannot be found. +.TP +.B \-l +Bind to interface with specified address. The default is to bind to +all local interfaces. +.TP +.B \-d +Debug mode. When this option is present, +.B unfsd +will not fork into the background at startup, and all messages that +would normally go to the system log go to stdout instead. +.TP +.B \-r +Report unreadable executables as readable. This applies both to +returned attributes and ACCESS requests. Please note that READ +requests for unreadable executables are always allowed, if +.B unfsd +is running as root, regardless of this option. +.TP +.B \-T +Test exports file and exit. When this option is given, +.B unfsd +will try to parse the exports file and exit with status 0 if this +is successful. If there is a syntax error in the exports file, +a message is printed on standard error and +.B unfsd +exits with status 1. +.SH SIGNALS +.TP +.BR "SIGTERM " "and " SIGINT +will cause +.B unfsd +to unregister itself from the portmapper and exit. +.TP +.B SIGHUP +will cause +.B unfsd +to re-read its configuration data. Currently, this means the program +will query the +.I passwd +database to find out the user and group id of user +.BR nobody . +.B unfsd +will also attempt to reload the exports file. If the exports file +contains errors, +.B unfsd +sends a warning message to the system log and nothing is exported until +the situation is corrected and another +.B SIGHUP +is sent. +.TP +.B SIGUSR1 +will cause +.B unfsd +to output statistics about its filehandle and file descriptor cache +to the system log. For the filehandle cache, it will output the number +of filehandles in the cache, the total number of cache accesses, and the +number of hits and misses. For the file descriptor cache, it will output +the number of currently held open READ and WRITE file descriptors. +.SH "EXPORTS FILE" +The exports file, +.I /etc/exports +by default, determines which directories on the server can be accessed +from NFS clients. An example: + +.nf +# sample NFS exports file +/home trusted(rw,no_root_squash) (ro) +"/with spaces" weirdo +/usr 1.2.3.4(rw) 192.168.2.0/24(ro,all_squash) +/home/foo bar(rw) 10.0.0.0/255.0.0.0(root_squash) +/home/joe joes_pc(anonuid=1100,anongid=1100,rw,all_squash) +.fi + +Comments start with a # character and cause the rest of the line to be +ignored. Extremely long exports can be split across multiple lines by +escaping the intermediate newlines with a backslash character. +.P +Each line starts with a directory that is to be exported. If +the directory name contains whitespace, it must be enclosed in double +quotes. To the right of the directory name, a list of client +specifications can be given. If this list is missing, the directory +is exported to everyone, using default options +.RB ( ro " and " root_squash ")." +.P +If the directory name contains symbolic links, they are expanded. This +means that you have to force +.B unfsd +to reload the exports file if the symlinks happen to change. +.P +Clients can be specified using either a hostname, an IP address, or +an IP network. Networks can be given by specifying the number of leading 1 +bits in the netmask or by giving the full netmask. If the hostname is +empty, the directory is exported to everyone. +.P +Options can follow a client specification and have to be enclosed +in parenthesis, with the opening paren directly following the client +name or address. If no options are given, +.B ro +and +.B root_squash +are enabled by default. The following options are supported by +.BR unfsd : +.TP +.B root_squash +Enable root squashing, mapping all NFS request done with a user id of +0 to the user id of the +.B nobody +user. This option is enabled by default. +.TP +.B no_root_squash +Disable root squashing. When this option is present, NFS requests done +with a user id of 0 will be done as the +.B root +user of the server, effectively disabling all permissions checks. +.TP +.B all_squash +Squash all users. When this option is present, all NFS requests will +be done as the +.B nobody +user of the server. +.TP +.B no_all_squash +Don't squash all users. This option is enabled by default. +.TP +.B rw +Allow read and write access on the exported directory. When this option +is present, clients are allowed to modify files and directories on +the server. +.TP +.B ro +Allow only read access on the exported directory. When this option +is present, clients are not allowed to modify files and directories +on the server. This option is enabled by default. +.TP +.B anonuid/anongid +Sets the uid and gid for anonymous mounts for this share - by default the +uid for nobody will be used, but using these options you can change this +on a per-share basis. +.TP +.B secure +Allow only mount requests coming from a source port below 1024. Using +these ports requires super-user privileges on many operating systems. +This option is enabled by default. +.TP +.B insecure +Allow mount requests coming from any source port. +.TP +.B removable +Consider this directory to be on a removable medium. When this option +is present, +.B unfsd +will not keep files open across multiple read or write requests. This +allows unmounting of the underlying filesystem on the server at any time. +Also, +.B unfsd +will not require that the exported path exists at startup or mount +time. If the path does not exist, an empty directory will be presented +to the client. This is useful for exporting mount points handled by +autofs. +.TP +.B fixed +Consider this directory to be on a fixed medium. This options is enabled +by default and allows +.B unfsd +to keep files open between multiple read or write requests. +.TP +.B password= +To be able to mount this export, the specified password is +required. The password needs be given in the mount request, +as in "mount yourhost:@password:gazonk/tmp /mnt". One time passwords +are also supported. When using passwords, the file handles +will include a hash of the password. This means that +.B if you change the password, all clients will need to remount this export. +See the file "doc/passwords.txt" in the source for more information. +.PP +If options not present on this list are encountered by +.BR unfsd , +they are silently ignored. +.SH BUGS +There are a few possible race conditions with other processes on the +server. They can happen if +.B unfsd +is performing an operation on a filesystem object while another +process is simultaneously first (a) removing the object and then (b) +creating a new object of the same name. If this happens, +.B unfsd +will attempt to perform the operation on the wrong, new object. +The time window in which this can happen is small. +.PP +When a client does a CREATE EXCLUSIVE procedure call, +.B unfsd +stores the verifier data in the mtime and atime attributes of the +created file. Malicious processes on the server could manipulate +those attributes, breaking the semantics of the exclusive create +operation. A process attempting to do so would need to be able +to see the NFS network traffic. +.PP +unfsd always uses the "nohide" semantics, which means that clients +will see all file systems mounted below the exported path. However, +some NFS clients do not cope well with this situation as, for +instance, it is then possible for two files in the one apparent +filesystem to have the same inode number. To avoid this, make sure +that the client mounts each exported file system. +.PP +Due to the way +.B unfsd +operates, it needs execute (lookup) and read permission on all directories +from the root directory all the way up to exported directories. +For example, if +.I /usr/share +is exported, +.B unfsd +is going to need permission for +.IR / ", " /usr ", and " /usr/share . +Since root squashing can be in effect, +.B unfsd +may run as the nobody user, which normally means having to grant +execute (lookup) and read permission for everybody on the server. +In the above example, +.B unfsd +also needs permission to access +.IR /usr/share/.. , +which can be different from +.I /usr +for some special setups (for example when using bind mounts under +Linux). +.SH FILES +.TP 20 +.I /etc/exports +Default exports file. +.SH AUTHOR +Pascal Schmidt +.SH "SEE ALSO" +.BR tags (7) diff --git a/unfs3/unfsd.init b/unfs3/unfsd.init new file mode 100755 index 0000000..0f66d2a --- /dev/null +++ b/unfs3/unfsd.init @@ -0,0 +1,71 @@ +#!/bin/bash +# -*- mode: shell-script; coding: UTF-8 -*- +# +# chkconfig: 235 99 10 +# description: Start or stop the unfs3 server +# +### BEGIN INIT INFO +# Provides: unfsd +# Required-Start: $network +# Required-Stop: $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Description: Start or stop the unfs3 server +### END INIT INFO + +description="unfs3 NFS server" +lockfile="/var/lock/subsys/unfsd" +pidfile="/var/run/unfsd.pid" + + +case "$1" in + 'start') + echo "Starting" ${description} + /usr/sbin/unfsd -i ${pidfile} + RETVAL=$? + if [ "${RETVAL}" = "0" ]; then + touch ${lockfile} >/dev/null 2>&1 + fi + ;; + 'stop') + echo "Shutting down" ${description} + if [ -s ${pidfile} ]; then + pid=`cat ${pidfile}` + kill -TERM ${pid} 2>/dev/null + sleep 2 + if kill -0 ${pid} 2>/dev/null; then + kill -KILL ${pid} + fi + fi + rm -f ${lockfile} ${pidfile} + ;; + 'status') + if [ -s ${pidfile} ]; then + pid=`cat ${pidfile}` + if kill -0 ${pid} 2>/dev/null; then + echo "${description} (pid ${pid}) is running" + RETVAL=0 + else + echo "${description} is stopped" + RETVAL=1 + fi + else + echo "${description} is stopped" + RETVAL=1 + fi + ;; + 'restart') + /etc/init.d/unfsd stop && /etc/init.d/unfsd start + RETVAL=$? + ;; + 'condrestart') + [ -f /var/lock/subsys/unfsd ] && /etc/init.d/unfsd stop && /etc/init.d/unfsd start + RETVAL=$? + ;; + *) + echo "Usage: $0 {start|stop|restart|condrestart|status}" + RETVAL=1 + ;; +esac +exit $RETVAL + diff --git a/unfs3/user.c b/unfs3/user.c new file mode 100644 index 0000000..241da1e --- /dev/null +++ b/unfs3/user.c @@ -0,0 +1,293 @@ + +/* + * UNFS3 user and group id handling + * (C) 2003, Pascal Schmidt + * see file LICENSE for license details + */ + +#include "config.h" + +#ifndef WIN32 +#include +#include +#include +#include +#endif /* WIN32 */ +#include +#include +#include +#include + +#include "nfs.h" +#include "mount.h" +#include "daemon.h" +#include "user.h" +#include "backend.h" +#include "Config/exports.h" + +/* user and group id we squash to */ +static uid_t squash_uid = 65534; +static gid_t squash_gid = 65534; + +/* whether we can use seteuid/setegid */ +static int can_switch = TRUE; + +/* + * initialize group and user id used for squashing + */ +void get_squash_ids(void) +{ + backend_passwdstruct *passwd; + + if (can_switch) { + passwd = backend_getpwnam("nobody"); + if (passwd) { + squash_uid = passwd->pw_uid; + squash_gid = passwd->pw_gid; + } else { + squash_uid = 65534; + squash_gid = 65534; + } + } +} + +/* + * mangle an id + */ +static int mangle(int id, int squash) +{ + if (!can_switch || (exports_opts & OPT_ALL_SQUASH)) + return squash; + else if (exports_opts & OPT_NO_ROOT_SQUASH) + return id; + else if (id == 0) + return squash; + else + return id; +} + +/* + * Mangle a given user id according to current settings + */ +int mangle_uid(int id) +{ + int squash = squash_uid; + + if (exports_anonuid() != ANON_NOTSPECIAL) + squash = exports_anonuid(); + + return mangle(id, squash); +} + +/* + * Mangle a given group id according to current settings + */ +int mangle_gid(int id) +{ + int squash = squash_gid; + + if (exports_anongid() != ANON_NOTSPECIAL) + squash = exports_anongid(); + + return mangle(id, squash); +} + +/* + * return user id of a request + */ +int get_uid(struct svc_req *req) +{ + struct authunix_parms *auth = (void *) req->rq_clntcred; + int squash = squash_uid; + + if (exports_anonuid() != ANON_NOTSPECIAL) + squash = exports_anonuid(); + + if (req->rq_cred.oa_flavor == AUTH_UNIX) + return mangle(auth->aup_uid, squash); + else + return squash; /* fallback if no uid given */ +} + +/* + * return group id of a request + */ +static int get_gid(struct svc_req *req) +{ + struct authunix_parms *auth = (void *) req->rq_clntcred; + int squash = squash_gid; + + if (exports_anongid() != ANON_NOTSPECIAL) + squash = exports_anongid(); + + if (req->rq_cred.oa_flavor == AUTH_UNIX) + return mangle(auth->aup_gid, squash); + else + return squash; /* fallback if no gid given */ +} + +/* + * check whether a request comes from a given user id + */ +int is_owner(int owner, struct svc_req *req) +{ + return (int) (owner == get_uid(req)); +} + +/* + * check if a request comes from somebody who has a given group id + */ +int has_group(int group, struct svc_req *req) +{ + struct authunix_parms *auth = (void *) req->rq_clntcred; + unsigned int i; + + if (req->rq_cred.oa_flavor == AUTH_UNIX) { + if (mangle(auth->aup_gid, squash_gid) == group) + return TRUE; + + /* search groups */ + for (i = 0; i < auth->aup_len; i++) + if (mangle(auth->aup_gids[i], squash_gid) == group) + return TRUE; + } + + return FALSE; +} + +/* + * switch to root + */ +void switch_to_root() +{ + if (!can_switch) + return; + + backend_setegid(0); + backend_seteuid(0); +} + +/* + * switch auxiliary group ids + */ +static int switch_groups(struct svc_req *req) +{ + struct authunix_parms *auth = (void *) req->rq_clntcred; + unsigned int i, max; + + max = (auth->aup_len <= 32) ? auth->aup_len : 32; + + for (i = 0; i < max; ++i) { + auth->aup_gids[i] = mangle(auth->aup_gids[i], squash_gid); + } + + return backend_setgroups(max, auth->aup_gids); +} + +/* + * switch user and group id to values listed in request + */ +void switch_user(struct svc_req *req) +{ + int uid, gid, aid; + + if (!can_switch) + return; + + if (opt_singleuser || (backend_getuid() != 0)) { + /* + * have uid/gid functions behave correctly by squashing + * all user and group ids to the current values + * + * otherwise ACCESS would malfunction + */ + squash_uid = backend_getuid(); + squash_gid = backend_getgid(); + + can_switch = FALSE; + return; + } + + backend_setegid(0); + backend_seteuid(0); + gid = backend_setegid(get_gid(req)); + aid = switch_groups(req); + uid = backend_seteuid(get_uid(req)); + + if (uid == -1 || gid == -1 || aid == -1) { + logmsg(LOG_EMERG, "euid/egid switching failed, aborting"); + daemon_exit(CRISIS); + } +} + +/* + * re-switch to root for reading executable files + */ +void read_executable(struct svc_req *req, backend_statstruct buf) +{ + int have_exec = 0; + + if (is_owner(buf.st_uid, req)) { + if (!(buf.st_mode & S_IRUSR) && (buf.st_mode & S_IXUSR)) + have_exec = 1; + } else if (has_group(buf.st_gid, req)) { + if (!(buf.st_mode & S_IRGRP) && (buf.st_mode & S_IXGRP)) + have_exec = 1; + } else { + if (!(buf.st_mode & S_IROTH) && (buf.st_mode & S_IXOTH)) + have_exec = 1; + } + + if (have_exec) { + backend_setegid(0); + backend_seteuid(0); + } +} + +/* + * re-switch to root for reading owned file + */ +void read_by_owner(struct svc_req *req, backend_statstruct buf) +{ + int have_owner = 0; + int have_read = 0; + + have_owner = is_owner(buf.st_uid, req); + + if (have_owner && (buf.st_mode & S_IRUSR)) { + have_read = 1; + } else if (has_group(buf.st_gid, req) && (buf.st_mode & S_IRGRP)) { + have_read = 1; + } else if (buf.st_mode & S_IROTH) { + have_read = 1; + } + + if (have_owner && !have_read) { + backend_setegid(0); + backend_seteuid(0); + } +} + +/* + * re-switch to root for writing owned file + */ +void write_by_owner(struct svc_req *req, backend_statstruct buf) +{ + int have_owner = 0; + int have_write = 0; + + have_owner = is_owner(buf.st_uid, req); + + if (have_owner && (buf.st_mode & S_IWUSR)) { + have_write = 1; + } else if (has_group(buf.st_gid, req) && (buf.st_mode & S_IWGRP)) { + have_write = 1; + } else if (buf.st_mode & S_IWOTH) { + have_write = 1; + } + + if (have_owner && !have_write) { + backend_setegid(0); + backend_seteuid(0); + } +} diff --git a/unfs3/user.h b/unfs3/user.h new file mode 100644 index 0000000..0109d25 --- /dev/null +++ b/unfs3/user.h @@ -0,0 +1,29 @@ +/* + * UNFS3 user and group id handling + * (C) 2003, Pascal Schmidt + * see file LICENSE for license details + */ + +#ifndef UNFS3_USER_H +#define UNFS3_USER_H + +#include "backend.h" + +int get_uid(struct svc_req *req); + +int mangle_uid(int id); +int mangle_gid(int id); + +int is_owner(int owner, struct svc_req *req); +int has_group(int group, struct svc_req *req); + +void get_squash_ids(void); + +void switch_to_root(); +void switch_user(struct svc_req *req); + +void read_executable(struct svc_req *req, backend_statstruct buf); +void read_by_owner(struct svc_req *req, backend_statstruct buf); +void write_by_owner(struct svc_req *req, backend_statstruct buf); + +#endif diff --git a/unfs3/winsupport.c b/unfs3/winsupport.c new file mode 100644 index 0000000..15c37b0 --- /dev/null +++ b/unfs3/winsupport.c @@ -0,0 +1,1062 @@ + +/* + * unfs3 Windows compatibility layer + * Copyright 2006 Peter Åstrand for Cendio AB + * see file LICENSE for license details + */ + +#ifdef WIN32 +#define _WIN32_WINDOWS 0x0410 /* We require Windows 98 or later For + GetLongPathName */ +#include +#include +#include "winsupport.h" +#include "Config/exports.h" +#include "daemon.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_NUM_DRIVES 26 +#define FT70SEC 11644473600LL /* seconds between 1601-01-01 and + 1970-01-01 */ +#define FT80SEC 315529200 /* seconds between 1970-01-01 and + 1980-01-01 */ + +#define wsizeof(x) (sizeof(x)/sizeof(wchar_t)) + +typedef struct _fdname { + int fd; + char *name; + struct _fdname *next; +} fdname; + +static fdname *fdnames = NULL; + +static char *get_fdname(int fd) +{ + fdname *fn; + + for (fn = fdnames; fn; fn = fn->next) { + if (fn->fd == fd) { + return fn->name; + break; + } + } + + assert(0); + return NULL; +} + +static int add_fdname(int fd, const char *name) +{ + fdname *fn; + + fn = malloc(sizeof(fdname)); + if (!fn) { + logmsg(LOG_CRIT, "add_mount: Unable to allocate memory"); + return -1; + } + + fn->fd = fd; + fn->name = strdup(name); + fn->next = fdnames; + fdnames = fn; + + return fd; +} + +static void remove_fdname(int fd) +{ + fdname *fn, **prevnext = &fdnames; + + for (fn = fdnames; fn; fn = fn->next) { + if (fn->fd == fd) { + *prevnext = fn->next; + free(fn->name); + free(fn); + break; + } + prevnext = &fn->next; + } +} + +/* + * The following UTF-8 validation is borrowed from + * ftp://ftp.unicode.org/Public/PROGRAMS/CVTUTF/ConvertUTF.c. + */ + +/* + * Copyright 2001-2004 Unicode, Inc. + * + * Disclaimer + * + * This source code is provided as is by Unicode, Inc. No claims are + * made as to fitness for any particular purpose. No warranties of any + * kind are expressed or implied. The recipient agrees to determine + * applicability of information provided. If this file has been + * purchased on magnetic or optical media from Unicode, Inc., the + * sole remedy for any claim will be exchange of defective media + * within 90 days of receipt. + * + * Limitations on Rights to Redistribute This Code + * + * Unicode, Inc. hereby grants the right to freely use the information + * supplied in this file in the creation of products supporting the + * Unicode Standard, and to make copies of this file in any form + * for internal or external distribution as long as this notice + * remains attached. + */ + +/* + * Index into the table below with the first byte of a UTF-8 sequence to + * get the number of trailing bytes that are supposed to follow it. + * Note that *legal* UTF-8 values can't have 4 or 5-bytes. The table is + * left as-is for anyone who may want to do such conversion, which was + * allowed in earlier algorithms. + */ +static const char trailingBytesForUTF8[256] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 +}; + +/* + * Utility routine to tell whether a sequence of bytes is legal UTF-8. + * This must be called with the length pre-determined by the first byte. + * If not calling this from ConvertUTF8to*, then the length can be set by: + * length = trailingBytesForUTF8[*source]+1; + * and the sequence is illegal right away if there aren't that many bytes + * available. + * If presented with a length > 4, this returns 0. The Unicode + * definition of UTF-8 goes up to 4-byte sequences. + */ + +static int isLegalUTF8(const unsigned char *source, int length) +{ + unsigned char a; + const unsigned char *srcptr = source + length; + + switch (length) { + default: + return 0; + /* Everything else falls through when "1"... */ + case 4: + if ((a = (*--srcptr)) < 0x80 || a > 0xBF) + return 0; + case 3: + if ((a = (*--srcptr)) < 0x80 || a > 0xBF) + return 0; + case 2: + if ((a = (*--srcptr)) > 0xBF) + return 0; + + switch (*source) { + /* no fall-through in this inner switch */ + case 0xE0: + if (a < 0xA0) + return 0; + break; + case 0xED: + if (a > 0x9F) + return 0; + break; + case 0xF0: + if (a < 0x90) + return 0; + break; + case 0xF4: + if (a > 0x8F) + return 0; + break; + default: + if (a < 0x80) + return 0; + } + + case 1: + if (*source >= 0x80 && *source < 0xC2) + return 0; + } + if (*source > 0xF4) + return 0; + return 1; +} + +/* End of code borrowed from ConvertUTF.c */ + +int isLegalUTF8String(const unsigned char *source) +{ + const unsigned char *seq, *sourceend; + int seqlen; + + sourceend = source + strlen(source); + seq = source; + + while (seq < sourceend) { + seqlen = trailingBytesForUTF8[*seq] + 1; + if (!isLegalUTF8(seq, seqlen)) + return 0; + seq += seqlen; + } + + return 1; +} + +/* Translate an internal representation of a path (like /c/home) to + a Windows path (like c:\home) */ +static wchar_t *intpath2winpath(const char *intpath) +{ + wchar_t *winpath; + int winpath_len; + wchar_t *slash; + const char *lastrootslash; + wchar_t *lastslash; + size_t intlen; + + /* Verify that input is valid UTF-8. We cannot use MB_ERR_INVALID_CHARS + to MultiByteToWideChar, since it's only available in late versions of + Windows. */ + if (!isLegalUTF8String(intpath)) { + logmsg(LOG_CRIT, "intpath2winpath: Illegal UTF-8 string:%s", intpath); + return NULL; + } + + /* Skip over multiple root slashes for paths like ///home/john */ + lastrootslash = intpath; + while (*lastrootslash == '/') + lastrootslash++; + if (lastrootslash != intpath) + lastrootslash--; + + intlen = strlen(lastrootslash); + /* One extra for /c -> c:\ */ + winpath_len = sizeof(wchar_t) * (intlen + 2); + winpath = malloc(winpath_len); + if (!winpath) { + logmsg(LOG_CRIT, "intpath2winpath: Unable to allocate memory"); + return NULL; + } + + if (!MultiByteToWideChar + (CP_UTF8, 0, lastrootslash, -1, winpath, winpath_len)) { + logmsg(LOG_CRIT, "intpath2winpath: MultiByteToWideChar failed"); + return NULL; + } + + /* If path ends with /.., chop of the last component. Eventually, we + might want to eliminate all occurances of .. */ + lastslash = wcsrchr(winpath, '/'); + if (!wcscmp(lastslash, L"/..")) { + *lastslash = '\0'; + lastslash = wcsrchr(winpath, '/'); + *lastslash = '\0'; + } + + /* Translate /x -> x:/ and /x/something -> x:/something */ + if ((winpath[0] == '/') && winpath[1]) { + switch (winpath[2]) { + case '\0': + winpath[2] = '/'; + winpath[3] = '\0'; + /* fall through */ + + case '/': + winpath[0] = winpath[1]; + winpath[1] = ':'; + break; + + default: + break; + } + } + + while ((slash = wcschr(winpath, '/')) != NULL) { + *slash = '\\'; + } + + return winpath; +} + +int win_seteuid(U(uid_t euid)) +{ + return 0; +} + +int win_setegid(U(gid_t egid)) +{ + return 0; +} + +int win_truncate(const char *path, off_t length) +{ + int fd, ret, saved_errno; + + fd = win_open(path, O_WRONLY); + if (fd < 0) + return -1; + ret = chsize(fd, length); + saved_errno = errno; + win_close(fd); + errno = saved_errno; + + return ret; +} + +int win_chown(U(const char *path), U(uid_t owner), U(gid_t group)) +{ + errno = EINVAL; + return -1; +} + +int win_fchown(U(int fd), U(uid_t owner), U(gid_t group)) +{ + errno = EINVAL; + return -1; +} + +int win_fchmod(int fildes, mode_t mode) +{ + wchar_t *winpath; + int ret; + + winpath = intpath2winpath(get_fdname(fildes)); + if (!winpath) { + errno = EINVAL; + return -1; + } + + ret = _wchmod(winpath, mode); + free(winpath); + return ret; +} + +int inet_aton(const char *cp, struct in_addr *addr) +{ + addr->s_addr = inet_addr(cp); + return (addr->s_addr == INADDR_NONE) ? 0 : 1; +} + +/* + If you need a good laugh, take a look at the "Suggested Interix + replacement" at: + http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnucmg/html/UCMGch10.asp +*/ +ssize_t pread(int fd, void *buf, size_t count, off_t offset) +{ + ssize_t size; + off_t ret; + + if ((ret = lseek(fd, offset, SEEK_SET)) < 0) + return -1; + size = read(fd, buf, count); + return size; +} + +ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset) +{ + ssize_t size; + off_t ret; + HANDLE h; + FILETIME ft; + SYSTEMTIME st; + ULARGE_INTEGER fti; + + if ((ret = lseek(fd, offset, SEEK_SET)) < 0) + return -1; + size = write(fd, buf, count); + + /* Since we are using the CreationTime attribute as "ctime", we need to + update it. From RFC1813: "Writing to the file changes the ctime in + addition to the mtime." */ + h = (HANDLE) _get_osfhandle(fd); + GetSystemTime(&st); + SystemTimeToFileTime(&st, &ft); + /* Ceil up to nearest even second */ + fti.LowPart = ft.dwLowDateTime; + fti.HighPart = ft.dwHighDateTime; + fti.QuadPart = ((fti.QuadPart + 20000000 - 1) / 20000000) * 20000000; + ft.dwLowDateTime = fti.LowPart; + ft.dwHighDateTime = fti.HighPart; + if (!SetFileTime(h, &ft, NULL, NULL)) { + fprintf(stderr, + "warning: pwrite: SetFileTime failed with error %ld\n", + GetLastError()); + } + + return size; +} + +void syslog(U(int priority), U(const char *format), ...) +{ + assert(0); +} + +int win_init() +{ + WORD winsock_ver; + WSADATA wsadata; + + /* Set up locale, so that string compares works correctly */ + setlocale(LC_ALL, ""); + + /* Verify that -s is used */ + if (!opt_singleuser) { + fprintf(stderr, "Single-user mode is required on this platform.\n"); + exit(1); + } + + /* Verify that -d is used */ + if (opt_detach) { + fprintf(stderr, + "Foreground (debug) mode is required on this platform.\n"); + exit(1); + } + + /* init winsock */ + winsock_ver = MAKEWORD(1, 1); + if (WSAStartup(winsock_ver, &wsadata)) { + fprintf(stderr, "Unable to initialise WinSock\n"); + exit(1); + } + if (LOBYTE(wsadata.wVersion) != 1 || HIBYTE(wsadata.wVersion) != 1) { + fprintf(stderr, "WinSock version is incompatible with 1.1\n"); + WSACleanup(); + exit(1); + } + + /* disable error popups, for example from drives not ready */ + SetErrorMode(SEM_FAILCRITICALERRORS); + + return 0; +} + +void win_shutdown() +{ + WSACleanup(); +} + +/* Wrapper for Windows stat function, which provides + st_dev and st_ino. These are calculated as follows: + + st_dev is set to the drive number (0=A 1=B ...). Our virtual root + "/" gets a st_dev of 0xff. + + st_ino is hashed from the full file path. Each half produces a 32 + bit hash. These are concatenated to a 64 bit value. The risk that + st_ino is the same for two files on the system is, if I'm not + mistaken, b=pigeon(2**32, f)**2. For f=1000, b=1e-08. By using a 64 + bit hash function this risk can be lowered. Possible future + enhancement. + + pigeon() can be calculated in Python with: + + def pigeon(m, n): + res = 1.0 + for i in range(m - n + 1, m): + res = res * i / m + return 1 - res +*/ +int win_stat(const char *file_name, backend_statstruct * buf) +{ + wchar_t *winpath; + int ret; + wchar_t pathbuf[4096]; + int retval; + size_t namelen; + wchar_t *splitpoint; + char savedchar; + struct _stat win_statbuf; + + /* Special case: Our top-level virtual root, containing each drive + represented as a directory. Compare with "My Computer" etc. This + virtual root has a hardcoded hash value of 1, to simplify debugging + etc. */ + if (!strcmp(file_name, "/")) { + buf->st_mode = S_IFDIR | S_IRUSR | S_IWUSR; + buf->st_nlink = MAX_NUM_DRIVES + 3; /* 3 extra for: . .. / */ + buf->st_uid = 1; + buf->st_gid = 1; + buf->st_rdev = 0; + buf->st_size = 4096; + buf->st_atime = 0; + buf->st_mtime = 0; + buf->st_ctime = 0; + buf->st_dev = 0xff; + buf->st_ino = 1; + return 0; + } + + winpath = intpath2winpath(file_name); + if (!winpath) { + errno = EINVAL; + return -1; + } + + ret = _wstat(winpath, &win_statbuf); + if (ret < 0) { + free(winpath); + return ret; + } + + /* Copy values to our struct */ + buf->st_mode = win_statbuf.st_mode; + buf->st_nlink = win_statbuf.st_nlink; + buf->st_uid = win_statbuf.st_uid; + buf->st_gid = win_statbuf.st_gid; + buf->st_rdev = win_statbuf.st_rdev; + buf->st_size = win_statbuf.st_size; + buf->st_atime = win_statbuf.st_atime; + buf->st_mtime = win_statbuf.st_mtime; + buf->st_ctime = win_statbuf.st_ctime; + buf->st_blocks = win_statbuf.st_size / 512; + + retval = GetFullPathNameW(winpath, wsizeof(pathbuf), pathbuf, NULL); + if (!retval) { + errno = ENOENT; + return -1; + } + + /* Set st_dev to the drive number */ + buf->st_dev = tolower(pathbuf[0]) - 'a'; + + /* GetLongPathName fails if called with only x:\, and drive x is not + ready. So, only call it for other paths. */ + if (pathbuf[0] && wcscmp(pathbuf + 1, L":\\")) { + retval = GetLongPathNameW(pathbuf, pathbuf, wsizeof(pathbuf)); + if (!retval || (unsigned) retval > wsizeof(pathbuf)) { + /* Strangely enough, GetLongPathName returns + ERROR_SHARING_VIOLATION for locked files, such as hiberfil.sys + */ + if (GetLastError() != ERROR_SHARING_VIOLATION) { + errno = ENAMETOOLONG; + return -1; + } + } + } + + /* Hash st_ino, by splitting in two halves */ + namelen = wcslen(pathbuf); + splitpoint = &pathbuf[namelen / 2]; + savedchar = *splitpoint; + *splitpoint = '\0'; + buf->st_ino = wfnv1a_32(pathbuf, 0); + assert(sizeof(buf->st_ino) == 8); + buf->st_ino = buf->st_ino << 32; + *splitpoint = savedchar; + buf->st_ino |= wfnv1a_32(splitpoint, 0); + +#if 0 + fprintf(stderr, + "win_stat: file=%s, ret=%d, st_dev=0x%x, st_ino=0x%I64x\n", + file_name, ret, buf->st_dev, buf->st_ino); +#endif + free(winpath); + return ret; +} + +int win_open(const char *pathname, int flags, ...) +{ + va_list args; + mode_t mode; + int fd; + wchar_t *winpath; + + va_start(args, flags); + mode = va_arg(args, int); + + va_end(args); + + winpath = intpath2winpath(pathname); + if (!winpath) { + errno = EINVAL; + return -1; + } + + fd = _wopen(winpath, flags | O_BINARY, mode); + free(winpath); + if (fd < 0) { + return fd; + } + + return add_fdname(fd, pathname); + +} + +int win_close(int fd) +{ + remove_fdname(fd); + return close(fd); +} + +int win_fstat(int fd, backend_statstruct * buf) +{ + return win_stat(get_fdname(fd), buf); +} + +/* + opendir implementation which emulates a virtual root with the drive + letters presented as directories. +*/ +UNFS3_WIN_DIR *win_opendir(const char *name) +{ + wchar_t *winpath; + UNFS3_WIN_DIR *ret; + + ret = malloc(sizeof(UNFS3_WIN_DIR)); + if (!ret) { + logmsg(LOG_CRIT, "win_opendir: Unable to allocate memory"); + return NULL; + } + + if (!strcmp("/", name)) { + /* Emulate root */ + ret->stream = NULL; + ret->currentdrive = 0; + ret->logdrives = GetLogicalDrives(); + } else { + winpath = intpath2winpath(name); + if (!winpath) { + free(ret); + errno = EINVAL; + return NULL; + } + + ret->stream = _wopendir(winpath); + free(winpath); + if (ret->stream == NULL) { + free(ret); + ret = NULL; + } + } + + return ret; +} + +struct dirent *win_readdir(UNFS3_WIN_DIR * dir) +{ + if (dir->stream == NULL) { + /* Emulate root */ + for (; dir->currentdrive < MAX_NUM_DRIVES; dir->currentdrive++) { + if (dir->logdrives & 1 << dir->currentdrive) + break; + } + + if (dir->currentdrive < MAX_NUM_DRIVES) { + dir->de.d_name[0] = 'a' + dir->currentdrive; + dir->de.d_name[1] = '\0'; + dir->currentdrive++; + return &dir->de; + } else { + return NULL; + } + } else { + struct _wdirent *de; + + de = _wreaddir(dir->stream); + if (!de) { + return NULL; + } + + if (!WideCharToMultiByte + (CP_UTF8, 0, de->d_name, -1, dir->de.d_name, + sizeof(dir->de.d_name), NULL, NULL)) { + logmsg(LOG_CRIT, "win_readdir: WideCharToMultiByte failed"); + return NULL; + } + return &dir->de; + } +} + +int win_closedir(UNFS3_WIN_DIR * dir) +{ + if (dir->stream == NULL) { + free(dir); + return 0; + } else { + return _wclosedir(dir->stream); + } +} + +void openlog(U(const char *ident), U(int option), U(int facility)) +{ + +} + +char *win_realpath(const char *path, char *resolved_path) +{ + return normpath(path, resolved_path); +} + +int win_readlink(U(const char *path), U(char *buf), U(size_t bufsiz)) +{ + errno = ENOSYS; + return -1; +} + +int win_mkdir(const char *pathname, U(mode_t mode)) +{ + wchar_t *winpath; + int ret; + + if (!strcmp("/", pathname)) { + /* Emulate root */ + errno = EROFS; + return -1; + } + + winpath = intpath2winpath(pathname); + if (!winpath) { + errno = EINVAL; + return -1; + } + + /* FIXME: Use mode */ + ret = _wmkdir(winpath); + free(winpath); + return ret; +} + +int win_symlink(U(const char *oldpath), U(const char *newpath)) +{ + errno = ENOSYS; + return -1; +} + +int win_mknod(U(const char *pathname), U(mode_t mode), U(dev_t dev)) +{ + errno = ENOSYS; + return -1; +} + +int win_mkfifo(U(const char *pathname), U(mode_t mode)) +{ + errno = ENOSYS; + return -1; +} + +int win_link(U(const char *oldpath), U(const char *newpath)) +{ + errno = ENOSYS; + return -1; +} + +int win_statvfs(const char *path, backend_statvfsstruct * buf) +{ + wchar_t *winpath; + DWORD SectorsPerCluster; + DWORD BytesPerSector; + DWORD NumberOfFreeClusters; + DWORD TotalNumberOfClusters; + ULARGE_INTEGER FreeBytesAvailable; + ULARGE_INTEGER TotalNumberOfBytes; + ULARGE_INTEGER TotalNumberOfFreeBytes; + + if (!strcmp("/", path)) { + /* Emulate root */ + buf->f_bsize = 1024; + buf->f_blocks = 1024; + buf->f_bfree = 0; + buf->f_bavail = 0; + buf->f_files = 1024; + buf->f_ffree = 0; + return 0; + } + + winpath = intpath2winpath(path); + if (!winpath) { + errno = EINVAL; + return -1; + } + + winpath[3] = '\0'; /* Cut off after x:\ */ + + if (!GetDiskFreeSpaceW + (winpath, &SectorsPerCluster, &BytesPerSector, &NumberOfFreeClusters, + &TotalNumberOfClusters)) { + errno = EIO; + return -1; + } + + if (!GetDiskFreeSpaceExW + (winpath, &FreeBytesAvailable, &TotalNumberOfBytes, + &TotalNumberOfFreeBytes)) { + errno = EIO; + return -1; + } + + buf->f_bsize = BytesPerSector; + buf->f_blocks = TotalNumberOfBytes.QuadPart / BytesPerSector; + buf->f_bfree = TotalNumberOfFreeBytes.QuadPart / BytesPerSector; + buf->f_bavail = FreeBytesAvailable.QuadPart / BytesPerSector; + buf->f_files = buf->f_blocks / SectorsPerCluster; + buf->f_ffree = buf->f_bfree / SectorsPerCluster; + free(winpath); + return 0; +} + +int win_remove(const char *pathname) +{ + wchar_t *winpath; + int ret; + + if (!strcmp("/", pathname)) { + /* Emulate root */ + errno = EROFS; + return -1; + } + + winpath = intpath2winpath(pathname); + if (!winpath) { + errno = EINVAL; + return -1; + } + + ret = _wremove(winpath); + free(winpath); + return ret; +} + +int win_chmod(const char *path, mode_t mode) +{ + wchar_t *winpath; + int ret; + + if (!strcmp("/", path)) { + /* Emulate root */ + errno = EROFS; + return -1; + } + + winpath = intpath2winpath(path); + if (!winpath) { + errno = EINVAL; + return -1; + } + + ret = _wchmod(winpath, mode); + free(winpath); + return ret; +} + +/* + If creation is false, the LastAccessTime will be set according to + times->actime. Otherwise, CreationTime will be set. LastWriteTime + is always set according to times->modtime. +*/ +static int win_utime_creation(const char *path, const struct utimbuf *times, + int creation) +{ + wchar_t *winpath; + int ret = 0; + HANDLE h; + ULARGE_INTEGER fti; + FILETIME xtime, mtime; + + if (!strcmp("/", path)) { + /* Emulate root */ + errno = EROFS; + return -1; + } + + winpath = intpath2winpath(path); + if (!winpath) { + errno = EINVAL; + return -1; + } + + /* Unfortunately, we cannot use utime(), since it doesn't support + directories. */ + fti.QuadPart = UInt32x32To64(times->actime + FT70SEC, 10000000); + xtime.dwHighDateTime = fti.HighPart; + xtime.dwLowDateTime = fti.LowPart; + fti.QuadPart = UInt32x32To64(times->modtime + FT70SEC, 10000000); + mtime.dwHighDateTime = fti.HighPart; + mtime.dwLowDateTime = fti.LowPart; + + h = CreateFileW(winpath, FILE_WRITE_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, NULL); + + if (!SetFileTime + (h, creation ? &xtime : NULL, creation ? NULL : &xtime, &mtime)) { + errno = EACCES; + ret = -1; + } + + CloseHandle(h); + free(winpath); + return ret; +} + +int win_utime(const char *path, const struct utimbuf *times) +{ + return win_utime_creation(path, times, FALSE); +} + +int win_rmdir(const char *path) +{ + wchar_t *winpath; + int ret; + + if (!strcmp("/", path)) { + /* Emulate root */ + errno = EROFS; + return -1; + } + + winpath = intpath2winpath(path); + if (!winpath) { + errno = EINVAL; + return -1; + } + + ret = _wrmdir(winpath); + free(winpath); + return ret; +} + +int win_rename(const char *oldpath, const char *newpath) +{ + wchar_t *oldwinpath, *newwinpath; + int ret; + + if (!strcmp("/", oldpath) && !strcmp("/", newpath)) { + /* Emulate root */ + errno = EROFS; + return -1; + } + + oldwinpath = intpath2winpath(oldpath); + if (!oldwinpath) { + errno = EINVAL; + return -1; + } + newwinpath = intpath2winpath(newpath); + if (!newwinpath) { + free(oldwinpath); + errno = EINVAL; + return -1; + } + + ret = _wrename(oldwinpath, newwinpath); + free(oldwinpath); + free(newwinpath); + return ret; +} + +int win_gen_nonce(char *nonce) +{ + HCRYPTPROV hCryptProv; + + if (!CryptAcquireContext + (&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) { + logmsg(LOG_ERR, "CryptAcquireContext failed with error 0x%lx", + GetLastError()); + return -1; + } + + if (!CryptGenRandom(hCryptProv, 32, nonce)) { + logmsg(LOG_ERR, "CryptGenRandom failed with error 0x%lx", + GetLastError()); + return -1; + } + + if (!CryptReleaseContext(hCryptProv, 0)) { + logmsg(LOG_ERR, "CryptReleaseContext failed with error 0x%lx", + GetLastError()); + return -1; + } + + return 0; +} + +/* Just like strncasecmp, but compare two UTF8 strings. Limited to 4096 chars. */ +int win_utf8ncasecmp(const char *s1, const char *s2, size_t n) +{ + wchar_t ws1[4096], ws2[4096]; + int converted; + + /* Make sure input is valid UTF-8 */ + if (!isLegalUTF8String(s1)) { + logmsg(LOG_CRIT, "win_utf8ncasecmp: Illegal UTF-8 string:%s", s1); + return -1; + } + if (!isLegalUTF8String(s2)) { + logmsg(LOG_CRIT, "win_utf8ncasecmp: Illegal UTF-8 string:%s", s2); + return -1; + } + + /* Convert both strings to wide chars */ + converted = MultiByteToWideChar(CP_UTF8, 0, s1, n, ws1, wsizeof(ws1)); + if (!converted) { + logmsg(LOG_CRIT, "win_utf8ncasecmp: MultiByteToWideChar failed"); + return -1; + } + ws1[converted] = '\0'; + converted = MultiByteToWideChar(CP_UTF8, 0, s2, n, ws2, wsizeof(ws2)); + if (!converted) { + logmsg(LOG_CRIT, "win_utf8ncasecmp: MultiByteToWideChar failed"); + return 1; + } + ws2[converted] = '\0'; + + /* compare */ + return _wcsicmp(ws1, ws2); +} + +static void win_verf_to_ubuf(struct utimbuf *ubuf, createverf3 verf) +{ + ubuf->actime = verf[0] | verf[1] << 8 | verf[2] << 16 | verf[3] << 24; + ubuf->modtime = verf[4] | verf[5] << 8 | verf[6] << 16 | verf[7] << 24; + + /* FAT can only store dates in the interval 1980-01-01 to 2107-12-31. + However, since the utime interface uses Epoch time, we are further + limited to 1980-01-01 to 2038-01-19, assuming 32 bit signed time_t. + math.log(2**31-1 - FT80SEC, 2) = 30.7, which means that we can only + use 30 bits. */ + ubuf->actime &= 0x3fffffff; + ubuf->actime += FT80SEC; + ubuf->modtime &= 0x3fffffff; + ubuf->modtime += FT80SEC; + /* While FAT CreationTime has a resolution of 10 ms, WriteTime only has a + resolution of 2 seconds. */ + ubuf->modtime &= ~1; +} + +int win_store_create_verifier(char *obj, createverf3 verf) +{ + struct utimbuf ubuf; + + win_verf_to_ubuf(&ubuf, verf); + return win_utime_creation(obj, &ubuf, TRUE); +} + +int win_check_create_verifier(backend_statstruct * buf, createverf3 verf) +{ + struct utimbuf ubuf; + + win_verf_to_ubuf(&ubuf, verf); + return (buf->st_ctime == ubuf.actime && buf->st_mtime == ubuf.modtime); +} + +#endif /* WIN32 */ diff --git a/unfs3/winsupport.h b/unfs3/winsupport.h new file mode 100644 index 0000000..6aa295b --- /dev/null +++ b/unfs3/winsupport.h @@ -0,0 +1,131 @@ + +/* + * unfs3 Windows compatibility + * Copyright 2006 Peter Åstrand for Cendio AB + * see file LICENSE for license details + */ + +#ifdef WIN32 +#ifndef UNFS3_WINSUPPORT_H +#define UNFS3_WINSUPPORT_H + +#include +#include +#include +#include "nfs.h" + +#define LOG_EMERG 0 /* system is unusable */ +#define LOG_ALERT 1 /* action must be taken immediately */ +#define LOG_CRIT 2 /* critical conditions */ +#define LOG_ERR 3 /* error conditions */ +#define LOG_WARNING 4 /* warning conditions */ +#define LOG_NOTICE 5 /* normal but significant condition */ +#define LOG_INFO 6 /* informational */ +#define LOG_DEBUG 7 /* debug-level messages */ +#define LOG_CONS 0 +#define LOG_PID 0 +#define LOG_DAEMON 0 +#define closelog() do { } while (0) + +#define O_NONBLOCK 0 +#define ELOOP ENAMETOOLONG + +#define S_IRWXG 0 +#define S_IXGRP S_IRGRP +#define S_IRGRP 0 +#define S_IWGRP 0 + +#define S_IRWXO 0 +#define S_IXOTH S_IROTH +#define S_IROTH 0 +#define S_IWOTH 0 + +#define S_IFLNK 0 +#define S_IFSOCK 0 + +typedef int socklen_t; +typedef uint32 uid_t; +typedef uint32 gid_t; + +typedef struct _backend_statstruct +{ + uint32 st_dev; + uint64 st_ino; + _mode_t st_mode; + short st_nlink; + uint32 st_uid; + uint32 st_gid; + _dev_t st_rdev; + _off_t st_size; + short st_blksize; + _off_t st_blocks; + time_t st_atime; + time_t st_mtime; + time_t st_ctime; +} backend_statstruct; + +typedef struct _backend_passwdstruct +{ + uid_t pw_uid; + gid_t pw_gid; +} backend_passwdstruct; + +/* Only includes fields actually used by unfs3 */ +typedef struct _backend_statvfsstruct +{ + unsigned long f_bsize; /* file system block size */ + uint64 f_blocks; /* size of fs in f_frsize units */ + uint64 f_bfree; /* # free blocks */ + uint64 f_bavail; /* # free blocks for non-root */ + uint64 f_files; /* # inodes */ + uint64 f_ffree; /* # free inodes */ +} backend_statvfsstruct; + +typedef struct _UNFS3_WIN_DIR +{ + _WDIR *stream; /* Windows DIR stream. NULL means root emulation */ + uint32 currentdrive; /* Next drive to check/return */ + struct dirent de; + DWORD logdrives; +} UNFS3_WIN_DIR; + +int inet_aton(const char *cp, struct in_addr *addr); +ssize_t pread(int fd, void *buf, size_t count, off_t offset); +ssize_t pwrite(int fd, const void *buf, size_t count, off_t offset); +void syslog(int priority, const char *format, ...); + +int win_seteuid(uid_t euid); +int win_setegid(gid_t egid); +int win_truncate(const char *path, off_t length); +int win_chown(const char *path, uid_t owner, gid_t group); +int win_fchown(int fd, uid_t owner, gid_t group); +int win_fchmod(int fildes, mode_t mode); +int win_stat(const char *file_name, backend_statstruct *buf); +int win_fstat(int fd, backend_statstruct *buf); +int win_open(const char *pathname, int flags, ...); +int win_close(int fd); +UNFS3_WIN_DIR *win_opendir(const char *name); +struct dirent *win_readdir(UNFS3_WIN_DIR *dir); +int win_closedir(UNFS3_WIN_DIR *dir); +int win_init(); +void openlog(const char *ident, int option, int facility); +char *win_realpath(const char *path, char *resolved_path); +int win_readlink(const char *path, char *buf, size_t bufsiz); +int win_mkdir(const char *pathname, mode_t mode); +int win_symlink(const char *oldpath, const char *newpath); +int win_mknod(const char *pathname, mode_t mode, dev_t dev); +int win_mkfifo(const char *pathname, mode_t mode); +int win_link(const char *oldpath, const char *newpath); +int win_statvfs(const char *path, backend_statvfsstruct *buf); +int win_remove(const char *pathname); +int win_chmod(const char *path, mode_t mode); +int win_utime(const char *path, const struct utimbuf *times); +int win_rmdir(const char *path); +int win_rename(const char *oldpath, const char *newpath); +int win_gen_nonce(char *nonce); +int win_utf8ncasecmp(const char *s1, const char *s2, size_t n); +int win_store_create_verifier(char *obj, createverf3 verf); +int win_check_create_verifier(backend_statstruct * buf, createverf3 verf); + +#endif /* UNFS3_WINSUPPORT_H */ +#endif /* WIN32 */ diff --git a/unfs3/xdr.c b/unfs3/xdr.c new file mode 100644 index 0000000..21e5ea7 --- /dev/null +++ b/unfs3/xdr.c @@ -0,0 +1,1656 @@ + +/* + * UNFS3 XDR routines + * Generated by rpcgen + */ +#include "config.h" + +#include +#include +#ifndef WIN32 +#include +#endif /* WIN32 */ + +#if HAVE_XDR_U_INT64_T == 1 +#define xdr_uint64_t xdr_u_int64_t +#undef HAVE_XDR_UINT64_T +#define HAVE_XDR_UINT64_T 1 +#endif + +#include "mount.h" +#include "nfs.h" +#include "xdr.h" + +bool_t xdr_fhandle3(XDR * xdrs, fhandle3 * objp) +{ + if (!xdr_bytes + (xdrs, (char **) &objp->fhandle3_val, (u_int *) & objp->fhandle3_len, + FHSIZE3)) + return FALSE; + return TRUE; +} + +bool_t xdr_mountstat3(XDR * xdrs, mountstat3 * objp) +{ + if (!xdr_enum(xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_mountres3_ok(XDR * xdrs, mountres3_ok * objp) +{ + if (!xdr_fhandle3(xdrs, &objp->fhandle)) + return FALSE; + if (!xdr_array + (xdrs, (char **) (void *) &objp->auth_flavors.auth_flavors_val, + (u_int *) & objp->auth_flavors.auth_flavors_len, ~0, sizeof(int), + (xdrproc_t) xdr_int)) + return FALSE; + return TRUE; +} + +bool_t xdr_mountres3(XDR * xdrs, mountres3 * objp) +{ + if (!xdr_mountstat3(xdrs, &objp->fhs_status)) + return FALSE; + switch (objp->fhs_status) { + case 0: + if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t xdr_dirpath(XDR * xdrs, dirpath * objp) +{ + if (!xdr_string(xdrs, objp, MNTPATHLEN)) + return FALSE; + return TRUE; +} + +bool_t xdr_name(XDR * xdrs, name * objp) +{ + if (!xdr_string(xdrs, objp, MNTNAMLEN)) + return FALSE; + return TRUE; +} + +bool_t xdr_mountlist(XDR * xdrs, mountlist * objp) +{ + if (!xdr_pointer + (xdrs, (char **) objp, sizeof(struct mountbody), + (xdrproc_t) xdr_mountbody)) + return FALSE; + return TRUE; +} + +bool_t xdr_mountbody(XDR * xdrs, mountbody * objp) +{ + if (!xdr_name(xdrs, &objp->ml_hostname)) + return FALSE; + if (!xdr_dirpath(xdrs, &objp->ml_directory)) + return FALSE; + if (!xdr_mountlist(xdrs, &objp->ml_next)) + return FALSE; + return TRUE; +} + +bool_t xdr_groups(XDR * xdrs, groups * objp) +{ + if (!xdr_pointer + (xdrs, (char **) objp, sizeof(struct groupnode), + (xdrproc_t) xdr_groupnode)) + return FALSE; + return TRUE; +} + +bool_t xdr_groupnode(XDR * xdrs, groupnode * objp) +{ + if (!xdr_name(xdrs, &objp->gr_name)) + return FALSE; + if (!xdr_groups(xdrs, &objp->gr_next)) + return FALSE; + return TRUE; +} + +bool_t xdr_exports(XDR * xdrs, exports * objp) +{ + if (!xdr_pointer + (xdrs, (char **) objp, sizeof(struct exportnode), + (xdrproc_t) xdr_exportnode)) + return FALSE; + return TRUE; +} + +bool_t xdr_exportnode(XDR * xdrs, exportnode * objp) +{ + if (!xdr_dirpath(xdrs, &objp->ex_dir)) + return FALSE; + if (!xdr_groups(xdrs, &objp->ex_groups)) + return FALSE; + if (!xdr_exports(xdrs, &objp->ex_next)) + return FALSE; + return TRUE; +} + +bool_t xdr_filename(XDR * xdrs, filename * objp) +{ + if (!xdr_string(xdrs, objp, NFS_MAXNAMLEN)) + return FALSE; + return TRUE; +} + +bool_t xdr_nfspath(XDR * xdrs, nfspath * objp) +{ + if (!xdr_string(xdrs, objp, NFS_MAXPATHLEN)) + return FALSE; + return TRUE; +} + +#if HAVE_XDR_UINT64 == 0 +#if HAVE_XDR_UINT64_T == 1 +bool_t xdr_uint64(XDR * xdrs, uint64 * objp) +{ + if (!xdr_uint64_t(xdrs, objp)) + return FALSE; + return TRUE; +} +#else +bool_t xdr_uint64(XDR * xdrs, uint64 * objp) +{ + char buf[8]; + + if (xdrs->x_op == XDR_ENCODE) { + buf[0] = (*objp >> 56) & 0xFF; + buf[1] = (*objp >> 48) & 0xFF; + buf[2] = (*objp >> 40) & 0xFF; + buf[3] = (*objp >> 32) & 0xFF; + buf[4] = (*objp >> 24) & 0xFF; + buf[5] = (*objp >> 16) & 0xFF; + buf[6] = (*objp >> 8) & 0xFF; + buf[7] = *objp & 0xFF; + if (!xdr_opaque(xdrs, buf, 8)) + return FALSE; + return TRUE; + } else if (xdrs->x_op == XDR_DECODE) { + uint32 *top = (void *) &buf[0]; + uint32 *bottom = (void *) &buf[4]; + + if (!xdr_opaque(xdrs, buf, 8)) + return FALSE; + *objp = (uint64) (ntohl(*top)) << 32 | ntohl(*bottom); + return TRUE; + } + + if (!xdr_opaque(xdrs, buf, 8)) + return FALSE; + return TRUE; +} +#endif +#endif + +#if HAVE_XDR_UINT32 == 0 && HAVE_XDR_U_LONG == 1 +bool_t xdr_uint32(XDR * xdrs, uint32 * objp) +{ + if (!xdr_u_long(xdrs, objp)) + return FALSE; + return TRUE; +} +#endif + +#if HAVE_XDR_INT32 == 0 && HAVE_XDR_LONG == 1 +bool_t xdr_int32(XDR * xdrs, int32 * objp) +{ + if (!xdr_long(xdrs, objp)) + return FALSE; + return TRUE; +} +#endif + +bool_t xdr_filename3(XDR * xdrs, filename3 * objp) +{ + if (!xdr_string(xdrs, objp, ~0)) + return FALSE; + return TRUE; +} + +bool_t xdr_nfspath3(XDR * xdrs, nfspath3 * objp) +{ + if (!xdr_string(xdrs, objp, ~0)) + return FALSE; + return TRUE; +} + +bool_t xdr_fileid3(XDR * xdrs, fileid3 * objp) +{ + if (!xdr_uint64(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_cookie3(XDR * xdrs, cookie3 * objp) +{ + if (!xdr_uint64(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_cookieverf3(XDR * xdrs, cookieverf3 objp) +{ + if (!xdr_opaque(xdrs, objp, NFS3_COOKIEVERFSIZE)) + return FALSE; + return TRUE; +} + +bool_t xdr_createverf3(XDR * xdrs, createverf3 objp) +{ + if (!xdr_opaque(xdrs, objp, NFS3_CREATEVERFSIZE)) + return FALSE; + return TRUE; +} + +bool_t xdr_writeverf3(XDR * xdrs, writeverf3 objp) +{ + if (!xdr_opaque(xdrs, objp, NFS3_WRITEVERFSIZE)) + return FALSE; + return TRUE; +} + +bool_t xdr_uid3(XDR * xdrs, uid3 * objp) +{ + if (!xdr_uint32(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_gid3(XDR * xdrs, gid3 * objp) +{ + if (!xdr_uint32(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_size3(XDR * xdrs, size3 * objp) +{ + if (!xdr_uint64(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_offset3(XDR * xdrs, offset3 * objp) +{ + if (!xdr_uint64(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_mode3(XDR * xdrs, mode3 * objp) +{ + if (!xdr_uint32(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_count3(XDR * xdrs, count3 * objp) +{ + if (!xdr_uint32(xdrs, objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_nfsstat3(XDR * xdrs, nfsstat3 * objp) +{ + if (!xdr_enum(xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_ftype3(XDR * xdrs, ftype3 * objp) +{ + if (!xdr_enum(xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_specdata3(XDR * xdrs, specdata3 * objp) +{ + if (!xdr_uint32(xdrs, &objp->specdata1)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->specdata2)) + return FALSE; + return TRUE; +} + +bool_t xdr_nfs_fh3(XDR * xdrs, nfs_fh3 * objp) +{ + if (!xdr_bytes + (xdrs, (char **) &objp->data.data_val, + (u_int *) & objp->data.data_len, NFS3_FHSIZE)) + return FALSE; + return TRUE; +} + +bool_t xdr_nfstime3(XDR * xdrs, nfstime3 * objp) +{ + if (!xdr_uint32(xdrs, &objp->seconds)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->nseconds)) + return FALSE; + return TRUE; +} + +bool_t xdr_fattr3(XDR * xdrs, fattr3 * objp) +{ + if (!xdr_ftype3(xdrs, &objp->type)) + return FALSE; + if (!xdr_mode3(xdrs, &objp->mode)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->nlink)) + return FALSE; + if (!xdr_uid3(xdrs, &objp->uid)) + return FALSE; + if (!xdr_gid3(xdrs, &objp->gid)) + return FALSE; + if (!xdr_size3(xdrs, &objp->size)) + return FALSE; + if (!xdr_size3(xdrs, &objp->used)) + return FALSE; + if (!xdr_specdata3(xdrs, &objp->rdev)) + return FALSE; + if (!xdr_uint64(xdrs, &objp->fsid)) + return FALSE; + if (!xdr_fileid3(xdrs, &objp->fileid)) + return FALSE; + if (!xdr_nfstime3(xdrs, &objp->atime)) + return FALSE; + if (!xdr_nfstime3(xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime3(xdrs, &objp->ctime)) + return FALSE; + return TRUE; +} + +bool_t xdr_post_op_attr(XDR * xdrs, post_op_attr * objp) +{ + if (!xdr_bool(xdrs, &objp->attributes_follow)) + return FALSE; + switch (objp->attributes_follow) { + case TRUE: + if (!xdr_fattr3(xdrs, &objp->post_op_attr_u.attributes)) + return FALSE; + break; + case FALSE: + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t xdr_wcc_attr(XDR * xdrs, wcc_attr * objp) +{ + if (!xdr_size3(xdrs, &objp->size)) + return FALSE; + if (!xdr_nfstime3(xdrs, &objp->mtime)) + return FALSE; + if (!xdr_nfstime3(xdrs, &objp->ctime)) + return FALSE; + return TRUE; +} + +bool_t xdr_pre_op_attr(XDR * xdrs, pre_op_attr * objp) +{ + if (!xdr_bool(xdrs, &objp->attributes_follow)) + return FALSE; + switch (objp->attributes_follow) { + case TRUE: + if (!xdr_wcc_attr(xdrs, &objp->pre_op_attr_u.attributes)) + return FALSE; + break; + case FALSE: + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t xdr_wcc_data(XDR * xdrs, wcc_data * objp) +{ + if (!xdr_pre_op_attr(xdrs, &objp->before)) + return FALSE; + if (!xdr_post_op_attr(xdrs, &objp->after)) + return FALSE; + return TRUE; +} + +bool_t xdr_post_op_fh3(XDR * xdrs, post_op_fh3 * objp) +{ + if (!xdr_bool(xdrs, &objp->handle_follows)) + return FALSE; + switch (objp->handle_follows) { + case TRUE: + if (!xdr_nfs_fh3(xdrs, &objp->post_op_fh3_u.handle)) + return FALSE; + break; + case FALSE: + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t xdr_time_how(XDR * xdrs, time_how * objp) +{ + if (!xdr_enum(xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_set_mode3(XDR * xdrs, set_mode3 * objp) +{ + if (!xdr_bool(xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case TRUE: + if (!xdr_mode3(xdrs, &objp->set_mode3_u.mode)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t xdr_set_uid3(XDR * xdrs, set_uid3 * objp) +{ + if (!xdr_bool(xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case TRUE: + if (!xdr_uid3(xdrs, &objp->set_uid3_u.uid)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t xdr_set_gid3(XDR * xdrs, set_gid3 * objp) +{ + if (!xdr_bool(xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case TRUE: + if (!xdr_gid3(xdrs, &objp->set_gid3_u.gid)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t xdr_set_size3(XDR * xdrs, set_size3 * objp) +{ + if (!xdr_bool(xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case TRUE: + if (!xdr_size3(xdrs, &objp->set_size3_u.size)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t xdr_set_atime(XDR * xdrs, set_atime * objp) +{ + if (!xdr_time_how(xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case SET_TO_CLIENT_TIME: + if (!xdr_nfstime3(xdrs, &objp->set_atime_u.atime)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t xdr_set_mtime(XDR * xdrs, set_mtime * objp) +{ + if (!xdr_time_how(xdrs, &objp->set_it)) + return FALSE; + switch (objp->set_it) { + case SET_TO_CLIENT_TIME: + if (!xdr_nfstime3(xdrs, &objp->set_mtime_u.mtime)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t xdr_sattr3(XDR * xdrs, sattr3 * objp) +{ + if (!xdr_set_mode3(xdrs, &objp->mode)) + return FALSE; + if (!xdr_set_uid3(xdrs, &objp->uid)) + return FALSE; + if (!xdr_set_gid3(xdrs, &objp->gid)) + return FALSE; + if (!xdr_set_size3(xdrs, &objp->size)) + return FALSE; + if (!xdr_set_atime(xdrs, &objp->atime)) + return FALSE; + if (!xdr_set_mtime(xdrs, &objp->mtime)) + return FALSE; + return TRUE; +} + +bool_t xdr_diropargs3(XDR * xdrs, diropargs3 * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->dir)) + return FALSE; + if (!xdr_filename3(xdrs, &objp->name)) + return FALSE; + return TRUE; +} + +bool_t xdr_GETATTR3args(XDR * xdrs, GETATTR3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->object)) + return FALSE; + return TRUE; +} + +bool_t xdr_GETATTR3resok(XDR * xdrs, GETATTR3resok * objp) +{ + if (!xdr_fattr3(xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_GETATTR3res(XDR * xdrs, GETATTR3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_GETATTR3resok(xdrs, &objp->GETATTR3res_u.resok)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t xdr_sattrguard3(XDR * xdrs, sattrguard3 * objp) +{ + if (!xdr_bool(xdrs, &objp->check)) + return FALSE; + switch (objp->check) { + case TRUE: + if (!xdr_nfstime3(xdrs, &objp->sattrguard3_u.obj_ctime)) + return FALSE; + break; + case FALSE: + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t xdr_SETATTR3args(XDR * xdrs, SETATTR3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->object)) + return FALSE; + if (!xdr_sattr3(xdrs, &objp->new_attributes)) + return FALSE; + if (!xdr_sattrguard3(xdrs, &objp->guard)) + return FALSE; + return TRUE; +} + +bool_t xdr_SETATTR3resok(XDR * xdrs, SETATTR3resok * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->obj_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_SETATTR3resfail(XDR * xdrs, SETATTR3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->obj_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_SETATTR3res(XDR * xdrs, SETATTR3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_SETATTR3resok(xdrs, &objp->SETATTR3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_SETATTR3resfail(xdrs, &objp->SETATTR3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_LOOKUP3args(XDR * xdrs, LOOKUP3args * objp) +{ + if (!xdr_diropargs3(xdrs, &objp->what)) + return FALSE; + return TRUE; +} + +bool_t xdr_LOOKUP3resok(XDR * xdrs, LOOKUP3resok * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->object)) + return FALSE; + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_post_op_attr(xdrs, &objp->dir_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_LOOKUP3resfail(XDR * xdrs, LOOKUP3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->dir_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_LOOKUP3res(XDR * xdrs, LOOKUP3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_LOOKUP3resok(xdrs, &objp->LOOKUP3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_LOOKUP3resfail(xdrs, &objp->LOOKUP3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_ACCESS3args(XDR * xdrs, ACCESS3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->object)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->access)) + return FALSE; + return TRUE; +} + +bool_t xdr_ACCESS3resok(XDR * xdrs, ACCESS3resok * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->access)) + return FALSE; + return TRUE; +} + +bool_t xdr_ACCESS3resfail(XDR * xdrs, ACCESS3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_ACCESS3res(XDR * xdrs, ACCESS3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_ACCESS3resok(xdrs, &objp->ACCESS3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_ACCESS3resfail(xdrs, &objp->ACCESS3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_READLINK3args(XDR * xdrs, READLINK3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->symlink)) + return FALSE; + return TRUE; +} + +bool_t xdr_READLINK3resok(XDR * xdrs, READLINK3resok * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->symlink_attributes)) + return FALSE; + if (!xdr_nfspath3(xdrs, &objp->data)) + return FALSE; + return TRUE; +} + +bool_t xdr_READLINK3resfail(XDR * xdrs, READLINK3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->symlink_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_READLINK3res(XDR * xdrs, READLINK3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READLINK3resok(xdrs, &objp->READLINK3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_READLINK3resfail(xdrs, &objp->READLINK3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_READ3args(XDR * xdrs, READ3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->file)) + return FALSE; + if (!xdr_offset3(xdrs, &objp->offset)) + return FALSE; + if (!xdr_count3(xdrs, &objp->count)) + return FALSE; + return TRUE; +} + +bool_t xdr_READ3resok(XDR * xdrs, READ3resok * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->file_attributes)) + return FALSE; + if (!xdr_count3(xdrs, &objp->count)) + return FALSE; + if (!xdr_bool(xdrs, &objp->eof)) + return FALSE; + if (!xdr_bytes + (xdrs, (char **) &objp->data.data_val, + (u_int *) & objp->data.data_len, ~0)) + return FALSE; + return TRUE; +} + +bool_t xdr_READ3resfail(XDR * xdrs, READ3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->file_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_READ3res(XDR * xdrs, READ3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READ3resok(xdrs, &objp->READ3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_READ3resfail(xdrs, &objp->READ3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_stable_how(XDR * xdrs, stable_how * objp) +{ + if (!xdr_enum(xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_WRITE3args(XDR * xdrs, WRITE3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->file)) + return FALSE; + if (!xdr_offset3(xdrs, &objp->offset)) + return FALSE; + if (!xdr_count3(xdrs, &objp->count)) + return FALSE; + if (!xdr_stable_how(xdrs, &objp->stable)) + return FALSE; + if (!xdr_bytes + (xdrs, (char **) &objp->data.data_val, + (u_int *) & objp->data.data_len, ~0)) + return FALSE; + return TRUE; +} + +bool_t xdr_WRITE3resok(XDR * xdrs, WRITE3resok * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->file_wcc)) + return FALSE; + if (!xdr_count3(xdrs, &objp->count)) + return FALSE; + if (!xdr_stable_how(xdrs, &objp->committed)) + return FALSE; + if (!xdr_writeverf3(xdrs, objp->verf)) + return FALSE; + return TRUE; +} + +bool_t xdr_WRITE3resfail(XDR * xdrs, WRITE3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->file_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_WRITE3res(XDR * xdrs, WRITE3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_WRITE3resok(xdrs, &objp->WRITE3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_WRITE3resfail(xdrs, &objp->WRITE3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_createmode3(XDR * xdrs, createmode3 * objp) +{ + if (!xdr_enum(xdrs, (enum_t *) objp)) + return FALSE; + return TRUE; +} + +bool_t xdr_createhow3(XDR * xdrs, createhow3 * objp) +{ + if (!xdr_createmode3(xdrs, &objp->mode)) + return FALSE; + switch (objp->mode) { + case UNCHECKED: + case GUARDED: + if (!xdr_sattr3(xdrs, &objp->createhow3_u.obj_attributes)) + return FALSE; + break; + case EXCLUSIVE: + if (!xdr_createverf3(xdrs, objp->createhow3_u.verf)) + return FALSE; + break; + default: + return FALSE; + } + return TRUE; +} + +bool_t xdr_CREATE3args(XDR * xdrs, CREATE3args * objp) +{ + if (!xdr_diropargs3(xdrs, &objp->where)) + return FALSE; + if (!xdr_createhow3(xdrs, &objp->how)) + return FALSE; + return TRUE; +} + +bool_t xdr_CREATE3resok(XDR * xdrs, CREATE3resok * objp) +{ + if (!xdr_post_op_fh3(xdrs, &objp->obj)) + return FALSE; + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_CREATE3resfail(XDR * xdrs, CREATE3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_CREATE3res(XDR * xdrs, CREATE3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_CREATE3resok(xdrs, &objp->CREATE3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_CREATE3resfail(xdrs, &objp->CREATE3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_MKDIR3args(XDR * xdrs, MKDIR3args * objp) +{ + if (!xdr_diropargs3(xdrs, &objp->where)) + return FALSE; + if (!xdr_sattr3(xdrs, &objp->attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_MKDIR3resok(XDR * xdrs, MKDIR3resok * objp) +{ + if (!xdr_post_op_fh3(xdrs, &objp->obj)) + return FALSE; + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_MKDIR3resfail(XDR * xdrs, MKDIR3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_MKDIR3res(XDR * xdrs, MKDIR3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_MKDIR3resok(xdrs, &objp->MKDIR3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_MKDIR3resfail(xdrs, &objp->MKDIR3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_symlinkdata3(XDR * xdrs, symlinkdata3 * objp) +{ + if (!xdr_sattr3(xdrs, &objp->symlink_attributes)) + return FALSE; + if (!xdr_nfspath3(xdrs, &objp->symlink_data)) + return FALSE; + return TRUE; +} + +bool_t xdr_SYMLINK3args(XDR * xdrs, SYMLINK3args * objp) +{ + if (!xdr_diropargs3(xdrs, &objp->where)) + return FALSE; + if (!xdr_symlinkdata3(xdrs, &objp->symlink)) + return FALSE; + return TRUE; +} + +bool_t xdr_SYMLINK3resok(XDR * xdrs, SYMLINK3resok * objp) +{ + if (!xdr_post_op_fh3(xdrs, &objp->obj)) + return FALSE; + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_SYMLINK3resfail(XDR * xdrs, SYMLINK3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_SYMLINK3res(XDR * xdrs, SYMLINK3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_SYMLINK3resok(xdrs, &objp->SYMLINK3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_SYMLINK3resfail(xdrs, &objp->SYMLINK3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_devicedata3(XDR * xdrs, devicedata3 * objp) +{ + if (!xdr_sattr3(xdrs, &objp->dev_attributes)) + return FALSE; + if (!xdr_specdata3(xdrs, &objp->spec)) + return FALSE; + return TRUE; +} + +bool_t xdr_mknoddata3(XDR * xdrs, mknoddata3 * objp) +{ + if (!xdr_ftype3(xdrs, &objp->type)) + return FALSE; + switch (objp->type) { + case NF3CHR: + case NF3BLK: + if (!xdr_devicedata3(xdrs, &objp->mknoddata3_u.device)) + return FALSE; + break; + case NF3SOCK: + case NF3FIFO: + if (!xdr_sattr3(xdrs, &objp->mknoddata3_u.pipe_attributes)) + return FALSE; + break; + default: + break; + } + return TRUE; +} + +bool_t xdr_MKNOD3args(XDR * xdrs, MKNOD3args * objp) +{ + if (!xdr_diropargs3(xdrs, &objp->where)) + return FALSE; + if (!xdr_mknoddata3(xdrs, &objp->what)) + return FALSE; + return TRUE; +} + +bool_t xdr_MKNOD3resok(XDR * xdrs, MKNOD3resok * objp) +{ + if (!xdr_post_op_fh3(xdrs, &objp->obj)) + return FALSE; + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_MKNOD3resfail(XDR * xdrs, MKNOD3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_MKNOD3res(XDR * xdrs, MKNOD3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_MKNOD3resok(xdrs, &objp->MKNOD3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_MKNOD3resfail(xdrs, &objp->MKNOD3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_REMOVE3args(XDR * xdrs, REMOVE3args * objp) +{ + if (!xdr_diropargs3(xdrs, &objp->object)) + return FALSE; + return TRUE; +} + +bool_t xdr_REMOVE3resok(XDR * xdrs, REMOVE3resok * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_REMOVE3resfail(XDR * xdrs, REMOVE3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_REMOVE3res(XDR * xdrs, REMOVE3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_REMOVE3resok(xdrs, &objp->REMOVE3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_REMOVE3resfail(xdrs, &objp->REMOVE3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_RMDIR3args(XDR * xdrs, RMDIR3args * objp) +{ + if (!xdr_diropargs3(xdrs, &objp->object)) + return FALSE; + return TRUE; +} + +bool_t xdr_RMDIR3resok(XDR * xdrs, RMDIR3resok * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_RMDIR3resfail(XDR * xdrs, RMDIR3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->dir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_RMDIR3res(XDR * xdrs, RMDIR3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_RMDIR3resok(xdrs, &objp->RMDIR3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_RMDIR3resfail(xdrs, &objp->RMDIR3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_RENAME3args(XDR * xdrs, RENAME3args * objp) +{ + if (!xdr_diropargs3(xdrs, &objp->from)) + return FALSE; + if (!xdr_diropargs3(xdrs, &objp->to)) + return FALSE; + return TRUE; +} + +bool_t xdr_RENAME3resok(XDR * xdrs, RENAME3resok * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->fromdir_wcc)) + return FALSE; + if (!xdr_wcc_data(xdrs, &objp->todir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_RENAME3resfail(XDR * xdrs, RENAME3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->fromdir_wcc)) + return FALSE; + if (!xdr_wcc_data(xdrs, &objp->todir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_RENAME3res(XDR * xdrs, RENAME3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_RENAME3resok(xdrs, &objp->RENAME3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_RENAME3resfail(xdrs, &objp->RENAME3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_LINK3args(XDR * xdrs, LINK3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->file)) + return FALSE; + if (!xdr_diropargs3(xdrs, &objp->link)) + return FALSE; + return TRUE; +} + +bool_t xdr_LINK3resok(XDR * xdrs, LINK3resok * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->file_attributes)) + return FALSE; + if (!xdr_wcc_data(xdrs, &objp->linkdir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_LINK3resfail(XDR * xdrs, LINK3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->file_attributes)) + return FALSE; + if (!xdr_wcc_data(xdrs, &objp->linkdir_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_LINK3res(XDR * xdrs, LINK3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_LINK3resok(xdrs, &objp->LINK3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_LINK3resfail(xdrs, &objp->LINK3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_READDIR3args(XDR * xdrs, READDIR3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->dir)) + return FALSE; + if (!xdr_cookie3(xdrs, &objp->cookie)) + return FALSE; + if (!xdr_cookieverf3(xdrs, objp->cookieverf)) + return FALSE; + if (!xdr_count3(xdrs, &objp->count)) + return FALSE; + return TRUE; +} + +bool_t xdr_entry3(XDR * xdrs, entry3 * objp) +{ + if (!xdr_fileid3(xdrs, &objp->fileid)) + return FALSE; + if (!xdr_filename3(xdrs, &objp->name)) + return FALSE; + if (!xdr_cookie3(xdrs, &objp->cookie)) + return FALSE; + if (!xdr_pointer + (xdrs, (char **) (void *) &objp->nextentry, sizeof(entry3), + (xdrproc_t) xdr_entry3)) + return FALSE; + return TRUE; +} + +bool_t xdr_dirlist3(XDR * xdrs, dirlist3 * objp) +{ + if (!xdr_pointer + (xdrs, (char **) (void *) &objp->entries, sizeof(entry3), + (xdrproc_t) xdr_entry3)) + return FALSE; + if (!xdr_bool(xdrs, &objp->eof)) + return FALSE; + return TRUE; +} + +bool_t xdr_READDIR3resok(XDR * xdrs, READDIR3resok * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->dir_attributes)) + return FALSE; + if (!xdr_cookieverf3(xdrs, objp->cookieverf)) + return FALSE; + if (!xdr_dirlist3(xdrs, &objp->reply)) + return FALSE; + return TRUE; +} + +bool_t xdr_READDIR3resfail(XDR * xdrs, READDIR3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->dir_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_READDIR3res(XDR * xdrs, READDIR3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READDIR3resok(xdrs, &objp->READDIR3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_READDIR3resfail(xdrs, &objp->READDIR3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_READDIRPLUS3args(XDR * xdrs, READDIRPLUS3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->dir)) + return FALSE; + if (!xdr_cookie3(xdrs, &objp->cookie)) + return FALSE; + if (!xdr_cookieverf3(xdrs, objp->cookieverf)) + return FALSE; + if (!xdr_count3(xdrs, &objp->dircount)) + return FALSE; + if (!xdr_count3(xdrs, &objp->maxcount)) + return FALSE; + return TRUE; +} + +bool_t xdr_entryplus3(XDR * xdrs, entryplus3 * objp) +{ + if (!xdr_fileid3(xdrs, &objp->fileid)) + return FALSE; + if (!xdr_filename3(xdrs, &objp->name)) + return FALSE; + if (!xdr_cookie3(xdrs, &objp->cookie)) + return FALSE; + if (!xdr_post_op_attr(xdrs, &objp->name_attributes)) + return FALSE; + if (!xdr_post_op_fh3(xdrs, &objp->name_handle)) + return FALSE; + if (!xdr_pointer + (xdrs, (char **) (void *) &objp->nextentry, sizeof(entryplus3), + (xdrproc_t) xdr_entryplus3)) + return FALSE; + return TRUE; +} + +bool_t xdr_dirlistplus3(XDR * xdrs, dirlistplus3 * objp) +{ + if (!xdr_pointer + (xdrs, (char **) (void *) &objp->entries, sizeof(entryplus3), + (xdrproc_t) xdr_entryplus3)) + return FALSE; + if (!xdr_bool(xdrs, &objp->eof)) + return FALSE; + return TRUE; +} + +bool_t xdr_READDIRPLUS3resok(XDR * xdrs, READDIRPLUS3resok * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->dir_attributes)) + return FALSE; + if (!xdr_cookieverf3(xdrs, objp->cookieverf)) + return FALSE; + if (!xdr_dirlistplus3(xdrs, &objp->reply)) + return FALSE; + return TRUE; +} + +bool_t xdr_READDIRPLUS3resfail(XDR * xdrs, READDIRPLUS3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->dir_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_READDIRPLUS3res(XDR * xdrs, READDIRPLUS3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_READDIRPLUS3resok(xdrs, &objp->READDIRPLUS3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_READDIRPLUS3resfail + (xdrs, &objp->READDIRPLUS3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_FSSTAT3args(XDR * xdrs, FSSTAT3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->fsroot)) + return FALSE; + return TRUE; +} + +bool_t xdr_FSSTAT3resok(XDR * xdrs, FSSTAT3resok * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_size3(xdrs, &objp->tbytes)) + return FALSE; + if (!xdr_size3(xdrs, &objp->fbytes)) + return FALSE; + if (!xdr_size3(xdrs, &objp->abytes)) + return FALSE; + if (!xdr_size3(xdrs, &objp->tfiles)) + return FALSE; + if (!xdr_size3(xdrs, &objp->ffiles)) + return FALSE; + if (!xdr_size3(xdrs, &objp->afiles)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->invarsec)) + return FALSE; + return TRUE; +} + +bool_t xdr_FSSTAT3resfail(XDR * xdrs, FSSTAT3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_FSSTAT3res(XDR * xdrs, FSSTAT3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_FSSTAT3resok(xdrs, &objp->FSSTAT3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_FSSTAT3resfail(xdrs, &objp->FSSTAT3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_FSINFO3args(XDR * xdrs, FSINFO3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->fsroot)) + return FALSE; + return TRUE; +} + +bool_t xdr_FSINFO3resok(XDR * xdrs, FSINFO3resok * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->rtmax)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->rtpref)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->rtmult)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->wtmax)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->wtpref)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->wtmult)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->dtpref)) + return FALSE; + if (!xdr_size3(xdrs, &objp->maxfilesize)) + return FALSE; + if (!xdr_nfstime3(xdrs, &objp->time_delta)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->properties)) + return FALSE; + return TRUE; +} + +bool_t xdr_FSINFO3resfail(XDR * xdrs, FSINFO3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_FSINFO3res(XDR * xdrs, FSINFO3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_FSINFO3resok(xdrs, &objp->FSINFO3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_FSINFO3resfail(xdrs, &objp->FSINFO3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_PATHCONF3args(XDR * xdrs, PATHCONF3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->object)) + return FALSE; + return TRUE; +} + +bool_t xdr_PATHCONF3resok(XDR * xdrs, PATHCONF3resok * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->linkmax)) + return FALSE; + if (!xdr_uint32(xdrs, &objp->name_max)) + return FALSE; + if (!xdr_bool(xdrs, &objp->no_trunc)) + return FALSE; + if (!xdr_bool(xdrs, &objp->chown_restricted)) + return FALSE; + if (!xdr_bool(xdrs, &objp->case_insensitive)) + return FALSE; + if (!xdr_bool(xdrs, &objp->case_preserving)) + return FALSE; + return TRUE; +} + +bool_t xdr_PATHCONF3resfail(XDR * xdrs, PATHCONF3resfail * objp) +{ + if (!xdr_post_op_attr(xdrs, &objp->obj_attributes)) + return FALSE; + return TRUE; +} + +bool_t xdr_PATHCONF3res(XDR * xdrs, PATHCONF3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_PATHCONF3resok(xdrs, &objp->PATHCONF3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_PATHCONF3resfail(xdrs, &objp->PATHCONF3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} + +bool_t xdr_COMMIT3args(XDR * xdrs, COMMIT3args * objp) +{ + if (!xdr_nfs_fh3(xdrs, &objp->file)) + return FALSE; + if (!xdr_offset3(xdrs, &objp->offset)) + return FALSE; + if (!xdr_count3(xdrs, &objp->count)) + return FALSE; + return TRUE; +} + +bool_t xdr_COMMIT3resok(XDR * xdrs, COMMIT3resok * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->file_wcc)) + return FALSE; + if (!xdr_writeverf3(xdrs, objp->verf)) + return FALSE; + return TRUE; +} + +bool_t xdr_COMMIT3resfail(XDR * xdrs, COMMIT3resfail * objp) +{ + if (!xdr_wcc_data(xdrs, &objp->file_wcc)) + return FALSE; + return TRUE; +} + +bool_t xdr_COMMIT3res(XDR * xdrs, COMMIT3res * objp) +{ + if (!xdr_nfsstat3(xdrs, &objp->status)) + return FALSE; + switch (objp->status) { + case NFS3_OK: + if (!xdr_COMMIT3resok(xdrs, &objp->COMMIT3res_u.resok)) + return FALSE; + break; + default: + if (!xdr_COMMIT3resfail(xdrs, &objp->COMMIT3res_u.resfail)) + return FALSE; + break; + } + return TRUE; +} diff --git a/unfs3/xdr.h b/unfs3/xdr.h new file mode 100644 index 0000000..3296c59 --- /dev/null +++ b/unfs3/xdr.h @@ -0,0 +1,165 @@ +/* + * UNFS3 XDR routine prototypes + * Generated by rpcgen + */ + +#ifndef UNFS3_XDR_H +#define UNFS3_XDR_H + +/* MOUNT protocol */ + +extern bool_t xdr_fhandle3 (XDR *, fhandle3*); +extern bool_t xdr_mountstat3 (XDR *, mountstat3*); +extern bool_t xdr_mountres3_ok (XDR *, mountres3_ok*); +extern bool_t xdr_mountres3 (XDR *, mountres3*); +extern bool_t xdr_dirpath (XDR *, dirpath*); +extern bool_t xdr_name (XDR *, name*); +extern bool_t xdr_mountlist (XDR *, mountlist*); +extern bool_t xdr_mountbody (XDR *, mountbody*); +extern bool_t xdr_groups (XDR *, groups*); +extern bool_t xdr_groupnode (XDR *, groupnode*); +extern bool_t xdr_exports (XDR *, exports*); +extern bool_t xdr_exportnode (XDR *, exportnode*); + +/* NFS protocol */ + +extern bool_t xdr_filename (XDR *, filename*); +extern bool_t xdr_nfspath (XDR *, nfspath*); +#if HAVE_XDR_UINT64 == 0 +extern bool_t xdr_uint64 (XDR *, uint64*); +#endif +#if HAVE_XDR_UINT32 == 0 +extern bool_t xdr_uint32 (XDR *, uint32*); +#endif +#if HAVE_XDR_INT32 == 0 +extern bool_t xdr_int32 (XDR *, int32*); +#endif +extern bool_t xdr_filename3 (XDR *, filename3*); +extern bool_t xdr_nfspath3 (XDR *, nfspath3*); +extern bool_t xdr_fileid3 (XDR *, fileid3*); +extern bool_t xdr_cookie3 (XDR *, cookie3*); +extern bool_t xdr_cookieverf3 (XDR *, cookieverf3); +extern bool_t xdr_createverf3 (XDR *, createverf3); +extern bool_t xdr_writeverf3 (XDR *, writeverf3); +extern bool_t xdr_uid3 (XDR *, uid3*); +extern bool_t xdr_gid3 (XDR *, gid3*); +extern bool_t xdr_size3 (XDR *, size3*); +extern bool_t xdr_offset3 (XDR *, offset3*); +extern bool_t xdr_mode3 (XDR *, mode3*); +extern bool_t xdr_count3 (XDR *, count3*); +extern bool_t xdr_nfsstat3 (XDR *, nfsstat3*); +extern bool_t xdr_ftype3 (XDR *, ftype3*); +extern bool_t xdr_specdata3 (XDR *, specdata3*); +extern bool_t xdr_nfs_fh3 (XDR *, nfs_fh3*); +extern bool_t xdr_nfstime3 (XDR *, nfstime3*); +extern bool_t xdr_fattr3 (XDR *, fattr3*); +extern bool_t xdr_post_op_attr (XDR *, post_op_attr*); +extern bool_t xdr_wcc_attr (XDR *, wcc_attr*); +extern bool_t xdr_pre_op_attr (XDR *, pre_op_attr*); +extern bool_t xdr_wcc_data (XDR *, wcc_data*); +extern bool_t xdr_post_op_fh3 (XDR *, post_op_fh3*); +extern bool_t xdr_time_how (XDR *, time_how*); +extern bool_t xdr_set_mode3 (XDR *, set_mode3*); +extern bool_t xdr_set_uid3 (XDR *, set_uid3*); +extern bool_t xdr_set_gid3 (XDR *, set_gid3*); +extern bool_t xdr_set_size3 (XDR *, set_size3*); +extern bool_t xdr_set_atime (XDR *, set_atime*); +extern bool_t xdr_set_mtime (XDR *, set_mtime*); +extern bool_t xdr_sattr3 (XDR *, sattr3*); +extern bool_t xdr_diropargs3 (XDR *, diropargs3*); +extern bool_t xdr_GETATTR3args (XDR *, GETATTR3args*); +extern bool_t xdr_GETATTR3resok (XDR *, GETATTR3resok*); +extern bool_t xdr_GETATTR3res (XDR *, GETATTR3res*); +extern bool_t xdr_sattrguard3 (XDR *, sattrguard3*); +extern bool_t xdr_SETATTR3args (XDR *, SETATTR3args*); +extern bool_t xdr_SETATTR3resok (XDR *, SETATTR3resok*); +extern bool_t xdr_SETATTR3resfail (XDR *, SETATTR3resfail*); +extern bool_t xdr_SETATTR3res (XDR *, SETATTR3res*); +extern bool_t xdr_LOOKUP3args (XDR *, LOOKUP3args*); +extern bool_t xdr_LOOKUP3resok (XDR *, LOOKUP3resok*); +extern bool_t xdr_LOOKUP3resfail (XDR *, LOOKUP3resfail*); +extern bool_t xdr_LOOKUP3res (XDR *, LOOKUP3res*); +extern bool_t xdr_ACCESS3args (XDR *, ACCESS3args*); +extern bool_t xdr_ACCESS3resok (XDR *, ACCESS3resok*); +extern bool_t xdr_ACCESS3resfail (XDR *, ACCESS3resfail*); +extern bool_t xdr_ACCESS3res (XDR *, ACCESS3res*); +extern bool_t xdr_READLINK3args (XDR *, READLINK3args*); +extern bool_t xdr_READLINK3resok (XDR *, READLINK3resok*); +extern bool_t xdr_READLINK3resfail (XDR *, READLINK3resfail*); +extern bool_t xdr_READLINK3res (XDR *, READLINK3res*); +extern bool_t xdr_READ3args (XDR *, READ3args*); +extern bool_t xdr_READ3resok (XDR *, READ3resok*); +extern bool_t xdr_READ3resfail (XDR *, READ3resfail*); +extern bool_t xdr_READ3res (XDR *, READ3res*); +extern bool_t xdr_stable_how (XDR *, stable_how*); +extern bool_t xdr_WRITE3args (XDR *, WRITE3args*); +extern bool_t xdr_WRITE3resok (XDR *, WRITE3resok*); +extern bool_t xdr_WRITE3resfail (XDR *, WRITE3resfail*); +extern bool_t xdr_WRITE3res (XDR *, WRITE3res*); +extern bool_t xdr_createmode3 (XDR *, createmode3*); +extern bool_t xdr_createhow3 (XDR *, createhow3*); +extern bool_t xdr_CREATE3args (XDR *, CREATE3args*); +extern bool_t xdr_CREATE3resok (XDR *, CREATE3resok*); +extern bool_t xdr_CREATE3resfail (XDR *, CREATE3resfail*); +extern bool_t xdr_CREATE3res (XDR *, CREATE3res*); +extern bool_t xdr_MKDIR3args (XDR *, MKDIR3args*); +extern bool_t xdr_MKDIR3resok (XDR *, MKDIR3resok*); +extern bool_t xdr_MKDIR3resfail (XDR *, MKDIR3resfail*); +extern bool_t xdr_MKDIR3res (XDR *, MKDIR3res*); +extern bool_t xdr_symlinkdata3 (XDR *, symlinkdata3*); +extern bool_t xdr_SYMLINK3args (XDR *, SYMLINK3args*); +extern bool_t xdr_SYMLINK3resok (XDR *, SYMLINK3resok*); +extern bool_t xdr_SYMLINK3resfail (XDR *, SYMLINK3resfail*); +extern bool_t xdr_SYMLINK3res (XDR *, SYMLINK3res*); +extern bool_t xdr_devicedata3 (XDR *, devicedata3*); +extern bool_t xdr_mknoddata3 (XDR *, mknoddata3*); +extern bool_t xdr_MKNOD3args (XDR *, MKNOD3args*); +extern bool_t xdr_MKNOD3resok (XDR *, MKNOD3resok*); +extern bool_t xdr_MKNOD3resfail (XDR *, MKNOD3resfail*); +extern bool_t xdr_MKNOD3res (XDR *, MKNOD3res*); +extern bool_t xdr_REMOVE3args (XDR *, REMOVE3args*); +extern bool_t xdr_REMOVE3resok (XDR *, REMOVE3resok*); +extern bool_t xdr_REMOVE3resfail (XDR *, REMOVE3resfail*); +extern bool_t xdr_REMOVE3res (XDR *, REMOVE3res*); +extern bool_t xdr_RMDIR3args (XDR *, RMDIR3args*); +extern bool_t xdr_RMDIR3resok (XDR *, RMDIR3resok*); +extern bool_t xdr_RMDIR3resfail (XDR *, RMDIR3resfail*); +extern bool_t xdr_RMDIR3res (XDR *, RMDIR3res*); +extern bool_t xdr_RENAME3args (XDR *, RENAME3args*); +extern bool_t xdr_RENAME3resok (XDR *, RENAME3resok*); +extern bool_t xdr_RENAME3resfail (XDR *, RENAME3resfail*); +extern bool_t xdr_RENAME3res (XDR *, RENAME3res*); +extern bool_t xdr_LINK3args (XDR *, LINK3args*); +extern bool_t xdr_LINK3resok (XDR *, LINK3resok*); +extern bool_t xdr_LINK3resfail (XDR *, LINK3resfail*); +extern bool_t xdr_LINK3res (XDR *, LINK3res*); +extern bool_t xdr_READDIR3args (XDR *, READDIR3args*); +extern bool_t xdr_entry3 (XDR *, entry3*); +extern bool_t xdr_dirlist3 (XDR *, dirlist3*); +extern bool_t xdr_READDIR3resok (XDR *, READDIR3resok*); +extern bool_t xdr_READDIR3resfail (XDR *, READDIR3resfail*); +extern bool_t xdr_READDIR3res (XDR *, READDIR3res*); +extern bool_t xdr_READDIRPLUS3args (XDR *, READDIRPLUS3args*); +extern bool_t xdr_entryplus3 (XDR *, entryplus3*); +extern bool_t xdr_dirlistplus3 (XDR *, dirlistplus3*); +extern bool_t xdr_READDIRPLUS3resok (XDR *, READDIRPLUS3resok*); +extern bool_t xdr_READDIRPLUS3resfail (XDR *, READDIRPLUS3resfail*); +extern bool_t xdr_READDIRPLUS3res (XDR *, READDIRPLUS3res*); +extern bool_t xdr_FSSTAT3args (XDR *, FSSTAT3args*); +extern bool_t xdr_FSSTAT3resok (XDR *, FSSTAT3resok*); +extern bool_t xdr_FSSTAT3resfail (XDR *, FSSTAT3resfail*); +extern bool_t xdr_FSSTAT3res (XDR *, FSSTAT3res*); +extern bool_t xdr_FSINFO3args (XDR *, FSINFO3args*); +extern bool_t xdr_FSINFO3resok (XDR *, FSINFO3resok*); +extern bool_t xdr_FSINFO3resfail (XDR *, FSINFO3resfail*); +extern bool_t xdr_FSINFO3res (XDR *, FSINFO3res*); +extern bool_t xdr_PATHCONF3args (XDR *, PATHCONF3args*); +extern bool_t xdr_PATHCONF3resok (XDR *, PATHCONF3resok*); +extern bool_t xdr_PATHCONF3resfail (XDR *, PATHCONF3resfail*); +extern bool_t xdr_PATHCONF3res (XDR *, PATHCONF3res*); +extern bool_t xdr_COMMIT3args (XDR *, COMMIT3args*); +extern bool_t xdr_COMMIT3resok (XDR *, COMMIT3resok*); +extern bool_t xdr_COMMIT3resfail (XDR *, COMMIT3resfail*); +extern bool_t xdr_COMMIT3res (XDR *, COMMIT3res*); + +#endif