commands.c revision 1.2.10.2 1 /* $NetBSD: commands.c,v 1.2.10.2 2006/06/21 14:52:53 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 /* __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