libexport.a: Add export_free()
[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         clp->m_count++;
133         new->m_client = clp;
134         new->m_mayexport = exp->m_mayexport;
135         new->m_exported = 0;
136         new->m_xtabent = 0;
137         new->m_changed = 0;
138         new->m_warned = 0;
139         export_add(new);
140
141         return new;
142 }
143
144 /*
145  * Add export entry to hash table
146  */
147 void 
148 export_add(nfs_export *exp)
149 {
150         exp_hash_table *p_tbl;
151         exp_hash_entry *p_hen;
152         nfs_export *p_next;
153
154         int type = exp->m_client->m_type;
155         int pos;
156
157         pos = export_hash(exp->m_export.e_path);
158         p_tbl = &(exportlist[type]); /* pointer to hash table */
159         p_hen = &(p_tbl->entries[pos]); /* pointer to hash table entry */
160
161         if (!(p_hen->p_first)) { /* hash table entry is empty */ 
162                 p_hen->p_first = exp;
163                 p_hen->p_last  = exp;
164
165                 exp->m_next = p_tbl->p_head;
166                 p_tbl->p_head = exp;
167         } else { /* hash table entry is NOT empty */
168                 p_next = p_hen->p_last->m_next;
169                 p_hen->p_last->m_next = exp;
170                 exp->m_next = p_next;
171                 p_hen->p_last = exp;
172         }
173 }
174
175 nfs_export *
176 export_find(struct hostent *hp, char *path)
177 {
178         nfs_export      *exp;
179         int             i;
180
181         for (i = 0; i < MCL_MAXTYPES; i++) {
182                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
183                         if (!export_check(exp, hp, path))
184                                 continue;
185                         if (exp->m_client->m_type == MCL_FQDN)
186                                 return exp;
187                         return export_dup(exp, hp);
188                 }
189         }
190
191         return NULL;
192 }
193
194 static nfs_export *
195 export_allowed_internal (struct hostent *hp, char *path)
196 {
197         nfs_export      *exp;
198         int             i;
199
200         for (i = 0; i < MCL_MAXTYPES; i++) {
201                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
202                         if (!exp->m_mayexport ||
203                             !export_check(exp, hp, path))
204                                 continue;
205                         return exp;
206                 }
207         }
208
209         return NULL;
210 }
211
212 nfs_export *
213 export_allowed(struct hostent *hp, char *path)
214 {
215         nfs_export              *exp;
216         char                    epath[MAXPATHLEN+1];
217         char                    *p = NULL;
218
219         if (path [0] != '/') return NULL;
220
221         strncpy(epath, path, sizeof (epath) - 1);
222         epath[sizeof (epath) - 1] = '\0';
223
224         /* Try the longest matching exported pathname. */
225         while (1) {
226                 exp = export_allowed_internal (hp, epath);
227                 if (exp)
228                         return exp;
229                 /* We have to treat the root, "/", specially. */
230                 if (p == &epath[1]) break;
231                 p = strrchr(epath, '/');
232                 if (p == epath) p++;
233                 *p = '\0';
234         }
235
236         return NULL;
237 }
238
239 /*
240  * Search hash table for export entry. 
241  */  
242 nfs_export *
243 export_lookup(char *hname, char *path, int canonical) 
244 {
245         nfs_client *clp;
246         nfs_export *exp;
247         exp_hash_entry *p_hen;
248
249         int pos;
250
251         clp = client_lookup(hname, canonical);
252         if(clp == NULL)
253                 return NULL;
254
255         pos = export_hash(path);
256         p_hen = &(exportlist[clp->m_type].entries[pos]); 
257         for(exp = p_hen->p_first; exp && (exp != p_hen->p_last->m_next); 
258                         exp = exp->m_next) {
259                 if (exp->m_client == clp && !strcmp(exp->m_export.e_path, path)) {
260                         return exp;
261                 }
262         }
263         return NULL;
264 }
265
266 static int
267 export_check(nfs_export *exp, struct hostent *hp, char *path)
268 {
269         if (strcmp(path, exp->m_export.e_path))
270                 return 0;
271
272         return client_check(exp->m_client, hp);
273 }
274
275 /**
276  * export_freeall - deallocate all nfs_export records
277  *
278  */
279 void
280 export_freeall(void)
281 {
282         nfs_export      *exp, *nxt;
283         int             i, j;
284
285         for (i = 0; i < MCL_MAXTYPES; i++) {
286                 for (exp = exportlist[i].p_head; exp; exp = nxt) {
287                         nxt = exp->m_next;
288                         client_release(exp->m_client);
289                         export_free(exp);
290                 }
291                 for (j = 0; j < HASH_TABLE_SIZE; j++) {
292                         exportlist[i].entries[j].p_first = NULL;
293                         exportlist[i].entries[j].p_last = NULL;
294                 }
295                 exportlist[i].p_head = NULL;
296         }
297         client_freeall();
298 }
299
300 /*
301  * Compute and returns integer from string. 
302  * Note: Its understood the smae integers can be same for 
303  *       different strings, but it should not matter.
304  */
305 static unsigned int 
306 strtoint(char *str)
307 {
308         int i = 0;
309         unsigned int n = 0;
310
311         while ( str[i] != '\0') {
312                 n+=((int)str[i])*i;
313                 i++;
314         }
315         return n;
316 }
317
318 /*
319  * Hash function
320  */
321 static int 
322 export_hash(char *str)
323 {
324         int num = strtoint(str);
325
326         return num % HASH_TABLE_SIZE;
327 }