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