[linux-cifs-client] [PATCH 1/2]: Utility program that allows configuration of cifs client settings

Suresh Jayaraman sjayaraman at suse.de
Mon Jan 7 15:38:24 GMT 2008


This patch provides a utility program that allows configuration 
of cifs VFS client settings using the /proc interface.

Signed-off-by: Suresh Jayaraman <sjayaraman at suse.de>
---

/*
 * cifsconfig.c - Simple program that allows run-time cifs configuration using
 * the proc interface
 *
 * Copyright (C) 2008 Suresh Jayaraman (sjayaraman at suse.de)
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

/* Configurable files in /proc/fs/cifs */
#define CIFS_MULTIUSRMNT	"/proc/fs/cifs/MultiuserMount"
#define CIFS_SECFLAGS		"/proc/fs/cifs/SecurityFlags"
#define CIFS_DBGINFO		"/proc/fs/cifs/cifsFYI"
#define CIFS_TRACESMB		"/proc/fs/cifs/traceSMB"
#define CIFS_LOOKUPCACHE	"/proc/fs/cifs/LookupCacheEnabled"
#define CIFS_OPLOCK		"/proc/fs/cifs/OplockEnabled"
#define CIFS_LINUXEXTN		"/proc/fs/cifs/LinuxExtensionsEnabled"
#define CIFS_EXPERIMENTAL	"/proc/fs/cifs/Experimental"

#define FLAG_LEN		12

static char *progname;

/* Function prototypes */
static void usage(void);
static void dump_cfg_values(void);
static void dump_fileinfo(char *);
static int check_input(char *, int);
static int set_cifs_param(char *, unsigned int);
static int set_sec_flags(char *);

static void usage(void)
{
	fprintf(stderr,
		"Usage: %s [OPTION] [VALUE]\n"
		"OPTIONS:\n"
		"\t-a\t\tShow all cifs config values\n"
		"\t-h\t\tShow help information\n"
		"\t-d [flags]\tSet cifsFYI debug log level\n"
		"\t-t [value]\tEnable(1)/Disable(0) traceSMB\n"
		"\t-x [value]\tEnable(1)/Disable(0) Experimental options\n"
		"\t-c [value]\tEnable(1)/Disable(0) LookupCache\n"
		"\t-m [value]\tEnable(1)/Disable(0) MultiuserMount\n"
		"\t-l [value]\tEnable(1)/Disable(0) LinuxExtensions\n"
		"\t-o [value]\tEnable(1)/Disable(0) Oplock\n"
		"\t-s [flags]\tSet security flag in hex\n",
		progname);

	exit(1);
}

static void dump_fileinfo(char *proc_file)
{
	FILE *fp;
	char buf[FLAG_LEN];
	char *config;

	config = strrchr(proc_file, '/');
	if (config != NULL)
		config++;
	else
		config = proc_file;

	printf("\t%s: ", config);
	fp = fopen(proc_file, "r");
	if (fp != NULL) {
		while (fgets(buf, sizeof(buf), fp) != NULL)
			fprintf(stdout, "%s", buf);
		fclose(fp);
	} else if (errno == ENOENT) {
		fprintf(stderr, "%s: failed to open %s : %s\n", progname,
				proc_file, strerror(errno));
		fprintf(stderr, "Hint: Check whether cifs module is loaded\n");
		exit(1);
	} else {
		fprintf(stderr, "%s: failed to open %s: %s\n", progname,
				proc_file, strerror(errno));
		exit(1);
	}

	return;
}

static void dump_cfg_values(void)
{
	/* Dump all config values */
	printf("CIFS Configuration\n");
	printf("------------------\n");
	dump_fileinfo(CIFS_DBGINFO);
	dump_fileinfo(CIFS_TRACESMB);
	dump_fileinfo(CIFS_EXPERIMENTAL);
	dump_fileinfo(CIFS_LOOKUPCACHE);
	dump_fileinfo(CIFS_MULTIUSRMNT);
	dump_fileinfo(CIFS_LINUXEXTN);
	dump_fileinfo(CIFS_OPLOCK);
	dump_fileinfo(CIFS_SECFLAGS);

	return;
}

/*
 * We seem to allow '1' or 'y' or 'Y' for setting values and
 * '0' or 'n' or 'N' for resetting values
 */
static int check_input(char *val, int dbg)
{
	char ch = *val;
	int flag;

	if (ch == '0'  || ch == 'n' || ch == 'N')
		flag = 0;
	else if (ch == '1' || ch == 'y' || ch == 'Y')
		flag = 1;
	else if ((ch > '1') && (ch <= '9')) {
		/* Currently, cifs module allows value up to 9 though the
		 * maximum value can be 7.
		 * Only cifsFYI can contain values other than '0' and '1' */
		if (dbg)
			flag = (int) (ch - '0');
		else
			return -1;
	} else
		return -1;

	return flag;
}

/*
 * Use this function to set/reset values
 */
int set_cifs_param(char *proc_file, unsigned int value)
{
	FILE *fp;

	fp = fopen(proc_file, "w");
	if (fp != NULL) {
		if (fprintf(fp, "%u\n", value) < 0) {
			fprintf(stderr, "%s: failed to write to %s: %s\n",
					progname, proc_file, strerror(errno));
			return -1;
		}
		fclose(fp);
	} else {
		fprintf(stderr, "%s: failed to open %s: %s\n", progname,
				proc_file, strerror(errno));
		return -1;
	}
	printf("Set %s to %u\n", proc_file, value);

	return 0;
}

