/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ref_subr.h" extern int errno; #define SERVICE_TYPE "nfs-basic" char *nfs_basic_service_type(void); boolean_t nfs_basic_supports_svc(const char *); int nfs_basic_deref(const char *, const char *, char *, size_t *); int nfs_basic_form(const char *, const char *, char *, size_t *); struct rp_plugin_ops rp_plugin_ops = { RP_PLUGIN_V1, NULL, /* rpo_init */ NULL, /* rpo_fini */ nfs_basic_service_type, nfs_basic_supports_svc, nfs_basic_form, nfs_basic_deref }; /* * What service type does this module support? */ char * nfs_basic_service_type() { return (SERVICE_TYPE); } /* * Does this module support a particular service type? */ boolean_t nfs_basic_supports_svc(const char *svc_type) { if (!svc_type) return (0); return (!strncasecmp(svc_type, SERVICE_TYPE, strlen(SERVICE_TYPE))); } /* * Take a string with a set of locations like this: * host1:/path1 host2:/path2 host3:/path3 * and convert it to an fs_locations4 for the deref routine. */ static fs_locations4 * get_fs_locations(char *buf) { fs_locations4 *result = NULL; fs_location4 *fsl_array; int i, gothost; int fsl_count = 0, escape = 0, delimiter = 0; int len; char *p, *sp, *dp, buf2[SYMLINK_MAX]; if (buf == NULL) return (NULL); #ifdef DEBUG printf("get_fs_locations: input %s\n", buf); #endif /* * Count fs_location entries by counting spaces. * Remember that escaped spaces ("\ ") may exist. * We mark the location boundaries with null bytes. * Variable use: * escape - set if we have found a backspace, * part of either "\ " or "\\" * delimiter - set if we have found a space and * used to skip multiple spaces */ for (sp = buf; sp && *sp; sp++) { if (*sp == '\\') { escape = 1; delimiter = 0; continue; } if (*sp == ' ') { if (delimiter == 1) continue; if (escape == 0) { delimiter = 1; fsl_count++; *sp = '\0'; } else escape = 0; } else delimiter = 0; } len = sp - buf; sp--; if (escape == 0 && *sp != '\0') fsl_count++; #ifdef DEBUG printf("get_fs_locations: fsl_count %d\n", fsl_count); #endif if (fsl_count == 0) goto out; /* Alloc space for everything */ result = calloc(1, sizeof (fs_locations4)); if (result == NULL) goto out; fsl_array = calloc(fsl_count, sizeof (fs_location4)); if (fsl_array == NULL) { free(result); result = NULL; goto out; } result->locations.locations_len = fsl_count; result->locations.locations_val = fsl_array; result->fs_root.pathname4_len = 0; result->fs_root.pathname4_val = NULL; /* * Copy input, removing escapes from host:/path/to/my\ files */ sp = buf; dp = buf2; bzero(buf2, sizeof (buf2)); i = gothost = 0; while ((sp && *sp && (sp - buf < len)) || gothost) { if (!gothost) { /* Drop leading spaces */ if (*sp == ' ') { sp++; continue; } /* Look for the rightmost colon for host */ p = strrchr(sp, ':'); if (!p) { #ifdef DEBUG printf("get_fs_locations: skipping %s\n", sp); #endif fsl_count--; sp += strlen(sp) + 1; } else { bcopy(sp, dp, p - sp); sp = p + 1; #ifdef DEBUG printf("get_fs_locations: host %s\n", buf2); #endif fsl_array[i].server.server_len = 1; fsl_array[i].server.server_val = malloc(sizeof (utf8string)); if (fsl_array[i].server.server_val == NULL) { int j; free(result); result = NULL; for (j = 0; j < i; j++) free(fsl_array[j]. server.server_val); free(fsl_array); goto out; } str_to_utf8(buf2, fsl_array[i].server.server_val); gothost = 1; dp = buf2; bzero(buf2, sizeof (buf2)); } continue; } /* End of string should mean a pathname */ if (*sp == '\0' && gothost) { #ifdef DEBUG printf("get_fs_locations: path %s\n", buf2); #endif (void) make_pathname4(buf2, &fsl_array[i].rootpath); i++; gothost = 0; dp = buf2; bzero(buf2, sizeof (buf2)); if (sp - buf < len) sp++; continue; } /* Skip a single escape character */ if (*sp == '\\') sp++; /* Plain char, just copy it */ *dp++ = *sp++; } /* * If we're still expecting a path name, we don't have a * server:/path pair and should discard the server and * note that we got fewer locations than expected. */ if (gothost) { fsl_count--; free(fsl_array[i].server.server_val); fsl_array[i].server.server_val = NULL; fsl_array[i].server.server_len = 0; } /* * If we have zero entries, we never got a whole server:/path * pair, and so cannot have anything else allocated. */ if (fsl_count <= 0) { free(result); free(fsl_array); return (NULL); } /* * Make sure we reflect the right number of locations. */ if (fsl_count < result->locations.locations_len) result->locations.locations_len = fsl_count; out: return (result); } /* * Deref function for nfs-basic service type returns an fs_locations4. */ int nfs_basic_deref(const char *svc_type, const char *svc_data, char *buf, size_t *bufsz) { int slen, err; fs_locations4 *fsl; XDR xdr; if ((!svc_type) || (!svc_data) || (!buf) || (!bufsz) || (*bufsz == 0)) return (EINVAL); if (strcasecmp(svc_type, SERVICE_TYPE)) return (ENOTSUP); fsl = get_fs_locations((char *)svc_data); if (fsl == NULL) return (ENOENT); #ifdef DEBUG printf("nfs_basic_deref: past get_fs_locations()\n"); #endif slen = xdr_sizeof(xdr_fs_locations4, (void *)fsl); if (slen > *bufsz) { *bufsz = slen; xdr_free(xdr_fs_locations4, (char *)fsl); return (EOVERFLOW); } #ifdef DEBUG printf("nfs_basic_deref: past buffer check\n"); print_referral_summary(fsl); #endif xdrmem_create(&xdr, buf, *bufsz, XDR_ENCODE); err = xdr_fs_locations4(&xdr, fsl); XDR_DESTROY(&xdr); xdr_free(xdr_fs_locations4, (char *)fsl); if (err != TRUE) return (EINVAL); *bufsz = slen; #ifdef DEBUG printf("nfs_basic_deref: past xdr_fs_locations4() and done\n"); #endif return (0); } /* * Form function for nfs-basic service type. */ int nfs_basic_form(const char *svc_type, const char *svc_data, char *buf, size_t *bufsz) { int slen; if ((!svc_type) || (!svc_data) || (!buf) || (*bufsz == 0)) return (EINVAL); if (strcmp(svc_type, SERVICE_TYPE)) return (ENOTSUP); slen = strlen(svc_data) + 1; if (slen > *bufsz) { *bufsz = slen; return (EOVERFLOW); } *bufsz = slen; strncpy(buf, svc_data, slen); return (0); }