]> git.decadent.org.uk Git - nfs-utils.git/blob - support/export/export.c
1800efd1622d1d4ddb9221a0844718adc0c67956
[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(const nfs_export *exp, const struct addrinfo *ai,
28                                 const char *path);
29 static nfs_export *
30                 export_allowed_internal(const struct addrinfo *ai,
31                                 const char *path);
32
33 static void
34 export_free(nfs_export *exp)
35 {
36         xfree(exp->m_export.e_squids);
37         xfree(exp->m_export.e_sqgids);
38         free(exp->m_export.e_mountpoint);
39         free(exp->m_export.e_fslocdata);
40
41         xfree(exp->m_export.e_hostname);
42         xfree(exp);
43 }
44
45 static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep)
46 {
47         if (exp->m_export.e_flags != eep->e_flags) {
48                 xlog(L_ERROR, "incompatible duplicated export entries:");
49                 xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname,
50                                 eep->e_path, eep->e_flags);
51                 xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname,
52                                 exp->m_export.e_path, exp->m_export.e_flags);
53         } else {
54                 xlog(L_ERROR, "duplicated export entries:");
55                 xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path);
56                 xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname,
57                                 exp->m_export.e_path);
58         }
59 }
60
61 /**
62  * export_read - read entries from /etc/exports
63  * @fname: name of file to read from
64  *
65  */
66 void
67 export_read(char *fname)
68 {
69         struct exportent        *eep;
70         nfs_export              *exp;
71
72         setexportent(fname, "r");
73         while ((eep = getexportent(0,1)) != NULL) {
74                 exp = export_lookup(eep->e_hostname, eep->e_path, 0);
75                 if (!exp)
76                         export_create(eep, 0);
77                 else
78                         warn_duplicated_exports(exp, eep);
79         }
80         endexportent();
81 }
82
83 /*
84  * Create an in-core export struct from an export entry.
85  */
86 nfs_export *
87 export_create(struct exportent *xep, int canonical)
88 {
89         nfs_client      *clp;
90         nfs_export      *exp;
91
92         if (!(clp = client_lookup(xep->e_hostname, canonical))) {
93                 /* bad export entry; complaint already logged */
94                 return NULL;
95         }
96         exp = (nfs_export *) xmalloc(sizeof(*exp));
97         export_init(exp, clp, xep);
98         export_add(exp);
99
100         return exp;
101 }
102
103 static void
104 export_init(nfs_export *exp, nfs_client *clp, struct exportent *nep)
105 {
106         struct exportent        *e = &exp->m_export;
107
108         dupexportent(e, nep);
109         if (nep->e_hostname)
110                 e->e_hostname = xstrdup(nep->e_hostname);
111
112         exp->m_exported = 0;
113         exp->m_xtabent = 0;
114         exp->m_mayexport = 0;
115         exp->m_changed = 0;
116         exp->m_warned = 0;
117         exp->m_client = clp;
118         clp->m_count++;
119 }
120
121 /*
122  * Duplicate exports data. The in-core export struct retains the
123  * original hostname from /etc/exports, while the in-core client struct
124  * gets the newly found FQDN.
125  */
126 static nfs_export *
127 export_dup(nfs_export *exp, const struct addrinfo *ai)
128 {
129         nfs_export              *new;
130         nfs_client              *clp;
131
132         new = (nfs_export *) xmalloc(sizeof(*new));
133         memcpy(new, exp, sizeof(*new));
134         dupexportent(&new->m_export, &exp->m_export);
135         if (exp->m_export.e_hostname)
136                 new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname);
137         clp = client_dup(exp->m_client, ai);
138         if (clp == NULL) {
139                 export_free(new);
140                 return NULL;
141         }
142         clp->m_count++;
143         new->m_client = clp;
144         new->m_mayexport = exp->m_mayexport;
145         new->m_exported = 0;
146         new->m_xtabent = 0;
147         new->m_changed = 0;
148         new->m_warned = 0;
149         export_add(new);
150
151         return new;
152 }
153
154 /*
155  * Add export entry to hash table
156  */
157 void 
158 export_add(nfs_export *exp)
159 {
160         exp_hash_table *p_tbl;
161         exp_hash_entry *p_hen;
162         nfs_export *p_next;
163
164         int type = exp->m_client->m_type;
165         int pos;
166
167         pos = export_hash(exp->m_export.e_path);
168         p_tbl = &(exportlist[type]); /* pointer to hash table */
169         p_hen = &(p_tbl->entries[pos]); /* pointer to hash table entry */
170
171         if (!(p_hen->p_first)) { /* hash table entry is empty */ 
172                 p_hen->p_first = exp;
173                 p_hen->p_last  = exp;
174
175                 exp->m_next = p_tbl->p_head;
176                 p_tbl->p_head = exp;
177         } else { /* hash table entry is NOT empty */
178                 p_next = p_hen->p_last->m_next;
179                 p_hen->p_last->m_next = exp;
180                 exp->m_next = p_next;
181                 p_hen->p_last = exp;
182         }
183 }
184
185 /**
186  * export_find - find or create a suitable nfs_export for @ai and @path
187  * @ai: pointer to addrinfo for client
188  * @path: '\0'-terminated ASCII string containing export path
189  *
190  * Returns a pointer to nfs_export data matching @ai and @path,
191  * or NULL if an error occurs.
192  */
193 nfs_export *
194 export_find(const struct addrinfo *ai, const char *path)
195 {
196         nfs_export      *exp;
197         int             i;
198
199         for (i = 0; i < MCL_MAXTYPES; i++) {
200                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
201                         if (!export_check(exp, ai, path))
202                                 continue;
203                         if (exp->m_client->m_type == MCL_FQDN)
204                                 return exp;
205                         return export_dup(exp, ai);
206                 }
207         }
208
209         return NULL;
210 }
211
212 static nfs_export *
213 export_allowed_internal(const struct addrinfo *ai, const char *path)
214 {
215         nfs_export      *exp;
216         int             i;
217
218         for (i = 0; i < MCL_MAXTYPES; i++) {
219                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
220                         if (!exp->m_mayexport ||
221                             !export_check(exp, ai, path))
222                                 continue;
223                         return exp;
224                 }
225         }
226
227         return NULL;
228 }
229
230 /**
231  * export_allowed - determine if this export is allowed
232  * @ai: pointer to addrinfo for client
233  * @path: '\0'-terminated ASCII string containing export path
234  *
235  * Returns a pointer to nfs_export data matching @ai and @path,
236  * or NULL if the export is not allowed.
237  */
238 nfs_export *
239 export_allowed(const struct addrinfo *ai, const char *path)
240 {
241         nfs_export              *exp;
242         char                    epath[MAXPATHLEN+1];
243         char                    *p = NULL;
244
245         if (path [0] != '/') return NULL;
246
247         strncpy(epath, path, sizeof (epath) - 1);
248         epath[sizeof (epath) - 1] = '\0';
249
250         /* Try the longest matching exported pathname. */
251         while (1) {
252                 exp = export_allowed_internal(ai, epath);
253                 if (exp)
254                         return exp;
255                 /* We have to treat the root, "/", specially. */
256                 if (p == &epath[1]) break;
257                 p = strrchr(epath, '/');
258                 if (p == epath) p++;
259                 *p = '\0';
260         }
261
262         return NULL;
263 }
264
265 /*
266  * Search hash table for export entry. 
267  */  
268 nfs_export *
269 export_lookup(char *hname, char *path, int canonical) 
270 {
271         nfs_client *clp;
272         nfs_export *exp;
273         exp_hash_entry *p_hen;
274
275         int pos;
276
277         clp = client_lookup(hname, canonical);
278         if(clp == NULL)
279                 return NULL;
280
281         pos = export_hash(path);
282         p_hen = &(exportlist[clp->m_type].entries[pos]); 
283         for(exp = p_hen->p_first; exp && (exp != p_hen->p_last->m_next); 
284                         exp = exp->m_next) {
285                 if (exp->m_client == clp && !strcmp(exp->m_export.e_path, path)) {
286                         return exp;
287                 }
288         }
289         return NULL;
290 }
291
292 static int
293 export_check(const nfs_export *exp, const struct addrinfo *ai, const char *path)
294 {
295         if (strcmp(path, exp->m_export.e_path))
296                 return 0;
297
298         return client_check(exp->m_client, ai);
299 }
300
301 /**
302  * export_freeall - deallocate all nfs_export records
303  *
304  */
305 void
306 export_freeall(void)
307 {
308         nfs_export      *exp, *nxt;
309         int             i, j;
310
311         for (i = 0; i < MCL_MAXTYPES; i++) {
312                 for (exp = exportlist[i].p_head; exp; exp = nxt) {
313                         nxt = exp->m_next;
314                         client_release(exp->m_client);
315                         export_free(exp);
316                 }
317                 for (j = 0; j < HASH_TABLE_SIZE; j++) {
318                         exportlist[i].entries[j].p_first = NULL;
319                         exportlist[i].entries[j].p_last = NULL;
320                 }
321                 exportlist[i].p_head = NULL;
322         }
323         client_freeall();
324 }
325
326 /*
327  * Compute and returns integer from string. 
328  * Note: Its understood the smae integers can be same for 
329  *       different strings, but it should not matter.
330  */
331 static unsigned int 
332 strtoint(char *str)
333 {
334         int i = 0;
335         unsigned int n = 0;
336
337         while ( str[i] != '\0') {
338                 n+=((int)str[i])*i;
339                 i++;
340         }
341         return n;
342 }
343
344 /*
345  * Hash function
346  */
347 static int 
348 export_hash(char *str)
349 {
350         int num = strtoint(str);
351
352         return num % HASH_TABLE_SIZE;
353 }