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