/*
 * mountd	This program handles RPC "NFS" mount requests.
 *
 * Usage:	[rpc.]mountd [-dhnpv] [-f authfile]
 *
 * Authors:	Mark A. Shand, May 1988
 *		Donald J. Becker, <becker@super.org>
 *		Rick Sladkey, <jrs@world.std.com>
 *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 *
 *		Copyright 1988 Mark A. Shand
 *		This software maybe be used for any purpose provided
 *		the above copyright notice is retained.  It is supplied
 *		as is, with no warranty expressed or implied.
 */

#include "nfsd.h"
#include "getopt.h"

#ifndef HAVE_RPCGEN_C
#define mountproc_null_1_svc		mountproc_null_1
#define mountproc_mnt_1_svc		mountproc_mnt_1
#define mountproc_dump_1_svc		mountproc_dump_1
#define mountproc_umnt_1_svc		mountproc_umnt_1
#define mountproc_umntall_1_svc		mountproc_umntall_1
#define mountproc_export_1_svc		mountproc_export_1
#define mountproc_exportall_1_svc	mountproc_exportall_1
#endif

char argbuf[MNTPATHLEN + 1];
char *auth_file = NULL;
#ifndef HAVE_RPCGEN_I
int _rpcpmstart = 0;
#endif

static _PRO(void usage, (FILE *, int));
extern _PRO(int mountd_main, (int, char **));

extern char version[];
static char *program_name;
static struct option longopts[] =
{
	{ "debug", 0, 0, 'd' },
	{ "exports-file", 1, 0, 'f' },
	{ "help", 0, 0, 'h' },
	{ "allow-non-root", 0, 0, 'n' },
	{ "promiscous", 0, 0, 'p' },
	{ "re-export", 0, 0, 'r', },
	{ "version", 0, 0, 'v' },
	{ NULL, 0, 0, 0 }
};

/* In mount_svc.c: */
extern _PRO(void mount_run, (void));

/* The NULL request handler. */
void *mountproc_null_1_svc(argp, rqstp)
void *argp;
struct svc_req *rqstp;
{
	static char res;

	memset(&res, '\0', sizeof(res));
	log_call(rqstp, "mountproc_null_1", "");
	return ((void *) &res);
}

fhstatus *mountproc_mnt_1_svc(argp, rqstp)
dirpath *argp;
struct svc_req *rqstp;
{
	static fhstatus res;
	struct stat stbuf;
	clnt_param *cp;
	char nargbuf[MNTPATHLEN + 1];

	memset(&res, '\0', sizeof(res));
	sprintf(argbuf, "%s", *argp);
	log_call(rqstp, "mountproc_mnt_1", argbuf);

	/* It is important to resolve symlinks before checking permissions. */
	if (realpath(argbuf, nargbuf) == NULL) {
		res.fhs_status = nfs_errno();
		return (&res);
	}
	strcpy(argbuf, nargbuf);
	if (stat(argbuf, &stbuf) < 0) {
		res.fhs_status = nfs_errno();
		return (&res);
	}

	/* Now authenticate the intruder... */
	if (((cp = auth_clnt(rqstp, argbuf)) == NULL))
		res.fhs_status = NFSERR_ACCES;
	else if (!S_ISDIR(stbuf.st_mode) && !S_ISREG(stbuf.st_mode))
		res.fhs_status = NFSERR_NOTDIR;
	else
		res.fhs_status = fh_create((nfs_fh *)
			&res.fhstatus_u.fhs_fhandle, argbuf);
	return (&res);
}

mountlist *mountproc_dump_1_svc(argp, rqstp)
void *argp;
struct svc_req *rqstp;
{
	static mountlist res;

	memset(&res, '\0', sizeof(res));
	log_call(rqstp, "mountproc_dump_1", "");
	return (&res);
}

void *mountproc_umnt_1_svc(argp, rqstp)
dirpath *argp;
struct svc_req *rqstp;
{
	static char res;

	memset(&res, '\0', sizeof(res));
	sprintf(argbuf, "%s", *argp);
	log_call(rqstp, "mountproc_umnt_1", argbuf);
	return ((void *) &res);
}

void *mountproc_umntall_1_svc(argp, rqstp)
void *argp;
struct svc_req *rqstp;
{
	static char res;

	memset(&res, '\0', sizeof(res));
	log_call(rqstp, "mountproc_umntall_1", "");
	return ((void *) &res);
}

exports *mountproc_export_1_svc(argp, rqstp)
void *argp;
struct svc_req *rqstp;
{
	static exports res;

	memset(&res, '\0', sizeof(res));
	log_call(rqstp, "mountproc_export_1", "");
	res = export_list;
	return (&res);
}

exports *mountproc_exportall_1_svc(argp, rqstp)
void *argp;
struct svc_req *rqstp;
{
	log_call(rqstp, "mountproc_exportall_1", "");
	return (mountproc_export_1_svc(argp, rqstp));
}

static void mountd_init(argc, argv)
int argc;
char *argv[];
{
	int c;

	program_name = argv[0];

	/* Parse the command line options and arguments. */
	opterr = 0;
	while ((c = getopt_long(argc, argv, "df:hnprv", longopts, NULL)) != EOF)
		switch (c) {
		case 'h':
			usage(stdout, 0);
			break;
		case 'd':
			toggle_logging(0);
			break;
		case 'f':
			auth_file = optarg;
			break;
		case 'n':
			allow_non_root = 1;
			break;
		case 'p':
			promiscuous = 1;
			break;
		case 'r':
			re_export = 1;
			break;
		case 'v':
			printf("%s\n", version);
			exit(0);
		case 0:
			break;
		case '?':
		default:
			usage(stderr, 1);
		}

	/* No more arguments allowed. */
	if (optind != argc)
		usage(stderr, 1);

#ifndef HAVE_RPCGEN_I
#ifndef RPC_SVC_FG
	/* We first fork off a child. */
	if ((c = fork()) > 0)
		exit(0);
	if (c < 0) {
		fprintf(stderr, "mountd: cannot fork: %s\n", strerror(errno));
		exit(-1);
	}
	/* Now we remove ourselves from the foreground. */
	(void) close(0);
	(void) close(1);
	(void) close(2);
#ifdef TIOCNOTTY
	if ((c = open("/dev/tty", O_RDWR)) >= 0) {
		(void) ioctl(c, TIOCNOTTY, (char *) NULL);
		(void) close(c);
	}
#else
	setsid();
#endif
#endif /* not RPC_SVC_FG */
#endif /* not HAVE_RPCGEN_I */

	/* Initialize logging. */
	log_open("mountd");

	/* Initialize the FH module. */
	fh_init();

	/* Initialize the AUTH module. */
	auth_init(auth_file);

	/* Enable the LOG toggle with a signal. */
	(void) signal(SIGUSR1, toggle_logging);
}

int main(argc, argv)
int argc;
char *argv[];
{
	mountd_init(argc, argv);
	mountd_main(argc, argv);
	exit(0);
}

static void usage(fp, n)
FILE *fp;
int n;
{
	fprintf(fp, "Usage: %s [-dhnpv] [-f exports-file]\n", program_name);
	fprintf(fp, "       [--debug] [--help] [--allow-non-root]\n");
	fprintf(fp, "       [--promiscuous] [--version]\n");
	fprintf(fp, "       [--exports-file=file]\n");
	exit(n);
}

