1 /*        $NetBSD: subr_userconf.c,v 1.27 2018/09/16 23:18:55 mrg Exp $         */
2 
3 /*
4  * Copyright (c) 1996 Mats O Jansson <moj@stacken.kth.se>
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 ``AS IS'' AND ANY EXPRESS
17  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
20  * 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  *        OpenBSD: subr_userconf.c,v 1.19 2000/01/08 23:23:37 d Exp
29  */
30 
31 #include <sys/cdefs.h>
32 __KERNEL_RCSID(0, "$NetBSD: subr_userconf.c,v 1.27 2018/09/16 23:18:55 mrg Exp $");
33 
34 #include <sys/param.h>
35 #include <sys/systm.h>
36 #include <sys/device.h>
37 #include <sys/time.h>
38 #include <sys/userconf.h>
39 
40 #include <dev/cons.h>
41 
42 extern struct cfdata cfdata[];
43 
44 static int userconf_base = 16;                              /* Base for "large" numbers */
45 static int userconf_maxdev = -1;                  /* # of used device slots   */
46 static int userconf_totdev = -1;                  /* # of device slots        */
47 #if 0
48 static int userconf_maxlocnames = -1;             /* # of locnames            */
49 #endif
50 static int userconf_cnt = -1;                     /* Line counter for ...     */
51 static int userconf_lines = 12;                             /* ... # of lines per page  */
52 static int userconf_histlen = 0;
53 static int userconf_histcur = 0;
54 static char userconf_history[1024];
55 static int userconf_histsz = sizeof(userconf_history);
56 static char userconf_argbuf[40];                  /* Additional input         */
57 static char userconf_cmdbuf[40];                  /* Command line             */
58 static char userconf_histbuf[40];
59 
60 #define UC_CHANGE 'c'
61 #define UC_DISABLE 'd'
62 #define UC_ENABLE 'e'
63 #define UC_FIND 'f'
64 #define UC_SHOW 's'
65 
66 static const char *userconf_cmds[] = {
67           "base",             "b",
68           "change", "c",
69           "disable",          "d",
70           "enable", "e",
71           "exit",             "q",
72           "find",             "f",
73           "help",             "h",
74           "list",             "l",
75           "lines",  "L",
76           "quit",             "q",
77           "?",                "h",
78           "",                  "",
79 };
80 
81 void
userconf_init(void)82 userconf_init(void)
83 {
84           int i;
85           struct cfdata *cf;
86 
87           i = 0;
88           for (cf = cfdata; cf->cf_name; cf++)
89                     i++;
90 
91           userconf_maxdev = i - 1;
92           userconf_totdev = i - 1;
93 
94           userconf_bootinfo();
95 }
96 
97 static int
userconf_more(void)98 userconf_more(void)
99 {
100           int quit = 0;
101           char c = '\0';
102 
103           if (userconf_cnt != -1) {
104                     if (userconf_cnt == userconf_lines) {
105                               printf("-- more --");
106                               cnpollc(1);
107                               c = cngetc();
108                               cnpollc(0);
109                               userconf_cnt = 0;
110                               printf("\r            \r");
111                     }
112                     userconf_cnt++;
113                     if (c == 'q' || c == 'Q')
114                               quit = 1;
115           }
116           return (quit);
117 }
118 
119 static void
userconf_hist_cmd(char cmd)120 userconf_hist_cmd(char cmd)
121 {
122           userconf_histcur = userconf_histlen;
123           if (userconf_histcur < userconf_histsz) {
124                     userconf_history[userconf_histcur] = cmd;
125                     userconf_histcur++;
126           }
127 }
128 
129 static void
userconf_hist_int(int val)130 userconf_hist_int(int val)
131 {
132           snprintf(userconf_histbuf, sizeof(userconf_histbuf), " %d", val);
133           if ((userconf_histcur + strlen(userconf_histbuf)) < userconf_histsz) {
134                     memcpy(&userconf_history[userconf_histcur],
135                           userconf_histbuf,
136                           strlen(userconf_histbuf));
137                     userconf_histcur = userconf_histcur + strlen(userconf_histbuf);
138           }
139 }
140 
141 static void
userconf_hist_eoc(void)142 userconf_hist_eoc(void)
143 {
144           if (userconf_histcur < userconf_histsz) {
145                     userconf_history[userconf_histcur] = '\n';
146                     userconf_histcur++;
147                     userconf_histlen = userconf_histcur;
148           }
149 }
150 
151 static void
userconf_pnum(int val)152 userconf_pnum(int val)
153 {
154           if (val > -2 && val < 16) {
155                     printf("%d",val);
156           } else {
157                     switch (userconf_base) {
158                     case 8:
159                               printf("0%o",val);
160                               break;
161                     case 10:
162                               printf("%d",val);
163                               break;
164                     case 16:
165                     default:
166                               printf("0x%x",val);
167                               break;
168                     }
169           }
170 }
171 
172 static void
userconf_pdevnam(short dev)173 userconf_pdevnam(short dev)
174 {
175           struct cfdata *cd;
176 
177           cd = &cfdata[dev];
178           printf("%s", cd->cf_name);
179           switch (cd->cf_fstate) {
180           case FSTATE_NOTFOUND:
181           case FSTATE_DNOTFOUND:
182                     printf("%d", cd->cf_unit);
183                     break;
184           case FSTATE_FOUND:
185                     printf("*FOUND*");
186                     break;
187           case FSTATE_STAR:
188           case FSTATE_DSTAR:
189                     printf("*");
190                     break;
191           default:
192                     printf("*UNKNOWN*");
193                     break;
194           }
195 }
196 
197 static void
userconf_pdev(short devno)198 userconf_pdev(short devno)
199 {
200           struct cfdata *cd;
201           const struct cfparent *cfp;
202           int   *l;
203           const struct cfiattrdata *ia;
204           const struct cflocdesc *ld;
205           int nld, i;
206 
207           if (devno > userconf_maxdev) {
208                     printf("Unknown devno (max is %d)\n", userconf_maxdev);
209                     return;
210           }
211 
212           cd = &cfdata[devno];
213 
214           printf("[%3d] ", devno);
215           userconf_pdevnam(devno);
216           printf(" at");
217           cfp = cd->cf_pspec;
218           if (cfp == NULL)
219                     printf(" root");
220           else if (cfp->cfp_parent != NULL && cfp->cfp_unit != -1)
221                     printf(" %s%d", cfp->cfp_parent, cfp->cfp_unit);
222           else
223                     printf(" %s?", cfp->cfp_parent != NULL ? cfp->cfp_parent
224                                                                    : cfp->cfp_iattr);
225           switch (cd->cf_fstate) {
226           case FSTATE_NOTFOUND:
227           case FSTATE_FOUND:
228           case FSTATE_STAR:
229                     break;
230           case FSTATE_DNOTFOUND:
231           case FSTATE_DSTAR:
232                     printf(" disable");
233                     break;
234           default:
235                     printf(" ???");
236                     break;
237           }
238           if (cfp) {
239                     l = cd->cf_loc;
240                     ia = cfiattr_lookup(cfp->cfp_iattr, 0);
241                     KASSERT(ia);
242                     ld = ia->ci_locdesc;
243                     nld = ia->ci_loclen;
244                     for (i = 0; i < nld; i++) {
245                               printf(" %s ", ld[i].cld_name);
246                               if (!ld[i].cld_defaultstr
247                                   || (l[i] != ld[i].cld_default))
248                                         userconf_pnum(l[i]);
249                               else
250                                         printf("?");
251                     }
252           }
253           printf("\n");
254 }
255 
256 static int
userconf_number(char * c,int * val)257 userconf_number(char *c, int *val)
258 {
259           u_int num = 0;
260           int neg = 0;
261           int base = 10;
262 
263           if (*c == '-') {
264                     neg = 1;
265                     c++;
266           }
267           if (*c == '0') {
268                     base = 8;
269                     c++;
270                     if (*c == 'x' || *c == 'X') {
271                               base = 16;
272                               c++;
273                     }
274           }
275           while (*c != '\n' && *c != '\t' && *c != ' ' && *c != '\0') {
276                     u_char cc = *c;
277 
278                     if (cc >= '0' && cc <= '9')
279                               cc = cc - '0';
280                     else if (cc >= 'a' && cc <= 'f')
281                               cc = cc - 'a' + 10;
282                     else if (cc >= 'A' && cc <= 'F')
283                               cc = cc - 'A' + 10;
284                     else
285                               return (-1);
286 
287                     if (cc > base)
288                               return (-1);
289                     num = num * base + cc;
290                     c++;
291           }
292 
293           if (neg && num > INT_MAX)     /* overflow */
294                     return (1);
295           *val = neg ? - num : num;
296           return (0);
297 }
298 
299 static int
userconf_device(char * cmd,int * len,short * unit,short * state)300 userconf_device(char *cmd, int *len, short *unit, short *state)
301 {
302           short u = 0, s = FSTATE_FOUND;
303           int l = 0;
304           char *c;
305 
306           c = cmd;
307           while (!(!*c || *c == ' ' || *c == '\t' || *c == '\n'))
308                     c++;
309           while (c > cmd) {
310                     c--;
311                     if (!((*c >= '0' && *c <= '9') || *c == '*')) {
312                               c++;
313                               break;
314                     }
315           }
316           l = c - cmd;
317           if (*c == '*') {
318                     s = FSTATE_STAR;
319                     c++;
320           } else {
321                     while (*c >= '0' && *c <= '9') {
322                               s = FSTATE_NOTFOUND;
323                               u = u*10 + *c - '0';
324                               c++;
325                     }
326           }
327           while (*c == ' ' || *c == '\t' || *c == '\n')
328                     c++;
329 
330           if (*c == '\0') {
331                     *len = l;
332                     *unit = u;
333                     *state = s;
334                     return(0);
335           }
336 
337           return(-1);
338 }
339 
340 static void
userconf_modify(const struct cflocdesc * item,int * val)341 userconf_modify(const struct cflocdesc *item, int *val)
342 {
343           int ok = 0;
344           int a;
345           char *c;
346 
347           while (!ok) {
348                     printf("%s [", item->cld_name);
349                     if (item->cld_defaultstr && (*val == item->cld_default))
350                               printf("?");
351                     else
352                               userconf_pnum(*val);
353                     printf("] ? ");
354 
355                     cngetsn(userconf_argbuf, sizeof(userconf_argbuf));
356 
357                     c = userconf_argbuf;
358                     while (*c == ' ' || *c == '\t' || *c == '\n') c++;
359 
360                     if (*c != '\0') {
361                               if (*c == '?') {
362                                         if (item->cld_defaultstr) {
363                                                   *val = item->cld_default;
364                                                   ok = 1;
365                                         } else
366                                                   printf("No default\n");
367                               } else if (userconf_number(c, &a) == 0) {
368                                         *val = a;
369                                         ok = 1;
370                               } else {
371                                         printf("Unknown argument\n");
372                               }
373                     } else {
374                               ok = 1;
375                     }
376           }
377 }
378 
379 static void
userconf_change(int devno)380 userconf_change(int devno)
381 {
382           struct cfdata *cd;
383           char c = '\0';
384           int   *l;
385           int   ln;
386           const struct cfiattrdata *ia;
387           const struct cflocdesc *ld;
388           int nld;
389 
390           if (devno <=  userconf_maxdev) {
391 
392                     userconf_pdev(devno);
393 
394                     while (c != 'y' && c != 'Y' && c != 'n' && c != 'N') {
395                               printf("change (y/n) ?");
396                               cnpollc(1);
397                               c = cngetc();
398                               cnpollc(0);
399                               printf("\n");
400                     }
401 
402                     if (c == 'y' || c == 'Y') {
403 
404                               /* XXX add cmd 'c' <devno> */
405                               userconf_hist_cmd('c');
406                               userconf_hist_int(devno);
407 
408                               cd = &cfdata[devno];
409                               l = cd->cf_loc;
410                               ia = cfiattr_lookup(cd->cf_pspec->cfp_iattr, 0);
411                               KASSERT(ia);
412                               ld = ia->ci_locdesc;
413                               nld = ia->ci_loclen;
414 
415                               for (ln = 0; ln < nld; ln++)
416                               {
417                                         userconf_modify(&ld[ln], l);
418 
419                                         /* XXX add *l */
420                                         userconf_hist_int(*l);
421 
422                                         l++;
423                               }
424 
425                               printf("[%3d] ", devno);
426                               userconf_pdevnam(devno);
427                               printf(" changed\n");
428                               userconf_pdev(devno);
429 
430                               /* XXX add eoc */
431                               userconf_hist_eoc();
432 
433                     }
434           } else {
435                     printf("Unknown devno (max is %d)\n", userconf_maxdev);
436           }
437 }
438 
439 static void
userconf_disable(int devno)440 userconf_disable(int devno)
441 {
442           int done = 0;
443 
444           if (devno <= userconf_maxdev) {
445                     switch (cfdata[devno].cf_fstate) {
446                     case FSTATE_NOTFOUND:
447                               cfdata[devno].cf_fstate = FSTATE_DNOTFOUND;
448                               break;
449                     case FSTATE_STAR:
450                               cfdata[devno].cf_fstate = FSTATE_DSTAR;
451                               break;
452                     case FSTATE_DNOTFOUND:
453                     case FSTATE_DSTAR:
454                               done = 1;
455                               break;
456                     default:
457                               printf("Error unknown state\n");
458                               break;
459                     }
460 
461                     printf("[%3d] ", devno);
462                     userconf_pdevnam(devno);
463                     if (done) {
464                               printf(" already");
465                     } else {
466                               /* XXX add cmd 'd' <devno> eoc */
467                               userconf_hist_cmd('d');
468                               userconf_hist_int(devno);
469                               userconf_hist_eoc();
470                     }
471                     printf(" disabled\n");
472           } else {
473                     printf("Unknown devno (max is %d)\n", userconf_maxdev);
474           }
475 }
476 
477 static void
userconf_enable(int devno)478 userconf_enable(int devno)
479 {
480           int done = 0;
481 
482           if (devno <= userconf_maxdev) {
483                     switch (cfdata[devno].cf_fstate) {
484                     case FSTATE_DNOTFOUND:
485                               cfdata[devno].cf_fstate = FSTATE_NOTFOUND;
486                               break;
487                     case FSTATE_DSTAR:
488                               cfdata[devno].cf_fstate = FSTATE_STAR;
489                               break;
490                     case FSTATE_NOTFOUND:
491                     case FSTATE_STAR:
492                               done = 1;
493                               break;
494                     default:
495                               printf("Error unknown state\n");
496                               break;
497                     }
498 
499                     printf("[%3d] ", devno);
500                     userconf_pdevnam(devno);
501                     if (done) {
502                               printf(" already");
503                     } else {
504                               /* XXX add cmd 'e' <devno> eoc */
505                               userconf_hist_cmd('d');
506                               userconf_hist_int(devno);
507                               userconf_hist_eoc();
508                     }
509                     printf(" enabled\n");
510           } else {
511                     printf("Unknown devno (max is %d)\n", userconf_maxdev);
512           }
513 }
514 
515 static void
userconf_help(void)516 userconf_help(void)
517 {
518           int j = 0, k;
519 
520           printf("command   args                description\n");
521           while (*userconf_cmds[j] != '\0') {
522                     printf("%s", userconf_cmds[j]);
523                     k = strlen(userconf_cmds[j]);
524                     while (k < 10) {
525                               printf(" ");
526                               k++;
527                     }
528                     switch (*userconf_cmds[j+1]) {
529                     case 'L':
530                               printf("[count]             number of lines before more");
531                               break;
532                     case 'b':
533                               printf("8|10|16             base on large numbers");
534                               break;
535                     case 'c':
536                               printf("devno|dev           change devices");
537                               break;
538                     case 'd':
539                               printf("devno|dev           disable devices");
540                               break;
541                     case 'e':
542                               printf("devno|dev           enable devices");
543                               break;
544                     case 'f':
545                               printf("devno|dev           find devices");
546                               break;
547                     case 'h':
548                               printf("                    this message");
549                               break;
550                     case 'l':
551                               printf("                    list configuration");
552                               break;
553                     case 'q':
554                               printf("                    leave userconf");
555                               break;
556                     default:
557                               printf("                    don't know");
558                               break;
559                     }
560                     printf("\n");
561                     j += 2;
562           }
563 }
564 
565 static void
userconf_list(void)566 userconf_list(void)
567 {
568           int i = 0;
569 
570           userconf_cnt = 0;
571 
572           while (cfdata[i].cf_name != NULL) {
573                     if (userconf_more())
574                               break;
575                     userconf_pdev(i++);
576           }
577 
578           userconf_cnt = -1;
579 }
580 
581 static void
userconf_common_dev(char * dev,int len,short unit,short state,char routine)582 userconf_common_dev(char *dev, int len, short unit, short state, char routine)
583 {
584           int i = 0;
585 
586           switch (routine) {
587           case UC_CHANGE:
588                     break;
589           default:
590                     userconf_cnt = 0;
591                     break;
592           }
593 
594           while (cfdata[i].cf_name != NULL) {
595                     if (strlen(cfdata[i].cf_name) == len) {
596 
597                               /*
598                                * Ok, if device name is correct
599                                *  If state == FSTATE_FOUND, look for "dev"
600                                *  If state == FSTATE_STAR, look for "dev*"
601                                *  If state == FSTATE_NOTFOUND, look for "dev0"
602                                */
603                               if (strncasecmp(dev, cfdata[i].cf_name,
604                                                   len) == 0 &&
605                                   (state == FSTATE_FOUND ||
606                                    (state == FSTATE_STAR &&
607                                     (cfdata[i].cf_fstate == FSTATE_STAR ||
608                                      cfdata[i].cf_fstate == FSTATE_DSTAR)) ||
609                                    (state == FSTATE_NOTFOUND &&
610                                     cfdata[i].cf_unit == unit &&
611                                     (cfdata[i].cf_fstate == FSTATE_NOTFOUND ||
612                                      cfdata[i].cf_fstate == FSTATE_DNOTFOUND)))) {
613                                         if (userconf_more())
614                                                   break;
615                                         switch (routine) {
616                                         case UC_CHANGE:
617                                                   userconf_change(i);
618                                                   break;
619                                         case UC_ENABLE:
620                                                   userconf_enable(i);
621                                                   break;
622                                         case UC_DISABLE:
623                                                   userconf_disable(i);
624                                                   break;
625                                         case UC_FIND:
626                                                   userconf_pdev(i);
627                                                   break;
628                                         default:
629                                                   printf("Unknown routine /%c/\n",
630                                                       routine);
631                                                   break;
632                                         }
633                               }
634                     }
635                     i++;
636           }
637 
638           switch (routine) {
639           case UC_CHANGE:
640                     break;
641           default:
642                     userconf_cnt = -1;
643                     break;
644           }
645 }
646 
647 #if 0
648 static void
649 userconf_add_read(char *prompt, char field, char *dev, int len, int *val)
650 {
651           int ok = 0;
652           int a;
653           char *c;
654 
655           *val = -1;
656 
657           while (!ok) {
658                     printf("%s ? ", prompt);
659 
660                     getsn(userconf_argbuf, sizeof(userconf_argbuf));
661 
662                     c = userconf_argbuf;
663                     while (*c == ' ' || *c == '\t' || *c == '\n') c++;
664 
665                     if (*c != '\0') {
666                               if (userconf_number(c, &a) == 0) {
667                                         if (a > userconf_maxdev) {
668                                                   printf("Unknown devno (max is %d)\n",
669                                                       userconf_maxdev);
670                                         } else if (strncasecmp(dev,
671                                             cfdata[a].cf_name, len) != 0 &&
672                                                   field == 'a') {
673                                                   printf("Not same device type\n");
674                                         } else {
675                                                   *val = a;
676                                                   ok = 1;
677                                         }
678                               } else if (*c == '?') {
679                                         userconf_common_dev(dev, len, 0,
680                                             FSTATE_FOUND, UC_FIND);
681                               } else if (*c == 'q' || *c == 'Q') {
682                                         ok = 1;
683                               } else {
684                                         printf("Unknown argument\n");
685                               }
686                     } else {
687                               ok = 1;
688                     }
689           }
690 }
691 #endif /* 0 */
692 
693 int
userconf_parse(char * cmd)694 userconf_parse(char *cmd)
695 {
696           char *c, *v;
697           int i = 0, j = 0, k, a;
698           short unit, state;
699 
700           c = cmd;
701           while (*c == ' ' || *c == '\t')
702                     c++;
703           v = c;
704           while (*c != ' ' && *c != '\t' && *c != '\n' && *c != '\0') {
705                     c++;
706                     i++;
707           }
708 
709           k = -1;
710           while (*userconf_cmds[j] != '\0') {
711                     if (strlen(userconf_cmds[j]) == i) {
712                               if (strncasecmp(v, userconf_cmds[j], i) == 0)
713                                         k = j;
714                     }
715                     j += 2;
716           }
717 
718           while (*c == ' ' || *c == '\t' || *c == '\n')
719                     c++;
720 
721           if (k == -1) {
722                     if (*v != '\n')
723                               printf("Unknown command, try help\n");
724           } else {
725                     switch (*userconf_cmds[k+1]) {
726                     case 'L':
727                               if (*c == '\0')
728                                         printf("Argument expected\n");
729                               else if (userconf_number(c, &a) == 0)
730                                         userconf_lines = a;
731                               else
732                                         printf("Unknown argument\n");
733                               break;
734                     case 'b':
735                               if (*c == '\0')
736                                         printf("8|10|16 expected\n");
737                               else if (userconf_number(c, &a) == 0) {
738                                         if (a == 8 || a == 10 || a == 16) {
739                                                   userconf_base = a;
740                                         } else {
741                                                   printf("8|10|16 expected\n");
742                                         }
743                               } else
744                                         printf("Unknown argument\n");
745                               break;
746                     case 'c':
747                               if (*c == '\0')
748                                         printf("DevNo or Dev expected\n");
749                               else if (userconf_number(c, &a) == 0)
750                                         userconf_change(a);
751                               else if (userconf_device(c, &a, &unit, &state) == 0)
752                                         userconf_common_dev(c, a, unit, state, UC_CHANGE);
753                               else
754                                         printf("Unknown argument\n");
755                               break;
756                     case 'd':
757                               if (*c == '\0')
758                                         printf("Attr, DevNo or Dev expected\n");
759                               else if (userconf_number(c, &a) == 0)
760                                         userconf_disable(a);
761                               else if (userconf_device(c, &a, &unit, &state) == 0)
762                                         userconf_common_dev(c, a, unit, state, UC_DISABLE);
763                               else
764                                         printf("Unknown argument\n");
765                               break;
766                     case 'e':
767                               if (*c == '\0')
768                                         printf("Attr, DevNo or Dev expected\n");
769                               else if (userconf_number(c, &a) == 0)
770                                         userconf_enable(a);
771                               else if (userconf_device(c, &a, &unit, &state) == 0)
772                                         userconf_common_dev(c, a, unit, state, UC_ENABLE);
773                               else
774                                         printf("Unknown argument\n");
775                               break;
776                     case 'f':
777                               if (*c == '\0')
778                                         printf("DevNo or Dev expected\n");
779                               else if (userconf_number(c, &a) == 0)
780                                         userconf_pdev(a);
781                               else if (userconf_device(c, &a, &unit, &state) == 0)
782                                         userconf_common_dev(c, a, unit, state, UC_FIND);
783                               else
784                                         printf("Unknown argument\n");
785                               break;
786                     case 'h':
787                               userconf_help();
788                               break;
789                     case 'l':
790                               if (*c == '\0')
791                                         userconf_list();
792                               else
793                                         printf("Unknown argument\n");
794                               break;
795                     case 'q':
796                               /* XXX add cmd 'q' eoc */
797                               userconf_hist_cmd('q');
798                               userconf_hist_eoc();
799                               return(-1);
800                     case 's':
801                     default:
802                               printf("Unknown command\n");
803                               break;
804                     }
805           }
806           return(0);
807 }
808 
809 void
userconf_prompt(void)810 userconf_prompt(void)
811 {
812           const char prompt[] = "uc> ";
813 
814           printf("userconf: configure system autoconfiguration:\n");
815 
816           while (1) {
817                     printf(prompt);
818                     if (cngetsn(userconf_cmdbuf, sizeof(userconf_cmdbuf)) > 0 &&
819                         userconf_parse(userconf_cmdbuf))
820                               break;
821           }
822           printf("Continuing...\n");
823 }
824