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
59void
60free_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
73struct replica *
74parse_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	}
201bad:
202	if (list)
203		free_replica(list, *count);
204	if (!found_colon)
205		*count = -1;
206	free(special2);
207	return (NULL);
208}
209