mountd: Convert colons in IPv6 presentation addresses tosemicolons
[nfs-utils.git] / support / nfs / rmtab.c
1 /*
2  * support/nfs/rmtab.c
3  *
4  * Handling for rmtab.
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 <stdlib.h>
15 #include <string.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <errno.h>
19 #include <signal.h>
20 #include "nfslib.h"
21
22 /*
23  * Colons in incoming IPv6 presentation addresses have to
24  * replaced with another character, since rmtab already
25  * uses colons to delineate fields.
26  *
27  * Use a printable character, but one that would never be
28  * found in a presentation address or domain name
29  */
30 #define IPV6_COLON      ';'
31
32 #define LINELEN         (2048)
33
34 static FILE     *rmfp = NULL;
35
36 int
37 setrmtabent(char *type)
38 {
39         if (rmfp)
40                 fclose(rmfp);
41         rmfp = fsetrmtabent(_PATH_RMTAB, type);
42         return (rmfp != NULL);
43 }
44
45 FILE *
46 fsetrmtabent(char *fname, char *type)
47 {
48         int     readonly = !strcmp(type, "r");
49         FILE    *fp;
50
51         if (!fname)
52                 return NULL;
53         if ((fp = fopen(fname, type)) == NULL) {
54                 xlog(L_ERROR, "can't open %s for %sing", fname,
55                                 readonly ? "read" : "writ");
56                 return NULL;
57         }
58         return fp;
59 }
60
61 struct rmtabent *
62 getrmtabent(int log, long *pos)
63 {
64         return fgetrmtabent(rmfp, log, pos);
65 }
66
67 struct rmtabent *
68 fgetrmtabent(FILE *fp, int log, long *pos)
69 {
70         static struct rmtabent  re;
71         char            *count, *host, *path, *c;
72         static char     buf[LINELEN];
73
74         errno = 0;
75         if (!fp)
76                 return NULL;
77         do {
78                 if (pos)
79                         *pos = ftell (fp);
80                 if (fgets(buf, sizeof(buf)-1, fp) == NULL)
81                         return NULL;
82                 host = buf;
83                 if ((path = strchr(host, '\n')) != NULL)
84                         *path = '\0';
85                 if (!(path = strchr(host, ':'))) {
86                         if (log)
87                                 xlog(L_ERROR, "malformed entry in rmtab file");
88                         errno = EINVAL;
89                         return NULL;
90                 }
91                 *path++ = '\0';
92                 count = strchr(path, ':');
93                 if (count) {
94                         *count++ = '\0';
95                         re.r_count = strtol (count, NULL, 0);
96                 }
97                 else
98                         re.r_count = 1;
99         } while (0);
100
101         strncpy(re.r_client, host, sizeof (re.r_client) - 1);
102         re.r_client[sizeof (re.r_client) - 1] = '\0';
103         for (c = re.r_client; *c != '\0'; c++)
104                 if (*c == IPV6_COLON)
105                         *c = ':';
106
107         strncpy(re.r_path, path, sizeof (re.r_path) - 1);
108         re.r_path[sizeof (re.r_path) - 1] = '\0';
109
110         return &re;
111 }
112
113 void
114 putrmtabent(struct rmtabent *rep, long *pos)
115 {
116         fputrmtabent(rmfp, rep, pos);
117 }
118
119 void
120 fputrmtabent(FILE *fp, struct rmtabent *rep, long *pos)
121 {
122         static char     buf[LINELEN];
123         char            *c;
124
125         if (!fp || (pos && fseek (fp, *pos, SEEK_SET) != 0))
126                 return;
127
128         /*
129          * To avoid confusing the token parser in fgetrmtabent(),
130          * convert colons in incoming IPv6 presentation addresses
131          * to semicolons.
132          */
133         if (strlen(rep->r_client) > sizeof(buf)) {
134                 xlog(L_ERROR, "client name too large");
135                 return;
136         }
137         strncpy(buf, rep->r_client, sizeof(buf));
138         for (c = buf; *c != '\0'; c++)
139                 if (*c == ':')
140                         *c = IPV6_COLON;
141
142         (void)fprintf(fp, "%s:%s:0x%.8x\n", buf, rep->r_path, rep->r_count);
143 }
144
145 void
146 endrmtabent(void)
147 {
148         fendrmtabent(rmfp);
149         rmfp = NULL;
150 }
151
152 void
153 fendrmtabent(FILE *fp)
154 {
155         if (fp) {
156                 static int have_new_cache = -1;
157                 if (have_new_cache == -1) /* check only once */
158                         have_new_cache = check_new_cache();
159
160                 if (!have_new_cache) {
161                         /*
162                          * If we are using the old caching interface: exportfs
163                          * uses the rmtab to determine what should be exported,
164                          * so it is important that it be up-to-date.
165                          *
166                          * If we are using the new caching interface: the rmtab
167                          * is ignored by exportfs and the fdatasync only serves
168                          * to slow us down.
169                          */
170                         fflush(fp);
171                         fdatasync(fileno(fp));
172                 }
173
174                 fclose(fp);
175         }
176 }
177
178 void
179 rewindrmtabent(void)
180 {
181         if (rmfp)
182                 rewind(rmfp);
183 }
184
185 void
186 frewindrmtabent(FILE *fp)
187 {
188         if (fp)
189                 rewind (fp);
190 }