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