xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lib/nfs_subr.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
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