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
remote_lock(char * fshost,caddr_t fh)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
URLparse(char * str)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
convert_special(char ** specialp,char * host,char * oldpath,char * newpath,char * cur_special)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
set_nfsv4_ephemeral_mount_to(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