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