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
free_replica(struct replica * list,int count)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 *
parse_replica(char * special,int * count)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