utils: Return status 0 on clean exits
[nfs-utils.git] / utils / mountd / fsloc.c
1 /*
2  * COPYRIGHT (c) 2006
3  * THE REGENTS OF THE UNIVERSITY OF MICHIGAN
4  * ALL RIGHTS RESERVED
5  *
6  * Permission is granted to use, copy, create derivative works
7  * and redistribute this software and such derivative works
8  * for any purpose, so long as the name of The University of
9  * Michigan is not used in any advertising or publicity
10  * pertaining to the use of distribution of this software
11  * without specific, written prior authorization.  If the
12  * above copyright notice or any other identification of the
13  * University of Michigan is included in any copy of any
14  * portion of this software, then the disclaimer below must
15  * also be included.
16  *
17  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
18  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
19  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
20  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
21  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
23  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
25  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
26  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
27  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGES.
29  */
30
31 #include <stdlib.h>
32 #include <string.h>
33 #include <syslog.h>
34
35 #include "fsloc.h"
36 #include "exportfs.h"
37
38 /* Debugging tool: prints out @servers info to syslog */
39 static void replicas_print(struct servers *sp)
40 {
41         int i;
42         if (!sp) {
43                 xlog(L_NOTICE, "NULL replicas pointer");
44                 return;
45         }
46         xlog(L_NOTICE, "replicas listsize=%i", sp->h_num);
47         for (i=0; i<sp->h_num; i++) {
48                 xlog(L_NOTICE, "    %s:%s",
49                        sp->h_mp[i]->h_host, sp->h_mp[i]->h_path);
50         }
51 }
52
53 #ifdef DEBUG
54 /* Called by setting 'Method = stub' in config file.  Just returns
55  * some syntactically correct gibberish for testing purposes.
56  */
57 static struct servers *method_stub(char *key)
58 {
59         struct servers *sp;
60         struct mount_point *mp;
61
62         xlog(L_NOTICE, "called method_stub\n");
63         sp = malloc(sizeof(struct servers));
64         if (!sp)
65                 return NULL;
66         mp = calloc(1, sizeof(struct mount_point));
67         if (!mp) {
68                 free(sp);
69                 return NULL;
70         }
71         sp->h_num = 1;
72         sp->h_mp[0] = mp;
73         mp->h_host = strdup("stub_server");
74         mp->h_path = strdup("/my/test/path");
75         sp->h_referral = 1;
76         return sp;
77 }
78 #endif  /* DEBUG */
79
80 /* Scan @list, which is a NULL-terminated array of strings of the
81  * form path@host[+host], and return corresponding servers structure.
82  */
83 static struct servers *parse_list(char **list)
84 {
85         int i;
86         struct servers *res;
87         struct mount_point *mp;
88         char *cp;
89
90         res = malloc(sizeof(struct servers));
91         if (!res)
92                 return NULL;
93         res->h_num = 0;
94
95         /* parse each of the answers in sucession. */
96         for (i=0; list[i] && i<FSLOC_MAX_LIST; i++) {
97                 mp = calloc(1, sizeof(struct mount_point));
98                 if (!mp) {
99                         release_replicas(res);
100                         return NULL;
101                 }
102                 cp = strchr(list[i], '@');
103                 if ((!cp) || list[i][0] != '/') {
104                         xlog(L_WARNING, "invalid entry '%s'", list[i]);
105                         continue; /* XXX Need better error handling */
106                 }
107                 res->h_mp[i] = mp;
108                 res->h_num++;
109                 mp->h_path = strndup(list[i], cp - list[i]);
110                 cp++;
111                 mp->h_host = strdup(cp);
112                 /* hosts are '+' separated, kernel expects ':' separated */
113                 while ( (cp = strchr(mp->h_host, '+')) )
114                        *cp = ':';
115         }
116         return res;
117 }
118
119 /* @data is a string of form path@host[+host][:path@host[+host]]
120  */
121 static struct servers *method_list(char *data)
122 {
123         char *copy, *ptr=data, *p;
124         char **list;
125         int i, listsize;
126         struct servers *rv=NULL;
127         bool v6esc = false;
128
129         xlog(L_NOTICE, "method_list(%s)", data);
130         for (ptr--, listsize=1; ptr; ptr=index(ptr, ':'), listsize++)
131                 ptr++;
132         list = malloc(listsize * sizeof(char *));
133         copy = strdup(data);
134         if (copy)
135                 xlog(L_NOTICE, "converted to %s", copy);
136         if (list && copy) {
137                 ptr = copy;
138                 for (p = ptr, i = 0; *p && i < listsize; p++) {
139                         if (*p == '[')
140                                 v6esc = true;
141                         else if (*p == ']')
142                                 v6esc = false;
143
144                         if (!v6esc && *p == ':') {
145                                 *p = '\0';
146                                 if (*ptr)
147                                         list[i++] = ptr;
148                                 ptr = p + 1;
149                         }
150                 }
151                 if (*ptr)
152                         list[i++] = ptr;
153                 list[i] = NULL;
154                 rv = parse_list(list);
155         }
156         free(copy);
157         free(list);
158         replicas_print(rv);
159         return rv;
160 }
161
162 /* Returns appropriately filled struct servers, or NULL if had a problem */
163 struct servers *replicas_lookup(int method, char *data)
164 {
165         struct servers *sp=NULL;
166         switch(method) {
167         case FSLOC_NONE:
168                 break;
169         case FSLOC_REFER:
170                 sp = method_list(data);
171                 if (sp)
172                         sp->h_referral = 1;
173                 break;
174         case FSLOC_REPLICA:
175                 sp = method_list(data);
176                 if (sp)
177                         sp->h_referral = 0;
178                 break;
179 #ifdef DEBUG
180         case FSLOC_STUB:
181                 sp = method_stub(data);
182                 break;
183 #endif
184         default:
185                 xlog(L_WARNING, "Unknown method = %i", method);
186         }
187         replicas_print(sp);
188         return sp;
189 }
190
191 void release_replicas(struct servers *server)
192 {
193         int i;
194
195         if (!server) return;
196         for (i = 0; i < server->h_num; i++) {
197                 free(server->h_mp[i]->h_host);
198                 free(server->h_mp[i]->h_path);
199                 free(server->h_mp[i]);
200         }
201         free(server);
202 }