Home | History | Annotate | Line # | Download | only in common
commands.c revision 1.1.2.2
      1 /*	$NetBSD: commands.c,v 1.1.2.2 2006/04/11 11:53:40 yamt Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 1998 Michael Smith <msmith (at) freebsd.org>
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
     17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26  * SUCH DAMAGE.
     27  */
     28 
     29 #include <sys/cdefs.h>
     30 
     31 #include <lib/libsa/stand.h>
     32 #include <lib/libkern/libkern.h>
     33 
     34 #include "bootstrap.h"
     35 
     36 char		*command_errmsg;
     37 char		command_errbuf[256];	/* XXX should have procedural interface for setting, size limit? */
     38 
     39 static int page_file(char *filename);
     40 
     41 /*
     42  * Help is read from a formatted text file.
     43  *
     44  * Entries in the file are formatted as
     45 
     46 # Ttopic [Ssubtopic] Ddescription
     47 help
     48 text
     49 here
     50 #
     51 
     52  *
     53  * Note that for code simplicity's sake, the above format must be followed
     54  * exactly.
     55  *
     56  * Subtopic entries must immediately follow the topic (this is used to
     57  * produce the listing of subtopics).
     58  *
     59  * If no argument(s) are supplied by the user, the help for 'help' is displayed.
     60  */
     61 
     62 static int
     63 help_getnext(int fd, char **topic, char **subtopic, char **desc)
     64 {
     65     char	line[81], *cp, *ep;
     66 
     67     for (;;) {
     68 	if (fgetstr(line, 80, fd) < 0)
     69 	    return(0);
     70 
     71 	if ((strlen(line) < 3) || (line[0] != '#') || (line[1] != ' '))
     72 	    continue;
     73 
     74 	*topic = *subtopic = *desc = NULL;
     75 	cp = line + 2;
     76 	while((cp != NULL) && (*cp != 0)) {
     77 	    ep = strchr(cp, ' ');
     78 	    if ((*cp == 'T') && (*topic == NULL)) {
     79 		if (ep != NULL)
     80 		    *ep++ = 0;
     81 		*topic = strdup(cp + 1);
     82 	    } else if ((*cp == 'S') && (*subtopic == NULL)) {
     83 		if (ep != NULL)
     84 		    *ep++ = 0;
     85 		*subtopic = strdup(cp + 1);
     86 	    } else if (*cp == 'D') {
     87 		*desc = strdup(cp + 1);
     88 		ep = NULL;
     89 	    }
     90 	    cp = ep;
     91 	}
     92 	if (*topic == NULL) {
     93 	    if (*subtopic != NULL)
     94 		free(*subtopic);
     95 	    if (*desc != NULL)
     96 		free(*desc);
     97 	    continue;
     98 	}
     99 	return(1);
    100     }
    101 }
    102 
    103 static int
    104 help_emitsummary(char *topic, char *subtopic, char *desc)
    105 {
    106     int		i;
    107 
    108     pager_output("    ");
    109     pager_output(topic);
    110     i = strlen(topic);
    111     if (subtopic != NULL) {
    112 	pager_output(" ");
    113 	pager_output(subtopic);
    114 	i += strlen(subtopic) + 1;
    115     }
    116     if (desc != NULL) {
    117 	do {
    118 	    pager_output(" ");
    119 	} while (i++ < 30);
    120 	pager_output(desc);
    121     }
    122     return (pager_output("\n"));
    123 }
    124 
    125 
    126 int
    127 command_help(int argc, char *argv[])
    128 {
    129     char	buf[81];	/* XXX buffer size? */
    130     int		hfd, matched, doindex;
    131     char	*topic, *subtopic, *t, *s, *d;
    132 
    133     /* page the help text from our load path */
    134     sprintf(buf, "%s/boot/loader.help", getenv("loaddev"));
    135     if ((hfd = open(buf, O_RDONLY)) < 0) {
    136 	printf("Verbose help not available, use '?' to list commands\n");
    137 	return(CMD_OK);
    138     }
    139 
    140     /* pick up request from arguments */
    141     topic = subtopic = NULL;
    142     switch(argc) {
    143     case 3:
    144 	subtopic = strdup(argv[2]);
    145     case 2:
    146 	topic = strdup(argv[1]);
    147 	break;
    148     case 1:
    149 	topic = strdup("help");
    150 	break;
    151     default:
    152 	command_errmsg = "usage is 'help <topic> [<subtopic>]";
    153 	return(CMD_ERROR);
    154     }
    155 
    156     /* magic "index" keyword */
    157     doindex = !strcmp(topic, "index");
    158     matched = doindex;
    159 
    160     /* Scan the helpfile looking for help matching the request */
    161     pager_open();
    162     while(help_getnext(hfd, &t, &s, &d)) {
    163 
    164 	if (doindex) {		/* dink around formatting */
    165 	    if (help_emitsummary(t, s, d))
    166 		break;
    167 
    168 	} else if (strcmp(topic, t)) {
    169 	    /* topic mismatch */
    170 	    if(matched)		/* nothing more on this topic, stop scanning */
    171 		break;
    172 
    173 	} else {
    174 	    /* topic matched */
    175 	    matched = 1;
    176 	    if (((subtopic == NULL) && (s == NULL)) ||
    177 		((subtopic != NULL) && (s != NULL) && !strcmp(subtopic, s))) {
    178 		/* exact match, print text */
    179 		while((fgetstr(buf, 80, hfd) >= 0) && (buf[0] != '#')) {
    180 		    if (pager_output(buf))
    181 			break;
    182 		    if (pager_output("\n"))
    183 			break;
    184 		}
    185 	    } else if ((subtopic == NULL) && (s != NULL)) {
    186 		/* topic match, list subtopics */
    187 		if (help_emitsummary(t, s, d))
    188 		    break;
    189 	    }
    190 	}
    191 	free(t);
    192 	free(s);
    193 	free(d);
    194     }
    195     pager_close();
    196     close(hfd);
    197     if (!matched) {
    198 	sprintf(command_errbuf, "no help available for '%s'", topic);
    199 	free(topic);
    200 	if (subtopic)
    201 	    free(subtopic);
    202 	return(CMD_ERROR);
    203     }
    204     free(topic);
    205     if (subtopic)
    206 	free(subtopic);
    207     return(CMD_OK);
    208 }
    209 
    210 
    211 int
    212 command_commandlist(int argc, char *argv[])
    213 {
    214     struct bootblk_command	*cmdp;
    215     int		res;
    216     char	name[20];
    217     int i;
    218 
    219     res = 0;
    220     pager_open();
    221     res = pager_output("Available commands:\n");
    222 
    223     for (i = 0, cmdp = commands; (cmdp->c_name != NULL) && (cmdp->c_desc != NULL ); i++, cmdp = commands + i) {
    224 	    if (res)
    225 	    break;
    226 	if ((cmdp->c_name != NULL) && (cmdp->c_desc != NULL)) {
    227 	    sprintf(name, "  %s  ", cmdp->c_name);
    228 	    pager_output(name);
    229 	    pager_output(cmdp->c_desc);
    230 	    res = pager_output("\n");
    231 	}
    232     }
    233     pager_close();
    234     return(CMD_OK);
    235 }
    236 
    237 /*
    238  * XXX set/show should become set/echo if we have variable
    239  * substitution happening.
    240  */
    241 
    242 int
    243 command_show(int argc, char *argv[])
    244 {
    245     struct env_var	*ev;
    246     char		*cp;
    247 
    248     if (argc < 2) {
    249 	/*
    250 	 * With no arguments, print everything.
    251 	 */
    252 	pager_open();
    253 	for (ev = environ; ev != NULL; ev = ev->ev_next) {
    254 	    pager_output(ev->ev_name);
    255 	    cp = getenv(ev->ev_name);
    256 	    if (cp != NULL) {
    257 		pager_output("=");
    258 		pager_output(cp);
    259 	    }
    260 	    if (pager_output("\n"))
    261 		break;
    262 	}
    263 	pager_close();
    264     } else {
    265 	if ((cp = getenv(argv[1])) != NULL) {
    266 	    printf("%s\n", cp);
    267 	} else {
    268 	    sprintf(command_errbuf, "variable '%s' not found", argv[1]);
    269 	    return(CMD_ERROR);
    270 	}
    271     }
    272     return(CMD_OK);
    273 }
    274 
    275 
    276 int
    277 command_set(int argc, char *argv[])
    278 {
    279     int		err;
    280 
    281     if (argc != 2) {
    282 	command_errmsg = "wrong number of arguments";
    283 	return(CMD_ERROR);
    284     } else {
    285 	if ((err = putenv(argv[1])) != 0) {
    286 	    command_errmsg = strerror(err);
    287 	    return(CMD_ERROR);
    288 	}
    289     }
    290     return(CMD_OK);
    291 }
    292 
    293 
    294 int
    295 command_unset(int argc, char *argv[])
    296 {
    297     int		err;
    298 
    299     if (argc != 2) {
    300 	command_errmsg = "wrong number of arguments";
    301 	return(CMD_ERROR);
    302     } else {
    303 	if ((err = unsetenv(argv[1])) != 0) {
    304 	    command_errmsg = strerror(err);
    305 	    return(CMD_ERROR);
    306 	}
    307     }
    308     return(CMD_OK);
    309 }
    310 
    311 
    312 int
    313 command_echo(int argc, char *argv[])
    314 {
    315     char	*s;
    316     int		nl, ch;
    317 
    318     nl = 0;
    319     optind = 1;
    320     optreset = 1;
    321     while ((ch = getopt(argc, argv, "n")) != -1) {
    322 	switch(ch) {
    323 	case 'n':
    324 	    nl = 1;
    325 	    break;
    326 	case '?':
    327 	default:
    328 	    /* getopt has already reported an error */
    329 	    return(CMD_OK);
    330 	}
    331     }
    332     argv += (optind);
    333     argc -= (optind);
    334 
    335     s = unargv(argc, argv);
    336     if (s != NULL) {
    337 	printf("%s", s);
    338 	free(s);
    339     }
    340     if (!nl)
    341 	printf("\n");
    342     return(CMD_OK);
    343 }
    344 
    345 /*
    346  * A passable emulation of the sh(1) command of the same name.
    347  */
    348 
    349 
    350 int
    351 command_read(int argc, char *argv[])
    352 {
    353     char	*prompt;
    354     int		timeout;
    355     time_t	when;
    356     char	*cp;
    357     char	*name;
    358     char	buf[256];		/* XXX size? */
    359     int		c;
    360 
    361     timeout = -1;
    362     prompt = NULL;
    363     optind = 1;
    364     optreset = 1;
    365     while ((c = getopt(argc, argv, "p:t:")) != -1) {
    366 	switch(c) {
    367 
    368 	case 'p':
    369 	    prompt = optarg;
    370 	    break;
    371 	case 't':
    372 	    timeout = strtol(optarg, &cp, 0);
    373 	    if (cp == optarg) {
    374 		sprintf(command_errbuf, "bad timeout '%s'", optarg);
    375 		return(CMD_ERROR);
    376 	    }
    377 	    break;
    378 	default:
    379 	    return(CMD_OK);
    380 	}
    381     }
    382 
    383     argv += (optind);
    384     argc -= (optind);
    385     name = (argc > 0) ? argv[0]: NULL;
    386 
    387     if (prompt != NULL)
    388 	printf("%s", prompt);
    389     if (timeout >= 0) {
    390 	when = time(NULL) + timeout;
    391 	while (!ischar())
    392 	    if (time(NULL) >= when)
    393 		return(CMD_OK);		/* is timeout an error? */
    394     }
    395 
    396     ngets(buf, sizeof(buf));
    397 
    398     if (name != NULL)
    399 	setenv(name, buf, 1);
    400     return(CMD_OK);
    401 }
    402 
    403 /*
    404  * File pager
    405  */
    406 
    407 int
    408 command_more(int argc, char *argv[])
    409 {
    410     int         i;
    411     int         res;
    412     char	line[80];
    413 
    414     res=0;
    415     pager_open();
    416     for (i = 1; (i < argc) && (res == 0); i++) {
    417 	sprintf(line, "*** FILE %s BEGIN ***\n", argv[i]);
    418 	if (pager_output(line))
    419 		break;
    420         res = page_file(argv[i]);
    421 	if (!res) {
    422 	    sprintf(line, "*** FILE %s END ***\n", argv[i]);
    423 	    res = pager_output(line);
    424 	}
    425     }
    426     pager_close();
    427 
    428     if (res == 0)
    429 	return CMD_OK;
    430     else
    431 	return CMD_ERROR;
    432 }
    433 
    434 static int
    435 page_file(char *filename)
    436 {
    437     int result;
    438 
    439     result = pager_file(filename);
    440 
    441     if (result == -1)
    442 	sprintf(command_errbuf, "error showing %s", filename);
    443 
    444     return result;
    445 }
    446 
    447 /*
    448  * List all disk-like devices
    449  */
    450 
    451 int
    452 command_lsdev(int argc, char *argv[])
    453 {
    454     int		verbose, ch, i;
    455     char	line[80];
    456 
    457     verbose = 0;
    458     optind = 1;
    459     optreset = 1;
    460     while ((ch = getopt(argc, argv, "v")) != -1) {
    461 	switch(ch) {
    462 	case 'v':
    463 	    verbose = 1;
    464 	    break;
    465 	case '?':
    466 	default:
    467 	    /* getopt has already reported an error */
    468 	    return(CMD_OK);
    469 	}
    470     }
    471     argv += (optind);
    472     argc -= (optind);
    473 
    474     pager_open();
    475 
    476     sprintf(line, "Device Enumeration:\n");
    477     pager_output(line);
    478 
    479     for (i = 0; i < ndevs; i++) {
    480 	 sprintf(line, "%s\n", devsw[i].dv_name);
    481 	    if (pager_output(line))
    482 		    break;
    483     }
    484 
    485     pager_close();
    486     return(CMD_OK);
    487 }
    488 
    489