xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lib/replica.c (revision 8b80e8cb6855118d46f605e91b5ed4ce83417395)
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 #pragma ident	"%Z%%M%	%I%	%E% SMI"
50 
51 #include <stdio.h>
52 #include <malloc.h>
53 #include <string.h>
54 #include <strings.h>
55 #include <sys/types.h>
56 #include <errno.h>
57 #include "replica.h"
58 
59 void
60 free_replica(struct replica *list, int count)
61 {
62 	int i;
63 
64 	for (i = 0; i < count; i++) {
65 		if (list[i].host)
66 			free(list[i].host);
67 		if (list[i].path)
68 			free(list[i].path);
69 	}
70 	free(list);
71 }
72 
73 struct replica *
74 parse_replica(char *special, int *count)
75 {
76 	struct replica *list = NULL;
77 	char *root, *special2;
78 	char *proot, *x, *y;
79 	int scount, v6addr, i;
80 	int found_colon = 0;
81 
82 	*count = 0;
83 	scount = 0;
84 	v6addr = 0;
85 	root = special2 = strdup(special);
86 	proot = root;
87 
88 	while (root) {
89 		switch (*root) {
90 		case '[':
91 			if ((root != special2) && (*(root -1) != ',')) {
92 				root++;
93 				break;
94 			}
95 			y = strchr(root, ']');
96 			if (!y) {
97 				root++;
98 				break;
99 			}
100 			if ((*(y + 1) != ',') && (*(y + 1) != ':')) {
101 				root = y + 1;
102 				break;
103 			}
104 			/*
105 			 * Found a v6 Literal Address, so set "v6addr"
106 			 * and grab the address and store it in the list
107 			 * under "host part".
108 			 */
109 			proot = root + 1;
110 			root = y + 1;
111 			v6addr = 1;
112 			if ((list = realloc(list, (*count + 1) *
113 			    sizeof (struct replica))) == NULL)
114 				goto bad;
115 			bzero(&list[(*count)++], sizeof (struct replica));
116 			*y = '\0';
117 			list[*count-1].host = strdup(proot);
118 			if (!list[*count-1].host)
119 				goto bad;
120 			break;
121 		case ':':
122 			*root = '\0';
123 			x = root + 1;
124 			/*
125 			 * Find comma (if present), which bounds the path.
126 			 * The comma implies that the user is trying to
127 			 * specify failover syntax if another colon follows.
128 			 */
129 			if (((y = strchr(x, ',')) != NULL) &&
130 			    (strchr((y + 1), ':'))) {
131 				root = y + 1;
132 				*y = '\0';
133 			} else {
134 				found_colon = 1;
135 				root = NULL;
136 			}
137 			/*
138 			 * If "v6addr" is set, unset it, and since the "host
139 			 * part" is already taken care of, skip to the "path
140 			 * path" part.
141 			 */
142 			if (v6addr == 1)
143 				v6addr = 0;
144 			else {
145 				if ((list = realloc(list, (*count + 1) *
146 				    sizeof (struct replica))) == NULL)
147 					goto bad;
148 				bzero(&list[(*count)++],
149 				    sizeof (struct replica));
150 				list[*count-1].host = strdup(proot);
151 				if (!list[*count-1].host)
152 					goto bad;
153 				proot = root;
154 
155 			}
156 			for (i = scount; i < *count; i++) {
157 				list[i].path = strdup(x);
158 				if (!list[i].path)
159 					goto bad;
160 			}
161 			scount = i;
162 			proot = root;
163 			if (y)
164 				*y = ',';
165 			break;
166 		case ',':
167 			/*
168 			 * If "v6addr" is set, unset it and continue
169 			 * else grab the address and store it in the list
170 			 * under "host part".
171 			 */
172 			if (v6addr == 1) {
173 				v6addr = 0;
174 				proot = ++root;
175 			} else {
176 				*root = '\0';
177 				root++;
178 				if ((list = realloc(list, (*count + 1) *
179 				    sizeof (struct replica))) == NULL)
180 					goto bad;
181 				bzero(&list[(*count)++],
182 				    sizeof (struct replica));
183 				list[*count-1].host = strdup(proot);
184 				if (!list[*count-1].host)
185 					goto bad;
186 				proot = root;
187 				*(root - 1) = ',';
188 			}
189 			break;
190 		default:
191 			if (*root == '\0')
192 				root = NULL;
193 			else
194 				root++;
195 		}
196 	}
197 	if (found_colon) {
198 		free(special2);
199 		return (list);
200 	}
201 bad:
202 	if (list)
203 		free_replica(list, *count);
204 	if (!found_colon)
205 		*count = -1;
206 	free(special2);
207 	return (NULL);
208 }
209