xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lib/replica.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * replica.c
24  *
25  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 /*
30  * Parse replicated server lists of the form:
31  *
32  *	host1:/path1,host2,host3,host4:/path2,host5:/path3
33  *
34  * into an array containing its constituent parts:
35  *
36  *	host1	/path1
37  *	host2	/path2
38  *	host3	/path2
39  *	host4	/path2
40  *	host5	/path3
41  * where a server could also be represented in form of literal address
42  * and in case it is an IPv6 literal address it will be enclosed in
43  * square brackets [IPv6 Literal address]
44  * Problems indicated by null return; they will be memory allocation
45  * errors worthy of an error message unless count == -1, which means
46  * a parse error.
47  */
48 
49 #include <stdio.h>
50 #include <malloc.h>
51 #include <string.h>
52 #include <strings.h>
53 #include <sys/types.h>
54 #include <errno.h>
55 #include "replica.h"
56 
57 void
58 free_replica(struct replica *list, int count)
59 {
60 	int i;
61 
62 	for (i = 0; i < count; i++) {
63 		if (list[i].host)
64 			free(list[i].host);
65 		if (list[i].path)
66 			free(list[i].path);
67 	}
68 	free(list);
69 }
70 
71 struct replica *
72 parse_replica(char *special, int *count)
73 {
74 	struct replica *list = NULL;
75 	char *root, *special2;
76 	char *proot, *x, *y;
77 	int scount, v6addr, i;
78 	int found_colon = 0;
79 
80 	*count = 0;
81 	scount = 0;
82 	v6addr = 0;
83 	root = special2 = strdup(special);
84 	proot = root;
85 
86 	while (root) {
87 		switch (*root) {
88 		case '[':
89 			if ((root != special2) && (*(root -1) != ',')) {
90 				root++;
91 				break;
92 			}
93 			y = strchr(root, ']');
94 			if (!y) {
95 				root++;
96 				break;
97 			}
98 			if ((*(y + 1) != ',') && (*(y + 1) != ':')) {
99 				root = y + 1;
100 				break;
101 			}
102 			/*
103 			 * Found a v6 Literal Address, so set "v6addr"
104 			 * and grab the address and store it in the list
105 			 * under "host part".
106 			 */
107 			proot = root + 1;
108 			root = y + 1;
109 			v6addr = 1;
110 			if ((list = realloc(list, (*count + 1) *
111 			    sizeof (struct replica))) == NULL)
112 				goto bad;
113 			bzero(&list[(*count)++], sizeof (struct replica));
114 			*y = '\0';
115 			list[*count-1].host = strdup(proot);
116 			if (!list[*count-1].host)
117 				goto bad;
118 			break;
119 		case ':':
120 			*root = '\0';
121 			x = root + 1;
122 			/*
123 			 * Find comma (if present), which bounds the path.
124 			 * The comma implies that the user is trying to
125 			 * specify failover syntax if another colon follows.
126 			 */
127 			if (((y = strchr(x, ',')) != NULL) &&
128 			    (strchr((y + 1), ':'))) {
129 				root = y + 1;
130 				*y = '\0';
131 			} else {
132 				found_colon = 1;
133 				root = NULL;
134 			}
135 			/*
136 			 * If "v6addr" is set, unset it, and since the "host
137 			 * part" is already taken care of, skip to the "path
138 			 * path" part.
139 			 */
140 			if (v6addr == 1)
141 				v6addr = 0;
142 			else {
143 				if ((list = realloc(list, (*count + 1) *
144 				    sizeof (struct replica))) == NULL)
145 					goto bad;
146 				bzero(&list[(*count)++],
147 				    sizeof (struct replica));
148 				list[*count-1].host = strdup(proot);
149 				if (!list[*count-1].host)
150 					goto bad;
151 				proot = root;
152 
153 			}
154 			for (i = scount; i < *count; i++) {
155 				list[i].path = strdup(x);
156 				if (!list[i].path)
157 					goto bad;
158 			}
159 			scount = i;
160 			proot = root;
161 			if (y)
162 				*y = ',';
163 			break;
164 		case ',':
165 			/*
166 			 * If "v6addr" is set, unset it and continue
167 			 * else grab the address and store it in the list
168 			 * under "host part".
169 			 */
170 			if (v6addr == 1) {
171 				v6addr = 0;
172 				proot = ++root;
173 			} else {
174 				*root = '\0';
175 				root++;
176 				if ((list = realloc(list, (*count + 1) *
177 				    sizeof (struct replica))) == NULL)
178 					goto bad;
179 				bzero(&list[(*count)++],
180 				    sizeof (struct replica));
181 				list[*count-1].host = strdup(proot);
182 				if (!list[*count-1].host)
183 					goto bad;
184 				proot = root;
185 				*(root - 1) = ',';
186 			}
187 			break;
188 		default:
189 			if (*root == '\0')
190 				root = NULL;
191 			else
192 				root++;
193 		}
194 	}
195 	if (found_colon) {
196 		free(special2);
197 		return (list);
198 	}
199 bad:
200 	if (list)
201 		free_replica(list, *count);
202 	if (!found_colon)
203 		*count = -1;
204 	free(special2);
205 	return (NULL);
206 }
207