libexport.a: Allow client_init() to fail instead of exit
[nfs-utils.git] / support / export / xtab.c
1 /*
2  * support/export/xtab.c
3  *
4  * Interface to the xtab file.
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 <sys/fcntl.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include "xmalloc.h"
18 #include "nfslib.h"
19 #include "exportfs.h"
20 #include "xio.h"
21 #include "xlog.h"
22 #include "v4root.h"
23
24 int v4root_needed;
25 static void cond_rename(char *newfile, char *oldfile);
26
27 static int
28 xtab_read(char *xtab, char *lockfn, int is_export)
29 {
30     /* is_export == 0  => reading /proc/fs/nfs/exports - we know these things are exported to kernel
31      * is_export == 1  => reading /var/lib/nfs/etab - these things are allowed to be exported
32      * is_export == 2  => reading /var/lib/nfs/xtab - these things might be known to kernel
33      */
34         struct exportent        *xp;
35         nfs_export              *exp;
36         int                     lockid;
37
38         if ((lockid = xflock(lockfn, "r")) < 0)
39                 return 0;
40         setexportent(xtab, "r");
41         if (is_export == 1)
42                 v4root_needed = 1;
43         while ((xp = getexportent(is_export==0, 0)) != NULL) {
44                 if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) &&
45                     !(exp = export_create(xp, is_export!=1))) {
46                         continue;
47                 }
48                 switch (is_export) {
49                 case 0:
50                         exp->m_exported = 1;
51                         break;
52                 case 1:
53                         exp->m_xtabent = 1;
54                         exp->m_mayexport = 1;
55                         if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0)
56                                 v4root_needed = 0;
57                         break;
58                 case 2:
59                         exp->m_exported = -1;/* may be exported */
60                         break;
61                 }
62         }
63         endexportent();
64         xfunlock(lockid);
65
66         return 0;
67 }
68
69 int
70 xtab_mount_read(void)
71 {
72         int fd;
73         if ((fd=open(_PATH_PROC_EXPORTS, O_RDONLY))>=0) {
74                 close(fd);
75                 return xtab_read(_PATH_PROC_EXPORTS,
76                                  _PATH_PROC_EXPORTS, 0);
77         } else if ((fd=open(_PATH_PROC_EXPORTS_ALT, O_RDONLY) >= 0)) {
78                 close(fd);
79                 return xtab_read(_PATH_PROC_EXPORTS_ALT,
80                                  _PATH_PROC_EXPORTS_ALT, 0);
81         } else
82                 return xtab_read(_PATH_XTAB, _PATH_XTABLCK, 2);
83 }
84
85 int
86 xtab_export_read(void)
87 {
88         return xtab_read(_PATH_ETAB, _PATH_ETABLCK, 1);
89 }
90
91 /*
92  * mountd now keeps an open fd for the etab at all times to make sure that the
93  * inode number changes when the xtab_export_write is done. If you change the
94  * routine below such that the files are edited in place, then you'll need to
95  * fix the auth_reload logic as well...
96  */
97 static int
98 xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export)
99 {
100         struct exportent        xe;
101         nfs_export              *exp;
102         int                     lockid, i;
103
104         if ((lockid = xflock(lockfn, "w")) < 0) {
105                 xlog(L_ERROR, "can't lock %s for writing", xtab);
106                 return 0;
107         }
108         setexportent(xtabtmp, "w");
109
110         for (i = 0; i < MCL_MAXTYPES; i++) {
111                 for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
112                         if (is_export && !exp->m_xtabent)
113                                 continue;
114                         if (!is_export && ! exp->m_exported)
115                                 continue;
116
117                         /* write out the export entry using the FQDN */
118                         xe = exp->m_export;
119                         xe.e_hostname = exp->m_client->m_hostname;
120                         putexportent(&xe);
121                 }
122         }
123         endexportent();
124
125         cond_rename(xtabtmp, xtab);
126
127         xfunlock(lockid);
128
129         return 1;
130 }
131
132 int
133 xtab_export_write()
134 {
135         return xtab_write(_PATH_ETAB, _PATH_ETABTMP, _PATH_ETABLCK, 1);
136 }
137
138 int
139 xtab_mount_write()
140 {
141         return xtab_write(_PATH_XTAB, _PATH_XTABTMP, _PATH_XTABLCK, 0);
142 }
143
144 void
145 xtab_append(nfs_export *exp)
146 {
147         struct exportent xe;
148         int             lockid;
149
150         if ((lockid = xflock(_PATH_XTABLCK, "w")) < 0)
151                 return;
152         setexportent(_PATH_XTAB, "a");
153         xe = exp->m_export;
154         xe.e_hostname = exp->m_client->m_hostname;
155         putexportent(&xe);
156         endexportent();
157         xfunlock(lockid);
158         exp->m_xtabent = 1;
159 }
160
161 /*
162  * rename newfile onto oldfile unless
163  * they are identical
164  */
165 static void cond_rename(char *newfile, char *oldfile)
166 {
167         int nfd, ofd;
168         char nbuf[4096], obuf[4096];
169         int ncnt, ocnt;
170
171         nfd = open(newfile, 0);
172         if (nfd < 0)
173                 return;
174         ofd = open(oldfile, 0);
175         if (ofd < 0) {
176                 close(nfd);
177                 rename(newfile, oldfile);
178                 return;
179         }
180
181         do {
182                 ncnt = read(nfd, nbuf, sizeof(nbuf));
183                 if (ncnt < 0)
184                         break;
185                 ocnt = read(ofd, obuf, sizeof(obuf));
186                 if (ocnt < 0)
187                         break;
188                 if (ncnt != ocnt)
189                         break;
190                 if (ncnt == 0) {
191                         close(nfd);
192                         close(ofd);
193                         unlink(newfile);
194                         return;
195                 }
196         } while (memcmp(obuf, nbuf, ncnt) == 0);
197
198         /* some mis-match */
199         close(nfd);
200         close(ofd);
201         rename(newfile, oldfile);
202         return;
203 }