File:  [Qemu by Fabrice Bellard] / qemu / cmd.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:18:01 2018 UTC (2 years, 3 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, HEAD
qemu 1.0.1

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

unix.superglobalmegacorp.com