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 * nfs_subr.c 24 * 25 * Copyright (c) 1996 Sun Microsystems Inc 26 * All Rights Reserved. 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <stdlib.h> 32 #include <string.h> 33 #include <sys/types.h> 34 #include <rpcsvc/nlm_prot.h> 35 #include <sys/utsname.h> 36 #include <nfs/nfs.h> 37 #include "nfs_subr.h" 38 39 /* 40 * This function is added to detect compatibility problem with SunOS4.x. 41 * The compatibility problem exists when fshost cannot decode the request 42 * arguments for NLM_GRANTED procedure. 43 * Only in this case we use local locking. 44 * In any other case we use fshost's lockd for remote file locking. 45 * Return value: 1 if we should use local locking, 0 if not. 46 */ 47 int 48 remote_lock(char *fshost, caddr_t fh) 49 { 50 nlm_testargs rlm_args; 51 nlm_res rlm_res; 52 struct timeval timeout = { 5, 0}; 53 CLIENT *cl; 54 enum clnt_stat rpc_stat; 55 struct utsname myid; 56 57 (void) memset((char *)&rlm_args, 0, sizeof (nlm_testargs)); 58 (void) memset((char *)&rlm_res, 0, sizeof (nlm_res)); 59 /* 60 * Assign the hostname and the file handle for the 61 * NLM_GRANTED request below. If for some reason the uname call fails, 62 * list the server as the caller so that caller_name has some 63 * reasonable value. 64 */ 65 if (uname(&myid) == -1) { 66 rlm_args.alock.caller_name = fshost; 67 } else { 68 rlm_args.alock.caller_name = myid.nodename; 69 } 70 rlm_args.alock.fh.n_len = sizeof (fhandle_t); 71 rlm_args.alock.fh.n_bytes = fh; 72 73 cl = clnt_create(fshost, NLM_PROG, NLM_VERS, "datagram_v"); 74 if (cl == NULL) 75 return (0); 76 77 rpc_stat = clnt_call(cl, NLM_GRANTED, 78 xdr_nlm_testargs, (caddr_t)&rlm_args, 79 xdr_nlm_res, (caddr_t)&rlm_res, timeout); 80 clnt_destroy(cl); 81 82 return (rpc_stat == RPC_CANTDECODEARGS); 83 } 84 85 #define fromhex(c) ((c >= '0' && c <= '9') ? (c - '0') : \ 86 ((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\ 87 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0))) 88 89 /* 90 * The implementation of URLparse guarantees that the final string will 91 * fit in the original one. Replaces '%' occurrences followed by 2 characters 92 * with its corresponding hexadecimal character. 93 */ 94 void 95 URLparse(char *str) 96 { 97 char *p, *q; 98 99 p = q = str; 100 while (*p) { 101 *q = *p; 102 if (*p++ == '%') { 103 if (*p) { 104 *q = fromhex(*p) * 16; 105 p++; 106 if (*p) { 107 *q += fromhex(*p); 108 p++; 109 } 110 } 111 } 112 q++; 113 } 114 *q = '\0'; 115 } 116 117 /* 118 * Convert from URL syntax to host:path syntax. 119 */ 120 int 121 convert_special(char **specialp, char *host, char *oldpath, char *newpath, 122 char *cur_special) 123 { 124 125 char *url; 126 char *newspec; 127 char *p; 128 char *p1, *p2; 129 130 /* 131 * Rebuild the URL. This is necessary because parse replica 132 * assumes that nfs: is the host name. 133 */ 134 url = malloc(strlen("nfs:") + strlen(oldpath) + 1); 135 136 if (url == NULL) 137 return (-1); 138 139 strcpy(url, "nfs:"); 140 strcat(url, oldpath); 141 142 /* 143 * If we haven't done any conversion yet, allocate a buffer for it. 144 */ 145 if (*specialp == NULL) { 146 newspec = *specialp = strdup(cur_special); 147 if (newspec == NULL) { 148 free(url); 149 return (-1); 150 } 151 152 } else { 153 newspec = *specialp; 154 } 155 156 /* 157 * Now find the first occurence of the URL in the special string. 158 */ 159 p = strstr(newspec, url); 160 161 if (p == NULL) { 162 free(url); 163 return (-1); 164 } 165 166 p1 = p; 167 p2 = host; 168 169 /* 170 * Overwrite the URL in the special. 171 * 172 * Begin with the host name. 173 */ 174 for (;;) { 175 /* 176 * Sine URL's take more room than host:path, there is 177 * no way we should hit a null byte in the original special. 178 */ 179 if (*p1 == '\0') { 180 free(url); 181 free(*specialp); 182 *specialp = NULL; 183 return (-1); 184 } 185 186 if (*p2 == '\0') { 187 break; 188 } 189 190 *p1 = *p2; 191 p1++; 192 p2++; 193 } 194 195 /* 196 * Add the : separator. 197 */ 198 *p1 = ':'; 199 p1++; 200 201 /* 202 * Now over write into special the path portion of host:path in 203 */ 204 p2 = newpath; 205 for (;;) { 206 if (*p1 == '\0') { 207 free(url); 208 free(*specialp); 209 *specialp = NULL; 210 return (-1); 211 } 212 if (*p2 == '\0') { 213 break; 214 } 215 *p1 = *p2; 216 p1++; 217 p2++; 218 } 219 220 /* 221 * Now shift the rest of original special into the gap created 222 * by replacing nfs://host[:port]/path with host:path. 223 */ 224 p2 = p + strlen(url); 225 for (;;) { 226 if (*p1 == '\0') { 227 free(url); 228 free(*specialp); 229 *specialp = NULL; 230 return (-1); 231 } 232 if (*p2 == '\0') { 233 break; 234 } 235 *p1 = *p2; 236 p1++; 237 p2++; 238 } 239 240 *p1 = '\0'; 241 242 free(url); 243 return (0); 244 } 245