1*7a286c47SDai Ngo /* 2*7a286c47SDai Ngo * CDDL HEADER START 3*7a286c47SDai Ngo * 4*7a286c47SDai Ngo * The contents of this file are subject to the terms of the 5*7a286c47SDai Ngo * Common Development and Distribution License (the "License"). 6*7a286c47SDai Ngo * You may not use this file except in compliance with the License. 7*7a286c47SDai Ngo * 8*7a286c47SDai Ngo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*7a286c47SDai Ngo * or http://www.opensolaris.org/os/licensing. 10*7a286c47SDai Ngo * See the License for the specific language governing permissions 11*7a286c47SDai Ngo * and limitations under the License. 12*7a286c47SDai Ngo * 13*7a286c47SDai Ngo * When distributing Covered Code, include this CDDL HEADER in each 14*7a286c47SDai Ngo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*7a286c47SDai Ngo * If applicable, add the following below this CDDL HEADER, with the 16*7a286c47SDai Ngo * fields enclosed by brackets "[]" replaced with your own identifying 17*7a286c47SDai Ngo * information: Portions Copyright [yyyy] [name of copyright owner] 18*7a286c47SDai Ngo * 19*7a286c47SDai Ngo * CDDL HEADER END 20*7a286c47SDai Ngo */ 21*7a286c47SDai Ngo /* 22*7a286c47SDai Ngo * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23*7a286c47SDai Ngo * Use is subject to license terms. 24*7a286c47SDai Ngo */ 25*7a286c47SDai Ngo 26*7a286c47SDai Ngo #include <sys/types.h> 27*7a286c47SDai Ngo #include <sys/param.h> 28*7a286c47SDai Ngo #include <sys/errno.h> 29*7a286c47SDai Ngo 30*7a286c47SDai Ngo #ifdef _KERNEL 31*7a286c47SDai Ngo #include <sys/sunddi.h> 32*7a286c47SDai Ngo #include <fs/fs_reparse.h> 33*7a286c47SDai Ngo #else 34*7a286c47SDai Ngo #include <string.h> 35*7a286c47SDai Ngo #include <limits.h> 36*7a286c47SDai Ngo #include <sys/fs_reparse.h> 37*7a286c47SDai Ngo 38*7a286c47SDai Ngo #define strfree(str) free((str)) 39*7a286c47SDai Ngo #endif 40*7a286c47SDai Ngo 41*7a286c47SDai Ngo static char *reparse_skipspace(char *cp); 42*7a286c47SDai Ngo static int reparse_create_nvlist(const char *string, nvlist_t *nvl); 43*7a286c47SDai Ngo static int reparse_add_nvpair(char *token, nvlist_t *nvl); 44*7a286c47SDai Ngo static boolean_t reparse_validate_svctype(char *svc_str); 45*7a286c47SDai Ngo static int reparse_validate_create_nvlist(const char *string, nvlist_t *nvl); 46*7a286c47SDai Ngo 47*7a286c47SDai Ngo /* array of characters not allowed in service type string */ 48*7a286c47SDai Ngo static char svctype_invalid_chars[] = { '{', '}', 0 }; 49*7a286c47SDai Ngo 50*7a286c47SDai Ngo /* 51*7a286c47SDai Ngo * reparse_init() 52*7a286c47SDai Ngo * 53*7a286c47SDai Ngo * Function to allocate a new name-value pair list. 54*7a286c47SDai Ngo * Caller needs to call reparse_free() to free memory 55*7a286c47SDai Ngo * used by the list when done. 56*7a286c47SDai Ngo * 57*7a286c47SDai Ngo * Return pointer to new list else return NULL. 58*7a286c47SDai Ngo */ 59*7a286c47SDai Ngo nvlist_t * 60*7a286c47SDai Ngo reparse_init(void) 61*7a286c47SDai Ngo { 62*7a286c47SDai Ngo nvlist_t *nvl; 63*7a286c47SDai Ngo 64*7a286c47SDai Ngo /* 65*7a286c47SDai Ngo * Service type is unique, only one entry 66*7a286c47SDai Ngo * of each service type is allowed 67*7a286c47SDai Ngo */ 68*7a286c47SDai Ngo if (nvlist_alloc(&nvl, NV_UNIQUE_NAME, 0)) 69*7a286c47SDai Ngo return (NULL); 70*7a286c47SDai Ngo 71*7a286c47SDai Ngo return (nvl); 72*7a286c47SDai Ngo } 73*7a286c47SDai Ngo 74*7a286c47SDai Ngo /* 75*7a286c47SDai Ngo * reparse_free() 76*7a286c47SDai Ngo * 77*7a286c47SDai Ngo * Function to free memory of a nvlist allocated previously 78*7a286c47SDai Ngo * by reparse_init(). 79*7a286c47SDai Ngo */ 80*7a286c47SDai Ngo void 81*7a286c47SDai Ngo reparse_free(nvlist_t *nvl) 82*7a286c47SDai Ngo { 83*7a286c47SDai Ngo nvlist_free(nvl); 84*7a286c47SDai Ngo } 85*7a286c47SDai Ngo 86*7a286c47SDai Ngo /* 87*7a286c47SDai Ngo * reparse_parse() 88*7a286c47SDai Ngo * 89*7a286c47SDai Ngo * Parse the specified string and populate the nvlist with the svc_types 90*7a286c47SDai Ngo * and data from the 'string'. The string could be read from the reparse 91*7a286c47SDai Ngo * point symlink body. This routine will allocate memory that must be 92*7a286c47SDai Ngo * freed by reparse_free(). 93*7a286c47SDai Ngo * 94*7a286c47SDai Ngo * If ok return 0 and the nvlist is populated, otherwise return error code. 95*7a286c47SDai Ngo */ 96*7a286c47SDai Ngo int 97*7a286c47SDai Ngo reparse_parse(const char *string, nvlist_t *nvl) 98*7a286c47SDai Ngo { 99*7a286c47SDai Ngo int err; 100*7a286c47SDai Ngo 101*7a286c47SDai Ngo if (string == NULL || nvl == NULL) 102*7a286c47SDai Ngo return (EINVAL); 103*7a286c47SDai Ngo 104*7a286c47SDai Ngo if ((err = reparse_validate(string)) != 0) 105*7a286c47SDai Ngo return (err); 106*7a286c47SDai Ngo 107*7a286c47SDai Ngo if ((err = reparse_create_nvlist(string, nvl)) != 0) 108*7a286c47SDai Ngo return (err); 109*7a286c47SDai Ngo 110*7a286c47SDai Ngo return (0); 111*7a286c47SDai Ngo } 112*7a286c47SDai Ngo 113*7a286c47SDai Ngo static char * 114*7a286c47SDai Ngo reparse_skipspace(char *cp) 115*7a286c47SDai Ngo { 116*7a286c47SDai Ngo while ((*cp) && (*cp == ' ' || *cp == '\t')) 117*7a286c47SDai Ngo cp++; 118*7a286c47SDai Ngo return (cp); 119*7a286c47SDai Ngo } 120*7a286c47SDai Ngo 121*7a286c47SDai Ngo static boolean_t 122*7a286c47SDai Ngo reparse_validate_svctype(char *svc_str) 123*7a286c47SDai Ngo { 124*7a286c47SDai Ngo int nx, ix, len; 125*7a286c47SDai Ngo 126*7a286c47SDai Ngo if (svc_str == NULL) 127*7a286c47SDai Ngo return (B_FALSE); 128*7a286c47SDai Ngo 129*7a286c47SDai Ngo len = strlen(svc_str); 130*7a286c47SDai Ngo for (ix = 0; ix < len; ix++) { 131*7a286c47SDai Ngo for (nx = 0; nx < sizeof (svctype_invalid_chars); nx++) { 132*7a286c47SDai Ngo if (svc_str[ix] == svctype_invalid_chars[nx]) 133*7a286c47SDai Ngo return (B_FALSE); 134*7a286c47SDai Ngo } 135*7a286c47SDai Ngo } 136*7a286c47SDai Ngo return (B_TRUE); 137*7a286c47SDai Ngo } 138*7a286c47SDai Ngo 139*7a286c47SDai Ngo static boolean_t 140*7a286c47SDai Ngo reparse_validate_svc_token(char *svc_token) 141*7a286c47SDai Ngo { 142*7a286c47SDai Ngo char save_c, *cp; 143*7a286c47SDai Ngo 144*7a286c47SDai Ngo if (svc_token == NULL) 145*7a286c47SDai Ngo return (B_FALSE); 146*7a286c47SDai Ngo if ((cp = strchr(svc_token, ':')) == NULL) 147*7a286c47SDai Ngo return (B_FALSE); 148*7a286c47SDai Ngo 149*7a286c47SDai Ngo save_c = *cp; 150*7a286c47SDai Ngo *cp = '\0'; 151*7a286c47SDai Ngo 152*7a286c47SDai Ngo /* 153*7a286c47SDai Ngo * make sure service type and service data are non-empty string. 154*7a286c47SDai Ngo */ 155*7a286c47SDai Ngo if (strlen(svc_token) == 0 || strlen(cp + 1) == 0) { 156*7a286c47SDai Ngo *cp = save_c; 157*7a286c47SDai Ngo return (B_FALSE); 158*7a286c47SDai Ngo } 159*7a286c47SDai Ngo 160*7a286c47SDai Ngo *cp = save_c; 161*7a286c47SDai Ngo return (B_TRUE); 162*7a286c47SDai Ngo } 163*7a286c47SDai Ngo 164*7a286c47SDai Ngo /* 165*7a286c47SDai Ngo * Format of reparse data: 166*7a286c47SDai Ngo * @{REPARSE@{servicetype:data} [@{servicetype:data}] ...} 167*7a286c47SDai Ngo * REPARSE_TAG_STR@{REPARSE_TOKEN} [@{REPARSE_TOKEN}] ... REPARSE_TAG_END 168*7a286c47SDai Ngo * 169*7a286c47SDai Ngo * Validating reparse data: 170*7a286c47SDai Ngo * . check for valid length of reparse data 171*7a286c47SDai Ngo * . check for valid reparse data format 172*7a286c47SDai Ngo * Return 0 if OK else return error code. 173*7a286c47SDai Ngo */ 174*7a286c47SDai Ngo int 175*7a286c47SDai Ngo reparse_validate(const char *string) 176*7a286c47SDai Ngo { 177*7a286c47SDai Ngo return (reparse_validate_create_nvlist(string, NULL)); 178*7a286c47SDai Ngo } 179*7a286c47SDai Ngo 180*7a286c47SDai Ngo /* 181*7a286c47SDai Ngo * reparse_validate_create_nvlist 182*7a286c47SDai Ngo * 183*7a286c47SDai Ngo * dual-purpose function: 184*7a286c47SDai Ngo * . Validate a reparse data string. 185*7a286c47SDai Ngo * . Validate a reparse data string and parse the data 186*7a286c47SDai Ngo * into a nvlist. 187*7a286c47SDai Ngo */ 188*7a286c47SDai Ngo static int 189*7a286c47SDai Ngo reparse_validate_create_nvlist(const char *string, nvlist_t *nvl) 190*7a286c47SDai Ngo { 191*7a286c47SDai Ngo int err, tcnt; 192*7a286c47SDai Ngo char *reparse_data, save_c, save_e, *save_e_ptr, *cp, *s_str, *e_str; 193*7a286c47SDai Ngo 194*7a286c47SDai Ngo if (string == NULL) 195*7a286c47SDai Ngo return (EINVAL); 196*7a286c47SDai Ngo 197*7a286c47SDai Ngo if (strlen(string) >= MAXREPARSELEN) 198*7a286c47SDai Ngo return (ENAMETOOLONG); 199*7a286c47SDai Ngo 200*7a286c47SDai Ngo if ((reparse_data = strdup(string)) == NULL) 201*7a286c47SDai Ngo return (ENOMEM); 202*7a286c47SDai Ngo 203*7a286c47SDai Ngo /* check FS_REPARSE_TAG_STR */ 204*7a286c47SDai Ngo if (strncmp(reparse_data, FS_REPARSE_TAG_STR, 205*7a286c47SDai Ngo strlen(FS_REPARSE_TAG_STR))) { 206*7a286c47SDai Ngo strfree(reparse_data); 207*7a286c47SDai Ngo return (EINVAL); 208*7a286c47SDai Ngo } 209*7a286c47SDai Ngo 210*7a286c47SDai Ngo /* locate FS_REPARSE_TAG_END_CHAR */ 211*7a286c47SDai Ngo if ((cp = strrchr(reparse_data, FS_REPARSE_TAG_END_CHAR)) == NULL) { 212*7a286c47SDai Ngo strfree(reparse_data); 213*7a286c47SDai Ngo return (EINVAL); 214*7a286c47SDai Ngo } 215*7a286c47SDai Ngo save_e = *cp; 216*7a286c47SDai Ngo save_e_ptr = cp; 217*7a286c47SDai Ngo *cp = '\0'; 218*7a286c47SDai Ngo 219*7a286c47SDai Ngo e_str = cp; 220*7a286c47SDai Ngo cp++; /* should point to NULL, or spaces */ 221*7a286c47SDai Ngo 222*7a286c47SDai Ngo cp = reparse_skipspace(cp); 223*7a286c47SDai Ngo if (*cp) { 224*7a286c47SDai Ngo *save_e_ptr = save_e; 225*7a286c47SDai Ngo strfree(reparse_data); 226*7a286c47SDai Ngo return (EINVAL); 227*7a286c47SDai Ngo } 228*7a286c47SDai Ngo 229*7a286c47SDai Ngo /* skip FS_REPARSE_TAG_STR */ 230*7a286c47SDai Ngo s_str = reparse_data + strlen(FS_REPARSE_TAG_STR); 231*7a286c47SDai Ngo 232*7a286c47SDai Ngo /* skip spaces after FS_REPARSE_TAG_STR */ 233*7a286c47SDai Ngo s_str = reparse_skipspace(s_str); 234*7a286c47SDai Ngo 235*7a286c47SDai Ngo tcnt = 0; 236*7a286c47SDai Ngo while (s_str < e_str) { 237*7a286c47SDai Ngo /* check FS_TOKEN_START_STR */ 238*7a286c47SDai Ngo if (strncmp(s_str, FS_TOKEN_START_STR, 239*7a286c47SDai Ngo strlen(FS_TOKEN_START_STR))) { 240*7a286c47SDai Ngo *save_e_ptr = save_e; 241*7a286c47SDai Ngo strfree(reparse_data); 242*7a286c47SDai Ngo return (EINVAL); 243*7a286c47SDai Ngo } 244*7a286c47SDai Ngo 245*7a286c47SDai Ngo /* skip over FS_TOKEN_START_STR */ 246*7a286c47SDai Ngo s_str += strlen(FS_TOKEN_START_STR); 247*7a286c47SDai Ngo 248*7a286c47SDai Ngo /* locate FS_TOKEN_END_STR */ 249*7a286c47SDai Ngo if ((cp = strstr(s_str, FS_TOKEN_END_STR)) == NULL) { 250*7a286c47SDai Ngo *save_e_ptr = save_e; 251*7a286c47SDai Ngo strfree(reparse_data); 252*7a286c47SDai Ngo return (EINVAL); 253*7a286c47SDai Ngo } 254*7a286c47SDai Ngo 255*7a286c47SDai Ngo tcnt++; 256*7a286c47SDai Ngo save_c = *cp; 257*7a286c47SDai Ngo *cp = '\0'; 258*7a286c47SDai Ngo 259*7a286c47SDai Ngo /* check for valid characters in service type */ 260*7a286c47SDai Ngo if (reparse_validate_svctype(s_str) == B_FALSE) { 261*7a286c47SDai Ngo *cp = save_c; 262*7a286c47SDai Ngo *save_e_ptr = save_e; 263*7a286c47SDai Ngo strfree(reparse_data); 264*7a286c47SDai Ngo return (EINVAL); 265*7a286c47SDai Ngo } 266*7a286c47SDai Ngo 267*7a286c47SDai Ngo if (strlen(s_str) == 0) { 268*7a286c47SDai Ngo *cp = save_c; 269*7a286c47SDai Ngo *save_e_ptr = save_e; 270*7a286c47SDai Ngo strfree(reparse_data); 271*7a286c47SDai Ngo return (EINVAL); 272*7a286c47SDai Ngo } 273*7a286c47SDai Ngo 274*7a286c47SDai Ngo if (reparse_validate_svc_token(s_str) == B_FALSE) { 275*7a286c47SDai Ngo *cp = save_c; 276*7a286c47SDai Ngo *save_e_ptr = save_e; 277*7a286c47SDai Ngo strfree(reparse_data); 278*7a286c47SDai Ngo return (EINVAL); 279*7a286c47SDai Ngo } 280*7a286c47SDai Ngo 281*7a286c47SDai Ngo /* create a nvpair entry */ 282*7a286c47SDai Ngo if (nvl != NULL && 283*7a286c47SDai Ngo (err = reparse_add_nvpair(s_str, nvl)) != 0) { 284*7a286c47SDai Ngo *cp = save_c; 285*7a286c47SDai Ngo *save_e_ptr = save_e; 286*7a286c47SDai Ngo strfree(reparse_data); 287*7a286c47SDai Ngo return (err); 288*7a286c47SDai Ngo } 289*7a286c47SDai Ngo 290*7a286c47SDai Ngo *cp = save_c; 291*7a286c47SDai Ngo 292*7a286c47SDai Ngo /* skip over FS_TOKEN_END_STR */ 293*7a286c47SDai Ngo cp += strlen(FS_TOKEN_END_STR); 294*7a286c47SDai Ngo cp = reparse_skipspace(cp); 295*7a286c47SDai Ngo s_str = cp; 296*7a286c47SDai Ngo } 297*7a286c47SDai Ngo *save_e_ptr = save_e; 298*7a286c47SDai Ngo strfree(reparse_data); 299*7a286c47SDai Ngo 300*7a286c47SDai Ngo return (tcnt ? 0 : EINVAL); 301*7a286c47SDai Ngo } 302*7a286c47SDai Ngo 303*7a286c47SDai Ngo static int 304*7a286c47SDai Ngo reparse_add_nvpair(char *token, nvlist_t *nvl) 305*7a286c47SDai Ngo { 306*7a286c47SDai Ngo int err; 307*7a286c47SDai Ngo char save_c, *cp; 308*7a286c47SDai Ngo 309*7a286c47SDai Ngo if ((cp = strchr(token, ':')) == NULL) 310*7a286c47SDai Ngo return (EINVAL); 311*7a286c47SDai Ngo 312*7a286c47SDai Ngo save_c = *cp; 313*7a286c47SDai Ngo *cp = '\0'; 314*7a286c47SDai Ngo err = nvlist_add_string(nvl, token, cp + 1); 315*7a286c47SDai Ngo *cp = save_c; 316*7a286c47SDai Ngo 317*7a286c47SDai Ngo return (err); 318*7a286c47SDai Ngo } 319*7a286c47SDai Ngo 320*7a286c47SDai Ngo static int 321*7a286c47SDai Ngo reparse_create_nvlist(const char *string, nvlist_t *nvl) 322*7a286c47SDai Ngo { 323*7a286c47SDai Ngo if (nvl == NULL) 324*7a286c47SDai Ngo return (EINVAL); 325*7a286c47SDai Ngo 326*7a286c47SDai Ngo return (reparse_validate_create_nvlist(string, nvl)); 327*7a286c47SDai Ngo } 328