xref: /dragonfly/contrib/lvm2/dist/tools/lvm.c (revision 86d7f5d3)
1*86d7f5d3SJohn Marino /*	$NetBSD: lvm.c,v 1.1.1.2 2009/02/18 11:17:44 haad Exp $	*/
2*86d7f5d3SJohn Marino 
3*86d7f5d3SJohn Marino /*
4*86d7f5d3SJohn Marino  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5*86d7f5d3SJohn Marino  * Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved.
6*86d7f5d3SJohn Marino  *
7*86d7f5d3SJohn Marino  * This file is part of LVM2.
8*86d7f5d3SJohn Marino  *
9*86d7f5d3SJohn Marino  * This copyrighted material is made available to anyone wishing to use,
10*86d7f5d3SJohn Marino  * modify, copy, or redistribute it subject to the terms and conditions
11*86d7f5d3SJohn Marino  * of the GNU General Public License v.2.
12*86d7f5d3SJohn Marino  *
13*86d7f5d3SJohn Marino  * You should have received a copy of the GNU General Public License
14*86d7f5d3SJohn Marino  * along with this program; if not, write to the Free Software Foundation,
15*86d7f5d3SJohn Marino  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16*86d7f5d3SJohn Marino  */
17*86d7f5d3SJohn Marino 
18*86d7f5d3SJohn Marino #include "tools.h"
19*86d7f5d3SJohn Marino #include "lvm2cmdline.h"
20*86d7f5d3SJohn Marino 
main(int argc,char ** argv)21*86d7f5d3SJohn Marino int main(int argc, char **argv)
22*86d7f5d3SJohn Marino {
23*86d7f5d3SJohn Marino 	return lvm2_main(argc, argv);
24*86d7f5d3SJohn Marino }
25*86d7f5d3SJohn Marino 
26*86d7f5d3SJohn Marino #ifdef READLINE_SUPPORT
27*86d7f5d3SJohn Marino 
28*86d7f5d3SJohn Marino #  include <readline/readline.h>
29*86d7f5d3SJohn Marino #  include <readline/history.h>
30*86d7f5d3SJohn Marino #  ifndef HAVE_RL_COMPLETION_MATCHES
31*86d7f5d3SJohn Marino #    define rl_completion_matches(a, b) completion_matches((char *)a, b)
32*86d7f5d3SJohn Marino #  endif
33*86d7f5d3SJohn Marino 
34*86d7f5d3SJohn Marino static struct cmdline_context *_cmdline;
35*86d7f5d3SJohn Marino 
36*86d7f5d3SJohn Marino /* List matching commands */
_list_cmds(const char * text,int state)37*86d7f5d3SJohn Marino static char *_list_cmds(const char *text, int state)
38*86d7f5d3SJohn Marino {
39*86d7f5d3SJohn Marino 	static int i = 0;
40*86d7f5d3SJohn Marino 	static size_t len = 0;
41*86d7f5d3SJohn Marino 
42*86d7f5d3SJohn Marino 	/* Initialise if this is a new completion attempt */
43*86d7f5d3SJohn Marino 	if (!state) {
44*86d7f5d3SJohn Marino 		i = 0;
45*86d7f5d3SJohn Marino 		len = strlen(text);
46*86d7f5d3SJohn Marino 	}
47*86d7f5d3SJohn Marino 
48*86d7f5d3SJohn Marino 	while (i < _cmdline->num_commands)
49*86d7f5d3SJohn Marino 		if (!strncmp(text, _cmdline->commands[i++].name, len))
50*86d7f5d3SJohn Marino 			return strdup(_cmdline->commands[i - 1].name);
51*86d7f5d3SJohn Marino 
52*86d7f5d3SJohn Marino 	return NULL;
53*86d7f5d3SJohn Marino }
54*86d7f5d3SJohn Marino 
55*86d7f5d3SJohn Marino /* List matching arguments */
_list_args(const char * text,int state)56*86d7f5d3SJohn Marino static char *_list_args(const char *text, int state)
57*86d7f5d3SJohn Marino {
58*86d7f5d3SJohn Marino 	static int match_no = 0;
59*86d7f5d3SJohn Marino 	static size_t len = 0;
60*86d7f5d3SJohn Marino 	static struct command *com;
61*86d7f5d3SJohn Marino 
62*86d7f5d3SJohn Marino 	/* Initialise if this is a new completion attempt */
63*86d7f5d3SJohn Marino 	if (!state) {
64*86d7f5d3SJohn Marino 		char *s = rl_line_buffer;
65*86d7f5d3SJohn Marino 		int j = 0;
66*86d7f5d3SJohn Marino 
67*86d7f5d3SJohn Marino 		match_no = 0;
68*86d7f5d3SJohn Marino 		com = NULL;
69*86d7f5d3SJohn Marino 		len = strlen(text);
70*86d7f5d3SJohn Marino 
71*86d7f5d3SJohn Marino 		/* Find start of first word in line buffer */
72*86d7f5d3SJohn Marino 		while (isspace(*s))
73*86d7f5d3SJohn Marino 			s++;
74*86d7f5d3SJohn Marino 
75*86d7f5d3SJohn Marino 		/* Look for word in list of commands */
76*86d7f5d3SJohn Marino 		for (j = 0; j < _cmdline->num_commands; j++) {
77*86d7f5d3SJohn Marino 			const char *p;
78*86d7f5d3SJohn Marino 			char *q = s;
79*86d7f5d3SJohn Marino 
80*86d7f5d3SJohn Marino 			p = _cmdline->commands[j].name;
81*86d7f5d3SJohn Marino 			while (*p == *q) {
82*86d7f5d3SJohn Marino 				p++;
83*86d7f5d3SJohn Marino 				q++;
84*86d7f5d3SJohn Marino 			}
85*86d7f5d3SJohn Marino 			if ((!*p) && *q == ' ') {
86*86d7f5d3SJohn Marino 				com = _cmdline->commands + j;
87*86d7f5d3SJohn Marino 				break;
88*86d7f5d3SJohn Marino 			}
89*86d7f5d3SJohn Marino 		}
90*86d7f5d3SJohn Marino 
91*86d7f5d3SJohn Marino 		if (!com)
92*86d7f5d3SJohn Marino 			return NULL;
93*86d7f5d3SJohn Marino 	}
94*86d7f5d3SJohn Marino 
95*86d7f5d3SJohn Marino 	/* Short form arguments */
96*86d7f5d3SJohn Marino 	if (len < 3) {
97*86d7f5d3SJohn Marino 		while (match_no < com->num_args) {
98*86d7f5d3SJohn Marino 			char s[3];
99*86d7f5d3SJohn Marino 			char c;
100*86d7f5d3SJohn Marino 			if (!(c = (_cmdline->the_args +
101*86d7f5d3SJohn Marino 				   com->valid_args[match_no++])->short_arg))
102*86d7f5d3SJohn Marino 				continue;
103*86d7f5d3SJohn Marino 
104*86d7f5d3SJohn Marino 			sprintf(s, "-%c", c);
105*86d7f5d3SJohn Marino 			if (!strncmp(text, s, len))
106*86d7f5d3SJohn Marino 				return strdup(s);
107*86d7f5d3SJohn Marino 		}
108*86d7f5d3SJohn Marino 	}
109*86d7f5d3SJohn Marino 
110*86d7f5d3SJohn Marino 	/* Long form arguments */
111*86d7f5d3SJohn Marino 	if (match_no < com->num_args)
112*86d7f5d3SJohn Marino 		match_no = com->num_args;
113*86d7f5d3SJohn Marino 
114*86d7f5d3SJohn Marino 	while (match_no - com->num_args < com->num_args) {
115*86d7f5d3SJohn Marino 		const char *l;
116*86d7f5d3SJohn Marino 		l = (_cmdline->the_args +
117*86d7f5d3SJohn Marino 		     com->valid_args[match_no++ - com->num_args])->long_arg;
118*86d7f5d3SJohn Marino 		if (*(l + 2) && !strncmp(text, l, len))
119*86d7f5d3SJohn Marino 			return strdup(l);
120*86d7f5d3SJohn Marino 	}
121*86d7f5d3SJohn Marino 
122*86d7f5d3SJohn Marino 	return NULL;
123*86d7f5d3SJohn Marino }
124*86d7f5d3SJohn Marino 
125*86d7f5d3SJohn Marino /* Custom completion function */
_completion(const char * text,int start_pos,int end_pos __attribute ((unused)))126*86d7f5d3SJohn Marino static char **_completion(const char *text, int start_pos,
127*86d7f5d3SJohn Marino 			  int end_pos __attribute((unused)))
128*86d7f5d3SJohn Marino {
129*86d7f5d3SJohn Marino 	char **match_list = NULL;
130*86d7f5d3SJohn Marino 	int p = 0;
131*86d7f5d3SJohn Marino 
132*86d7f5d3SJohn Marino 	while (isspace((int) *(rl_line_buffer + p)))
133*86d7f5d3SJohn Marino 		p++;
134*86d7f5d3SJohn Marino 
135*86d7f5d3SJohn Marino 	/* First word should be one of our commands */
136*86d7f5d3SJohn Marino 	if (start_pos == p)
137*86d7f5d3SJohn Marino 		match_list = rl_completion_matches(text, _list_cmds);
138*86d7f5d3SJohn Marino 
139*86d7f5d3SJohn Marino 	else if (*text == '-')
140*86d7f5d3SJohn Marino 		match_list = rl_completion_matches(text, _list_args);
141*86d7f5d3SJohn Marino 	/* else other args */
142*86d7f5d3SJohn Marino 
143*86d7f5d3SJohn Marino 	/* No further completion */
144*86d7f5d3SJohn Marino 	rl_attempted_completion_over = 1;
145*86d7f5d3SJohn Marino 	return match_list;
146*86d7f5d3SJohn Marino }
147*86d7f5d3SJohn Marino 
_hist_file(char * buffer,size_t size)148*86d7f5d3SJohn Marino static int _hist_file(char *buffer, size_t size)
149*86d7f5d3SJohn Marino {
150*86d7f5d3SJohn Marino 	char *e = getenv("HOME");
151*86d7f5d3SJohn Marino 
152*86d7f5d3SJohn Marino 	if (dm_snprintf(buffer, size, "%s/.lvm_history", e) < 0) {
153*86d7f5d3SJohn Marino 		log_error("$HOME/.lvm_history: path too long");
154*86d7f5d3SJohn Marino 		return 0;
155*86d7f5d3SJohn Marino 	}
156*86d7f5d3SJohn Marino 
157*86d7f5d3SJohn Marino 	return 1;
158*86d7f5d3SJohn Marino }
159*86d7f5d3SJohn Marino 
_read_history(struct cmd_context * cmd)160*86d7f5d3SJohn Marino static void _read_history(struct cmd_context *cmd)
161*86d7f5d3SJohn Marino {
162*86d7f5d3SJohn Marino 	char hist_file[PATH_MAX];
163*86d7f5d3SJohn Marino 
164*86d7f5d3SJohn Marino 	if (!_hist_file(hist_file, sizeof(hist_file)))
165*86d7f5d3SJohn Marino 		return;
166*86d7f5d3SJohn Marino 
167*86d7f5d3SJohn Marino 	if (read_history(hist_file))
168*86d7f5d3SJohn Marino 		log_very_verbose("Couldn't read history from %s.", hist_file);
169*86d7f5d3SJohn Marino 
170*86d7f5d3SJohn Marino 	stifle_history(find_config_tree_int(cmd, "shell/history_size",
171*86d7f5d3SJohn Marino 				       DEFAULT_MAX_HISTORY));
172*86d7f5d3SJohn Marino 
173*86d7f5d3SJohn Marino }
174*86d7f5d3SJohn Marino 
_write_history(void)175*86d7f5d3SJohn Marino static void _write_history(void)
176*86d7f5d3SJohn Marino {
177*86d7f5d3SJohn Marino 	char hist_file[PATH_MAX];
178*86d7f5d3SJohn Marino 
179*86d7f5d3SJohn Marino 	if (!_hist_file(hist_file, sizeof(hist_file)))
180*86d7f5d3SJohn Marino 		return;
181*86d7f5d3SJohn Marino 
182*86d7f5d3SJohn Marino 	if (write_history(hist_file))
183*86d7f5d3SJohn Marino 		log_very_verbose("Couldn't write history to %s.", hist_file);
184*86d7f5d3SJohn Marino }
185*86d7f5d3SJohn Marino 
lvm_shell(struct cmd_context * cmd,struct cmdline_context * cmdline)186*86d7f5d3SJohn Marino int lvm_shell(struct cmd_context *cmd, struct cmdline_context *cmdline)
187*86d7f5d3SJohn Marino {
188*86d7f5d3SJohn Marino 	int argc, ret;
189*86d7f5d3SJohn Marino 	char *input = NULL, *args[MAX_ARGS], **argv;
190*86d7f5d3SJohn Marino 
191*86d7f5d3SJohn Marino 	rl_readline_name = "lvm";
192*86d7f5d3SJohn Marino 	rl_attempted_completion_function = (CPPFunction *) _completion;
193*86d7f5d3SJohn Marino 
194*86d7f5d3SJohn Marino 	_read_history(cmd);
195*86d7f5d3SJohn Marino 
196*86d7f5d3SJohn Marino 	_cmdline = cmdline;
197*86d7f5d3SJohn Marino 
198*86d7f5d3SJohn Marino 	_cmdline->interactive = 1;
199*86d7f5d3SJohn Marino 	while (1) {
200*86d7f5d3SJohn Marino 		free(input);
201*86d7f5d3SJohn Marino 		input = readline("lvm> ");
202*86d7f5d3SJohn Marino 
203*86d7f5d3SJohn Marino 		/* EOF */
204*86d7f5d3SJohn Marino 		if (!input) {
205*86d7f5d3SJohn Marino 			printf("\n");
206*86d7f5d3SJohn Marino 			break;
207*86d7f5d3SJohn Marino 		}
208*86d7f5d3SJohn Marino 
209*86d7f5d3SJohn Marino 		/* empty line */
210*86d7f5d3SJohn Marino 		if (!*input)
211*86d7f5d3SJohn Marino 			continue;
212*86d7f5d3SJohn Marino 
213*86d7f5d3SJohn Marino 		add_history(input);
214*86d7f5d3SJohn Marino 
215*86d7f5d3SJohn Marino 		argv = args;
216*86d7f5d3SJohn Marino 
217*86d7f5d3SJohn Marino 		if (lvm_split(input, &argc, argv, MAX_ARGS) == MAX_ARGS) {
218*86d7f5d3SJohn Marino 			log_error("Too many arguments, sorry.");
219*86d7f5d3SJohn Marino 			continue;
220*86d7f5d3SJohn Marino 		}
221*86d7f5d3SJohn Marino 
222*86d7f5d3SJohn Marino 		if (!strcmp(argv[0], "lvm")) {
223*86d7f5d3SJohn Marino 			argv++;
224*86d7f5d3SJohn Marino 			argc--;
225*86d7f5d3SJohn Marino 		}
226*86d7f5d3SJohn Marino 
227*86d7f5d3SJohn Marino 		if (!argc)
228*86d7f5d3SJohn Marino 			continue;
229*86d7f5d3SJohn Marino 
230*86d7f5d3SJohn Marino 		if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "exit")) {
231*86d7f5d3SJohn Marino 			remove_history(history_length - 1);
232*86d7f5d3SJohn Marino 			log_error("Exiting.");
233*86d7f5d3SJohn Marino 			break;
234*86d7f5d3SJohn Marino 		}
235*86d7f5d3SJohn Marino 
236*86d7f5d3SJohn Marino 		ret = lvm_run_command(cmd, argc, argv);
237*86d7f5d3SJohn Marino 		if (ret == ENO_SUCH_CMD)
238*86d7f5d3SJohn Marino 			log_error("No such command '%s'.  Try 'help'.",
239*86d7f5d3SJohn Marino 				  argv[0]);
240*86d7f5d3SJohn Marino 
241*86d7f5d3SJohn Marino                 if ((ret != ECMD_PROCESSED) && !error_message_produced()) {
242*86d7f5d3SJohn Marino 			log_debug("Internal error: Failed command did not use log_error");
243*86d7f5d3SJohn Marino 			log_error("Command failed with status code %d.", ret);
244*86d7f5d3SJohn Marino 		}
245*86d7f5d3SJohn Marino 		_write_history();
246*86d7f5d3SJohn Marino 	}
247*86d7f5d3SJohn Marino 
248*86d7f5d3SJohn Marino 	free(input);
249*86d7f5d3SJohn Marino 	return 0;
250*86d7f5d3SJohn Marino }
251*86d7f5d3SJohn Marino 
252*86d7f5d3SJohn Marino #endif	/* READLINE_SUPPORT */
253