10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * replica.c
240Sstevel@tonic-gate  *
25*312Sfrankho  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
260Sstevel@tonic-gate  * Use is subject to license terms.
270Sstevel@tonic-gate  */
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Parse replicated server lists of the form:
310Sstevel@tonic-gate  *
320Sstevel@tonic-gate  *	host1:/path1,host2,host3,host4:/path2,host5:/path3
330Sstevel@tonic-gate  *
340Sstevel@tonic-gate  * into an array containing its constituent parts:
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  *	host1	/path1
370Sstevel@tonic-gate  *	host2	/path2
380Sstevel@tonic-gate  *	host3	/path2
390Sstevel@tonic-gate  *	host4	/path2
400Sstevel@tonic-gate  *	host5	/path3
410Sstevel@tonic-gate  * where a server could also be represented in form of literal address
420Sstevel@tonic-gate  * and in case it is an IPv6 literal address it will be enclosed in
430Sstevel@tonic-gate  * square brackets [IPv6 Literal address]
440Sstevel@tonic-gate  * Problems indicated by null return; they will be memory allocation
450Sstevel@tonic-gate  * errors worthy of an error message unless count == -1, which means
460Sstevel@tonic-gate  * a parse error.
470Sstevel@tonic-gate  */
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
500Sstevel@tonic-gate 
510Sstevel@tonic-gate #include <stdio.h>
520Sstevel@tonic-gate #include <malloc.h>
530Sstevel@tonic-gate #include <string.h>
54*312Sfrankho #include <strings.h>
550Sstevel@tonic-gate #include <sys/types.h>
560Sstevel@tonic-gate #include <errno.h>
570Sstevel@tonic-gate #include "replica.h"
580Sstevel@tonic-gate 
59*312Sfrankho void
60*312Sfrankho free_replica(struct replica *list, int count)
61*312Sfrankho {
62*312Sfrankho 	int i;
63*312Sfrankho 
64*312Sfrankho 	for (i = 0; i < count; i++) {
65*312Sfrankho 		if (list[i].host)
66*312Sfrankho 			free(list[i].host);
67*312Sfrankho 		if (list[i].path)
68*312Sfrankho 			free(list[i].path);
69*312Sfrankho 	}
70*312Sfrankho 	free(list);
71*312Sfrankho }
72*312Sfrankho 
730Sstevel@tonic-gate struct replica *
740Sstevel@tonic-gate parse_replica(char *special, int *count)
750Sstevel@tonic-gate {
760Sstevel@tonic-gate 	struct replica *list = NULL;
770Sstevel@tonic-gate 	char *root, *special2;
780Sstevel@tonic-gate 	char *proot, *x, *y;
790Sstevel@tonic-gate 	int scount, v6addr, i;
800Sstevel@tonic-gate 	int found_colon = 0;
810Sstevel@tonic-gate 
820Sstevel@tonic-gate 	*count = 0;
830Sstevel@tonic-gate 	scount = 0;
840Sstevel@tonic-gate 	v6addr = 0;
850Sstevel@tonic-gate 	root = special2 = strdup(special);
860Sstevel@tonic-gate 	proot = root;
870Sstevel@tonic-gate 
880Sstevel@tonic-gate 	while (root) {
890Sstevel@tonic-gate 		switch (*root) {
900Sstevel@tonic-gate 		case '[':
910Sstevel@tonic-gate 			if ((root != special2) && (*(root -1) != ',')) {
920Sstevel@tonic-gate 				root++;
930Sstevel@tonic-gate 				break;
940Sstevel@tonic-gate 			}
950Sstevel@tonic-gate 			y = strchr(root, ']');
960Sstevel@tonic-gate 			if (!y) {
970Sstevel@tonic-gate 				root++;
980Sstevel@tonic-gate 				break;
990Sstevel@tonic-gate 			}
1000Sstevel@tonic-gate 			if ((*(y + 1) != ',') && (*(y + 1) != ':')) {
1010Sstevel@tonic-gate 				root = y + 1;
1020Sstevel@tonic-gate 				break;
1030Sstevel@tonic-gate 			}
1040Sstevel@tonic-gate 			/*
1050Sstevel@tonic-gate 			 * Found a v6 Literal Address, so set "v6addr"
1060Sstevel@tonic-gate 			 * and grab the address and store it in the list
1070Sstevel@tonic-gate 			 * under "host part".
1080Sstevel@tonic-gate 			 */
1090Sstevel@tonic-gate 			proot = root + 1;
1100Sstevel@tonic-gate 			root = y + 1;
1110Sstevel@tonic-gate 			v6addr = 1;
112*312Sfrankho 			if ((list = realloc(list, (*count + 1) *
113*312Sfrankho 			    sizeof (struct replica))) == NULL)
1140Sstevel@tonic-gate 				goto bad;
115*312Sfrankho 			bzero(&list[(*count)++], sizeof (struct replica));
1160Sstevel@tonic-gate 			*y = '\0';
1170Sstevel@tonic-gate 			list[*count-1].host = strdup(proot);
1180Sstevel@tonic-gate 			if (!list[*count-1].host)
1190Sstevel@tonic-gate 				goto bad;
1200Sstevel@tonic-gate 			break;
1210Sstevel@tonic-gate 		case ':':
1220Sstevel@tonic-gate 			*root = '\0';
1230Sstevel@tonic-gate 			x = root + 1;
1240Sstevel@tonic-gate 			/*
1250Sstevel@tonic-gate 			 * Find comma (if present), which bounds the path.
1260Sstevel@tonic-gate 			 * The comma implies that the user is trying to
1270Sstevel@tonic-gate 			 * specify failover syntax if another colon follows.
1280Sstevel@tonic-gate 			 */
1290Sstevel@tonic-gate 			if (((y = strchr(x, ',')) != NULL) &&
1300Sstevel@tonic-gate 			    (strchr((y + 1), ':'))) {
1310Sstevel@tonic-gate 				root = y + 1;
1320Sstevel@tonic-gate 				*y = '\0';
1330Sstevel@tonic-gate 			} else {
1340Sstevel@tonic-gate 				found_colon = 1;
1350Sstevel@tonic-gate 				root = NULL;
1360Sstevel@tonic-gate 			}
1370Sstevel@tonic-gate 			/*
1380Sstevel@tonic-gate 			 * If "v6addr" is set, unset it, and since the "host
1390Sstevel@tonic-gate 			 * part" is already taken care of, skip to the "path
1400Sstevel@tonic-gate 			 * path" part.
1410Sstevel@tonic-gate 			 */
1420Sstevel@tonic-gate 			if (v6addr == 1)
1430Sstevel@tonic-gate 				v6addr = 0;
1440Sstevel@tonic-gate 			else {
145*312Sfrankho 				if ((list = realloc(list, (*count + 1) *
146*312Sfrankho 				    sizeof (struct replica))) == NULL)
1470Sstevel@tonic-gate 					goto bad;
148*312Sfrankho 				bzero(&list[(*count)++],
149*312Sfrankho 				    sizeof (struct replica));
1500Sstevel@tonic-gate 				list[*count-1].host = strdup(proot);
1510Sstevel@tonic-gate 				if (!list[*count-1].host)
1520Sstevel@tonic-gate 					goto bad;
1530Sstevel@tonic-gate 				proot = root;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 			}
1560Sstevel@tonic-gate 			for (i = scount; i < *count; i++) {
1570Sstevel@tonic-gate 				list[i].path = strdup(x);
1580Sstevel@tonic-gate 				if (!list[i].path)
1590Sstevel@tonic-gate 					goto bad;
1600Sstevel@tonic-gate 			}
1610Sstevel@tonic-gate 			scount = i;
1620Sstevel@tonic-gate 			proot = root;
1630Sstevel@tonic-gate 			if (y)
1640Sstevel@tonic-gate 				*y = ',';
1650Sstevel@tonic-gate 			break;
1660Sstevel@tonic-gate 		case ',':
1670Sstevel@tonic-gate 			/*
1680Sstevel@tonic-gate 			 * If "v6addr" is set, unset it and continue
1690Sstevel@tonic-gate 			 * else grab the address and store it in the list
1700Sstevel@tonic-gate 			 * under "host part".
1710Sstevel@tonic-gate 			 */
1720Sstevel@tonic-gate 			if (v6addr == 1) {
1730Sstevel@tonic-gate 				v6addr = 0;
1740Sstevel@tonic-gate 				proot = ++root;
1750Sstevel@tonic-gate 			} else {
1760Sstevel@tonic-gate 				*root = '\0';
1770Sstevel@tonic-gate 				root++;
178*312Sfrankho 				if ((list = realloc(list, (*count + 1) *
179*312Sfrankho 				    sizeof (struct replica))) == NULL)
1800Sstevel@tonic-gate 					goto bad;
181*312Sfrankho 				bzero(&list[(*count)++],
182*312Sfrankho 				    sizeof (struct replica));
1830Sstevel@tonic-gate 				list[*count-1].host = strdup(proot);
1840Sstevel@tonic-gate 				if (!list[*count-1].host)
1850Sstevel@tonic-gate 					goto bad;
1860Sstevel@tonic-gate 				proot = root;
1870Sstevel@tonic-gate 				*(root - 1) = ',';
1880Sstevel@tonic-gate 			}
1890Sstevel@tonic-gate 			break;
1900Sstevel@tonic-gate 		default:
1910Sstevel@tonic-gate 			if (*root == '\0')
1920Sstevel@tonic-gate 				root = NULL;
1930Sstevel@tonic-gate 			else
1940Sstevel@tonic-gate 				root++;
1950Sstevel@tonic-gate 		}
1960Sstevel@tonic-gate 	}
1970Sstevel@tonic-gate 	if (found_colon) {
1980Sstevel@tonic-gate 		free(special2);
1990Sstevel@tonic-gate 		return (list);
2000Sstevel@tonic-gate 	}
2010Sstevel@tonic-gate bad:
202*312Sfrankho 	if (list)
203*312Sfrankho 		free_replica(list, *count);
2040Sstevel@tonic-gate 	if (!found_colon)
2050Sstevel@tonic-gate 		*count = -1;
2060Sstevel@tonic-gate 	free(special2);
2070Sstevel@tonic-gate 	return (NULL);
2080Sstevel@tonic-gate }
209