int set_sec_flags(char *value)
{
	FILE *fp;
	char buf[FLAG_LEN];
	char *copy;

	memset(buf, 0, sizeof(buf));

	fp = fopen(CIFS_SECFLAGS, "w");
	if (fp != NULL) {
		if (strlen(value)+1 > FLAG_LEN) {
			fprintf(stderr, "%s: Security flag too long\n", progname);
			return -1;
		}
		snprintf(buf, sizeof(buf), "0x%s", value);
		buf[sizeof(buf)-1] = '\0';
		copy = strdup(buf);
		if (copy == NULL) {
			fprintf(stderr, "%s: failed to allocate memory\n",
					progname);
			return -1;
		}

		if (fprintf(fp, "%s\n", buf) < 0) {
			fprintf(stderr, "%s: failed to write to %s: %s\n",
					progname, CIFS_SECFLAGS, strerror(errno));
			return -1;
		}
		fclose(fp);
		/* XXX: This is ugly. Currently, as there seem to be no 
		 * foolproof way to check whether the flag is valid or not
		 * from user space, we read back the value to make sure the 
		 * security flags are actually set. */
		fp = fopen(CIFS_SECFLAGS, "r");
		if (fp != NULL) {
			if (fgets(buf, sizeof(buf), fp) != NULL)
				buf[strlen(buf)-1] = '\0';
		}
		fclose(fp);
		if (strcmp(copy, buf)) {
			fprintf(stderr, "%s: failed to set Security flag."
				"The flag %s may be invalid\n", progname, value);
			fprintf(stderr, "Hint: Check fs/cifs/README for valid"
				"flags\n");
			return -1;
		}
	} else {
		fprintf(stderr, "%s: failed to open %s: %s\n", progname,
				CIFS_SECFLAGS, strerror(errno));
		return -1;
	}
	printf("Set %s to %s\n", CIFS_SECFLAGS, value);

	if (copy)
		free(copy);

	return 0;
}


int main(int argc, char *argv[])
{
	int opt, i;
	int dval, tval, xval;
	int cval, mval, opval, lval;
	char *secval;

	dval = tval = xval = 0;
	cval = mval = opval = lval = 0;
	progname = argv[0];
	if (argc < 2) {
		fprintf(stderr, "%s: missing arguments\n", progname);
		fprintf(stderr, "Try `%s -h' for more information.\n",
				progname);
		return -1;
	}

	while ((opt = getopt(argc, argv, "ahd:t:x:c:m:o:l:s:")) != -1) {
		switch (opt) {
		case 'a':
			if (argc != 2)
				usage();
			else {
				dump_cfg_values();
				break;
			}
		case 'm':
			mval = check_input(optarg, 0);
			if (mval < 0)
				goto err_bad;
			else {
				if (set_cifs_param(CIFS_MULTIUSRMNT, mval))
					goto err_fail;
				break;
			}
		case 't':
			tval = check_input(optarg, 0);
			if (tval < 0)
				goto err_bad;
			else {
				if (set_cifs_param(CIFS_TRACESMB, tval))
					goto err_fail;
				else
					break;
			}
		case 'c':
			cval = check_input(optarg, 0);
			if (cval < 0)
				goto err_bad;
			else {
				if (set_cifs_param(CIFS_LOOKUPCACHE, cval))
					goto err_fail;
				else
					break;
			}
		case 'o':
			opval = check_input(optarg, 0);
			if (opval < 0)
				goto err_bad;
			else {
				if (set_cifs_param(CIFS_OPLOCK, opval))
					goto err_fail;
				else
					break;
			}
		case 'l':
			lval = check_input(optarg, 0);
			if (lval < 0)
				goto err_bad;
			else {
				if (set_cifs_param(CIFS_LINUXEXTN, lval))
					goto err_fail;
				else
					break;
			}
		case 'x':
			xval = check_input(optarg, 0);
			if (xval < 0)
				goto err_bad;
			else {
				if (set_cifs_param(CIFS_EXPERIMENTAL, xval))
					goto err_fail;
				else
					break;
			}
		case 'd':
			dval = check_input(optarg, 1);
			if (dval < 0)
				goto err_bad;
			else {
				if (set_cifs_param(CIFS_DBGINFO, dval))
					goto err_fail;
				else
					break;
			}
		case 's':
			secval = optarg;
			if (set_sec_flags(secval))
				goto err_fail;
			else
				break;
		case 'h':
			usage();
		case '?':
			fprintf(stderr, "Try `%s -h' for more information.\n",
					progname);
			goto err_fail;

		default:
			usage();
		}
	}

	for (i = optind; i < argc; i++) {
		fprintf(stderr, "%s: invalid option %s\n", progname, argv[i]);
		fprintf(stderr, "Try `%s -h' for more information.\n", progname);
		return -1;
	}

	return 0;

err_fail:
	return -1;
err_bad:
	fprintf(stderr, "%s: invalid value: %s\n", progname, optarg);
	fprintf(stderr, "Hint: Check fs/cifs/README for valid values.\n");
	return -1;
}


More information about the linux-cifs-client mailing list