/*
 * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
 * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License version 2.
 */

#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/completion.h>
#include <linux/buffer_head.h>
#include <linux/gfs2_ondisk.h>
#include <linux/lm_interface.h>

#include "gfs2.h"
#include "incore.h"
#include "mount.h"
#include "sys.h"
#include "util.h"

/**
 * gfs2_mount_args - Parse mount options
 * @sdp:
 * @data:
 *
 * Return: errno
 */

int gfs2_mount_args(struct gfs2_sbd *sdp, char *data_arg, int remount)
{
	struct gfs2_args *args = &sdp->sd_args;
	char *data = data_arg;
	char *options, *o, *v;
	int error = 0;

	if (!remount) {
		/*  If someone preloaded options, use those instead  */
		spin_lock(&gfs2_sys_margs_lock);
		if (gfs2_sys_margs) {
			data = gfs2_sys_margs;
			gfs2_sys_margs = NULL;
		}
		spin_unlock(&gfs2_sys_margs_lock);

		/*  Set some defaults  */
		args->ar_num_glockd = GFS2_GLOCKD_DEFAULT;
		args->ar_quota = GFS2_QUOTA_DEFAULT;
		args->ar_data = GFS2_DATA_DEFAULT;
	}

	/* Split the options into tokens with the "," character and
	   process them */

	for (options = data; (o = strsep(&options, ",")); ) {
		if (!*o)
			continue;

		v = strchr(o, '=');
		if (v)
			*v++ = 0;

		if (!strcmp(o, "lockproto")) {
			if (!v)
				goto need_value;
			if (remount && strcmp(v, args->ar_lockproto))
				goto cant_remount;
			strncpy(args->ar_lockproto, v, GFS2_LOCKNAME_LEN);
			args->ar_lockproto[GFS2_LOCKNAME_LEN - 1] = 0;
		}

		else if (!strcmp(o, "locktable")) {
			if (!v)
				goto need_value;
			if (remount && strcmp(v, args->ar_locktable))
				goto cant_remount;
			strncpy(args->ar_locktable, v, GFS2_LOCKNAME_LEN);
			args->ar_locktable[GFS2_LOCKNAME_LEN - 1] = 0;
		}

		else if (!strcmp(o, "hostdata")) {
			if (!v)
				goto need_value;
			if (remount && strcmp(v, args->ar_hostdata))
				goto cant_remount;
			strncpy(args->ar_hostdata, v, GFS2_LOCKNAME_LEN);
			args->ar_hostdata[GFS2_LOCKNAME_LEN - 1] = 0;
		}

		else if (!strcmp(o, "spectator")) {
			if (remount && !args->ar_spectator)
				goto cant_remount;
			args->ar_spectator = 1;
			sdp->sd_vfs->s_flags |= MS_RDONLY;
		}

		else if (!strcmp(o, "ignore_local_fs")) {
			if (remount && !args->ar_ignore_local_fs)
				goto cant_remount;
			args->ar_ignore_local_fs = 1;
		}

		else if (!strcmp(o, "localflocks")) {
			if (remount && !args->ar_localflocks)
				goto cant_remount;
			args->ar_localflocks = 1;
		}

		else if (!strcmp(o, "localcaching")) {
			if (remount && !args->ar_localcaching)
				goto cant_remount;
			args->ar_localcaching = 1;
		}

		else if (!strcmp(o, "debug"))
			args->ar_debug = 1;

		else if (!strcmp(o, "nodebug"))
			args->ar_debug = 0;

		else if (!strcmp(o, "upgrade")) {
			if (remount && !args->ar_upgrade)
				goto cant_remount;
			args->ar_upgrade = 1;
		}

		else if (!strcmp(o, "num_glockd")) {
			unsigned int x;
			if (!v)
				goto need_value;
			sscanf(v, "%u", &x);
			if (remount && x != args->ar_num_glockd)
				goto cant_remount;
			if (!x || x > GFS2_GLOCKD_MAX) {
				fs_info(sdp, "0 < num_glockd <= %u  (not %u)\n",
				        GFS2_GLOCKD_MAX, x);
				error = -EINVAL;
				break;
			}
			args->ar_num_glockd = x;
		}

		else if (!strcmp(o, "acl")) {
			args->ar_posix_acl = 1;
			sdp->sd_vfs->s_flags |= MS_POSIXACL;
		}

		else if (!strcmp(o, "noacl")) {
			args->ar_posix_acl = 0;
			sdp->sd_vfs->s_flags &= ~MS_POSIXACL;
		}

		else if (!strcmp(o, "quota")) {
			if (!v)
				goto need_value;
			if (!strcmp(v, "off"))
				args->ar_quota = GFS2_QUOTA_OFF;
			else if (!strcmp(v, "account"))
				args->ar_quota = GFS2_QUOTA_ACCOUNT;
			else if (!strcmp(v, "on"))
				args->ar_quota = GFS2_QUOTA_ON;
			else {
				fs_info(sdp, "invalid value for quota\n");
				error = -EINVAL;
				break;
			}
		}

		else if (!strcmp(o, "suiddir"))
			args->ar_suiddir = 1;

		else if (!strcmp(o, "nosuiddir"))
			args->ar_suiddir = 0;

		else if (!strcmp(o, "data")) {
			if (!v)
				goto need_value;
			if (!strcmp(v, "writeback"))
				args->ar_data = GFS2_DATA_WRITEBACK;
			else if (!strcmp(v, "ordered"))
				args->ar_data = GFS2_DATA_ORDERED;
			else {
				fs_info(sdp, "invalid value for data\n");
				error = -EINVAL;
				break;
			}
		}

		else {
			fs_info(sdp, "unknown option: %s\n", o);
			error = -EINVAL;
			break;
		}
	}

	if (error)
		fs_info(sdp, "invalid mount option(s)\n");

	if (data != data_arg)
		kfree(data);

	return error;

need_value:
	fs_info(sdp, "need value for option %s\n", o);
	return -EINVAL;

cant_remount:
	fs_info(sdp, "can't remount with option %s\n", o);
	return -EINVAL;
}

