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