Exportfs and rpc.mountd optimalization
[nfs-utils.git] / support / export / export.c
1 /*
2  * support/export/export.c
3  *
4  * Maintain list of exported file systems.
5  *
6  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
7  */
8
9 #ifdef HAVE_CONFIG_H
10 #include <config.h>
11 #endif
12
13 #include <string.h>
14 #include <sys/types.h>
15 #include <sys/param.h>
16 #include <netinet/in.h>
17 #include <stdlib.h>
18 #include "xmalloc.h"
19 #include "nfslib.h"
20 #include "exportfs.h"
21
22 exp_hash_table exportlist[MCL_MAXTYPES] = {{NULL, {{NULL,NULL}, }}, }; 
23 static int export_hash(char *);
24
25 static void     export_init(nfs_export *exp, nfs_client *clp,
26                                         struct exportent *nep);
27 static int      export_check(nfs_export *, struct hostent *, char *);
28 static nfs_export *
29                 export_allowed_internal(struct hostent *hp, char *path);
30
31 int
32 export_read(char *fname)
33 {
34         struct exportent        *eep;
35         nfs_export              *exp;
36
37         setexportent(fname, "r");
38         while ((eep = getexportent(0,1)) != NULL) {
39           exp = export_lookup(eep->e_hostname, eep->e_path, 0);
40           if (!exp)
41             export_create(eep,0);
42           else {
43             if (exp->m_export.e_flags != eep->e_flags) {
44               xlog(L_ERROR, "incompatible duplicated export entries:");
45               xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname,
46                    eep->e_path, eep->e_flags);
47               xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname,
48                    exp->m_export.e_path, exp->m_export.e_flags);
49             }
50             else {
51               xlog(L_ERROR, "duplicated export entries:");
52               xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path);
53               xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname,
54                    exp->m_export.e_path);
55             }
56           }
57         }
58         endexportent();
59
60         return 0;
61 }
62
63 /*
64  * Create an in-core export struct from an export entry.
65  */
66 nfs_export *
67 export_create(struct exportent *xep, int canonical)
68 {
69         nfs_client      *clp;
70         nfs_export      *exp;
71
72         if (!(clp = client_lookup(xep->e_hostname, canonical))) {
73                 /* bad export entry; complaint already logged */
74                 return NULL;
75         }
76         exp = (nfs_export *) xmalloc(sizeof(*exp));
77         export_init(exp, clp, xep);
78         export_add(exp);
79
80         return exp;
81 }
82
83 static void
84 export_init(nfs_export *exp, nfs_client *clp, struct exportent *nep)
85 {
86         struct exportent        *e = &exp->m_export;
87
88         dupexportent(e, nep);
89         if (nep->e_hostname)
90                 e->e_hostname = xstrdup(nep->e_hostname);
91
92         exp->m_exported = 0;
93         exp->m_xtabent = 0;
94         exp->m_mayexport = 0;
95         exp->m_changed = 0;
96         exp->m_warned = 0;
97         exp->m_client = clp;
98         clp->m_count++;
99 }
100
101 /*
102  * Duplicate exports data. The in-core export struct retains the
103  * original hostname from /etc/exports, while the in-core client struct
104  * gets the newly found FQDN.
105  */
106 nfs_export *
107 export_dup(nfs_export *exp, struct hostent *hp)
108 {
109         nfs_export              *new;
110         nfs_client              *clp;
111
112         new = (nfs_export *) xmalloc(sizeof(*new));
113         memcpy(new, exp, sizeof(*new));
114         dupexportent(&new->m_export, &exp->m_export);
115         if (exp->m_export.e_hostname)
116                 new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname);
117         clp = client_dup(exp->m_client, hp);
118         clp->m_count++;
119         new->m_client = clp;
120         new->m_mayexport = exp->m_mayexport;
121         new->m_exported = 0;
122         new->m_xtabent = 0;
123         new->m_changed = 0;
124         new->m_warned = 0;
125         export_add(new);
126
127         return new;
128 }
129 /*
130  * Add export entry to hash table
131  */
132 void 
133 export_add(nfs_export *exp)
134 {
135         exp_hash_table *p_tbl;
136         exp_hash_entry *p_hen;
137         nfs_export *p_next;
138
139         int type = exp->m_client->m_type;
140         int pos;
141
142         pos = export_hash(exp->m_export.e_path);
143         p_tbl = &(exportlist[type]); /* pointer to hash table */
144         p_hen = &(p_tbl->entries[pos]); /* pointer to hash table entry */
145
146         if (!(p_hen->p_first)) { /* hash table entry is empty */ 
147                 p_hen->p_first = exp;
148                 p_hen->p_last  = exp;
149
150                 exp->m_next = p_tbl->p_head;
151                 p_tbl->p_head = exp;
152         } else { /* hash table entry is NOT empty */
153                 p_next = p_hen->p_last->m_next;
154                 p_hen->p_last->m_next = exp;
155                 exp->m_next = p_next;
156                 p_hen->p_last = exp;
157         }
158 }
159
160 nfs_export *
161 export_find(struct hostent *hp, char *path)
162 {
163         nfs_export      *exp;
164         int             i;
165
166         for (i = 0; i < MCL_MAXTYPES; i++) {
167                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
168                         if (!export_check(exp, hp, path))
169                                 continue;
170                         if (exp->m_client->m_type == MCL_FQDN)
171                                 return exp;
172                         return export_dup(exp, hp);
173                 }
174         }
175
176         return NULL;
177 }
178
179 static nfs_export *
180 export_allowed_internal (struct hostent *hp, char *path)
181 {
182         nfs_export      *exp;
183         int             i;
184
185         for (i = 0; i < MCL_MAXTYPES; i++) {
186                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
187                         if (!exp->m_mayexport ||
188                             !export_check(exp, hp, path))
189                                 continue;
190                         return exp;
191                 }
192         }
193
194         return NULL;
195 }
196
197 nfs_export *
198 export_allowed(struct hostent *hp, char *path)
199 {
200         nfs_export              *exp;
201         char                    epath[MAXPATHLEN+1];
202         char                    *p = NULL;
203
204         if (path [0] != '/') return NULL;
205
206         strncpy(epath, path, sizeof (epath) - 1);
207         epath[sizeof (epath) - 1] = '\0';
208
209         /* Try the longest matching exported pathname. */
210         while (1) {
211                 exp = export_allowed_internal (hp, epath);
212                 if (exp)
213                         return exp;
214                 /* We have to treat the root, "/", specially. */
215                 if (p == &epath[1]) break;
216                 p = strrchr(epath, '/');
217                 if (p == epath) p++;
218                 *p = '\0';
219         }
220
221         return NULL;
222 }
223
224 /*
225  * Search hash table for export entry. 
226  */  
227 nfs_export *
228 export_lookup(char *hname, char *path, int canonical) 
229 {
230         nfs_client *clp;
231         nfs_export *exp;
232         exp_hash_entry *p_hen;
233
234         int pos;
235
236         clp = client_lookup(hname, canonical);
237         if(clp == NULL)
238                 return NULL;
239
240         pos = export_hash(path);
241         p_hen = &(exportlist[clp->m_type].entries[pos]); 
242         for(exp = p_hen->p_first; exp && (exp != p_hen->p_last->m_next); 
243                         exp = exp->m_next) {
244                 if (exp->m_client == clp && !strcmp(exp->m_export.e_path, path)) {
245                         return exp;
246                 }
247         }
248         return NULL;
249 }
250
251 static int
252 export_check(nfs_export *exp, struct hostent *hp, char *path)
253 {
254         if (strcmp(path, exp->m_export.e_path))
255                 return 0;
256
257         return client_check(exp->m_client, hp);
258 }
259
260 void
261 export_freeall(void)
262 {
263         nfs_export      *exp, *nxt;
264         int             i, j;
265
266         for (i = 0; i < MCL_MAXTYPES; i++) {
267                 for (exp = exportlist[i].p_head; exp; exp = nxt) {
268                         nxt = exp->m_next;
269                         client_release(exp->m_client);
270                         if (exp->m_export.e_squids)
271                                 xfree(exp->m_export.e_squids);
272                         if (exp->m_export.e_sqgids)
273                                 xfree(exp->m_export.e_sqgids);
274                         if (exp->m_export.e_mountpoint)
275                                 free(exp->m_export.e_mountpoint);
276                         if (exp->m_export.e_fslocdata)
277                                 xfree(exp->m_export.e_fslocdata);
278                         xfree(exp->m_export.e_hostname);
279                         xfree(exp);
280                 }
281       for(j = 0; j < HASH_TABLE_SIZE; j++) {
282         exportlist[i].entries[j].p_first = NULL;
283         exportlist[i].entries[j].p_last = NULL;
284       }
285       exportlist[i].p_head = NULL;
286         }
287         client_freeall();
288 }
289
290 /*
291  * Compute and returns integer from string. 
292  * Note: Its understood the smae integers can be same for 
293  *       different strings, but it should not matter.
294  */
295 static unsigned int 
296 strtoint(char *str)
297 {
298         int i = 0;
299         unsigned int n = 0;
300
301         while ( str[i] != '\0') {
302                 n+=((int)str[i])*i;
303                 i++;
304         }
305         return n;
306 }
307
308 /*
309  * Hash function
310  */
311 static int 
312 export_hash(char *str)
313 {
314         int num = strtoint(str);
315
316         return num % HASH_TABLE_SIZE;
317 }