File:  [Qemu by Fabrice Bellard] / qemu / cmd.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:24:53 2018 UTC (3 years, 1 month ago) by root
Branches: qemu, MAIN
CVS tags: qemu0150, qemu0141, qemu0140, qemu0130, HEAD
qemu 0.13.0

    1: /*
    2:  * Copyright (c) 2003-2005 Silicon Graphics, Inc.
    3:  * All Rights Reserved.
    4:  *
    5:  * This program is free software; you can redistribute it and/or
    6:  * modify it under the terms of the GNU General Public License as
    7:  * published by the Free Software Foundation.
    8:  *
    9:  * This program is distributed in the hope that it would be useful,
   10:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   11:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   12:  * GNU General Public License for more details.
   13:  *
   14:  * You should have received a copy of the GNU General Public License
   15:  * along with this program; if not, see <http://www.gnu.org/licenses/>.
   16:  */
   17: 
   18: #include <stdio.h>
   19: #include <stdlib.h>
   20: #include <string.h>
   21: #include <ctype.h>
   22: #include <errno.h>
   23: #include <sys/time.h>
   24: #include <getopt.h>
   25: 
   26: #include "cmd.h"
   27: #include "qemu-aio.h"
   28: 
   29: #define _(x)	x	/* not gettext support yet */
   30: 
   31: /* from libxcmd/command.c */
   32: 
   33: cmdinfo_t	*cmdtab;
   34: int		ncmds;
   35: 
   36: static argsfunc_t	args_func;
   37: static checkfunc_t	check_func;
   38: static int		ncmdline;
   39: static char		**cmdline;
   40: 
   41: static int
   42: compare(const void *a, const void *b)
   43: {
   44: 	return strcmp(((const cmdinfo_t *)a)->name,
   45: 		      ((const cmdinfo_t *)b)->name);
   46: }
   47: 
   48: void
   49: add_command(
   50: 	const cmdinfo_t	*ci)
   51: {
   52: 	cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
   53: 	cmdtab[ncmds - 1] = *ci;
   54: 	qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
   55: }
   56: 
   57: static int
   58: check_command(
   59: 	const cmdinfo_t	*ci)
   60: {
   61: 	if (check_func)
   62: 		return check_func(ci);
   63: 	return 1;
   64: }
   65: 
   66: void
   67: add_check_command(
   68: 	checkfunc_t	cf)
   69: {
   70: 	check_func = cf;
   71: }
   72: 
   73: int
   74: command_usage(
   75: 	const cmdinfo_t *ci)
   76: {
   77: 	printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
   78: 	return 0;
   79: }
   80: 
   81: int
   82: command(
   83: 	const cmdinfo_t	*ct,
   84: 	int		argc,
   85: 	char		**argv)
   86: {
   87: 	char		*cmd = argv[0];
   88: 
   89: 	if (!check_command(ct))
   90: 		return 0;
   91: 
   92: 	if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) {
   93: 		if (ct->argmax == -1)
   94: 			fprintf(stderr,
   95: 	_("bad argument count %d to %s, expected at least %d arguments\n"),
   96: 				argc-1, cmd, ct->argmin);
   97: 		else if (ct->argmin == ct->argmax)
   98: 			fprintf(stderr,
   99: 	_("bad argument count %d to %s, expected %d arguments\n"),
  100: 				argc-1, cmd, ct->argmin);
  101: 		else
  102: 			fprintf(stderr,
  103: 	_("bad argument count %d to %s, expected between %d and %d arguments\n"),
  104: 			argc-1, cmd, ct->argmin, ct->argmax);
  105: 		return 0;
  106: 	}
  107: 	optind = 0;
  108: 	return ct->cfunc(argc, argv);
  109: }
  110: 
  111: const cmdinfo_t *
  112: find_command(
  113: 	const char	*cmd)
  114: {
  115: 	cmdinfo_t	*ct;
  116: 
  117: 	for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
  118: 		if (strcmp(ct->name, cmd) == 0 ||
  119: 		    (ct->altname && strcmp(ct->altname, cmd) == 0))
  120: 			return (const cmdinfo_t *)ct;
  121: 	}
  122: 	return NULL;
  123: }
  124: 
  125: void
  126: add_user_command(char *optarg)
  127: {
  128: 	ncmdline++;
  129: 	cmdline = realloc(cmdline, sizeof(char*) * (ncmdline));
  130: 	if (!cmdline) {
  131: 		perror("realloc");
  132: 		exit(1);
  133: 	}
  134: 	cmdline[ncmdline-1] = optarg;
  135: }
  136: 
  137: static int
  138: args_command(
  139: 	int	index)
  140: {
  141: 	if (args_func)
  142: 		return args_func(index);
  143: 	return 0;
  144: }
  145: 
  146: void
  147: add_args_command(
  148: 	argsfunc_t	af)
  149: {
  150: 	args_func = af;
  151: }
  152: 
  153: static void prep_fetchline(void *opaque)
  154: {
  155:     int *fetchable = opaque;
  156: 
  157:     qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
  158:     *fetchable= 1;
  159: }
  160: 
  161: static char *get_prompt(void);
  162: 
  163: void
  164: command_loop(void)
  165: {
  166: 	int		c, i, j = 0, done = 0, fetchable = 0, prompted = 0;
  167: 	char		*input;
  168: 	char		**v;
  169: 	const cmdinfo_t	*ct;
  170: 
  171: 	for (i = 0; !done && i < ncmdline; i++) {
  172: 		input = strdup(cmdline[i]);
  173: 		if (!input) {
  174: 			fprintf(stderr,
  175: 				_("cannot strdup command '%s': %s\n"),
  176: 				cmdline[i], strerror(errno));
  177: 			exit(1);
  178: 		}
  179: 		v = breakline(input, &c);
  180: 		if (c) {
  181: 			ct = find_command(v[0]);
  182: 			if (ct) {
  183: 				if (ct->flags & CMD_FLAG_GLOBAL)
  184: 					done = command(ct, c, v);
  185: 				else {
  186: 					j = 0;
  187: 					while (!done && (j = args_command(j)))
  188: 						done = command(ct, c, v);
  189: 				}
  190: 			} else
  191: 				fprintf(stderr, _("command \"%s\" not found\n"),
  192: 					v[0]);
  193: 		}
  194: 		doneline(input, v);
  195: 	}
  196: 	if (cmdline) {
  197: 		free(cmdline);
  198: 		return;
  199: 	}
  200: 
  201: 	while (!done) {
  202:         if (!prompted) {
  203:             printf("%s", get_prompt());
  204:             fflush(stdout);
  205:             qemu_aio_set_fd_handler(STDIN_FILENO, prep_fetchline, NULL, NULL,
  206:                                     NULL, &fetchable);
  207:             prompted = 1;
  208:         }
  209: 
  210:         qemu_aio_wait();
  211: 
  212:         if (!fetchable) {
  213:             continue;
  214:         }
  215: 		if ((input = fetchline()) == NULL)
  216: 			break;
  217: 		v = breakline(input, &c);
  218: 		if (c) {
  219: 			ct = find_command(v[0]);
  220: 			if (ct)
  221: 				done = command(ct, c, v);
  222: 			else
  223: 				fprintf(stderr, _("command \"%s\" not found\n"),
  224: 					v[0]);
  225: 		}
  226: 		doneline(input, v);
  227: 
  228:         prompted = 0;
  229:         fetchable = 0;
  230: 	}
  231:     qemu_aio_set_fd_handler(STDIN_FILENO, NULL, NULL, NULL, NULL, NULL);
  232: }
  233: 
  234: /* from libxcmd/input.c */
  235: 
  236: #if defined(ENABLE_READLINE)
  237: # include <readline/history.h>
  238: # include <readline/readline.h>
  239: #elif defined(ENABLE_EDITLINE)
  240: # include <histedit.h>
  241: #endif
  242: 
  243: static char *
  244: get_prompt(void)
  245: {
  246: 	static char	prompt[FILENAME_MAX + 2 /*"> "*/ + 1 /*"\0"*/ ];
  247: 
  248: 	if (!prompt[0])
  249: 		snprintf(prompt, sizeof(prompt), "%s> ", progname);
  250: 	return prompt;
  251: }
  252: 
  253: #if defined(ENABLE_READLINE)
  254: char *
  255: fetchline(void)
  256: {
  257: 	char	*line;
  258: 
  259: 	line = readline(get_prompt());
  260: 	if (line && *line)
  261: 		add_history(line);
  262: 	return line;
  263: }
  264: #elif defined(ENABLE_EDITLINE)
  265: static char *el_get_prompt(EditLine *e) { return get_prompt(); }
  266: char *
  267: fetchline(void)
  268: {
  269: 	static EditLine	*el;
  270: 	static History	*hist;
  271: 	HistEvent	hevent;
  272: 	char		*line;
  273: 	int		count;
  274: 
  275: 	if (!el) {
  276: 		hist = history_init();
  277: 		history(hist, &hevent, H_SETSIZE, 100);
  278: 		el = el_init(progname, stdin, stdout, stderr);
  279: 		el_source(el, NULL);
  280: 		el_set(el, EL_SIGNAL, 1);
  281: 		el_set(el, EL_PROMPT, el_get_prompt);
  282: 		el_set(el, EL_HIST, history, (const char *)hist);
  283: 	}
  284: 	line = strdup(el_gets(el, &count));
  285: 	if (line) {
  286: 		if (count > 0)
  287: 			line[count-1] = '\0';
  288: 		if (*line)
  289: 			history(hist, &hevent, H_ENTER, line);
  290: 	}
  291: 	return line;
  292: }
  293: #else
  294: # define MAXREADLINESZ	1024
  295: char *
  296: fetchline(void)
  297: {
  298: 	char	*p, *line = malloc(MAXREADLINESZ);
  299: 
  300: 	if (!line)
  301: 		return NULL;
  302: 	if (!fgets(line, MAXREADLINESZ, stdin)) {
  303: 		free(line);
  304: 		return NULL;
  305: 	}
  306: 	p = line + strlen(line);
  307: 	if (p != line && p[-1] == '\n')
  308: 		p[-1] = '\0';
  309: 	return line;
  310: }
  311: #endif
  312: 
  313: static char *qemu_strsep(char **input, const char *delim)
  314: {
  315:     char *result = *input;
  316:     if (result != NULL) {
  317:         char *p;
  318: 
  319:         for (p = result; *p != '\0'; p++) {
  320:             if (strchr(delim, *p)) {
  321:                 break;
  322:             }
  323:         }
  324:         if (*p == '\0') {
  325:             *input = NULL;
  326:         } else {
  327:             *p = '\0';
  328:             *input = p + 1;
  329:         }
  330:     }
  331:     return result;
  332: }
  333: 
  334: char **
  335: breakline(
  336: 	char	*input,
  337: 	int	*count)
  338: {
  339: 	int	c = 0;
  340: 	char	*p;
  341: 	char	**rval = calloc(sizeof(char *), 1);
  342: 
  343: 	while (rval && (p = qemu_strsep(&input, " ")) != NULL) {
  344: 		if (!*p)
  345: 			continue;
  346: 		c++;
  347: 		rval = realloc(rval, sizeof(*rval) * (c + 1));
  348: 		if (!rval) {
  349: 			c = 0;
  350: 			break;
  351: 		}
  352: 		rval[c - 1] = p;
  353: 		rval[c] = NULL;
  354: 	}
  355: 	*count = c;
  356: 	return rval;
  357: }
  358: 
  359: void
  360: doneline(
  361: 	char	*input,
  362: 	char	**vec)
  363: {
  364: 	free(input);
  365: 	free(vec);
  366: }
  367: 
  368: #define EXABYTES(x)	((long long)(x) << 60)
  369: #define PETABYTES(x)	((long long)(x) << 50)
  370: #define TERABYTES(x)	((long long)(x) << 40)
  371: #define GIGABYTES(x)	((long long)(x) << 30)
  372: #define MEGABYTES(x)	((long long)(x) << 20)
  373: #define KILOBYTES(x)	((long long)(x) << 10)
  374: 
  375: long long
  376: cvtnum(
  377: 	char		*s)
  378: {
  379: 	long long	i;
  380: 	char		*sp;
  381: 	int		c;
  382: 
  383: 	i = strtoll(s, &sp, 0);
  384: 	if (i == 0 && sp == s)
  385: 		return -1LL;
  386: 	if (*sp == '\0')
  387: 		return i;
  388: 
  389: 	if (sp[1] != '\0')
  390: 		return -1LL;
  391: 
  392: 	c = tolower(*sp);
  393: 	switch (c) {
  394: 	default:
  395: 		return i;
  396: 	case 'k':
  397: 		return KILOBYTES(i);
  398: 	case 'm':
  399: 		return MEGABYTES(i);
  400: 	case 'g':
  401: 		return GIGABYTES(i);
  402: 	case 't':
  403: 		return TERABYTES(i);
  404: 	case 'p':
  405: 		return PETABYTES(i);
  406: 	case 'e':
  407: 		return  EXABYTES(i);
  408: 	}
  409: 	return -1LL;
  410: }
  411: 
  412: #define TO_EXABYTES(x)	((x) / EXABYTES(1))
  413: #define TO_PETABYTES(x)	((x) / PETABYTES(1))
  414: #define TO_TERABYTES(x)	((x) / TERABYTES(1))
  415: #define TO_GIGABYTES(x)	((x) / GIGABYTES(1))
  416: #define TO_MEGABYTES(x)	((x) / MEGABYTES(1))
  417: #define TO_KILOBYTES(x)	((x) / KILOBYTES(1))
  418: 
  419: void
  420: cvtstr(
  421: 	double		value,
  422: 	char		*str,
  423: 	size_t		size)
  424: {
  425: 	const char	*fmt;
  426: 	int		precise;
  427: 
  428: 	precise = ((double)value * 1000 == (double)(int)value * 1000);
  429: 
  430: 	if (value >= EXABYTES(1)) {
  431: 		fmt = precise ? "%.f EiB" : "%.3f EiB";
  432: 		snprintf(str, size, fmt, TO_EXABYTES(value));
  433: 	} else if (value >= PETABYTES(1)) {
  434: 		fmt = precise ? "%.f PiB" : "%.3f PiB";
  435: 		snprintf(str, size, fmt, TO_PETABYTES(value));
  436: 	} else if (value >= TERABYTES(1)) {
  437: 		fmt = precise ? "%.f TiB" : "%.3f TiB";
  438: 		snprintf(str, size, fmt, TO_TERABYTES(value));
  439: 	} else if (value >= GIGABYTES(1)) {
  440: 		fmt = precise ? "%.f GiB" : "%.3f GiB";
  441: 		snprintf(str, size, fmt, TO_GIGABYTES(value));
  442: 	} else if (value >= MEGABYTES(1)) {
  443: 		fmt = precise ? "%.f MiB" : "%.3f MiB";
  444: 		snprintf(str, size, fmt, TO_MEGABYTES(value));
  445: 	} else if (value >= KILOBYTES(1)) {
  446: 		fmt = precise ? "%.f KiB" : "%.3f KiB";
  447: 		snprintf(str, size, fmt, TO_KILOBYTES(value));
  448: 	} else {
  449: 		snprintf(str, size, "%f bytes", value);
  450: 	}
  451: }
  452: 
  453: struct timeval
  454: tsub(struct timeval t1, struct timeval t2)
  455: {
  456: 	t1.tv_usec -= t2.tv_usec;
  457: 	if (t1.tv_usec < 0) {
  458: 		t1.tv_usec += 1000000;
  459: 		t1.tv_sec--;
  460: 	}
  461: 	t1.tv_sec -= t2.tv_sec;
  462: 	return t1;
  463: }
  464: 
  465: double
  466: tdiv(double value, struct timeval tv)
  467: {
  468: 	return value / ((double)tv.tv_sec + ((double)tv.tv_usec / 1000000.0));
  469: }
  470: 
  471: #define HOURS(sec)	((sec) / (60 * 60))
  472: #define MINUTES(sec)	(((sec) % (60 * 60)) / 60)
  473: #define SECONDS(sec)	((sec) % 60)
  474: 
  475: void
  476: timestr(
  477: 	struct timeval	*tv,
  478: 	char		*ts,
  479: 	size_t		size,
  480: 	int		format)
  481: {
  482: 	double		usec = (double)tv->tv_usec / 1000000.0;
  483: 
  484: 	if (format & TERSE_FIXED_TIME) {
  485: 		if (!HOURS(tv->tv_sec)) {
  486: 			snprintf(ts, size, "%u:%02u.%02u",
  487: 				(unsigned int) MINUTES(tv->tv_sec),
  488: 				(unsigned int) SECONDS(tv->tv_sec),
  489: 				(unsigned int) usec * 100);
  490: 			return;
  491: 		}
  492: 		format |= VERBOSE_FIXED_TIME;	/* fallback if hours needed */
  493: 	}
  494: 
  495: 	if ((format & VERBOSE_FIXED_TIME) || tv->tv_sec) {
  496: 		snprintf(ts, size, "%u:%02u:%02u.%02u",
  497: 			(unsigned int) HOURS(tv->tv_sec),
  498: 			(unsigned int) MINUTES(tv->tv_sec),
  499: 			(unsigned int) SECONDS(tv->tv_sec),
  500: 			(unsigned int) usec * 100);
  501: 	} else {
  502: 		snprintf(ts, size, "0.%04u sec", (unsigned int) usec * 10000);
  503: 	}
  504: }
  505: 
  506: 
  507: /* from libxcmd/quit.c */
  508: 
  509: static cmdinfo_t quit_cmd;
  510: 
  511: /* ARGSUSED */
  512: static int
  513: quit_f(
  514: 	int	argc,
  515: 	char	**argv)
  516: {
  517: 	return 1;
  518: }
  519: 
  520: void
  521: quit_init(void)
  522: {
  523: 	quit_cmd.name = _("quit");
  524: 	quit_cmd.altname = _("q");
  525: 	quit_cmd.cfunc = quit_f;
  526: 	quit_cmd.argmin = -1;
  527: 	quit_cmd.argmax = -1;
  528: 	quit_cmd.flags = CMD_FLAG_GLOBAL;
  529: 	quit_cmd.oneline = _("exit the program");
  530: 
  531: 	add_command(&quit_cmd);
  532: }
  533: 
  534: /* from libxcmd/help.c */
  535: 
  536: static cmdinfo_t help_cmd;
  537: static void help_onecmd(const char *cmd, const cmdinfo_t *ct);
  538: static void help_oneline(const char *cmd, const cmdinfo_t *ct);
  539: 
  540: static void
  541: help_all(void)
  542: {
  543: 	const cmdinfo_t	*ct;
  544: 
  545: 	for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++)
  546: 		help_oneline(ct->name, ct);
  547: 	printf(_("\nUse 'help commandname' for extended help.\n"));
  548: }
  549: 
  550: static int
  551: help_f(
  552: 	int		argc,
  553: 	char		**argv)
  554: {
  555: 	const cmdinfo_t	*ct;
  556: 
  557: 	if (argc == 1) {
  558: 		help_all();
  559: 		return 0;
  560: 	}
  561: 	ct = find_command(argv[1]);
  562: 	if (ct == NULL) {
  563: 		printf(_("command %s not found\n"), argv[1]);
  564: 		return 0;
  565: 	}
  566: 	help_onecmd(argv[1], ct);
  567: 	return 0;
  568: }
  569: 
  570: static void
  571: help_onecmd(
  572: 	const char	*cmd,
  573: 	const cmdinfo_t	*ct)
  574: {
  575: 	help_oneline(cmd, ct);
  576: 	if (ct->help)
  577: 		ct->help();
  578: }
  579: 
  580: static void
  581: help_oneline(
  582: 	const char	*cmd,
  583: 	const cmdinfo_t	*ct)
  584: {
  585: 	if (cmd)
  586: 		printf("%s ", cmd);
  587: 	else {
  588: 		printf("%s ", ct->name);
  589: 		if (ct->altname)
  590: 			printf("(or %s) ", ct->altname);
  591: 	}
  592: 	if (ct->args)
  593: 		printf("%s ", ct->args);
  594: 	printf("-- %s\n", ct->oneline);
  595: }
  596: 
  597: void
  598: help_init(void)
  599: {
  600: 	help_cmd.name = _("help");
  601: 	help_cmd.altname = _("?");
  602: 	help_cmd.cfunc = help_f;
  603: 	help_cmd.argmin = 0;
  604: 	help_cmd.argmax = 1;
  605: 	help_cmd.flags = CMD_FLAG_GLOBAL;
  606: 	help_cmd.args = _("[command]");
  607: 	help_cmd.oneline = _("help for one or all commands");
  608: 
  609: 	add_command(&help_cmd);
  610: }

unix.superglobalmegacorp.com