#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/syslog.h>
#include <sys/ucred.h>
#include <sys/wait.h>
#include <sys/mount.h>
#include <sys/time.h>
#include <nfs/rpcv2.h>
#include <nfs/nfsproto.h>
#include <nfs/nfs.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#ifdef DEBUG
int debug = 1;
#else
int debug = 0;
#endif
int *thread_status = NULL;
pthread_cond_t cond;
pthread_mutex_t mutex;
void nonfs __P((int));
void usage __P((void));
void *nfsiod_thread __P((void *));
int
main(argc, argv)
int argc;
char *argv[];
{
int ch, num_servers;
int i, rv, threadcnt;
#define MAXNFSIODCNT 32
#define DEFNFSIODCNT 1
num_servers = DEFNFSIODCNT;
while ((ch = getopt(argc, argv, "n:")) != EOF)
switch (ch) {
case 'n':
num_servers = atoi(optarg);
if (num_servers < 1 || num_servers > MAXNFSIODCNT) {
warnx("nfsiod count %d; reset to %d",
num_servers, DEFNFSIODCNT);
num_servers = DEFNFSIODCNT;
}
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc > 1)
usage();
if (argc == 1) {
num_servers = atoi(argv[0]);
if (num_servers < 1 || num_servers > MAXNFSIODCNT) {
warnx("nfsiod count %d; reset to %d",
num_servers, DEFNFSIODCNT);
num_servers = DEFNFSIODCNT;
}
}
thread_status = malloc(sizeof(int) * num_servers);
if (thread_status == NULL)
errx(1, "unable to allocate memory");
rv = pthread_cond_init(&cond, NULL);
if (rv)
errc(1, rv, "condition variable init failed");
rv = pthread_mutex_init(&mutex, NULL);
if (rv)
errc(1, rv, "mutex init failed");
if (debug == 0) {
daemon(0, 0);
(void)signal(SIGHUP, SIG_IGN);
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGSYS, nonfs);
}
openlog("nfsiod:", LOG_PID, LOG_DAEMON);
threadcnt = 0;
for (i=0; i < num_servers; i++) {
pthread_t thd;
thread_status[i] = 1;
rv = pthread_create(&thd, NULL, nfsiod_thread, (void*)i);
if (rv) {
syslog(LOG_ERR, "thread_create: %s", strerror(rv));
thread_status[i] = 0;
continue;
}
threadcnt++;
}
if (!threadcnt)
errx(1, "unable to start any threads");
if (threadcnt != num_servers)
syslog(LOG_ERR, "only able to create %d of %d threads",
threadcnt, num_servers);
rv = pthread_mutex_lock(&mutex);
if (rv)
errc(1, rv, "mutex lock failed");
while (threadcnt > 0) {
rv = pthread_cond_wait(&cond, &mutex);
if (rv)
errc(1, rv, "nfsiod: cond wait failed");
for (i=0; i < num_servers; i++) {
if (!thread_status[i])
continue;
if (thread_status[i] == 1)
continue;
threadcnt--;
thread_status[i] = 0;
syslog(LOG_ERR, "lost nfsiod thread %d - "
"%d of %d threads remain",
i, threadcnt, num_servers);
}
rv = pthread_mutex_lock(&mutex);
if (rv)
errc(1, rv, "mutex lock failed");
}
exit (0);
}
void *
nfsiod_thread(void *arg)
{
int rv, thread = (int)arg;
if ((rv = nfssvc(NFSSVC_BIOD, NULL)) < 0) {
thread_status[thread] = rv;
syslog(LOG_ERR, "nfssvc: %s", strerror(rv));
pthread_cond_signal(&cond);
return NULL;
}
thread_status[thread] = 0;
pthread_cond_signal(&cond);
return NULL;
}
void
nonfs(signo)
int signo;
{
syslog(LOG_ERR, "missing system call: NFS not available.");
}
void
usage()
{
(void)fprintf(stderr, "usage: nfsiod [-n num_servers]\n");
exit(1);
}