Make warning about host matching multiple exports more helpful.
[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 nfs_export      *exportlist[MCL_MAXTYPES] = { NULL, };
23
24 static void     export_init(nfs_export *exp, nfs_client *clp,
25                                         struct exportent *nep);
26 static int      export_check(nfs_export *, struct hostent *, char *);
27 static nfs_export *
28                 export_allowed_internal(struct hostent *hp, char *path);
29
30 int
31 export_read(char *fname)
32 {
33         struct exportent        *eep;
34         nfs_export              *exp;
35
36         setexportent(fname, "r");
37         while ((eep = getexportent(0,1)) != NULL) {
38           exp = export_lookup(eep->e_hostname, eep->e_path, 0);
39           if (!exp)
40             export_create(eep,0);
41           else {
42             if (exp->m_export.e_flags != eep->e_flags) {
43               xlog(L_ERROR, "incompatible duplicated export entries:");
44               xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname,
45                    eep->e_path, eep->e_flags);
46               xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname,
47                    exp->m_export.e_path, exp->m_export.e_flags);
48             }
49             else {
50               xlog(L_ERROR, "duplicated export entries:");
51               xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path);
52               xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname,
53                    exp->m_export.e_path);
54             }
55           }
56         }
57         endexportent();
58
59         return 0;
60 }
61
62 /*
63  * Create an in-core export struct from an export entry.
64  */
65 nfs_export *
66 export_create(struct exportent *xep, int canonical)
67 {
68         nfs_client      *clp;
69         nfs_export      *exp;
70
71         if (!(clp = client_lookup(xep->e_hostname, canonical))) {
72                 /* bad export entry; complaint already logged */
73                 return NULL;
74         }
75         exp = (nfs_export *) xmalloc(sizeof(*exp));
76         export_init(exp, clp, xep);
77         export_add(exp);
78
79         return exp;
80 }
81
82 static void
83 export_init(nfs_export *exp, nfs_client *clp, struct exportent *nep)
84 {
85         struct exportent        *e = &exp->m_export;
86
87         dupexportent(e, nep);
88
89         exp->m_exported = 0;
90         exp->m_xtabent = 0;
91         exp->m_mayexport = 0;
92         exp->m_changed = 0;
93         exp->m_warned = 0;
94         exp->m_client = clp;
95         clp->m_count++;
96 }
97
98 /*
99  * Duplicate exports data. The in-core export struct retains the
100  * original hostname from /etc/exports, while the in-core client struct
101  * gets the newly found FQDN.
102  */
103 nfs_export *
104 export_dup(nfs_export *exp, struct hostent *hp)
105 {
106         nfs_export              *new;
107         nfs_client              *clp;
108
109         new = (nfs_export *) xmalloc(sizeof(*new));
110         memcpy(new, exp, sizeof(*new));
111         dupexportent(&new->m_export, &exp->m_export);
112         clp = client_dup(exp->m_client, hp);
113         clp->m_count++;
114         new->m_client = clp;
115         new->m_mayexport = exp->m_mayexport;
116         new->m_exported = 0;
117         new->m_xtabent = 0;
118         new->m_changed = 0;
119         new->m_warned = 0;
120         export_add(new);
121
122         return new;
123 }
124
125 void
126 export_add(nfs_export *exp)
127 {
128         nfs_export      **epp;
129         int             type = exp->m_client->m_type;
130         int             slen = strlen(exp->m_export.e_path);
131
132         if (type < 0 || type >= MCL_MAXTYPES)
133                 xlog(L_FATAL, "unknown client type in export_add");
134
135         epp = exportlist + type;
136         while (*epp && slen <= strlen((*epp)->m_export.e_path))
137                 epp = &((*epp)->m_next);
138         exp->m_next = *epp;
139         *epp = exp;
140 }
141
142 nfs_export *
143 export_find(struct hostent *hp, char *path)
144 {
145         nfs_export      *exp;
146         int             i;
147
148         for (i = 0; i < MCL_MAXTYPES; i++) {
149                 for (exp = exportlist[i]; exp; exp = exp->m_next) {
150                         if (!export_check(exp, hp, path))
151                                 continue;
152                         if (exp->m_client->m_type == MCL_FQDN)
153                                 return exp;
154                         return export_dup(exp, hp);
155                 }
156         }
157
158         return NULL;
159 }
160
161 static nfs_export *
162 export_allowed_internal (struct hostent *hp, char *path)
163 {
164         nfs_export      *exp;
165         int             i;
166
167         for (i = 0; i < MCL_MAXTYPES; i++) {
168                 for (exp = exportlist[i]; exp; exp = exp->m_next) {
169                         if (!exp->m_mayexport ||
170                             !export_check(exp, hp, path))
171                                 continue;
172                         return exp;
173                 }
174         }
175
176         return NULL;
177 }
178
179 nfs_export *
180 export_allowed(struct hostent *hp, char *path)
181 {
182         nfs_export              *exp;
183         char                    epath[MAXPATHLEN+1];
184         char                    *p = NULL;
185
186         if (path [0] != '/') return NULL;
187
188         strncpy(epath, path, sizeof (epath) - 1);
189         epath[sizeof (epath) - 1] = '\0';
190
191         /* Try the longest matching exported pathname. */
192         while (1) {
193                 exp = export_allowed_internal (hp, epath);
194                 if (exp)
195                         return exp;
196                 /* We have to treat the root, "/", specially. */
197                 if (p == &epath[1]) break;
198                 p = strrchr(epath, '/');
199                 if (p == epath) p++;
200                 *p = '\0';
201         }
202
203         return NULL;
204 }
205
206 nfs_export *
207 export_lookup(char *hname, char *path, int canonical)
208 {
209         nfs_client      *clp;
210         nfs_export      *exp;
211
212         if (!(clp = client_lookup(hname, canonical)))
213                 return NULL;
214         for (exp = exportlist[clp->m_type]; exp; exp = exp->m_next)
215                 if (exp->m_client == clp && !strcmp(exp->m_export.e_path, path))
216                         return exp;
217         return NULL;
218 }
219
220 static int
221 export_check(nfs_export *exp, struct hostent *hp, char *path)
222 {
223         if (strcmp(path, exp->m_export.e_path))
224                 return 0;
225
226         return client_check(exp->m_client, hp);
227 }
228
229 void
230 export_freeall(void)
231 {
232         nfs_export      *exp, *nxt;
233         int             i;
234
235         for (i = 0; i < MCL_MAXTYPES; i++) {
236                 for (exp = exportlist[i]; exp; exp = nxt) {
237                         nxt = exp->m_next;
238                         client_release(exp->m_client);
239                         if (exp->m_export.e_squids)
240                                 xfree(exp->m_export.e_squids);
241                         if (exp->m_export.e_sqgids)
242                                 xfree(exp->m_export.e_sqgids);
243                         if (exp->m_export.e_mountpoint)
244                                 free(exp->m_export.e_mountpoint);
245                         if (exp->m_export.e_fslocdata)
246                                 xfree(exp->m_export.e_fslocdata);
247                         xfree(exp);
248                 }
249                 exportlist[i] = NULL;
250         }
251         client_freeall();
252 }
253
254 void
255 export_reset(nfs_export *exp)
256 {
257         if (!exp)
258                 return;
259
260         /* Restore m_path. */
261         strncpy(exp->m_export.m_path, exp->m_export.e_path,
262                 sizeof (exp->m_export.m_path) - 1);
263         exp->m_export.m_path[sizeof (exp->m_export.m_path) - 1] = '\0';
264 }