/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <rpcsvc/nlm_prot.h>
#include <sys/utsname.h>
#include <nfs/nfs.h>
#include "nfs_subr.h"
#include <errno.h>
#include <deflt.h>
#include <nfs/nfssys.h>
extern int _nfssys(enum nfssys_op, void *);
/*
* This function is added to detect compatibility problem with SunOS4.x.
* The compatibility problem exists when fshost cannot decode the request
* arguments for NLM_GRANTED procedure.
* Only in this case we use local locking.
* In any other case we use fshost's lockd for remote file locking.
* Return value: 1 if we should use local locking, 0 if not.
*/
int
remote_lock(char *fshost, caddr_t fh)
{
nlm_testargs rlm_args;
nlm_res rlm_res;
struct timeval timeout = { 5, 0};
CLIENT *cl;
enum clnt_stat rpc_stat;
struct utsname myid;
(void) memset((char *)&rlm_args, 0, sizeof (nlm_testargs));
(void) memset((char *)&rlm_res, 0, sizeof (nlm_res));
/*
* Assign the hostname and the file handle for the
* NLM_GRANTED request below. If for some reason the uname call fails,
* list the server as the caller so that caller_name has some
* reasonable value.
*/
if (uname(&myid) == -1) {
rlm_args.alock.caller_name = fshost;
} else {
rlm_args.alock.caller_name = myid.nodename;
}
rlm_args.alock.fh.n_len = sizeof (fhandle_t);
rlm_args.alock.fh.n_bytes = fh;
cl = clnt_create(fshost, NLM_PROG, NLM_VERS, "datagram_v");
if (cl == NULL)
return (0);
rpc_stat = clnt_call(cl, NLM_GRANTED,
xdr_nlm_testargs, (caddr_t)&rlm_args,
xdr_nlm_res, (caddr_t)&rlm_res, timeout);
clnt_destroy(cl);
return (rpc_stat == RPC_CANTDECODEARGS);
}
#define fromhex(c) ((c >= '0' && c <= '9') ? (c - '0') : \
((c >= 'A' && c <= 'F') ? (c - 'A' + 10) :\
((c >= 'a' && c <= 'f') ? (c - 'a' + 10) : 0)))
/*
* The implementation of URLparse guarantees that the final string will
* fit in the original one. Replaces '%' occurrences followed by 2 characters
* with its corresponding hexadecimal character.
*/
void
URLparse(char *str)
{
char *p, *q;
p = q = str;
while (*p) {
*q = *p;
if (*p++ == '%') {
if (*p) {
*q = fromhex(*p) * 16;
p++;
if (*p) {
*q += fromhex(*p);
p++;
}
}
}
q++;
}
*q = '\0';
}
/*
* Convert from URL syntax to host:path syntax.
*/
int
convert_special(char **specialp, char *host, char *oldpath, char *newpath,
char *cur_special)
{
char *url;
char *newspec;
char *p;
char *p1, *p2;
/*
* Rebuild the URL. This is necessary because parse replica
* assumes that nfs: is the host name.
*/
url = malloc(strlen("nfs:") + strlen(oldpath) + 1);
if (url == NULL)
return (-1);
strcpy(url, "nfs:");
strcat(url, oldpath);
/*
* If we haven't done any conversion yet, allocate a buffer for it.
*/
if (*specialp == NULL) {
newspec = *specialp = strdup(cur_special);
if (newspec == NULL) {
free(url);
return (-1);
}
} else {
newspec = *specialp;
}
/*
* Now find the first occurence of the URL in the special string.
*/
p = strstr(newspec, url);
if (p == NULL) {
free(url);
return (-1);
}
p1 = p;
p2 = host;
/*
* Overwrite the URL in the special.
*
* Begin with the host name.
*/
for (;;) {
/*
* Sine URL's take more room than host:path, there is
* no way we should hit a null byte in the original special.
*/
if (*p1 == '\0') {
free(url);
free(*specialp);
*specialp = NULL;
return (-1);
}
if (*p2 == '\0') {
break;
}
*p1 = *p2;
p1++;
p2++;
}
/*
* Add the : separator.
*/
*p1 = ':';
p1++;
/*
* Now over write into special the path portion of host:path in
*/
p2 = newpath;
for (;;) {
if (*p1 == '\0') {
free(url);
free(*specialp);
*specialp = NULL;
return (-1);
}
if (*p2 == '\0') {
break;
}
*p1 = *p2;
p1++;
p2++;
}
/*
* Now shift the rest of original special into the gap created
* by replacing nfs://host[:port]/path with host:path.
*/
p2 = p + strlen(url);
for (;;) {
if (*p1 == '\0') {
free(url);
free(*specialp);
*specialp = NULL;
return (-1);
}
if (*p2 == '\0') {
break;
}
*p1 = *p2;
p1++;
p2++;
}
*p1 = '\0';
free(url);
return (0);
}
/*
* Solaris autofs configuration file location
*/
#define AUTOFSADMIN "/etc/default/autofs"
#define AUTOFS_MOUNT_TIMEOUT 600 /* default min time mount will */
void
set_nfsv4_ephemeral_mount_to(void)
{
char *defval;
uint_t mount_to = AUTOFS_MOUNT_TIMEOUT;
/*
* Get the value from /etc/default/autofs
*/
if ((defopen(AUTOFSADMIN)) == 0) {
if ((defval = defread("AUTOMOUNT_TIMEOUT=")) != NULL) {
errno = 0;
mount_to = strtoul(defval, (char **)NULL, 10);
if (errno != 0)
mount_to = AUTOFS_MOUNT_TIMEOUT;
}
/* close defaults file */
defopen(NULL);
}
(void) _nfssys(NFS4_EPHEMERAL_MOUNT_TO, &mount_to);
}