xref: /illumos-gate/usr/src/cmd/fs.d/nfs/lib/nfs_subr.c (revision 69a119caa6570c7077699161b7c28b6ee9f8b0f4)
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 (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdlib.h>
29 #include <string.h>
30 #include <sys/types.h>
31 #include <rpcsvc/nlm_prot.h>
32 #include <sys/utsname.h>
33 #include <nfs/nfs.h>
34 #include "nfs_subr.h"
35 #include <errno.h>
36 #include <deflt.h>
37 
38 #include <nfs/nfssys.h>
39 extern int _nfssys(enum nfssys_op, void *);
40 
41 /*
42  * This function is added to detect compatibility problem with SunOS4.x.
43  * The compatibility problem exists when fshost cannot decode the request
44  * arguments for NLM_GRANTED procedure.
45  * Only in this case  we use local locking.
46  * In any other case we use fshost's lockd for remote file locking.
47  * Return value: 1 if we should use local locking, 0 if not.
48  */
49 int
50 remote_lock(char *fshost, caddr_t fh)
51 {
52 	nlm_testargs rlm_args;
53 	nlm_res rlm_res;
54 	struct timeval timeout = { 5, 0};
55 	CLIENT *cl;
56 	enum clnt_stat rpc_stat;
57 	struct utsname myid;
58 
59 	(void) memset((char *)&rlm_args, 0, sizeof (nlm_testargs));
60 	(void) memset((char *)&rlm_res, 0, sizeof (nlm_res));
61 	/*
62 	 * Assign the hostname and the file handle for the
63 	 * NLM_GRANTED request below.  If for some reason the uname call fails,
64 	 * list the server as the caller so that caller_name has some
65 	 * reasonable value.
66 	 */
67 	if (uname(&myid) == -1)  {
68 		rlm_args.alock.caller_name = fshost;
69 	} else {
70 		rlm_args.alock.caller_name = myid.nodename;
71 	}
72 	rlm_args.alock.fh.n_len = sizeof (fhandle_t);
73 	rlm_args.alock.fh.n_bytes = fh;
74 
75 	cl = clnt_create(fshost, NLM_PROG, NLM_VERS, "datagram_v");
76 	if (cl == NULL)
77 		return (0);
78 
79 	rpc_stat = clnt_call(cl, NLM_GRANTED,
80 	    xdr_nlm_testargs, (caddr_t)&rlm_args,
81 	    xdr_nlm_res, (caddr_t)&rlm_res, timeout);
82 	clnt_destroy(cl);
83 
84 	return (rpc_stat == RPC_CANTDECODEARGS);
85 }
86 
87 #define	fromhex(c)  ((c >= '0' && c <= '9') ? (c - '0') : \
88 			((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\
89 			((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
90 
91 /*
92  * The implementation of URLparse guarantees that the final string will
93  * fit in the original one. Replaces '%' occurrences followed by 2 characters
94  * with its corresponding hexadecimal character.
95  */
96 void
97 URLparse(char *str)
98 {
99 	char *p, *q;
100 
101 	p = q = str;
102 	while (*p) {
103 		*q = *p;
104 		if (*p++ == '%') {
105 			if (*p) {
106 				*q = fromhex(*p) * 16;
107 				p++;
108 				if (*p) {
109 					*q += fromhex(*p);
110 					p++;
111 				}
112 			}
113 		}
114 		q++;
115 	}
116 	*q = '\0';
117 }
118 
119 /*
120  * Convert from URL syntax to host:path syntax.
121  */
122 int
123 convert_special(char **specialp, char *host, char *oldpath, char *newpath,
124 	char *cur_special)
125 {
126 
127 	char *url;
128 	char *newspec;
129 	char *p;
130 	char *p1, *p2;
131 
132 	/*
133 	 * Rebuild the URL. This is necessary because parse replica
134 	 * assumes that nfs: is the host name.
135 	 */
136 	url = malloc(strlen("nfs:") + strlen(oldpath) + 1);
137 
138 	if (url == NULL)
139 		return (-1);
140 
141 	strcpy(url, "nfs:");
142 	strcat(url, oldpath);
143 
144 	/*
145 	 * If we haven't done any conversion yet, allocate a buffer for it.
146 	 */
147 	if (*specialp == NULL) {
148 		newspec = *specialp = strdup(cur_special);
149 		if (newspec == NULL) {
150 			free(url);
151 			return (-1);
152 		}
153 
154 	} else {
155 		newspec = *specialp;
156 	}
157 
158 	/*
159 	 * Now find the first occurence of the URL in the special string.
160 	 */
161 	p = strstr(newspec, url);
162 
163 	if (p == NULL) {
164 		free(url);
165 		return (-1);
166 	}
167 
168 	p1 = p;
169 	p2 = host;
170 
171 	/*
172 	 * Overwrite the URL in the special.
173 	 *
174 	 * Begin with the host name.
175 	 */
176 	for (;;) {
177 		/*
178 		 * Sine URL's take more room than host:path, there is
179 		 * no way we should hit a null byte in the original special.
180 		 */
181 		if (*p1 == '\0') {
182 			free(url);
183 			free(*specialp);
184 			*specialp = NULL;
185 			return (-1);
186 		}
187 
188 		if (*p2 == '\0') {
189 			break;
190 		}
191 
192 		*p1 = *p2;
193 		p1++;
194 		p2++;
195 	}
196 
197 	/*
198 	 * Add the : separator.
199 	 */
200 	*p1 = ':';
201 	p1++;
202 
203 	/*
204 	 * Now over write into special the path portion of host:path in
205 	 */
206 	p2 = newpath;
207 	for (;;) {
208 		if (*p1 == '\0') {
209 			free(url);
210 			free(*specialp);
211 			*specialp = NULL;
212 			return (-1);
213 		}
214 		if (*p2 == '\0') {
215 			break;
216 		}
217 		*p1 = *p2;
218 		p1++;
219 		p2++;
220 	}
221 
222 	/*
223 	 * Now shift the rest of original special into the gap created
224 	 * by replacing nfs://host[:port]/path with host:path.
225 	 */
226 	p2 = p + strlen(url);
227 	for (;;) {
228 		if (*p1 == '\0') {
229 			free(url);
230 			free(*specialp);
231 			*specialp = NULL;
232 			return (-1);
233 		}
234 		if (*p2 == '\0') {
235 			break;
236 		}
237 		*p1 = *p2;
238 		p1++;
239 		p2++;
240 	}
241 
242 	*p1 = '\0';
243 
244 	free(url);
245 	return (0);
246 }
247 
248 /*
249  * Solaris autofs configuration file location
250  */
251 #define	AUTOFSADMIN		"/etc/default/autofs"
252 #define	AUTOFS_MOUNT_TIMEOUT	600	/* default min time mount will */
253 
254 void
255 set_nfsv4_ephemeral_mount_to(void)
256 {
257 	char	*defval;
258 
259 	uint_t	mount_to = AUTOFS_MOUNT_TIMEOUT;
260 
261 	/*
262 	 * Get the value from /etc/default/autofs
263 	 */
264 	if ((defopen(AUTOFSADMIN)) == 0) {
265 		if ((defval = defread("AUTOMOUNT_TIMEOUT=")) != NULL) {
266 			errno = 0;
267 			mount_to = strtoul(defval, (char **)NULL, 10);
268 			if (errno != 0)
269 				mount_to = AUTOFS_MOUNT_TIMEOUT;
270 		}
271 
272 		/* close defaults file */
273 		defopen(NULL);
274 	}
275 
276 	(void) _nfssys(NFS4_EPHEMERAL_MOUNT_TO, &mount_to);
277 }
278