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