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