From 20dbe75fbb7baf2ec08329ba547809417bccd6e6 Mon Sep 17 00:00:00 2001 From: wangdi <wangdi> Date: Sun, 4 Jan 2004 07:29:43 +0000 Subject: [PATCH] add snapconf utils --- lustre/snapfs/utils/Makefile.am | 13 + lustre/snapfs/utils/parser.c | 747 ++++++++++++++++++++++++++++++++ lustre/snapfs/utils/parser.h | 74 ++++ lustre/snapfs/utils/snapconf.c | 68 +++ lustre/snapfs/utils/snapctl.c | 253 +++++++++++ lustre/snapfs/utils/snapctl.h | 24 + 6 files changed, 1179 insertions(+) create mode 100644 lustre/snapfs/utils/Makefile.am create mode 100644 lustre/snapfs/utils/parser.c create mode 100644 lustre/snapfs/utils/parser.h create mode 100644 lustre/snapfs/utils/snapconf.c create mode 100644 lustre/snapfs/utils/snapctl.c create mode 100644 lustre/snapfs/utils/snapctl.h diff --git a/lustre/snapfs/utils/Makefile.am b/lustre/snapfs/utils/Makefile.am new file mode 100644 index 0000000000..d5aff12fda --- /dev/null +++ b/lustre/snapfs/utils/Makefile.am @@ -0,0 +1,13 @@ +# Administration utilities Makefile +#CPPFLAGS = $(HAVE_LIBREADLINE) -I$(top_srcdir)/utils -I$(top_srcdir)/portals/include -I$(srcdir)/../ -Wall -L../../portals/utils +#CFLAGS:= -g -O2 +DEFS= + +CFLAGS:=-g -O2 -I$(top_srcdir)/utils -I$(top_srcdir)/portals/include -I$(srcdir)/../ -Wall -L../../portals/utils +CPPFLAGS = $(HAVE_LIBREADLINE) +KFLAGS:= +noinst_PROGRAMS = snapconf +snapconf_LDADD := $(LIBREADLINE) -lptlctl -ltermcap +snapconf_SOURCES = parser.c snapctl.c snapconf.c parser.h snapctl.h +include $(top_srcdir)/Rules + diff --git a/lustre/snapfs/utils/parser.c b/lustre/snapfs/utils/parser.c new file mode 100644 index 0000000000..a2bbe20539 --- /dev/null +++ b/lustre/snapfs/utils/parser.c @@ -0,0 +1,747 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Copyright (C) 2001 Cluster File Systems, Inc. + * + * This file is part of Lustre, http://www.sf.net/projects/lustre/ + * + * Lustre is free software; you can redistribute it and/or + * modify it under the terms of version 2 of the GNU General Public + * License as published by the Free Software Foundation. + * + * Lustre 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 Lustre; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> +#include <string.h> +#include <stddef.h> +#include <unistd.h> +#include <sys/param.h> +#include <assert.h> + +#ifdef HAVE_LIBREADLINE +#define READLINE_LIBRARY +#include <readline/readline.h> + +/* completion_matches() is #if 0-ed out in modern glibc */ +#ifndef completion_matches +#define completion_matches rl_completion_matches +#endif +extern void using_history(void); +extern void stifle_history(int); +extern void add_history(char *); +#endif + +#include "parser.h" + +static command_t * top_level; /* Top level of commands, initialized by + * InitParser */ +static char * parser_prompt = NULL;/* Parser prompt, set by InitParser */ +static int done; /* Set to 1 if user types exit or quit */ +static int ignore_errors; /* Normally, the parser will quit when + an error occurs in non-interacive + mode. Setting this to non-zero will + force it to keep buggering on. */ + + +/* static functions */ +static char *skipwhitespace(char *s); +static char *skiptowhitespace(char *s); +static command_t *find_cmd(char *name, command_t cmds[], char **next); +static int process(char *s, char **next, command_t *lookup, command_t **result, + char **prev); +static void print_commands(char *str, command_t *table); + +static char * skipwhitespace(char * s) +{ + char * t; + int len; + + len = (int)strlen(s); + for (t = s; t <= s + len && isspace(*t); t++); + return(t); +} + + +static char * skiptowhitespace(char * s) +{ + char * t; + + for (t = s; *t && !isspace(*t); t++); + return(t); +} + +static int line2args(char *line, char **argv, int maxargs) +{ + char *arg; + int i = 0; + + arg = strtok(line, " \t"); + if ( arg ) { + argv[i] = arg; + i++; + } else + return 0; + + while( (arg = strtok(NULL, " \t")) && (i <= maxargs)) { + argv[i] = arg; + i++; + } + return i; +} + +/* find a command -- return it if unique otherwise print alternatives */ +static command_t *Parser_findargcmd(char *name, command_t cmds[]) +{ + command_t *cmd; + + for (cmd = cmds; cmd->pc_name; cmd++) { + if (strcmp(name, cmd->pc_name) == 0) + return cmd; + } + return NULL; +} + +void Parser_ignore_errors(int ignore) +{ + ignore_errors = ignore; +} + +int Parser_execarg(int argc, char **argv, command_t cmds[]) +{ + command_t *cmd; + + cmd = Parser_findargcmd(argv[0], cmds); + if ( cmd ) { + int rc = (cmd->pc_func)(argc, argv); + if (rc == CMD_HELP) + fprintf(stderr, "%s\n", cmd->pc_help); + return rc; + } else { + printf("Try interactive use without arguments or use one of:\n"); + for (cmd = cmds; cmd->pc_name; cmd++) + printf("\"%s\"\n", cmd->pc_name); + printf("as argument.\n"); + } + return -1; +} + +/* returns the command_t * (NULL if not found) corresponding to a + _partial_ match with the first token in name. It sets *next to + point to the following token. Does not modify *name. */ +static command_t * find_cmd(char * name, command_t cmds[], char ** next) +{ + int i, len; + + if (!cmds || !name ) + return NULL; + + /* This sets name to point to the first non-white space character, + and next to the first whitespace after name, len to the length: do + this with strtok*/ + name = skipwhitespace(name); + *next = skiptowhitespace(name); + len = *next - name; + if (len == 0) + return NULL; + + for (i = 0; cmds[i].pc_name; i++) { + if (strncasecmp(name, cmds[i].pc_name, len) == 0) { + *next = skipwhitespace(*next); + return(&cmds[i]); + } + } + return NULL; +} + +/* Recursively process a command line string s and find the command + corresponding to it. This can be ambiguous, full, incomplete, + non-existent. */ +static int process(char *s, char ** next, command_t *lookup, + command_t **result, char **prev) +{ + *result = find_cmd(s, lookup, next); + *prev = s; + + /* non existent */ + if (!*result) + return CMD_NONE; + + /* found entry: is it ambigous, i.e. not exact command name and + more than one command in the list matches. Note that find_cmd + points to the first ambiguous entry */ + if (strncasecmp(s, (*result)->pc_name, strlen((*result)->pc_name))) { + char *another_next; + command_t *another_result = find_cmd(s, (*result) + 1, + &another_next); + int found_another = 0; + + while (another_result) { + if (strncasecmp(s, another_result->pc_name, + strlen(another_result->pc_name)) == 0){ + *result = another_result; + *next = another_next; + goto got_it; + } + another_result = find_cmd(s, another_result + 1, + &another_next); + found_another = 1; + } + if (found_another) + return CMD_AMBIG; + } + +got_it: + /* found a unique command: component or full? */ + if ( (*result)->pc_func ) { + return CMD_COMPLETE; + } else { + if ( *next == '\0' ) { + return CMD_INCOMPLETE; + } else { + return process(*next, next, (*result)->pc_sub_cmd, + result, prev); + } + } +} + +#ifdef HAVE_LIBREADLINE +static command_t * match_tbl; /* Command completion against this table */ +static char * command_generator(const char * text, int state) +{ + static int index, + len; + char *name; + + /* Do we have a match table? */ + if (!match_tbl) + return NULL; + + /* If this is the first time called on this word, state is 0 */ + if (!state) { + index = 0; + len = (int)strlen(text); + } + + /* Return next name in the command list that paritally matches test */ + while ( (name = (match_tbl + index)->pc_name) ) { + index++; + + if (strncasecmp(name, text, len) == 0) { + return(strdup(name)); + } + } + + /* No more matches */ + return NULL; +} + +/* probably called by readline */ +static char **command_completion(char * text, int start, int end) +{ + command_t * table; + char * pos; + + match_tbl = top_level; + for (table = find_cmd(rl_line_buffer, match_tbl, &pos); + table; + table = find_cmd(pos, match_tbl, &pos)) { + + if (*(pos - 1) == ' ') match_tbl = table->pc_sub_cmd; + } + + return(completion_matches(text, command_generator)); +} +#endif + +/* take a string and execute the function or print help */ +int execute_line(char * line) +{ + command_t *cmd, *ambig; + char *prev; + char *next, *tmp; + char *argv[MAXARGS]; + int i; + int rc = 0; + + switch (process(line, &next, top_level, &cmd, &prev)) { + case CMD_AMBIG: + fprintf(stderr, "Ambiguous command \'%s\'\nOptions: ", line); + while( (ambig = find_cmd(prev, cmd, &tmp)) ) { + fprintf(stderr, "%s ", ambig->pc_name); + cmd = ambig + 1; + } + fprintf(stderr, "\n"); + break; + case CMD_NONE: + fprintf(stderr, "No such command, type help\n"); + break; + case CMD_INCOMPLETE: + fprintf(stderr, + "'%s' incomplete command. Use '%s x' where x is one of:\n", + line, line); + fprintf(stderr, "\t"); + for (i = 0; cmd->pc_sub_cmd[i].pc_name; i++) { + fprintf(stderr, "%s ", cmd->pc_sub_cmd[i].pc_name); + } + fprintf(stderr, "\n"); + break; + case CMD_COMPLETE: + i = line2args(line, argv, MAXARGS); + rc = (cmd->pc_func)(i, argv); + + if (rc == CMD_HELP) + fprintf(stderr, "%s\n", cmd->pc_help); + + break; + } + + return rc; +} + +int +noop_fn () +{ + return (0); +} + +/* just in case you're ever in an airplane and discover you + forgot to install readline-dev. :) */ +int init_input() +{ + int interactive = isatty (fileno (stdin)); + +#ifdef HAVE_LIBREADLINE + using_history(); + stifle_history(HISTORY); + + if (!interactive) + { + rl_prep_term_function = (rl_vintfunc_t *)noop_fn; + rl_deprep_term_function = (rl_voidfunc_t *)noop_fn; + } + + rl_attempted_completion_function = (CPPFunction *)command_completion; + rl_completion_entry_function = (void *)command_generator; +#endif + return interactive; +} + +#ifndef HAVE_LIBREADLINE +#define add_history(s) +char * readline(char * prompt) +{ + char line[2048]; + int n = 0; + if (prompt) + printf ("%s", prompt); + if (fgets(line, sizeof(line), stdin) == NULL) + return (NULL); + n = strlen(line); + if (n && line[n-1] == '\n') + line[n-1] = '\0'; + return strdup(line); +} +#endif + +/* this is the command execution machine */ +int Parser_commands(void) +{ + char *line, *s; + int rc = 0, save_error = 0; + int interactive; + + interactive = init_input(); + + while(!done) { + line = readline(interactive ? parser_prompt : NULL); + + if (!line) break; + + s = skipwhitespace(line); + + if (*s) { + add_history(s); + rc = execute_line(s); + } + /* stop on error if not-interactive */ + if (rc != 0 && !interactive) { + if (save_error == 0) + save_error = rc; + if (!ignore_errors) + done = 1; + } + + free(line); + } + if (save_error) + rc = save_error; + return rc; +} + + +/* sets the parser prompt */ +void Parser_init(char * prompt, command_t * cmds) +{ + done = 0; + top_level = cmds; + if (parser_prompt) free(parser_prompt); + parser_prompt = strdup(prompt); +} + +/* frees the parser prompt */ +void Parser_exit(int argc, char *argv[]) +{ + done = 1; + free(parser_prompt); + parser_prompt = NULL; +} + +/* convert a string to an integer */ +int Parser_int(char *s, int *val) +{ + int ret; + + if (*s != '0') + ret = sscanf(s, "%d", val); + else if (*(s+1) != 'x') + ret = sscanf(s, "%o", val); + else { + s++; + ret = sscanf(++s, "%x", val); + } + + return(ret); +} + + +void Parser_qhelp(int argc, char *argv[]) { + + printf("Available commands are:\n"); + + print_commands(NULL, top_level); + printf("For more help type: help command-name\n"); +} + +int Parser_help(int argc, char **argv) +{ + char line[1024]; + char *next, *prev, *tmp; + command_t *result, *ambig; + int i; + + if ( argc == 1 ) { + Parser_qhelp(argc, argv); + return 0; + } + + line[0]='\0'; + for ( i = 1 ; i < argc ; i++ ) { + strcat(line, argv[i]); + } + + switch ( process(line, &next, top_level, &result, &prev) ) { + case CMD_COMPLETE: + fprintf(stderr, "%s: %s\n",line, result->pc_help); + break; + case CMD_NONE: + fprintf(stderr, "%s: Unknown command.\n", line); + break; + case CMD_INCOMPLETE: + fprintf(stderr, + "'%s' incomplete command. Use '%s x' where x is one of:\n", + line, line); + fprintf(stderr, "\t"); + for (i = 0; result->pc_sub_cmd[i].pc_name; i++) { + fprintf(stderr, "%s ", result->pc_sub_cmd[i].pc_name); + } + fprintf(stderr, "\n"); + break; + case CMD_AMBIG: + fprintf(stderr, "Ambiguous command \'%s\'\nOptions: ", line); + while( (ambig = find_cmd(prev, result, &tmp)) ) { + fprintf(stderr, "%s ", ambig->pc_name); + result = ambig + 1; + } + fprintf(stderr, "\n"); + break; + } + return 0; +} + + +void Parser_printhelp(char *cmd) +{ + char *argv[] = { "help", cmd }; + Parser_help(2, argv); +} + + +/************************************************************************* + * COMMANDS * + *************************************************************************/ +static void print_commands(char * str, command_t * table) { + command_t * cmds; + char buf[80]; + + for (cmds = table; cmds->pc_name; cmds++) { + if (cmds->pc_func) { + if (str) printf("\t%s %s\n", str, cmds->pc_name); + else printf("\t%s\n", cmds->pc_name); + } + if (cmds->pc_sub_cmd) { + if (str) { + sprintf(buf, "%s %s", str, cmds->pc_name); + print_commands(buf, cmds->pc_sub_cmd); + } else { + print_commands(cmds->pc_name, cmds->pc_sub_cmd); + } + } + } +} + +char *Parser_getstr(const char *prompt, const char *deft, char *res, + size_t len) +{ + char *line = NULL; + int size = strlen(prompt) + strlen(deft) + 8; + char *theprompt; + theprompt = malloc(size); + assert(theprompt); + + sprintf(theprompt, "%s [%s]: ", prompt, deft); + + line = readline(theprompt); + free(theprompt); + + if ( line == NULL || *line == '\0' ) { + strncpy(res, deft, len); + } else { + strncpy(res, line, len); + } + + if ( line ) { + free(line); + return res; + } else { + return NULL; + } +} + +/* get integer from prompt, loop forever to get it */ +int Parser_getint(const char *prompt, long min, long max, long deft, int base) +{ + int rc; + long result; + char *line; + int size = strlen(prompt) + 40; + char *theprompt = malloc(size); + assert(theprompt); + sprintf(theprompt,"%s [%ld, (0x%lx)]: ", prompt, deft, deft); + + fflush(stdout); + + do { + line = NULL; + line = readline(theprompt); + if ( !line ) { + fprintf(stdout, "Please enter an integer.\n"); + fflush(stdout); + continue; + } + if ( *line == '\0' ) { + free(line); + result = deft; + break; + } + rc = Parser_arg2int(line, &result, base); + free(line); + if ( rc != 0 ) { + fprintf(stdout, "Invalid string.\n"); + fflush(stdout); + } else if ( result > max || result < min ) { + fprintf(stdout, "Error: response must lie between %ld and %ld.\n", + min, max); + fflush(stdout); + } else { + break; + } + } while ( 1 ) ; + + if (theprompt) + free(theprompt); + return result; + +} + +/* get boolean (starting with YyNn; loop forever */ +int Parser_getbool(const char *prompt, int deft) +{ + int result = 0; + char *line; + int size = strlen(prompt) + 8; + char *theprompt = malloc(size); + assert(theprompt); + + fflush(stdout); + + if ( deft != 0 && deft != 1 ) { + fprintf(stderr, "Error: Parser_getbool given bad default %d\n", + deft); + assert ( 0 ); + } + sprintf(theprompt, "%s [%s]: ", prompt, (deft==0)? "N" : "Y"); + + do { + line = NULL; + line = readline(theprompt); + if ( line == NULL ) { + result = deft; + break; + } + if ( *line == '\0' ) { + result = deft; + break; + } + if ( *line == 'y' || *line == 'Y' ) { + result = 1; + break; + } + if ( *line == 'n' || *line == 'N' ) { + result = 0; + break; + } + if ( line ) + free(line); + fprintf(stdout, "Invalid string. Must start with yY or nN\n"); + fflush(stdout); + } while ( 1 ); + + if ( line ) + free(line); + if ( theprompt ) + free(theprompt); + return result; +} + +/* parse int out of a string or prompt for it */ +long Parser_intarg(const char *inp, const char *prompt, int deft, + int min, int max, int base) +{ + long result; + int rc; + + rc = Parser_arg2int(inp, &result, base); + + if ( rc == 0 ) { + return result; + } else { + return Parser_getint(prompt, deft, min, max, base); + } +} + +/* parse int out of a string or prompt for it */ +char *Parser_strarg(char *inp, const char *prompt, const char *deft, + char *answer, int len) +{ + if ( inp == NULL || *inp == '\0' ) { + return Parser_getstr(prompt, deft, answer, len); + } else + return inp; +} + +/* change a string into a number: return 0 on success. No invalid characters + allowed. The processing of base and validity follows strtol(3)*/ +int Parser_arg2int(const char *inp, long *result, int base) +{ + char *endptr; + + if ( (base !=0) && (base < 2 || base > 36) ) + return 1; + + *result = strtol(inp, &endptr, base); + + if ( *inp != '\0' && *endptr == '\0' ) + return 0; + else + return 1; +} + +/* Convert human readable size string to and int; "1k" -> 1000 */ +int Parser_size (int *sizep, char *str) { + int size; + char mod[32]; + + switch (sscanf (str, "%d%1[gGmMkK]", &size, mod)) { + default: + return (-1); + + case 1: + *sizep = size; + return (0); + + case 2: + switch (*mod) { + case 'g': + case 'G': + *sizep = size << 30; + return (0); + + case 'm': + case 'M': + *sizep = size << 20; + return (0); + + case 'k': + case 'K': + *sizep = size << 10; + return (0); + + default: + *sizep = size; + return (0); + } + } +} + +/* Convert a string boolean to an int; "enable" -> 1 */ +int Parser_bool (int *b, char *str) { + if (!strcasecmp (str, "no") || + !strcasecmp (str, "n") || + !strcasecmp (str, "off") || + !strcasecmp (str, "down") || + !strcasecmp (str, "disable")) + { + *b = 0; + return (0); + } + + if (!strcasecmp (str, "yes") || + !strcasecmp (str, "y") || + !strcasecmp (str, "on") || + !strcasecmp (str, "up") || + !strcasecmp (str, "enable")) + { + *b = 1; + return (0); + } + + return (-1); +} + +int Parser_quit(int argc, char **argv) +{ + argc = argc; + argv = argv; + done = 1; + return 0; +} diff --git a/lustre/snapfs/utils/parser.h b/lustre/snapfs/utils/parser.h new file mode 100644 index 0000000000..a1f899bfc8 --- /dev/null +++ b/lustre/snapfs/utils/parser.h @@ -0,0 +1,74 @@ +#ifndef _PARSER_H_ +#define _PARSER_H_ + +#define HISTORY 100 /* Don't let history grow unbounded */ +#define MAXARGS 512 + +#define CMD_COMPLETE 0 +#define CMD_INCOMPLETE 1 +#define CMD_NONE 2 +#define CMD_AMBIG 3 +#define CMD_HELP 4 + +typedef struct parser_cmd { + char *pc_name; + int (* pc_func)(int, char **); + struct parser_cmd * pc_sub_cmd; + char *pc_help; +} command_t; + +typedef struct argcmd { + char *ac_name; + int (*ac_func)(int, char **); + char *ac_help; +} argcmd_t; + +typedef struct network { + char *type; + char *server; + int port; +} network_t; + +int Parser_quit(int argc, char **argv); +void Parser_init(char *, command_t *); /* Set prompt and load command list */ +int Parser_commands(void); /* Start the command parser */ +void Parser_qhelp(int, char **); /* Quick help routine */ +int Parser_help(int, char **); /* Detailed help routine */ +void Parser_ignore_errors(int ignore); /* Set the ignore errors flag */ +void Parser_printhelp(char *); /* Detailed help routine */ +void Parser_exit(int, char **); /* Shuts down command parser */ +int Parser_execarg(int argc, char **argv, command_t cmds[]); +int execute_line(char * line); + +/* Converts a string to an integer */ +int Parser_int(char *, int *); + +/* Prompts for a string, with default values and a maximum length */ +char *Parser_getstr(const char *prompt, const char *deft, char *res, + size_t len); + +/* Prompts for an integer, with minimum, maximum and default values and base */ +int Parser_getint(const char *prompt, long min, long max, long deft, + int base); + +/* Prompts for a yes/no, with default */ +int Parser_getbool(const char *prompt, int deft); + +/* Extracts an integer from a string, or prompts if it cannot get one */ +long Parser_intarg(const char *inp, const char *prompt, int deft, + int min, int max, int base); + +/* Extracts a word from the input, or propmts if it cannot get one */ +char *Parser_strarg(char *inp, const char *prompt, const char *deft, + char *answer, int len); + +/* Extracts an integer from a string with a base */ +int Parser_arg2int(const char *inp, long *result, int base); + +/* Convert human readable size string to and int; "1k" -> 1000 */ +int Parser_size(int *sizep, char *str); + +/* Convert a string boolean to an int; "enable" -> 1 */ +int Parser_bool(int *b, char *str); + +#endif diff --git a/lustre/snapfs/utils/snapconf.c b/lustre/snapfs/utils/snapconf.c new file mode 100644 index 0000000000..1344873834 --- /dev/null +++ b/lustre/snapfs/utils/snapconf.c @@ -0,0 +1,68 @@ +/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- + * vim:expandtab:shiftwidth=8:tabstop=8: + * + * Copyright (C) 2002 Cluster File Systems, Inc. + * utils/snapconf.c + * + */ + + +#include <stdlib.h> +#include <stdio.h> +#include <portals/api-support.h> +#include <portals/ptlctl.h> +#include <portals/list.h> +#include "parser.h" +#include "snapctl.h" + +static int jt_quit(int argc, char **argv) { + Parser_quit(argc, argv); + return 0; +} + +static int jt_noop(int argc, char **argv) { + return 0; +} + +static int jt_opt_ignore_errors(int argc, char **argv) { + Parser_ignore_errors(1); + return 0; +} + +command_t cmdlist[] = { + /* Metacommands */ + {"--ignore_errors", jt_opt_ignore_errors, 0, + "ignore errors that occur during script processing\n" + "--ignore_errors"}, + /* snapshot commands*/ + {"add", snapshot_add, 0, + "add [table_no] <snap_name> add snapshot to the device\n"}, + {"list", snapshot_list, 0, "snap_list list snap available device\n"}, + {"dev", snapshot_dev, 0, "open <device> open available snap device\n"}, + + /* User interface commands */ + {"======= control ========", jt_noop, 0, "control commands"}, + {"help", Parser_help, 0, "help"}, + {"exit", jt_quit, 0, "quit"}, + {"quit", jt_quit, 0, "quit"}, + { 0, 0, 0, NULL } +}; + +int main(int argc, char **argv) +{ + int rc; + + setlinebuf(stdout); + + Parser_init("snapconf > ", cmdlist); + init_snap_list(); + + if (argc > 1) { + rc = Parser_execarg(argc - 1, argv + 1, cmdlist); + } else { + rc = Parser_commands(); + } + + return rc; +} + diff --git a/lustre/snapfs/utils/snapctl.c b/lustre/snapfs/utils/snapctl.c new file mode 100644 index 0000000000..8f82b62747 --- /dev/null +++ b/lustre/snapfs/utils/snapctl.c @@ -0,0 +1,253 @@ +#include <stdio.h> +#include <stdlib.h> +#include <mntent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> +#include <time.h> +#include <string.h> +#include <portals/list.h> +#include "parser.h" +#include "snapctl.h" +#include <snapfs_internal.h> + +#define IOC_PACK(ioc, length, input) \ +do{ \ + ioc.data = input; \ + ioc.len = length; \ +}while(0) + +static struct list_head snap_list; +struct open_snap_device open_device_table; +struct snap_device snap_device_list[10]; + + +static int get_snaplist() +{ + FILE *mnt_filp = NULL; + int error = 0; + + /*open mount list*/ + mnt_filp = setmntent("/etc/mtab", "r"); + + if (!mnt_filp) + return -EINVAL; + /*get the mentent and check snap mount*/ + while (!feof(mnt_filp)) { + struct mntent* entry; + + entry = getmntent(mnt_filp); + + if (!entry) continue; + + if (!strcmp(entry->mnt_type, "snap_current")) { + /*found a snap_mount structure add to the snaplist*/ + struct snap_mnt *s_mnt; + char *opt = NULL; + char dev_name[DEV_NAME_MAX_LEN]; + struct stat statbuf; + + s_mnt = (struct snap_mnt *) malloc(sizeof(struct snap_mnt)); + if (!s_mnt) { + error = ENOMEM; + goto exit; + } + memset(s_mnt, 0, sizeof(struct snap_mnt)); + memcpy(&s_mnt->device.name[0], entry->mnt_fsname, strlen(entry->mnt_fsname)); + opt = hasmntopt(entry, "loop"); + memset(dev_name, 0, DEV_NAME_MAX_LEN); + if (opt) { + /* Loop device mount find the real dev_name*/ + char *name = opt, *name_dev = dev_name; + + while (*name++ != '='); + while (*name != ',' && *name != ')' && *name ) { + *name_dev++ = *name++; + } + + } else { + memcpy(dev_name, entry->mnt_fsname, strlen(entry->mnt_fsname)); + } + + if ((error = stat(dev_name, &statbuf)) != 0) { + fprintf(stderr, "can not stat %s", strerror(errno)); + goto exit; + } + s_mnt->device.dev = (unsigned long)statbuf.st_rdev; + + list_add(&s_mnt->snap_mnt_list, &snap_list); + } + } +exit: + if (mnt_filp) + endmntent(mnt_filp); + return error; +} + +static void release_snap_list() +{ + struct snap_mnt *snaplist; + + list_for_each_entry(snaplist, &snap_list, snap_mnt_list) { + list_del(&snaplist->snap_mnt_list); + free(snaplist); + } +} + +void init_snap_list() +{ + int i; + + INIT_LIST_HEAD(&snap_list); + open_device_table.count = 0; + for(i = 0; i < 10; i++) { + memset(&open_device_table.device[i].name[0], + 0, DEV_NAME_MAX_LEN); + open_device_table.device[i].fd = -1; + } +} + +static int open_device(char *name, unsigned int dev) +{ + int index=0, error = 0, i = 0, found = 0; + + /*XXX Does these information necessary*/ + for (i = 0; i < open_device_table.count; i++) { + if (!strcmp(&open_device_table.device[i].name[0], name)) { + index = i; + found = 1; + break; + } + } + if (found == 0) { + open_device_table.device[index].dev = dev; + memset(&open_device_table.device[index].name[0], + 0, DEV_NAME_MAX_LEN); + memcpy(&open_device_table.device[index].name[0], + name, strlen(name)); + open_device_table.count ++; + } + /*FIXME If there are more than device, how to handle it*/ + if (open_device_table.device[index].fd < 0) { + /*open device*/ + int fd = open(SNAPDEV_NAME, O_RDWR); + + if (fd < 0) { + if (errno == ENOENT) { + dev_t snap_dev=makedev(SNAP_PSDEV_MAJOR,SNAP_PSDEV_MINOR); + /*create snapdevice node*/ + error = mknod(SNAPDEV_NAME, S_IRUSR|S_IWUSR|S_IFCHR, snap_dev); + if (error) { + fprintf(stderr, "Can not make node %s :%s \n", + SNAPDEV_NAME, strerror(errno)); + return (-errno); + } + if ((fd = open(SNAPDEV_NAME, O_RDWR)) < 0) { + fprintf(stderr, "Can not open node %s: %s\n", + SNAPDEV_NAME, strerror(errno)); + return (-errno); + } + } else { + fprintf(stderr, "Can not open node %s: %s %d \n", + SNAPDEV_NAME, strerror(errno), errno); + return(-errno); + } + } + open_device_table.device[index].fd = fd; + } + return 0; +} + +int snapshot_dev(int argc, char **argv) +{ + struct snap_mnt *snaplist; + char *dev_name; + int rc; + + if (argc != 2) { + fprintf(stderr, "The argument count is not right \n"); + return CMD_HELP; + } + + dev_name = argv[1]; + + get_snaplist(); + list_for_each_entry(snaplist, &snap_list, snap_mnt_list) { + if (!strcmp(&snaplist->device.name[0], dev_name)) { + rc = open_device(&snaplist->device.name[0], + snaplist->device.dev); + release_snap_list(); + return rc; + } + } + release_snap_list(); + fprintf(stderr, "can not find the device %s", dev_name); + return (-EINVAL); +} +int snapshot_list(int argc, char **argv) +{ + struct snap_mnt *snaplist; + if (argc != 1) { + fprintf(stderr, "The argument count is not right \n"); + return CMD_HELP; + } + + get_snaplist(); + list_for_each_entry(snaplist, &snap_list, snap_mnt_list) { + fprintf(stderr, "devid: %lu name: %s", + snaplist->device.dev, + &snaplist->device.name[0]); + } + release_snap_list(); + return 0; +} +int snapshot_add(int argc, char **argv) +{ + int rc, i; + + if (argc != 3 && argc !=2) { + fprintf(stderr, "The argument count is not right \n"); + return CMD_HELP; + } + + if (open_device_table.count == 0) { + fprintf(stderr, "Please first open a snapdevice \n"); + return (-EINVAL); + } + for (i = 0; i < open_device_table.count; i++) { + struct snap_table_data *snap_ioc_data; + struct ioc_data ioc_data; + + snap_ioc_data = (struct snap_table_data *) + malloc(sizeof(struct snap_table_data)); + snap_ioc_data->tblcmd_count = 1; + snap_ioc_data->dev = open_device_table.device[i].dev; + + if (argc == 3) { + snap_ioc_data->tblcmd_no = atoi(argv[1]); + memcpy(&snap_ioc_data->tblcmd_snaps[0].name[0], + argv[2], strlen(argv[2])); + } else { + snap_ioc_data->tblcmd_no = 0; + memcpy(&snap_ioc_data->tblcmd_snaps[0].name[0], + argv[1], strlen(argv[1])); + } + snap_ioc_data->tblcmd_snaps[0].time = time(NULL); + IOC_PACK(ioc_data, sizeof(struct snap_table_data), (char*)snap_ioc_data); + + if ((rc = ioctl(open_device_table.device[i].fd, + IOC_SNAP_ADD, &ioc_data))) { + fprintf(stderr, "add snapshot %s failed %d \n", + &snap_ioc_data->tblcmd_snaps[0].name[0], rc); + } else { + fprintf(stderr, "add snapshot %s success\n", + &snap_ioc_data->tblcmd_snaps[0].name[0]); + } + free(snap_ioc_data); + return rc; + } + return 0; +} diff --git a/lustre/snapfs/utils/snapctl.h b/lustre/snapfs/utils/snapctl.h new file mode 100644 index 0000000000..ef0f68b956 --- /dev/null +++ b/lustre/snapfs/utils/snapctl.h @@ -0,0 +1,24 @@ +/* snapctl.h */ +#define DEV_NAME_MAX_LEN 64 +struct snap_device { + char name[DEV_NAME_MAX_LEN]; + unsigned long dev; + int fd; +}; +struct snap_mnt { + struct snap_device device; + struct list_head snap_mnt_list; +}; +struct open_snap_device { + struct snap_device device[10]; + int count; +}; +struct ioc_data { + int len; + char *data; +}; +extern void init_snap_list(void); + +extern int snapshot_dev(int argc, char **argv); +extern int snapshot_list(int argc, char **argv); +extern int snapshot_add(int argc, char **argv); -- GitLab