#include <sys/param.h>
#include <sys/mount.h>
#include <sys/queue.h>
#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/sysctl.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <signal.h>
#include <netdb.h>
#include "nlm_prot.h"
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs_lock.h>
#include <nfs/nfs.h>
#include <mach/mach.h>
#include <mach/mach_error.h>
#include <servers/bootstrap.h>
#include "lockd_mach.h"
#include "lockd_machServer.h"
#include "lockd.h"
#include "lockd_lock.h"
#define nfslockdans(_v, _ansp) \
((_ansp)->la_version = (_v), \
nfsclnt(NFSCLNT_LOCKDANS, (_ansp)))
static mach_port_t lockd_receive_right;
union MaxMsgSize {
union __RequestUnion__lockd_mach_subsystem req;
union __ReplyUnion__lockd_mach_subsystem rep;
};
#define MAX_LOCKD_MSG_SIZE (sizeof (union MaxMsgSize) + MAX_TRAILER_SIZE)
#define BOOTSTRAP_NAME "com.apple.lockd"
typedef struct __owner {
pid_t pid;
time_t tod;
} OWNER;
static OWNER owner;
static char hostname[MAXHOSTNAMELEN + 1];
static time_t shutdown_time_client = 0;
static time_t shutdown_time_server = 0;
static void set_auth(CLIENT *cl, struct xucred *ucred);
int lock_request(LOCKD_MSG *);
int cancel_request(LOCKD_MSG *);
int test_request(LOCKD_MSG *);
void show(LOCKD_MSG *);
int unlock_request(LOCKD_MSG *);
#define d_calls (config.verbose > 1)
#define d_args (config.verbose > 2)
static const char *
from_addr(saddr)
struct sockaddr *saddr;
{
static char inet_buf[INET6_ADDRSTRLEN];
if (getnameinfo(saddr, saddr->sa_len, inet_buf, sizeof(inet_buf),
NULL, 0, NI_NUMERICHOST) == 0)
return inet_buf;
return "???";
}
static int
get_client_and_server_state(int *mounts, int *servers, int *maxservers)
{
size_t size = sizeof(int);
int rv = 0;
*mounts = *servers = *maxservers = 0;
if (sysctlbyname("vfs.generic.nfs.client.lockd_mounts", mounts, &size, NULL, 0))
rv++;
if (sysctlbyname("vfs.generic.nfs.server.nfsd_thread_count", servers, &size, NULL, 0))
rv++;
if (sysctlbyname("vfs.generic.nfs.server.nfsd_thread_max", maxservers, &size, NULL, 0))
rv++;
return (rv);
}
static void
shutdown_timer(void)
{
if (!shutdown_time_client || !shutdown_time_server) {
if (config.verbose) {
int mounts, servers, maxservers;
get_client_and_server_state(&mounts, &servers, &maxservers);
syslog(LOG_DEBUG, "shutdown_timer: %d %d, mounts %d servers %d %d\n",
shutdown_time_client, shutdown_time_server,
mounts, servers, maxservers);
}
return;
}
statd_stop();
handle_sig_cleanup(0);
}
kern_return_t
svc_lockd_request(
mach_port_t mp __attribute__((unused)),
uint32_t vers,
uint32_t flags,
uint64_t xid,
int64_t flk_start,
int64_t flk_len,
int32_t flk_pid,
int32_t flk_type,
int32_t flk_whence,
uint32_t *sock_address,
uint32_t *cred,
uint32_t fh_len,
uint8_t *fh)
{
LOCKD_MSG msg;
int ret;
if (shutdown_time_client) {
shutdown_time_client = 0;
alarm(0);
}
if (hostname[0] == '\0')
(void)gethostname(hostname, sizeof(hostname) - 1);
msg.lm_version = vers;
msg.lm_flags = flags;
msg.lm_xid = xid;
msg.lm_fl.l_start = flk_start;
msg.lm_fl.l_len = flk_len;
msg.lm_fl.l_pid = flk_pid;
msg.lm_fl.l_type = flk_type;
msg.lm_fl.l_whence = flk_whence;
msg.lm_fh_len = fh_len;
bcopy(sock_address, &msg.lm_addr, sizeof(msg.lm_addr));
bcopy(cred, &msg.lm_cred, sizeof(struct xucred));
bcopy(fh, msg.lm_fh, NFSV3_MAX_FH_SIZE);
if (d_args)
show(&msg);
if (msg.lm_version != LOCKD_MSG_VERSION) {
syslog(LOG_ERR, "unknown msg type: %d", msg.lm_version);
}
switch (msg.lm_fl.l_type) {
case F_RDLCK:
case F_WRLCK:
if (msg.lm_flags & LOCKD_MSG_TEST)
ret = test_request(&msg);
else if (msg.lm_flags & LOCKD_MSG_CANCEL)
ret = cancel_request(&msg);
else
ret = lock_request(&msg);
break;
case F_UNLCK:
ret = unlock_request(&msg);
break;
default:
ret = 1;
syslog(LOG_ERR, "unknown lock type: %d", msg.lm_fl.l_type);
break;
}
if (ret) {
struct lockd_ans ans;
bzero(&ans, sizeof(ans));
ans.la_xid = msg.lm_xid;
ans.la_errno = ENOTSUP;
if (nfslockdans(LOCKD_ANS_VERSION, &ans)) {
syslog(LOG_DEBUG, "process %d: %m", msg.lm_fl.l_pid);
}
}
return (KERN_SUCCESS);
}
kern_return_t
svc_lockd_ping(mach_port_t mp __attribute__((unused)))
{
if (shutdown_time_server) {
shutdown_time_server = 0;
alarm(0);
}
return (KERN_SUCCESS);
}
kern_return_t
svc_lockd_shutdown(mach_port_t mp __attribute__((unused)))
{
int mounts, servers, maxservers;
struct timeval now;
time_t shutdown_time;
unsigned int delay;
if (get_client_and_server_state(&mounts, &servers, &maxservers)) {
syslog(LOG_ERR, "lockd_shutdown: sysctl failed");
return (KERN_FAILURE);
}
gettimeofday(&now, NULL);
if ((!servers || !maxservers) && !shutdown_time_server) {
syslog(LOG_DEBUG, "lockd_shutdown: server, delay %d", config.shutdown_delay_server);
shutdown_time_server = now.tv_sec + config.shutdown_delay_server;
}
if (!mounts && !shutdown_time_client) {
syslog(LOG_DEBUG, "lockd_shutdown: client, delay %d", config.shutdown_delay_client);
shutdown_time_client = now.tv_sec + config.shutdown_delay_client;
}
if (!shutdown_time_client || !shutdown_time_server) {
syslog(LOG_DEBUG, "lockd_shutdown: hold on, client %d server %d", shutdown_time_client, shutdown_time_server);
alarm(0);
return (KERN_SUCCESS);
}
shutdown_time = MAX(shutdown_time_client, shutdown_time_server);
delay = shutdown_time - now.tv_sec;
syslog(LOG_DEBUG, "lockd_shutdown: arm timer, delay %d", delay);
alarm(delay);
return (KERN_SUCCESS);
}
static void *
client_request_thread(void *arg __attribute__((unused)))
{
mach_msg_server(lockd_mach_server, MAX_LOCKD_MSG_SIZE,
lockd_receive_right,
MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_AUDIT) |
MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0));
return (NULL);
}
void
client_mach_request(void)
{
#if 0
pthread_t request_thr;
pthread_attr_t attr[1];
#endif
struct sigaction sigalarm;
kern_return_t kr;
int mounts, servers, maxservers;
struct timeval now;
time_t shutdown_time;
unsigned int delay;
kr = bootstrap_check_in(bootstrap_port,
BOOTSTRAP_NAME, &lockd_receive_right);
if (kr != BOOTSTRAP_SUCCESS) {
syslog(LOG_ERR, "Could not checkin for receive right %s\n",
bootstrap_strerror(kr));
return;
}
(void)time(&owner.tod);
owner.pid = getpid();
sigalarm.sa_handler = (sig_t) shutdown_timer;
sigemptyset(&sigalarm.sa_mask);
sigalarm.sa_flags = SA_RESTART;
if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
strerror(errno));
}
gettimeofday(&now, NULL);
mounts = servers = maxservers = 0;
if (get_client_and_server_state(&mounts, &servers, &maxservers))
syslog(LOG_ERR, "lockd setup: sysctl failed");
if (!servers || !maxservers) {
shutdown_time_server = now.tv_sec + config.shutdown_delay_server;
} else {
shutdown_time_server = 0;
}
if (!mounts) {
shutdown_time_client = now.tv_sec + config.shutdown_delay_client;
} else {
shutdown_time_client = 0;
}
if (shutdown_time_client && shutdown_time_server) {
shutdown_time = MAX(shutdown_time_client, shutdown_time_server);
delay = shutdown_time - now.tv_sec;
syslog(LOG_DEBUG, "lockd setup: no client or server, arm timer, delay %d", delay);
alarm(delay);
}
#if 0
pthread_attr_init(attr);
(void) pthread_attr_setdetachstate(attr, PTHREAD_CREATE_DETACHED);
error = pthread_create(&request_thr, attr, client_request_thread, NULL);
if (error) {
syslog(LOG_ERR, "unable to create request thread: %s",
strerror(error));
return;
}
#endif
(void) client_request_thread(NULL);
}
void
set_auth(cl, xucred)
CLIENT *cl;
struct xucred *xucred;
{
if (cl->cl_auth != NULL)
cl->cl_auth->ah_ops->ah_destroy(cl->cl_auth);
cl->cl_auth = authunix_create(hostname,
xucred->cr_uid,
xucred->cr_groups[0],
xucred->cr_ngroups - 1,
(int *)&xucred->cr_groups[1]);
}
int
test_request(LOCKD_MSG *msg)
{
CLIENT *cli;
struct timeval timeout = {0, 0};
char dummy;
if (d_calls)
syslog(LOG_DEBUG, "test request: %s: %s to %s",
(msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3",
msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
from_addr((struct sockaddr *)&msg->lm_addr));
if (msg->lm_flags & LOCKD_MSG_NFSV3) {
struct nlm4_testargs arg4;
arg4.cookie.n_bytes = (char *)&msg->lm_xid;
arg4.cookie.n_len = sizeof(msg->lm_xid);
arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
arg4.alock.caller_name = hostname;
arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
arg4.alock.fh.n_len = msg->lm_fh_len;
arg4.alock.oh.n_bytes = (char *)&owner;
arg4.alock.oh.n_len = sizeof(owner);
arg4.alock.svid = msg->lm_fl.l_pid;
arg4.alock.l_offset = msg->lm_fl.l_start;
arg4.alock.l_len = msg->lm_fl.l_len;
if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS4, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL)
return (1);
set_auth(cli, &msg->lm_cred);
(void)clnt_call(cli, NLM4_TEST_MSG,
(xdrproc_t)xdr_nlm4_testargs, &arg4, (xdrproc_t)xdr_void, &dummy, timeout);
} else {
struct nlm_testargs arg;
arg.cookie.n_bytes = (char *)&msg->lm_xid;
arg.cookie.n_len = sizeof(msg->lm_xid);
arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
arg.alock.caller_name = hostname;
arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
arg.alock.fh.n_len = msg->lm_fh_len;
arg.alock.oh.n_bytes = (char *)&owner;
arg.alock.oh.n_len = sizeof(owner);
arg.alock.svid = msg->lm_fl.l_pid;
arg.alock.l_offset = msg->lm_fl.l_start;
arg.alock.l_len = msg->lm_fl.l_len;
if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL)
return (1);
set_auth(cli, &msg->lm_cred);
(void)clnt_call(cli, NLM_TEST_MSG,
(xdrproc_t)xdr_nlm_testargs, &arg, (xdrproc_t)xdr_void, &dummy, timeout);
}
return (0);
}
int
lock_request(LOCKD_MSG *msg)
{
CLIENT *cli;
struct nlm4_lockargs arg4;
struct nlm_lockargs arg;
struct timeval timeout = {0, 0};
char dummy;
if (d_calls)
syslog(LOG_DEBUG, "lock request: %s %s: %s to %s",
(msg->lm_flags & LOCKD_MSG_RECLAIM) ? "RECLAIM" : "",
(msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3",
msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
from_addr((struct sockaddr *)&msg->lm_addr));
monitor_lock_host_by_addr((struct sockaddr *)&msg->lm_addr);
if (msg->lm_flags & LOCKD_MSG_NFSV3) {
arg4.cookie.n_bytes = (char *)&msg->lm_xid;
arg4.cookie.n_len = sizeof(msg->lm_xid);
arg4.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0;
arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
arg4.alock.caller_name = hostname;
arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
arg4.alock.fh.n_len = msg->lm_fh_len;
arg4.alock.oh.n_bytes = (char *)&owner;
arg4.alock.oh.n_len = sizeof(owner);
arg4.alock.svid = msg->lm_fl.l_pid;
arg4.alock.l_offset = msg->lm_fl.l_start;
arg4.alock.l_len = msg->lm_fl.l_len;
arg4.reclaim = (msg->lm_flags & LOCKD_MSG_RECLAIM) ? 1 : 0;
arg4.state = nsm_state;
if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS4, 1+arg4.reclaim, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL)
return (1);
set_auth(cli, &msg->lm_cred);
(void)clnt_call(cli, NLM4_LOCK_MSG,
(xdrproc_t)xdr_nlm4_lockargs, &arg4, (xdrproc_t)xdr_void, &dummy, timeout);
} else {
arg.cookie.n_bytes = (char *)&msg->lm_xid;
arg.cookie.n_len = sizeof(msg->lm_xid);
arg.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0;
arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
arg.alock.caller_name = hostname;
arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
arg.alock.fh.n_len = msg->lm_fh_len;
arg.alock.oh.n_bytes = (char *)&owner;
arg.alock.oh.n_len = sizeof(owner);
arg.alock.svid = msg->lm_fl.l_pid;
arg.alock.l_offset = msg->lm_fl.l_start;
arg.alock.l_len = msg->lm_fl.l_len;
arg.reclaim = (msg->lm_flags & LOCKD_MSG_RECLAIM) ? 1 : 0;
arg.state = nsm_state;
if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS, 1+arg.reclaim, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL)
return (1);
set_auth(cli, &msg->lm_cred);
(void)clnt_call(cli, NLM_LOCK_MSG,
(xdrproc_t)xdr_nlm_lockargs, &arg, (xdrproc_t)xdr_void, &dummy, timeout);
}
return (0);
}
int
cancel_request(LOCKD_MSG *msg)
{
CLIENT *cli;
struct nlm4_cancargs arg4;
struct nlm_cancargs arg;
struct timeval timeout = {0, 0};
char dummy;
if (d_calls)
syslog(LOG_DEBUG, "cancel request: %s: %s to %s",
(msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3",
msg->lm_fl.l_type == F_WRLCK ? "write" : "read",
from_addr((struct sockaddr *)&msg->lm_addr));
if (msg->lm_flags & LOCKD_MSG_NFSV3) {
arg4.cookie.n_bytes = (char *)&msg->lm_xid;
arg4.cookie.n_len = sizeof(msg->lm_xid);
arg4.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0;
arg4.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
arg4.alock.caller_name = hostname;
arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
arg4.alock.fh.n_len = msg->lm_fh_len;
arg4.alock.oh.n_bytes = (char *)&owner;
arg4.alock.oh.n_len = sizeof(owner);
arg4.alock.svid = msg->lm_fl.l_pid;
arg4.alock.l_offset = msg->lm_fl.l_start;
arg4.alock.l_len = msg->lm_fl.l_len;
if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS4, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL)
return (1);
set_auth(cli, &msg->lm_cred);
(void)clnt_call(cli, NLM4_CANCEL_MSG,
(xdrproc_t)xdr_nlm4_cancargs, &arg4, (xdrproc_t)xdr_void, &dummy, timeout);
} else {
arg.cookie.n_bytes = (char *)&msg->lm_xid;
arg.cookie.n_len = sizeof(msg->lm_xid);
arg.block = (msg->lm_flags & LOCKD_MSG_BLOCK) ? 1 : 0;
arg.exclusive = msg->lm_fl.l_type == F_WRLCK ? 1 : 0;
arg.alock.caller_name = hostname;
arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
arg.alock.fh.n_len = msg->lm_fh_len;
arg.alock.oh.n_bytes = (char *)&owner;
arg.alock.oh.n_len = sizeof(owner);
arg.alock.svid = msg->lm_fl.l_pid;
arg.alock.l_offset = msg->lm_fl.l_start;
arg.alock.l_len = msg->lm_fl.l_len;
if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL)
return (1);
set_auth(cli, &msg->lm_cred);
(void)clnt_call(cli, NLM_CANCEL_MSG,
(xdrproc_t)xdr_nlm_cancargs, &arg, (xdrproc_t)xdr_void, &dummy, timeout);
}
return (0);
}
int
unlock_request(LOCKD_MSG *msg)
{
CLIENT *cli;
struct nlm4_unlockargs arg4;
struct nlm_unlockargs arg;
struct timeval timeout = {0, 0};
char dummy;
if (d_calls)
syslog(LOG_DEBUG, "unlock request: %s: to %s",
(msg->lm_flags & LOCKD_MSG_NFSV3) ? "V4" : "V1/3",
from_addr((struct sockaddr *)&msg->lm_addr));
if (msg->lm_flags & LOCKD_MSG_NFSV3) {
arg4.cookie.n_bytes = (char *)&msg->lm_xid;
arg4.cookie.n_len = sizeof(msg->lm_xid);
arg4.alock.caller_name = hostname;
arg4.alock.fh.n_bytes = (char *)&msg->lm_fh;
arg4.alock.fh.n_len = msg->lm_fh_len;
arg4.alock.oh.n_bytes = (char *)&owner;
arg4.alock.oh.n_len = sizeof(owner);
arg4.alock.svid = msg->lm_fl.l_pid;
arg4.alock.l_offset = msg->lm_fl.l_start;
arg4.alock.l_len = msg->lm_fl.l_len;
if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS4, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL)
return (1);
set_auth(cli, &msg->lm_cred);
(void)clnt_call(cli, NLM4_UNLOCK_MSG,
(xdrproc_t)xdr_nlm4_unlockargs, &arg4, (xdrproc_t)xdr_void, &dummy, timeout);
} else {
arg.cookie.n_bytes = (char *)&msg->lm_xid;
arg.cookie.n_len = sizeof(msg->lm_xid);
arg.alock.caller_name = hostname;
arg.alock.fh.n_bytes = (char *)&msg->lm_fh;
arg.alock.fh.n_len = msg->lm_fh_len;
arg.alock.oh.n_bytes = (char *)&owner;
arg.alock.oh.n_len = sizeof(owner);
arg.alock.svid = msg->lm_fl.l_pid;
arg.alock.l_offset = msg->lm_fl.l_start;
arg.alock.l_len = msg->lm_fl.l_len;
if ((cli = get_client((struct sockaddr *)&msg->lm_addr, NLM_VERS, 1, (msg->lm_flags & LOCKD_MSG_TCP))) == NULL)
return (1);
set_auth(cli, &msg->lm_cred);
(void)clnt_call(cli, NLM_UNLOCK_MSG,
(xdrproc_t)xdr_nlm_unlockargs, &arg, (xdrproc_t)xdr_void, &dummy, timeout);
}
return (0);
}
int
lock_answer(int version, netobj *netcookie, nlm4_lock *lock, int flags, int result)
{
struct lockd_ans ans;
ans.la_flags = 0;
ans.la_pid = 0;
if (flags & LOCK_ANSWER_GRANTED)
ans.la_flags |= LOCKD_ANS_GRANTED;
if (netcookie->n_len != sizeof(ans.la_xid)) {
if (lock == NULL) {
syslog(LOG_ERR, "inedible nlm cookie");
return -1;
}
ans.la_xid = 0;
ans.la_fh_len = lock->fh.n_len;
if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) {
syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len);
return -1;
}
memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len);
ans.la_pid = lock->svid;
ans.la_start = lock->l_offset;
ans.la_len = lock->l_len;
ans.la_flags |= LOCKD_ANS_LOCK_INFO;
if (flags & LOCK_ANSWER_LOCK_EXCL)
ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
} else {
memcpy(&ans.la_xid, netcookie->n_bytes, sizeof(ans.la_xid));
ans.la_fh_len = 0;
}
if (d_calls)
syslog(LOG_DEBUG, "lock answer: pid %d: %s %d", ans.la_pid,
version == NLM_VERS4 ? "nlmv4" : "nlmv3", result);
if (version == NLM_VERS4)
switch (result) {
case nlm4_granted:
ans.la_errno = 0;
if ((flags & LOCK_ANSWER_GRANTED) && lock &&
!(ans.la_flags & LOCKD_ANS_LOCK_INFO)) {
ans.la_fh_len = lock->fh.n_len;
if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) {
syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len);
return -1;
}
memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len);
ans.la_pid = lock->svid;
ans.la_start = lock->l_offset;
ans.la_len = lock->l_len;
ans.la_flags |= LOCKD_ANS_LOCK_INFO;
if (flags & LOCK_ANSWER_LOCK_EXCL)
ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
}
break;
default:
ans.la_errno = EACCES;
break;
case nlm4_denied:
if (lock == NULL)
ans.la_errno = EAGAIN;
else {
ans.la_pid = lock->svid;
ans.la_start = lock->l_offset;
ans.la_len = lock->l_len;
ans.la_flags |= LOCKD_ANS_LOCK_INFO;
if (flags & LOCK_ANSWER_LOCK_EXCL)
ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
ans.la_errno = 0;
}
break;
case nlm4_denied_nolocks:
ans.la_errno = ENOLCK;
break;
case nlm4_blocked:
ans.la_errno = EINPROGRESS;
break;
case nlm4_denied_grace_period:
ans.la_errno = EAGAIN;
ans.la_flags |= LOCKD_ANS_DENIED_GRACE;
break;
case nlm4_deadlck:
ans.la_errno = EDEADLK;
break;
case nlm4_rofs:
ans.la_errno = EROFS;
break;
case nlm4_stale_fh:
ans.la_errno = ESTALE;
break;
case nlm4_fbig:
ans.la_errno = EFBIG;
break;
case nlm4_failed:
ans.la_errno = EACCES;
break;
}
else
switch (result) {
case nlm_granted:
ans.la_errno = 0;
if ((flags & LOCK_ANSWER_GRANTED) && lock &&
!(ans.la_flags & LOCKD_ANS_LOCK_INFO)) {
ans.la_fh_len = lock->fh.n_len;
if (!lock->fh.n_len || (lock->fh.n_len > NFS_SMALLFH)) {
syslog(LOG_ERR, "bogus filehandle size %d in answer", lock->fh.n_len);
return -1;
}
memcpy(ans.la_fh, lock->fh.n_bytes, ans.la_fh_len);
ans.la_pid = lock->svid;
ans.la_start = lock->l_offset;
ans.la_len = lock->l_len;
ans.la_flags |= LOCKD_ANS_LOCK_INFO;
if (flags & LOCK_ANSWER_LOCK_EXCL)
ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
}
break;
default:
ans.la_errno = EACCES;
break;
case nlm_denied:
if (lock == NULL)
ans.la_errno = EAGAIN;
else {
ans.la_pid = lock->svid;
ans.la_start = lock->l_offset;
ans.la_len = lock->l_len;
ans.la_flags |= LOCKD_ANS_LOCK_INFO;
if (flags & LOCK_ANSWER_LOCK_EXCL)
ans.la_flags |= LOCKD_ANS_LOCK_EXCL;
ans.la_errno = 0;
}
break;
case nlm_denied_nolocks:
ans.la_errno = ENOLCK;
break;
case nlm_blocked:
ans.la_errno = EINPROGRESS;
break;
case nlm_denied_grace_period:
ans.la_errno = EAGAIN;
ans.la_flags |= LOCKD_ANS_DENIED_GRACE;
break;
case nlm_deadlck:
ans.la_errno = EDEADLK;
break;
}
if (nfslockdans(LOCKD_ANS_VERSION, &ans)) {
syslog(LOG_DEBUG, "lock_answer(%d): process %d: %m",
result, ans.la_pid);
return -1;
}
return 0;
}
void
show(LOCKD_MSG *mp)
{
static char hex[] = "0123456789abcdef";
size_t len;
u_int8_t *p, *t, buf[NFS_SMALLFH*3+1];
syslog(LOG_DEBUG, "process ID: %d\n", mp->lm_fl.l_pid);
for (t = buf, p = (u_int8_t *)mp->lm_fh,
len = mp->lm_fh_len;
len > 0; ++p, --len) {
*t++ = '\\';
*t++ = hex[(*p & 0xf0) >> 4];
*t++ = hex[*p & 0x0f];
}
*t = '\0';
syslog(LOG_DEBUG, "fh_len %d, fh %s\n", mp->lm_fh_len, buf);
syslog(LOG_DEBUG, "start %qu; len %qu; pid %d; type %d; whence %d\n",
mp->lm_fl.l_start, mp->lm_fl.l_len, mp->lm_fl.l_pid,
mp->lm_fl.l_type, mp->lm_fl.l_whence);
syslog(LOG_DEBUG, "wait was %s\n", (mp->lm_flags & LOCKD_MSG_BLOCK) ? "set" : "not set");
}