[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