#include <arpa/inet.h>
#include <sys/mount.h>
#include <sys/stat.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include "ipconfig.h"
#include "kinit.h"
#include "netdev.h"
#include "nfsmount.h"

static char *sub_client(__u32 client, char *path, size_t len)
{
	struct in_addr addr = { client };
	char buf[len];

	if (strstr(path, "%s") != NULL) {
		if (client == INADDR_NONE) {
			fprintf(stderr, "Root-NFS: no client address\n");
			exit(1);
		}

		snprintf(buf, len, path, inet_ntoa(addr));
		strcpy(path, buf);
	}

	return path;
}

#define NFS_ARGC 6
#define MOUNT_POINT "/root"

int mount_nfs_root(int argc, char *argv[], int flags)
{
	(void) flags; // FIXME - don't ignore this
	
	struct in_addr addr = { INADDR_NONE };
	__u32 client = INADDR_NONE;
	const int len = 1024;
	struct netdev *dev;
	char *mtpt = MOUNT_POINT;
	char *path = NULL;
	char *dev_bootpath = NULL;
	char root[len];
	char *x, *opts;
	int ret = 0;
	int a = 1;
	char *nfs_argv[NFS_ARGC + 1] = { "NFS-Mount" };

	for (dev = ifaces; dev; dev = dev->next) {
		if (dev->ip_server != INADDR_NONE &&
		    dev->ip_server != INADDR_ANY) {
			addr.s_addr = dev->ip_server;
			client = dev->ip_addr;
			dev_bootpath = dev->bootpath;
			break;
		}
		if (dev->ip_addr != INADDR_NONE &&
		    dev->ip_addr != INADDR_ANY) {
			client = dev->ip_addr;
		}
	}

	/*
	 * if the "nfsroot" option is set then it overrides
	 * bootpath supplied by the boot server.
	 */
	if ((path = get_arg(argc, argv, "nfsroot=")) == NULL ) {
		if ((path = dev_bootpath) == NULL || path[0] == '\0')
			/* no path - set a default */
			path = (char *) "/tftpboot/%s";
	} else if (dev_bootpath && dev_bootpath[0] != '\0')
		fprintf(stderr,
			"nsfroot=%s overrides boot server bootpath %s\n",
			path, dev_bootpath);

	if ((opts = strchr(path, ',')) != NULL) {
		*opts++ = '\0';
		nfs_argv[a++] = (char *) "-o";
		nfs_argv[a++] = opts;
	}

	if ((x = strchr(path, ':')) == NULL) {
		if (addr.s_addr == INADDR_NONE) {
			fprintf(stderr, "Root-NFS: no server defined\n");
			exit(1);
		}

		snprintf(root, len, "%s:%s", inet_ntoa(addr), path);

		nfs_argv[a++] = sub_client(client, root, len);
	} else {
		strcpy(root, path);
		nfs_argv[a++] = sub_client(client, root, len);
	}

	DEBUG(("NFS-Root: mounting %s on %s with options '%s'\n",
	       argv[a - 1], mtpt, opts ? opts : "none"));

	nfs_argv[a++] = mtpt;
	nfs_argv[a] = NULL;
	assert(a <= NFS_ARGC);

	if ((ret = nfsmount_main(a, nfs_argv)) != 0) {
		ret = -1;
		goto done;
	}

done:
	return ret;
}
