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